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 meta = class << self; self; end
74 meta.send(:define_method, name) { @table[name] }
75 meta.send(:define_method, :"#{name}=") { |x| @table[name] = x }
79 def method_missing(mid, *args) # :nodoc:
84 raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
87 raise TypeError, "can't modify frozen #{self.class}", caller(1)
90 self.new_ostruct_member(mname)
91 @table[mname.intern] = args[0]
95 raise NoMethodError, "undefined method `#{mname}' for #{self}", caller(1)
100 # Remove the named field from the object.
102 def delete_field(name)
103 @table.delete name.to_sym
106 InspectKey = :__inspect_key__ # :nodoc:
109 # Returns a string containing a detailed summary of the keys and values.
112 str = "#<#{self.class}"
114 Thread.current[InspectKey] ||= []
115 if Thread.current[InspectKey].include?(self) then
120 str << "," unless first
123 Thread.current[InspectKey] << v
125 str << " #{k}=#{v.inspect}"
127 Thread.current[InspectKey].pop
136 attr_reader :table # :nodoc:
140 # Compare this object and +other+ for equality.
143 return false unless(other.kind_of?(OpenStruct))
144 return @table == other.table