Search code examples
rubyexpando

Creating an Expando object in Ruby


Is there a better way to write this Expando class? The way it is written does not work. I'm using Ruby 1.8.7

starting code quoted from https://gist.github.com/300462/3fdf51800768f2c7089a53726384350c890bc7c3

class Expando
    def method_missing(method_id, *arguments)
        if match = method_id.id2name.match(/(\w*)(\s*)(=)(\s*)(\.*)/)
              puts match[1].to_sym # think this was supposed to be commented 
              self.class.class_eval{ attr_accessor match[1].to_sym } 
              instance_variable_set("#{match[1]}", match[5])
        else
              super.method_missing(method_id, *arguments)
        end  
    end    
end

person = Expando.new 
person.name = "Michael"
person.surname = "Erasmus"
person.age = 29 

Solution

  • The easiest way to write it is to not write it at all! :) See the OpenStruct class, included in the standard library:

    require 'ostruct'
    
    record = OpenStruct.new
    record.name    = "John Smith"
    record.age     = 70
    record.pension = 300
    

    If I was going to write it, though, I'd do it like this:

    # Access properties via methods or Hash notation
    class Expando
      def initialize
        @properties = {}
      end
      def method_missing( name, *args )
        name = name.to_s
        if name[-1] == ?=
          @properties[name[0..-2]] = args.first
        else
          @properties[name]
        end
      end
      def []( key )
        @properties[key]
      end
      def []=( key,val )
        @properties[key] = val
      end
    end
    
    person = Expando.new
    person.name = "Michael"
    person['surname'] = "Erasmus"
    puts "#{person['name']} #{person.surname}"
    #=> Michael Erasmus