在Ruby中将参数传递给包含的模块?

时间:2021-11-28 05:17:55

I'm hoping to implement something like all of the great plugins out there for ruby, so that you can do this:

我希望能够实现像ruby那样的所有优秀插件,以便你可以这样做:

acts_as_commentable
has_attached_file :avatar

But I have one constraint:

但我有一个约束:

That helper method can only include a module; it can't define any variables or methods.

该辅助方法只能包含一个模块;它无法定义任何变量或方法。

The reason for this is because, I want the options hash to define something like type, and that could be converted into one of say 20 different 'workhorse' modules, all of which I could sum up in a line like this:

这样做的原因是,我希望选项哈希定义类似于类型的东西,并且可以将其转换为20个不同的“主力”模块中的一个,所有这些我可以在这样的行中总结:

def dynamic_method(options = {})
 include ("My::Helpers::#{options[:type].to_s.camelize}").constantize(options)
end

Then those 'workhorses' would handle the options, doing things like:

那些'workhorses'会处理选项,做的事情如下:

has_many "#{options[:something]}"

Here's what the structure looks like, and I'm wondering if you know the missing piece in the puzzle:

这是结构的样子,我想知道你是否知道拼图中缺失的部分:

# 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!"

That %Q? I'm not totally sure how to use, but I'm basically just wanting to somehow be able to pass the options hash from that helper method into the workhorse module. Is that possible? That way, the workhorse module could define all sorts of functionality, but I could name the variables whatever I wanted at runtime.

那%Q?我不完全确定如何使用,但我基本上只是想以某种方式能够将辅助方法中的选项哈希传递给主力模块。那可能吗?这样,主力模块可以定义各种功能,但我可以在运行时命名变量。

3 个解决方案

#1


2  

You might want to look at the Modularity gem, which does exactly what you want.

您可能希望查看Modularity gem,它可以完全满足您的需求。

#2


3  

I'm working on something similar, based on some clever ruby code I saw once but now can't find again. I have things almost working, but it messes up things like self.included and self.extended in your Module, for somewhat obvious reasons that could be worked around, but I don't like how complicated it would get. I think there's one trick I haven't thought of yet that would make this work more perfectly.

我正在研究类似的东西,基于我曾经看过的一些聪明的红宝石代码,但现在再也找不到了。我的东西几乎可以工作,但是它会混淆像自我包含和自我扩展的东西,因为有些明显的原因可以解决,但我不喜欢它会有多复杂。我认为还有一个我没有想到的技巧会让这项工作更加完美。

So this may or may not work for you, but what I'm trying is the idea of an anonymous module created dynamically based on your options. (I think 'type' may be a reserved word but I'm not sure, so let's say "options" instead). Check out this idea:

所以这可能适用于您,也可能不适合您,但我正在尝试的是根据您的选项动态创建的匿名模块的想法。 (我认为'type'可能是一个保留词,但我不确定,所以让我们说“选项”)。看看这个想法:


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 }

Kind of neat, huh? But isn't quite good enough for me yet, because the actual Module you get from HelperModule[options] doesn't have the self.included and self.extended from the original HelperModule. I guess I could just define self.included and self.extended in the anon module, but I don't like the code confusion. I also don't like having to explicitly say "include HelperModule" in the anonymous module, I'd rather it be, like "self", except "self" doesn't mean the right thing there, so that doesn't work.

有点整洁,对吧?但对我来说还不够好,因为你从HelperModule [options]获得的实际模块没有原始HelperModule中的self.included和self.extended。我想我可以在anon模块中定义self.included和self.extended,但我不喜欢代码混淆。我也不喜欢在匿名模块中明确说“包含HelperModule”,我宁愿它像“自我”一样,除了“自我”并不意味着那里正确的东西,所以这不起作用。

Ah, wait, guess what I just discovered: If this general approach seems like it should work for you, it can be supplied by the paramix gem: http://rubyworks.github.com/paramix/

啊,等等,猜猜我刚发现的东西:如果这种一般方法看起来应该对你有用,它可以由paramix gem提供:http://rubyworks.github.com/paramix/

#3


0  

ActionModel gem can help you. I use it in my projects.

ActionModel gem可以帮到你。我在我的项目中使用它。

#1


2  

You might want to look at the Modularity gem, which does exactly what you want.

您可能希望查看Modularity gem,它可以完全满足您的需求。

#2


3  

I'm working on something similar, based on some clever ruby code I saw once but now can't find again. I have things almost working, but it messes up things like self.included and self.extended in your Module, for somewhat obvious reasons that could be worked around, but I don't like how complicated it would get. I think there's one trick I haven't thought of yet that would make this work more perfectly.

我正在研究类似的东西,基于我曾经看过的一些聪明的红宝石代码,但现在再也找不到了。我的东西几乎可以工作,但是它会混淆像自我包含和自我扩展的东西,因为有些明显的原因可以解决,但我不喜欢它会有多复杂。我认为还有一个我没有想到的技巧会让这项工作更加完美。

So this may or may not work for you, but what I'm trying is the idea of an anonymous module created dynamically based on your options. (I think 'type' may be a reserved word but I'm not sure, so let's say "options" instead). Check out this idea:

所以这可能适用于您,也可能不适合您,但我正在尝试的是根据您的选项动态创建的匿名模块的想法。 (我认为'type'可能是一个保留词,但我不确定,所以让我们说“选项”)。看看这个想法:


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 }

Kind of neat, huh? But isn't quite good enough for me yet, because the actual Module you get from HelperModule[options] doesn't have the self.included and self.extended from the original HelperModule. I guess I could just define self.included and self.extended in the anon module, but I don't like the code confusion. I also don't like having to explicitly say "include HelperModule" in the anonymous module, I'd rather it be, like "self", except "self" doesn't mean the right thing there, so that doesn't work.

有点整洁,对吧?但对我来说还不够好,因为你从HelperModule [options]获得的实际模块没有原始HelperModule中的self.included和self.extended。我想我可以在anon模块中定义self.included和self.extended,但我不喜欢代码混淆。我也不喜欢在匿名模块中明确说“包含HelperModule”,我宁愿它像“自我”一样,除了“自我”并不意味着那里正确的东西,所以这不起作用。

Ah, wait, guess what I just discovered: If this general approach seems like it should work for you, it can be supplied by the paramix gem: http://rubyworks.github.com/paramix/

啊,等等,猜猜我刚发现的东西:如果这种一般方法看起来应该对你有用,它可以由paramix gem提供:http://rubyworks.github.com/paramix/

#3


0  

ActionModel gem can help you. I use it in my projects.

ActionModel gem可以帮到你。我在我的项目中使用它。