From 135db0fe5315e37176daf83dd7c52e200d3011d7 Mon Sep 17 00:00:00 2001 From: "Peter H. Boling" Date: Fri, 23 May 2025 07:47:55 +0700 Subject: [PATCH 1/4] =?UTF-8?q?=F0=9F=91=B7=20qlty.toml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- qlty.toml | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 qlty.toml diff --git a/README.md b/README.md index f27bc46..b447880 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # 🐍 SnakyHash -[![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] +[![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] --- diff --git a/qlty.toml b/qlty.toml new file mode 100644 index 0000000..e69ec73 --- /dev/null +++ b/qlty.toml @@ -0,0 +1,78 @@ +# For a guide to configuration, visit https://qlty.sh/d/config +# Or for a full reference, visit https://qlty.sh/d/qlty-toml +config_version = "0" + +exclude_patterns = [ + "*_min.*", + "*-min.*", + "*.min.*", + "**/.yarn/**", + "**/*.d.ts", + "**/assets/**", + "**/bin/**", + "**/bower_components/**", + "**/build/**", + "**/cache/**", + "**/config/**", + "**/.devcontainer", + "**/db/**", + "**/deps/**", + "**/dist/**", + "**/doc/**", + "**/extern/**", + "**/external/**", + "**/generated/**", + "**/Godeps/**", + "**/gradlew/**", + "**/mvnw/**", + "**/node_modules/**", + "**/protos/**", + "**/seed/**", + "**/target/**", + "**/templates/**", + "**/testdata/**", + "**/vendor/**", +] + + +test_patterns = [ + "**/test/**", + "**/spec/**", + "**/*.test.*", + "**/*.spec.*", + "**/*_test.*", + "**/*_spec.*", + "**/test_*.*", + "**/spec_*.*", +] + +[smells] +mode = "comment" + +[smells.boolean_logic] +threshold = 4 +enabled = true + +[smells.file_complexity] +threshold = 55 +enabled = false + +[smells.return_statements] +threshold = 4 +enabled = true + +[smells.nested_control_flow] +threshold = 4 +enabled = true + +[smells.function_parameters] +threshold = 4 +enabled = true + +[smells.function_complexity] +threshold = 5 +enabled = true + +[smells.duplication] +enabled = true +threshold = 20 \ No newline at end of file From 5b4b225203304c2db00307151a6c4b58c3b5abf4 Mon Sep 17 00:00:00 2001 From: "Peter H. Boling" Date: Fri, 23 May 2025 07:49:55 +0700 Subject: [PATCH 2/4] =?UTF-8?q?=E2=9C=A8=20New=20features=20and=20bug=20fi?= =?UTF-8?q?xes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Added - `#dump` instance method injected by `extend SnakyHash::Serializer` (@pboling) - `dump_hash_extensions` - new feature, analogous to `load_hash_extensions` (@pboling) - `dump_value_extensions` - alternate name for `dump_extensions` (@pboling) - `load_value_extensions` - alternate name for `load_extensions` (@pboling) - Clarifying documentation (@pboling) ### Fixed - Serializer extensions dump and load empty values properly (@pboling) - Fixed `dump_extensions`, `load_extensions`, `load_hash_extensions` - Intended usage is primarily JSON, and oauth2 gem - OAuth2 spec can have legitimately empty values (e.g. scopes could be empty) - Previous logic was inherited from design decisions made by `serialized_hashie` gem; doesn't apply here --- .rubocop_gradual.lock | 4 +- CHANGELOG.md | 43 +++- README.md | 107 ++++++--- REEK | 36 ++- doc/SnakyHash.html | 2 +- doc/SnakyHash/Error.html | 2 +- doc/SnakyHash/Extensions.html | 2 +- doc/SnakyHash/Serializer.html | 20 +- .../Serializer/BackportedInstanceMethods.html | 22 +- .../ConvenienceInstanceMethods.html | 224 ++++++++++++++++++ doc/SnakyHash/Serializer/Modulizer.html | 32 ++- doc/SnakyHash/Snake.html | 2 +- doc/SnakyHash/Snake/SnakyModulizer.html | 2 +- doc/SnakyHash/StringKeyed.html | 2 +- doc/SnakyHash/SymbolKeyed.html | 2 +- doc/SnakyHash/Version.html | 2 +- doc/_index.html | 17 +- doc/class_list.html | 2 +- doc/file.CHANGELOG.html | 79 ++++-- doc/file.CODE_OF_CONDUCT.html | 2 +- doc/file.CONTRIBUTING.html | 2 +- doc/file.LICENSE.html | 2 +- doc/file.README.html | 146 +++++++----- doc/file.SECURITY.html | 2 +- doc/index.html | 146 +++++++----- doc/method_list.html | 28 ++- doc/top-level-namespace.html | 2 +- lib/snaky_hash/serializer.rb | 62 +++-- spec/shared_contexts/base_hash.rb | 9 + spec/shared_contexts/without_serializer.rb | 7 + spec/shared_examples/a_serialized_hash.rb | 39 ++- spec/snaky_hash/serializer_spec.rb | 28 +++ 32 files changed, 816 insertions(+), 261 deletions(-) create mode 100644 doc/SnakyHash/Serializer/ConvenienceInstanceMethods.html diff --git a/.rubocop_gradual.lock b/.rubocop_gradual.lock index 4ea5290..9f334d6 100644 --- a/.rubocop_gradual.lock +++ b/.rubocop_gradual.lock @@ -5,8 +5,8 @@ "snaky_hash.gemspec:1781125773": [ [4, 23, 12, "Gemspec/RubyVersionGlobalsUsage: Do not use `RUBY_VERSION` in gemspec file.", 31296028] ], - "spec/shared_contexts/base_hash.rb:829438978": [ - [3, 22, 11, "RSpec/ContextWording: Context description should match /^when\\b/, /^with\\b/, or /^without\\b/.", 3936427458] + "spec/shared_contexts/base_hash.rb:2702242093": [ + [12, 22, 11, "RSpec/ContextWording: Context description should match /^when\\b/, /^with\\b/, or /^without\\b/.", 3936427458] ], "spec/snaky_hash/bad_snake_spec.rb:3931746112": [ [3, 16, 11, "RSpec/DescribeClass: The first argument to describe should be the class or module being tested.", 1577626599] diff --git a/CHANGELOG.md b/CHANGELOG.md index f567bac..f0fa4b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,31 @@ and this project adheres to [Semantic Versioning v2](https://semver.org/spec/v2. ## [Unreleased] ### Added ### Changed -### Fixed +### Deprecated ### Removed +### Fixed +### Security + +## [2.0.3] - 2025-05-23 +- TAG: [v2.0.3][2.0.3t] +- COVERAGE: 100.00% -- 130/130 lines in 7 files +- BRANCH COVERAGE: 100.00% -- 37/37 branches in 7 files +- 100.00% documented +### Added +- `#dump` instance method injected by `extend SnakyHash::Serializer` (@pboling) +- `dump_hash_extensions` - new feature, analogous to `load_hash_extensions` (@pboling) +- `dump_value_extensions` - alternate name for `dump_extensions` (@pboling) +- `load_value_extensions` - alternate name for `load_extensions` (@pboling) +- Clarifying documentation (@pboling) +### Fixed +- Serializer extensions dump and load empty values properly (@pboling) + - Fixed `dump_extensions`, `load_extensions`, `load_hash_extensions` + - Intended usage is primarily JSON, and oauth2 gem + - OAuth2 spec can have legitimately empty values (e.g. scopes could be empty) + - Previous logic was inherited from design decisions made by `serialized_hashie` gem; doesn't apply here -## [2.0.2] - 2025-05-21 ([tag][2.0.2t]) +## [2.0.2] - 2025-05-21 +- TAG: [v2.0.2][2.0.2t] - COVERAGE: 100.00% -- 119/119 lines in 7 files - BRANCH COVERAGE: 100.00% -- 35/35 branches in 7 files - 100.00% documented @@ -26,7 +47,8 @@ and this project adheres to [Semantic Versioning v2](https://semver.org/spec/v2. - Documentation site at [snaky-hash.galtzo.com](https://snaky-hash.galtzo.com) (@pboling) - 100% documented! (@pboling) -## [2.0.1] - 2022-09-23 ([tag][2.0.1t]) +## [2.0.1] - 2022-09-23 +- TAG: [v2.0.1][2.0.1t] ### Added - Certificate for signing gem releases (@pboling) - Gemspec metadata (@pboling) @@ -36,7 +58,8 @@ and this project adheres to [Semantic Versioning v2](https://semver.org/spec/v2. ### Changed - Gem releases are now cryptographically signed (@pboling) -## [2.0.0] - 2022-08-29 ([tag][2.0.0t]) +## [2.0.0] - 2022-08-29 +- TAG: [v2.0.0][2.0.0t] ### Changed - **BREAKING**: `SnakeHash::Snake` is now a mixin, now with support for symbol or string keys ```ruby @@ -48,18 +71,22 @@ end - `SnakyHash::StringKeyed`: a Hashie::Mash class with snake-cased String keys - `SnakyHash::SymbolKeyed`: a Hashie::Mash class with snake-cased Symbol keys -## [1.0.1] - 2022-08-26 ([tag][1.0.1t]) +## [1.0.1] - 2022-08-26 +- TAG: [v1.0.1][1.0.1t] ### Added - Missing LICENSE.txt file to release ### Removed - Accidentally added bundler dependency (vestige of transpec process) is now removed -## [1.0.0] - 2022-08-26 ([tag][1.0.0t]) +## [1.0.0] - 2022-08-26 +- TAG: [v1.0.0][1.0.0t] ### Added - Initial release -[Unreleased]: https://gitlab.com/oauth-xx/snaky_hash/-/compare/v2.0.2...main -[2.0.21]: https://gitlab.com/oauth-xx/snaky_hash/-/compare/v2.0.1...v2.0.2 +[Unreleased]: https://gitlab.com/oauth-xx/snaky_hash/-/compare/v2.0.3...main +[2.0.3]: https://gitlab.com/oauth-xx/snaky_hash/-/compare/v2.0.2...v2.0.3 +[2.0.3t]: https://gitlab.com/oauth-xx/snaky_hash/-/releases/tag/v2.0.3 +[2.0.2]: https://gitlab.com/oauth-xx/snaky_hash/-/compare/v2.0.1...v2.0.2 [2.0.2t]: https://gitlab.com/oauth-xx/snaky_hash/-/releases/tag/v2.0.2 [2.0.1]: https://gitlab.com/oauth-xx/snaky_hash/-/compare/v2.0.0...v2.0.1 [2.0.1t]: https://gitlab.com/oauth-xx/snaky_hash/-/releases/tag/v2.0.1 diff --git a/README.md b/README.md index b447880..4c3d00c 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ and provide a nice psuedo-object interface. It can be thought of as a mashup of: * `Rash` (specifically the [`rash_alt`](https://github.com/shishi/rash_alt) flavor), which is a special `Mash`, made popular by the `hashie` gem, and -* `serialized_hashie` [gem by krystal](https://github.com/krystal/serialized-hashie) +* `serialized_hashie` [gem by krystal](https://github.com/krystal/serialized-hashie), rewritten, with some behavior changes Classes that `include SnakyHash::Snake.new` should inherit from `Hashie::Mash`. @@ -46,6 +46,17 @@ SnakyHash::StringKeyed.class_eval do end ``` +or you can create a custom class + +```ruby +class MyHash < Hashie::Mash + include SnakyHash::Snake.new(key_type: :string, serializer: true) + # Which is the same as: + # include SnakyHash::Snake.new(key_type: :string) + # extend SnakyHash::Serializer +end +``` + You can then add serialization extensions as needed. See [serialization](#serialization) and [extensions](#extensions) for more. | 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 You can write your own arbitrary extensions: -* "Hash Load" extensions operate on the hash, and nested hashes +* "Hash Load" extensions operate on the hash and nested hashes * use `::load_hash_extensions.add(:extension_name) { |hash| }` -* "Load" extensions operate on the values, and nested hash's values, if any - * use `::load_extensions.add(:extension_name) { |value| }` -* "Dump" extensions operate on the values, and nested hash's values, if any - * use `::dump_extensions.add(:extension_name) { |value| }` + * since v2.0.2, bugs fixed in v2.0.3 +* "Value Load" extensions operate on the values, and nested hashes' values, if any + * use `::load_value_extensions.add(:extension_name) { |value| }` + * since v2.0.2, bugs fixed in v2.0.3 +* "Hash Dump" extensions operate on the hash and nested hashes + * use `::dump_hash_extensions.add(:extension_name) { |value| }` + * since v2.0.3 +* "Value Dump" extensions operate on the values, and nested hashes' values, if any + * use `::dump_value_extensions.add(:extension_name) { |value| }` + * since v2.0.2, bugs fixed in v2.0.3 #### Example -Let's say I want all integer-like keys, except 0, to be integer keys, -while 0 converts to, and stays, a string forever. +Let's say I want to really smash up my hash and make it more food-like. ```ruby class MyExtSnakedHash < Hashie::Mash include SnakyHash::Snake.new( key_type: :symbol, # default :string - serializer: true, # default: false + serializer: true, # default: false ) end -MyExtSnakedHash.load_hash_extensions.add(:non_zero_keys_to_int) do |value| - if value.is_a?(Hash) - value.transform_keys do |key| - key_int = key.to_s.to_i - if key_int > 0 - key_int - else - key - end - end - else - value +# We could swap all values with indexed apples (obliteraating nested data!) +MyExtSnakedHash.dump_hash_extensions.add(:to_apple) do |value| + num = 0 + value.transform_values do |_key| + key = "apple-#{num}" + num += 1 + key end end -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"}} -dump = MyExtSnakedHash.dump(snake) # => "{\"1\":\"a\",\"0\":4,\"very_fine_hat\":{\"3\":\"v\",\"5\":7,\"very_fine_hat\":\"feathers\"}}" -hydrated = MyExtSnakedHash.load(dump) # => {1 => "a", "0": 4, very_fine_hat: {3 => "v", 5 => 7, very_fine_hat: "feathers"}} -hydrated.class # => MyExtSnakedHash -hydrated["1"] # => nil -hydrated[1] # => "a" -hydrated["0"] # => 4 -hydrated[0] # => nil -hydrated.very_fine_hat # => {3 => "v", 5 => 7, very_fine_hat: "feathers"} -hydrated.very_fine_hat.very_fine_hat # => "feathers" -hydrated.very_fine_hat[:very_fine_hat] # => 'feathers' -hydrated.very_fine_hat["very_fine_hat"] # => 'feathers' +# And then when loading the dump we could convert the yum to pear +MyExtSnakedHash.load_hash_extensions.add(:apple_to_pear) do |value| + value.transform_keys do |key| + key.to_s.sub("yum", "pear") + end +end + +# We could swap all index numbers "beet-" +MyExtSnakedHash.dump_value_extensions.add(:to_beet) do |value| + value.to_s.sub(/(\d+)/) { |match| "beet-#{match[0]}" } +end + +# And then when loading the dump we could convert beet to corn +MyExtSnakedHash.load_value_extensions.add(:beet_to_corn) do |value| + value.to_s.sub("beet", "corn") +end + +snake = MyExtSnakedHash.new({"YumBread" => "b", "YumCake" => {"b" => "b"}, "YumBoba" => [1, 2, 3]}) +snake # => {yum_bread: "b", yum_cake: {b: "b"}, yum_boba: [1, 2, 3]} +snake.yum_bread # => "b" +snake.yum_cake # => {b: "b"} +snake.yum_boba # => [1, 2, 3] +dump = snake.dump +dump # => "{\"yum_bread\":\"apple-beet-0\",\"yum_cake\":\"apple-beet-1\",\"yum_boba\":\"apple-beet-2\"}" +hydrated = MyExtSnakedHash.load(dump) +hydrated # => {pear_bread: "apple-corn-0", pear_cake: "apple-corn-1", pear_boba: "apple-corn-2"} ``` See the specs for more examples. -### Stranger Things +### Bad Ideas I don't recommend using these features... but they exist (for now). + +
+ Show me what I should *not* do! + You can still access the original un-snaked camel keys. And through them you can even use un-snaked camel methods. But don't. ```ruby +snake = SnakyHash::StringKeyed["VeryFineHat" => "Feathers"] snake.key?("VeryFineHat") # => true snake["VeryFineHat"] # => 'Feathers' snake.VeryFineHat # => 'Feathers', PLEASE don't do this!!! snake["VeryFineHat"] = "pop" # Please don't do this... you'll get a warning, and it works (for now), but no guarantees. # 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. # => "pop" +``` + +Since you are reading this, here's what to do instead. + +```ruby snake.very_fine_hat = "pop" # => 'pop', do this instead!!! snake.very_fine_hat # => 'pop' snake[:very_fine_hat] = "moose" # => 'moose', or do this instead!!! @@ -285,6 +320,8 @@ snake["very_fine_hat"] = "cheese" # => 'cheese', or do this instead!!! snake.very_fine_hat # => 'cheese' ``` +
+ ### 🚀 Release Instructions See [CONTRIBUTING.md][🤝contributing]. @@ -553,7 +590,7 @@ or one of the others at the head of this README. [📌gitmoji]:https://gitmoji.dev [📌gitmoji-img]:https://img.shields.io/badge/gitmoji_commits-%20😜%20😍-34495e.svg?style=flat-square [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ -[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.119-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue +[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.130-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue [🔐security]: SECURITY.md [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year diff --git a/REEK b/REEK index fc7da0f..d826649 100644 --- a/REEK +++ b/REEK @@ -2,27 +2,25 @@ spec/snaky_hash/snake_spec.rb -- 1 warning: [4]:IrresponsibleModule: TheSnakedHash has no descriptive comment [https://github.com/troessner/reek/blob/v6.5.0/docs/Irresponsible-Module.md] lib/snaky_hash/extensions.rb -- 1 warning: [11]:InstanceVariableAssumption: SnakyHash::Extensions assumes too much for instance variable '@extensions' [https://github.com/troessner/reek/blob/v6.5.0/docs/Instance-Variable-Assumption.md] -lib/snaky_hash/serializer.rb -- 8 warnings: - [106]:NilCheck: SnakyHash::Serializer#blank? performs a nil-check [https://github.com/troessner/reek/blob/v6.5.0/docs/Nil-Check.md] - [165]:TooManyStatements: SnakyHash::Serializer#load_value has approx 6 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] - [87]:TooManyStatements: SnakyHash::Serializer::BackportedInstanceMethods#transform_values has approx 7 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] - [58]:TooManyStatements: SnakyHash::Serializer::Modulizer#to_extended_mod has approx 7 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] - [128]:UncommunicativeVariableName: SnakyHash::Serializer#dump_hash has the variable name 'v' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Variable-Name.md] - [145]:UncommunicativeVariableName: SnakyHash::Serializer#dump_value has the variable name 'v' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Variable-Name.md] - [172]:UncommunicativeVariableName: SnakyHash::Serializer#load_value has the variable name 'v' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Variable-Name.md] - [105]:UtilityFunction: SnakyHash::Serializer#blank? doesn't depend on instance state (maybe move it to another class?) [https://github.com/troessner/reek/blob/v6.5.0/docs/Utility-Function.md] +lib/snaky_hash/serializer.rb -- 6 warnings: + [132]:NilCheck: SnakyHash::Serializer#blank? performs a nil-check [https://github.com/troessner/reek/blob/v6.5.0/docs/Nil-Check.md] + [99]:TooManyStatements: SnakyHash::Serializer::BackportedInstanceMethods#transform_values has approx 7 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] + [58]:TooManyStatements: SnakyHash::Serializer::Modulizer#to_extended_mod has approx 13 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] + [170]:UncommunicativeVariableName: SnakyHash::Serializer#dump_value has the variable name 'v' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Variable-Name.md] + [203]:UncommunicativeVariableName: SnakyHash::Serializer#load_value has the variable name 'v' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Variable-Name.md] + [131]:UtilityFunction: SnakyHash::Serializer#blank? doesn't depend on instance state (maybe move it to another class?) [https://github.com/troessner/reek/blob/v6.5.0/docs/Utility-Function.md] lib/snaky_hash/snake.rb -- 11 warnings: [30]:BooleanParameter: SnakyHash::Snake#initialize has boolean parameter 'serializer' [https://github.com/troessner/reek/blob/v6.5.0/docs/Boolean-Parameter.md] - [64, 70]:DuplicateMethodCall: SnakyHash::Snake::SnakyModulizer#to_mod calls 'define_method(:convert_key)' 2 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] - [64, 70]:DuplicateMethodCall: SnakyHash::Snake::SnakyModulizer#to_mod calls 'key.respond_to?(:to_sym)' 2 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] - [64, 70]:DuplicateMethodCall: SnakyHash::Snake::SnakyModulizer#to_mod calls 'key.to_s' 2 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] - [82, 86]:DuplicateMethodCall: SnakyHash::Snake::SnakyModulizer#to_mod calls 'self.class' 2 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] - [64, 70]:DuplicateMethodCall: SnakyHash::Snake::SnakyModulizer#to_mod calls 'underscore_string(key.to_s)' 2 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] - [83, 85]:DuplicateMethodCall: SnakyHash::Snake::SnakyModulizer#to_mod calls 'val.dup' 2 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] - [64, 70]:ManualDispatch: SnakyHash::Snake::SnakyModulizer#to_mod manually dispatches method call [https://github.com/troessner/reek/blob/v6.5.0/docs/Manual-Dispatch.md] - [88]:NestedIterators: SnakyHash::Snake::SnakyModulizer#to_mod contains iterators nested 2 deep [https://github.com/troessner/reek/blob/v6.5.0/docs/Nested-Iterators.md] + [69, 75]:DuplicateMethodCall: SnakyHash::Snake::SnakyModulizer#to_mod calls 'define_method(:convert_key)' 2 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] + [69, 75]:DuplicateMethodCall: SnakyHash::Snake::SnakyModulizer#to_mod calls 'key.respond_to?(:to_sym)' 2 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] + [69, 75]:DuplicateMethodCall: SnakyHash::Snake::SnakyModulizer#to_mod calls 'key.to_s' 2 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] + [87, 91]:DuplicateMethodCall: SnakyHash::Snake::SnakyModulizer#to_mod calls 'self.class' 2 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] + [69, 75]:DuplicateMethodCall: SnakyHash::Snake::SnakyModulizer#to_mod calls 'underscore_string(key.to_s)' 2 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] + [88, 90]:DuplicateMethodCall: SnakyHash::Snake::SnakyModulizer#to_mod calls 'val.dup' 2 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] + [69, 75]:ManualDispatch: SnakyHash::Snake::SnakyModulizer#to_mod manually dispatches method call [https://github.com/troessner/reek/blob/v6.5.0/docs/Manual-Dispatch.md] + [93]:NestedIterators: SnakyHash::Snake::SnakyModulizer#to_mod contains iterators nested 2 deep [https://github.com/troessner/reek/blob/v6.5.0/docs/Nested-Iterators.md] [56]:TooManyStatements: SnakyHash::Snake::SnakyModulizer#to_mod has approx 17 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] - [88]:UncommunicativeVariableName: SnakyHash::Snake::SnakyModulizer#to_mod has the variable name 'e' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Variable-Name.md] + [93]:UncommunicativeVariableName: SnakyHash::Snake::SnakyModulizer#to_mod has the variable name 'e' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Variable-Name.md] .yard_gfm_support.rb -- 1 warning: [9, 9]:FeatureEnvy: KramdownGfmDocument#initialize refers to 'options' more than self (maybe move it to another class?) [https://github.com/troessner/reek/blob/v6.5.0/docs/Feature-Envy.md] -22 total warnings +20 total warnings diff --git a/doc/SnakyHash.html b/doc/SnakyHash.html index c4b3cab..401feec 100644 --- a/doc/SnakyHash.html +++ b/doc/SnakyHash.html @@ -147,7 +147,7 @@

