Ответ 1
Возможно, вы захотите посмотреть Modularity gem, который делает именно то, что вы хотите.
Я надеюсь реализовать что-то вроде всех великолепных плагинов там для ruby, чтобы вы могли это сделать:
acts_as_commentable
has_attached_file :avatar
Но у меня есть одно ограничение:
Этот вспомогательный метод может включать только модуль; он не может определить какие-либо переменные или методы.
Причина этого заключается в том, что я хочу, чтобы хэш параметров определял что-то вроде type
, и это могло быть преобразовано в один из 20 различных модулей "рабочая лошадка", все из которых я мог бы суммировать в строке типа это:
def dynamic_method(options = {})
include ("My::Helpers::#{options[:type].to_s.camelize}").constantize(options)
end
Тогда эти "рабочие лошадки" будут обрабатывать варианты, делая такие вещи, как:
has_many "#{options[:something]}"
Вот как выглядит структура, и мне интересно, знаете ли вы недостающую часть в головоломке:
# 1 - The workhorse, encapsuling all dynamic variables
module My::Module
def self.included(base)
base.extend ClassMethods
base.class_eval do
include InstanceMethods
end
end
module InstanceMethods
self.instance_eval %Q?
def #{options[:my_method]}
"world!"
end
?
end
module ClassMethods
end
end
# 2 - all this does is define that helper method
module HelperModule
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def dynamic_method(options = {})
# don't know how to get options through!
include My::Module(options)
end
end
end
# 3 - send it to active_record
ActiveRecord::Base.send(:include, HelperModule)
# 4 - what it looks like
class TestClass < ActiveRecord::Base
dynamic_method :my_method => "hello"
end
puts TestClass.new.hello #=> "world!"
Это %Q?
Я не совсем уверен, как использовать, но я просто хочу как-то передать хеш options
из этого вспомогательного метода в модуль рабочей лошади. Это возможно? Таким образом, модуль рабочей лошадки мог бы определять всевозможные функциональные возможности, но я мог бы назвать переменные, которые мне нужны во время выполнения.
Возможно, вы захотите посмотреть Modularity gem, который делает именно то, что вы хотите.
Я работаю над чем-то подобным, основанным на некотором умном коде Ruby, который я видел один раз, но теперь не могу найти снова. У меня есть вещи, которые почти работают, но это путается с такими вещами, как self.included и self.extended в вашем модуле, по несколько очевидным причинам, которые можно было бы проработать, но мне не нравится, насколько это будет сложно. Я думаю, там один трюк, о котором я еще не думал, что сделало бы эту работу более совершенной.
Таким образом, это может работать или не работать для вас, но я пытаюсь создать анонимный модуль, созданный динамически на основе ваших опций. (Я думаю, что "тип" может быть зарезервированным словом, но я не уверен, так что скажем "варианты" вместо этого). Ознакомьтесь с этой идеей:
Module HelperModule
def[](options)
Module.new do
include HelperModule
define_method(:options) { options }
end
end
def options
raise TypeError.new("You need to instantiate this module with [], man!")
end
end
obj = Object.new
obj.extend(HelperModule)
obj.options => raises TypeError
obj = Object.new
obj.extend(HelperModule[ :my_option => "my_option" ]
obj.options => { my_option => "my_option }
Вид аккуратный, да? Но пока еще недостаточно для меня, потому что фактический модуль, который вы получаете из HelperModule [options], не имеет self.included и self.extended из исходного HelperModule. Думаю, я мог бы просто определить self.included и self.extended в модуле анонов, но мне не нравится путаница кода. Мне также не нравится явно говорить "включить HelperModule" в анонимный модуль, я бы предпочел, чтобы это было, как "я", кроме "я", это не значит, что это правильно, так что это не работает,
А, подождите, угадайте, что я только что обнаружил: если этот общий подход кажется, что он должен сработать для вас, он может быть поставлен с помощью paramix gem: http://rubyworks.github.com/paramix/
ActionModel gem может вам помочь. Я использую его в своих проектах.