开发者

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