Does Ruby have a method_missing equivalent for undefined instance variables?

拟墨画扇 提交于 2020-01-03 07:19:10

问题


When I invoke a method that doesn't exist, method_missing will tell me the name of the method. When I attempt to access a variable that hasn't been set, the value is simply nil.

I'm attempting to dynamically intercept access to nil instance variables and return a value based on the name of the variable being accessed. The closest equivalent would be PHP's __get. Is there any equivalent functionality in Ruby?


回答1:


I do not believe this is possible in Ruby. The recommended way would be to use a ''user'' method rather than a ''@user'' instance var in your templates.

This is consistent with the way you deal with Ruby objects externally (''obj.user'' is a method which refers to ''@user'', but is actually not ''@user'' itself). If you need any kind of special logic with an attribute, your best bet is to use a method (or method_missing), regardless if you're accessing it from inside or outside the object.




回答2:


See my answer to another similar question. But just because you can do it doesn't mean that it's a good idea. Sensible design can generally overcome the need for this kind of thing and allow you to produce more readable and hence maintainable code.

instance_variable_get seems to be the closest equivalent of PHP's __get from what I can see (although I'm not a PHP user).

Looking at the relevant Ruby source code, the only 'missing' method for variables is const_missing for constants, nothing for instance variables.




回答3:


there isn't an instance_variable_missing (at least that I know of) But why are you accessing randomly named instance variables anyway?

If your thread all the access to the object state through method calls (as you should anyway) then you wouldn't need this.

If you are looking for a way to define magic stuff without messing up with the method lookup, you may want to use const_missing.




回答4:


A bit late but, instance_variable_missing is the same as method_missing to a point... Take the following class:

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

Now let's get some instance variables:

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

Not sure why the method is nil for you...

EDIT:

By the sounds of it you want to accomplish:

t = SomeClass.new
t.property.child = 1

So let's try returning a Test object from our previous example:

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

So what happens when we call:

t = Test.new
t.property.child = 1
#=>[:property]
#=>[:child=,1]

So this goes to show that this is indeed possible to do. OpenStruct uses this same technique to set instance variables dynamically. In the below example, I create EternalStruct which does exactly what you wanted:

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

Usage of 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"


来源:https://stackoverflow.com/questions/7651213/does-ruby-have-a-method-missing-equivalent-for-undefined-instance-variables

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!