我有一个简单的ruby函数:
module MyModule
def foo(param)
puts param
end
end
我希望能够使用bar
和Baz
等未定义的令牌进行调用,如下所示:
foo bar
foo Baz
请注意,我需要能够传递任何以字母开头的标记名称(大写或小写)。
我可以通过添加method_missing来处理第一种情况(小写起始名bar
):
module MyModule
def method_missing(meth, *args, &blk)
meth.to_s
end
end
但是第二行(Baz
)给了我一个未初始化的常量错误,所以我尝试添加一个类似的const_missing:
module MyModule
def const_missing(const_name)
const_name.to_s
end
end
但我仍然使用Baz
得到未初始化的常量错误 - 如何捕获以大写字母开头的缺少名称并返回字符串?
更新:以下是重现场景的完整代码:
module MyModule
def foo(param)
puts param
end
def method_missing(meth, *args, &blk)
meth.to_s
end
def const_missing(const_name)
const_name.to_s
end
end
include MyModule
foo "bar" #=> bar
foo bar #=> bar
foo Baz #=> uninitialized constant Baz (NameError)
答案 0 :(得分:1)
如果您只想撰写Baz
,则需要定义Object.const_missing
并拨打MyModule.const_missing
。
def Object.const_missing(const_name)
MyModule.const_missing(const_name)
end
您收到错误,因为当前作用域中没有常量Baz
,这是主要的ruby对象Object
。
这是更好,更具启发性的测试代码:
include MyModule
p foo(bar)
p bar
p MyModule.Baz
p Baz
输出是这样的:
bar # 1
nil # from puts
"bar" # 2
"Baz" # 3
test.rb:19:in `<main>': uninitialized constant Baz (NameError) # 4
foo bar
调用方法foo,永远不会调用缺少方法。 bar
在当前对象中搜索方法,然后调用Object
上的method_missing,其中包含MyModule
MyModule.Baz
在模块MyModule中搜索常量,然后调用const_missing
。 Baz
在当前模块中搜索constant_missing,并调用const_missing
Object.const_missing
,即Object的类实例方法。 当ruby查找方法时,它以对象方法开始,只有当它无法定义它们时才会查看它的模块,然后查看父类,然后是父类模块等。不能覆盖它的对象/类方法模块。
Object
(ruby的主要对象,包括内核)定义了它的const_missing
方法,但不是method_missing
。
search = "method_"
Object.public_methods.select { |s| s.to_s.include?(search) }
=> [:method_defined?, :public_method_defined?,
:private_method_defined?, :protected_method_defined?]
注意没有方法丢失。搜索const_
会找到const_missing
search = "const_"
=> "const_"
irb(main):011:0> Object.public_methods.select { |s| s.to_s.include?(search) }
=> [:const_get, :const_defined?, :const_set, :const_missing]