使用Ruby别名来扩展Gem

时间:2011-07-23 16:39:09

标签: ruby-on-rails ruby

这更像是一个理论问题,但无论如何我很好奇。我是一个ruby / ruby​​ on rails newbie(但在其他语言/框架方面有很多古老的经验)所以这主要是一个好奇/学习的问题。在此先感谢您的帮助!

我以为我可以使用别名快速扩展到ruby gem,如下所示:

module InstallMyExtension
  def self.included(base)
    base.class_eval {
      alias :some_method_in_gem_without_my_extension :some_method_in_gem
      alias :some_method_in_gem :some_method_in_gem_with_my_extension
    }
  end

  def some_method_in_gem_with_my_extension
    debugger
    # ... do fun stuff here
    some_method_in_gem_without_my_extension
  end

end

然后在一些初始化文件中我做:

Foo::SomeControllerInFoo.send :include, InstallMyExtension

我在Radiant CMS中学到了这种技术,它在所有地方都使用它来扩展基本行为。我知道这种技术现在已被拒绝了,但它似乎是一种快速尝试一些想法的方法,然后在宝石等上分支等等。

首先,在Rails 3中有一个更好的方法来做这样的快速黑客扩展(这可能只是为了测试一个理论,在分配宝石之前等等)

第二关,它不起作用,有很多我不明白的事情

然后让我解释一下我所看到的奇怪之处:<​​/ p>

即使如果我按照上面的说明执行“include”,当我进入控制台时,我看到一些非常奇怪的行为,我不明白:

1)我键入Foo :: SomeControllerInFoo我得到了Foo :: SomeControllerInFoo,正如我所料。但是,如果第二次运行相同的表达式,Foo :: SomeControllerInFoo会回来未定义!

2)只是为了玩我foo = Foo :: SomeControllerInFoo,然后我可以做foo.send,foo.methods,无论我喜欢什么,但只有我在foo中保存类的副本!那是什么?

3)如果我现在执行foo.send:include,MyExtension调试控制台中的行为是预期的(即gem中包含的原始类现在已经添加了我的行为。)但是在初始化期间运行相同的代码没有效果。没有什么破坏,但控制器没有扩展。

1 个答案:

答案 0 :(得分:2)

奇怪的是它不起作用,我只是再次尝试确保这一点(将此代码放在config/initializers中的文件中)。

我总是使用快捷方式:

alias_method_chain :some_method_in_gem, :my_extension

而不是两个别名行,但它完全相同。

您可以直接使用class_eval更轻松地覆盖某些方法。再次在初始化器中:

Foo::SomeControllerInFoo.class_eval do
  def some_method_in_gem
   #your redefinition
  end
end

对不起,但没有其他问题的附加值:看起来真的很奇怪和错误。


可以肯定的是,当您想要运行控制器中定义的方法时,请执行以下操作:

c = Foo::SomeControllerInFoo.new
c.method_name