sd_struct 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7b543501f8aa5ae85ede78790fe9322e02329912
4
+ data.tar.gz: 307b9ffef98af9acd6bfb3220ecefac8d1b593b3
5
+ SHA512:
6
+ metadata.gz: 5677a893ed42b6c60dadd6d411931174a7b39ff6303452a3418961bc304cc9948ad01f60d886eaad2109162c1952e76f166e69a484fdd71d67e39339348aef61
7
+ data.tar.gz: cc7349a61ce9c5af6c9038a930e0e1fc13ea30091c2a546a02848b16c2461fdd9641413dfcae883d51fc88d31e601ff548a23d9234e879bf2b020178db05b877
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sd_struct.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2017 Adrian Setyadi
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,264 @@
1
+ # SDStruct
2
+
3
+ An alternative to OpenStruct that is stricter in assigning values and deeper in
4
+ consuming the passed Hash and transforming it back to Hash or JSON, equipped
5
+ with deep digging capabilities.
6
+
7
+ ## Usage
8
+
9
+ ### From JSON
10
+
11
+ Example of a response body in JSON.
12
+
13
+ ```JSON
14
+ {
15
+ "object": {
16
+ "a": "bau bau",
17
+ "c": "boo boo"
18
+ },
19
+ "array": [
20
+ {
21
+ "one": 1,
22
+ "two": 2,
23
+ "three": 3
24
+ }
25
+ ],
26
+ "two words": "Foo bar"
27
+ }
28
+ ```
29
+
30
+
31
+ > In OpenStruct, it's not obvious how to get a value with fields that contain spaces.
32
+ > Some people don't even know that it can be accessed.
33
+
34
+ ```ruby
35
+ ## with OpenStruct
36
+ o_struct = JSON.parse(response.body, object_class: OpenStruct)
37
+ # => #<OpenStruct object=#<OpenStruct a="bau bau", c="boo boo">,
38
+ # array=[#<OpenStruct one=1, two=2, three=3>], two words="Foo bar">
39
+
40
+ o_struct["two words"]
41
+ # => "Foo bar"
42
+
43
+
44
+ ## with SDStruct
45
+ sd_struct = JSON.parse(response.body, object_class: SDStruct)
46
+ # => #<SDStruct .object=#<SDStruct .a="bau bau", .c="boo boo">,
47
+ # .array=[#<SDStruct .one=1, .two=2, .three=3>], ['two words']="Foo bar">
48
+
49
+ sd_struct["two words"]
50
+ # => "Foo bar"
51
+ ```
52
+
53
+
54
+ > OpenStruct's `to_h` doesn't return a hash deeply.
55
+
56
+ ```ruby
57
+ ## OpenStruct
58
+ o_struct.to_h
59
+ # => {:object=>#<OpenStruct a="bau bau", c="boo boo">,
60
+ # :array=>[#<OpenStruct one=1, two=2, three=3>], :"two words"=>"Foo bar"}
61
+
62
+ ## SDStruct
63
+ sd_struct.to_h
64
+ # => {:object=>{:a=>"bau bau", :c=>"boo boo"},
65
+ # :array=>[{:one=>1, :two=>2, :three=>3}], "two words"=>"Foo bar"}
66
+ ```
67
+
68
+
69
+ > OpenStruct uses `method_missing` to create new field, while SDStruct prevent creation
70
+ > of new field using dot notation.
71
+
72
+ SDStruct prevent creation of new field using dot notation once it is initialized
73
+ to prevent assigning unintended field when you mistyped the key/field. SDStruct
74
+ is stricter in that way. However, SDStruct can also be lenient. You can use
75
+ square brackets when you want to assign a new field.
76
+
77
+ ```ruby
78
+ ## OpenStruct
79
+ o_struct.book = "title"
80
+ # => "title"
81
+
82
+ o_struct
83
+ # => #<OpenStruct object=#<OpenStruct a="bau bau", c="boo boo">,
84
+ # array=[#<OpenStruct one=1, two=2, three=3>], two words="Foo bar", book="title">
85
+
86
+
87
+ ## SDStruct
88
+ sd_struct.book = "title"
89
+ # => NoMethodError: undefined method `book=' for #<SDStruct:0x007ffa65b10a28>
90
+
91
+ sd_struct["book"] = "title"
92
+ # => "title"
93
+
94
+ sd_struct
95
+ # => #<SDStruct .object=#<SDStruct .a="bau bau", .c="boo boo">,
96
+ # .array=[#<SDStruct .one=1, .two=2, .three=3>], ['two words']="Foo bar", .book="title">
97
+ ```
98
+
99
+
100
+ > OpenStruct doesn't have search or deep digging functionalities
101
+
102
+ ```ruby
103
+ sd_struct.find('object/a')
104
+ # => "bau bau"
105
+
106
+ sd_struct.find('array/0/one')
107
+ # => 1
108
+
109
+ sd_struct.find('object->a', separator: '->')
110
+ # => "bau bau"
111
+
112
+ sd_struct.find('array.0.one', separator: '.')
113
+ # => 1
114
+
115
+ # You can push it to find deeper. It will return the first occurrence of the matched field
116
+ sd_struct.find('a')
117
+ # => "bau bau"
118
+
119
+ sd_struct.find('0/one')
120
+ # => 1
121
+
122
+ sd_struct.find('one')
123
+ # => 1
124
+
125
+ sd_struct.find('four')
126
+ # => nil
127
+
128
+ sd_struct.dig_deep(0, :one)
129
+ # => 1
130
+
131
+ sd_struct.dig_deep(:one)
132
+ # => 1
133
+ ```
134
+
135
+
136
+ > SDStruct is suitable for building JSON request body
137
+
138
+ You can parse a default JSON file for request body, fill it in, and only send
139
+ parts that are not empty.
140
+
141
+ ```ruby
142
+ # SDStruct also has `delete_field` method
143
+ sd_struct.delete_field(:book)
144
+ # => #<Class:#<SDStruct:0x007ffa65b10a28>>
145
+
146
+ sd_struct
147
+ # => #<SDStruct .object=#<SDStruct .a="bau bau", .c="boo boo">,
148
+ # .array=[#<SDStruct .one=1, .two=2, .three=3>], ['two words']="Foo bar">
149
+
150
+ sd_struct.find('0').one = 0
151
+ sd_struct.find('0').three = 0
152
+ sd_struct['two words'] = ""
153
+ sd_struct
154
+ # => #<SDStruct .object=#<SDStruct .a="bau bau", .c="boo boo">,
155
+ # .array=[#<SDStruct .one=0, .two=2, .three=0>], ['two words']="">
156
+ ```
157
+
158
+ By default, blank value, 0, [""], and [{}] are considered not important.
159
+ Therefore, keys with those values are excluded from the generated JSON string.
160
+
161
+ ```ruby
162
+ sd_struct.to_json
163
+ # => "{\"object\":{\"a\":\"bau bau\",\"c\":\"boo boo\"},\"array\":[{\"two\":2}]}"
164
+
165
+ sd_struct.find('0').two = 0
166
+ sd_struct.to_json
167
+ # => "{\"object\":{\"a\":\"bau bau\",\"c\":\"boo boo\"}}"
168
+ ```
169
+
170
+ However, you can include them if you want to by removing them from `:values_to_exclude` option.
171
+
172
+ ```ruby
173
+ sd_struct.to_json values_to_exclude: [[""], [{}]] # default to [0, [""], [{}]]
174
+ # => "{\"object\":{\"a\":\"bau bau\",\"c\":\"boo boo\"},\"array\":[{\"one\":0,\"two\":0,\"three\":0}]}"
175
+
176
+ sd_struct.to_json values_to_exclude: [[""], [{}]], exclude_blank_values: false # default to true
177
+ # => "{\"object\":{\"a\":\"bau bau\",\"c\":\"boo boo\"},\"array\":[{\"one\":0,\"two\":0,\"three\":0}],\"two words\":\"\"}"
178
+ ```
179
+
180
+ ### From Hash
181
+
182
+ Example of a Hash.
183
+
184
+ ```ruby
185
+ {
186
+ :object => {
187
+ :a => "bau bau",
188
+ :c => "boo boo"
189
+ },
190
+ :array => [
191
+ {
192
+ :one => 1,
193
+ :two => 2,
194
+ :three => 3
195
+ }
196
+ ],
197
+ "two words" => "Foo bar"
198
+ }
199
+ ```
200
+
201
+
202
+ > OpensStruct doesn't consume a hash deeply
203
+
204
+ ```ruby
205
+ ## with OpenStruct
206
+ o_struct = OpenStruct.new(hash)
207
+ # => #<OpenStruct object={:a=>"bau bau", :c=>"boo boo"},
208
+ # array=[{:one=>1, :two=>2, :three=>3}], two words="Foo bar">
209
+
210
+ ## with SDStruct
211
+ sd_struct = SDStruct.new(hash)
212
+ # => #<SDStruct .object=#<SDStruct .a="bau bau", .c="boo boo">,
213
+ # .array=[#<SDStruct .one=1, .two=2, .three=3>], ['two words']="Foo bar">
214
+ ```
215
+
216
+ ## Reserved Field Names
217
+
218
+ `dig`, `to_h`, `find`, `keys`, `marshal_dump`, `marshal_load`, `table`, `delete_field`,
219
+ `fields`, `dig_deep`, `new_member`, `spaced_keys`, `non_spaced_keys`, `delete_key`
220
+
221
+ ## Dependencies
222
+
223
+ ActiveSupport (if you use Rails, this should already be installed)
224
+
225
+ ### ActiveSupport Installation (for when you don't use Rails)
226
+
227
+ Add this line to your application's Gemfile:
228
+
229
+ ```ruby
230
+ gem 'activesupport'
231
+ ```
232
+
233
+ And then execute:
234
+
235
+ $ bundle
236
+
237
+ Or install it yourself as:
238
+
239
+ $ gem install activesupport
240
+
241
+
242
+ ## Installation
243
+
244
+ Add this line to your application's Gemfile:
245
+
246
+ ```ruby
247
+ gem 'sd_struct'
248
+ ```
249
+
250
+ And then execute:
251
+
252
+ $ bundle
253
+
254
+ Or install it yourself as:
255
+
256
+ $ gem install sd_struct
257
+
258
+ ## Contributing
259
+
260
+ 1. Fork it ( https://github.com/styd/sd_struct/fork )
261
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
262
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
263
+ 4. Push to the branch (`git push origin my-new-feature`)
264
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/lib/sd_struct.rb ADDED
@@ -0,0 +1,234 @@
1
+ require "sd_struct/version"
2
+
3
+
4
+ # Alternative to OpenStruct that is more strict and go deeper.
5
+ #
6
+ # @author Adrian Setyadi
7
+ #
8
+ class SDStruct
9
+ using Module.new {
10
+ refine Hash do
11
+ def to_struct
12
+ SDStruct.new(to_h.dup)
13
+ end
14
+ end
15
+
16
+ refine Array do
17
+ alias :original_to_h :to_h
18
+
19
+ def to_h(camelize_keys = false)
20
+ map{|x| x.respond_to?(:to_h) ? x.to_h(camelize_keys) : x }
21
+ end
22
+
23
+ # Call `to_struct` to an Array to go deeper or to a Hash to change it to SDStruct
24
+ #
25
+ # @return [Array<SDStruct,Object>] array of SDStruct or any other objects
26
+ #
27
+ def to_struct
28
+ map{|x| ( x.is_a?(Hash) || x.is_a?(Array) ) ? x.to_struct : x }
29
+ end
30
+
31
+ def dig_deep(*args)
32
+ full_args = args.dup
33
+ parent_key = args.shift
34
+ result = nil
35
+ if parent_key.is_a?(Integer)
36
+ result = dig(parent_key)
37
+ unless result.nil? || args.length.zero?
38
+ result = result.dig_deep(*args)
39
+ end
40
+ end
41
+ if result.nil?
42
+ each do |x|
43
+ if x.respond_to?(:dig_deep) || x.is_a?(Array)
44
+ result = x.dig_deep(*full_args)
45
+ end
46
+ return result unless result.nil?
47
+ end
48
+ end
49
+ return result
50
+ end
51
+ end
52
+ }
53
+
54
+ def initialize(hash = nil, deep = true)
55
+ @table = {}
56
+ if hash
57
+ hash.each_pair do |k, v|
58
+ v = v.to_struct if deep && ( v.is_a?(Hash) || v.is_a?(Array) )
59
+ @table[new_member(k)] = v
60
+ end
61
+ end
62
+ end
63
+
64
+ def initialize_copy(orig)
65
+ super
66
+ @table = @table.dup
67
+ end
68
+
69
+ def marshal_dump
70
+ to_h
71
+ end
72
+
73
+ def marshal_load(x)
74
+ @table = x.map{|a| ( a.is_a?(Hash) || a.is_a?(Array) ) ? a.to_struct : a }
75
+ .original_to_h
76
+ end
77
+
78
+ def to_h(opt = {})
79
+ opt = {
80
+ camelize_keys: false,
81
+ exclude_blank_values: false,
82
+ values_to_exclude: []
83
+ }.merge(opt)
84
+
85
+ @table.map do |k, v|
86
+ v = v.to_h(opt) if v.is_a?(self.class) || v.is_a?(Array)
87
+ k = k.to_s.camelize(:lower) if opt[:camelize_keys] && !k[/\s+/]
88
+ [k, v]
89
+ end.original_to_h
90
+ .select{|_,v| opt[:exclude_blank_values] ? v.present? : !v.nil? }
91
+ .select{|_,v| !v.in?(opt[:values_to_exclude]) }
92
+ end
93
+
94
+ def to_json(opt = {})
95
+ opt = {
96
+ camelize_keys: true,
97
+ exclude_blank_values: true,
98
+ values_to_exclude: [0, [""], [{}]]
99
+ }.merge(opt)
100
+
101
+ to_h(opt).to_json
102
+ end
103
+
104
+ def new_member(name)
105
+ name = name.to_s.underscore.to_sym unless name[/\s+/] # contains whitespace
106
+ unless respond_to?(name)
107
+ define_singleton_method(name) { @table[name] }
108
+ define_singleton_method("#{name}=") { |x| @table[name] = x }
109
+ end
110
+ name
111
+ end
112
+ protected :new_member
113
+
114
+ def [](name)
115
+ @table.has_key?(name) ? @table[name] : @table[name.to_s.underscore.to_sym]
116
+ end
117
+
118
+ def []=(name, value)
119
+ @table[new_member(name)] = value
120
+ end
121
+
122
+ InspectKey = :__inspect_key__ # :nodoc:
123
+
124
+ def inspect
125
+ str = "#<#{self.class}"
126
+
127
+ ids = (Thread.current[InspectKey] ||= [])
128
+ if ids.include?(object_id)
129
+ return str << ' ...>'
130
+ end
131
+
132
+ ids << object_id
133
+ begin
134
+ first = true
135
+ for k,v in @table
136
+ str << "," unless first
137
+ first = false
138
+ str << " #{k[/\s+/] ? "['#{k}']" : ".#{k}"}=#{v.inspect}"
139
+ end
140
+ return str << '>'
141
+ ensure
142
+ ids.pop
143
+ end
144
+ end
145
+ alias :to_s :inspect
146
+
147
+ def dig_deep(*args)
148
+ full_args = args.dup
149
+ parent_key = args.shift
150
+ result = dig(parent_key)
151
+ unless result.nil? || args.length.zero?
152
+ if result.respond_to?(:dig)
153
+ result = result.dig(*args)
154
+ end
155
+ end
156
+ if result.nil?
157
+ @table.values
158
+ .select{|v| v.respond_to?(:dig) }
159
+ .each do |v|
160
+ if v.respond_to?(:dig_deep) || v.is_a?(Array)
161
+ result = v.dig_deep(*full_args)
162
+ end
163
+ return result unless result.nil?
164
+ end
165
+ end
166
+ return result
167
+ end
168
+
169
+ def dig(*args)
170
+ @table.dig(*args)
171
+ end
172
+
173
+ def find(key_str, opt = {})
174
+ opt = {
175
+ separator: "/"
176
+ }.merge(opt)
177
+
178
+ args = key_str.split(opt[:separator])
179
+ .map do |x|
180
+ x.strip!
181
+ if !!(x =~ /\A[-+]?\d+\z/)
182
+ x.to_i
183
+ else
184
+ if x[/\s+/]
185
+ x
186
+ else
187
+ x.underscore.to_sym
188
+ end
189
+ end
190
+ end
191
+
192
+ result = dig_deep(*args) rescue nil
193
+ return result
194
+ end
195
+
196
+ attr_reader :table
197
+ protected :table
198
+
199
+ def ==(other)
200
+ return false unless other.kind_of?(self.class)
201
+ @table == other.table
202
+ end
203
+
204
+ def eql?(other)
205
+ return false unless other.kind_of?(self.class)
206
+ @table.eql?(other.table)
207
+ end
208
+
209
+ def hash
210
+ @table.hash
211
+ end
212
+
213
+ def spaced_keys
214
+ @table.keys - non_spaced_keys
215
+ end
216
+
217
+ def non_spaced_keys
218
+ methods(false).select{|x| x[/^\S+[^=]$/]}
219
+ end
220
+ alias :fields :non_spaced_keys
221
+
222
+ def keys
223
+ @table.keys
224
+ end
225
+
226
+ def delete_field(name)
227
+ sym = name.to_sym
228
+ @table.delete(sym) do
229
+ raise NameError.new("no field `#{sym}' in #{self}", sym)
230
+ end
231
+ singleton_class.__send__(:remove_method, sym, "#{sym}=")
232
+ end
233
+ alias :delete_key :delete_field
234
+ end
@@ -0,0 +1,3 @@
1
+ class SDStruct
2
+ VERSION = "0.0.3"
3
+ end
data/sd_struct.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sd_struct/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "sd_struct"
8
+ spec.version = SDStruct::VERSION
9
+ spec.authors = ["Adrian Setyadi"]
10
+ spec.email = ["a.styd@yahoo.com"]
11
+ spec.summary = %q{Stricter and Deeper Struct}
12
+ spec.description = %q{An alternative to OpenStruct that stricter in assigning values and deeper in
13
+ consuming the passed Hash and transforming it back to Hash or JSON, equipped
14
+ with deep digging capabilities.}
15
+ spec.homepage = ""
16
+ spec.license = "MIT"
17
+
18
+ spec.files = `git ls-files -z`.split("\x0")
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_runtime_dependency "activesupport", "~> 4", "> 4"
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.7"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sd_struct
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Adrian Setyadi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-04-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4'
20
+ - - ">"
21
+ - !ruby/object:Gem::Version
22
+ version: '4'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '4'
30
+ - - ">"
31
+ - !ruby/object:Gem::Version
32
+ version: '4'
33
+ - !ruby/object:Gem::Dependency
34
+ name: bundler
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.7'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.7'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '10.0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '10.0'
61
+ description: |-
62
+ An alternative to OpenStruct that stricter in assigning values and deeper in
63
+ consuming the passed Hash and transforming it back to Hash or JSON, equipped
64
+ with deep digging capabilities.
65
+ email:
66
+ - a.styd@yahoo.com
67
+ executables: []
68
+ extensions: []
69
+ extra_rdoc_files: []
70
+ files:
71
+ - ".gitignore"
72
+ - Gemfile
73
+ - LICENSE.txt
74
+ - README.md
75
+ - Rakefile
76
+ - lib/sd_struct.rb
77
+ - lib/sd_struct/version.rb
78
+ - sd_struct.gemspec
79
+ homepage: ''
80
+ licenses:
81
+ - MIT
82
+ metadata: {}
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 2.5.1
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: Stricter and Deeper Struct
103
+ test_files: []