Usage with symbol keys and seri

diff --git a/doc/SnakyHash/Error.html b/doc/SnakyHash/Error.html index 2bc57b3..b0eed62 100644 --- a/doc/SnakyHash/Error.html +++ b/doc/SnakyHash/Error.html @@ -124,7 +124,7 @@

Overview

diff --git a/doc/SnakyHash/Extensions.html b/doc/SnakyHash/Extensions.html index afa52f4..15038e3 100644 --- a/doc/SnakyHash/Extensions.html +++ b/doc/SnakyHash/Extensions.html @@ -645,7 +645,7 @@

diff --git a/doc/SnakyHash/Serializer.html b/doc/SnakyHash/Serializer.html index af49581..964dd0c 100644 --- a/doc/SnakyHash/Serializer.html +++ b/doc/SnakyHash/Serializer.html @@ -112,7 +112,7 @@

Basic usage

- Modules: BackportedInstanceMethods, Modulizer + Modules: BackportedInstanceMethods, ConvenienceInstanceMethods, Modulizer @@ -273,7 +273,8 @@

27 28 29 -30 +30 +31
# File 'lib/snaky_hash/serializer.rb', line 21
@@ -281,6 +282,7 @@ 

def extended(base) extended_module = Modulizer.to_extended_mod base.extend(extended_module) + base.include(ConvenienceInstanceMethods) # :nocov: # This will be run in CI on Ruby 2.3, but we only collect coverage from current Ruby unless base.instance_methods.include?(:transform_values) @@ -360,13 +362,13 @@

 
 
