Передать аргументы включенному модулю в Ruby? - PullRequest
12 голосов
/ 22 марта 2010

Я надеюсь реализовать что-то наподобие всех замечательных плагинов для 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 из этого вспомогательного метода в модуль рабочей лошадки. Это возможно? Таким образом, модуль рабочей лошадки может определять все виды функциональных возможностей, но я мог бы называть переменные как угодно во время выполнения.

Ответы [ 3 ]

3 голосов
/ 01 апреля 2010

Я работаю над чем-то похожим, основываясь на каком-то умном рубиновом коде, который я видел однажды, но теперь не могу найти снова. У меня есть вещи, которые почти работают, но они портят такие вещи, как self.included и self.extended в вашем модуле, по несколько очевидным причинам, которые можно обойти, но мне не нравится, насколько сложным это будет , Я думаю, что есть одна хитрость, о которой я еще не думал, которая сделает эту работу более совершенной.

Так что это может или не может работать для вас, но я пытаюсь представить идею анонимного модуля, создаваемого динамически на основе ваших опций. (Я думаю, что «type» может быть зарезервированным словом, но я не уверен, поэтому давайте вместо этого скажем «options»). Проверьте эту идею:


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 в модуле anon, но мне не нравится путаница в коде. Мне также не нравится явно указывать «включить HelperModule» в анонимный модуль, я бы предпочел, чтобы, как «я», за исключением того, что «я» не означает, что правильно, так что это не работает ,

Ах, подождите, угадайте, что я только что обнаружил: если этот общий подход кажется вам подходящим, он может быть предоставлен гемом paramix: http://rubyworks.github.com/paramix/

2 голосов
/ 17 сентября 2010

Возможно, вы захотите взглянуть на камень Modularity , который делает именно то, что вы хотите.

0 голосов
/ 15 февраля 2014

ActionModel драгоценный камень может помочь вам. Я использую это в своих проектах.

...