Method_missing 有效,但 const_missing 无效
Method_missing works, but const_missing does not work
我有一个简单的 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
的未初始化常量错误 - 如何捕获以大写字母开头的缺失名称和 return 字符串?
更新:这里是重现场景的完整代码:
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)
解决方案
如果你想只写 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,永远不会调用方法 missing。
bar
在当前对象中搜索方法,然后在 Object
上调用 method_missing,它包含在 MyModule
中
MyModule.Baz
在模块 MyModule 中搜索常量,然后调用 const_missing
。
Baz
在当前模块中搜索 constant_missing 并调用 const_missing
即 Object.const_missing
,Object 的 class 实例方法。
当 ruby 查找方法时,它从对象方法开始,只有当它不能定义它们时,它才会查看它的模块,然后是父 class,然后是父 classes模块等。无法从它的模块中覆盖 objects/classes 方法。
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]
我有一个简单的 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
的未初始化常量错误 - 如何捕获以大写字母开头的缺失名称和 return 字符串?
更新:这里是重现场景的完整代码:
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)
解决方案
如果你想只写 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,永远不会调用方法 missing。bar
在当前对象中搜索方法,然后在Object
上调用 method_missing,它包含在MyModule
中
MyModule.Baz
在模块 MyModule 中搜索常量,然后调用const_missing
。Baz
在当前模块中搜索 constant_missing 并调用const_missing
即Object.const_missing
,Object 的 class 实例方法。
当 ruby 查找方法时,它从对象方法开始,只有当它不能定义它们时,它才会查看它的模块,然后是父 class,然后是父 classes模块等。无法从它的模块中覆盖 objects/classes 方法。
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]