Ruby是否有一个与未定义的实例变量等效的method_missing?

时间:2011-10-04 16:40:46

标签: ruby metaprogramming method-missing

当我调用一个不存在的方法时,method_missing会告诉我该方法的名称。当我尝试访问尚未设置的变量时,该值只是nil

我正在尝试动态拦截对nil实例变量的访问,并根据要访问的变量的名称返回一个值。最接近的等价物是PHP的__get。 Ruby中有没有相同的功能?

4 个答案:

答案 0 :(得分:2)

我不相信这在Ruby中是可行的。推荐的方法是在模板中使用“用户”方法而不是“@user”实例var。

这与外部处理Ruby对象的方式一致(''obj.user''是一个引用''@user''的方法,但实际上并不是''@user''本身)。如果您需要具有属性的任何特殊逻辑,最好的方法是使用方法(或method_missing),无论您是从对象内部还是外部访问它。

答案 1 :(得分:1)

查看我的answer to another similar question。但仅仅因为你可以这样做并不意味着它是一个好主意。明智的设计通常可以克服对此类事物的需求,并允许您生成更易读且可维护的代码。

instance_variable_get似乎是我能看到的最接近的PHP __get(虽然我不是PHP用户)。

查看relevant Ruby source code,唯一'缺失'变量的方法是常量const_missing,实例变量没有。

答案 2 :(得分:0)

没有instance_variable_missing(至少我知道) 但是为什么要访问随机命名的实例变量呢?

如果您的线程通过方法调用对所有对象的访问状态(无论如何应该如此),那么您就不需要这样了。

如果您正在寻找一种方法来定义魔术内容而不会弄乱方法查找,您可能需要使用const_missing

答案 3 :(得分:0)

有点晚了,但是instance_variable_missingmethod_missing有点相似...上下面的课:

class Test
 def method_missing(*args)
  puts args.inspect
 end
end 
t = Test.new

现在让我们获取一些实例变量:

t.pineapples     #=> [:pineapples]
t.pineapples = 5 #=> [:pineapples=,5]

不确定为什么该方法对您没有帮助...

编辑:

根据您想完成的声音

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"