ostruct 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d125c51b4a6541c0dcb5422065b685c156e847218380e2c01f1ef8fac08e40dc
4
+ data.tar.gz: 7c5aa451998687071f22794e2e24ea644e7a6698e4eebe608ccd42a6cdf3199c
5
+ SHA512:
6
+ metadata.gz: c58234c3f25e5eee4f47faf91c0016051e9bd72016d38a54248b1695424016d4cb46be9a09ef29837cd268cac57f0c7eebe1e5c330d218c580b304f1210764bc
7
+ data.tar.gz: 3698d2ab77b8c9904b43143795226e9f3abce36a55fc2923fc7ed65f4cf48d60790ec55e2f43d6bfb75c0f010aa23b32c08d73c00f6468420f4fc8131dce22dc
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ Gemfile.lock
@@ -0,0 +1,6 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.5.1
5
+ - ruby-head
6
+ before_install: gem install bundler -v 1.15.4
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in ostruct.gemspec
6
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
16
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
+ SUCH DAMAGE.
@@ -0,0 +1,69 @@
1
+ # OpenStruct
2
+
3
+ An OpenStruct is a data structure, similar to a Hash, that allows the definition of arbitrary attributes with their ccompanying values. This is accomplished by using Ruby's metaprogramming to define methods on the class itself.
4
+
5
+ ## Installation
6
+
7
+ The `ostruct` library comes pre-packaged with Ruby. No installation is necessary.
8
+
9
+ ## Usage
10
+
11
+ ```
12
+ require "ostruct"
13
+
14
+ person = OpenStruct.new
15
+ person.name = "John Smith"
16
+ person.age = 70
17
+
18
+ person.name # => "John Smith"
19
+ person.age # => 70
20
+ person.address # => nil
21
+ ```
22
+
23
+ An OpenStruct employs a Hash internally to store the attributes and values and can even be initialized with one:
24
+
25
+ ```
26
+ australia = OpenStruct.new(:country => "Australia", :capital => "Canberra")
27
+ # => #<OpenStruct country="Australia", capital="Canberra">
28
+ ```
29
+
30
+ Hash keys with spaces or characters that could normally not be used for method calls (e.g. <code>()[]*</code>) will not be immediately available on the OpenStruct object as a method for retrieval or assignment, but can still be reached through the Object#send method.
31
+
32
+ ```
33
+ measurements = OpenStruct.new("length (in inches)" => 24)
34
+ measurements.send("length (in inches)") # => 24
35
+
36
+ message = OpenStruct.new(:queued? => true)
37
+ message.queued? # => true
38
+ message.send("queued?=", false)
39
+ message.queued? # => false
40
+ ```
41
+
42
+ Removing the presence of an attribute requires the execution of the delete_field method as setting the property value to +nil+ will not remove the attribute.
43
+
44
+ ```
45
+ first_pet = OpenStruct.new(:name => "Rowdy", :owner => "John Smith")
46
+ second_pet = OpenStruct.new(:name => "Rowdy")
47
+
48
+ first_pet.owner = nil
49
+ first_pet # => #<OpenStruct name="Rowdy", owner=nil>
50
+ first_pet == second_pet # => false
51
+
52
+ first_pet.delete_field(:owner)
53
+ first_pet # => #<OpenStruct name="Rowdy">
54
+ first_pet == second_pet # => true
55
+ ```
56
+
57
+ ## Development
58
+
59
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
60
+
61
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
62
+
63
+ ## Contributing
64
+
65
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/ostruct.
66
+
67
+ ## License
68
+
69
+ The gem is available as open source under the terms of the [2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause).
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test" << "test/lib"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/test_*.rb']
8
+ end
9
+
10
+ task :default => [:test]
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "ostruct"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,369 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # = ostruct.rb: OpenStruct implementation
4
+ #
5
+ # Author:: Yukihiro Matsumoto
6
+ # Documentation:: Gavin Sinclair
7
+ #
8
+ # OpenStruct allows the creation of data objects with arbitrary attributes.
9
+ # See OpenStruct for an example.
10
+ #
11
+
12
+ #
13
+ # An OpenStruct is a data structure, similar to a Hash, that allows the
14
+ # definition of arbitrary attributes with their accompanying values. This is
15
+ # accomplished by using Ruby's metaprogramming to define methods on the class
16
+ # itself.
17
+ #
18
+ # == Examples
19
+ #
20
+ # require "ostruct"
21
+ #
22
+ # person = OpenStruct.new
23
+ # person.name = "John Smith"
24
+ # person.age = 70
25
+ #
26
+ # person.name # => "John Smith"
27
+ # person.age # => 70
28
+ # person.address # => nil
29
+ #
30
+ # An OpenStruct employs a Hash internally to store the attributes and values
31
+ # and can even be initialized with one:
32
+ #
33
+ # australia = OpenStruct.new(:country => "Australia", :capital => "Canberra")
34
+ # # => #<OpenStruct country="Australia", capital="Canberra">
35
+ #
36
+ # Hash keys with spaces or characters that could normally not be used for
37
+ # method calls (e.g. <code>()[]*</code>) will not be immediately available
38
+ # on the OpenStruct object as a method for retrieval or assignment, but can
39
+ # still be reached through the Object#send method.
40
+ #
41
+ # measurements = OpenStruct.new("length (in inches)" => 24)
42
+ # measurements.send("length (in inches)") # => 24
43
+ #
44
+ # message = OpenStruct.new(:queued? => true)
45
+ # message.queued? # => true
46
+ # message.send("queued?=", false)
47
+ # message.queued? # => false
48
+ #
49
+ # Removing the presence of an attribute requires the execution of the
50
+ # delete_field method as setting the property value to +nil+ will not
51
+ # remove the attribute.
52
+ #
53
+ # first_pet = OpenStruct.new(:name => "Rowdy", :owner => "John Smith")
54
+ # second_pet = OpenStruct.new(:name => "Rowdy")
55
+ #
56
+ # first_pet.owner = nil
57
+ # first_pet # => #<OpenStruct name="Rowdy", owner=nil>
58
+ # first_pet == second_pet # => false
59
+ #
60
+ # first_pet.delete_field(:owner)
61
+ # first_pet # => #<OpenStruct name="Rowdy">
62
+ # first_pet == second_pet # => true
63
+ #
64
+ #
65
+ # == Implementation
66
+ #
67
+ # An OpenStruct utilizes Ruby's method lookup structure to find and define the
68
+ # necessary methods for properties. This is accomplished through the methods
69
+ # method_missing and define_singleton_method.
70
+ #
71
+ # This should be a consideration if there is a concern about the performance of
72
+ # the objects that are created, as there is much more overhead in the setting
73
+ # of these properties compared to using a Hash or a Struct.
74
+ #
75
+ class OpenStruct
76
+
77
+ #
78
+ # Creates a new OpenStruct object. By default, the resulting OpenStruct
79
+ # object will have no attributes.
80
+ #
81
+ # The optional +hash+, if given, will generate attributes and values
82
+ # (can be a Hash, an OpenStruct or a Struct).
83
+ # For example:
84
+ #
85
+ # require "ostruct"
86
+ # hash = { "country" => "Australia", :capital => "Canberra" }
87
+ # data = OpenStruct.new(hash)
88
+ #
89
+ # data # => #<OpenStruct country="Australia", capital="Canberra">
90
+ #
91
+ def initialize(hash=nil)
92
+ @table = {}
93
+ if hash
94
+ hash.each_pair do |k, v|
95
+ k = k.to_sym
96
+ @table[k] = v
97
+ end
98
+ end
99
+ end
100
+
101
+ # Duplicates an OpenStruct object's Hash table.
102
+ def initialize_copy(orig) # :nodoc:
103
+ super
104
+ @table = @table.dup
105
+ end
106
+
107
+ #
108
+ # Converts the OpenStruct to a hash with keys representing
109
+ # each attribute (as symbols) and their corresponding values.
110
+ #
111
+ # require "ostruct"
112
+ # data = OpenStruct.new("country" => "Australia", :capital => "Canberra")
113
+ # data.to_h # => {:country => "Australia", :capital => "Canberra" }
114
+ #
115
+ def to_h
116
+ @table.dup
117
+ end
118
+
119
+ #
120
+ # :call-seq:
121
+ # ostruct.each_pair {|name, value| block } -> ostruct
122
+ # ostruct.each_pair -> Enumerator
123
+ #
124
+ # Yields all attributes (as symbols) along with the corresponding values
125
+ # or returns an enumerator if no block is given.
126
+ #
127
+ # require "ostruct"
128
+ # data = OpenStruct.new("country" => "Australia", :capital => "Canberra")
129
+ # data.each_pair.to_a # => [[:country, "Australia"], [:capital, "Canberra"]]
130
+ #
131
+ def each_pair
132
+ return to_enum(__method__) { @table.size } unless block_given?
133
+ @table.each_pair{|p| yield p}
134
+ self
135
+ end
136
+
137
+ #
138
+ # Provides marshalling support for use by the Marshal library.
139
+ #
140
+ def marshal_dump
141
+ @table
142
+ end
143
+
144
+ #
145
+ # Provides marshalling support for use by the Marshal library.
146
+ #
147
+ def marshal_load(x)
148
+ @table = x
149
+ end
150
+
151
+ #
152
+ # Used internally to check if the OpenStruct is able to be
153
+ # modified before granting access to the internal Hash table to be modified.
154
+ #
155
+ def modifiable? # :nodoc:
156
+ begin
157
+ @modifiable = true
158
+ rescue
159
+ exception_class = defined?(FrozenError) ? FrozenError : RuntimeError
160
+ raise exception_class, "can't modify frozen #{self.class}", caller(3)
161
+ end
162
+ @table
163
+ end
164
+ private :modifiable?
165
+
166
+ # ::Kernel.warn("do not use OpenStruct#modifiable", uplevel: 1)
167
+ alias modifiable modifiable? # :nodoc:
168
+ protected :modifiable
169
+
170
+ #
171
+ # Used internally to defined properties on the
172
+ # OpenStruct. It does this by using the metaprogramming function
173
+ # define_singleton_method for both the getter method and the setter method.
174
+ #
175
+ def new_ostruct_member!(name) # :nodoc:
176
+ name = name.to_sym
177
+ unless singleton_class.method_defined?(name)
178
+ define_singleton_method(name) { @table[name] }
179
+ define_singleton_method("#{name}=") {|x| modifiable?[name] = x}
180
+ end
181
+ name
182
+ end
183
+ private :new_ostruct_member!
184
+
185
+ # ::Kernel.warn("do not use OpenStruct#new_ostruct_member", uplevel: 1)
186
+ alias new_ostruct_member new_ostruct_member! # :nodoc:
187
+ protected :new_ostruct_member
188
+
189
+ def freeze
190
+ @table.each_key {|key| new_ostruct_member!(key)}
191
+ super
192
+ end
193
+
194
+ def respond_to_missing?(mid, include_private = false) # :nodoc:
195
+ mname = mid.to_s.chomp("=").to_sym
196
+ @table&.key?(mname) || super
197
+ end
198
+
199
+ def method_missing(mid, *args) # :nodoc:
200
+ len = args.length
201
+ if mname = mid[/.*(?==\z)/m]
202
+ if len != 1
203
+ raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
204
+ end
205
+ modifiable?[new_ostruct_member!(mname)] = args[0]
206
+ elsif len == 0 # and /\A[a-z_]\w*\z/ =~ mid #
207
+ if @table.key?(mid)
208
+ new_ostruct_member!(mid) unless frozen?
209
+ @table[mid]
210
+ end
211
+ else
212
+ begin
213
+ super
214
+ rescue NoMethodError => err
215
+ err.backtrace.shift
216
+ raise
217
+ end
218
+ end
219
+ end
220
+
221
+ #
222
+ # :call-seq:
223
+ # ostruct[name] -> object
224
+ #
225
+ # Returns the value of an attribute.
226
+ #
227
+ # require "ostruct"
228
+ # person = OpenStruct.new("name" => "John Smith", "age" => 70)
229
+ # person[:age] # => 70, same as person.age
230
+ #
231
+ def [](name)
232
+ @table[name.to_sym]
233
+ end
234
+
235
+ #
236
+ # :call-seq:
237
+ # ostruct[name] = obj -> obj
238
+ #
239
+ # Sets the value of an attribute.
240
+ #
241
+ # require "ostruct"
242
+ # person = OpenStruct.new("name" => "John Smith", "age" => 70)
243
+ # person[:age] = 42 # equivalent to person.age = 42
244
+ # person.age # => 42
245
+ #
246
+ def []=(name, value)
247
+ modifiable?[new_ostruct_member!(name)] = value
248
+ end
249
+
250
+ #
251
+ # :call-seq:
252
+ # ostruct.dig(name, ...) -> object
253
+ #
254
+ # Extracts the nested value specified by the sequence of +name+
255
+ # objects by calling +dig+ at each step, returning +nil+ if any
256
+ # intermediate step is +nil+.
257
+ #
258
+ # require "ostruct"
259
+ # address = OpenStruct.new("city" => "Anytown NC", "zip" => 12345)
260
+ # person = OpenStruct.new("name" => "John Smith", "address" => address)
261
+ #
262
+ # person.dig(:address, "zip") # => 12345
263
+ # person.dig(:business_address, "zip") # => nil
264
+ #
265
+ # data = OpenStruct.new(:array => [1, [2, 3]])
266
+ #
267
+ # data.dig(:array, 1, 0) # => 2
268
+ # data.dig(:array, 0, 0) # TypeError: Integer does not have #dig method
269
+ #
270
+ def dig(name, *names)
271
+ begin
272
+ name = name.to_sym
273
+ rescue NoMethodError
274
+ raise TypeError, "#{name} is not a symbol nor a string"
275
+ end
276
+ @table.dig(name, *names)
277
+ end
278
+
279
+ #
280
+ # Removes the named field from the object. Returns the value that the field
281
+ # contained if it was defined.
282
+ #
283
+ # require "ostruct"
284
+ #
285
+ # person = OpenStruct.new(name: "John", age: 70, pension: 300)
286
+ #
287
+ # person.delete_field("age") # => 70
288
+ # person # => #<OpenStruct name="John", pension=300>
289
+ #
290
+ # Setting the value to +nil+ will not remove the attribute:
291
+ #
292
+ # person.pension = nil
293
+ # person # => #<OpenStruct name="John", pension=nil>
294
+ #
295
+ def delete_field(name)
296
+ sym = name.to_sym
297
+ begin
298
+ singleton_class.remove_method(sym, "#{sym}=")
299
+ rescue NameError
300
+ end
301
+ @table.delete(sym) do
302
+ raise NameError.new("no field `#{sym}' in #{self}", sym)
303
+ end
304
+ end
305
+
306
+ InspectKey = :__inspect_key__ # :nodoc:
307
+
308
+ #
309
+ # Returns a string containing a detailed summary of the keys and values.
310
+ #
311
+ def inspect
312
+ ids = (Thread.current[InspectKey] ||= [])
313
+ if ids.include?(object_id)
314
+ detail = ' ...'
315
+ else
316
+ ids << object_id
317
+ begin
318
+ detail = @table.map do |key, value|
319
+ " #{key}=#{value.inspect}"
320
+ end.join(',')
321
+ ensure
322
+ ids.pop
323
+ end
324
+ end
325
+ ['#<', self.class, detail, '>'].join
326
+ end
327
+ alias :to_s :inspect
328
+
329
+ attr_reader :table # :nodoc:
330
+ protected :table
331
+ alias table! table
332
+
333
+ #
334
+ # Compares this object and +other+ for equality. An OpenStruct is equal to
335
+ # +other+ when +other+ is an OpenStruct and the two objects' Hash tables are
336
+ # equal.
337
+ #
338
+ # require "ostruct"
339
+ # first_pet = OpenStruct.new("name" => "Rowdy")
340
+ # second_pet = OpenStruct.new(:name => "Rowdy")
341
+ # third_pet = OpenStruct.new("name" => "Rowdy", :age => nil)
342
+ #
343
+ # first_pet == second_pet # => true
344
+ # first_pet == third_pet # => false
345
+ #
346
+ def ==(other)
347
+ return false unless other.kind_of?(OpenStruct)
348
+ @table == other.table!
349
+ end
350
+
351
+ #
352
+ # Compares this object and +other+ for equality. An OpenStruct is eql? to
353
+ # +other+ when +other+ is an OpenStruct and the two objects' Hash tables are
354
+ # eql?.
355
+ #
356
+ def eql?(other)
357
+ return false unless other.kind_of?(OpenStruct)
358
+ @table.eql?(other.table!)
359
+ end
360
+
361
+ # Computes a hash code for this OpenStruct.
362
+ # Two OpenStruct objects with the same content will have the same hash code
363
+ # (and will compare using #eql?).
364
+ #
365
+ # See also Object#hash.
366
+ def hash
367
+ @table.hash
368
+ end
369
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "ostruct"
5
+ spec.version = "0.1.0"
6
+ spec.authors = ["Marc-Andre Lafortune"]
7
+ spec.email = ["ruby-core@marc-andre.ca"]
8
+
9
+ spec.summary = %q{Class to build custom data structures, similar to a Hash.}
10
+ spec.description = %q{Class to build custom data structures, similar to a Hash.}
11
+ spec.homepage = "https://github.com/ruby/ostruct"
12
+ spec.license = "BSD-2-Clause"
13
+
14
+ spec.files = [".gitignore", ".travis.yml", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", "bin/console", "bin/setup", "lib/ostruct.rb", "ostruct.gemspec"]
15
+ spec.bindir = "exe"
16
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_development_dependency "bundler"
20
+ spec.add_development_dependency "rake"
21
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ostruct
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Marc-Andre Lafortune
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-12-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Class to build custom data structures, similar to a Hash.
42
+ email:
43
+ - ruby-core@marc-andre.ca
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - ".travis.yml"
50
+ - Gemfile
51
+ - LICENSE.txt
52
+ - README.md
53
+ - Rakefile
54
+ - bin/console
55
+ - bin/setup
56
+ - lib/ostruct.rb
57
+ - ostruct.gemspec
58
+ homepage: https://github.com/ruby/ostruct
59
+ licenses:
60
+ - BSD-2-Clause
61
+ metadata: {}
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubyforge_project:
78
+ rubygems_version: 2.7.6
79
+ signing_key:
80
+ specification_version: 4
81
+ summary: Class to build custom data structures, similar to a Hash.
82
+ test_files: []