=begin rdoc = OpenStructable OpensStructable is a mixin module which can provide OpenStruct behavior to any class or object. OpenStructable allows extention of data objects with arbitrary attributes. == Usage require 'raspberry/new/ostructable' class Record include OpenStructable end record = Record.new record.name = "John Smith" record.age = 70 record.pension = 300 puts record.name # -> "John Smith" puts record.address # -> nil == TODO * Keep this uptodate with ostruct.rb. * See if Matz will accept it into core so we don't have to anymore! * As with OpenStruct, marshalling is problematic at the moment. == Author(s) * Yukihiro Matsumoto * Gavin Sinclair (Documentation) * Thomas Sawyer == History * 2005.04.11 Passed basic test. =end module OpenStructable # Duplicate an OpenStruct object members. def initialize_copy(orig) super @__table__ = @__table__.dup end def new_ostruct_member(name) self.instance_eval %{ def #{name}; @__table__[:#{name}]; end def #{name}=(x); @__table__[:#{name}] = x; end } end # # Generate additional attributes and values. # def update(hash) @__table__ ||= {} if hash for k,v in hash @__table__[k.to_sym] = v new_ostruct_member(k) end end end def method_missing(mid, *args) # :nodoc: mname = mid.id2name len = args.length if mname =~ /=$/ if len != 1 raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1) end if self.frozen? raise TypeError, "can't modify frozen #{self.class}", caller(1) end mname.chop! @__table__ ||= {} @__table__[mname.intern] = args[0] self.new_ostruct_member(mname) elsif len == 0 @__table__ ||= {} @__table__[mid] else raise NoMethodError, "undefined method `#{mname}' for #{self}", caller(1) end end # # Remove the named field from the object. # def delete_field(name) @__table__ ||= {} @__table__.delete name.to_sym end # # Returns a string containing a detailed summary of the keys and values. # def inspect str = "<#{self.class}" for k,v in (@__table__ ||= {}) str << " #{k}=#{v.inspect}" end str << ">" end def __table__ # :nodoc: @__table__ ||= {} end protected :__table__ # # Compare this object and +other+ for equality. # def ==(other) return false unless(other.kind_of?(OpenStruct)) return @__table__ == other.table end end =begin # # It is possibe to implement OpenStruct itself with # this OpenStructable module as follows: # class OpenStruct include OpenStructable def initialize(hash=nil) update(hash) end end =end