2 # = ostruct.rb: OpenStruct implementation
4 # Author:: Yukihiro Matsumoto
5 # Documentation:: Gavin Sinclair
7 # OpenStruct allows the creation of data objects with arbitrary attributes.
8 # See OpenStruct for an example.
12 # OpenStruct allows you to create data objects and set arbitrary attributes.
17 # record = OpenStruct.new
18 # record.name = "John Smith"
20 # record.pension = 300
22 # puts record.name # -> "John Smith"
23 # puts record.address # -> nil
25 # It is like a hash with a different way to access the data. In fact, it is
26 # implemented with a hash, and you can initialize it with one.
28 # hash = { "country" => "Australia", :population => 20_000_000 }
29 # data = OpenStruct.new(hash)
31 # p data # -> <OpenStruct country="Australia" population=20000000>
35 # Create a new OpenStruct object. The optional +hash+, if given, will
36 # generate attributes and values. For example.
39 # hash = { "country" => "Australia", :population => 20_000_000 }
40 # data = OpenStruct.new(hash)
42 # p data # -> <OpenStruct country="Australia" population=20000000>
44 # By default, the resulting OpenStruct object will have no attributes.
46 def initialize(hash=nil)
56 # Duplicate an OpenStruct object members.
57 def initialize_copy(orig)
67 @table.each_key{|key| new_ostruct_member(key)}
70 def new_ostruct_member(name)
72 unless self.respond_to?(name)
73 class << self; self; end.class_eval do
74 define_method(name) { @table[name] }
75 define_method(:"#{name}=") { |x| @table[name] = x }
80 def method_missing(mid, *args) # :nodoc:
85 raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
88 raise TypeError, "can't modify frozen #{self.class}", caller(1)
91 self.new_ostruct_member(mname)
92 @table[mname.intern] = args[0]
96 raise NoMethodError, "undefined method `#{mname}' for #{self}", caller(1)
101 # Remove the named field from the object.
103 def delete_field(name)
104 @table.delete name.to_sym
107 InspectKey = :__inspect_key__ # :nodoc:
110 # Returns a string containing a detailed summary of the keys and values.
113 str = "#<#{self.class}"
115 Thread.current[InspectKey] ||= []
116 if Thread.current[InspectKey].include?(self) then
121 str << "," unless first
124 Thread.current[InspectKey] << v
126 str << " #{k}=#{v.inspect}"
128 Thread.current[InspectKey].pop
137 attr_reader :table # :nodoc:
141 # Compare this object and +other+ for equality.
144 return false unless(other.kind_of?(OpenStruct))
145 return @table == other.table