2010-03-22 102 views
12

我希望能实现像所有伟大的插件在那里为红宝石,这样就可以做到这一点:将参数传递给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?我不完全知道如何使用,但我基本上只是想以某种方式能够从helper方法通过options散列成主力模块。那可能吗?这样,workhorse模块可以定义各种功能,但是我可以在运行时为变量命名。

回答

3

我的工作类似的东西,根据我看到了曾经有些聪明的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。我想我可以在anon模块中定义self.included和self.extended,但我不喜欢代码混淆。我也不喜欢在匿名模块中明确地说“包含HelperModule”,我宁愿它是像“自我”一样,除了“自我”并不意味着那里是正确的事情,所以这是行不通的。

啊,等一下,你猜我刚发现:如果这个一般方法看起来像它应该为你工作,它可以通过paramix宝石提供: http://rubyworks.github.com/paramix/

0

ActionModel宝石可以帮助你。我在我的项目中使用它。

+0

你能详细说明在这种情况下这可能会有什么帮助吗?这可能是显而易见的,但在这个网站上的好答案包括这类信息。一个没有解释的指针并不是一个真正的答案.... – GreenAsJade 2014-02-14 23:56:08

+0

它是acts_as对于ruby类的DSL。您可以将字段和选项传递给action(模块),例如acts_as_searchable:title,ignorecase:true – 2014-02-15 00:25:18