当我调用一个不存在的方法时,method_missing
会告诉我方法的名称。当我尝试访问尚未设置的变量时,该值只是nil
.
我正在尝试动态拦截对 nil 实例变量的访问,并根据正在访问的变量的名称返回一个值。最接近的等价物是 PHP 的__get
. Ruby 中是否有任何等效的功能?
当我调用一个不存在的方法时,method_missing
会告诉我方法的名称。当我尝试访问尚未设置的变量时,该值只是nil
.
我正在尝试动态拦截对 nil 实例变量的访问,并根据正在访问的变量的名称返回一个值。最接近的等价物是 PHP 的__get
. Ruby 中是否有任何等效的功能?
请参阅我对另一个类似问题的回答。但仅仅因为你能做到并不意味着这是一个好主意。明智的设计通常可以克服对此类事物的需求,并允许您生成更具可读性和可维护性的代码。
instance_variable_get
似乎是__get
我所看到的最接近 PHP 的等价物(尽管我不是 PHP 用户)。
查看相关的 Ruby 源代码,变量的唯一“缺失”方法是const_missing
常量,没有实例变量。
我不相信这在 Ruby 中是可能的。推荐的方法是在模板中使用 ''user'' 方法而不是 ''@user'' 实例变量。
这与您在外部处理 Ruby 对象的方式是一致的(''obj.user'' 是一个引用 ''@user'' 的方法,但实际上不是 ''@user'' 本身)。如果您需要任何具有属性的特殊逻辑,最好的办法是使用方法(或 method_missing),无论您是从对象内部还是外部访问它。
没有 instance_variable_missing (至少我知道)但是你为什么要访问随机命名的实例变量呢?
如果您的线程通过方法调用(无论如何都应该)访问对象状态,那么您将不需要这个。
如果您正在寻找一种方法来定义神奇的东西而不会弄乱方法查找,您可能想要使用const_missing
.
有点晚了,但是,在一点instance_variable_missing
上是一样method_missing
的……上以下课:
class Test
def method_missing(*args)
puts args.inspect
end
end
t = Test.new
现在让我们获取一些实例变量:
t.pineapples #=> [:pineapples]
t.pineapples = 5 #=> [:pineapples=,5]
不知道为什么这个方法对你来说是 nil ......
编辑:
根据您想要完成的声音:
t = SomeClass.new
t.property.child = 1
因此,让我们尝试Test
从前面的示例中返回一个对象:
class Test
def method_missing(*args)
puts args.inspect
return Test.new
end
end
那么当我们调用时会发生什么:
t = Test.new
t.property.child = 1
#=>[:property]
#=>[:child=,1]
所以这表明这确实是可能的。OpenStruct
使用相同的技术动态设置实例变量。在下面的示例中,我创建EternalStruct
的正是您想要的:
require 'ostruct'
class EternalStruct < OpenStruct
def method_missing(*args)
ret = super(*args)
if !ret
newES = EternalStruct.new
self.__send__((args[0].to_s + "=").to_sym, newES)
return newES
end
end
end
的用法EternalStruct
:
t = EternalStruct.new
t.foo.bar.baz = "Store me!"
t.foo.bar.baz #=> "Store me!"
t.foo #=> #<EternalStruct bar=#<EternalStruct baz="Store me!">>
t.a = 1
t.a #=> 1
t.b #=> #<EternalStruct:...>
t.b = {}
t.b #=> {}
def t.c(arg)
puts arg
end
t.c("hi there") #=> "hi there"