问题
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