hash_delegator 0.1.0
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 +7 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.travis.yml +8 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +59 -0
- data/LICENSE.txt +21 -0
- data/README.md +60 -0
- data/Rakefile +6 -0
- data/hash_delegator.gemspec +29 -0
- data/lib/core_ext.rb +13 -0
- data/lib/hash_delegator.rb +301 -0
- data/lib/hash_delegator/version.rb +3 -0
- metadata +59 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 62b082b39fe733c614750de7ae37885d846872e0867b34846bc9329db6b5f743
|
4
|
+
data.tar.gz: 7892a0389be4d989747fc2a330c86196d8744c90fb1dbbecedabaf009fa19171
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3138e6b948c4828b6bad9d3811e5cfe4eb18d83059f866a321166a93fbf766ca59701d959d835a3c807592b21d3af6294273bc647a3ccdb8871684e0f24a47c5
|
7
|
+
data.tar.gz: 4d5859d57253c4fd6dd7ad275d8ca785a38a907ede3c94712455069249649a9aa5b4543d2b6b7204d8cc61911dbf15152d22807232da276491df7ce80e446dd5
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
hash_delegator (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
ast (2.4.2)
|
10
|
+
diff-lcs (1.4.4)
|
11
|
+
parallel (1.20.1)
|
12
|
+
parser (3.0.1.1)
|
13
|
+
ast (~> 2.4.1)
|
14
|
+
rainbow (3.0.0)
|
15
|
+
rake (12.3.3)
|
16
|
+
regexp_parser (2.1.1)
|
17
|
+
rexml (3.2.5)
|
18
|
+
rspec (3.10.0)
|
19
|
+
rspec-core (~> 3.10.0)
|
20
|
+
rspec-expectations (~> 3.10.0)
|
21
|
+
rspec-mocks (~> 3.10.0)
|
22
|
+
rspec-core (3.10.1)
|
23
|
+
rspec-support (~> 3.10.0)
|
24
|
+
rspec-expectations (3.10.1)
|
25
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
26
|
+
rspec-support (~> 3.10.0)
|
27
|
+
rspec-mocks (3.10.2)
|
28
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
29
|
+
rspec-support (~> 3.10.0)
|
30
|
+
rspec-support (3.10.2)
|
31
|
+
rubocop (1.16.1)
|
32
|
+
parallel (~> 1.10)
|
33
|
+
parser (>= 3.0.0.0)
|
34
|
+
rainbow (>= 2.2.2, < 4.0)
|
35
|
+
regexp_parser (>= 1.8, < 3.0)
|
36
|
+
rexml
|
37
|
+
rubocop-ast (>= 1.7.0, < 2.0)
|
38
|
+
ruby-progressbar (~> 1.7)
|
39
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
40
|
+
rubocop-ast (1.7.0)
|
41
|
+
parser (>= 3.0.1.1)
|
42
|
+
rubocop-rspec (2.4.0)
|
43
|
+
rubocop (~> 1.0)
|
44
|
+
rubocop-ast (>= 1.1.0)
|
45
|
+
ruby-progressbar (1.11.0)
|
46
|
+
unicode-display_width (2.0.0)
|
47
|
+
|
48
|
+
PLATFORMS
|
49
|
+
ruby
|
50
|
+
|
51
|
+
DEPENDENCIES
|
52
|
+
hash_delegator!
|
53
|
+
rake (~> 12.0)
|
54
|
+
rspec (~> 3.0)
|
55
|
+
rubocop
|
56
|
+
rubocop-rspec
|
57
|
+
|
58
|
+
BUNDLED WITH
|
59
|
+
2.2.16
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2021 Delon Newman
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
[](https://travis-ci.com/delonnewman/hash_delegator)
|
2
|
+
|
3
|
+
# HashDelegator
|
4
|
+
|
5
|
+
Thread-safe immutable objects that provide delegation and basic validation to hashes.
|
6
|
+
|
7
|
+
## Synopsis
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
class Person < HashDelegator
|
11
|
+
require :first_name, :last_name
|
12
|
+
transform_keys(&:to_sym)
|
13
|
+
|
14
|
+
def name
|
15
|
+
"#{first_name} #{last_name}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
person = Person.new(first_name: "Mary", last_name: "Lamb", age: 32)
|
20
|
+
person.age # => 32
|
21
|
+
person.name # => "Mary Lamb"
|
22
|
+
|
23
|
+
# it supports all non-mutating methods of Hash
|
24
|
+
person.merge!(favorite_food: "Thai") # => NoMethodError
|
25
|
+
person.merge(favorite_food: "Thai") # => #<Person { first_name: "Mary", last_name: "Lamb", age: 32 }>
|
26
|
+
|
27
|
+
# respects inheritance
|
28
|
+
class Employee < Person
|
29
|
+
require :employee_id
|
30
|
+
end
|
31
|
+
|
32
|
+
Employee.new(age: 32, employee_id: 1234) # => Error, first_name attribute is required
|
33
|
+
Employee.new(first_name: "John", last_name: "Smith", age: 23, employee_id: 3456) # => #<Employee ...>
|
34
|
+
```
|
35
|
+
|
36
|
+
## Installation
|
37
|
+
|
38
|
+
Add this line to your application's Gemfile:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
gem 'hash_delegator'
|
42
|
+
```
|
43
|
+
|
44
|
+
And then execute:
|
45
|
+
|
46
|
+
$ bundle install
|
47
|
+
|
48
|
+
Or install it yourself as:
|
49
|
+
|
50
|
+
$ gem install hash_delegator
|
51
|
+
|
52
|
+
## See Also
|
53
|
+
|
54
|
+
- [Dry Struct](https://dry-rb.org/gems/dry-struct)
|
55
|
+
- [Clojure Records](https://clojure.org/reference/datatypes#_deftype_and_defrecord)
|
56
|
+
- [Delegator](https://rubyapi.org/3.0/o/delegator)
|
57
|
+
|
58
|
+
## License
|
59
|
+
|
60
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative 'lib/hash_delegator/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "hash_delegator"
|
5
|
+
spec.version = HashDelegator::VERSION
|
6
|
+
spec.authors = ["Delon Newman"]
|
7
|
+
spec.email = ["contact@delonnewman.name"]
|
8
|
+
|
9
|
+
spec.summary = %q{Method delegation to a hash}
|
10
|
+
spec.description = spec.summary
|
11
|
+
spec.homepage = "https://github.com/delonnewman/hash_delegator"
|
12
|
+
spec.license = "MIT"
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
14
|
+
|
15
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
16
|
+
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
19
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}#changelog"
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
24
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
25
|
+
end
|
26
|
+
spec.bindir = "exe"
|
27
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ["lib"]
|
29
|
+
end
|
data/lib/core_ext.rb
ADDED
@@ -0,0 +1,301 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
require 'core_ext'
|
5
|
+
require 'hash_delegator/version'
|
6
|
+
|
7
|
+
# Provides delegation and basic validation for Hashes
|
8
|
+
class HashDelegator
|
9
|
+
class << self
|
10
|
+
# Return required attributes or nil
|
11
|
+
#
|
12
|
+
# @return [Array, nil]
|
13
|
+
def required_attributes
|
14
|
+
return @required_attributes if @required_attributes
|
15
|
+
|
16
|
+
superclass.required_attributes if superclass.respond_to?(:required_attributes)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Specifiy required attributes
|
20
|
+
#
|
21
|
+
# @param attributes [Array]
|
22
|
+
# @return [HashDelegator]
|
23
|
+
def required(*attributes)
|
24
|
+
@required_attributes =
|
25
|
+
if superclass.respond_to?(:required_attributes) && !superclass.required_attributes.nil?
|
26
|
+
superclass.required_attributes + attributes
|
27
|
+
else
|
28
|
+
attributes
|
29
|
+
end
|
30
|
+
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
# @deprecated
|
35
|
+
def require(*attributes)
|
36
|
+
warn 'HashDelegator.require is deprecated'
|
37
|
+
required(*attrbutes)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Specify the default value if the value is a Proc or a block is passed
|
41
|
+
# each hash's default_proc attribute will be set.
|
42
|
+
#
|
43
|
+
# @param value [Object] default value
|
44
|
+
# @param block [Proc] default proc
|
45
|
+
# @return [HashDelegator]
|
46
|
+
def default(value = nil, &block)
|
47
|
+
if block
|
48
|
+
@default_value = block
|
49
|
+
return self
|
50
|
+
end
|
51
|
+
|
52
|
+
if value.is_a?(Proc) && value.lambda? && value.arity != 2
|
53
|
+
lambda = value
|
54
|
+
value = ->(*args) { lambda.call(*args.slice(0, lambda.arity)) }
|
55
|
+
end
|
56
|
+
|
57
|
+
@default_value = value
|
58
|
+
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
# Return the default value
|
63
|
+
def default_value
|
64
|
+
return @default_value if @default_value
|
65
|
+
|
66
|
+
superclass.default_value if superclass.respond_to?(:default_value)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Specify the key transformer
|
70
|
+
def transform_keys(&block)
|
71
|
+
@key_transformer = block
|
72
|
+
end
|
73
|
+
|
74
|
+
# Return the key transformer
|
75
|
+
def key_transformer
|
76
|
+
return @key_transformer if @key_transformer
|
77
|
+
|
78
|
+
superclass.key_transformer if superclass.respond_to?(:key_transformer)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Methods that mutate the internal hash, these cannot be called publicly.
|
83
|
+
MUTATING_METHODS = Set[
|
84
|
+
:clear,
|
85
|
+
:delete,
|
86
|
+
:update,
|
87
|
+
:delete_if,
|
88
|
+
:keep_if,
|
89
|
+
:compact!,
|
90
|
+
:filter!,
|
91
|
+
:merge!,
|
92
|
+
:reject!,
|
93
|
+
:select!,
|
94
|
+
:transform_keys!,
|
95
|
+
:transform_values!,
|
96
|
+
:default=,
|
97
|
+
:default_proc=,
|
98
|
+
:compare_by_identity,
|
99
|
+
:rehash,
|
100
|
+
:replace,
|
101
|
+
:initialize_copy,
|
102
|
+
:shift,
|
103
|
+
:store
|
104
|
+
].freeze
|
105
|
+
|
106
|
+
# Methods that are closed (in the algebraic sense) meaning that
|
107
|
+
# they will not remove required keys.
|
108
|
+
CLOSED_METHODS = Set[
|
109
|
+
:compact,
|
110
|
+
:merge
|
111
|
+
].freeze
|
112
|
+
|
113
|
+
EMPTY_HASH = {}.freeze
|
114
|
+
private_constant :EMPTY_HASH
|
115
|
+
|
116
|
+
# Initialize the HashDelegator with the given hash.
|
117
|
+
# If the hash is not frozen it will be duplicated. If a key transformer
|
118
|
+
# is specified the hashes keys will be processed with it (duplicating the original hash).
|
119
|
+
# The hash will be validated for the existance of the required attributes (note
|
120
|
+
# that a key with a nil value still exists in the hash).
|
121
|
+
#
|
122
|
+
#
|
123
|
+
# @param hash [Hash]
|
124
|
+
def initialize(hash = EMPTY_HASH)
|
125
|
+
raise 'HashDelegator should not be initialized' if instance_of?(HashDelegator)
|
126
|
+
|
127
|
+
@hash =
|
128
|
+
if self.class.key_transformer
|
129
|
+
hash.transform_keys(&self.class.key_transformer)
|
130
|
+
elsif hash.frozen?
|
131
|
+
hash
|
132
|
+
else
|
133
|
+
hash.dup
|
134
|
+
end
|
135
|
+
|
136
|
+
if self.class.default_value.is_a?(Proc)
|
137
|
+
@hash.default_proc = self.class.default_value
|
138
|
+
else
|
139
|
+
@hash.default = self.class.default_value
|
140
|
+
end
|
141
|
+
|
142
|
+
if self.class.required_attributes
|
143
|
+
self.class.required_attributes.each do |attribute|
|
144
|
+
attribute = self.class.key_transformer.call(attribute) if self.class.key_transformer
|
145
|
+
raise "#{attribute.inspect} is required, but is missing" unless key?(attribute)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# If the given keys include any required attributes
|
151
|
+
# the hash will be duplicated and except will be called
|
152
|
+
# on the duplicated hash. Otherwise a new instance of
|
153
|
+
# the HashDelegator will be return without the specified keys.
|
154
|
+
#
|
155
|
+
# @param keys [Array]
|
156
|
+
# @return [Hash, HashDelegator]
|
157
|
+
def except(*keys)
|
158
|
+
common = keys & self.class.required_attributes
|
159
|
+
|
160
|
+
if common.empty?
|
161
|
+
self.class.new(@hash.except(*keys))
|
162
|
+
else
|
163
|
+
to_hash.except(*keys)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
# If the given keys include all of the required attributes
|
168
|
+
# a new HashDelegator will be returned with only the specified keys.
|
169
|
+
# Otherwise a internal hash will be duplicated and slice will
|
170
|
+
# be called on the duplicated hash.
|
171
|
+
#
|
172
|
+
# @param keys [Array]
|
173
|
+
# @return [Hash, HashDelegator]
|
174
|
+
def slice(*keys)
|
175
|
+
required = self.class.required_attributes
|
176
|
+
common = keys & required
|
177
|
+
|
178
|
+
if keys.size == common.size && common.size == required.size
|
179
|
+
self.class.new(@hash.slice(*keys))
|
180
|
+
else
|
181
|
+
to_hash.slice(*keys)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Return a duplicate of the delegated hash.
|
186
|
+
#
|
187
|
+
# @return [Hash]
|
188
|
+
def to_hash
|
189
|
+
@hash.dup
|
190
|
+
end
|
191
|
+
alias to_h to_hash
|
192
|
+
|
193
|
+
def to_s
|
194
|
+
"#<#{self.class} #{@hash.inspect}>"
|
195
|
+
end
|
196
|
+
alias inspect to_s
|
197
|
+
|
198
|
+
# Return the value associated with the given key. If a key transformer
|
199
|
+
# is special the key will be transformed first. If the key is missing
|
200
|
+
# the default value will be return (nil unless specified).
|
201
|
+
#
|
202
|
+
# @param key
|
203
|
+
def [](key)
|
204
|
+
if self.class.key_transformer
|
205
|
+
@hash[self.class.key_transformer.call(key)]
|
206
|
+
else
|
207
|
+
@hash[key]
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# Return the numerical hash of the decorated hash.
|
212
|
+
#
|
213
|
+
# @return [Integer]
|
214
|
+
def hash
|
215
|
+
@hash.hash
|
216
|
+
end
|
217
|
+
|
218
|
+
# Return true if the other object has the same numerical hash
|
219
|
+
# as this object.
|
220
|
+
#
|
221
|
+
# @return [Boolean]
|
222
|
+
def eql?(other)
|
223
|
+
@hash.hash == other.hash
|
224
|
+
end
|
225
|
+
|
226
|
+
# Return true if the other object has all of this objects required attributes.
|
227
|
+
#
|
228
|
+
# @param other
|
229
|
+
def ===(other)
|
230
|
+
required = self.class.required_attributes
|
231
|
+
|
232
|
+
other.respond_to?(:keys) && (common = other.keys & required) &&
|
233
|
+
common.size == other.keys.size && common.size == required.size
|
234
|
+
end
|
235
|
+
|
236
|
+
# Return true if the other object is of the same class and the
|
237
|
+
# numerical hash of the other object and this object are equal.
|
238
|
+
#
|
239
|
+
# @param other
|
240
|
+
#
|
241
|
+
# @return [Boolean]
|
242
|
+
def ==(other)
|
243
|
+
other.instance_of?(self.class) && eql?(other)
|
244
|
+
end
|
245
|
+
|
246
|
+
# Return true if the superclass responds to the method
|
247
|
+
# or if the method is a key of the internal hash or
|
248
|
+
# if the hash responds to this method. Otherwise return false.
|
249
|
+
#
|
250
|
+
# @note DO NOT USE DIRECTLY
|
251
|
+
#
|
252
|
+
# @see Object#respond_to?
|
253
|
+
# @see Object#respond_to_missing?
|
254
|
+
#
|
255
|
+
# @param method [Symbol]
|
256
|
+
# @param include_all [Boolean]
|
257
|
+
def respond_to_missing?(method, include_all)
|
258
|
+
super || key?(method) || hash_respond_to?(method)
|
259
|
+
end
|
260
|
+
|
261
|
+
# If the method is a key of the internal hash return it's value.
|
262
|
+
# If the internal hash responds to the method forward the method
|
263
|
+
# to the hash. If the method is 'closed' retrun a new HashDelegator
|
264
|
+
# otherwise return the raw result. If none of these conditions hold
|
265
|
+
# call the superclass' method_missing.
|
266
|
+
#
|
267
|
+
# @see CLOSED_METHODS
|
268
|
+
# @see Object#method_missing
|
269
|
+
#
|
270
|
+
# @param method [Symbol]
|
271
|
+
# @param args [Array]
|
272
|
+
# @param block [Proc]
|
273
|
+
def method_missing(method, *args, &block)
|
274
|
+
return @hash[method] if @hash.key?(method)
|
275
|
+
|
276
|
+
if hash_respond_to?(method)
|
277
|
+
result = @hash.public_send(method, *args, &block)
|
278
|
+
return result unless CLOSED_METHODS.include?(method)
|
279
|
+
|
280
|
+
return self.class.new(result)
|
281
|
+
end
|
282
|
+
|
283
|
+
super
|
284
|
+
end
|
285
|
+
|
286
|
+
private
|
287
|
+
|
288
|
+
def hash_respond_to?(method)
|
289
|
+
!MUTATING_METHODS.include?(method) && @hash.respond_to?(method)
|
290
|
+
end
|
291
|
+
|
292
|
+
protected
|
293
|
+
|
294
|
+
# Set the key of the internal hash to the given value.
|
295
|
+
#
|
296
|
+
# @param key
|
297
|
+
# @param value
|
298
|
+
def []=(key, value)
|
299
|
+
@hash[key] = value
|
300
|
+
end
|
301
|
+
end
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hash_delegator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Delon Newman
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-06-14 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Method delegation to a hash
|
14
|
+
email:
|
15
|
+
- contact@delonnewman.name
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- ".gitignore"
|
21
|
+
- ".rspec"
|
22
|
+
- ".travis.yml"
|
23
|
+
- Gemfile
|
24
|
+
- Gemfile.lock
|
25
|
+
- LICENSE.txt
|
26
|
+
- README.md
|
27
|
+
- Rakefile
|
28
|
+
- hash_delegator.gemspec
|
29
|
+
- lib/core_ext.rb
|
30
|
+
- lib/hash_delegator.rb
|
31
|
+
- lib/hash_delegator/version.rb
|
32
|
+
homepage: https://github.com/delonnewman/hash_delegator
|
33
|
+
licenses:
|
34
|
+
- MIT
|
35
|
+
metadata:
|
36
|
+
allowed_push_host: https://rubygems.org
|
37
|
+
homepage_uri: https://github.com/delonnewman/hash_delegator
|
38
|
+
source_code_uri: https://github.com/delonnewman/hash_delegator
|
39
|
+
changelog_uri: https://github.com/delonnewman/hash_delegator#changelog
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: 2.3.0
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
requirements: []
|
55
|
+
rubygems_version: 3.1.6
|
56
|
+
signing_key:
|
57
|
+
specification_version: 4
|
58
|
+
summary: Method delegation to a hash
|
59
|
+
test_files: []
|