1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
#
# = 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 # -> <OpenStruct country="Australia" population=20000000>
#
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 # -> <OpenStruct country="Australia" population=20000000>
#
# 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 modifiable
begin
@modifiable = true
rescue
raise TypeError, "can't modify frozen #{self.class}", caller(3)
end
@table
end
protected :modifiable
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| modifiable[name] = x }
end
end
name
end
def method_missing(mid, *args) # :nodoc:
mname = mid.id2name
len = args.length
if mname.chomp!('=')
if len != 1
raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
end
modifiable[new_ostruct_member(mname)] = 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}"
ids = (Thread.current[InspectKey] ||= [])
if ids.include?(object_id)
return str << ' ...>'
end
ids << object_id
begin
first = true
for k,v in @table
str << "," unless first
first = false
str << " #{k}=#{v.inspect}"
end
return str << '>'
ensure
ids.pop
end
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
|