tags:

views:

108

answers:

5
+1  Q: 

Ruby access magic

Assume, I have the following class:

class MyClass
  attr_accessor :vars

  def initialize
    @vars = []
  end

  def 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?

A: 

Sure you can. This is exactly what, for instance, this plugin does for application-wide configuration settings.

Simone Carletti
+1  A: 

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.

Veger
A: 

you can do this with instance_varibable_set and instance_variable_get:

MyClass.instance_variable_set(:@var_name, "value")

ennuikiller
+1  A: 

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
banister
Defining new methods is a tricky/troublesome business. And assuming that the example of the OP is a simplistic view of reality things might get messy.
Veger
I also think `method_missing` can be a pain, esp. since a robust implementation requires patching `respond_to?` as well.
banister
True, but it seems more flexible in removing, renaming, etc variables, since it is directly dependant on `@vars`. Thus any changes in it are reflected immediately.
Veger
yep you're right about that. Guess it all depends on his exact use-case. I usually prefer defining methods to using `method_missing` if i can get away with it since it's faster and 'less magic' (though that's debatable)
banister
+3  A: 

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"
Wayne Conrad