-37
 38
 39
-40
+40 +41

-
# File 'lib/snaky_hash/serializer.rb', line 37
+      
# File 'lib/snaky_hash/serializer.rb', line 38
 
 def dump(obj)
   hash = dump_hash(obj)
@@ -438,19 +440,17 @@ 

 
 
-46
 47
 48
 49
 50
-
# File 'lib/snaky_hash/serializer.rb', line 46
+      
# File 'lib/snaky_hash/serializer.rb', line 47
 
 def load(raw_hash)
   hash = JSON.parse(presence(raw_hash) || "{}")
-  hash = load_value(new(hash))
-  new(hash)
+  load_hash(new(hash))
 end
@@ -462,7 +462,7 @@

diff --git a/doc/SnakyHash/Serializer/BackportedInstanceMethods.html b/doc/SnakyHash/Serializer/BackportedInstanceMethods.html index 986d9f6..693f9bc 100644 --- a/doc/SnakyHash/Serializer/BackportedInstanceMethods.html +++ b/doc/SnakyHash/Serializer/BackportedInstanceMethods.html @@ -222,18 +222,18 @@

 
 
-87
-88
-89
-90
-91
-92
-93
-94
-95
+99 +100 +101 +102 +103 +104 +105 +106 +107 -
# File 'lib/snaky_hash/serializer.rb', line 87
+      
# File 'lib/snaky_hash/serializer.rb', line 99
 
 def transform_values(&block)
   return enum_for(:transform_values) { size } unless block_given?
@@ -254,7 +254,7 @@ 

diff --git a/doc/SnakyHash/Serializer/ConvenienceInstanceMethods.html b/doc/SnakyHash/Serializer/ConvenienceInstanceMethods.html new file mode 100644 index 0000000..4561f70 --- /dev/null +++ b/doc/SnakyHash/Serializer/ConvenienceInstanceMethods.html @@ -0,0 +1,224 @@ + + + + + + + Module: SnakyHash::Serializer::ConvenienceInstanceMethods + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: SnakyHash::Serializer::ConvenienceInstanceMethods + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
lib/snaky_hash/serializer.rb
+
+ +
+ +

Overview

+
+

Provides convenient instance methods for serialization

+ + +
+
+
+ +
+

Examples:

+ + +

Using convenience methods

+
+ +
hash = MyHash.new(key: 'value')
+json = hash.dump #=> '{"key":"value"}'
+ +
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ +
    + +
  • + + + #dump ⇒ String + + + + + + + + + + + + + +

    Serializes the current hash instance to JSON.

    +
    + +
  • + + +
+ + + + +
+

Instance Method Details

+ + +
+

+ + #dumpString + + + + + +

+
+

Serializes the current hash instance to JSON

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    JSON string representation of the hash

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+120
+121
+122
+
+
# File 'lib/snaky_hash/serializer.rb', line 120
+
+def dump
+  self.class.dump(self)
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/doc/SnakyHash/Serializer/Modulizer.html b/doc/SnakyHash/Serializer/Modulizer.html index 9059f77..75a70f5 100644 --- a/doc/SnakyHash/Serializer/Modulizer.html +++ b/doc/SnakyHash/Serializer/Modulizer.html @@ -196,24 +196,48 @@

69 70 71 -72

+72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84
# File 'lib/snaky_hash/serializer.rb', line 58
 
 def to_extended_mod
   Module.new do
+    define_method :load_value_extensions do
+      @load_value_extensions ||= Extensions.new
+    end
+
     define_method :load_extensions do
-      @load_extensions ||= Extensions.new
+      load_value_extensions
+    end
+
+    define_method :dump_value_extensions do
+      @dump_value_extensions ||= Extensions.new
     end
 
     define_method :dump_extensions do
-      @dump_extensions ||= Extensions.new
+      dump_value_extensions
     end
 
     define_method :load_hash_extensions do
       @load_hash_extensions ||= Extensions.new
     end
+
+    define_method :dump_hash_extensions do
+      @dump_hash_extensions ||= Extensions.new
+    end
   end
 end
@@ -226,7 +250,7 @@

diff --git a/doc/SnakyHash/Snake.html b/doc/SnakyHash/Snake.html index bbcfefb..6045886 100644 --- a/doc/SnakyHash/Snake.html +++ b/doc/SnakyHash/Snake.html @@ -376,7 +376,7 @@

diff --git a/doc/SnakyHash/Snake/SnakyModulizer.html b/doc/SnakyHash/Snake/SnakyModulizer.html index c302b5b..9c81000 100644 --- a/doc/SnakyHash/Snake/SnakyModulizer.html +++ b/doc/SnakyHash/Snake/SnakyModulizer.html @@ -358,7 +358,7 @@

diff --git a/doc/SnakyHash/StringKeyed.html b/doc/SnakyHash/StringKeyed.html index 2c29b30..5438824 100644 --- a/doc/SnakyHash/StringKeyed.html +++ b/doc/SnakyHash/StringKeyed.html @@ -130,7 +130,7 @@

Overview

diff --git a/doc/SnakyHash/SymbolKeyed.html b/doc/SnakyHash/SymbolKeyed.html index 1ec2c92..f9ae32c 100644 --- a/doc/SnakyHash/SymbolKeyed.html +++ b/doc/SnakyHash/SymbolKeyed.html @@ -130,7 +130,7 @@

Overview

diff --git a/doc/SnakyHash/Version.html b/doc/SnakyHash/Version.html index 5f121a0..b911c23 100644 --- a/doc/SnakyHash/Version.html +++ b/doc/SnakyHash/Version.html @@ -148,7 +148,7 @@

diff --git a/doc/_index.html b/doc/_index.html index 007b704..08d217b 100644 --- a/doc/_index.html +++ b/doc/_index.html @@ -106,6 +106,21 @@

Namespace Listing A-Z

