匿名模块可以用于什么目的?
Ruby应用程序中的匿名模块可以用于什么目的? 概念本身很容易掌握,但我无法想象你曾经使用过这样的东西的任何理由。 他们解决了什么问题?
这里有一个更普遍的原则。
Phil Karlton着名地说: “计算机科学只有两个难题:缓存失效和命名事物。” 因此,命名事情很难。 这意味着,如果我们能够在不命名的情况下逃脱,我们应该这样做!
或者,如果从不同的角度来看待它:如果命名很难,那么给某个名称意味着事情很重要。 但有时候,我们的程序中有些东西并不重要,因而不值得一个名字。
这不是Ruby模块独有的。 您可以询问有关任何匿名概念的问题,事实上,问题会一直被问到。 当C#2.0引入匿名方法时,人们会问为什么人们会想要使用没有名称的方法,当C#3.0引入匿名lambdas(和匿名类型)时,人们会问为什么人们会想要使用它们。 与Python的命名函数相比,Python的匿名函数受到严格限制,而Python社区则询问为什么人们需要完整的匿名函数。 当然,我们,因为Ruby程序员习惯于轻量级(块)和完全具体化( Proc
)的匿名函数,我们无法理解为什么人们不想使用它。
Java从1.1开始有匿名类,自8开始有匿名lambda。基本上,匿名“东西”无处不在,它们很有用,尤其适用于快速一次性使用。
例如,如果你只想包装一些现有的方法,而不是经历alias_method
的麻烦(你真的不应该再使用它来解决那个问题,现在Module#prepend
已经存在并且是一个更好的解决方案),你可以做:
class Array prepend(Module.new do def [](*) puts 'Before-hook' super.tap { puts 'After-hook' } end end) end p [42][0] # Before-hook # After-hook # => 42
这是一个Rails特定的答案,它不是一般的匿名模块。
简短的回答
在覆盖生成的方法时能够调用super
。
答案很长
给定一个创建方法的模块:
module Generator def generate_method(name) define_method(name) do "I am #{name}" end end end
从类中调用generate_method
会创建一个新的实例方法:
class MyClass extend Generator generate_method :foo end MyClass.new.method(:foo) #=> #
调用该方法按预期工作:
MyClass.new.foo #=> "I am foo"
但你不能轻易改变foo
:
class MyClass def foo super.upcase end end MyClass.new.foo #=> no superclass method `foo'
如果我们的生成器使用匿名模块来定义以下方法:
module Generator def generate_method(name) generated_methods.module_eval do define_method(name) do "I am #{name}" end end end def generated_methods @generated_methods ||= begin mod = Module.new include(mod) mod end end end
我们得到:
class MyClass extend Generator generate_method :foo end MyClass.new.method(:foo) #=> #)#foo>
并且改变foo
现在按预期工作:
class MyClass def foo super.upcase end end MyClass.new.foo #=> "I AM FOO"
- 我如何需要ActiveSupport的rescue_from方法?
- 未初始化的常量TZInfo :: InvalidTimezoneIdentifier(NameError) – Rails 4
- 测试ActiveSupport :: TimeWithZone对象是否相等
- 在特定时区的某一天开始获取时间对象
- 如何解决activesupport 3.0.0与2.x相比的行为差异?
- 你如何处理ActiveSupport :: JSON和JSON gem之间的冲突?
- NoMethodError:ActiveSupport的未定义方法`halt_callback_chains_on_return_false =’:模块
- Rails time_ago_in_words产生错误的输出
- btw const_get和qualified_const_get有什么区别?