Created
December 2, 2019 20:21
-
-
Save igor-alexandrov/b80c1af4f786a4215a0ce331f765d796 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module PluginA | |
DEFAULT_OPTIONS = { | |
c: 3, | |
d: 4, | |
} | |
module InstanceMethods | |
def plugin_a_method_a | |
"plugin_a_method_a" | |
end | |
end | |
module Y | |
module InstanceMethods | |
def plugin_a_module_y_method_a | |
"plugin_a_module_y_method_a" | |
end | |
end | |
end | |
end | |
class PluginB | |
module InstanceMethods | |
def plugin_b_method_b | |
"plugin_b_method_b" | |
end | |
end | |
end | |
class X | |
PLUGINS = [] of Nil | |
class PluginSettings | |
def all | |
[] of Nil | |
end | |
end | |
def self.plugin_settings | |
PluginSettings.new | |
end | |
macro inherited | |
{{@type}}::PLUGINS = [] of Nil | |
{% for plugin in @type.superclass.constant(:PLUGINS) %} | |
load_plugin({{plugin[:decl]}}, {{plugin[:options].double_splat}}) | |
{% end %} | |
end | |
macro load_plugin(plugin, **args) | |
{% plugin = plugin.resolve %} | |
{% options = args %} | |
{% if PLUGINS.map { |e| e[:decl] }.includes?(plugin) %} | |
raise ArgumentError.new("Cannot load plugin {{plugin.stringify}} to {{@type}}. Plugin has already been initialized") | |
{% else %} | |
{% if plugin.constant(:DEFAULT_OPTIONS) %} | |
{% if !options %} | |
{% options = plugin.constant(:DEFAULT_OPTIONS) %} | |
{% end %} | |
{% for key in plugin.constant(:DEFAULT_OPTIONS).keys %} | |
{% unless options[key] %} | |
{{ options[key] = plugin.constant(:DEFAULT_OPTIONS)[key] }} | |
{% end %} | |
{% end %} | |
{% end %} | |
{% PLUGINS << {decl: plugin, options: options} %} | |
{% end %} | |
{% if plugin.constant(:InstanceMethods) %} | |
include {{plugin.constant(:InstanceMethods)}} | |
{% end %} | |
{% if plugin.constant(:ClassMethods) %} | |
extend {{plugin.constant(:ClassMethods)}} | |
{% end %} | |
{% if plugin.constant(:FileClassMethods) %} | |
class UploadedFile < Shrine::UploadedFile | |
extend {{plugin.constant(:FileClassMethods)}} | |
end | |
{% end %} | |
{% if plugin.constant(:FileMethods) %} | |
class UploadedFile < Shrine::UploadedFile | |
include {{plugin.constant(:FileMethods)}} | |
end | |
{% end %} | |
end | |
macro finalize_plugins! | |
class PluginsSettings | |
def all | |
{% if @type.constant(:PLUGINS) %} | |
{{ | |
@type.constant(:PLUGINS).map do |plugin| | |
options = (plugin[:options].empty? ? nil : plugin[:options]) | |
{ | |
name: plugin[:decl].stringify.underscore.split("::").last, | |
options: options.id | |
} | |
end | |
}} | |
{% end %} | |
end | |
def [](key : Symbol | String) | |
all.find{ |plugin| plugin[:name] == key.to_s}.try &.[:options] | |
end | |
{% for plugin in @type.constant(:PLUGINS) %} | |
def {{ plugin[:decl].stringify.underscore.split("::").last.id }} | |
{% if plugin[:options].empty? %} | |
nil | |
{% else %} | |
{{ plugin[:options] }} | |
{% end %} | |
end | |
{% end %} | |
end | |
def self.plugin_settings | |
PluginsSettings.new | |
end | |
end | |
end | |
class Y < X | |
proc_1 = ->( x : Int32 ) { x+1 } | |
load_plugin(PluginA, a: 1, b: proc_1) | |
# load_plugin(PluginA, a: 1, b: ->( x : Int32 ) { x+1 }) | |
finalize_plugins! | |
end | |
class Z < Y | |
load_plugin(PluginB) | |
finalize_plugins! | |
end | |
class V < Y | |
end | |
class W < X | |
end | |
puts "Y" | |
puts Y.plugin_settings["plugin_a"] | |
puts Y.plugin_settings["plugin_b"] | |
puts Y.plugin_settings.plugin_a | |
puts "Z" | |
puts Z.plugin_settings["plugin_b"] | |
puts Z.plugin_settings.plugin_b | |
puts "V" | |
puts V.plugin_settings.all | |
puts V.plugin_settings.plugin_a | |
puts "W" | |
puts W.plugin_settings.all | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment