sd_struct 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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: []