我已在method_missing
上写了一个小包装:
module Util
def method_missing_for(regex, &blk1)
define_method(:method_missing) do |name, *args, &blk2|
match = name.to_s.scan(regex).flatten[0]
if match
blk1.call(match, *args, &blk2)
else
super(name, *args, &blk2)
end
end
end
end
然后使用它:
class Foo
extend Util
method_missing_for(/^say_(.+)$/){ |word| puts word }
end
Foo.new.say_hello
# => "hello"
问题是我不能多次为一个课程调用它。我添加method_missing
的{{1}}只会被覆盖。我有什么选择?从概念上讲,我知道我可以重构define_method
以获取多个正则表达式=>阻止映射,然后调用一次而不是多次。它的核心是一个大案例陈述,它测试所有的正则表达式。但我宁愿能够利用method_missing_for
。
super
答案 0 :(得分:0)
我的想法是在声明时注册定义,并在完成所有声明时定义这些方法。用法会略有不同,但我认为仍然可以接受
class Foo
extend Util
phantom_methods do
method_missing_for(/^say_(.+)$/){ |word| puts word }
method_missing_for(/^foo_(.+)$/){ |word| puts word }
end
end
Util
的实施将是
module Util
def phantom_methods
# Initialize the registration table
@_phantom_methods = {}
# Allow declaring methods
yield
# Consume the registration table and define a single `method_missing`
define_method(:method_missing) do |name, *args, &blk|
pair = self.class.instance_variable_get(:@_phantom_methods).find {|regexp, prc| name =~ regexp}
pair ? pair[1].call($1) : super(name, *args, &blk)
end
# Good practice to also define `respond_to_missing?`
define_method(:respond_to_missing?) do |name, include_private = false|
self.class.instance_variable_get(:@_phantom_methods).any? {|regexp, _| name =~ regexp}
end
end
# Declare a phantom method
def method_missing_for(regexp, &blk)
# Register the definition
@_phantom_methods[regexp] = blk
end
end
顺便说一下,我从this book借用了幻影方法这个短语。
答案 1 :(得分:0)
问题是我不能多次为一个课程调用它。我添加
method_missing
的{{1}}只会被覆盖。
不,它没有。它完成了写。
你已经有了这句话的解决方案:你需要骑而不是:
define_method
注意:命名模块可能有用也可能没有用,因此它在祖先链中显示了一个合理的名称,从而改善了调试体验:
module Util
def method_missing_for(regex, &blk1)
prepend(Module.new do
##################### this is the only change compared to your code
define_method(:method_missing) do |name, *args, &blk2|
match = name.to_s.scan(regex).flatten[0]
if match
blk1.(match, *args, &blk2)
else
super(name, *args, &blk2)
end
end
end)
####
end
end
class Foo
extend Util
method_missing_for(/^say_(.+)$/) { |word| puts word }
method_missing_for(/foobar/) {}
end
Foo.new.say_hello
# hello
另见When monkey patching a method, can you call the overridden method from the new implementation?更全面的治疗方法。