From 0dc342de848a642ecce8db697b8fecd83a63e117 Mon Sep 17 00:00:00 2001 From: yugui Date: Mon, 25 Aug 2008 15:02:05 +0000 Subject: added tag v1_9_0_4 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/tags/v1_9_0_4@18845 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- trunk/lib/ostruct.rb | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 trunk/lib/ostruct.rb (limited to 'trunk/lib/ostruct.rb') diff --git a/trunk/lib/ostruct.rb b/trunk/lib/ostruct.rb new file mode 100644 index 0000000000..f3ed01524b --- /dev/null +++ b/trunk/lib/ostruct.rb @@ -0,0 +1,147 @@ +# +# = ostruct.rb: OpenStruct implementation +# +# Author:: Yukihiro Matsumoto +# Documentation:: Gavin Sinclair +# +# OpenStruct allows the creation of data objects with arbitrary attributes. +# See OpenStruct for an example. +# + +# +# OpenStruct allows you to create data objects and set arbitrary attributes. +# For example: +# +# require 'ostruct' +# +# record = OpenStruct.new +# record.name = "John Smith" +# record.age = 70 +# record.pension = 300 +# +# puts record.name # -> "John Smith" +# puts record.address # -> nil +# +# It is like a hash with a different way to access the data. In fact, it is +# implemented with a hash, and you can initialize it with one. +# +# hash = { "country" => "Australia", :population => 20_000_000 } +# data = OpenStruct.new(hash) +# +# p data # -> +# +class OpenStruct + # + # Create a new OpenStruct object. The optional +hash+, if given, will + # generate attributes and values. For example. + # + # require 'ostruct' + # hash = { "country" => "Australia", :population => 20_000_000 } + # data = OpenStruct.new(hash) + # + # p data # -> + # + # By default, the resulting OpenStruct object will have no attributes. + # + def initialize(hash=nil) + @table = {} + if hash + for k,v in hash + @table[k.to_sym] = v + new_ostruct_member(k) + end + end + end + + # Duplicate an OpenStruct object members. + def initialize_copy(orig) + super + @table = @table.dup + end + + def marshal_dump + @table + end + def marshal_load(x) + @table = x + @table.each_key{|key| new_ostruct_member(key)} + end + + def new_ostruct_member(name) + name = name.to_sym + unless self.respond_to?(name) + class << self; self; end.class_eval do + define_method(name) { @table[name] } + define_method(:"#{name}=") { |x| @table[name] = x } + 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! + self.new_ostruct_member(mname) + @table[mname.intern] = args[0] + elsif len == 0 + @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.delete name.to_sym + end + + InspectKey = :__inspect_key__ # :nodoc: + + # + # Returns a string containing a detailed summary of the keys and values. + # + def inspect + str = "#<#{self.class}" + + Thread.current[InspectKey] ||= [] + if Thread.current[InspectKey].include?(self) then + str << " ..." + else + first = true + for k,v in @table + str << "," unless first + first = false + + Thread.current[InspectKey] << v + begin + str << " #{k}=#{v.inspect}" + ensure + Thread.current[InspectKey].pop + end + end + end + + str << ">" + end + alias :to_s :inspect + + attr_reader :table # :nodoc: + protected :table + + # + # Compare this object and +other+ for equality. + # + def ==(other) + return false unless(other.kind_of?(OpenStruct)) + return @table == other.table + end +end -- cgit v1.2.3