snaky_hash 2.0.2 โ†’ 2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d15358e100316a4b2347ab0b1a55b2e16f87ee69991b0579328b049b8b04abf
4
- data.tar.gz: 5030164f28379f7d237da28aab846aa9ce1cfb55f308e257bb3cb38246da1f36
3
+ metadata.gz: 7a4ebce56adbdd1bb1cd6ac0fe46f3b891e0c0cf689ec611e6ca00e03c503fc1
4
+ data.tar.gz: ae1ffc55d9c653904a2c65bdfeb1b1724c6bce5eab251a225b036baaa5c165c5
5
5
  SHA512:
6
- metadata.gz: d34d715bf7deb832a4ce4f04338d3cff147547d979bc42d56e8258a0975265296ec5550035581181e94d2a9b7af1afbf9de27db476b8229cec5d5c18e43b51e7
7
- data.tar.gz: fa3e81dd83544e92d1bfe7174e34d8d6cec4d4f20d39d84bc82bf16b9852155e962d58058ff7aa312f32f3d97a7d3857367aa61892912811bd25de94982ab825
6
+ metadata.gz: 21e5beae61652b1307f346b676618562e1a713ff3db552e6dfc379683088e6e9de721eaca35dd32788564c77113d015af0d592def73697a2b25b5d8258a337b7
7
+ data.tar.gz: 26327dc66ec45f4ab558e1cd383615107a72587b700df71837302ddef530d7b83acd5b70fb9601ad2c14f3d9c26290c956e99e941f1ce0568fed075317dacd81
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -7,10 +7,31 @@ and this project adheres to [Semantic Versioning v2](https://semver.org/spec/v2.
7
7
  ## [Unreleased]
8
8
  ### Added
9
9
  ### Changed
10
- ### Fixed
10
+ ### Deprecated
11
11
  ### Removed
12
+ ### Fixed
13
+ ### Security
14
+
15
+ ## [2.0.3] - 2025-05-23
16
+ - TAG: [v2.0.3][2.0.3t]
17
+ - COVERAGE: 100.00% -- 132/132 lines in 7 files
18
+ - BRANCH COVERAGE: 100.00% -- 38/38 branches in 7 files
19
+ - 100.00% documented
20
+ ### Added
21
+ - `#dump` instance method injected by `extend SnakyHash::Serializer` (@pboling)
22
+ - `dump_hash_extensions` - new feature, analogous to `load_hash_extensions` (@pboling)
23
+ - `dump_value_extensions` - alternate name for `dump_extensions` (@pboling)
24
+ - `load_value_extensions` - alternate name for `load_extensions` (@pboling)
25
+ - Clarifying documentation (@pboling)
26
+ ### Fixed
27
+ - [gh4](https://github.com/oauth-xx/snaky_hash/pull/4) - Serializer extensions dump and load empty values properly (@pboling)
28
+ - Fixed `dump_extensions`, `load_extensions`, `load_hash_extensions`
29
+ - Intended usage is primarily JSON, and oauth2 gem
30
+ - OAuth2 spec can have legitimately empty values (e.g. scopes could be empty)
31
+ - Previous logic was inherited from design decisions made by `serialized_hashie` gem; doesn't apply here
12
32
 
13
- ## [2.0.2] - 2025-05-21 ([tag][2.0.2t])
33
+ ## [2.0.2] - 2025-05-21
34
+ - TAG: [v2.0.2][2.0.2t]
14
35
  - COVERAGE: 100.00% -- 119/119 lines in 7 files
15
36
  - BRANCH COVERAGE: 100.00% -- 35/35 branches in 7 files
16
37
  - 100.00% documented
@@ -26,7 +47,8 @@ and this project adheres to [Semantic Versioning v2](https://semver.org/spec/v2.
26
47
  - Documentation site at [snaky-hash.galtzo.com](https://snaky-hash.galtzo.com) (@pboling)
27
48
  - 100% documented! (@pboling)
28
49
 
29
- ## [2.0.1] - 2022-09-23 ([tag][2.0.1t])
50
+ ## [2.0.1] - 2022-09-23
51
+ - TAG: [v2.0.1][2.0.1t]
30
52
  ### Added
31
53
  - Certificate for signing gem releases (@pboling)
32
54
  - Gemspec metadata (@pboling)
@@ -36,7 +58,8 @@ and this project adheres to [Semantic Versioning v2](https://semver.org/spec/v2.
36
58
  ### Changed
37
59
  - Gem releases are now cryptographically signed (@pboling)
38
60
 
39
- ## [2.0.0] - 2022-08-29 ([tag][2.0.0t])
61
+ ## [2.0.0] - 2022-08-29
62
+ - TAG: [v2.0.0][2.0.0t]
40
63
  ### Changed
41
64
  - **BREAKING**: `SnakeHash::Snake` is now a mixin, now with support for symbol or string keys
42
65
  ```ruby
@@ -48,18 +71,22 @@ end
48
71
  - `SnakyHash::StringKeyed`: a Hashie::Mash class with snake-cased String keys
49
72
  - `SnakyHash::SymbolKeyed`: a Hashie::Mash class with snake-cased Symbol keys
50
73
 
51
- ## [1.0.1] - 2022-08-26 ([tag][1.0.1t])
74
+ ## [1.0.1] - 2022-08-26
75
+ - TAG: [v1.0.1][1.0.1t]
52
76
  ### Added
53
77
  - Missing LICENSE.txt file to release
54
78
  ### Removed
55
79
  - Accidentally added bundler dependency (vestige of transpec process) is now removed
56
80
 
57
- ## [1.0.0] - 2022-08-26 ([tag][1.0.0t])
81
+ ## [1.0.0] - 2022-08-26
82
+ - TAG: [v1.0.0][1.0.0t]
58
83
  ### Added
59
84
  - Initial release
60
85
 
61
- [Unreleased]: https://gitlab.com/oauth-xx/snaky_hash/-/compare/v2.0.2...main
62
- [2.0.21]: https://gitlab.com/oauth-xx/snaky_hash/-/compare/v2.0.1...v2.0.2
86
+ [Unreleased]: https://gitlab.com/oauth-xx/snaky_hash/-/compare/v2.0.3...main
87
+ [2.0.3]: https://gitlab.com/oauth-xx/snaky_hash/-/compare/v2.0.2...v2.0.3
88
+ [2.0.3t]: https://gitlab.com/oauth-xx/snaky_hash/-/releases/tag/v2.0.3
89
+ [2.0.2]: https://gitlab.com/oauth-xx/snaky_hash/-/compare/v2.0.1...v2.0.2
63
90
  [2.0.2t]: https://gitlab.com/oauth-xx/snaky_hash/-/releases/tag/v2.0.2
64
91
  [2.0.1]: https://gitlab.com/oauth-xx/snaky_hash/-/compare/v2.0.0...v2.0.1
65
92
  [2.0.1t]: https://gitlab.com/oauth-xx/snaky_hash/-/releases/tag/v2.0.1
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ๐Ÿ SnakyHash
2
2
 
3
- [![Version][๐Ÿ‘ฝversioni]][๐Ÿ‘ฝversion] [![License: MIT][๐Ÿ“„license-img]][๐Ÿ“„license-ref] [![Downloads Rank][๐Ÿ‘ฝdl-ranki]][๐Ÿ‘ฝdl-rank] [![Open Source Helpers][๐Ÿ‘ฝoss-helpi]][๐Ÿ‘ฝoss-help] [![Depfu][๐Ÿ”‘depfuiโ™ป๏ธ]][๐Ÿ”‘depfu] [![Coveralls Test Coverage][๐Ÿ”‘coveralls-img]][๐Ÿ”‘coveralls] [![QLTY Test Coverage][๐Ÿ”‘qlty-coviโ™ป๏ธ]][๐Ÿ”‘qlty-cov] [![CI Heads][๐ŸšŽ3-hd-wfi]][๐ŸšŽ3-hd-wf] [![CI Runtime Dependencies @ HEAD][๐ŸšŽ12-crh-wfi]][๐ŸšŽ12-crh-wf] [![CI Current][๐ŸšŽ11-c-wfi]][๐ŸšŽ11-c-wf] [![CI Truffle Ruby][๐ŸšŽ9-t-wfi]][๐ŸšŽ9-t-wf] [![CI JRuby][๐ŸšŽ10-j-wfi]][๐ŸšŽ10-j-wf] [![CI Supported][๐ŸšŽ6-s-wfi]][๐ŸšŽ6-s-wf] [![CI Legacy][๐ŸšŽ4-lg-wfi]][๐ŸšŽ4-lg-wf] [![CI Unsupported][๐ŸšŽ7-us-wfi]][๐ŸšŽ7-us-wf] [![CI Ancient][๐ŸšŽ1-an-wfi]][๐ŸšŽ1-an-wf] [![CI Test Coverage][๐ŸšŽ2-cov-wfi]][๐ŸšŽ2-cov-wf] [![CI Style][๐ŸšŽ5-st-wfi]][๐ŸšŽ5-st-wf] [![CodeQL][๐Ÿ–codeQL-img]][๐Ÿ–codeQL]
3
+ [![Version][๐Ÿ‘ฝversioni]][๐Ÿ‘ฝversion] [![License: MIT][๐Ÿ“„license-img]][๐Ÿ“„license-ref] [![Downloads Rank][๐Ÿ‘ฝdl-ranki]][๐Ÿ‘ฝdl-rank] [![Open Source Helpers][๐Ÿ‘ฝoss-helpi]][๐Ÿ‘ฝoss-help] [![Depfu][๐Ÿ”‘depfuiโ™ป๏ธ]][๐Ÿ”‘depfu] [![Coveralls Test Coverage][๐Ÿ”‘coveralls-img]][๐Ÿ”‘coveralls] [![QLTY Test Coverage][๐Ÿ”‘qlty-coviโ™ป๏ธ]][๐Ÿ”‘qlty-cov] [![QLTY Maintainability][๐Ÿ”‘qlty-mntiโ™ป๏ธ]][๐Ÿ”‘qlty-mnt] [![CI Heads][๐ŸšŽ3-hd-wfi]][๐ŸšŽ3-hd-wf] [![CI Runtime Dependencies @ HEAD][๐ŸšŽ12-crh-wfi]][๐ŸšŽ12-crh-wf] [![CI Current][๐ŸšŽ11-c-wfi]][๐ŸšŽ11-c-wf] [![CI Truffle Ruby][๐ŸšŽ9-t-wfi]][๐ŸšŽ9-t-wf] [![CI JRuby][๐ŸšŽ10-j-wfi]][๐ŸšŽ10-j-wf] [![CI Supported][๐ŸšŽ6-s-wfi]][๐ŸšŽ6-s-wf] [![CI Legacy][๐ŸšŽ4-lg-wfi]][๐ŸšŽ4-lg-wf] [![CI Unsupported][๐ŸšŽ7-us-wfi]][๐ŸšŽ7-us-wf] [![CI Ancient][๐ŸšŽ1-an-wfi]][๐ŸšŽ1-an-wf] [![CI Test Coverage][๐ŸšŽ2-cov-wfi]][๐ŸšŽ2-cov-wf] [![CI Style][๐ŸšŽ5-st-wfi]][๐ŸšŽ5-st-wf] [![CodeQL][๐Ÿ–codeQL-img]][๐Ÿ–codeQL]
4
4
 
5
5
  ---
6
6
 
@@ -14,7 +14,7 @@ and provide a nice psuedo-object interface.
14
14
  It can be thought of as a mashup of:
15
15
 
16
16
  * `Rash` (specifically the [`rash_alt`](https://github.com/shishi/rash_alt) flavor), which is a special `Mash`, made popular by the `hashie` gem, and
17
- * `serialized_hashie` [gem by krystal](https://github.com/krystal/serialized-hashie)
17
+ * `serialized_hashie` [gem by krystal](https://github.com/krystal/serialized-hashie), rewritten, with some behavior changes
18
18
 
19
19
  Classes that `include SnakyHash::Snake.new` should inherit from `Hashie::Mash`.
20
20
 
@@ -46,6 +46,17 @@ SnakyHash::StringKeyed.class_eval do
46
46
  end
47
47
  ```
48
48
 
49
+ or you can create a custom class
50
+
51
+ ```ruby
52
+ class MyHash < Hashie::Mash
53
+ include SnakyHash::Snake.new(key_type: :string, serializer: true)
54
+ # Which is the same as:
55
+ # include SnakyHash::Snake.new(key_type: :string)
56
+ # extend SnakyHash::Serializer
57
+ end
58
+ ```
59
+
49
60
  You can then add serialization extensions as needed. See [serialization](#serialization) and [extensions](#extensions) for more.
50
61
 
51
62
  | Federated [DVCS][๐Ÿ’Žd-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
@@ -212,71 +223,95 @@ This is also not a bug, though if you need different behavior, there is a soluti
212
223
 
213
224
  You can write your own arbitrary extensions:
214
225
 
215
- * "Hash Load" extensions operate on the hash, and nested hashes
226
+ * "Hash Load" extensions operate on the hash and nested hashes
216
227
  * use `::load_hash_extensions.add(:extension_name) { |hash| }`
217
- * "Load" extensions operate on the values, and nested hash's values, if any
218
- * use `::load_extensions.add(:extension_name) { |value| }`
219
- * "Dump" extensions operate on the values, and nested hash's values, if any
220
- * use `::dump_extensions.add(:extension_name) { |value| }`
228
+ * since v2.0.2, bugs fixed in v2.0.3
229
+ * "Value Load" extensions operate on the values, and nested hashes' values, if any
230
+ * use `::load_value_extensions.add(:extension_name) { |value| }`
231
+ * since v2.0.2, bugs fixed in v2.0.3
232
+ * "Hash Dump" extensions operate on the hash and nested hashes
233
+ * use `::dump_hash_extensions.add(:extension_name) { |value| }`
234
+ * since v2.0.3
235
+ * "Value Dump" extensions operate on the values, and nested hashes' values, if any
236
+ * use `::dump_value_extensions.add(:extension_name) { |value| }`
237
+ * since v2.0.2, bugs fixed in v2.0.3
221
238
 
222
239
  #### Example
223
240
 
224
- Let's say I want all integer-like keys, except 0, to be integer keys,
225
- while 0 converts to, and stays, a string forever.
241
+ Let's say I want to really smash up my hash and make it more food-like.
226
242
 
227
243
  ```ruby
228
244
  class MyExtSnakedHash < Hashie::Mash
229
245
  include SnakyHash::Snake.new(
230
246
  key_type: :symbol, # default :string
231
- serializer: true, # default: false
247
+ serializer: true, # default: false
232
248
  )
233
249
  end
234
250
 
235
- MyExtSnakedHash.load_hash_extensions.add(:non_zero_keys_to_int) do |value|
236
- if value.is_a?(Hash)
237
- value.transform_keys do |key|
238
- key_int = key.to_s.to_i
239
- if key_int > 0
240
- key_int
241
- else
242
- key
243
- end
244
- end
245
- else
246
- value
251
+ # We could swap all values with indexed apples (obliteraating nested data!)
252
+ MyExtSnakedHash.dump_hash_extensions.add(:to_apple) do |value|
253
+ num = 0
254
+ value.transform_values do |_key|
255
+ key = "apple-#{num}"
256
+ num += 1
257
+ key
247
258
  end
248
259
  end
249
260
 
250
- snake = MyExtSnakedHash.new(1 => "a", 0 => 4, "VeryFineHat" => {3 => "v", 5 => 7, :very_fine_hat => "feathers"}) # => {1 => "a", 0 => 4, very_fine_hat: {3 => "v", 5 => 7, very_fine_hat: "feathers"}}
251
- dump = MyExtSnakedHash.dump(snake) # => "{\"1\":\"a\",\"0\":4,\"very_fine_hat\":{\"3\":\"v\",\"5\":7,\"very_fine_hat\":\"feathers\"}}"
252
- hydrated = MyExtSnakedHash.load(dump) # => {1 => "a", "0": 4, very_fine_hat: {3 => "v", 5 => 7, very_fine_hat: "feathers"}}
253
- hydrated.class # => MyExtSnakedHash
254
- hydrated["1"] # => nil
255
- hydrated[1] # => "a"
256
- hydrated["0"] # => 4
257
- hydrated[0] # => nil
258
- hydrated.very_fine_hat # => {3 => "v", 5 => 7, very_fine_hat: "feathers"}
259
- hydrated.very_fine_hat.very_fine_hat # => "feathers"
260
- hydrated.very_fine_hat[:very_fine_hat] # => 'feathers'
261
- hydrated.very_fine_hat["very_fine_hat"] # => 'feathers'
261
+ # And then when loading the dump we could convert the yum to pear
262
+ MyExtSnakedHash.load_hash_extensions.add(:apple_to_pear) do |value|
263
+ value.transform_keys do |key|
264
+ key.to_s.sub("yum", "pear")
265
+ end
266
+ end
267
+
268
+ # We could swap all index numbers "beet-<number>"
269
+ MyExtSnakedHash.dump_value_extensions.add(:to_beet) do |value|
270
+ value.to_s.sub(/(\d+)/) { |match| "beet-#{match[0]}" }
271
+ end
272
+
273
+ # And then when loading the dump we could convert beet to corn
274
+ MyExtSnakedHash.load_value_extensions.add(:beet_to_corn) do |value|
275
+ value.to_s.sub("beet", "corn")
276
+ end
277
+
278
+ snake = MyExtSnakedHash.new({"YumBread" => "b", "YumCake" => {"b" => "b"}, "YumBoba" => [1, 2, 3]})
279
+ snake # => {yum_bread: "b", yum_cake: {b: "b"}, yum_boba: [1, 2, 3]}
280
+ snake.yum_bread # => "b"
281
+ snake.yum_cake # => {b: "b"}
282
+ snake.yum_boba # => [1, 2, 3]
283
+ dump = snake.dump
284
+ dump # => "{\"yum_bread\":\"apple-beet-0\",\"yum_cake\":\"apple-beet-1\",\"yum_boba\":\"apple-beet-2\"}"
285
+ hydrated = MyExtSnakedHash.load(dump)
286
+ hydrated # => {pear_bread: "apple-corn-0", pear_cake: "apple-corn-1", pear_boba: "apple-corn-2"}
262
287
  ```
263
288
 
264
289
  See the specs for more examples.
265
290
 
266
- ### Stranger Things
291
+ ### Bad Ideas
267
292
 
268
293
  I don't recommend using these features... but they exist (for now).
294
+
295
+ <details>
296
+ <summary>Show me what I should *not* do!</summary>
297
+
269
298
  You can still access the original un-snaked camel keys.
270
299
  And through them you can even use un-snaked camel methods.
271
300
  But don't.
272
301
 
273
302
  ```ruby
303
+ snake = SnakyHash::StringKeyed["VeryFineHat" => "Feathers"]
274
304
  snake.key?("VeryFineHat") # => true
275
305
  snake["VeryFineHat"] # => 'Feathers'
276
306
  snake.VeryFineHat # => 'Feathers', PLEASE don't do this!!!
277
307
  snake["VeryFineHat"] = "pop" # Please don't do this... you'll get a warning, and it works (for now), but no guarantees.
278
308
  # WARN -- : You are setting a key that conflicts with a built-in method MySnakedHash#VeryFineHat defined in MySnakedHash. This can cause unexpected behavior when accessing the key as a property. You can still access the key via the #[] method.
279
309
  # => "pop"
310
+ ```
311
+
312
+ Since you are reading this, here's what to do instead.
313
+
314
+ ```ruby
280
315
  snake.very_fine_hat = "pop" # => 'pop', do this instead!!!
281
316
  snake.very_fine_hat # => 'pop'
282
317
  snake[:very_fine_hat] = "moose" # => 'moose', or do this instead!!!
@@ -285,6 +320,8 @@ snake["very_fine_hat"] = "cheese" # => 'cheese', or do this instead!!!
285
320
  snake.very_fine_hat # => 'cheese'
286
321
  ```
287
322
 
323
+ </details>
324
+
288
325
  ### ๐Ÿš€ Release Instructions
289
326
 
290
327
  See [CONTRIBUTING.md][๐Ÿคcontributing].
@@ -553,7 +590,7 @@ or one of the others at the head of this README.
553
590
  [๐Ÿ“Œgitmoji]:https://gitmoji.dev
554
591
  [๐Ÿ“Œgitmoji-img]:https://img.shields.io/badge/gitmoji_commits-%20๐Ÿ˜œ%20๐Ÿ˜-34495e.svg?style=flat-square
555
592
  [๐Ÿงฎkloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
556
- [๐Ÿงฎkloc-img]: https://img.shields.io/badge/KLOC-0.119-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
593
+ [๐Ÿงฎkloc-img]: https://img.shields.io/badge/KLOC-0.132-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
557
594
  [๐Ÿ”security]: SECURITY.md
558
595
  [๐Ÿ”security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
559
596
  [๐Ÿ“„copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -21,6 +21,7 @@ module SnakyHash
21
21
  def extended(base)
22
22
  extended_module = Modulizer.to_extended_mod
23
23
  base.extend(extended_module)
24
+ base.include(ConvenienceInstanceMethods)
24
25
  # :nocov:
25
26
  # This will be run in CI on Ruby 2.3, but we only collect coverage from current Ruby
26
27
  unless base.instance_methods.include?(:transform_values)
@@ -45,8 +46,7 @@ module SnakyHash
45
46
  # @return [Hash] deserialized hash object
46
47
  def load(raw_hash)
47
48
  hash = JSON.parse(presence(raw_hash) || "{}")
48
- hash = load_value(new(hash))
49
- new(hash)
49
+ load_hash(new(hash))
50
50
  end
51
51
 
52
52
  # Internal module for generating extension methods
@@ -57,17 +57,29 @@ module SnakyHash
57
57
  # @return [Module] a module containing extension management methods
58
58
  def to_extended_mod
59
59
  Module.new do
60
+ define_method :load_value_extensions do
61
+ @load_value_extensions ||= Extensions.new
62
+ end
63
+
60
64
  define_method :load_extensions do
61
- @load_extensions ||= Extensions.new
65
+ load_value_extensions
66
+ end
67
+
68
+ define_method :dump_value_extensions do
69
+ @dump_value_extensions ||= Extensions.new
62
70
  end
63
71
 
64
72
  define_method :dump_extensions do
65
- @dump_extensions ||= Extensions.new
73
+ dump_value_extensions
66
74
  end
67
75
 
68
76
  define_method :load_hash_extensions do
69
77
  @load_hash_extensions ||= Extensions.new
70
78
  end
79
+
80
+ define_method :dump_hash_extensions do
81
+ @dump_hash_extensions ||= Extensions.new
82
+ end
71
83
  end
72
84
  end
73
85
  end
@@ -96,6 +108,20 @@ module SnakyHash
96
108
  # :nocov:
97
109
  end
98
110
 
111
+ # Provides convenient instance methods for serialization
112
+ #
113
+ # @example Using convenience methods
114
+ # hash = MyHash.new(key: 'value')
115
+ # json = hash.dump #=> '{"key":"value"}'
116
+ module ConvenienceInstanceMethods
117
+ # Serializes the current hash instance to JSON
118
+ #
119
+ # @return [String] JSON string representation of the hash
120
+ def dump
121
+ self.class.dump(self)
122
+ end
123
+ end
124
+
99
125
  private
100
126
 
101
127
  # Checks if a value is blank (nil or empty string)
@@ -117,15 +143,14 @@ module SnakyHash
117
143
  blank?(value) ? nil : value
118
144
  end
119
145
 
120
- # Processes a hash for dumping, transforming its values
146
+ # Processes a hash for dumping, transforming its keys and/or values
121
147
  #
122
148
  # @param hash [Hash] hash to process
123
149
  # @return [Hash] processed hash with transformed values
124
150
  def dump_hash(hash)
125
- hash = self[hash].transform_values do |value|
151
+ dump_hash_extensions.run(self[hash]).transform_values do |value|
126
152
  dump_value(value)
127
153
  end
128
- hash.reject { |_, v| blank?(v) }
129
154
  end
130
155
 
131
156
  # Processes a single value for dumping
@@ -134,7 +159,7 @@ module SnakyHash
134
159
  # @return [Object, nil] processed value
135
160
  def dump_value(value)
136
161
  if blank?(value)
137
- return
162
+ return value
138
163
  end
139
164
 
140
165
  if value.is_a?(::Hash)
@@ -148,28 +173,46 @@ module SnakyHash
148
173
  dump_extensions.run(value)
149
174
  end
150
175
 
151
- # Processes a hash for loading, transforming its values
176
+ # Processes a hash for loading, transforming its keys and/or values
152
177
  #
153
178
  # @param hash [Hash] hash to process
154
179
  # @return [Hash] processed hash with transformed values
155
180
  def load_hash(hash)
156
- hash.transform_values do |value|
181
+ ran = load_hash_extensions.run(self[hash])
182
+ return load_value(ran) unless ran.is_a?(::Hash)
183
+
184
+ res = self[ran].transform_values do |value|
157
185
  load_value(value)
158
186
  end
187
+
188
+ # TODO: Drop this hack when dropping support for Ruby 2.6
189
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7")
190
+ res
191
+ else
192
+ # :nocov:
193
+ # In Ruby <= 2.6 Hash#transform_values returned a new vanilla Hash,
194
+ # rather than a hash of the class being transformed.
195
+ self[res]
196
+ # :nocov:
197
+ end
159
198
  end
160
199
 
161
200
  # Processes a single value for loading
162
201
  #
163
202
  # @param value [Object] value to process
164
- # @return [Object] processed value
203
+ # @return [Object, nil] processed value
165
204
  def load_value(value)
205
+ if blank?(value)
206
+ return value
207
+ end
208
+
166
209
  if value.is_a?(::Hash)
167
- hash = load_hash_extensions.run(new(value))
168
- return load_hash(new(hash)) if hash.is_a?(::Hash)
169
- return load_value(hash)
210
+ return load_hash(value)
170
211
  end
171
212
 
172
- return value.map { |v| load_value(v) } if value.is_a?(Array)
213
+ if value.is_a?(::Array)
214
+ return value.map { |v| load_value(v) }.compact
215
+ end
173
216
 
174
217
  load_extensions.run(value)
175
218
  end
@@ -57,7 +57,12 @@ module SnakyHash
57
57
  Module.new do
58
58
  case key_type
59
59
  when :string then
60
- # Converts a key to a string if possible, after underscoring
60
+ # Converts a key to a string if it is symbolizable, after underscoring
61
+ #
62
+ # @note checks for to_sym instead of to_s, because nearly everything responds_to?(:to_s)
63
+ # so respond_to?(:to_s) isn't very useful as a test, and would result in symbolizing integers
64
+ # amd it also provides parity between the :symbol behavior, and the :string behavior,
65
+ # regarding which keys get converted for a given version of Ruby.
61
66
  #
62
67
  # @param key [Object] the key to convert
63
68
  # @return [String, Object] the converted key or original if not convertible
@@ -8,6 +8,6 @@ module SnakyHash
8
8
  # Current version of SnakyHash
9
9
  #
10
10
  # @return [String] the current version in semantic versioning format
11
- VERSION = "2.0.2"
11
+ VERSION = "2.0.3"
12
12
  end
13
13
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: snaky_hash
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Boling
@@ -35,7 +35,7 @@ cert_chain:
35
35
  DVjBtqT23eugOqQ73umLcYDZkc36vnqGxUBSsXrzY9pzV5gGr2I8YUxMqf6ATrZt
36
36
  L9nRqA==
37
37
  -----END CERTIFICATE-----
38
- date: 2025-05-21 00:00:00.000000000 Z
38
+ date: 2025-05-23 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: hashie
@@ -211,10 +211,10 @@ licenses:
211
211
  - MIT
212
212
  metadata:
213
213
  homepage_uri: https://snaky-hash.galtzo.com/
214
- source_code_uri: https://github.com/oauth-xx/snaky_hash/releases/tag//v2.0.2
215
- changelog_uri: https://gitlab.com/oauth-xx/snaky_hash/-/blob/v2.0.2/CHANGELOG.md
214
+ source_code_uri: https://github.com/oauth-xx/snaky_hash/releases/tag//v2.0.3
215
+ changelog_uri: https://gitlab.com/oauth-xx/snaky_hash/-/blob/v2.0.3/CHANGELOG.md
216
216
  bug_tracker_uri: https://gitlab.com/oauth-xx/snaky_hash/-/issues
217
- documentation_uri: https://www.rubydoc.info/gems/snaky_hash/2.0.2
217
+ documentation_uri: https://www.rubydoc.info/gems/snaky_hash/2.0.3
218
218
  wiki_uri: https://gitlab.com/oauth-xx/snaky_hash/-/wiki
219
219
  mailing_list_uri: https://groups.google.com/g/oauth-ruby
220
220
  funding_uri: https://liberapay.com/pboling
metadata.gz.sig CHANGED
Binary file