wrest 4.0.0-universal-java-18

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.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +169 -0
  3. data/LICENCE +7 -0
  4. data/README.md +436 -0
  5. data/bin/wrest +4 -0
  6. data/bin/wrest_shell.rb +23 -0
  7. data/lib/wrest/async_request/event_machine_backend.rb +32 -0
  8. data/lib/wrest/async_request/thread_backend.rb +34 -0
  9. data/lib/wrest/async_request/thread_pool.rb +29 -0
  10. data/lib/wrest/async_request.rb +51 -0
  11. data/lib/wrest/cache_proxy.rb +119 -0
  12. data/lib/wrest/caching/memcached.rb +37 -0
  13. data/lib/wrest/caching/redis.rb +38 -0
  14. data/lib/wrest/caching.rb +57 -0
  15. data/lib/wrest/callback.rb +70 -0
  16. data/lib/wrest/components/container/alias_accessors.rb +70 -0
  17. data/lib/wrest/components/container/typecaster.rb +178 -0
  18. data/lib/wrest/components/container.rb +204 -0
  19. data/lib/wrest/components/mutators/base.rb +65 -0
  20. data/lib/wrest/components/mutators/camel_to_snake_case.rb +26 -0
  21. data/lib/wrest/components/mutators/xml_type_caster.rb +56 -0
  22. data/lib/wrest/components/mutators.rb +42 -0
  23. data/lib/wrest/components/translators/content_types.rb +25 -0
  24. data/lib/wrest/components/translators/json.rb +36 -0
  25. data/lib/wrest/components/translators/txt.rb +35 -0
  26. data/lib/wrest/components/translators/xml/conversions.rb +56 -0
  27. data/lib/wrest/components/translators/xml.rb +77 -0
  28. data/lib/wrest/components/translators.rb +30 -0
  29. data/lib/wrest/components.rb +22 -0
  30. data/lib/wrest/core_ext/hash/conversions.rb +45 -0
  31. data/lib/wrest/core_ext/hash.rb +7 -0
  32. data/lib/wrest/core_ext/string/conversions.rb +38 -0
  33. data/lib/wrest/core_ext/string.rb +7 -0
  34. data/lib/wrest/exceptions.rb +38 -0
  35. data/lib/wrest/hash_with_case_insensitive_access.rb +52 -0
  36. data/lib/wrest/hash_with_indifferent_access.rb +442 -0
  37. data/lib/wrest/http_codes.rb +83 -0
  38. data/lib/wrest/http_shared/headers.rb +345 -0
  39. data/lib/wrest/http_shared/standard_headers.rb +22 -0
  40. data/lib/wrest/http_shared/standard_tokens.rb +21 -0
  41. data/lib/wrest/http_shared.rb +25 -0
  42. data/lib/wrest/multipart.rb +84 -0
  43. data/lib/wrest/native/connection_factory.rb +28 -0
  44. data/lib/wrest/native/delete.rb +27 -0
  45. data/lib/wrest/native/get.rb +83 -0
  46. data/lib/wrest/native/options.rb +27 -0
  47. data/lib/wrest/native/patch.rb +27 -0
  48. data/lib/wrest/native/post.rb +27 -0
  49. data/lib/wrest/native/post_multipart.rb +36 -0
  50. data/lib/wrest/native/put.rb +27 -0
  51. data/lib/wrest/native/put_multipart.rb +36 -0
  52. data/lib/wrest/native/redirection.rb +39 -0
  53. data/lib/wrest/native/request.rb +161 -0
  54. data/lib/wrest/native/response.rb +278 -0
  55. data/lib/wrest/native/session.rb +66 -0
  56. data/lib/wrest/native.rb +36 -0
  57. data/lib/wrest/test/request_patches.rb +12 -0
  58. data/lib/wrest/test.rb +3 -0
  59. data/lib/wrest/uri/builders.rb +48 -0
  60. data/lib/wrest/uri.rb +312 -0
  61. data/lib/wrest/uri_template.rb +63 -0
  62. data/lib/wrest/utils.rb +129 -0
  63. data/lib/wrest/version.rb +14 -0
  64. data/lib/wrest.rb +77 -0
  65. data/lib/wrest_no_ext.rb +7 -0
  66. metadata +286 -0
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2009 Sidu Ponnappa
4
+
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8
+ # Unless required by applicable law or agreed to in writing, software distributed under the License
9
+ # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and limitations under the License.
11
+
12
+ module Wrest
13
+ module CoreExt # :nodoc:
14
+ module Hash # :nodoc:
15
+ # Makes it easier to build other objects from a Hash
16
+ module Conversions
17
+ # This method accepts a hash mutator (found in Wrest::Compononents)
18
+ # to build a new hash map by making changes to an existing one.
19
+ #
20
+ # No, this method does not mutate the state of the hash it is invoked on,
21
+ # but rather builds a new one.
22
+ #
23
+ # Yes, the name is misleading in that respect. However, one
24
+ # hopes the absence of an exclamation mark will increase clarity.
25
+ #
26
+ # Uses include mutating the hash produced by deserialising xml
27
+ # by using the meta data in the hash to type cast values.
28
+ #
29
+ # Example:
30
+ # "http://search.yahooapis.com/NewsSearchService/V1/newsSearch".to_uri.get(
31
+ # :appid => 'YahooDemo',
32
+ # :output => 'xml',
33
+ # :query => 'India',
34
+ # :results=> '3',
35
+ # :start => '1'
36
+ # ).deserialise.mutate_using(XmlTypeCaster.new)
37
+ def mutate_using(mutator)
38
+ mutated_hash = {}
39
+ each { |tuple| mutated_hash.store(*mutator.mutate(tuple)) }
40
+ mutated_hash
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'wrest/core_ext/hash/conversions'
4
+
5
+ class Hash # :nodoc:
6
+ include Wrest::CoreExt::Hash::Conversions
7
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2009 Sidu Ponnappa
4
+
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8
+ # Unless required by applicable law or agreed to in writing, software distributed under the License
9
+ # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and limitations under the License.
11
+
12
+ module Wrest
13
+ module CoreExt # :nodoc:
14
+ module String # :nodoc:
15
+ # Makes it easier to build other objects from a String
16
+ # This module is opt-out - if you don't want the to_uri
17
+ # and to_uri_template convenience method on String, set
18
+ # the NoStringExtensions constant on the Wrest module
19
+ # before requiring wrest.
20
+ #
21
+ # module Wrest
22
+ # NoStringExtensions = true
23
+ # end
24
+ # require 'wrest'
25
+ module Conversions
26
+ # A convenience method equivalent to Wrest::Uri.new(string)
27
+ def to_uri(options = {})
28
+ Wrest::Uri.new(strip, options)
29
+ end
30
+
31
+ # A convenience method equivalent to Wrest:UriTemplate.new(uri_pattern)
32
+ def to_uri_template(options = {})
33
+ Wrest::UriTemplate.new(strip, options)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'wrest/core_ext/string/conversions'
4
+
5
+ class String # :nodoc:
6
+ include Wrest::CoreExt::String::Conversions unless Wrest.const_defined?('NoStringExtensions')
7
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wrest
4
+ module Exceptions # :nodoc:
5
+ # Raised when a base method that should be overriden
6
+ # is invoked on a subclass that has not implemented it.
7
+ class MethodNotOverridden < StandardError
8
+ end
9
+
10
+ # Raised when a translator for an unregisterd response content type
11
+ # is requested. See Translators.
12
+ class UnsupportedContentType < StandardError
13
+ end
14
+
15
+ # Raised when a request auto redirects more times than are allowed
16
+ # by its follow_redirects_limit. See Wrest::Native::Redirection.
17
+ class AutoRedirectLimitExceeded < StandardError
18
+ end
19
+
20
+ # Raised when a request is made when either RAILS_ENV or
21
+ # ENV['RAILS_ENV'] is set to 'test', which is the case when
22
+ # running tests/specs in a Rails application.
23
+ #
24
+ # See wrest/test/request_patches.
25
+ class RealRequestMadeInTestEnvironmet < StandardError
26
+ end
27
+
28
+ # Raised when a request times out
29
+ class Timeout < StandardError
30
+ end
31
+
32
+ class UnsupportedHttpVerb < StandardError
33
+ end
34
+
35
+ class UnsupportedFeature < StandardError
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wrest
4
+ # A hash with case-insensitive key access.
5
+ #
6
+ # hash = Wrest::HashWithCaseInsensitiveAccess.new 'Abcd' => 1, 'xyz' => 2
7
+ #
8
+ # hash['abcd'] #=> 1
9
+ # hash['aBCd'] #=> 1
10
+ #
11
+ class HashWithCaseInsensitiveAccess < ::Hash # :nodoc:
12
+ def initialize(hash = {})
13
+ super()
14
+ hash.each do |key, value|
15
+ self[convert_key(key)] = value
16
+ end
17
+ end
18
+
19
+ def [](key)
20
+ super(convert_key(key))
21
+ end
22
+
23
+ def []=(key, value)
24
+ super(convert_key(key), value)
25
+ end
26
+
27
+ def delete(key)
28
+ super(convert_key(key))
29
+ end
30
+
31
+ def values_at(*indices)
32
+ indices.collect { |key| self[convert_key(key)] }
33
+ end
34
+
35
+ def merge(other)
36
+ dup.merge!(other)
37
+ end
38
+
39
+ def merge!(other)
40
+ other.each do |key, value|
41
+ self[convert_key(key)] = value
42
+ end
43
+ self
44
+ end
45
+
46
+ protected
47
+
48
+ def convert_key(key)
49
+ key.is_a?(String) ? key.downcase : key
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,442 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wrest
4
+ # https://github.com/rails/rails/commit/1dcad65f8075d5b766082d3fbabdcb20fecb4ccd
5
+ # Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered
6
+ # to be the same.
7
+ #
8
+ # rgb = ActiveSupport::HashWithIndifferentAccess.new
9
+ #
10
+ # rgb[:black] = '#000000'
11
+ # rgb[:black] # => '#000000'
12
+ # rgb['black'] # => '#000000'
13
+ #
14
+ # rgb['white'] = '#FFFFFF'
15
+ # rgb[:white] # => '#FFFFFF'
16
+ # rgb['white'] # => '#FFFFFF'
17
+ #
18
+ # Internally symbols are mapped to strings when used as keys in the entire
19
+ # writing interface (calling <tt>[]=</tt>, <tt>merge</tt>, etc). This
20
+ # mapping belongs to the public interface. For example, given:
21
+ #
22
+ # hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1)
23
+ #
24
+ # You are guaranteed that the key is returned as a string:
25
+ #
26
+ # hash.keys # => ["a"]
27
+ #
28
+ # Technically other types of keys are accepted:
29
+ #
30
+ # hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1)
31
+ # hash[0] = 0
32
+ # hash # => {"a"=>1, 0=>0}
33
+ #
34
+ # but this class is intended for use cases where strings or symbols are the
35
+ # expected keys and it is convenient to understand both as the same. For
36
+ # example the +params+ hash in Ruby on Rails.
37
+ #
38
+ # Note that core extensions define <tt>Hash#with_indifferent_access</tt>:
39
+ #
40
+ # rgb = { black: '#000000', white: '#FFFFFF' }.with_indifferent_access
41
+ #
42
+ # which may be handy.
43
+ #
44
+ class HashWithIndifferentAccess < Hash
45
+ # Returns +true+ so that <tt>Array#extract_options!</tt> finds members of
46
+ # this class.
47
+ def extractable_options?
48
+ true
49
+ end
50
+
51
+ def with_indifferent_access
52
+ dup
53
+ end
54
+
55
+ def nested_under_indifferent_access
56
+ self
57
+ end
58
+
59
+ def initialize(constructor = nil)
60
+ if constructor.respond_to?(:to_hash)
61
+ super()
62
+ update(constructor)
63
+
64
+ hash = constructor.is_a?(Hash) ? constructor : constructor.to_hash
65
+ self.default = hash.default if hash.default
66
+ self.default_proc = hash.default_proc if hash.default_proc
67
+ elsif constructor.nil?
68
+ super()
69
+ else
70
+ super(constructor)
71
+ end
72
+ end
73
+
74
+ def self.[](*args)
75
+ new.merge!(Hash[*args])
76
+ end
77
+
78
+ alias regular_writer []= unless method_defined?(:regular_writer)
79
+ alias regular_update update unless method_defined?(:regular_update)
80
+
81
+ # Assigns a new value to the hash:
82
+ #
83
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
84
+ # hash[:key] = 'value'
85
+ #
86
+ # This value can be later fetched using either +:key+ or <tt>'key'</tt>.
87
+ def []=(key, value)
88
+ regular_writer(convert_key(key), convert_value(value, conversion: :assignment))
89
+ end
90
+
91
+ alias store []=
92
+
93
+ # Updates the receiver in-place, merging in the hashes passed as arguments:
94
+ #
95
+ # hash_1 = ActiveSupport::HashWithIndifferentAccess.new
96
+ # hash_1[:key] = 'value'
97
+ #
98
+ # hash_2 = ActiveSupport::HashWithIndifferentAccess.new
99
+ # hash_2[:key] = 'New Value!'
100
+ #
101
+ # hash_1.update(hash_2) # => {"key"=>"New Value!"}
102
+ #
103
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
104
+ # hash.update({ "a" => 1 }, { "b" => 2 }) # => { "a" => 1, "b" => 2 }
105
+ #
106
+ # The arguments can be either an
107
+ # <tt>ActiveSupport::HashWithIndifferentAccess</tt> or a regular +Hash+.
108
+ # In either case the merge respects the semantics of indifferent access.
109
+ #
110
+ # If the argument is a regular hash with keys +:key+ and <tt>"key"</tt> only one
111
+ # of the values end up in the receiver, but which one is unspecified.
112
+ #
113
+ # When given a block, the value for duplicated keys will be determined
114
+ # by the result of invoking the block with the duplicated key, the value
115
+ # in the receiver, and the value in +other_hash+. The rules for duplicated
116
+ # keys follow the semantics of indifferent access:
117
+ #
118
+ # hash_1[:key] = 10
119
+ # hash_2['key'] = 12
120
+ # hash_1.update(hash_2) { |key, old, new| old + new } # => {"key"=>22}
121
+ def update(*other_hashes, &block)
122
+ if other_hashes.size == 1
123
+ update_with_single_argument(other_hashes.first, block)
124
+ else
125
+ other_hashes.each do |other_hash|
126
+ update_with_single_argument(other_hash, block)
127
+ end
128
+ end
129
+ self
130
+ end
131
+
132
+ alias merge! update
133
+
134
+ # Checks the hash for a key matching the argument passed in:
135
+ #
136
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
137
+ # hash['key'] = 'value'
138
+ # hash.key?(:key) # => true
139
+ # hash.key?('key') # => true
140
+ def key?(key)
141
+ super(convert_key(key))
142
+ end
143
+
144
+ alias include? key?
145
+ alias has_key? key?
146
+ alias member? key?
147
+
148
+ # Same as <tt>Hash#[]</tt> where the key passed as argument can be
149
+ # either a string or a symbol:
150
+ #
151
+ # counters = ActiveSupport::HashWithIndifferentAccess.new
152
+ # counters[:foo] = 1
153
+ #
154
+ # counters['foo'] # => 1
155
+ # counters[:foo] # => 1
156
+ # counters[:zoo] # => nil
157
+ def [](key)
158
+ super(convert_key(key))
159
+ end
160
+
161
+ # Same as <tt>Hash#assoc</tt> where the key passed as argument can be
162
+ # either a string or a symbol:
163
+ #
164
+ # counters = ActiveSupport::HashWithIndifferentAccess.new
165
+ # counters[:foo] = 1
166
+ #
167
+ # counters.assoc('foo') # => ["foo", 1]
168
+ # counters.assoc(:foo) # => ["foo", 1]
169
+ # counters.assoc(:zoo) # => nil
170
+ def assoc(key)
171
+ super(convert_key(key))
172
+ end
173
+
174
+ # Same as <tt>Hash#fetch</tt> where the key passed as argument can be
175
+ # either a string or a symbol:
176
+ #
177
+ # counters = ActiveSupport::HashWithIndifferentAccess.new
178
+ # counters[:foo] = 1
179
+ #
180
+ # counters.fetch('foo') # => 1
181
+ # counters.fetch(:bar, 0) # => 0
182
+ # counters.fetch(:bar) { |key| 0 } # => 0
183
+ # counters.fetch(:zoo) # => KeyError: key not found: "zoo"
184
+ def fetch(key, *extras)
185
+ super(convert_key(key), *extras)
186
+ end
187
+
188
+ # Same as <tt>Hash#dig</tt> where the key passed as argument can be
189
+ # either a string or a symbol:
190
+ #
191
+ # counters = ActiveSupport::HashWithIndifferentAccess.new
192
+ # counters[:foo] = { bar: 1 }
193
+ #
194
+ # counters.dig('foo', 'bar') # => 1
195
+ # counters.dig(:foo, :bar) # => 1
196
+ # counters.dig(:zoo) # => nil
197
+ def dig(*args)
198
+ args[0] = convert_key(args[0]) if args.size.positive?
199
+ super(*args)
200
+ end
201
+
202
+ # Same as <tt>Hash#default</tt> where the key passed as argument can be
203
+ # either a string or a symbol:
204
+ #
205
+ # hash = ActiveSupport::HashWithIndifferentAccess.new(1)
206
+ # hash.default # => 1
207
+ #
208
+ # hash = ActiveSupport::HashWithIndifferentAccess.new { |hash, key| key }
209
+ # hash.default # => nil
210
+ # hash.default('foo') # => 'foo'
211
+ # hash.default(:foo) # => 'foo'
212
+ def default(*args)
213
+ super(*args.map { |arg| convert_key(arg) })
214
+ end
215
+
216
+ # Returns an array of the values at the specified indices:
217
+ #
218
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
219
+ # hash[:a] = 'x'
220
+ # hash[:b] = 'y'
221
+ # hash.values_at('a', 'b') # => ["x", "y"]
222
+ def values_at(*keys)
223
+ super(*keys.map { |key| convert_key(key) })
224
+ end
225
+
226
+ # Returns an array of the values at the specified indices, but also
227
+ # raises an exception when one of the keys can't be found.
228
+ #
229
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
230
+ # hash[:a] = 'x'
231
+ # hash[:b] = 'y'
232
+ # hash.fetch_values('a', 'b') # => ["x", "y"]
233
+ # hash.fetch_values('a', 'c') { |key| 'z' } # => ["x", "z"]
234
+ # hash.fetch_values('a', 'c') # => KeyError: key not found: "c"
235
+ def fetch_values(*indices, &block)
236
+ super(*indices.map { |key| convert_key(key) }, &block)
237
+ end
238
+
239
+ # Returns a shallow copy of the hash.
240
+ #
241
+ # hash = ActiveSupport::HashWithIndifferentAccess.new({ a: { b: 'b' } })
242
+ # dup = hash.dup
243
+ # dup[:a][:c] = 'c'
244
+ #
245
+ # hash[:a][:c] # => "c"
246
+ # dup[:a][:c] # => "c"
247
+ def dup
248
+ self.class.new(self).tap do |new_hash|
249
+ set_defaults(new_hash)
250
+ end
251
+ end
252
+
253
+ # This method has the same semantics of +update+, except it does not
254
+ # modify the receiver but rather returns a new hash with indifferent
255
+ # access with the result of the merge.
256
+ def merge(*hashes, &block)
257
+ dup.update(*hashes, &block)
258
+ end
259
+
260
+ # Like +merge+ but the other way around: Merges the receiver into the
261
+ # argument and returns a new hash with indifferent access as result:
262
+ #
263
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
264
+ # hash['a'] = nil
265
+ # hash.reverse_merge(a: 0, b: 1) # => {"a"=>nil, "b"=>1}
266
+ def reverse_merge(other_hash)
267
+ super(self.class.new(other_hash))
268
+ end
269
+
270
+ alias with_defaults reverse_merge
271
+
272
+ # Same semantics as +reverse_merge+ but modifies the receiver in-place.
273
+ def reverse_merge!(other_hash)
274
+ super(self.class.new(other_hash))
275
+ end
276
+
277
+ alias with_defaults! reverse_merge!
278
+
279
+ # Replaces the contents of this hash with other_hash.
280
+ #
281
+ # h = { "a" => 100, "b" => 200 }
282
+ # h.replace({ "c" => 300, "d" => 400 }) # => {"c"=>300, "d"=>400}
283
+ def replace(other_hash)
284
+ super(self.class.new(other_hash))
285
+ end
286
+
287
+ # Removes the specified key from the hash.
288
+ def delete(key)
289
+ super(convert_key(key))
290
+ end
291
+
292
+ # Returns a hash with indifferent access that includes everything except given keys.
293
+ # hash = { a: "x", b: "y", c: 10 }.with_indifferent_access
294
+ # hash.except(:a, "b") # => {c: 10}.with_indifferent_access
295
+ # hash # => { a: "x", b: "y", c: 10 }.with_indifferent_access
296
+ def except(*keys)
297
+ slice(*self.keys - keys.map { |key| convert_key(key) })
298
+ end
299
+
300
+ alias without except
301
+
302
+ def stringify_keys!
303
+ transform_keys!(&:to_s)
304
+ end
305
+
306
+ def stringify_keys
307
+ transform_keys(&:to_s)
308
+ end
309
+
310
+ def symbolize_keys
311
+ symbolize_keys!
312
+ end
313
+
314
+ def symbolize_keys!
315
+ transform_keys! do |key|
316
+ key.to_sym
317
+ rescue StandardError
318
+ key
319
+ end
320
+ end
321
+
322
+ alias to_options symbolize_keys
323
+
324
+ def to_options!
325
+ self
326
+ end
327
+
328
+ def select(*args, &block)
329
+ return to_enum(:select) unless block_given?
330
+
331
+ dup.tap { |hash| hash.select!(*args, &block) }
332
+ end
333
+
334
+ def reject(*args, &block)
335
+ return to_enum(:reject) unless block_given?
336
+
337
+ dup.tap { |hash| hash.reject!(*args, &block) }
338
+ end
339
+
340
+ def transform_values(*args, &block)
341
+ return to_enum(:transform_values) unless block_given?
342
+
343
+ dup.tap { |hash| hash.transform_values!(*args, &block) }
344
+ end
345
+
346
+ def transform_keys(*args, &block)
347
+ return to_enum(:transform_keys) unless block_given?
348
+
349
+ dup.tap { |hash| hash.transform_keys!(*args, &block) }
350
+ end
351
+
352
+ def transform_keys!
353
+ return enum_for(:transform_keys!) { size } unless block_given?
354
+
355
+ keys.each do |key|
356
+ self[yield(key)] = delete(key)
357
+ end
358
+ self
359
+ end
360
+
361
+ def slice(*keys)
362
+ keys.map! { |key| convert_key(key) }
363
+ self.class.new(super)
364
+ end
365
+
366
+ def slice!(*keys)
367
+ keys.map! { |key| convert_key(key) }
368
+ super
369
+ end
370
+
371
+ def compact
372
+ dup.tap(&:compact!)
373
+ end
374
+
375
+ # Convert to a regular hash with string keys.
376
+ def to_hash
377
+ a_new_hash = {}
378
+ set_defaults(a_new_hash)
379
+
380
+ each do |key, value|
381
+ a_new_hash[key] = convert_value(value, conversion: :to_hash)
382
+ end
383
+ a_new_hash
384
+ end
385
+
386
+ private
387
+
388
+ if Symbol.method_defined?(:name)
389
+ def convert_key(key)
390
+ key.is_a?(Symbol) ? key.name : key
391
+ end
392
+ else
393
+ def convert_key(key)
394
+ key.is_a?(Symbol) ? key.to_s : key
395
+ end
396
+ end
397
+
398
+ def convert_value(value, conversion: nil)
399
+ case value
400
+ when Hash
401
+ convert_hash_value(conversion, value)
402
+ when Array
403
+ convert_array_value(conversion, value)
404
+ else
405
+ value
406
+ end
407
+ end
408
+
409
+ def convert_array_value(conversion, value)
410
+ value = value.dup if conversion != :assignment || value.frozen?
411
+ value.map! { |e| convert_value(e, conversion: conversion) }
412
+ value
413
+ end
414
+
415
+ def convert_hash_value(conversion, value)
416
+ if conversion == :to_hash
417
+ value.to_hash
418
+ else
419
+ HashWithIndifferentAccess.new(value)
420
+ end
421
+ end
422
+
423
+ def set_defaults(target) # rubocop:disable Naming/AccessorMethodName
424
+ if default_proc
425
+ target.default_proc = default_proc.dup
426
+ else
427
+ target.default = default
428
+ end
429
+ end
430
+
431
+ def update_with_single_argument(other_hash, block)
432
+ if other_hash.is_a? HashWithIndifferentAccess
433
+ regular_update(other_hash, &block)
434
+ else
435
+ other_hash.to_hash.each_pair do |key, value|
436
+ value = block.call(convert_key(key), self[key], value) if block && key?(key)
437
+ regular_writer(convert_key(key), convert_value(value))
438
+ end
439
+ end
440
+ end
441
+ end
442
+ end