snaky_hash 2.0.1 → 2.0.7

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.
data/README.md CHANGED
@@ -1,33 +1,138 @@
1
- # SnakyHash
1
+ <a href="https://github.com/ruby-oauth"><img alt="ruby-oauth Logo by Aboling0, CC BY-SA 4.0" src="https://logos.galtzo.com/assets/images/ruby-oauth/avatar-128px.svg" width="14%" align="right"/></a>
2
2
 
3
- This gem is used by the `oauth` and `oauth2` gems, and others, to normalize hash keys and lookups,
4
- and provide a nice psuedo-object interface.
3
+ # 🔮 SnakyHash
5
4
 
6
- It has its roots in the `Rash` (specifically the [`rash_alt`](https://github.com/shishi/rash_alt) flavor), which is a special `Mash`, made popular by the `hashie` gem.
5
+ [![Version][👽versioni]][👽version] [![GitHub tag (latest SemVer)][⛳️tag-img]][⛳️tag] [![License: MIT][📄license-img]][📄license] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![CodeCov Test Coverage][🏀codecovi]][🏀codecov] [![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] [![Deps Locked][🚎13-🔒️-wfi]][🚎13-🔒️-wf] [![Deps Unlocked][🚎14-🔓️-wfi]][🚎14-🔓️-wf] [![CI Test Coverage][🚎2-cov-wfi]][🚎2-cov-wf] [![CI Style][🚎5-st-wfi]][🚎5-st-wf] [![Apache SkyWalking Eyes License Compatibility Check][🚎15-🪪-wfi]][🚎15-🪪-wf]
7
6
 
8
- Classes that include `SnakyHash::Snake` should inherit from `Hashie::Mash`.
7
+ `if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know][✉️discord-invite], as I may have missed the [discord notification][✉️discord-invite].
9
8
 
10
- ## Installation
9
+ ---
10
+
11
+ `if ci_badges.map(&:color).all? { it == "green"}` 👇️ send money so I can do more of this. FLOSS maintenance is now my full-time job.
12
+
13
+ [![OpenCollective Backers][🖇osc-backers-i]][🖇osc-backers] [![OpenCollective Sponsors][🖇osc-sponsors-i]][🖇osc-sponsors] [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Donate on PayPal][🖇paypal-img]][🖇paypal] [![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate at ko-fi.com][🖇kofi-img]][🖇kofi]
14
+
15
+ <details markdown="1">
16
+ <summary>👣 How will this project approach the September 2025 hostile takeover of RubyGems? 🚑️</summary>
17
+
18
+ I've summarized my thoughts in [this blog post](https://dev.to/galtzo/hostile-takeover-of-rubygems-my-thoughts-5hlo).
19
+
20
+ </details>
21
+
22
+ ## 🌻 Synopsis <a href="https://discord.gg/3qme4XHNKN"><img alt="Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0" src="https://logos.galtzo.com/assets/images/galtzo-floss/avatar-128px.svg" width="8%" align="right"/></a> <a href="https://ruby-toolbox.com"><img alt="ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5" src="https://logos.galtzo.com/assets/images/ruby-lang/avatar-128px.svg" width="8%" align="right"/></a>
23
+
24
+ ## 💡 Info you can shake a stick at
25
+
26
+ | Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |
27
+ |-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
28
+ | Works with JRuby | [![JRuby 9.2 Compat][💎jruby-9.2i]][🚎jruby-9.2-wf] [![JRuby 9.3 Compat][💎jruby-9.3i]][🚎jruby-9.3-wf] <br/> [![JRuby 9.4 Compat][💎jruby-9.4i]][🚎jruby-9.4-wf] [![JRuby 10.0 Compat][💎jruby-10.0i]][🚎jruby-10.0-wf] [![JRuby current Compat][💎jruby-c-i]][🚎10-j-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf]|
29
+ | Works with Truffle Ruby | [![Truffle Ruby 22.3 Compat][💎truby-22.3i]][🚎truby-22.3-wf] [![Truffle Ruby 23.0 Compat][💎truby-23.0i]][🚎truby-23.0-wf] [![Truffle Ruby 23.1 Compat][💎truby-23.1i]][🚎truby-23.1-wf] <br/> [![Truffle Ruby 24.2 Compat][💎truby-24.2i]][🚎truby-24.2-wf] [![Truffle Ruby 25.0 Compat][💎truby-25.0i]][🚎truby-25.0-wf] [![Truffle Ruby 33.0 Compat][💎truby-33.0i]][🚎truby-33.0-wf] [![Truffle Ruby current Compat][💎truby-c-i]][🚎9-t-wf] [![Truffle Ruby HEAD Compat][💎truby-headi]][🚎3-hd-wf]|
30
+ | Works with MRI Ruby 4 | [![Ruby current Compat][💎ruby-c-i]][🚎11-c-wf] [![Ruby HEAD Compat][💎ruby-headi]][🚎3-hd-wf]|
31
+ | Works with MRI Ruby 3 | [![Ruby 3.0 Compat][💎ruby-3.0i]][🚎ruby-3.0-wf] [![Ruby 3.1 Compat][💎ruby-3.1i]][🚎ruby-3.1-wf] [![Ruby 3.2 Compat][💎ruby-3.2i]][🚎ruby-3.2-wf] [![Ruby 3.3 Compat][💎ruby-3.3i]][🚎ruby-3.3-wf] [![Ruby 3.4 Compat][💎ruby-3.4i]][🚎ruby-3.4-wf]|
32
+ | Works with MRI Ruby 2 | ![Ruby 2.2 Compat][💎ruby-2.2i] ![Ruby 2.3 Compat][💎ruby-2.3i] <br/> [![Ruby 2.4 Compat][💎ruby-2.4i]][🚎ruby-2.4-wf] [![Ruby 2.5 Compat][💎ruby-2.5i]][🚎ruby-2.5-wf] [![Ruby 2.6 Compat][💎ruby-2.6i]][🚎ruby-2.6-wf] [![Ruby 2.7 Compat][💎ruby-2.7i]][🚎ruby-2.7-wf]|
33
+ | Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork] [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor] |
34
+ | Source | [![Source on GitLab.com][📜src-gl-img]][📜src-gl] [![Source on CodeBerg.org][📜src-cb-img]][📜src-cb] [![Source on Github.com][📜src-gh-img]][📜src-gh] [![The best SHA: dQw4w9WgXcQ!][🧮kloc-img]][🧮kloc] |
35
+ | Documentation | [![Current release on RubyDoc.info][📜docs-cr-rd-img]][🚎yard-current] [![YARD on Galtzo.com][📜docs-head-rd-img]][🚎yard-head] [![Maintainer Blog][🚂maint-blog-img]][🚂maint-blog] [![GitLab Wiki][📜gl-wiki-img]][📜gl-wiki] [![GitHub Wiki][📜gh-wiki-img]][📜gh-wiki] |
36
+ | Compliance | [![License: MIT][📄license-img]][📄license] [![Apache license compatibility: Category A][📄license-compat-img]][📄license-compat] [![📄ilo-declaration-img]][📄ilo-declaration] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] |
37
+ | Style | [![Enforced Code Style Linter][💎rlts-img]][💎rlts] [![Keep-A-Changelog 1.0.0][📗keep-changelog-img]][📗keep-changelog] [![Gitmoji Commits][📌gitmoji-img]][📌gitmoji] [![Compatibility appraised by: appraisal2][💎appraisal2-img]][💎appraisal2] |
38
+ | Maintainer 🎖️ | [![Follow Me on LinkedIn][💖🖇linkedin-img]][💖🖇linkedin] [![Follow Me on Ruby.Social][💖🐘ruby-mast-img]][💖🐘ruby-mast] [![Follow Me on Bluesky][💖🦋bluesky-img]][💖🦋bluesky] [![Contact Maintainer][🚂maint-contact-img]][🚂maint-contact] [![My technical writing][💖💁🏼‍♂️devto-img]][💖💁🏼‍♂️devto] |
39
+ | `...` 💖 | [![Find Me on WellFound:][💖✌️wellfound-img]][💖✌️wellfound] [![Find Me on CrunchBase][💖💲crunchbase-img]][💖💲crunchbase] [![My LinkTree][💖🌳linktree-img]][💖🌳linktree] [![More About Me][💖💁🏼‍♂️aboutme-img]][💖💁🏼‍♂️aboutme] [🧊][💖🧊berg] [🐙][💖🐙hub] [🛖][💖🛖hut] [🧪][💖🧪lab] |
40
+
41
+ ### Compatibility
42
+
43
+ Compatible with MRI Ruby 2.2.0+, and concordant releases of JRuby, and TruffleRuby.
44
+ CI workflows and Appraisals are generated for MRI Ruby 2.4+.
45
+ This test floor is configured by `ruby.test_minimum` in `.kettle-jem.yml` and
46
+ may be higher than the gem's runtime compatibility floor when legacy Rubies are
47
+ not practical for the current toolchain.
48
+
49
+ <a href="https://github.com/kettle-dev"><img alt="kettle-dev Logo by Aboling0, CC BY-SA 4.0" src="https://logos.galtzo.com/assets/images/kettle-dev/avatar-128px.svg" width="14%" align="right"/></a>
50
+
51
+ The _amazing_ test matrix is powered by the kettle-dev stack.
52
+
53
+ <details markdown="1">
54
+ <summary>How kettle-dev manages complexity in tests</summary>
55
+
56
+ | Gem | Source | Role | Daily download rank |
57
+ |-----|--------|------|---------------------|
58
+ | [appraisal2](https://bestgems.org/gems/appraisal2) | [GitHub](https://github.com/appraisal-rb/appraisal2) | multi-dependency Appraisal matrix generation | [![Daily download rank for appraisal2](https://img.shields.io/gem/rd/appraisal2.svg?style=flat-square)](https://bestgems.org/gems/appraisal2) |
59
+ | [appraisal2-rubocop](https://bestgems.org/gems/appraisal2-rubocop) | [GitHub](https://github.com/appraisal-rb/appraisal2-rubocop) | RuboCop Appraisal generator integration | [![Daily download rank for appraisal2-rubocop](https://img.shields.io/gem/rd/appraisal2-rubocop.svg?style=flat-square)](https://bestgems.org/gems/appraisal2-rubocop) |
60
+ | [kettle-dev](https://bestgems.org/gems/kettle-dev) | [GitHub](https://github.com/kettle-dev/kettle-dev) | development, release, and CI workflow tooling | [![Daily download rank for kettle-dev](https://img.shields.io/gem/rd/kettle-dev.svg?style=flat-square)](https://bestgems.org/gems/kettle-dev) |
61
+ | [kettle-jem](https://bestgems.org/gems/kettle-jem) | [GitHub](https://github.com/kettle-dev/kettle-jem) | Appraisals & CI workflow templates | [![Daily download rank for kettle-jem](https://img.shields.io/gem/rd/kettle-jem.svg?style=flat-square)](https://bestgems.org/gems/kettle-jem) |
62
+ | [kettle-soup-cover](https://bestgems.org/gems/kettle-soup-cover) | [GitHub](https://github.com/kettle-dev/kettle-soup-cover) | SimpleCov coverage policy and reporting | [![Daily download rank for kettle-soup-cover](https://img.shields.io/gem/rd/kettle-soup-cover.svg?style=flat-square)](https://bestgems.org/gems/kettle-soup-cover) |
63
+ | [kettle-test](https://bestgems.org/gems/kettle-test) | [GitHub](https://github.com/kettle-dev/kettle-test) | standard test runner and coverage harness | [![Daily download rank for kettle-test](https://img.shields.io/gem/rd/kettle-test.svg?style=flat-square)](https://bestgems.org/gems/kettle-test) |
64
+ | [rubocop-lts](https://bestgems.org/gems/rubocop-lts) | [GitHub](https://github.com/rubocop-lts/rubocop-lts) | Ruby-version-aware linting | [![Daily download rank for rubocop-lts](https://img.shields.io/gem/rd/rubocop-lts.svg?style=flat-square)](https://bestgems.org/gems/rubocop-lts) |
65
+ | [turbo_tests2](https://bestgems.org/gems/turbo_tests2) | [GitHub](https://github.com/galtzo-floss/turbo_tests2) | parallel test execution | [![Daily download rank for turbo_tests2](https://img.shields.io/gem/rd/turbo_tests2.svg?style=flat-square)](https://bestgems.org/gems/turbo_tests2) |
66
+
67
+ </details>
68
+
69
+ ### Federated DVCS
70
+
71
+ <details markdown="1">
72
+ <summary>Find this repo on federated forges (Coming soon!)</summary>
73
+
74
+ | Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
75
+ |-------------------------------------------------|-----------------------------------------------------------------------|---------------------------|--------------------------|---------------------------|--------------------------|------------------------------|
76
+ | 🧪 [ruby-oauth/snaky_hash on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix | ➖ |
77
+ | 🧊 [ruby-oauth/snaky_hash on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
78
+ | 🐙 [ruby-oauth/snaky_hash on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix | [💚][gh-discussions] |
79
+ | 🎮️ [Discord Server][✉️discord-invite] | [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] | [Let's][✉️discord-invite] | [talk][✉️discord-invite] | [about][✉️discord-invite] | [this][✉️discord-invite] | [library!][✉️discord-invite] |
80
+
81
+ </details>
82
+
83
+ [gh-discussions]: https://github.com/ruby-oauth/snaky_hash/discussions
84
+
85
+ ### Enterprise Support [![Tidelift](https://tidelift.com/badges/package/rubygems/snaky_hash)](https://tidelift.com/subscription/pkg/rubygems-snaky_hash?utm_source=rubygems-snaky_hash&utm_medium=referral&utm_campaign=readme)
86
+
87
+ Available as part of the Tidelift Subscription.
88
+
89
+ <details markdown="1">
90
+ <summary>Need enterprise-level guarantees?</summary>
91
+
92
+ The maintainers of this and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use.
93
+
94
+ [![Get help from me on Tidelift][🏙️entsup-tidelift-img]][🏙️entsup-tidelift]
95
+
96
+ - 💡Subscribe for support guarantees covering _all_ your FLOSS dependencies
97
+ - 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar]
98
+ - 💡Tidelift pays maintainers to maintain the software you depend on!<br/>📊`@`Pointy Haired Boss: An [enterprise support][🏙️entsup-tidelift] subscription is "[never gonna let you down][🧮kloc]", and *supports* open source maintainers
99
+
100
+ Alternatively:
101
+
102
+ - [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]
103
+ - [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork]
104
+ - [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor]
105
+
106
+ </details>
107
+
108
+ ## ✨ Installation
11
109
 
12
110
  Install the gem and add to the application's Gemfile by executing:
13
111
 
14
- $ bundle add snaky_hash
112
+ ```console
113
+ bundle add snaky_hash
114
+ ```
15
115
 
16
116
  If bundler is not being used to manage dependencies, install the gem by executing:
17
117
 
18
- $ gem install snaky_hash
118
+ ```console
119
+ gem install snaky_hash
120
+ ```
121
+
122
+ ## ⚙️ Configuration
19
123
 
20
- ## Usage
124
+ ## 🔧 Basic Usage
21
125
 
22
126
  ```ruby
23
127
  class MySnakedHash < Hashie::Mash
24
128
  include SnakyHash::Snake.new(key_type: :string) # or :symbol
25
129
  end
26
130
 
27
- snake = MySnakedHash.new(a: "a", "b" => "b", 2 => 2, "VeryFineHat" => "Feathers")
131
+ snake = MySnakedHash.new(:a => "a", "b" => "b", 2 => 2, "VeryFineHat" => "Feathers")
28
132
  snake.a # => 'a'
29
133
  snake.b # => 'b'
30
- snake[2] # 2
134
+ snake[2] # => 2
135
+ snake["2"] # => nil, note that this gem only affects string / symbol keys.
31
136
  snake.very_fine_hat # => 'Feathers'
32
137
  snake[:very_fine_hat] # => 'Feathers'
33
138
  snake["very_fine_hat"] # => 'Feathers'
@@ -38,19 +143,129 @@ The `key_type` determines how the key is actually stored, but the hash acts as "
38
143
  Note also that keys which do not respond to `to_sym`, because they don't have a natural conversion to a Symbol,
39
144
  are left as-is.
40
145
 
41
- ### Stranger Things
146
+ ### Serialization
147
+
148
+ ```ruby
149
+ class MySerializedSnakedHash < Hashie::Mash
150
+ include SnakyHash::Snake.new(
151
+ key_type: :symbol, # default :string
152
+ serializer: true # default: false
153
+ )
154
+ end
155
+
156
+ snake = MySerializedSnakedHash.new(:a => "a", "b" => "b", 2 => 2, "VeryFineHat" => "Feathers") # => {a: "a", b: "b", 2 => 2, very_fine_hat: "Feathers"}
157
+ dump = MySerializedSnakedHash.dump(snake) # => "{\"a\":\"a\",\"b\":\"b\",\"2\":2,\"very_fine_hat\":\"Feathers\"}"
158
+ hydrated = MySerializedSnakedHash.load(dump) # => {a: "a", b: "b", "2": 2, very_fine_hat: "Feathers"}
159
+ hydrated.class # => MySerializedSnakedHash
160
+ hydrated.a # => 'a'
161
+ hydrated.b # => 'b'
162
+ hydrated[2] # => nil # NOTE: this is the opposite of snake[2] => 2
163
+ hydrated["2"] # => 2 # NOTE: this is the opposite of snake["2"] => nil
164
+ hydrated.very_fine_hat # => 'Feathers'
165
+ hydrated[:very_fine_hat] # => 'Feathers'
166
+ hydrated["very_fine_hat"] # => 'Feathers'
167
+ ```
168
+
169
+ Note that the key `VeryFineHat` changed to `very_fine_hat`.
170
+ That is indeed the point of this library, so not a bug.
171
+
172
+ Note that the key `2` changed to `"2"` (because JSON keys are strings).
173
+ When the JSON dump was reloaded it did not know to restore it as `2` instead of `"2"`.
174
+ This is also not a bug, though if you need different behavior, there is a solution in the [next section](#extensions).
175
+
176
+ ### Extensions
177
+
178
+ You can write your own arbitrary extensions:
179
+
180
+ * "Hash Load" extensions operate on the hash and nested hashes
181
+ * use `::load_hash_extensions.add(:extension_name) { |hash| }`
182
+ * since v2.0.2, bugs fixed in v2.0.3
183
+ * "Value Load" extensions operate on the values, and nested hashes' values, if any
184
+ * use `::load_value_extensions.add(:extension_name) { |value| }`
185
+ * since v2.0.2, bugs fixed in v2.0.3
186
+ * "Hash Dump" extensions operate on the hash and nested hashes
187
+ * use `::dump_hash_extensions.add(:extension_name) { |value| }`
188
+ * since v2.0.3
189
+ * "Value Dump" extensions operate on the values, and nested hashes' values, if any
190
+ * use `::dump_value_extensions.add(:extension_name) { |value| }`
191
+ * since v2.0.2, bugs fixed in v2.0.3
192
+
193
+ #### Example
194
+
195
+ Let's say I want to really smash up my hash and make it more food-like.
196
+
197
+ ```ruby
198
+ class MyExtSnakedHash < Hashie::Mash
199
+ include SnakyHash::Snake.new(
200
+ key_type: :symbol, # default :string
201
+ serializer: true # default: false
202
+ )
203
+ end
204
+
205
+ # We could swap all values with indexed apples (obliteraating nested data!)
206
+ MyExtSnakedHash.dump_hash_extensions.add(:to_apple) do |value|
207
+ num = 0
208
+ value.transform_values do |_key|
209
+ key = "apple-#{num}"
210
+ num += 1
211
+ key
212
+ end
213
+ end
214
+
215
+ # And then when loading the dump we could convert the yum to pear
216
+ MyExtSnakedHash.load_hash_extensions.add(:apple_to_pear) do |value|
217
+ value.transform_keys do |key|
218
+ key.to_s.sub("yum", "pear")
219
+ end
220
+ end
221
+
222
+ # We could swap all index numbers "beet-<number>"
223
+ MyExtSnakedHash.dump_value_extensions.add(:to_beet) do |value|
224
+ value.to_s.sub(/(\d+)/) { |match| "beet-#{match[0]}" }
225
+ end
226
+
227
+ # And then when loading the dump we could convert beet to corn
228
+ MyExtSnakedHash.load_value_extensions.add(:beet_to_corn) do |value|
229
+ value.to_s.sub("beet", "corn")
230
+ end
231
+
232
+ snake = MyExtSnakedHash.new({"YumBread" => "b", "YumCake" => {"b" => "b"}, "YumBoba" => [1, 2, 3]})
233
+ snake # => {yum_bread: "b", yum_cake: {b: "b"}, yum_boba: [1, 2, 3]}
234
+ snake.yum_bread # => "b"
235
+ snake.yum_cake # => {b: "b"}
236
+ snake.yum_boba # => [1, 2, 3]
237
+ dump = snake.dump
238
+ dump # => "{\"yum_bread\":\"apple-beet-0\",\"yum_cake\":\"apple-beet-1\",\"yum_boba\":\"apple-beet-2\"}"
239
+ hydrated = MyExtSnakedHash.load(dump)
240
+ hydrated # => {pear_bread: "apple-corn-0", pear_cake: "apple-corn-1", pear_boba: "apple-corn-2"}
241
+ ```
242
+
243
+ See the specs for more examples.
244
+
245
+ ### Bad Ideas
42
246
 
43
247
  I don't recommend using these features... but they exist (for now).
248
+
249
+ <details>
250
+ <summary>Show me what I should *not* do!</summary>
251
+
44
252
  You can still access the original un-snaked camel keys.
45
253
  And through them you can even use un-snaked camel methods.
254
+ But don't.
46
255
 
47
256
  ```ruby
257
+ snake = SnakyHash::StringKeyed["VeryFineHat" => "Feathers"]
48
258
  snake.key?("VeryFineHat") # => true
49
259
  snake["VeryFineHat"] # => 'Feathers'
50
260
  snake.VeryFineHat # => 'Feathers', PLEASE don't do this!!!
51
261
  snake["VeryFineHat"] = "pop" # Please don't do this... you'll get a warning, and it works (for now), but no guarantees.
52
262
  # 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.
53
263
  # => "pop"
264
+ ```
265
+
266
+ Since you are reading this, here's what to do instead.
267
+
268
+ ```ruby
54
269
  snake.very_fine_hat = "pop" # => 'pop', do this instead!!!
55
270
  snake.very_fine_hat # => 'pop'
56
271
  snake[:very_fine_hat] = "moose" # => 'moose', or do this instead!!!
@@ -59,20 +274,412 @@ snake["very_fine_hat"] = "cheese" # => 'cheese', or do this instead!!!
59
274
  snake.very_fine_hat # => 'cheese'
60
275
  ```
61
276
 
62
- ## Development
277
+ </details>
278
+
279
+ ### 🚀 Release Instructions
280
+
281
+ See [CONTRIBUTING.md][🤝contributing].
282
+
283
+ ## 🦷 FLOSS Funding
284
+
285
+ While ruby-oauth tools are free software and will always be, the project would benefit immensely from some funding.
286
+ Raising a monthly budget of... "dollars" would make the project more sustainable.
287
+
288
+ We welcome both individual and corporate sponsors! We also offer a
289
+ wide array of funding channels to account for your preferences.
290
+ Currently, [Open Collective][🖇osc] is our preferred funding platform.
291
+
292
+ **If you're working in a company that's making significant use of ruby-oauth tools we'd
293
+ appreciate it if you suggest to your company to become a ruby-oauth sponsor.**
294
+
295
+ You can support the development of ruby-oauth tools via
296
+ [GitHub Sponsors][🖇sponsor],
297
+ [Liberapay][⛳liberapay],
298
+ [PayPal][🖇paypal],
299
+ [Open Collective][🖇osc]
300
+ and [Tidelift][🏙️entsup-tidelift].
301
+
302
+ | 📍 NOTE |
303
+ |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
304
+ | If doing a sponsorship in the form of donation is problematic for your company <br/> from an accounting standpoint, we'd recommend the use of Tidelift, <br/> where you can get a support-like subscription instead. |
305
+
306
+ ### Open Collective for Individuals
307
+
308
+ Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/ruby-oauth#backer)]
309
+
310
+ NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
311
+
312
+ <!-- OPENCOLLECTIVE-INDIVIDUALS:START -->
313
+ No backers yet. Be the first!
314
+ <!-- OPENCOLLECTIVE-INDIVIDUALS:END -->
315
+
316
+ ### Open Collective for Organizations
317
+
318
+ Become a sponsor and get your logo on our README on GitHub with a link to your site. [[Become a sponsor](https://opencollective.com/ruby-oauth#sponsor)]
319
+
320
+ NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
321
+
322
+ <!-- OPENCOLLECTIVE-ORGANIZATIONS:START -->
323
+ No sponsors yet. Be the first!
324
+
325
+ ### Open Collective for Donors
326
+
327
+ [Bill Woika](https://opencollective.com/bill-woika) [Philipp Ebneter](https://opencollective.com/guest-e77282f7) [Grigoriy](https://opencollective.com/guest-c93e0c48)
328
+ <!-- OPENCOLLECTIVE-ORGANIZATIONS:END -->
329
+
330
+ [kettle-readme-backers]: https://github.com/ruby-oauth/snaky_hash/blob/main/bin/kettle-readme-backers
331
+
332
+ ### Another way to support open-source
333
+
334
+ I’m driven by a passion to foster a thriving open-source community – a space where people can tackle complex problems, no matter how small. Revitalizing libraries that have fallen into disrepair, and building new libraries focused on solving real-world challenges, are my passions. I was recently affected by layoffs, and the tech jobs market is unwelcoming. I’m reaching out here because your support would significantly aid my efforts to provide for my family, and my farm (11 🐔 chickens, 2 🐶 dogs, 3 🐰 rabbits, 8 🐈‍ cats).
335
+
336
+ If you work at a company that uses my work, please encourage them to support me as a corporate sponsor. My work on gems you use might show up in `bundle fund`.
337
+
338
+ I’m developing a new library, [floss_funding][🖇floss-funding-gem], designed to empower open-source developers like myself to get paid for the work we do, in a sustainable way. Please give it a look.
339
+
340
+ **[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
341
+
342
+ [![OpenCollective Backers][🖇osc-backers-i]][🖇osc-backers] [![OpenCollective Sponsors][🖇osc-sponsors-i]][🖇osc-sponsors] [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Donate on PayPal][🖇paypal-img]][🖇paypal] [![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate to my FLOSS efforts at ko-fi.com][🖇kofi-img]][🖇kofi]
343
+
344
+ ## 🔐 Security
345
+
346
+ See [SECURITY.md][🔐security].
347
+
348
+ ## 🤝 Contributing
349
+
350
+ If you need some ideas of where to help, you could work on adding more code coverage,
351
+ or if it is already 💯 (see [below](#code-coverage)) check [issues][🤝gh-issues] or [PRs][🤝gh-pulls],
352
+ or use the gem and think about how it could be better.
353
+
354
+ We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it.
355
+
356
+ See [CONTRIBUTING.md][🤝contributing] for more detailed instructions.
357
+
358
+ ### 🚀 Release Instructions
359
+
360
+ See [CONTRIBUTING.md][🤝contributing].
361
+
362
+ ### Code Coverage
363
+
364
+ <details markdown="1">
365
+ <summary>Coverage service badges</summary>
366
+
367
+ [![Coverage Graph][🏀codecov-g]][🏀codecov]
368
+
369
+ [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls]
370
+
371
+ [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov]
372
+
373
+ </details>
374
+
375
+ ### 🪇 Code of Conduct
376
+
377
+ Everyone interacting with this project's codebases, issue trackers,
378
+ chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct].
379
+
380
+ ## 🌈 Contributors
381
+
382
+ [![Contributors][🖐contributors-img]][🖐contributors]
383
+
384
+ Made with [contributors-img][🖐contrib-rocks].
385
+
386
+ Also see GitLab Contributors: [https://gitlab.com/ruby-oauth/snaky_hash/-/graphs/main][🚎contributors-gl]
387
+
388
+ <details markdown="1">
389
+ <summary>⭐️ Star History</summary>
390
+
391
+ <a href="https://star-history.com/ruby-oauth/snaky_hash&Date">
392
+ <picture>
393
+ <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=ruby-oauth/snaky_hash&type=Date&theme=dark" />
394
+ <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=ruby-oauth/snaky_hash&type=Date" />
395
+ <img alt="Star History Chart" src="https://api.star-history.com/svg?repos=ruby-oauth/snaky_hash&type=Date" />
396
+ </picture>
397
+ </a>
398
+
399
+ </details>
400
+
401
+ ## 📌 Versioning
402
+
403
+ This library follows [![Semantic Versioning 2.0.0][📌semver-img]][📌semver] for its public API where practical.
404
+ For most applications, prefer the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
405
+
406
+ For example:
407
+
408
+ ```ruby
409
+ spec.add_dependency("snaky_hash", "~> 2.0")
410
+ ```
411
+
412
+ <details markdown="1">
413
+ <summary>📌 Is "Platform Support" part of the public API? More details inside.</summary>
414
+
415
+ Dropping support for a platform can be a breaking change for affected users.
416
+ If a release changes supported platforms, it should be called out clearly in the changelog and versioned with that impact in mind.
417
+
418
+ To get a better understanding of how SemVer is intended to work over a project's lifetime,
419
+ read this article from the creator of SemVer:
420
+
421
+ - ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]
422
+
423
+ </details>
424
+
425
+ See [CHANGELOG.md][📌changelog] for a list of releases.
426
+
427
+ ## 📄 License
428
+
429
+ The gem is available as open source under the terms of
430
+ the [MIT](MIT.md) [![License: MIT][📄license-img]][📄license-ref].
431
+
432
+ ### © Copyright
433
+
434
+ See [LICENSE.md][📄license] for the official copyright notice.
435
+
436
+ <details markdown="1">
437
+ <summary>Copyright holders</summary>
438
+
439
+ - Copyright (c) 2022, 2025-2026 Peter H. Boling
440
+
441
+ </details>
442
+
443
+ ## 🤑 A request for help
444
+
445
+ Maintainers have teeth and need to pay their dentists.
446
+ After getting laid off in an RIF in March, and encountering difficulty finding a new one,
447
+ I began spending most of my time building open source tools.
448
+ I'm hoping to be able to pay for my kids' health insurance this month,
449
+ so if you value the work I am doing, I need your support.
450
+ Please consider sponsoring me or the project.
451
+
452
+ To join the community or get help 👇️ Join the Discord.
453
+
454
+ [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]
455
+
456
+ To say "thanks!" ☝️ Join the Discord or 👇️ send money.
63
457
 
64
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
458
+ [![Sponsor ruby-oauth/snaky_hash on Open Source Collective][🖇osc-all-bottom-img]][🖇osc] 💌 [![Sponsor me on GitHub Sponsors][🖇sponsor-bottom-img]][🖇sponsor] 💌 [![Sponsor me on Liberapay][⛳liberapay-bottom-img]][⛳liberapay] 💌 [![Donate on PayPal][🖇paypal-bottom-img]][🖇paypal]
65
459
 
66
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
460
+ ### Please give the project a star ♥.
67
461
 
68
- ## Contributing
462
+ Many parts of this project are actively managed by a [kettle-jem](https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/kettle-jem) smart template utilizing [StructuredMerge.org](https://structuredmerge.org) merge contracts.
69
463
 
70
- Bug reports and pull requests are welcome on GitHub at https://gitlab.com/oauth-xx/snaky_hash. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://gitlab.com/oauth-xx/snaky_hash/-/blob/main/CODE_OF_CONDUCT.md).
464
+ Thanks for RTFM. ☺️
71
465
 
72
- ## License
466
+ [⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611&style=flat
467
+ [⛳liberapay-bottom-img]: https://img.shields.io/liberapay/goal/pboling.svg?style=for-the-badge&logo=liberapay&color=a51611
468
+ [⛳liberapay]: https://liberapay.com/pboling/donate
469
+ [🖇osc-all-img]: https://img.shields.io/opencollective/all/ruby-oauth
470
+ [🖇osc-sponsors-img]: https://img.shields.io/opencollective/sponsors/ruby-oauth
471
+ [🖇osc-backers-img]: https://img.shields.io/opencollective/backers/ruby-oauth
472
+ [🖇osc-backers]: https://opencollective.com/ruby-oauth#backer
473
+ [🖇osc-backers-i]: https://opencollective.com/ruby-oauth/backers/badge.svg?style=flat
474
+ [🖇osc-sponsors]: https://opencollective.com/ruby-oauth#sponsor
475
+ [🖇osc-sponsors-i]: https://opencollective.com/ruby-oauth/sponsors/badge.svg?style=flat
476
+ [🖇osc-all-bottom-img]: https://img.shields.io/opencollective/all/ruby-oauth?style=for-the-badge
477
+ [🖇osc-sponsors-bottom-img]: https://img.shields.io/opencollective/sponsors/ruby-oauth?style=for-the-badge
478
+ [🖇osc-backers-bottom-img]: https://img.shields.io/opencollective/backers/ruby-oauth?style=for-the-badge
479
+ [🖇osc]: https://opencollective.com/ruby-oauth
480
+ [🖇sponsor-img]: https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github
481
+ [🖇sponsor-bottom-img]: https://img.shields.io/badge/Sponsor_Me!-pboling-blue?style=for-the-badge&logo=github
482
+ [🖇sponsor]: https://github.com/sponsors/pboling
483
+ [🖇kofi-img]: https://img.shields.io/badge/ko--fi-%E2%9C%93-a51611.svg?style=flat
484
+ [🖇kofi]: https://ko-fi.com/pboling
485
+ [🖇buyme-small-img]: https://img.shields.io/badge/buy_me_a_coffee-%E2%9C%93-a51611.svg?style=flat
486
+ [🖇buyme-img]: https://img.buymeacoffee.com/button-api/?text=Buy%20me%20a%20latte&emoji=&slug=pboling&button_colour=FFDD00&font_colour=000000&font_family=Cookie&outline_colour=000000&coffee_colour=ffffff
487
+ [🖇buyme]: https://www.buymeacoffee.com/pboling
488
+ [🖇paypal-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=flat&logo=paypal
489
+ [🖇paypal-bottom-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=for-the-badge&logo=paypal&color=0A0A0A
490
+ [🖇paypal]: https://www.paypal.com/paypalme/peterboling
491
+ [🖇floss-funding.dev]: https://floss-funding.dev
492
+ [🖇floss-funding-gem]: https://github.com/galtzo-floss/floss_funding
493
+ [✉️discord-invite]: https://discord.gg/3qme4XHNKN
494
+ [✉️discord-invite-img-ftb]: https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord
495
+ [✉️ruby-friends-img]: https://img.shields.io/badge/daily.dev-%F0%9F%92%8E_Ruby_Friends-0A0A0A?style=for-the-badge&logo=dailydotdev&logoColor=white
496
+ [✉️ruby-friends]: https://app.daily.dev/squads/rubyfriends
73
497
 
74
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
498
+ [✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
499
+ [⛳️gem-namespace]: https://github.com/ruby-oauth/snaky_hash
500
+ [⛳️namespace-img]: https://img.shields.io/badge/namespace-SnakyHash-3C2D2D.svg?style=square&logo=ruby&logoColor=white
501
+ [⛳️gem-name]: https://bestgems.org/gems/snaky_hash
502
+ [⛳️name-img]: https://img.shields.io/badge/name-snaky__hash-3C2D2D.svg?style=square&logo=rubygems&logoColor=red
503
+ [⛳️tag-img]: https://img.shields.io/github/tag/ruby-oauth/snaky_hash.svg
504
+ [⛳️tag]: https://github.com/ruby-oauth/snaky_hash/releases
505
+ [🚂maint-blog]: http://www.railsbling.com/tags/snaky_hash
506
+ [🚂maint-blog-img]: https://img.shields.io/badge/blog-railsbling-0093D0.svg?style=for-the-badge&logo=rubyonrails&logoColor=orange
507
+ [🚂maint-contact]: http://www.railsbling.com/contact
508
+ [🚂maint-contact-img]: https://img.shields.io/badge/Contact-Maintainer-0093D0.svg?style=flat&logo=rubyonrails&logoColor=red
509
+ [💖🖇linkedin]: http://www.linkedin.com/in/peterboling
510
+ [💖🖇linkedin-img]: https://img.shields.io/badge/LinkedIn-Profile-0B66C2?style=flat&logo=newjapanprowrestling
511
+ [💖✌️wellfound]: https://wellfound.com/u/peter-boling
512
+ [💖✌️wellfound-img]: https://img.shields.io/badge/peter--boling-orange?style=flat&logo=wellfound
513
+ [💖💲crunchbase]: https://www.crunchbase.com/person/peter-boling
514
+ [💖💲crunchbase-img]: https://img.shields.io/badge/peter--boling-purple?style=flat&logo=crunchbase
515
+ [💖🐘ruby-mast]: https://ruby.social/@galtzo
516
+ [💖🐘ruby-mast-img]: https://img.shields.io/mastodon/follow/109447111526622197?domain=https://ruby.social&style=flat&logo=mastodon&label=Ruby%20@galtzo
517
+ [💖🦋bluesky]: https://bsky.app/profile/galtzo.com
518
+ [💖🦋bluesky-img]: https://img.shields.io/badge/@galtzo.com-0285FF?style=flat&logo=bluesky&logoColor=white
519
+ [💖🌳linktree]: https://linktr.ee/galtzo
520
+ [💖🌳linktree-img]: https://img.shields.io/badge/galtzo-purple?style=flat&logo=linktree
521
+ [💖💁🏼‍♂️devto]: https://dev.to/galtzo
522
+ [💖💁🏼‍♂️devto-img]: https://img.shields.io/badge/dev.to-0A0A0A?style=flat&logo=devdotto&logoColor=white
523
+ [💖💁🏼‍♂️aboutme]: https://about.me/peter.boling
524
+ [💖💁🏼‍♂️aboutme-img]: https://img.shields.io/badge/about.me-0A0A0A?style=flat&logo=aboutme&logoColor=white
525
+ [💖🧊berg]: https://codeberg.org/pboling
526
+ [💖🐙hub]: https://github.org/pboling
527
+ [💖🛖hut]: https://sr.ht/~galtzo/
528
+ [💖🧪lab]: https://gitlab.com/pboling
529
+ [👨🏼‍🏫expsup-upwork]: https://www.upwork.com/freelancers/~014942e9b056abdf86?mp_source=share
530
+ [👨🏼‍🏫expsup-upwork-img]: https://img.shields.io/badge/UpWork-13544E?style=for-the-badge&logo=Upwork&logoColor=white
531
+ [👨🏼‍🏫expsup-codementor]: https://www.codementor.io/peterboling?utm_source=github&utm_medium=button&utm_term=peterboling&utm_campaign=github
532
+ [👨🏼‍🏫expsup-codementor-img]: https://img.shields.io/badge/CodeMentor-Get_Help-1abc9c?style=for-the-badge&logo=CodeMentor&logoColor=white
533
+ [🏙️entsup-tidelift]: https://tidelift.com/subscription/pkg/rubygems-snaky_hash?utm_source=rubygems-snaky_hash&utm_medium=referral&utm_campaign=readme
534
+ [🏙️entsup-tidelift-img]: https://img.shields.io/badge/Tidelift_and_Sonar-Enterprise_Support-FD3456?style=for-the-badge&logo=sonar&logoColor=white
535
+ [🏙️entsup-tidelift-sonar]: https://blog.tidelift.com/tidelift-joins-sonar
536
+ [💁🏼‍♂️peterboling]: http://www.peterboling.com
537
+ [🚂railsbling]: http://www.railsbling.com
538
+ [📜src-gl-img]: https://img.shields.io/badge/GitLab-FBA326?style=for-the-badge&logo=Gitlab&logoColor=orange
539
+ [📜src-gl]: https://gitlab.com/ruby-oauth/snaky_hash
540
+ [📜src-cb-img]: https://img.shields.io/badge/CodeBerg-4893CC?style=for-the-badge&logo=CodeBerg&logoColor=blue
541
+ [📜src-cb]: https://codeberg.org/ruby-oauth/snaky_hash
542
+ [📜src-gh-img]: https://img.shields.io/badge/GitHub-238636?style=for-the-badge&logo=Github&logoColor=green
543
+ [📜src-gh]: https://github.com/ruby-oauth/snaky_hash
544
+ [📜docs-cr-rd-img]: https://img.shields.io/badge/RubyDoc-Current_Release-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
545
+ [📜docs-head-rd-img]: https://img.shields.io/badge/YARD_on_Galtzo.com-HEAD-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
546
+ [📜gl-wiki]: https://gitlab.com/ruby-oauth/snaky_hash/-/wikis/home
547
+ [📜gh-wiki]: https://github.com/ruby-oauth/snaky_hash/wiki
548
+ [📜gl-wiki-img]: https://img.shields.io/badge/wiki-gitlab-943CD2.svg?style=for-the-badge&logo=gitlab&logoColor=white
549
+ [📜gh-wiki-img]: https://img.shields.io/badge/wiki-github-943CD2.svg?style=for-the-badge&logo=github&logoColor=white
550
+ [👽dl-rank]: https://bestgems.org/gems/snaky_hash
551
+ [👽dl-ranki]: https://img.shields.io/gem/rd/snaky_hash.svg
552
+ [👽version]: https://bestgems.org/gems/snaky_hash
553
+ [👽versioni]: https://img.shields.io/gem/v/snaky_hash.svg
554
+ [🏀qlty-mnt]: https://qlty.sh/gh/ruby-oauth/projects/snaky_hash
555
+ [🏀qlty-mnti]: https://qlty.sh/gh/ruby-oauth/projects/snaky_hash/maintainability.svg
556
+ [🏀qlty-cov]: https://qlty.sh/gh/ruby-oauth/projects/snaky_hash/metrics/code?sort=coverageRating
557
+ [🏀qlty-covi]: https://qlty.sh/gh/ruby-oauth/projects/snaky_hash/coverage.svg
558
+ [🏀codecov]: https://codecov.io/gh/ruby-oauth/snaky_hash
559
+ [🏀codecovi]: https://codecov.io/gh/ruby-oauth/snaky_hash/graph/badge.svg
560
+ [🏀coveralls]: https://coveralls.io/github/ruby-oauth/snaky_hash?branch=main
561
+ [🏀coveralls-img]: https://coveralls.io/repos/github/ruby-oauth/snaky_hash/badge.svg?branch=main
562
+ [🚎ruby-2.4-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/ruby-2.4.yml
563
+ [🚎ruby-2.5-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/ruby-2.5.yml
564
+ [🚎ruby-2.6-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/ruby-2.6.yml
565
+ [🚎ruby-2.7-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/ruby-2.7.yml
566
+ [🚎ruby-3.0-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/ruby-3.0.yml
567
+ [🚎ruby-3.1-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/ruby-3.1.yml
568
+ [🚎ruby-3.2-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/ruby-3.2.yml
569
+ [🚎ruby-3.3-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/ruby-3.3.yml
570
+ [🚎ruby-3.4-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/ruby-3.4.yml
571
+ [🚎jruby-9.2-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/jruby-9.2.yml
572
+ [🚎jruby-9.3-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/jruby-9.3.yml
573
+ [🚎jruby-9.4-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/jruby-9.4.yml
574
+ [🚎jruby-10.0-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/jruby-10.0.yml
575
+ [🚎truby-22.3-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/truffleruby-22.3.yml
576
+ [🚎truby-23.0-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/truffleruby-23.0.yml
577
+ [🚎truby-23.1-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/truffleruby-23.1.yml
578
+ [🚎truby-24.2-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/truffleruby-24.2.yml
579
+ [🚎truby-25.0-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/truffleruby-25.0.yml
580
+ [🚎truby-33.0-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/truffleruby-33.0.yml
581
+ [🚎2-cov-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/coverage.yml
582
+ [🚎2-cov-wfi]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/coverage.yml/badge.svg
583
+ [🚎3-hd-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/heads.yml
584
+ [🚎3-hd-wfi]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/heads.yml/badge.svg
585
+ [🚎5-st-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/style.yml
586
+ [🚎5-st-wfi]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/style.yml/badge.svg
587
+ [🚎9-t-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/truffle.yml
588
+ [🚎9-t-wfi]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/truffle.yml/badge.svg
589
+ [🚎10-j-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/jruby.yml
590
+ [🚎10-j-wfi]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/jruby.yml/badge.svg
591
+ [🚎11-c-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/current.yml
592
+ [🚎11-c-wfi]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/current.yml/badge.svg
593
+ [🚎12-crh-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/dep-heads.yml
594
+ [🚎12-crh-wfi]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/dep-heads.yml/badge.svg
595
+ [🚎13-🔒️-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/locked_deps.yml
596
+ [🚎13-🔒️-wfi]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/locked_deps.yml/badge.svg
597
+ [🚎14-🔓️-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/unlocked_deps.yml
598
+ [🚎14-🔓️-wfi]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/unlocked_deps.yml/badge.svg
599
+ [🚎15-🪪-wf]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/license-eye.yml
600
+ [🚎15-🪪-wfi]: https://github.com/ruby-oauth/snaky_hash/actions/workflows/license-eye.yml/badge.svg
601
+ [💎ruby-2.2i]: https://img.shields.io/badge/Ruby-2.2_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=white
602
+ [💎ruby-2.3i]: https://img.shields.io/badge/Ruby-2.3_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=white
603
+ [💎ruby-2.4i]: https://img.shields.io/badge/Ruby-2.4-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
604
+ [💎ruby-2.5i]: https://img.shields.io/badge/Ruby-2.5-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
605
+ [💎ruby-2.6i]: https://img.shields.io/badge/Ruby-2.6-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
606
+ [💎ruby-2.7i]: https://img.shields.io/badge/Ruby-2.7-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
607
+ [💎ruby-3.0i]: https://img.shields.io/badge/Ruby-3.0-CC342D?style=for-the-badge&logo=ruby&logoColor=white
608
+ [💎ruby-3.1i]: https://img.shields.io/badge/Ruby-3.1-CC342D?style=for-the-badge&logo=ruby&logoColor=white
609
+ [💎ruby-3.2i]: https://img.shields.io/badge/Ruby-3.2-CC342D?style=for-the-badge&logo=ruby&logoColor=white
610
+ [💎ruby-3.3i]: https://img.shields.io/badge/Ruby-3.3-CC342D?style=for-the-badge&logo=ruby&logoColor=white
611
+ [💎ruby-3.4i]: https://img.shields.io/badge/Ruby-3.4-CC342D?style=for-the-badge&logo=ruby&logoColor=white
612
+ [💎ruby-c-i]: https://img.shields.io/badge/Ruby-current-CC342D?style=for-the-badge&logo=ruby&logoColor=green
613
+ [💎ruby-headi]: https://img.shields.io/badge/Ruby-HEAD-CC342D?style=for-the-badge&logo=ruby&logoColor=blue
614
+ [💎truby-22.3i]: https://img.shields.io/badge/Truffle_Ruby-22.3-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
615
+ [💎truby-23.0i]: https://img.shields.io/badge/Truffle_Ruby-23.0-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
616
+ [💎truby-23.1i]: https://img.shields.io/badge/Truffle_Ruby-23.1-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
617
+ [💎truby-24.2i]: https://img.shields.io/badge/Truffle_Ruby-24.2-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
618
+ [💎truby-25.0i]: https://img.shields.io/badge/Truffle_Ruby-25.0-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
619
+ [💎truby-33.0i]: https://img.shields.io/badge/Truffle_Ruby-33.0-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
620
+ [💎truby-c-i]: https://img.shields.io/badge/Truffle_Ruby-current-34BCB1?style=for-the-badge&logo=ruby&logoColor=green
621
+ [💎truby-headi]: https://img.shields.io/badge/Truffle_Ruby-HEAD-34BCB1?style=for-the-badge&logo=ruby&logoColor=blue
622
+ [💎jruby-9.2i]: https://img.shields.io/badge/JRuby-9.2-FBE742?style=for-the-badge&logo=ruby&logoColor=red
623
+ [💎jruby-9.3i]: https://img.shields.io/badge/JRuby-9.3-FBE742?style=for-the-badge&logo=ruby&logoColor=red
624
+ [💎jruby-9.4i]: https://img.shields.io/badge/JRuby-9.4-FBE742?style=for-the-badge&logo=ruby&logoColor=red
625
+ [💎jruby-10.0i]: https://img.shields.io/badge/JRuby-10.0-FBE742?style=for-the-badge&logo=ruby&logoColor=red
626
+ [💎jruby-c-i]: https://img.shields.io/badge/JRuby-current-FBE742?style=for-the-badge&logo=ruby&logoColor=green
627
+ [💎jruby-headi]: https://img.shields.io/badge/JRuby-HEAD-FBE742?style=for-the-badge&logo=ruby&logoColor=blue
628
+ [🤝gh-issues]: https://github.com/ruby-oauth/snaky_hash/issues
629
+ [🤝gh-pulls]: https://github.com/ruby-oauth/snaky_hash/pulls
630
+ [🤝gl-issues]: https://gitlab.com/ruby-oauth/snaky_hash/-/issues
631
+ [🤝gl-pulls]: https://gitlab.com/ruby-oauth/snaky_hash/-/merge_requests
632
+ [🤝cb-issues]: https://codeberg.org/ruby-oauth/snaky_hash/issues
633
+ [🤝cb-pulls]: https://codeberg.org/ruby-oauth/snaky_hash/pulls
634
+ [🤝cb-donate]: https://donate.codeberg.org/
635
+ [🤝contributing]: https://github.com/ruby-oauth/snaky_hash/blob/main/CONTRIBUTING.md
636
+ [🏀codecov-g]: https://codecov.io/gh/ruby-oauth/snaky_hash/graph/badge.svg
637
+ [🖐contrib-rocks]: https://contrib.rocks
638
+ [🖐contributors]: https://github.com/ruby-oauth/snaky_hash/graphs/contributors
639
+ [🖐contributors-img]: https://contrib.rocks/image?repo=ruby-oauth/snaky_hash
640
+ [🚎contributors-gl]: https://gitlab.com/ruby-oauth/snaky_hash/-/graphs/main
641
+ [🪇conduct]: https://github.com/ruby-oauth/snaky_hash/blob/main/CODE_OF_CONDUCT.md
642
+ [🪇conduct-img]: https://img.shields.io/badge/Contributor_Covenant-2.1-259D6C.svg
643
+ [📌pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint
644
+ [📌semver]: https://semver.org/spec/v2.0.0.html
645
+ [📌semver-img]: https://img.shields.io/badge/semver-2.0.0-259D6C.svg?style=flat
646
+ [📌semver-breaking]: https://github.com/semver/semver/issues/716#issuecomment-869336139
647
+ [📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html
648
+ [📌changelog]: https://github.com/ruby-oauth/snaky_hash/blob/main/CHANGELOG.md
649
+ [📗keep-changelog]: https://keepachangelog.com/en/1.0.0/
650
+ [📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-34495e.svg?style=flat
651
+ [📌gitmoji]: https://gitmoji.dev
652
+ [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
653
+ [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
654
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.133-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
655
+ [🔐security]: https://github.com/ruby-oauth/snaky_hash/blob/main/SECURITY.md
656
+ [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
657
+ [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
658
+ [📄license]: LICENSE.md
659
+ [📄license-ref]: MIT.md
660
+ [📄license-img]: https://img.shields.io/badge/License-MIT-259D6C.svg
661
+ [📄license-compat]: https://www.apache.org/legal/resolved.html#category-a
662
+ [📄license-compat-img]: https://img.shields.io/badge/Apache_Compatible:_Category_A-%E2%9C%93-259D6C.svg?style=flat&logo=Apache
75
663
 
76
- ## Code of Conduct
664
+ [📄ilo-declaration]: https://www.ilo.org/declaration/lang--en/index.htm
665
+ [📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat
666
+ [🚎yard-current]: http://rubydoc.info/gems/snaky_hash
667
+ [🚎yard-head]: https://snaky-hash.galtzo.com
668
+ [💎stone_checksums]: https://github.com/galtzo-floss/stone_checksums
669
+ [💎SHA_checksums]: https://gitlab.com/ruby-oauth/snaky_hash/-/tree/main/checksums
670
+ [💎rlts]: https://github.com/rubocop-lts/rubocop-lts
671
+ [💎rlts-img]: https://img.shields.io/badge/code_style_&_linting-rubocop--lts-34495e.svg?plastic&logo=ruby&logoColor=white
672
+ [💎appraisal2]: https://github.com/appraisal-rb/appraisal2
673
+ [💎appraisal2-img]: https://img.shields.io/badge/appraised_by-appraisal2-34495e.svg?plastic&logo=ruby&logoColor=white
674
+ [💎d-in-dvcs]: https://railsbling.com/posts/dvcs/put_the_d_in_dvcs/
77
675
 
78
- Everyone interacting in the SnakyHash project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://gitlab.com/oauth-xx/snaky_hash/-/blob/main/CODE_OF_CONDUCT.md).
676
+ <!-- kettle-jem:metadata:start -->
677
+ | Field | Value |
678
+ |---|---|
679
+ | Package | snaky_hash |
680
+ | Description | 🔮 A Hashie::Mash joint to make #snakelife better |
681
+ | Homepage | https://github.com/ruby-oauth/snaky_hash |
682
+ | Source | https://github.com/ruby-oauth/snaky_hash |
683
+ | License | `MIT` |
684
+ | Funding | https://github.com/sponsors/pboling, https://ko-fi.com/pboling, https://liberapay.com/pboling/donate, https://opencollective.com/ruby-oauth, https://thanks.dev/u/gh/pboling, https://tidelift.com/funding/github/rubygems/snaky_hash, https://www.buymeacoffee.com/pboling |
685
+ <!-- kettle-jem:metadata:end -->