Ruby access magic
Assume, I have the following class:
class MyClass
attr_accessor :vars
def initialize
@vars = []
end
开发者_如何学Godef add_var var
@vars << var
end
end
I want to access inners vars like this:
x = MyClass.new('root')
x.add_var 'test'
x.add_var 'something'
x.add_var Myclass.new('google')
x.google.add_var 'nice'
puts x.test
puts x.something
puts x.google.nice
Generally speaking, is it possible? What/where should I dig for?
It's part of the standard Ruby library, and it's called OpenStruct:
#!/usr/bin/ruby1.8
require 'ostruct'
x = OpenStruct.new
x.google = OpenStruct.new
x.google.nice = 'Nice. Real nice'
p x.google.nice # "Nice. Real nice"
You can also initialize attributes in the constructor:
x = OpenStruct.new(:google=>OpenStruct.new(:nice=>'Nice. Real nice'))
p x.google.nice # => "Nice. Real nice"
If you want to implement something like this yourself you should find out more about method_missing. This method gets called when a method cannot be found. Using some clever code to find the called method name in your @vars
and react on that.
This is probably the same method used by the plugin weppos is talking about.
Sure you can. This is exactly what, for instance, this plugin does for application-wide configuration settings.
you can do this with instance_varibable_set and instance_variable_get:
MyClass.instance_variable_set(:@var_name, "value")
Just dynamically define a new method and have it return the object you want:
class MyClass
attr_accessor :vars
attr_reader :name
def initialize(name)
@name = name
@vars = []
end
def add_var(var)
@vars << var
if var.instance_of?(MyClass)
class << self; self; end.send(:define_method, var.name.to_sym) {
var
}
end
end
end
x = MyClass.new(:x)
x.add_var MyClass.new(:google)
x.google.add_var MyClass.new(:nice)
x.google.nice.name #=> :nice
精彩评论