有没有办法指定一个类方法,这样当对象被用作函数时,该方法被调用?像这样:
class MyClass
def some_magic_method(*args)
# stuff happens
end
end
# create object
myob = MyClass.new
# implicitly call some_magic_method
myob 'x'
答案 0 :(得分:3)
正如@CarySwoveland在评论中所提到的,您可以使用method_missing
。一个基本的例子如下:
class MyClass
def method_missing(method_name, *args)
if method_name.match?(/[xyz]/)
send(:magic_method, args.first)
else
super
end
end
def magic_method(a)
a = 'none' if a.nil?
"xyz-magic method; argument(s): #{a}"
end
end
myob = MyClass.new
myob.x #=> "xyz-magic method; argument(s): none"
myob.x(1) #=> "xyz-magic method; argument(s): 1"
myob.y #=> "xyz-magic method; argument(s): none"
myob.z #=> "xyz-magic method; argument(s): none"
这会捕获名为x,y或z的所有方法。我们的else
分支将所有其他未定义的方法发送到原始method_missing
:
myob.v #=> test.rb:7:in `method_missing': undefined method `v' for
#<MyClass:0x000000021914f8> (NoMethodError)
#from test.rb:25:in `<main>'
您捕获的方法取决于您,并且在这种情况下由正则表达式/[xyz]/
确定。
关键方法: BasicObject#method_missing
,Object#send
。有关详细信息,请查看此question,阅读Russ Olsen撰写的 Eloquent Ruby (此答案可参考)
答案 1 :(得分:2)
您可以编写命令类并使用ruby快捷方式
class MyClass
def self.call(text)
puts text
end
end
MyClass.('x')
此处MyClass.()
默认使用call
类方法。
答案 2 :(得分:0)
当您将对象作为函数调用时,您的意思是调用某个类'instance method
。这已得到支持:当您通过功能调用方法call
“调用”对象时,将调用实例方法()
(有关详细信息,请参阅此处How do I reference a function in Ruby?)。
class C
def call(x)
puts "Called with #{x}"
end
end
obj = C.new
obj.(88) # Called with 88 => nil
obj (88) # NoMethodError: undefined method `obj' for main:Object
如果你确实需要后一种语法,一个可怕的技巧是下面的一个(但只能在顶层工作,除非你随身携带绑定):
module Kernel
def method_missing(name,*args)
obj = begin
TOPLEVEL_BINDING.local_variable_get(name)
rescue
nil
end
return super if obj.nil?
obj.send :call, *args
end
end
obj = C.new
obj 88 # Called with OK => nil
此示例还希望告知您应始终牢记 谁是您的方法调用的接收器,以及可用于调用方法的语法(特别是当您省略点和括号时)。
class D
def obj; C.new end
def f
#(obj) 88 # BAD
(obj).(88)
#obj() 88 # BAD
obj().(88)
end
end
关键是你实际上没有函数,而是在对象上调用的方法。如果省略方法调用的接收方,则接收方默认为当前对象self
。但在您的示例中,myob
并未显示为显式接收器(因为myob.
中没有跟随点),因此查找当前对象的方法myob
。