~ubuntu-branches/ubuntu/quantal/ruby1.9.1/quantal

« back to all changes in this revision

Viewing changes to lib/ostruct.rb

  • Committer: Bazaar Package Importer
  • Author(s): Lucas Nussbaum
  • Date: 2011-09-24 19:16:17 UTC
  • mfrom: (1.1.8 upstream) (13.1.7 experimental)
  • Revision ID: james.westby@ubuntu.com-20110924191617-o1qz4rcmqjot8zuy
Tags: 1.9.3~rc1-1
* New upstream release: 1.9.3 RC1.
  + Includes load.c fixes. Closes: #639959.
* Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
9
9
#
10
10
 
11
11
#
12
 
# OpenStruct allows you to create data objects and set arbitrary attributes.
13
 
# For example:
 
12
# An OpenStruct is a data structure, similar to a Hash, that allows the
 
13
# definition of arbitrary attributes with their accompanying values. This is
 
14
# accomplished by using Ruby's metaprogramming to define methods on the class
 
15
# itself.
 
16
#
 
17
# == Examples:
14
18
#
15
19
#   require 'ostruct'
16
20
#
17
 
#   record = OpenStruct.new
18
 
#   record.name    = "John Smith"
19
 
#   record.age     = 70
20
 
#   record.pension = 300
21
 
#
22
 
#   puts record.name     # -> "John Smith"
23
 
#   puts record.address  # -> nil
24
 
#
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.
27
 
#
28
 
#   hash = { "country" => "Australia", :population => 20_000_000 }
29
 
#   data = OpenStruct.new(hash)
30
 
#
31
 
#   p data        # -> <OpenStruct country="Australia" population=20000000>
 
21
#   person = OpenStruct.new
 
22
#   person.name    = "John Smith"
 
23
#   person.age     = 70
 
24
#   person.pension = 300
 
25
#
 
26
#   puts person.name     # -> "John Smith"
 
27
#   puts person.age      # -> 70
 
28
#   puts person.address  # -> nil
 
29
#
 
30
# An OpenStruct employs a Hash internally to store the methods and values and
 
31
# can even be initialized with one:
 
32
#
 
33
#   country_data = { :country => "Australia", :population => 20_000_000 }
 
34
#   australia = OpenStruct.new(country_data)
 
35
#   p australia   # -> <OpenStruct country="Australia" population=20000000>
 
36
#
 
37
# You may also define the hash in the initialization call:
 
38
#
 
39
#   australia = OpenStruct.new(:country => "Australia", :population => 20_000_000)
 
40
#   p australia   # -> <OpenStruct country="Australia" population=20000000>
 
41
#
 
42
# Hash keys with spaces or characters that would normally not be able to use for
 
43
# method calls (e.g. ()[]*) will not be immediately available on the
 
44
# OpenStruct object as a method for retrieval or assignment, but can be still be
 
45
# reached through the Object#send method.
 
46
#
 
47
#   measurements = OpenStruct.new("length (in inches)" => 24)
 
48
#   measurements.send("length (in inches)")  # -> 24
 
49
#
 
50
#   data_point = OpenStruct.new(:queued? => true)
 
51
#   data_point.queued?                       # -> true
 
52
#   data_point.send("queued?=",false)
 
53
#   data_point.queued?                       # -> false
 
54
#
 
55
# Removing the presence of a method requires the execution the delete_field
 
56
# method as setting the property value to +nil+ will not remove the method.
 
57
#
 
58
#   first_pet = OpenStruct.new(:name => 'Rowdy', :owner => 'John Smith')
 
59
#   first_pet.owner = nil
 
60
#   second_pet = OpenStruct.new(:name => 'Rowdy')
 
61
#
 
62
#   first_pet == second_pet   # -> false
 
63
#
 
64
#   first_pet.delete_field(:owner)
 
65
#   first_pet == second_pet   # -> true
 
66
#
 
67
#
 
68
# == Implementation:
 
69
#
 
70
# An OpenStruct utilizes Ruby's method lookup structure to and find and define
 
71
# the necessary methods for properties. This is accomplished through the method
 
72
# method_missing and define_method.
 
73
#
 
74
# This should be a consideration if there is a concern about the performance of
 
75
# the objects that are created, as there is much more overhead in the setting
 
76
# of these properties compared to using a Hash or a Struct.
32
77
#
33
78
class OpenStruct
34
79
  #
35
 
  # Create a new OpenStruct object.  The optional +hash+, if given, will
36
 
  # generate attributes and values.  For example.
 
80
  # Creates a new OpenStruct object.  By default, the resulting OpenStruct
 
81
  # object will have no attributes.
 
82
  #
 
83
  # The optional +hash+, if given, will generate attributes and values.
 