+ + +
  • E
    • @@ -214,7 +229,7 @@

      Namespace Listing A-Z

      diff --git a/doc/class_list.html b/doc/class_list.html index d03a359..ac1b866 100644 --- a/doc/class_list.html +++ b/doc/class_list.html @@ -46,7 +46,7 @@

      Class List

      diff --git a/doc/file.CHANGELOG.html b/doc/file.CHANGELOG.html index 29ec16d..fcaf782 100644 --- a/doc/file.CHANGELOG.html +++ b/doc/file.CHANGELOG.html @@ -63,19 +63,56 @@

      The format (since v2) is based on Keep a Changelog v1,
      and this project adheres to Semantic Versioning v2.

      -

      Unreleased

      +

      Unreleased

      Added

      Changed

      -

      Fixed

      +

      Deprecated

      Removed

      +

      Fixed

      +

      Security

      -

      [2.0.2] - 2025-05-21 (tag)

      +

      +2.0.3 - 2025-05-23

        +
      • TAG: v2.0.3 +
      • COVERAGE: 100.00% – 119/119 lines in 7 files
      • BRANCH COVERAGE: 100.00% – 35/35 branches in 7 files
      • 100.00% documented

        Added

      • +
      • +#dump instance method injected by extend SnakyHash::Serializer (@pboling)
      • +
      • +dump_hash_extensions - new feature, analogous to load_hash_extensions (@pboling)
      • +
      • +dump_value_extensions - alternate name for dump_extensions (@pboling)
      • +
      • +load_value_extensions - alternate name for load_extensions (@pboling)
      • +
      • Clarifying documentation (@pboling) +

        Fixed

        +
      • +
      • Serializer extensions dump and load empty values properly (@pboling) +
          +
        • Fixed dump_extensions, load_extensions, load_hash_extensions +
        • +
        • Intended usage is primarily JSON, and oauth2 gem
        • +
        • OAuth2 spec can have legitimately empty values (e.g. scopes could be empty)
        • +
        • Previous logic was inherited from design decisions made by serialized_hashie gem; doesn’t apply here
        • +
        +
      • +
      + +

      +2.0.2 - 2025-05-21

      +
        +
      • TAG: v2.0.2 +
      • +
      • COVERAGE: 100.00% – 119/119 lines in 7 files
      • +
      • BRANCH COVERAGE: 100.00% – 35/35 branches in 7 files
      • +
      • 100.00% documented +

        Added

        +
      • Gem is signed by 20-year cert (@pboling)
        • Expires 2045-04-29
        • @@ -96,10 +133,12 @@

          Added

        • 100% documented! (@pboling)
        -

        -2.0.1 - 2022-09-23 (tag)

        -

        Added

        +

        +2.0.1 - 2022-09-23

          +
        • TAG: v2.0.1 +

          Added

          +
        • Certificate for signing gem releases (@pboling)
        • Gemspec metadata (@pboling)
            @@ -113,17 +152,19 @@

            Changed

          • Gem releases are now cryptographically signed (@pboling)
          -

          -2.0.0 - 2022-08-29 (tag)

          -

          Changed

          +

          +2.0.0 - 2022-08-29

            +
          • TAG: v2.0.0 +

            Changed

            +
          • BREAKING: SnakeHash::Snake is now a mixin, now with support for symbol or string keys
            class MySnakedHash < Hashie::Mash
             include SnakyHash::Snake.new(key_type: :string) # or :symbol
             end
             
            -

            Added

            +

            Added

          • SnakyHash::StringKeyed: a Hashie::Mash class with snake-cased String keys
          • @@ -131,27 +172,31 @@

            Added

            SnakyHash::SymbolKeyed: a Hashie::Mash class with snake-cased Symbol keys
          -

          -1.0.1 - 2022-08-26 (tag)

          -

          Added

          +

          +1.0.1 - 2022-08-26

            +
          • TAG: v1.0.1 +

            Added

            +
          • Missing LICENSE.txt file to release

            Removed

          • Accidentally added bundler dependency (vestige of transpec process) is now removed
          -

          -1.0.0 - 2022-08-26 (tag)

          -

          Added

          +

          +1.0.0 - 2022-08-26

            +
          • TAG: v1.0.0 +

            Added

            +
          • Initial release
          diff --git a/doc/file.CODE_OF_CONDUCT.html b/doc/file.CODE_OF_CONDUCT.html index f329f5a..7b1c480 100644 --- a/doc/file.CODE_OF_CONDUCT.html +++ b/doc/file.CODE_OF_CONDUCT.html @@ -192,7 +192,7 @@

          Attribution

          diff --git a/doc/file.CONTRIBUTING.html b/doc/file.CONTRIBUTING.html index cf114bd..5754c8f 100644 --- a/doc/file.CONTRIBUTING.html +++ b/doc/file.CONTRIBUTING.html @@ -195,7 +195,7 @@

          To release a new version:

          diff --git a/doc/file.LICENSE.html b/doc/file.LICENSE.html index fde6c9d..d81440a 100644 --- a/doc/file.LICENSE.html +++ b/doc/file.LICENSE.html @@ -60,7 +60,7 @@
          The MIT License (MIT)

          Copyright (c) 2022, 2025 Peter Boling

          Permission is hereby granted, free of charge, to any person obtaining a copy
          of this software and associated documentation files (the "Software"), to deal
          in the Software without restriction, including without limitation the rights
          to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
          copies of the Software, and to permit persons to whom the Software is
          furnished to do so, subject to the following conditions:

          The above copyright notice and this permission notice shall be included in
          all copies or substantial portions of the Software.

          THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
          IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
          FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
          AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
          LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
          OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
          THE SOFTWARE.
          diff --git a/doc/file.README.html b/doc/file.README.html index 3376ad9..7b449cc 100644 --- a/doc/file.README.html +++ b/doc/file.README.html @@ -59,7 +59,7 @@

          🐍 SnakyHash

          -

          Version License: MIT Downloads Rank Open Source Helpers Depfu Coveralls Test Coverage QLTY Test Coverage CI Heads CI Runtime Dependencies @ HEAD CI Current CI Truffle Ruby CI JRuby CI Supported CI Legacy CI Unsupported CI Ancient CI Test Coverage CI Style CodeQL

          +

          Version License: MIT Downloads Rank Open Source Helpers Depfu Coveralls Test Coverage QLTY Test Coverage QLTY Maintainability CI Heads CI Runtime Dependencies @ HEAD CI Current CI Truffle Ruby CI JRuby CI Supported CI Legacy CI Unsupported CI Ancient CI Test Coverage CI Style CodeQL


          @@ -76,8 +76,7 @@
        • Rash (specifically the rash_alt flavor), which is a special Mash, made popular by the hashie gem, and
        • -serialized_hashie gem by krystal -
        • +serialized_hashie gem by krystal, rewritten, with some behavior changes

        Classes that include SnakyHash::Snake.new should inherit from Hashie::Mash.

        @@ -108,6 +107,16 @@

        Note for use with oauth2 gem

        end +

        or you can create a custom class

        + +
        class MyHash < Hashie::Mash
        +  include SnakyHash::Snake.new(key_type: :string, serializer: true)
        +  # Which is the same as:
        +  # include SnakyHash::Snake.new(key_type: :string)
        +  # extend SnakyHash::Serializer
        +end
        +
        +

        You can then add serialization extensions as needed. See serialization and extensions for more.

        @@ -430,89 +439,120 @@

        Extensions

        You can write your own arbitrary extensions:

          -
        • “Hash Load” extensions operate on the hash, and nested hashes +
        • “Hash Load” extensions operate on the hash and nested hashes
          • use ::load_hash_extensions.add(:extension_name) { |hash| }
          • +
          • since v2.0.2, bugs fixed in v2.0.3
          • +
          +
        • +
        • “Value Load” extensions operate on the values, and nested hashes’ values, if any +
            +
          • use ::load_value_extensions.add(:extension_name) { |value| } +
          • +
          • since v2.0.2, bugs fixed in v2.0.3
        • -
        • “Load” extensions operate on the values, and nested hash’s values, if any +
        • “Hash Dump” extensions operate on the hash and nested hashes
            -
          • use ::load_extensions.add(:extension_name) { |value| } +
          • use ::dump_hash_extensions.add(:extension_name) { |value| }
          • +
          • since v2.0.3
        • -
        • “Dump” extensions operate on the values, and nested hash’s values, if any +
        • “Value Dump” extensions operate on the values, and nested hashes’ values, if any
            -
          • use ::dump_extensions.add(:extension_name) { |value| } +
          • use ::dump_value_extensions.add(:extension_name) { |value| }
          • +
          • since v2.0.2, bugs fixed in v2.0.3

        Example

        -

        Let’s say I want all integer-like keys, except 0, to be integer keys,
        -while 0 converts to, and stays, a string forever.

        +

        Let’s say I want to really smash up my hash and make it more food-like.

        class MyExtSnakedHash < Hashie::Mash
           include SnakyHash::Snake.new(
             key_type: :symbol, # default :string
        -    serializer: true,   # default: false
        +    serializer: true,  # default: false
           )
         end
         
        -MyExtSnakedHash.load_hash_extensions.add(:non_zero_keys_to_int) do |value|
        -  if value.is_a?(Hash)
        -    value.transform_keys do |key|
        -      key_int = key.to_s.to_i
        -      if key_int > 0
        -        key_int
        -      else
        -        key
        -      end
        -    end
        -  else
        -    value
        +# We could swap all values with indexed apples (obliteraating nested data!)
        +MyExtSnakedHash.dump_hash_extensions.add(:to_apple) do |value|
        +  num = 0
        +  value.transform_values do |_key|
        +    key = "apple-#{num}"
        +    num += 1
        +    key
           end
         end
         
        -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"}}
        -dump = MyExtSnakedHash.dump(snake) # => "{\"1\":\"a\",\"0\":4,\"very_fine_hat\":{\"3\":\"v\",\"5\":7,\"very_fine_hat\":\"feathers\"}}"
        -hydrated = MyExtSnakedHash.load(dump) # => {1 => "a", "0": 4, very_fine_hat: {3 => "v", 5 => 7, very_fine_hat: "feathers"}}
        -hydrated.class # => MyExtSnakedHash
        -hydrated["1"] # => nil
        -hydrated[1] # => "a"
        -hydrated["0"] # => 4
        -hydrated[0] # => nil
        -hydrated.very_fine_hat # => {3 => "v", 5 => 7, very_fine_hat: "feathers"}
        -hydrated.very_fine_hat.very_fine_hat # => "feathers"
        -hydrated.very_fine_hat[:very_fine_hat] # => 'feathers'
        -hydrated.very_fine_hat["very_fine_hat"] # => 'feathers'
        +# And then when loading the dump we could convert the yum to pear
        +MyExtSnakedHash.load_hash_extensions.add(:apple_to_pear) do |value|
        +  value.transform_keys do |key|
        +    key.to_s.sub("yum", "pear")
        +  end
        +end
        +
        +# We could swap all index numbers "beet-<number>"
        +MyExtSnakedHash.dump_value_extensions.add(:to_beet) do |value|
        +  value.to_s.sub(/(\d+)/) { |match| "beet-#{match[0]}" }
        +end
        +
        +# And then when loading the dump we could convert beet to corn
        +MyExtSnakedHash.load_value_extensions.add(:beet_to_corn) do |value|
        +  value.to_s.sub("beet", "corn")
        +end
        +
        +snake = MyExtSnakedHash.new({"YumBread" => "b", "YumCake" => {"b" => "b"}, "YumBoba" => [1, 2, 3]})
        +snake # => {yum_bread: "b", yum_cake: {b: "b"}, yum_boba: [1, 2, 3]}
        +snake.yum_bread # => "b"
        +snake.yum_cake # => {b: "b"}
        +snake.yum_boba # => [1, 2, 3]
        +dump = snake.dump
        +dump # => "{\"yum_bread\":\"apple-beet-0\",\"yum_cake\":\"apple-beet-1\",\"yum_boba\":\"apple-beet-2\"}"
        +hydrated = MyExtSnakedHash.load(dump)
        +hydrated # => {pear_bread: "apple-corn-0", pear_cake: "apple-corn-1", pear_boba: "apple-corn-2"}
         

        See the specs for more examples.

        -

        Stranger Things

        +

        Bad Ideas

        -

        I don’t recommend using these features… but they exist (for now).
        -You can still access the original un-snaked camel keys.
        -And through them you can even use un-snaked camel methods.
        -But don’t.

        +

        I don’t recommend using these features… but they exist (for now).

        -
        snake.key?("VeryFineHat") # => true
        -snake["VeryFineHat"] # => 'Feathers'
        -snake.VeryFineHat # => 'Feathers', PLEASE don't do this!!!
        -snake["VeryFineHat"] = "pop" # Please don't do this... you'll get a warning, and it works (for now), but no guarantees.
        +
        + Show me what I should *not* do! + +You can still access the original un-snaked camel keys. +And through them you can even use un-snaked camel methods. +But don't. + +```ruby +snake = SnakyHash::StringKeyed["VeryFineHat" => "Feathers"] +snake.key?("VeryFineHat") # => true +snake["VeryFineHat"] # => 'Feathers' +snake.VeryFineHat # => 'Feathers', PLEASE don't do this!!! +snake["VeryFineHat"] = "pop" # Please don't do this... you'll get a warning, and it works (for now), but no guarantees. # 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. -# => "pop" -snake.very_fine_hat = "pop" # => 'pop', do this instead!!! -snake.very_fine_hat # => 'pop' -snake[:very_fine_hat] = "moose" # => 'moose', or do this instead!!! -snake.very_fine_hat # => 'moose' -snake["very_fine_hat"] = "cheese" # => 'cheese', or do this instead!!! -snake.very_fine_hat # => 'cheese' -
        +# => "pop" +``` + +Since you are reading this, here's what to do instead. + +```ruby +snake.very_fine_hat = "pop" # => 'pop', do this instead!!! +snake.very_fine_hat # => 'pop' +snake[:very_fine_hat] = "moose" # => 'moose', or do this instead!!! +snake.very_fine_hat # => 'moose' +snake["very_fine_hat"] = "cheese" # => 'cheese', or do this instead!!! +snake.very_fine_hat # => 'cheese' +``` + +

        🚀 Release Instructions

        @@ -647,7 +687,7 @@

        🤑 One more thing

        diff --git a/doc/file.SECURITY.html b/doc/file.SECURITY.html index 88c59ef..6d46d95 100644 --- a/doc/file.SECURITY.html +++ b/doc/file.SECURITY.html @@ -104,7 +104,7 @@

        Snaky Hash for Enterprise

        diff --git a/doc/index.html b/doc/index.html index 0c9b20e..d7c34ab 100644 --- a/doc/index.html +++ b/doc/index.html @@ -59,7 +59,7 @@

        🐍 SnakyHash

        -

        Version License: MIT Downloads Rank Open Source Helpers Depfu Coveralls Test Coverage QLTY Test Coverage CI Heads CI Runtime Dependencies @ HEAD CI Current CI Truffle Ruby CI JRuby CI Supported CI Legacy CI Unsupported CI Ancient CI Test Coverage CI Style CodeQL

        +

        Version License: MIT Downloads Rank Open Source Helpers Depfu Coveralls Test Coverage QLTY Test Coverage QLTY Maintainability CI Heads CI Runtime Dependencies @ HEAD CI Current CI Truffle Ruby CI JRuby CI Supported CI Legacy CI Unsupported CI Ancient CI Test Coverage CI Style CodeQL


        @@ -76,8 +76,7 @@
      • Rash (specifically the rash_alt flavor), which is a special Mash, made popular by the hashie gem, and
      • -serialized_hashie gem by krystal -
      • +serialized_hashie gem by krystal, rewritten, with some behavior changes

        Classes that include SnakyHash::Snake.new should inherit from Hashie::Mash.

        @@ -108,6 +107,16 @@

        Note for use with oauth2 gem

        end +

        or you can create a custom class

        + +
        class MyHash < Hashie::Mash
        +  include SnakyHash::Snake.new(key_type: :string, serializer: true)
        +  # Which is the same as:
        +  # include SnakyHash::Snake.new(key_type: :string)
        +  # extend SnakyHash::Serializer
        +end
        +
        +

        You can then add serialization extensions as needed. See serialization and extensions for more.

        @@ -430,89 +439,120 @@

        Extensions

        You can write your own arbitrary extensions:

          -
        • “Hash Load” extensions operate on the hash, and nested hashes +
        • “Hash Load” extensions operate on the hash and nested hashes
          • use ::load_hash_extensions.add(:extension_name) { |hash| }
          • +
          • since v2.0.2, bugs fixed in v2.0.3
          • +
          +
        • +
        • “Value Load” extensions operate on the values, and nested hashes’ values, if any +
            +
          • use ::load_value_extensions.add(:extension_name) { |value| } +
          • +
          • since v2.0.2, bugs fixed in v2.0.3
        • -
        • “Load” extensions operate on the values, and nested hash’s values, if any +
        • “Hash Dump” extensions operate on the hash and nested hashes
            -
          • use ::load_extensions.add(:extension_name) { |value| } +
          • use ::dump_hash_extensions.add(:extension_name) { |value| }
          • +
          • since v2.0.3
        • -
        • “Dump” extensions operate on the values, and nested hash’s values, if any +
        • “Value Dump” extensions operate on the values, and nested hashes’ values, if any
            -
          • use ::dump_extensions.add(:extension_name) { |value| } +
          • use ::dump_value_extensions.add(:extension_name) { |value| }
          • +
          • since v2.0.2, bugs fixed in v2.0.3

        Example

        -

        Let’s say I want all integer-like keys, except 0, to be integer keys,
        -while 0 converts to, and stays, a string forever.

        +

        Let’s say I want to really smash up my hash and make it more food-like.

        class MyExtSnakedHash < Hashie::Mash
           include SnakyHash::Snake.new(
             key_type: :symbol, # default :string
        -    serializer: true,   # default: false
        +    serializer: true,  # default: false
           )
         end
         
        -MyExtSnakedHash.load_hash_extensions.add(:non_zero_keys_to_int) do |value|
        -  if value.is_a?(Hash)
        -    value.transform_keys do |key|
        -      key_int = key.to_s.to_i
        -      if key_int > 0
        -        key_int
        -      else
        -        key
        -      end
        -    end
        -  else
        -    value
        +# We could swap all values with indexed apples (obliteraating nested data!)
        +MyExtSnakedHash.dump_hash_extensions.add(:to_apple) do |value|
        +  num = 0
        +  value.transform_values do |_key|
        +    key = "apple-#{num}"
        +    num += 1
        +    key
           end
         end
         
        -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"}}
        -dump = MyExtSnakedHash.dump(snake) # => "{\"1\":\"a\",\"0\":4,\"very_fine_hat\":{\"3\":\"v\",\"5\":7,\"very_fine_hat\":\"feathers\"}}"
        -hydrated = MyExtSnakedHash.load(dump) # => {1 => "a", "0": 4, very_fine_hat: {3 => "v", 5 => 7, very_fine_hat: "feathers"}}
        -hydrated.class # => MyExtSnakedHash
        -hydrated["1"] # => nil
        -hydrated[1] # => "a"
        -hydrated["0"] # => 4
        -hydrated[0] # => nil
        -hydrated.very_fine_hat # => {3 => "v", 5 => 7, very_fine_hat: "feathers"}
        -hydrated.very_fine_hat.very_fine_hat # => "feathers"
        -hydrated.very_fine_hat[:very_fine_hat] # => 'feathers'
        -hydrated.very_fine_hat["very_fine_hat"] # => 'feathers'
        +# And then when loading the dump we could convert the yum to pear
        +MyExtSnakedHash.load_hash_extensions.add(:apple_to_pear) do |value|
        +  value.transform_keys do |key|
        +    key.to_s.sub("yum", "pear")
        +  end
        +end
        +
        +# We could swap all index numbers "beet-<number>"
        +MyExtSnakedHash.dump_value_extensions.add(:to_beet) do |value|
        +  value.to_s.sub(/(\d+)/) { |match| "beet-#{match[0]}" }
        +end
        +
        +# And then when loading the dump we could convert beet to corn
        +MyExtSnakedHash.load_value_extensions.add(:beet_to_corn) do |value|
        +  value.to_s.sub("beet", "corn")
        +end
        +
        +snake = MyExtSnakedHash.new({"YumBread" => "b", "YumCake" => {"b" => "b"}, "YumBoba" => [1, 2, 3]})
        +snake # => {yum_bread: "b", yum_cake: {b: "b"}, yum_boba: [1, 2, 3]}
        +snake.yum_bread # => "b"
        +snake.yum_cake # => {b: "b"}
        +snake.yum_boba # => [1, 2, 3]
        +dump = snake.dump
        +dump # => "{\"yum_bread\":\"apple-beet-0\",\"yum_cake\":\"apple-beet-1\",\"yum_boba\":\"apple-beet-2\"}"
        +hydrated = MyExtSnakedHash.load(dump)
        +hydrated # => {pear_bread: "apple-corn-0", pear_cake: "apple-corn-1", pear_boba: "apple-corn-2"}
         

        See the specs for more examples.

        -

        Stranger Things

        +

        Bad Ideas

        -

        I don’t recommend using these features… but they exist (for now).
        -You can still access the original un-snaked camel keys.
        -And through them you can even use un-snaked camel methods.
        -But don’t.

        +

        I don’t recommend using these features… but they exist (for now).

        -
        snake.key?("VeryFineHat") # => true
        -snake["VeryFineHat"] # => 'Feathers'
        -snake.VeryFineHat # => 'Feathers', PLEASE don't do this!!!
        -snake["VeryFineHat"] = "pop" # Please don't do this... you'll get a warning, and it works (for now), but no guarantees.
        +
        + Show me what I should *not* do! + +You can still access the original un-snaked camel keys. +And through them you can even use un-snaked camel methods. +But don't. + +```ruby +snake = SnakyHash::StringKeyed["VeryFineHat" => "Feathers"] +snake.key?("VeryFineHat") # => true +snake["VeryFineHat"] # => 'Feathers' +snake.VeryFineHat # => 'Feathers', PLEASE don't do this!!! +snake["VeryFineHat"] = "pop" # Please don't do this... you'll get a warning, and it works (for now), but no guarantees. # 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. -# => "pop" -snake.very_fine_hat = "pop" # => 'pop', do this instead!!! -snake.very_fine_hat # => 'pop' -snake[:very_fine_hat] = "moose" # => 'moose', or do this instead!!! -snake.very_fine_hat # => 'moose' -snake["very_fine_hat"] = "cheese" # => 'cheese', or do this instead!!! -snake.very_fine_hat # => 'cheese' -
        +# => "pop" +``` + +Since you are reading this, here's what to do instead. + +```ruby +snake.very_fine_hat = "pop" # => 'pop', do this instead!!! +snake.very_fine_hat # => 'pop' +snake[:very_fine_hat] = "moose" # => 'moose', or do this instead!!! +snake.very_fine_hat # => 'moose' +snake["very_fine_hat"] = "cheese" # => 'cheese', or do this instead!!! +snake.very_fine_hat # => 'cheese' +``` + +

        🚀 Release Instructions

        @@ -647,7 +687,7 @@

        🤑 One more thing

        diff --git a/doc/method_list.html b/doc/method_list.html index 7978db2..b585472 100644 --- a/doc/method_list.html +++ b/doc/method_list.html @@ -64,6 +64,14 @@

        Method List

      • +
        + #dump + SnakyHash::Serializer::ConvenienceInstanceMethods +
        +
      • + + +
      • extended SnakyHash::Serializer @@ -71,7 +79,7 @@

        Method List

      • -
      • +
      • #has? SnakyHash::Extensions @@ -79,7 +87,7 @@

        Method List

      • -
      • +
      • #included SnakyHash::Snake @@ -87,7 +95,7 @@

        Method List

      • -
      • +
      • #initialize SnakyHash::Snake @@ -95,7 +103,7 @@

        Method List

      • -
      • +
      • #initialize SnakyHash::Extensions @@ -103,7 +111,7 @@

        Method List

      • -
      • +
      • #load SnakyHash::Serializer @@ -111,7 +119,7 @@

        Method List

      • -
      • +
      • #reset SnakyHash::Extensions @@ -119,7 +127,7 @@

        Method List

      • -
      • +
      • #run SnakyHash::Extensions @@ -127,7 +135,7 @@

        Method List

      • -
      • +
      • to_extended_mod SnakyHash::Serializer::Modulizer @@ -135,7 +143,7 @@

        Method List

      • -
      • +
      • to_mod SnakyHash::Snake::SnakyModulizer @@ -143,7 +151,7 @@

        Method List

      • -
      • +
      • #transform_values SnakyHash::Serializer::BackportedInstanceMethods diff --git a/doc/top-level-namespace.html b/doc/top-level-namespace.html index d8fbfa5..1fa9085 100644 --- a/doc/top-level-namespace.html +++ b/doc/top-level-namespace.html @@ -100,7 +100,7 @@

        Defined Under Namespace

        diff --git a/lib/snaky_hash/serializer.rb b/lib/snaky_hash/serializer.rb index 52a657a..f463151 100644 --- a/lib/snaky_hash/serializer.rb +++ b/lib/snaky_hash/serializer.rb @@ -21,6 +21,7 @@ class << self def extended(base) extended_module = Modulizer.to_extended_mod base.extend(extended_module) + base.include(ConvenienceInstanceMethods) # :nocov: # This will be run in CI on Ruby 2.3, but we only collect coverage from current Ruby unless base.instance_methods.include?(:transform_values) @@ -45,8 +46,7 @@ def dump(obj) # @return [Hash] deserialized hash object def load(raw_hash) hash = JSON.parse(presence(raw_hash) || "{}") - hash = load_value(new(hash)) - new(hash) + load_hash(new(hash)) end # Internal module for generating extension methods @@ -57,17 +57,29 @@ class << self # @return [Module] a module containing extension management methods def to_extended_mod Module.new do + define_method :load_value_extensions do + @load_value_extensions ||= Extensions.new + end + define_method :load_extensions do - @load_extensions ||= Extensions.new + load_value_extensions + end + + define_method :dump_value_extensions do + @dump_value_extensions ||= Extensions.new end define_method :dump_extensions do - @dump_extensions ||= Extensions.new + dump_value_extensions end define_method :load_hash_extensions do @load_hash_extensions ||= Extensions.new end + + define_method :dump_hash_extensions do + @dump_hash_extensions ||= Extensions.new + end end end end @@ -96,6 +108,20 @@ def transform_values(&block) # :nocov: end + # Provides convenient instance methods for serialization + # + # @example Using convenience methods + # hash = MyHash.new(key: 'value') + # json = hash.dump #=> '{"key":"value"}' + module ConvenienceInstanceMethods + # Serializes the current hash instance to JSON + # + # @return [String] JSON string representation of the hash + def dump + self.class.dump(self) + end + end + private # Checks if a value is blank (nil or empty string) @@ -117,15 +143,14 @@ def presence(value) blank?(value) ? nil : value end - # Processes a hash for dumping, transforming its values + # Processes a hash for dumping, transforming its keys and/or values # # @param hash [Hash] hash to process # @return [Hash] processed hash with transformed values def dump_hash(hash) - hash = self[hash].transform_values do |value| + dump_hash_extensions.run(self[hash]).transform_values do |value| dump_value(value) end - hash.reject { |_, v| blank?(v) } end # Processes a single value for dumping @@ -134,7 +159,7 @@ def dump_hash(hash) # @return [Object, nil] processed value def dump_value(value) if blank?(value) - return + return value end if value.is_a?(::Hash) @@ -148,12 +173,15 @@ def dump_value(value) dump_extensions.run(value) end - # Processes a hash for loading, transforming its values + # Processes a hash for loading, transforming its keys and/or values # # @param hash [Hash] hash to process # @return [Hash] processed hash with transformed values def load_hash(hash) - hash.transform_values do |value| + ran = load_hash_extensions.run(self[hash]) + return load_value(ran) unless ran.is_a?(::Hash) + + self[ran].transform_values do |value| load_value(value) end end @@ -161,15 +189,19 @@ def load_hash(hash) # Processes a single value for loading # # @param value [Object] value to process - # @return [Object] processed value + # @return [Object, nil] processed value def load_value(value) + if blank?(value) + return value + end + if value.is_a?(::Hash) - hash = load_hash_extensions.run(new(value)) - return load_hash(new(hash)) if hash.is_a?(::Hash) - return load_value(hash) + return load_hash(value) end - return value.map { |v| load_value(v) } if value.is_a?(Array) + if value.is_a?(::Array) + return value.map { |v| load_value(v) }.compact + end load_extensions.run(value) end diff --git a/spec/shared_contexts/base_hash.rb b/spec/shared_contexts/base_hash.rb index 3500db6..042a03a 100644 --- a/spec/shared_contexts/base_hash.rb +++ b/spec/shared_contexts/base_hash.rb @@ -1,5 +1,14 @@ # frozen_string_literal: true +# A shared context that provides a base hash with various key formats for testing +# +# @example Using the shared context +# RSpec.describe MyClass do +# include_context "base hash" +# it "has data" do +# expect(base_hash["varOne"]).to eq(1) +# end +# end RSpec.shared_context "base hash" do let(:base_hash) do bh = { diff --git a/spec/shared_contexts/without_serializer.rb b/spec/shared_contexts/without_serializer.rb index e1fd5e9..8895a8b 100644 --- a/spec/shared_contexts/without_serializer.rb +++ b/spec/shared_contexts/without_serializer.rb @@ -1,3 +1,10 @@ +# A shared context that creates a hash class without serialization capabilities +# +# @example Using the shared context +# RSpec.describe MyClass do +# include_context "without serializer" +# # ... rest of the spec +# end RSpec.shared_context "without serializer" do subject(:hash_klass) do Class.new(Hashie::Mash) do diff --git a/spec/shared_examples/a_serialized_hash.rb b/spec/shared_examples/a_serialized_hash.rb index 3ff313c..1bc8fb4 100644 --- a/spec/shared_examples/a_serialized_hash.rb +++ b/spec/shared_examples/a_serialized_hash.rb @@ -1,20 +1,23 @@ RSpec.shared_examples_for "a serialized hash" do - describe ".dump" do - after { subject.dump_extensions.reset } + describe "::dump" do + after do + subject.dump_value_extensions.reset + subject.dump_hash_extensions.reset + end it "returns a JSON string" do value = subject.dump({hello: "World"}) expect(value).to eq '{"hello":"World"}' end - it "removes any nil values" do + it "does not remove nil values" do value = subject.dump({hello: "World", nilValue: nil}) - expect(value).to eq '{"hello":"World"}' + expect(value).to eq "{\"hello\":\"World\",\"nil_value\":null}" end - it "removes empty strings" do + it "does not remove empty strings" do value = subject.dump({hello: "World", nilValue: ""}) - expect(value).to eq '{"hello":"World"}' + expect(value).to eq "{\"hello\":\"World\",\"nil_value\":\"\"}" end it "does not remove false" do @@ -24,7 +27,7 @@ it "removes any empty items from top-level arrays" do value = subject.dump({hello: "World", array: [nil, 1, 2, "", false]}) - expect(value).to eq '{"hello":"World","array":[1,2,false]}' + expect(value).to eq '{"hello":"World","array":[1,2,"",false]}' end it "passes through any extensions that have been added" do @@ -46,9 +49,9 @@ end end - describe ".load" do + describe "::load" do after do - subject.load_extensions.reset + subject.load_value_extensions.reset subject.load_hash_extensions.reset end @@ -64,6 +67,24 @@ expect(hash).to be_empty end + it "creates a hash with nil value" do + hash = subject.load('{"myCount":null}') + expect(hash).to be_a Hashie::Mash + expect(hash["myCount"]).to be_nil + end + + it "creates a hash with empty value" do + hash = subject.load('{"myCount":""}') + expect(hash).to be_a Hashie::Mash + expect(hash["myCount"]).to eq("") + end + + it "creates a hash with 0 value" do + hash = subject.load('{"myCount":0}') + expect(hash).to be_a Hashie::Mash + expect(hash["myCount"]).to eq(0) + end + it "creates an empty Mash if the JSON is an empty string" do hash = subject.load("") expect(hash).to be_a Hashie::Mash diff --git a/spec/snaky_hash/serializer_spec.rb b/spec/snaky_hash/serializer_spec.rb index c1ccbff..a355f25 100644 --- a/spec/snaky_hash/serializer_spec.rb +++ b/spec/snaky_hash/serializer_spec.rb @@ -5,11 +5,39 @@ include_context "with serializer" it_behaves_like "a serialized hash" + + describe "#dump" do + subject(:instance) { hash_klass[hello: "World"] } + + after do + hash_klass.dump_value_extensions.reset + hash_klass.dump_hash_extensions.reset + end + + it "returns a JSON string" do + value = instance.dump + expect(value).to eq '{"hello":"World"}' + end + end end context "when extended" do include_context "with extended serializer" + describe "#dump" do + subject(:instance) { hash_klass[hello: "World"] } + + after do + hash_klass.dump_value_extensions.reset + hash_klass.dump_hash_extensions.reset + end + + it "returns a JSON string" do + value = instance.dump + expect(value).to eq '{"hello":"World"}' + end + end + it_behaves_like "a serialized hash" end end From e41431b2cb6b357e0bab8415aec6a5729e0931cb Mon Sep 17 00:00:00 2001 From: "Peter H. Boling" Date: Fri, 23 May 2025 09:01:19 +0700 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=90=9B=20Fix=20load=5Fextensions.run?= =?UTF-8?q?=20for=20Ruby=20<=3D=202.6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ancient.yml | 32 +++++++++---------- CHANGELOG.md | 6 ++-- README.md | 2 +- REEK | 7 ++-- doc/SnakyHash.html | 2 +- doc/SnakyHash/Error.html | 2 +- doc/SnakyHash/Extensions.html | 2 +- doc/SnakyHash/Serializer.html | 2 +- .../Serializer/BackportedInstanceMethods.html | 2 +- .../ConvenienceInstanceMethods.html | 2 +- doc/SnakyHash/Serializer/Modulizer.html | 2 +- doc/SnakyHash/Snake.html | 2 +- doc/SnakyHash/Snake/SnakyModulizer.html | 2 +- doc/SnakyHash/StringKeyed.html | 2 +- doc/SnakyHash/SymbolKeyed.html | 2 +- doc/SnakyHash/Version.html | 2 +- doc/_index.html | 2 +- doc/file.CHANGELOG.html | 9 +++--- doc/file.CODE_OF_CONDUCT.html | 2 +- doc/file.CONTRIBUTING.html | 2 +- doc/file.LICENSE.html | 2 +- doc/file.README.html | 4 +-- doc/file.SECURITY.html | 2 +- doc/index.html | 4 +-- doc/top-level-namespace.html | 2 +- lib/snaky_hash/serializer.rb | 13 +++++++- 26 files changed, 63 insertions(+), 50 deletions(-) diff --git a/.github/workflows/ancient.yml b/.github/workflows/ancient.yml index 4b061b2..8771e58 100644 --- a/.github/workflows/ancient.yml +++ b/.github/workflows/ancient.yml @@ -37,26 +37,26 @@ jobs: # Ruby 2.3 - ruby: "ruby-2.3" appraisal: "ruby-2-3" - exec_cmd: "rspec spec/snaky_hash/serializer_spec.rb:13" + exec_cmd: "rake test" gemfile: "Appraisal.root" rubygems: "3.3.27" bundler: "2.3.27" -# # Ruby 2.4 -# - ruby: "ruby-2.4" -# appraisal: "ruby-2-4" -# exec_cmd: "rake test" -# gemfile: "Appraisal.root" -# rubygems: "3.3.27" -# bundler: "2.3.27" -# -# # Ruby 2.5 -# - ruby: "ruby-2.5" -# appraisal: "ruby-2-5" -# exec_cmd: "rake test" -# gemfile: "Appraisal.root" -# rubygems: "3.3.27" -# bundler: "2.3.27" + # Ruby 2.4 + - ruby: "ruby-2.4" + appraisal: "ruby-2-4" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: "3.3.27" + bundler: "2.3.27" + + # Ruby 2.5 + - ruby: "ruby-2.5" + appraisal: "ruby-2-5" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: "3.3.27" + bundler: "2.3.27" steps: - name: Checkout diff --git a/CHANGELOG.md b/CHANGELOG.md index f0fa4b0..6130482 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,8 +14,8 @@ and this project adheres to [Semantic Versioning v2](https://semver.org/spec/v2. ## [2.0.3] - 2025-05-23 - TAG: [v2.0.3][2.0.3t] -- COVERAGE: 100.00% -- 130/130 lines in 7 files -- BRANCH COVERAGE: 100.00% -- 37/37 branches in 7 files +- COVERAGE: 100.00% -- 132/132 lines in 7 files +- BRANCH COVERAGE: 100.00% -- 38/38 branches in 7 files - 100.00% documented ### Added - `#dump` instance method injected by `extend SnakyHash::Serializer` (@pboling) @@ -24,7 +24,7 @@ and this project adheres to [Semantic Versioning v2](https://semver.org/spec/v2. - `load_value_extensions` - alternate name for `load_extensions` (@pboling) - Clarifying documentation (@pboling) ### Fixed -- Serializer extensions dump and load empty values properly (@pboling) +- [gh4](https://github.com/oauth-xx/snaky_hash/pull/4) - Serializer extensions dump and load empty values properly (@pboling) - Fixed `dump_extensions`, `load_extensions`, `load_hash_extensions` - Intended usage is primarily JSON, and oauth2 gem - OAuth2 spec can have legitimately empty values (e.g. scopes could be empty) diff --git a/README.md b/README.md index 4c3d00c..df2bdec 100644 --- a/README.md +++ b/README.md @@ -590,7 +590,7 @@ or one of the others at the head of this README. [📌gitmoji]:https://gitmoji.dev [📌gitmoji-img]:https://img.shields.io/badge/gitmoji_commits-%20😜%20😍-34495e.svg?style=flat-square [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ -[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.130-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue +[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.132-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue [🔐security]: SECURITY.md [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year diff --git a/REEK b/REEK index d826649..8bfce7e 100644 --- a/REEK +++ b/REEK @@ -2,12 +2,13 @@ spec/snaky_hash/snake_spec.rb -- 1 warning: [4]:IrresponsibleModule: TheSnakedHash has no descriptive comment [https://github.com/troessner/reek/blob/v6.5.0/docs/Irresponsible-Module.md] lib/snaky_hash/extensions.rb -- 1 warning: [11]:InstanceVariableAssumption: SnakyHash::Extensions assumes too much for instance variable '@extensions' [https://github.com/troessner/reek/blob/v6.5.0/docs/Instance-Variable-Assumption.md] -lib/snaky_hash/serializer.rb -- 6 warnings: +lib/snaky_hash/serializer.rb -- 7 warnings: [132]:NilCheck: SnakyHash::Serializer#blank? performs a nil-check [https://github.com/troessner/reek/blob/v6.5.0/docs/Nil-Check.md] + [180]:TooManyStatements: SnakyHash::Serializer#load_hash has approx 6 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] [99]:TooManyStatements: SnakyHash::Serializer::BackportedInstanceMethods#transform_values has approx 7 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] [58]:TooManyStatements: SnakyHash::Serializer::Modulizer#to_extended_mod has approx 13 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] [170]:UncommunicativeVariableName: SnakyHash::Serializer#dump_value has the variable name 'v' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Variable-Name.md] - [203]:UncommunicativeVariableName: SnakyHash::Serializer#load_value has the variable name 'v' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Variable-Name.md] + [214]:UncommunicativeVariableName: SnakyHash::Serializer#load_value has the variable name 'v' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Variable-Name.md] [131]:UtilityFunction: SnakyHash::Serializer#blank? doesn't depend on instance state (maybe move it to another class?) [https://github.com/troessner/reek/blob/v6.5.0/docs/Utility-Function.md] lib/snaky_hash/snake.rb -- 11 warnings: [30]:BooleanParameter: SnakyHash::Snake#initialize has boolean parameter 'serializer' [https://github.com/troessner/reek/blob/v6.5.0/docs/Boolean-Parameter.md] @@ -23,4 +24,4 @@ lib/snaky_hash/snake.rb -- 11 warnings: [93]:UncommunicativeVariableName: SnakyHash::Snake::SnakyModulizer#to_mod has the variable name 'e' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Variable-Name.md] .yard_gfm_support.rb -- 1 warning: [9, 9]:FeatureEnvy: KramdownGfmDocument#initialize refers to 'options' more than self (maybe move it to another class?) [https://github.com/troessner/reek/blob/v6.5.0/docs/Feature-Envy.md] -20 total warnings +21 total warnings diff --git a/doc/SnakyHash.html b/doc/SnakyHash.html index 401feec..b17fb18 100644 --- a/doc/SnakyHash.html +++ b/doc/SnakyHash.html @@ -147,7 +147,7 @@

        Usage with symbol keys and seri

        diff --git a/doc/SnakyHash/Error.html b/doc/SnakyHash/Error.html index b0eed62..8c69e15 100644 --- a/doc/SnakyHash/Error.html +++ b/doc/SnakyHash/Error.html @@ -124,7 +124,7 @@

        Overview

        diff --git a/doc/SnakyHash/Extensions.html b/doc/SnakyHash/Extensions.html index 15038e3..31e42d9 100644 --- a/doc/SnakyHash/Extensions.html +++ b/doc/SnakyHash/Extensions.html @@ -645,7 +645,7 @@

        diff --git a/doc/SnakyHash/Serializer.html b/doc/SnakyHash/Serializer.html index 964dd0c..dbf50eb 100644 --- a/doc/SnakyHash/Serializer.html +++ b/doc/SnakyHash/Serializer.html @@ -462,7 +462,7 @@

        diff --git a/doc/SnakyHash/Serializer/BackportedInstanceMethods.html b/doc/SnakyHash/Serializer/BackportedInstanceMethods.html index 693f9bc..bd18501 100644 --- a/doc/SnakyHash/Serializer/BackportedInstanceMethods.html +++ b/doc/SnakyHash/Serializer/BackportedInstanceMethods.html @@ -254,7 +254,7 @@

        diff --git a/doc/SnakyHash/Serializer/ConvenienceInstanceMethods.html b/doc/SnakyHash/Serializer/ConvenienceInstanceMethods.html index 4561f70..06f30df 100644 --- a/doc/SnakyHash/Serializer/ConvenienceInstanceMethods.html +++ b/doc/SnakyHash/Serializer/ConvenienceInstanceMethods.html @@ -214,7 +214,7 @@

        diff --git a/doc/SnakyHash/Serializer/Modulizer.html b/doc/SnakyHash/Serializer/Modulizer.html index 75a70f5..4d2b44e 100644 --- a/doc/SnakyHash/Serializer/Modulizer.html +++ b/doc/SnakyHash/Serializer/Modulizer.html @@ -250,7 +250,7 @@

        diff --git a/doc/SnakyHash/Snake.html b/doc/SnakyHash/Snake.html index 6045886..697cec0 100644 --- a/doc/SnakyHash/Snake.html +++ b/doc/SnakyHash/Snake.html @@ -376,7 +376,7 @@

        diff --git a/doc/SnakyHash/Snake/SnakyModulizer.html b/doc/SnakyHash/Snake/SnakyModulizer.html index 9c81000..0e1a6c3 100644 --- a/doc/SnakyHash/Snake/SnakyModulizer.html +++ b/doc/SnakyHash/Snake/SnakyModulizer.html @@ -358,7 +358,7 @@

        diff --git a/doc/SnakyHash/StringKeyed.html b/doc/SnakyHash/StringKeyed.html index 5438824..0c7f371 100644 --- a/doc/SnakyHash/StringKeyed.html +++ b/doc/SnakyHash/StringKeyed.html @@ -130,7 +130,7 @@

        Overview

        diff --git a/doc/SnakyHash/SymbolKeyed.html b/doc/SnakyHash/SymbolKeyed.html index f9ae32c..d759e09 100644 --- a/doc/SnakyHash/SymbolKeyed.html +++ b/doc/SnakyHash/SymbolKeyed.html @@ -130,7 +130,7 @@

        Overview

        diff --git a/doc/SnakyHash/Version.html b/doc/SnakyHash/Version.html index b911c23..0e6e9fb 100644 --- a/doc/SnakyHash/Version.html +++ b/doc/SnakyHash/Version.html @@ -148,7 +148,7 @@

        diff --git a/doc/_index.html b/doc/_index.html index 08d217b..cda1841 100644 --- a/doc/_index.html +++ b/doc/_index.html @@ -229,7 +229,7 @@

        Namespace Listing A-Z

        diff --git a/doc/file.CHANGELOG.html b/doc/file.CHANGELOG.html index fcaf782..655e611 100644 --- a/doc/file.CHANGELOG.html +++ b/doc/file.CHANGELOG.html @@ -76,8 +76,8 @@

        • TAG: v2.0.3
        • -
        • COVERAGE: 100.00% – 119/119 lines in 7 files
        • -
        • BRANCH COVERAGE: 100.00% – 35/35 branches in 7 files
        • +
        • COVERAGE: 100.00% – 130/130 lines in 7 files
        • +
        • BRANCH COVERAGE: 100.00% – 37/37 branches in 7 files
        • 100.00% documented

          Added

        • @@ -92,7 +92,8 @@

          Added

        • Clarifying documentation (@pboling)

          Fixed

        • -
        • Serializer extensions dump and load empty values properly (@pboling) +
        • +gh4 - Serializer extensions dump and load empty values properly (@pboling)
          • Fixed dump_extensions, load_extensions, load_hash_extensions
          • @@ -196,7 +197,7 @@

            Added

            diff --git a/doc/file.CODE_OF_CONDUCT.html b/doc/file.CODE_OF_CONDUCT.html index 7b1c480..8474c27 100644 --- a/doc/file.CODE_OF_CONDUCT.html +++ b/doc/file.CODE_OF_CONDUCT.html @@ -192,7 +192,7 @@

            Attribution

            diff --git a/doc/file.CONTRIBUTING.html b/doc/file.CONTRIBUTING.html index 5754c8f..1af76b5 100644 --- a/doc/file.CONTRIBUTING.html +++ b/doc/file.CONTRIBUTING.html @@ -195,7 +195,7 @@

            To release a new version:

            diff --git a/doc/file.LICENSE.html b/doc/file.LICENSE.html index d81440a..a5cafbb 100644 --- a/doc/file.LICENSE.html +++ b/doc/file.LICENSE.html @@ -60,7 +60,7 @@
            The MIT License (MIT)

            Copyright (c) 2022, 2025 Peter Boling

            Permission is hereby granted, free of charge, to any person obtaining a copy
            of this software and associated documentation files (the "Software"), to deal
            in the Software without restriction, including without limitation the rights
            to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
            copies of the Software, and to permit persons to whom the Software is
            furnished to do so, subject to the following conditions:

            The above copyright notice and this permission notice shall be included in
            all copies or substantial portions of the Software.

            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
            IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
            FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
            AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
            LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
            OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
            THE SOFTWARE.
            diff --git a/doc/file.README.html b/doc/file.README.html index 7b449cc..0fd8640 100644 --- a/doc/file.README.html +++ b/doc/file.README.html @@ -297,7 +297,7 @@

            💡 Info you can shake a stick at

      • @@ -687,7 +687,7 @@

        🤑 One more thing

        diff --git a/doc/file.SECURITY.html b/doc/file.SECURITY.html index 6d46d95..775ba75 100644 --- a/doc/file.SECURITY.html +++ b/doc/file.SECURITY.html @@ -104,7 +104,7 @@

        Snaky Hash for Enterprise

        diff --git a/doc/index.html b/doc/index.html index d7c34ab..f275334 100644 --- a/doc/index.html +++ b/doc/index.html @@ -297,7 +297,7 @@

        💡 Info you can shake a stick at

        @@ -687,7 +687,7 @@

        🤑 One more thing

        diff --git a/doc/top-level-namespace.html b/doc/top-level-namespace.html index 1fa9085..5a7265c 100644 --- a/doc/top-level-namespace.html +++ b/doc/top-level-namespace.html @@ -100,7 +100,7 @@

        Defined Under Namespace

        diff --git a/lib/snaky_hash/serializer.rb b/lib/snaky_hash/serializer.rb index f463151..0a579b5 100644 --- a/lib/snaky_hash/serializer.rb +++ b/lib/snaky_hash/serializer.rb @@ -181,9 +181,20 @@ def load_hash(hash) ran = load_hash_extensions.run(self[hash]) return load_value(ran) unless ran.is_a?(::Hash) - self[ran].transform_values do |value| + res = self[ran].transform_values do |value| load_value(value) end + + # TODO: Drop this hack when dropping support for Ruby 2.6 + if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7") + res + else + # :nocov: + # In Ruby <= 2.6 Hash#transform_values returned a new vanilla Hash, + # rather than a hash of the class being transformed. + self[res] + # :nocov: + end end # Processes a single value for loading From caccdc0ea32ec4c2e38f1806f7a0f2d41f74d84a Mon Sep 17 00:00:00 2001 From: "Peter H. Boling" Date: Fri, 23 May 2025 09:32:32 +0700 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=94=96=20Prepare=20release=20v2.0.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Gemfile.lock | 2 +- doc/SnakyHash.html | 2 +- doc/SnakyHash/Error.html | 2 +- doc/SnakyHash/Extensions.html | 2 +- doc/SnakyHash/Serializer.html | 2 +- doc/SnakyHash/Serializer/BackportedInstanceMethods.html | 2 +- doc/SnakyHash/Serializer/ConvenienceInstanceMethods.html | 2 +- doc/SnakyHash/Serializer/Modulizer.html | 2 +- doc/SnakyHash/Snake.html | 2 +- doc/SnakyHash/Snake/SnakyModulizer.html | 2 +- doc/SnakyHash/StringKeyed.html | 2 +- doc/SnakyHash/SymbolKeyed.html | 2 +- doc/SnakyHash/Version.html | 4 ++-- doc/_index.html | 2 +- doc/file.CHANGELOG.html | 6 +++--- doc/file.CODE_OF_CONDUCT.html | 2 +- doc/file.CONTRIBUTING.html | 2 +- doc/file.LICENSE.html | 2 +- doc/file.README.html | 4 ++-- doc/file.SECURITY.html | 2 +- doc/index.html | 4 ++-- doc/top-level-namespace.html | 2 +- lib/snaky_hash/version.rb | 2 +- 23 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 5545a0c..a44e705 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -23,7 +23,7 @@ GIT PATH remote: . specs: - snaky_hash (2.0.2) + snaky_hash (2.0.3) hashie (>= 0.1.0, < 6) version_gem (>= 1.1.8, < 3) diff --git a/doc/SnakyHash.html b/doc/SnakyHash.html index b17fb18..6c6f65c 100644 --- a/doc/SnakyHash.html +++ b/doc/SnakyHash.html @@ -147,7 +147,7 @@

        Usage with symbol keys and seri

        diff --git a/doc/SnakyHash/Error.html b/doc/SnakyHash/Error.html index 8c69e15..01e250e 100644 --- a/doc/SnakyHash/Error.html +++ b/doc/SnakyHash/Error.html @@ -124,7 +124,7 @@

        Overview

        diff --git a/doc/SnakyHash/Extensions.html b/doc/SnakyHash/Extensions.html index 31e42d9..d2cc5b1 100644 --- a/doc/SnakyHash/Extensions.html +++ b/doc/SnakyHash/Extensions.html @@ -645,7 +645,7 @@

        diff --git a/doc/SnakyHash/Serializer.html b/doc/SnakyHash/Serializer.html index dbf50eb..743534a 100644 --- a/doc/SnakyHash/Serializer.html +++ b/doc/SnakyHash/Serializer.html @@ -462,7 +462,7 @@

        diff --git a/doc/SnakyHash/Serializer/BackportedInstanceMethods.html b/doc/SnakyHash/Serializer/BackportedInstanceMethods.html index bd18501..d461e5b 100644 --- a/doc/SnakyHash/Serializer/BackportedInstanceMethods.html +++ b/doc/SnakyHash/Serializer/BackportedInstanceMethods.html @@ -254,7 +254,7 @@

        diff --git a/doc/SnakyHash/Serializer/ConvenienceInstanceMethods.html b/doc/SnakyHash/Serializer/ConvenienceInstanceMethods.html index 06f30df..5557eec 100644 --- a/doc/SnakyHash/Serializer/ConvenienceInstanceMethods.html +++ b/doc/SnakyHash/Serializer/ConvenienceInstanceMethods.html @@ -214,7 +214,7 @@

        diff --git a/doc/SnakyHash/Serializer/Modulizer.html b/doc/SnakyHash/Serializer/Modulizer.html index 4d2b44e..cb47788 100644 --- a/doc/SnakyHash/Serializer/Modulizer.html +++ b/doc/SnakyHash/Serializer/Modulizer.html @@ -250,7 +250,7 @@

        diff --git a/doc/SnakyHash/Snake.html b/doc/SnakyHash/Snake.html index 697cec0..d1c3fb6 100644 --- a/doc/SnakyHash/Snake.html +++ b/doc/SnakyHash/Snake.html @@ -376,7 +376,7 @@

        diff --git a/doc/SnakyHash/Snake/SnakyModulizer.html b/doc/SnakyHash/Snake/SnakyModulizer.html index 0e1a6c3..2ea2ecf 100644 --- a/doc/SnakyHash/Snake/SnakyModulizer.html +++ b/doc/SnakyHash/Snake/SnakyModulizer.html @@ -358,7 +358,7 @@

        diff --git a/doc/SnakyHash/StringKeyed.html b/doc/SnakyHash/StringKeyed.html index 0c7f371..d8835c1 100644 --- a/doc/SnakyHash/StringKeyed.html +++ b/doc/SnakyHash/StringKeyed.html @@ -130,7 +130,7 @@

        Overview

        diff --git a/doc/SnakyHash/SymbolKeyed.html b/doc/SnakyHash/SymbolKeyed.html index d759e09..8a72f5a 100644 --- a/doc/SnakyHash/SymbolKeyed.html +++ b/doc/SnakyHash/SymbolKeyed.html @@ -130,7 +130,7 @@

        Overview

        diff --git a/doc/SnakyHash/Version.html b/doc/SnakyHash/Version.html index 0e6e9fb..c4271d4 100644 --- a/doc/SnakyHash/Version.html +++ b/doc/SnakyHash/Version.html @@ -132,7 +132,7 @@

        -
        "2.0.2"
        +
        "2.0.3"
        @@ -148,7 +148,7 @@

        diff --git a/doc/_index.html b/doc/_index.html index cda1841..14a5542 100644 --- a/doc/_index.html +++ b/doc/_index.html @@ -229,7 +229,7 @@

        Namespace Listing A-Z

        diff --git a/doc/file.CHANGELOG.html b/doc/file.CHANGELOG.html index 655e611..e1db9cd 100644 --- a/doc/file.CHANGELOG.html +++ b/doc/file.CHANGELOG.html @@ -76,8 +76,8 @@

        • TAG: v2.0.3
        • -
        • COVERAGE: 100.00% – 130/130 lines in 7 files
        • -
        • BRANCH COVERAGE: 100.00% – 37/37 branches in 7 files
        • +
        • COVERAGE: 100.00% – 132/132 lines in 7 files
        • +
        • BRANCH COVERAGE: 100.00% – 38/38 branches in 7 files
        • 100.00% documented

          Added

        • @@ -197,7 +197,7 @@

          Added

          diff --git a/doc/file.CODE_OF_CONDUCT.html b/doc/file.CODE_OF_CONDUCT.html index 8474c27..80207a0 100644 --- a/doc/file.CODE_OF_CONDUCT.html +++ b/doc/file.CODE_OF_CONDUCT.html @@ -192,7 +192,7 @@

          Attribution

          diff --git a/doc/file.CONTRIBUTING.html b/doc/file.CONTRIBUTING.html index 1af76b5..9009b46 100644 --- a/doc/file.CONTRIBUTING.html +++ b/doc/file.CONTRIBUTING.html @@ -195,7 +195,7 @@

          To release a new version:

          diff --git a/doc/file.LICENSE.html b/doc/file.LICENSE.html index a5cafbb..4d2d2d7 100644 --- a/doc/file.LICENSE.html +++ b/doc/file.LICENSE.html @@ -60,7 +60,7 @@
          The MIT License (MIT)

          Copyright (c) 2022, 2025 Peter Boling

          Permission is hereby granted, free of charge, to any person obtaining a copy
          of this software and associated documentation files (the "Software"), to deal
          in the Software without restriction, including without limitation the rights
          to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
          copies of the Software, and to permit persons to whom the Software is
          furnished to do so, subject to the following conditions:

          The above copyright notice and this permission notice shall be included in
          all copies or substantial portions of the Software.

          THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
          IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
          FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
          AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
          LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
          OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
          THE SOFTWARE.
          diff --git a/doc/file.README.html b/doc/file.README.html index 0fd8640..75225d5 100644 --- a/doc/file.README.html +++ b/doc/file.README.html @@ -297,7 +297,7 @@

          💡 Info you can shake a stick at

        @@ -687,7 +687,7 @@

        🤑 One more thing

        diff --git a/doc/file.SECURITY.html b/doc/file.SECURITY.html index 775ba75..4008d00 100644 --- a/doc/file.SECURITY.html +++ b/doc/file.SECURITY.html @@ -104,7 +104,7 @@

        Snaky Hash for Enterprise

        diff --git a/doc/index.html b/doc/index.html index f275334..ea2baf5 100644 --- a/doc/index.html +++ b/doc/index.html @@ -297,7 +297,7 @@

        💡 Info you can shake a stick at

        @@ -687,7 +687,7 @@

        🤑 One more thing

        diff --git a/doc/top-level-namespace.html b/doc/top-level-namespace.html index 5a7265c..5c9a153 100644 --- a/doc/top-level-namespace.html +++ b/doc/top-level-namespace.html @@ -100,7 +100,7 @@

        Defined Under Namespace

        diff --git a/lib/snaky_hash/version.rb b/lib/snaky_hash/version.rb index a096a57..30fa30f 100644 --- a/lib/snaky_hash/version.rb +++ b/lib/snaky_hash/version.rb @@ -8,6 +8,6 @@ module Version # Current version of SnakyHash # # @return [String] the current version in semantic versioning format - VERSION = "2.0.2" + VERSION = "2.0.3" end end
        Source -Source on GitLab.com Source on CodeBerg.org Source on Github.com The best SHA: dQw4w9WgXcQ! +Source on GitLab.com Source on CodeBerg.org Source on Github.com The best SHA: dQw4w9WgXcQ!
        Source -Source on GitLab.com Source on CodeBerg.org Source on Github.com The best SHA: dQw4w9WgXcQ! +Source on GitLab.com Source on CodeBerg.org Source on Github.com The best SHA: dQw4w9WgXcQ!
        Source -Source on GitLab.com Source on CodeBerg.org Source on Github.com The best SHA: dQw4w9WgXcQ! +Source on GitLab.com Source on CodeBerg.org Source on Github.com The best SHA: dQw4w9WgXcQ!
        Source -Source on GitLab.com Source on CodeBerg.org Source on Github.com The best SHA: dQw4w9WgXcQ! +Source on GitLab.com Source on CodeBerg.org Source on Github.com The best SHA: dQw4w9WgXcQ!