84
  # For example:
37
85
  #
38
86
  #   require 'ostruct'
39
87
  #   hash = { "country" => "Australia", :population => 20_000_000 }
41
89
  #
42
90
  #   p data        # -> <OpenStruct country="Australia" population=20000000>
43
91
  #
44
 
  # By default, the resulting OpenStruct object will have no attributes.
 
92
  # You may also define the hash in the initialization call:
 
93
  #
 
94
  #   australia = OpenStruct.new(:country => "Australia",
 
95
  #                              :population => 20_000_000)
 
96
  #   p australia   # -> <OpenStruct country="Australia" population=20000000>
45
97
  #
46
98
  def initialize(hash=nil)
47
99
    @table = {}
59
111
    @table = @table.dup
60
112
  end
61
113
 
 
114
  #
 
115
  # Provides marshalling support for use by the Marshal library. Returning the
 
116
  # underlying Hash table that contains the functions defined as the keys and
 
117
  # the values assigned to them.
 
118
  #
 
119
  #    require 'ostruct'
 
120
  #
 
121
  #    person = OpenStruct.new
 
122
  #    person.name = 'John Smith'
 
123
  #    person.age  = 70
 
124
  #
 
125
  #    person.marshal_dump # => { :name => 'John Smith', :age => 70 }
 
126
  #
62
127
  def marshal_dump
63
128
    @table
64
129
  end
 
130
 
 
131
  #
 
132
  # Provides marshalling support for use by the Marshal library. Accepting
 
133
  # a Hash of keys and values which will be used to populate the internal table
 
134
  #
 
135
  #    require 'ostruct'
 
136
  #
 
137
  #    event = OpenStruct.new
 
138
  #    hash = { 'time' => Time.now, 'title' => 'Birthday Party' }
 
139
  #    event.marshal_load(hash)
 
140
  #    event.title # => 'Birthday Party'
 
141
  #
65
142
  def marshal_load(x)
66
143
    @table = x
67
144
    @table.each_key{|key| new_ostruct_member(key)}
68
145
  end
69
146
 
 
147
  #
 
148
  # #modifiable is used internally to check if the OpenStruct is able to be
 
149
  # modified before granting access to the internal Hash table to be augmented.
 
150
  #
70
151
  def modifiable
71
152
    begin
72
153
      @modifiable = true
77
158
  end
78
159
  protected :modifiable
79
160
 
 
161
  #
 
162
  # new_ostruct_member is used internally to defined properties on the
 
163
  # OpenStruct. It does this by using the metaprogramming function
 
164
  # define_method for both the getter method and the setter method.
 
165
  #
80
166
  def new_ostruct_member(name)
81
167
    name = name.to_sym
82
168
    unless self.respond_to?(name)
91
177
  def method_missing(mid, *args) # :nodoc:
92
178
    mname = mid.id2name
93
179
    len = args.length
94
 
    if mname.chomp!('=')
 
180
    if mname.chomp!('=') && mid != :[]=
95
181
      if len != 1
96
182
        raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
97
183
      end
98
184
      modifiable[new_ostruct_member(mname)] = args[0]
99
 
    elsif len == 0
 
185
    elsif len == 0 && mid != :[]
100
186
      @table[mid]
101
187
    else
102
 
      raise NoMethodError, "undefined method `#{mname}' for #{self}", caller(1)
 
188
      raise NoMethodError, "undefined method `#{mid}' for #{self}", caller(1)
103
189
    end
104
190
  end
105
191
 
106
192
  #
107
 
  # Remove the named field from the object.
 
193
  # Remove the named field from the object. Returning the value that the field
 
194
  # contained if it has defined.
 
195
  #
 
196
  #   require 'ostruct'
 
197
  #
 
198
  #   person = OpenStruct.new('name' => 'John Smith', 'age' => 70)
 
199
  #
 
200
  #   person.delete_field('name')  # => 'John Smith'
108
201
  #
109
202
  def delete_field(name)
110
 
    @table.delete name.to_sym
 
203
    sym = name.to_sym
 
204
    @table.delete sym
 
205
    singleton_class.__send__(:remove_method, sym, "#{name}=")
111
206
  end
112
207
 
113
208
  InspectKey = :__inspect_key__ # :nodoc:
142
237
  protected :table
143
238
 
144
239
  #
145
 
  # Compare this object and +other+ for equality.
 
240
  # Compares this object and +other+ for equality.  An OpenStruct is equal to
 
241
  # +other+ when +other+ is an OpenStruct and the two object's Hash tables are
 
242
  # equal.
146
243
  #
147
244
  def ==(other)
148
245
    return false unless(other.kind_of?(OpenStruct))