snaky_hash 2.0.2 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +91 -8
- data/CITATION.cff +23 -0
- data/CODE_OF_CONDUCT.md +24 -22
- data/IRP.md +107 -0
- data/LICENSE.txt +1 -1
- data/README.md +78 -45
- data/REEK +27 -0
- data/lib/snaky_hash/extensions.rb +0 -0
- data/lib/snaky_hash/serializer.rb +59 -16
- data/lib/snaky_hash/snake.rb +6 -1
- data/lib/snaky_hash/string_keyed.rb +0 -0
- data/lib/snaky_hash/symbol_keyed.rb +0 -0
- data/lib/snaky_hash/version.rb +2 -1
- data/lib/snaky_hash.rb +0 -0
- data/sig/snaky_hash.rbs +4 -0
- data.tar.gz.sig +0 -0
- metadata +118 -39
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6994e51a3a7343a5b2b2b1d0d055721203ed81764991032a0f81ae6c2931646f
|
|
4
|
+
data.tar.gz: 8453695e75b616782ab21c4cef71fc3870c1a1984b7c7f477babde05c2eef252
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0516c0b68ff581232463f5f6d81802fe3f2314693ce9270ce56d677bf62090163b5663bbb4a4e1d8ede5c26d9c51404cc1fa03005509a399b17e98cc4536aea2
|
|
7
|
+
data.tar.gz: 26816588362b496f9753f8087aabf650a8eaf024038e8f55e5216ad112d2b2c61f1f8ebcc225e184618e822c62a3e9f183bd4635c5c76ce8039bc209e922d860
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -1,20 +1,77 @@
|
|
|
1
1
|
# Changelog
|
|
2
|
+
|
|
2
3
|
All notable changes to this project will be documented in this file.
|
|
3
4
|
|
|
4
5
|
The format (since v2) is based on [Keep a Changelog v1](https://keepachangelog.com/en/1.0.0/),
|
|
5
6
|
and this project adheres to [Semantic Versioning v2](https://semver.org/spec/v2.0.0.html).
|
|
6
7
|
|
|
7
8
|
## [Unreleased]
|
|
9
|
+
|
|
8
10
|
### Added
|
|
11
|
+
|
|
9
12
|
### Changed
|
|
10
|
-
|
|
13
|
+
|
|
14
|
+
### Deprecated
|
|
15
|
+
|
|
11
16
|
### Removed
|
|
12
17
|
|
|
13
|
-
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
### Security
|
|
21
|
+
|
|
22
|
+
## [2.0.4] - 2026-05-16
|
|
23
|
+
|
|
24
|
+
- TAG: [v2.0.4][2.0.4t]
|
|
25
|
+
- COVERAGE: 100.00% -- 133/133 lines in 7 files
|
|
26
|
+
- BRANCH COVERAGE: 100.00% -- 38/38 branches in 7 files
|
|
27
|
+
- 100.00% documented
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- Incident Response Plan in IRP.md
|
|
32
|
+
- SnakyHash::VERSION (Traditional Constant Location)
|
|
33
|
+
- kettle-dev & kettle-test dev harnesses
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
|
|
37
|
+
- Contributor Conenant updated to version 2.1
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
41
|
+
- Specs
|
|
42
|
+
|
|
43
|
+
## [2.0.3] - 2025-05-23
|
|
44
|
+
|
|
45
|
+
- TAG: [v2.0.3][2.0.3t]
|
|
46
|
+
- COVERAGE: 100.00% -- 132/132 lines in 7 files
|
|
47
|
+
- BRANCH COVERAGE: 100.00% -- 38/38 branches in 7 files
|
|
48
|
+
- 100.00% documented
|
|
49
|
+
|
|
50
|
+
### Added
|
|
51
|
+
|
|
52
|
+
- `#dump` instance method injected by `extend SnakyHash::Serializer` (@pboling)
|
|
53
|
+
- `dump_hash_extensions` - new feature, analogous to `load_hash_extensions` (@pboling)
|
|
54
|
+
- `dump_value_extensions` - alternate name for `dump_extensions` (@pboling)
|
|
55
|
+
- `load_value_extensions` - alternate name for `load_extensions` (@pboling)
|
|
56
|
+
- Clarifying documentation (@pboling)
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
|
|
60
|
+
- [gh4](https://github.com/oauth-xx/snaky_hash/pull/4) - Serializer extensions dump and load empty values properly (@pboling)
|
|
61
|
+
- Fixed `dump_extensions`, `load_extensions`, `load_hash_extensions`
|
|
62
|
+
- Intended usage is primarily JSON, and oauth2 gem
|
|
63
|
+
- OAuth2 spec can have legitimately empty values (e.g. scopes could be empty)
|
|
64
|
+
- Previous logic was inherited from design decisions made by `serialized_hashie` gem; doesn't apply here
|
|
65
|
+
|
|
66
|
+
## [2.0.2] - 2025-05-21
|
|
67
|
+
|
|
68
|
+
- TAG: [v2.0.2][2.0.2t]
|
|
14
69
|
- COVERAGE: 100.00% -- 119/119 lines in 7 files
|
|
15
70
|
- BRANCH COVERAGE: 100.00% -- 35/35 branches in 7 files
|
|
16
71
|
- 100.00% documented
|
|
72
|
+
|
|
17
73
|
### Added
|
|
74
|
+
|
|
18
75
|
- Gem is signed by 20-year cert (@pboling)
|
|
19
76
|
- Expires 2045-04-29
|
|
20
77
|
- Gemspec metadata updates (@pboling)
|
|
@@ -26,40 +83,66 @@ and this project adheres to [Semantic Versioning v2](https://semver.org/spec/v2.
|
|
|
26
83
|
- Documentation site at [snaky-hash.galtzo.com](https://snaky-hash.galtzo.com) (@pboling)
|
|
27
84
|
- 100% documented! (@pboling)
|
|
28
85
|
|
|
29
|
-
## [2.0.1] - 2022-09-23
|
|
86
|
+
## [2.0.1] - 2022-09-23
|
|
87
|
+
|
|
88
|
+
- TAG: [v2.0.1][2.0.1t]
|
|
89
|
+
|
|
30
90
|
### Added
|
|
91
|
+
|
|
31
92
|
- Certificate for signing gem releases (@pboling)
|
|
32
93
|
- Gemspec metadata (@pboling)
|
|
33
94
|
- funding_uri
|
|
34
95
|
- mailing_list_uri
|
|
35
96
|
- Checksums for released gems (@pboling)
|
|
97
|
+
|
|
36
98
|
### Changed
|
|
99
|
+
|
|
37
100
|
- Gem releases are now cryptographically signed (@pboling)
|
|
38
101
|
|
|
39
|
-
## [2.0.0] - 2022-08-29
|
|
102
|
+
## [2.0.0] - 2022-08-29
|
|
103
|
+
|
|
104
|
+
- TAG: [v2.0.0][2.0.0t]
|
|
105
|
+
|
|
40
106
|
### Changed
|
|
107
|
+
|
|
41
108
|
- **BREAKING**: `SnakeHash::Snake` is now a mixin, now with support for symbol or string keys
|
|
42
109
|
```ruby
|
|
43
110
|
class MySnakedHash < Hashie::Mash
|
|
44
111
|
include SnakyHash::Snake.new(key_type: :string) # or :symbol
|
|
45
112
|
end
|
|
46
113
|
```
|
|
114
|
+
|
|
47
115
|
### Added
|
|
116
|
+
|
|
48
117
|
- `SnakyHash::StringKeyed`: a Hashie::Mash class with snake-cased String keys
|
|
49
118
|
- `SnakyHash::SymbolKeyed`: a Hashie::Mash class with snake-cased Symbol keys
|
|
50
119
|
|
|
51
|
-
## [1.0.1] - 2022-08-26
|
|
120
|
+
## [1.0.1] - 2022-08-26
|
|
121
|
+
|
|
122
|
+
- TAG: [v1.0.1][1.0.1t]
|
|
123
|
+
|
|
52
124
|
### Added
|
|
125
|
+
|
|
53
126
|
- Missing LICENSE.txt file to release
|
|
127
|
+
|
|
54
128
|
### Removed
|
|
129
|
+
|
|
55
130
|
- Accidentally added bundler dependency (vestige of transpec process) is now removed
|
|
56
131
|
|
|
57
|
-
## [1.0.0] - 2022-08-26
|
|
132
|
+
## [1.0.0] - 2022-08-26
|
|
133
|
+
|
|
134
|
+
- TAG: [v1.0.0][1.0.0t]
|
|
135
|
+
|
|
58
136
|
### Added
|
|
137
|
+
|
|
59
138
|
- Initial release
|
|
60
139
|
|
|
61
|
-
[Unreleased]: https://
|
|
62
|
-
[2.0.
|
|
140
|
+
[Unreleased]: https://github.com/ruby-oauth/snaky_hash/compare/v2.0.4...HEAD
|
|
141
|
+
[2.0.4]: https://github.com/ruby-oauth/snaky_hash/compare/v2.0.3...v2.0.4
|
|
142
|
+
[2.0.4t]: https://github.com/ruby-oauth/snaky_hash/releases/tag/v2.0.4
|
|
143
|
+
[2.0.3]: https://gitlab.com/oauth-xx/snaky_hash/-/compare/v2.0.2...v2.0.3
|
|
144
|
+
[2.0.3t]: https://gitlab.com/oauth-xx/snaky_hash/-/releases/tag/v2.0.3
|
|
145
|
+
[2.0.2]: https://gitlab.com/oauth-xx/snaky_hash/-/compare/v2.0.1...v2.0.2
|
|
63
146
|
[2.0.2t]: https://gitlab.com/oauth-xx/snaky_hash/-/releases/tag/v2.0.2
|
|
64
147
|
[2.0.1]: https://gitlab.com/oauth-xx/snaky_hash/-/compare/v2.0.0...v2.0.1
|
|
65
148
|
[2.0.1t]: https://gitlab.com/oauth-xx/snaky_hash/-/releases/tag/v2.0.1
|
data/CITATION.cff
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
title: snaky_hash
|
|
3
|
+
message: >-
|
|
4
|
+
If you use this work and you want to cite it,
|
|
5
|
+
then you can use the metadata from this file.
|
|
6
|
+
type: software
|
|
7
|
+
authors:
|
|
8
|
+
- given-names: Peter Hurn
|
|
9
|
+
family-names: Boling
|
|
10
|
+
email: peter@railsbling.com
|
|
11
|
+
affiliation: railsbling.com
|
|
12
|
+
orcid: 'https://orcid.org/0009-0008-8519-441X'
|
|
13
|
+
- given-names: Aboling0
|
|
14
|
+
email: aboling@railsbling.com
|
|
15
|
+
affiliation: railsbling.com
|
|
16
|
+
identifiers:
|
|
17
|
+
- type: url
|
|
18
|
+
value: 'https://github.com/oauth-xx/snaky_hash'
|
|
19
|
+
description: snaky_hash
|
|
20
|
+
repository-code: 'https://github.com/oauth-xx/snaky_hash'
|
|
21
|
+
abstract: >-
|
|
22
|
+
snaky_hash
|
|
23
|
+
license: See license file
|
data/CODE_OF_CONDUCT.md
CHANGED
|
@@ -7,8 +7,8 @@ We as members, contributors, and leaders pledge to make participation in our
|
|
|
7
7
|
community a harassment-free experience for everyone, regardless of age, body
|
|
8
8
|
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
|
9
9
|
identity and expression, level of experience, education, socio-economic status,
|
|
10
|
-
nationality, personal appearance, race, religion, or sexual
|
|
11
|
-
and orientation.
|
|
10
|
+
nationality, personal appearance, race, caste, color, religion, or sexual
|
|
11
|
+
identity and orientation.
|
|
12
12
|
|
|
13
13
|
We pledge to act and interact in ways that contribute to an open, welcoming,
|
|
14
14
|
diverse, inclusive, and healthy community.
|
|
@@ -23,17 +23,17 @@ community include:
|
|
|
23
23
|
* Giving and gracefully accepting constructive feedback
|
|
24
24
|
* Accepting responsibility and apologizing to those affected by our mistakes,
|
|
25
25
|
and learning from the experience
|
|
26
|
-
* Focusing on what is best not just for us as individuals, but for the
|
|
27
|
-
|
|
26
|
+
* Focusing on what is best not just for us as individuals, but for the overall
|
|
27
|
+
community
|
|
28
28
|
|
|
29
29
|
Examples of unacceptable behavior include:
|
|
30
30
|
|
|
31
|
-
* The use of sexualized language or imagery, and sexual attention or
|
|
32
|
-
|
|
31
|
+
* The use of sexualized language or imagery, and sexual attention or advances of
|
|
32
|
+
any kind
|
|
33
33
|
* Trolling, insulting or derogatory comments, and personal or political attacks
|
|
34
34
|
* Public or private harassment
|
|
35
|
-
* Publishing others' private information, such as a physical or email
|
|
36
|
-
|
|
35
|
+
* Publishing others' private information, such as a physical or email address,
|
|
36
|
+
without their explicit permission
|
|
37
37
|
* Other conduct which could reasonably be considered inappropriate in a
|
|
38
38
|
professional setting
|
|
39
39
|
|
|
@@ -53,7 +53,7 @@ decisions when appropriate.
|
|
|
53
53
|
|
|
54
54
|
This Code of Conduct applies within all community spaces, and also applies when
|
|
55
55
|
an individual is officially representing the community in public spaces.
|
|
56
|
-
Examples of representing our community include using an official
|
|
56
|
+
Examples of representing our community include using an official email address,
|
|
57
57
|
posting via an official social media account, or acting as an appointed
|
|
58
58
|
representative at an online or offline event.
|
|
59
59
|
|
|
@@ -61,7 +61,7 @@ representative at an online or offline event.
|
|
|
61
61
|
|
|
62
62
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
63
63
|
reported to the community leaders responsible for enforcement at
|
|
64
|
-
[
|
|
64
|
+
[![Contact BDFL][🚂bdfl-contact-img]][🚂bdfl-contact].
|
|
65
65
|
All complaints will be reviewed and investigated promptly and fairly.
|
|
66
66
|
|
|
67
67
|
All community leaders are obligated to respect the privacy and security of the
|
|
@@ -83,15 +83,15 @@ behavior was inappropriate. A public apology may be requested.
|
|
|
83
83
|
|
|
84
84
|
### 2. Warning
|
|
85
85
|
|
|
86
|
-
**Community Impact**: A violation through a single incident or series
|
|
87
|
-
|
|
86
|
+
**Community Impact**: A violation through a single incident or series of
|
|
87
|
+
actions.
|
|
88
88
|
|
|
89
89
|
**Consequence**: A warning with consequences for continued behavior. No
|
|
90
90
|
interaction with the people involved, including unsolicited interaction with
|
|
91
91
|
those enforcing the Code of Conduct, for a specified period of time. This
|
|
92
92
|
includes avoiding interactions in community spaces as well as external channels
|
|
93
|
-
like social media. Violating these terms may lead to a temporary or
|
|
94
|
-
|
|
93
|
+
like social media. Violating these terms may lead to a temporary or permanent
|
|
94
|
+
ban.
|
|
95
95
|
|
|
96
96
|
### 3. Temporary Ban
|
|
97
97
|
|
|
@@ -107,27 +107,29 @@ Violating these terms may lead to a permanent ban.
|
|
|
107
107
|
### 4. Permanent Ban
|
|
108
108
|
|
|
109
109
|
**Community Impact**: Demonstrating a pattern of violation of community
|
|
110
|
-
standards, including sustained inappropriate behavior,
|
|
110
|
+
standards, including sustained inappropriate behavior, harassment of an
|
|
111
111
|
individual, or aggression toward or disparagement of classes of individuals.
|
|
112
112
|
|
|
113
|
-
**Consequence**: A permanent ban from any sort of public interaction within
|
|
114
|
-
|
|
113
|
+
**Consequence**: A permanent ban from any sort of public interaction within the
|
|
114
|
+
community.
|
|
115
115
|
|
|
116
116
|
## Attribution
|
|
117
117
|
|
|
118
118
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
|
119
|
-
version 2.
|
|
120
|
-
[https://www.contributor-covenant.org/version/2/
|
|
119
|
+
version 2.1, available at
|
|
120
|
+
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
|
121
121
|
|
|
122
122
|
Community Impact Guidelines were inspired by
|
|
123
123
|
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
|
124
124
|
|
|
125
125
|
For answers to common questions about this code of conduct, see the FAQ at
|
|
126
|
-
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available
|
|
127
|
-
|
|
126
|
+
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
|
127
|
+
[https://www.contributor-covenant.org/translations][translations].
|
|
128
128
|
|
|
129
129
|
[homepage]: https://www.contributor-covenant.org
|
|
130
|
-
[v2.
|
|
130
|
+
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
|
131
131
|
[Mozilla CoC]: https://github.com/mozilla/diversity
|
|
132
132
|
[FAQ]: https://www.contributor-covenant.org/faq
|
|
133
133
|
[translations]: https://www.contributor-covenant.org/translations
|
|
134
|
+
[🚂bdfl-contact]: http://www.railsbling.com/contact
|
|
135
|
+
[🚂bdfl-contact-img]: https://img.shields.io/badge/Contact-BDFL-0093D0.svg?style=flat&logo=rubyonrails&logoColor=red
|
data/IRP.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Incident Response Plan (IRP)
|
|
2
|
+
|
|
3
|
+
Status: Draft
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
This Incident Response Plan (IRP) defines the steps the project maintainer(s) will follow when handling security incidents related to the `snaky_hash` gem. It is written for a small project with a single primary maintainer and is intended to be practical, concise, and actionable.
|
|
8
|
+
|
|
9
|
+
## Scope
|
|
10
|
+
|
|
11
|
+
Applies to security incidents that affect the `snaky_hash` codebase, releases (gems), CI/CD infrastructure related to building and publishing the gem, repository credentials, or any compromise of project infrastructure that could impact users.
|
|
12
|
+
|
|
13
|
+
## Key assumptions
|
|
14
|
+
- This project is maintained primarily by a single maintainer.
|
|
15
|
+
- Public vulnerability disclosure is handled via Tidelift (see `SECURITY.md`).
|
|
16
|
+
- The maintainer will act as incident commander unless otherwise delegated.
|
|
17
|
+
|
|
18
|
+
## Contact & Roles
|
|
19
|
+
|
|
20
|
+
- Incident Commander: Primary maintainer (repo owner). Responsible for coordinating triage, remediation, and communications.
|
|
21
|
+
- Secondary Contact: (optional) A trusted collaborator or organization contact if available.
|
|
22
|
+
|
|
23
|
+
### If you are an external reporter
|
|
24
|
+
- Do not publicly disclose details of an active vulnerability before coordination via Tidelift.
|
|
25
|
+
- See `SECURITY.md` for Tidelift disclosure instructions. If the reporter has questions and cannot use Tidelift, they may open a direct encrypted report as described in `SECURITY.md` (if available) or email the maintainer contact listed in the repository.
|
|
26
|
+
|
|
27
|
+
## Incident Handling Workflow (high level)
|
|
28
|
+
1. Identification & Reporting
|
|
29
|
+
- Reports may arrive via Tidelift, issue tracker, direct email, or third-party advisories.
|
|
30
|
+
- Immediately acknowledge receipt (within 24-72 hours) via the reporting channel.
|
|
31
|
+
|
|
32
|
+
2. Triage & Initial Assessment (first 72 hours)
|
|
33
|
+
- Confirm the report is not duplicative and gather: reproducer, affected versions, attack surface, exploitability, and CVSS-like severity estimate.
|
|
34
|
+
- Verify the issue against the codebase and reproduce locally if possible.
|
|
35
|
+
- Determine scope: which versions are affected, whether the issue is in code paths executed in common setups, and whether a workaround exists.
|
|
36
|
+
|
|
37
|
+
3. Containment & Mitigation
|
|
38
|
+
- If a simple mitigation or workaround (configuration change, safe default, or recommended upgrade) exists, document it clearly in the issue/Tidelift advisory.
|
|
39
|
+
- If immediate removal of a release is required (rare), consult Tidelift for coordinated takedown and notify package hosts if applicable.
|
|
40
|
+
|
|
41
|
+
4. Remediation & Patch
|
|
42
|
+
- Prepare a fix in a branch with tests and changelog entries. Prefer minimal, well-tested changes.
|
|
43
|
+
- Include tests that reproduce the faulty behavior and demonstrate the fix.
|
|
44
|
+
- Hardening: add fuzz tests, input validation, or additional checks as appropriate.
|
|
45
|
+
|
|
46
|
+
5. Release & Disclosure
|
|
47
|
+
- Coordinate disclosure through Tidelift per `SECURITY.md` timelines. Aim for a coordinated disclosure and patch release to minimize risk to users.
|
|
48
|
+
- Publish a patch release (increment gem version) and an advisory via Tidelift.
|
|
49
|
+
- Update `CHANGELOG.md` and repository release notes with non-sensitive details.
|
|
50
|
+
|
|
51
|
+
6. Post-Incident
|
|
52
|
+
- Produce a short postmortem: timeline, root cause, actions taken, and follow-ups.
|
|
53
|
+
- Add/adjust tests and CI checks to prevent regressions.
|
|
54
|
+
- If credentials or infrastructure were compromised, rotate secrets and audit access.
|
|
55
|
+
|
|
56
|
+
## Severity classification (guidance)
|
|
57
|
+
- High/Critical: Remote code execution, data exfiltration, or any vulnerability that can be exploited without user interaction. Immediate action and prioritized patching.
|
|
58
|
+
- Medium: Privilege escalation, sensitive information leaks that require specific conditions. Patch in the next release cycle with advisory.
|
|
59
|
+
- Low: Minor information leaks, UI issues, or non-exploitable bugs. Fix normally and include in the next scheduled release.
|
|
60
|
+
|
|
61
|
+
## Preservation of evidence
|
|
62
|
+
- Preserve all reporter-provided data, logs, and reproducer code in a secure location (local encrypted storage or private branch) for the investigation.
|
|
63
|
+
- Do not publish evidence that would enable exploitation before coordinated disclosure.
|
|
64
|
+
|
|
65
|
+
## Communication templates
|
|
66
|
+
Acknowledgement (to reporter)
|
|
67
|
+
|
|
68
|
+
"Thank you for reporting this issue. I've received your report and will triage it within 72 hours. If you can, please provide reproduction steps, affected versions, and any exploit PoC. I will coordinate disclosure through Tidelift per the project's security policy."
|
|
69
|
+
|
|
70
|
+
Public advisory (after patch is ready)
|
|
71
|
+
|
|
72
|
+
"A security advisory for snaky_hash (versions X.Y.Z) has been published via Tidelift. Please upgrade to version A.B.C which patches [brief description]. See the advisory for details and recommended mitigations."
|
|
73
|
+
|
|
74
|
+
## Runbook: Quick steps for a maintainer to patch and release
|
|
75
|
+
1. Create a branch: `git checkout -b fix/security-brief-description`
|
|
76
|
+
2. Reproduce the issue locally and add a regression spec in `spec/`.
|
|
77
|
+
3. Implement the fix and run the test suite: `bundle exec rspec` (or the project's preferred test command).
|
|
78
|
+
4. Bump version in `lib/snaky_hash/version.rb` following semantic versioning.
|
|
79
|
+
5. Update `CHANGELOG.md` with an entry describing the fix (avoid exploit details).
|
|
80
|
+
6. Commit and push the branch, open a PR, and merge after approvals.
|
|
81
|
+
7. Build and push the gem: `gem build snaky_hash.gemspec && gem push pkg/...` (coordinate with Tidelift before public push if disclosure is coordinated).
|
|
82
|
+
8. Publish a release on GitHub and ensure the Tidelift advisory is posted.
|
|
83
|
+
|
|
84
|
+
## Operational notes
|
|
85
|
+
- Secrets: Use local encrypted storage for any sensitive reporter data. If repository or CI secrets may be compromised, rotate them immediately and update dependent services.
|
|
86
|
+
- Access control: Limit who can publish gems and who has admin access to the repo. Keep an up-to-date list of collaborators in a secure place.
|
|
87
|
+
|
|
88
|
+
## Legal & regulatory
|
|
89
|
+
- If the incident involves user data or has legal implications, consult legal counsel or the maintainers' employer as appropriate. The maintainer should document the timeline and all communications.
|
|
90
|
+
|
|
91
|
+
## Retrospective & continuous improvement
|
|
92
|
+
After an incident, perform a brief post-incident review covering:
|
|
93
|
+
- What happened and why
|
|
94
|
+
- What was done to contain and remediate
|
|
95
|
+
- What tests or process changes will prevent recurrence
|
|
96
|
+
- Assign owners and deadlines for follow-up tasks
|
|
97
|
+
|
|
98
|
+
## References
|
|
99
|
+
- See `SECURITY.md` for the project's official disclosure channel (Tidelift).
|
|
100
|
+
|
|
101
|
+
## Appendix: Example checklist for an incident
|
|
102
|
+
- [ ] Acknowledge report to reporter (24-72 hours)
|
|
103
|
+
- [ ] Reproduce and classify severity
|
|
104
|
+
- [ ] Prepare and test a fix in a branch
|
|
105
|
+
- [ ] Coordinate disclosure via Tidelift
|
|
106
|
+
- [ ] Publish patch release and advisory
|
|
107
|
+
- [ ] Postmortem and follow-up actions
|
data/LICENSE.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
The MIT License (MIT)
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2022, 2025 Peter Boling
|
|
3
|
+
Copyright (c) 2022, 2025-2026 Peter Boling
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 🐍 SnakyHash
|
|
2
2
|
|
|
3
|
-
[![Version][👽versioni]][👽version] [![License: MIT][📄license-img]][📄license-ref] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![
|
|
3
|
+
[![Version][👽versioni]][👽version] [![License: MIT][📄license-img]][📄license-ref] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![Coveralls Test Coverage][🔑coveralls-img]][🔑coveralls] [![QLTY Test Coverage][🔑qlty-covi♻️]][🔑qlty-cov] [![QLTY Maintainability][🔑qlty-mnti♻️]][🔑qlty-mnt] [![CI Heads][🚎3-hd-wfi]][🚎3-hd-wf] [![CI Runtime Dependencies @ HEAD][🚎12-crh-wfi]][🚎12-crh-wf] [![CI Current][🚎11-c-wfi]][🚎11-c-wf] [![CI Truffle Ruby][🚎9-t-wfi]][🚎9-t-wf] [![CI JRuby][🚎10-j-wfi]][🚎10-j-wf] [![CI Supported][🚎6-s-wfi]][🚎6-s-wf] [![CI Legacy][🚎4-lg-wfi]][🚎4-lg-wf] [![CI Unsupported][🚎7-us-wfi]][🚎7-us-wf] [![CI Ancient][🚎1-an-wfi]][🚎1-an-wf] [![CI Test Coverage][🚎2-cov-wfi]][🚎2-cov-wf] [![CI Style][🚎5-st-wfi]][🚎5-st-wf] [![CodeQL][🖐codeQL-img]][🖐codeQL]
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -14,7 +14,7 @@ and provide a nice psuedo-object interface.
|
|
|
14
14
|
It can be thought of as a mashup of:
|
|
15
15
|
|
|
16
16
|
* `Rash` (specifically the [`rash_alt`](https://github.com/shishi/rash_alt) flavor), which is a special `Mash`, made popular by the `hashie` gem, and
|
|
17
|
-
* `serialized_hashie` [gem by krystal](https://github.com/krystal/serialized-hashie)
|
|
17
|
+
* `serialized_hashie` [gem by krystal](https://github.com/krystal/serialized-hashie), rewritten, with some behavior changes
|
|
18
18
|
|
|
19
19
|
Classes that `include SnakyHash::Snake.new` should inherit from `Hashie::Mash`.
|
|
20
20
|
|
|
@@ -46,6 +46,17 @@ SnakyHash::StringKeyed.class_eval do
|
|
|
46
46
|
end
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
or you can create a custom class
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
class MyHash < Hashie::Mash
|
|
53
|
+
include SnakyHash::Snake.new(key_type: :string, serializer: true)
|
|
54
|
+
# Which is the same as:
|
|
55
|
+
# include SnakyHash::Snake.new(key_type: :string)
|
|
56
|
+
# extend SnakyHash::Serializer
|
|
57
|
+
end
|
|
58
|
+
```
|
|
59
|
+
|
|
49
60
|
You can then add serialization extensions as needed. See [serialization](#serialization) and [extensions](#extensions) for more.
|
|
50
61
|
|
|
51
62
|
| Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
|
|
@@ -108,7 +119,7 @@ and are developed in tight collaboration with the oauth and oauth2 gems.
|
|
|
108
119
|
| Works with MRI Ruby 3 | [![Ruby 3.0 Compat][💎ruby-3.0i]][🚎4-lg-wf] [![Ruby 3.1 Compat][💎ruby-3.1i]][🚎6-s-wf] [![Ruby 3.2 Compat][💎ruby-3.2i]][🚎6-s-wf] [![Ruby 3.3 Compat][💎ruby-3.3i]][🚎6-s-wf] [![Ruby 3.4 Compat][💎ruby-c-i]][🚎11-c-wf] [![Ruby HEAD Compat][💎ruby-headi]][🚎3-hd-wf] |
|
|
109
120
|
| Works with MRI Ruby 2 | [![Ruby 2.3 Compat][💎ruby-2.3i]][🚎1-an-wf] [![Ruby 2.4 Compat][💎ruby-2.4i]][🚎1-an-wf] [![Ruby 2.5 Compat][💎ruby-2.5i]][🚎1-an-wf] [![Ruby 2.6 Compat][💎ruby-2.6i]][🚎7-us-wf] [![Ruby 2.7 Compat][💎ruby-2.7i]][🚎7-us-wf] |
|
|
110
121
|
| 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] |
|
|
111
|
-
| Documentation | [![Discussion][⛳gg-discussions-img]][⛳gg-discussions] [![Current release on RubyDoc.info][📜docs-cr-rd-img]][🚎yard-current] [![
|
|
122
|
+
| Documentation | [![Discussion][⛳gg-discussions-img]][⛳gg-discussions] [![Current release on RubyDoc.info][📜docs-cr-rd-img]][🚎yard-current] [![YARD on Galtzo.com][📜docs-head-rd-img]][🚎yard-head] [![BDFL Blog][🚂bdfl-blog-img]][🚂bdfl-blog] [![Wiki][📜wiki-img]][📜wiki] |
|
|
112
123
|
| Compliance | [![License: MIT][📄license-img]][📄license-ref] [![📄ilo-declaration-img]][📄ilo-declaration] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] |
|
|
113
124
|
| Style | [![Enforced Code Style Linter][💎rlts-img]][💎rlts] [![Keep-A-Changelog 1.0.0][📗keep-changelog-img]][📗keep-changelog] [![Gitmoji Commits][📌gitmoji-img]][📌gitmoji] |
|
|
114
125
|
| Support | [![Live Chat on Discord][✉️discord-invite-img]][✉️discord-invite] [![Get help from me on Upwork][👨🏼🏫expsup-upwork-img]][👨🏼🏫expsup-upwork] [![Get help from me on Codementor][👨🏼🏫expsup-codementor-img]][👨🏼🏫expsup-codementor] |
|
|
@@ -212,71 +223,95 @@ This is also not a bug, though if you need different behavior, there is a soluti
|
|
|
212
223
|
|
|
213
224
|
You can write your own arbitrary extensions:
|
|
214
225
|
|
|
215
|
-
* "Hash Load" extensions operate on the hash
|
|
226
|
+
* "Hash Load" extensions operate on the hash and nested hashes
|
|
216
227
|
* use `::load_hash_extensions.add(:extension_name) { |hash| }`
|
|
217
|
-
*
|
|
218
|
-
|
|
219
|
-
*
|
|
220
|
-
|
|
228
|
+
* since v2.0.2, bugs fixed in v2.0.3
|
|
229
|
+
* "Value Load" extensions operate on the values, and nested hashes' values, if any
|
|
230
|
+
* use `::load_value_extensions.add(:extension_name) { |value| }`
|
|
231
|
+
* since v2.0.2, bugs fixed in v2.0.3
|
|
232
|
+
* "Hash Dump" extensions operate on the hash and nested hashes
|
|
233
|
+
* use `::dump_hash_extensions.add(:extension_name) { |value| }`
|
|
234
|
+
* since v2.0.3
|
|
235
|
+
* "Value Dump" extensions operate on the values, and nested hashes' values, if any
|
|
236
|
+
* use `::dump_value_extensions.add(:extension_name) { |value| }`
|
|
237
|
+
* since v2.0.2, bugs fixed in v2.0.3
|
|
221
238
|
|
|
222
239
|
#### Example
|
|
223
240
|
|
|
224
|
-
Let's say I want
|
|
225
|
-
while 0 converts to, and stays, a string forever.
|
|
241
|
+
Let's say I want to really smash up my hash and make it more food-like.
|
|
226
242
|
|
|
227
243
|
```ruby
|
|
228
244
|
class MyExtSnakedHash < Hashie::Mash
|
|
229
245
|
include SnakyHash::Snake.new(
|
|
230
246
|
key_type: :symbol, # default :string
|
|
231
|
-
serializer: true,
|
|
247
|
+
serializer: true, # default: false
|
|
232
248
|
)
|
|
233
249
|
end
|
|
234
250
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
key
|
|
243
|
-
end
|
|
244
|
-
end
|
|
245
|
-
else
|
|
246
|
-
value
|
|
251
|
+
# We could swap all values with indexed apples (obliteraating nested data!)
|
|
252
|
+
MyExtSnakedHash.dump_hash_extensions.add(:to_apple) do |value|
|
|
253
|
+
num = 0
|
|
254
|
+
value.transform_values do |_key|
|
|
255
|
+
key = "apple-#{num}"
|
|
256
|
+
num += 1
|
|
257
|
+
key
|
|
247
258
|
end
|
|
248
259
|
end
|
|
249
260
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
261
|
+
# And then when loading the dump we could convert the yum to pear
|
|
262
|
+
MyExtSnakedHash.load_hash_extensions.add(:apple_to_pear) do |value|
|
|
263
|
+
value.transform_keys do |key|
|
|
264
|
+
key.to_s.sub("yum", "pear")
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# We could swap all index numbers "beet-<number>"
|
|
269
|
+
MyExtSnakedHash.dump_value_extensions.add(:to_beet) do |value|
|
|
270
|
+
value.to_s.sub(/(\d+)/) { |match| "beet-#{match[0]}" }
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# And then when loading the dump we could convert beet to corn
|
|
274
|
+
MyExtSnakedHash.load_value_extensions.add(:beet_to_corn) do |value|
|
|
275
|
+
value.to_s.sub("beet", "corn")
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
snake = MyExtSnakedHash.new({"YumBread" => "b", "YumCake" => {"b" => "b"}, "YumBoba" => [1, 2, 3]})
|
|
279
|
+
snake # => {yum_bread: "b", yum_cake: {b: "b"}, yum_boba: [1, 2, 3]}
|
|
280
|
+
snake.yum_bread # => "b"
|
|
281
|
+
snake.yum_cake # => {b: "b"}
|
|
282
|
+
snake.yum_boba # => [1, 2, 3]
|
|
283
|
+
dump = snake.dump
|
|
284
|
+
dump # => "{\"yum_bread\":\"apple-beet-0\",\"yum_cake\":\"apple-beet-1\",\"yum_boba\":\"apple-beet-2\"}"
|
|
285
|
+
hydrated = MyExtSnakedHash.load(dump)
|
|
286
|
+
hydrated # => {pear_bread: "apple-corn-0", pear_cake: "apple-corn-1", pear_boba: "apple-corn-2"}
|
|
262
287
|
```
|
|
263
288
|
|
|
264
289
|
See the specs for more examples.
|
|
265
290
|
|
|
266
|
-
###
|
|
291
|
+
### Bad Ideas
|
|
267
292
|
|
|
268
293
|
I don't recommend using these features... but they exist (for now).
|
|
294
|
+
|
|
295
|
+
<details>
|
|
296
|
+
<summary>Show me what I should *not* do!</summary>
|
|
297
|
+
|
|
269
298
|
You can still access the original un-snaked camel keys.
|
|
270
299
|
And through them you can even use un-snaked camel methods.
|
|
271
300
|
But don't.
|
|
272
301
|
|
|
273
302
|
```ruby
|
|
303
|
+
snake = SnakyHash::StringKeyed["VeryFineHat" => "Feathers"]
|
|
274
304
|
snake.key?("VeryFineHat") # => true
|
|
275
305
|
snake["VeryFineHat"] # => 'Feathers'
|
|
276
306
|
snake.VeryFineHat # => 'Feathers', PLEASE don't do this!!!
|
|
277
307
|
snake["VeryFineHat"] = "pop" # Please don't do this... you'll get a warning, and it works (for now), but no guarantees.
|
|
278
308
|
# WARN -- : You are setting a key that conflicts with a built-in method MySnakedHash#VeryFineHat defined in MySnakedHash. This can cause unexpected behavior when accessing the key as a property. You can still access the key via the #[] method.
|
|
279
309
|
# => "pop"
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Since you are reading this, here's what to do instead.
|
|
313
|
+
|
|
314
|
+
```ruby
|
|
280
315
|
snake.very_fine_hat = "pop" # => 'pop', do this instead!!!
|
|
281
316
|
snake.very_fine_hat # => 'pop'
|
|
282
317
|
snake[:very_fine_hat] = "moose" # => 'moose', or do this instead!!!
|
|
@@ -285,6 +320,8 @@ snake["very_fine_hat"] = "cheese" # => 'cheese', or do this instead!!!
|
|
|
285
320
|
snake.very_fine_hat # => 'cheese'
|
|
286
321
|
```
|
|
287
322
|
|
|
323
|
+
</details>
|
|
324
|
+
|
|
288
325
|
### 🚀 Release Instructions
|
|
289
326
|
|
|
290
327
|
See [CONTRIBUTING.md][🤝contributing].
|
|
@@ -310,8 +347,8 @@ See [CONTRIBUTING.md][🤝contributing] for more detailed instructions.
|
|
|
310
347
|
|
|
311
348
|
### 🪇 Code of Conduct
|
|
312
349
|
|
|
313
|
-
Everyone interacting
|
|
314
|
-
chat rooms and mailing lists
|
|
350
|
+
Everyone interacting with this project's codebases, issue trackers,
|
|
351
|
+
chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct].
|
|
315
352
|
|
|
316
353
|
## 🌈 Contributors
|
|
317
354
|
|
|
@@ -378,7 +415,7 @@ See [LICENSE.txt][📄license] for the official [Copyright Notice][📄copyright
|
|
|
378
415
|
|
|
379
416
|
<ul>
|
|
380
417
|
<li>
|
|
381
|
-
2022, 2025 Peter H. Boling, of
|
|
418
|
+
2022, 2025-2026 Peter H. Boling, of
|
|
382
419
|
<a href="https://railsbling.com">
|
|
383
420
|
RailsBling.com
|
|
384
421
|
<picture>
|
|
@@ -452,8 +489,6 @@ or one of the others at the head of this README.
|
|
|
452
489
|
[📜wiki-img]: https://img.shields.io/badge/wiki-examples-943CD2.svg?style=for-the-badge&logo=Wiki&logoColor=white
|
|
453
490
|
[👽dl-rank]: https://rubygems.org/gems/snaky_hash
|
|
454
491
|
[👽dl-ranki]: https://img.shields.io/gem/rd/snaky_hash.svg
|
|
455
|
-
[👽oss-help]: https://www.codetriage.com/oauth-xx/snaky_hash
|
|
456
|
-
[👽oss-helpi]: https://www.codetriage.com/oauth-xx/snaky_hash/badges/users.svg
|
|
457
492
|
[👽version]: https://rubygems.org/gems/snaky_hash
|
|
458
493
|
[👽versioni]: https://img.shields.io/gem/v/snaky_hash.svg
|
|
459
494
|
[🔑qlty-mnt]: https://qlty.sh/gh/oauth-xx/projects/snaky_hash
|
|
@@ -464,8 +499,6 @@ or one of the others at the head of this README.
|
|
|
464
499
|
[🔑codecovi♻️]: https://codecov.io/gh/oauth-xx/snaky_hash/graph/badge.svg?token=XqaZixl4ss
|
|
465
500
|
[🔑coveralls]: https://coveralls.io/github/oauth-xx/snaky_hash?branch=main
|
|
466
501
|
[🔑coveralls-img]: https://coveralls.io/repos/github/oauth-xx/snaky_hash/badge.svg?branch=main
|
|
467
|
-
[🔑depfu]: https://depfu.com/github/oauth-xx/snaky_hash?project_id=63073
|
|
468
|
-
[🔑depfui♻️]: https://badges.depfu.com/badges/7019dcf43672ba8c0e77e7fdd1063398/count.svg
|
|
469
502
|
[🖐codeQL]: https://github.com/oauth-xx/snaky_hash/security/code-scanning
|
|
470
503
|
[🖐codeQL-img]: https://github.com/oauth-xx/snaky_hash/actions/workflows/codeql-analysis.yml/badge.svg
|
|
471
504
|
[🚎1-an-wf]: https://github.com/oauth-xx/snaky_hash/actions/workflows/ancient.yml
|
|
@@ -553,7 +586,7 @@ or one of the others at the head of this README.
|
|
|
553
586
|
[📌gitmoji]:https://gitmoji.dev
|
|
554
587
|
[📌gitmoji-img]:https://img.shields.io/badge/gitmoji_commits-%20😜%20😍-34495e.svg?style=flat-square
|
|
555
588
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
556
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.
|
|
589
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.132-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
557
590
|
[🔐security]: SECURITY.md
|
|
558
591
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
559
592
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
|
@@ -581,4 +614,4 @@ CodeCov currently fails to parse the coverage upload.
|
|
|
581
614
|
|
|
582
615
|
[![Coverage Graph][🔑codecov-g♻️]][🔑codecov]
|
|
583
616
|
|
|
584
|
-
</details>
|
|
617
|
+
</details>
|
data/REEK
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
spec/snaky_hash/snake_spec.rb -- 1 warning:
|
|
2
|
+
[4]:IrresponsibleModule: TheSnakedHash has no descriptive comment [https://github.com/troessner/reek/blob/v6.5.0/docs/Irresponsible-Module.md]
|
|
3
|
+
lib/snaky_hash/extensions.rb -- 1 warning:
|
|
4
|
+
[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]
|
|
5
|
+
lib/snaky_hash/serializer.rb -- 7 warnings:
|
|
6
|
+
[132]:NilCheck: SnakyHash::Serializer#blank? performs a nil-check [https://github.com/troessner/reek/blob/v6.5.0/docs/Nil-Check.md]
|
|
7
|
+
[180]:TooManyStatements: SnakyHash::Serializer#load_hash has approx 6 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md]
|
|
8
|
+
[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]
|
|
9
|
+
[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]
|
|
10
|
+
[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]
|
|
11
|
+
[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]
|
|
12
|
+
[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]
|
|
13
|
+
lib/snaky_hash/snake.rb -- 11 warnings:
|
|
14
|
+
[30]:BooleanParameter: SnakyHash::Snake#initialize has boolean parameter 'serializer' [https://github.com/troessner/reek/blob/v6.5.0/docs/Boolean-Parameter.md]
|
|
15
|
+
[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]
|
|
16
|
+
[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]
|
|
17
|
+
[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]
|
|
18
|
+
[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]
|
|
19
|
+
[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]
|
|
20
|
+
[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]
|
|
21
|
+
[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]
|
|
22
|
+
[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]
|
|
23
|
+
[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]
|
|
24
|
+
[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]
|
|
25
|
+
.yard_gfm_support.rb -- 1 warning:
|
|
26
|
+
[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]
|
|
27
|
+
21 total warnings
|
|
File without changes
|
|
@@ -21,9 +21,10 @@ module SnakyHash
|
|
|
21
21
|
def extended(base)
|
|
22
22
|
extended_module = Modulizer.to_extended_mod
|
|
23
23
|
base.extend(extended_module)
|
|
24
|
+
base.include(ConvenienceInstanceMethods)
|
|
24
25
|
# :nocov:
|
|
25
26
|
# This will be run in CI on Ruby 2.3, but we only collect coverage from current Ruby
|
|
26
|
-
unless base.
|
|
27
|
+
unless base.method_defined?(:transform_values)
|
|
27
28
|
base.include(BackportedInstanceMethods)
|
|
28
29
|
end
|
|
29
30
|
# :nocov:
|
|
@@ -45,8 +46,7 @@ module SnakyHash
|
|
|
45
46
|
# @return [Hash] deserialized hash object
|
|
46
47
|
def load(raw_hash)
|
|
47
48
|
hash = JSON.parse(presence(raw_hash) || "{}")
|
|
48
|
-
|
|
49
|
-
new(hash)
|
|
49
|
+
load_hash(new(hash))
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
# Internal module for generating extension methods
|
|
@@ -57,17 +57,29 @@ module SnakyHash
|
|
|
57
57
|
# @return [Module] a module containing extension management methods
|
|
58
58
|
def to_extended_mod
|
|
59
59
|
Module.new do
|
|
60
|
+
define_method :load_value_extensions do
|
|
61
|
+
@load_value_extensions ||= Extensions.new
|
|
62
|
+
end
|
|
63
|
+
|
|
60
64
|
define_method :load_extensions do
|
|
61
|
-
|
|
65
|
+
load_value_extensions
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
define_method :dump_value_extensions do
|
|
69
|
+
@dump_value_extensions ||= Extensions.new
|
|
62
70
|
end
|
|
63
71
|
|
|
64
72
|
define_method :dump_extensions do
|
|
65
|
-
|
|
73
|
+
dump_value_extensions
|
|
66
74
|
end
|
|
67
75
|
|
|
68
76
|
define_method :load_hash_extensions do
|
|
69
77
|
@load_hash_extensions ||= Extensions.new
|
|
70
78
|
end
|
|
79
|
+
|
|
80
|
+
define_method :dump_hash_extensions do
|
|
81
|
+
@dump_hash_extensions ||= Extensions.new
|
|
82
|
+
end
|
|
71
83
|
end
|
|
72
84
|
end
|
|
73
85
|
end
|
|
@@ -96,6 +108,20 @@ module SnakyHash
|
|
|
96
108
|
# :nocov:
|
|
97
109
|
end
|
|
98
110
|
|
|
111
|
+
# Provides convenient instance methods for serialization
|
|
112
|
+
#
|
|
113
|
+
# @example Using convenience methods
|
|
114
|
+
# hash = MyHash.new(key: 'value')
|
|
115
|
+
# json = hash.dump #=> '{"key":"value"}'
|
|
116
|
+
module ConvenienceInstanceMethods
|
|
117
|
+
# Serializes the current hash instance to JSON
|
|
118
|
+
#
|
|
119
|
+
# @return [String] JSON string representation of the hash
|
|
120
|
+
def dump
|
|
121
|
+
self.class.dump(self)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
99
125
|
private
|
|
100
126
|
|
|
101
127
|
# Checks if a value is blank (nil or empty string)
|
|
@@ -117,15 +143,14 @@ module SnakyHash
|
|
|
117
143
|
blank?(value) ? nil : value
|
|
118
144
|
end
|
|
119
145
|
|
|
120
|
-
# Processes a hash for dumping, transforming its values
|
|
146
|
+
# Processes a hash for dumping, transforming its keys and/or values
|
|
121
147
|
#
|
|
122
148
|
# @param hash [Hash] hash to process
|
|
123
149
|
# @return [Hash] processed hash with transformed values
|
|
124
150
|
def dump_hash(hash)
|
|
125
|
-
|
|
151
|
+
dump_hash_extensions.run(self[hash]).transform_values do |value|
|
|
126
152
|
dump_value(value)
|
|
127
153
|
end
|
|
128
|
-
hash.reject { |_, v| blank?(v) }
|
|
129
154
|
end
|
|
130
155
|
|
|
131
156
|
# Processes a single value for dumping
|
|
@@ -134,7 +159,7 @@ module SnakyHash
|
|
|
134
159
|
# @return [Object, nil] processed value
|
|
135
160
|
def dump_value(value)
|
|
136
161
|
if blank?(value)
|
|
137
|
-
return
|
|
162
|
+
return value
|
|
138
163
|
end
|
|
139
164
|
|
|
140
165
|
if value.is_a?(::Hash)
|
|
@@ -148,28 +173,46 @@ module SnakyHash
|
|
|
148
173
|
dump_extensions.run(value)
|
|
149
174
|
end
|
|
150
175
|
|
|
151
|
-
# Processes a hash for loading, transforming its values
|
|
176
|
+
# Processes a hash for loading, transforming its keys and/or values
|
|
152
177
|
#
|
|
153
178
|
# @param hash [Hash] hash to process
|
|
154
179
|
# @return [Hash] processed hash with transformed values
|
|
155
180
|
def load_hash(hash)
|
|
156
|
-
|
|
181
|
+
ran = load_hash_extensions.run(self[hash])
|
|
182
|
+
return load_value(ran) unless ran.is_a?(::Hash)
|
|
183
|
+
|
|
184
|
+
res = self[ran].transform_values do |value|
|
|
157
185
|
load_value(value)
|
|
158
186
|
end
|
|
187
|
+
|
|
188
|
+
# TODO: Drop this hack when dropping support for Ruby 2.6
|
|
189
|
+
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7")
|
|
190
|
+
res
|
|
191
|
+
else
|
|
192
|
+
# :nocov:
|
|
193
|
+
# In Ruby <= 2.6 Hash#transform_values returned a new vanilla Hash,
|
|
194
|
+
# rather than a hash of the class being transformed.
|
|
195
|
+
self[res]
|
|
196
|
+
# :nocov:
|
|
197
|
+
end
|
|
159
198
|
end
|
|
160
199
|
|
|
161
200
|
# Processes a single value for loading
|
|
162
201
|
#
|
|
163
202
|
# @param value [Object] value to process
|
|
164
|
-
# @return [Object] processed value
|
|
203
|
+
# @return [Object, nil] processed value
|
|
165
204
|
def load_value(value)
|
|
205
|
+
if blank?(value)
|
|
206
|
+
return value
|
|
207
|
+
end
|
|
208
|
+
|
|
166
209
|
if value.is_a?(::Hash)
|
|
167
|
-
|
|
168
|
-
return load_hash(new(hash)) if hash.is_a?(::Hash)
|
|
169
|
-
return load_value(hash)
|
|
210
|
+
return load_hash(value)
|
|
170
211
|
end
|
|
171
212
|
|
|
172
|
-
|
|
213
|
+
if value.is_a?(::Array)
|
|
214
|
+
return value.map { |v| load_value(v) }.compact
|
|
215
|
+
end
|
|
173
216
|
|
|
174
217
|
load_extensions.run(value)
|
|
175
218
|
end
|
data/lib/snaky_hash/snake.rb
CHANGED
|
@@ -57,7 +57,12 @@ module SnakyHash
|
|
|
57
57
|
Module.new do
|
|
58
58
|
case key_type
|
|
59
59
|
when :string then
|
|
60
|
-
# Converts a key to a string if
|
|
60
|
+
# Converts a key to a string if it is symbolizable, after underscoring
|
|
61
|
+
#
|
|
62
|
+
# @note checks for to_sym instead of to_s, because nearly everything responds_to?(:to_s)
|
|
63
|
+
# so respond_to?(:to_s) isn't very useful as a test, and would result in symbolizing integers
|
|
64
|
+
# amd it also provides parity between the :symbol behavior, and the :string behavior,
|
|
65
|
+
# regarding which keys get converted for a given version of Ruby.
|
|
61
66
|
#
|
|
62
67
|
# @param key [Object] the key to convert
|
|
63
68
|
# @return [String, Object] the converted key or original if not convertible
|
|
File without changes
|
|
File without changes
|
data/lib/snaky_hash/version.rb
CHANGED
data/lib/snaky_hash.rb
CHANGED
|
File without changes
|
data/sig/snaky_hash.rbs
ADDED
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: snaky_hash
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0.
|
|
4
|
+
version: 2.0.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter Boling
|
|
@@ -35,7 +35,7 @@ cert_chain:
|
|
|
35
35
|
DVjBtqT23eugOqQ73umLcYDZkc36vnqGxUBSsXrzY9pzV5gGr2I8YUxMqf6ATrZt
|
|
36
36
|
L9nRqA==
|
|
37
37
|
-----END CERTIFICATE-----
|
|
38
|
-
date:
|
|
38
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
39
39
|
dependencies:
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: hashie
|
|
@@ -78,25 +78,33 @@ dependencies:
|
|
|
78
78
|
- !ruby/object:Gem::Version
|
|
79
79
|
version: '3'
|
|
80
80
|
- !ruby/object:Gem::Dependency
|
|
81
|
-
name:
|
|
81
|
+
name: kettle-dev
|
|
82
82
|
requirement: !ruby/object:Gem::Requirement
|
|
83
83
|
requirements:
|
|
84
84
|
- - "~>"
|
|
85
85
|
- !ruby/object:Gem::Version
|
|
86
|
-
version: '
|
|
87
|
-
- - ">="
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: 3.25.1
|
|
86
|
+
version: '2.0'
|
|
90
87
|
type: :development
|
|
91
88
|
prerelease: false
|
|
92
89
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
90
|
requirements:
|
|
94
91
|
- - "~>"
|
|
95
92
|
- !ruby/object:Gem::Version
|
|
96
|
-
version: '
|
|
97
|
-
|
|
93
|
+
version: '2.0'
|
|
94
|
+
- !ruby/object:Gem::Dependency
|
|
95
|
+
name: bundler-audit
|
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
|
97
|
+
requirements:
|
|
98
|
+
- - "~>"
|
|
98
99
|
- !ruby/object:Gem::Version
|
|
99
|
-
version:
|
|
100
|
+
version: 0.9.2
|
|
101
|
+
type: :development
|
|
102
|
+
prerelease: false
|
|
103
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
104
|
+
requirements:
|
|
105
|
+
- - "~>"
|
|
106
|
+
- !ruby/object:Gem::Version
|
|
107
|
+
version: 0.9.2
|
|
100
108
|
- !ruby/object:Gem::Dependency
|
|
101
109
|
name: rake
|
|
102
110
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -112,21 +120,47 @@ dependencies:
|
|
|
112
120
|
- !ruby/object:Gem::Version
|
|
113
121
|
version: '13.0'
|
|
114
122
|
- !ruby/object:Gem::Dependency
|
|
115
|
-
name:
|
|
123
|
+
name: require_bench
|
|
124
|
+
requirement: !ruby/object:Gem::Requirement
|
|
125
|
+
requirements:
|
|
126
|
+
- - "~>"
|
|
127
|
+
- !ruby/object:Gem::Version
|
|
128
|
+
version: '1.0'
|
|
129
|
+
- - ">="
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: 1.0.4
|
|
132
|
+
type: :development
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - "~>"
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '1.0'
|
|
139
|
+
- - ">="
|
|
140
|
+
- !ruby/object:Gem::Version
|
|
141
|
+
version: 1.0.4
|
|
142
|
+
- !ruby/object:Gem::Dependency
|
|
143
|
+
name: appraisal2
|
|
116
144
|
requirement: !ruby/object:Gem::Requirement
|
|
117
145
|
requirements:
|
|
118
146
|
- - "~>"
|
|
119
147
|
- !ruby/object:Gem::Version
|
|
120
|
-
version: '3.
|
|
148
|
+
version: '3.0'
|
|
149
|
+
- - ">="
|
|
150
|
+
- !ruby/object:Gem::Version
|
|
151
|
+
version: 3.0.6
|
|
121
152
|
type: :development
|
|
122
153
|
prerelease: false
|
|
123
154
|
version_requirements: !ruby/object:Gem::Requirement
|
|
124
155
|
requirements:
|
|
125
156
|
- - "~>"
|
|
126
157
|
- !ruby/object:Gem::Version
|
|
127
|
-
version: '3.
|
|
158
|
+
version: '3.0'
|
|
159
|
+
- - ">="
|
|
160
|
+
- !ruby/object:Gem::Version
|
|
161
|
+
version: 3.0.6
|
|
128
162
|
- !ruby/object:Gem::Dependency
|
|
129
|
-
name:
|
|
163
|
+
name: kettle-test
|
|
130
164
|
requirement: !ruby/object:Gem::Requirement
|
|
131
165
|
requirements:
|
|
132
166
|
- - "~>"
|
|
@@ -134,7 +168,7 @@ dependencies:
|
|
|
134
168
|
version: '1.0'
|
|
135
169
|
- - ">="
|
|
136
170
|
- !ruby/object:Gem::Version
|
|
137
|
-
version: 1.0.
|
|
171
|
+
version: 1.0.10
|
|
138
172
|
type: :development
|
|
139
173
|
prerelease: false
|
|
140
174
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -144,34 +178,51 @@ dependencies:
|
|
|
144
178
|
version: '1.0'
|
|
145
179
|
- - ">="
|
|
146
180
|
- !ruby/object:Gem::Version
|
|
147
|
-
version: 1.0.
|
|
181
|
+
version: 1.0.10
|
|
148
182
|
- !ruby/object:Gem::Dependency
|
|
149
|
-
name:
|
|
183
|
+
name: ruby-progressbar
|
|
150
184
|
requirement: !ruby/object:Gem::Requirement
|
|
151
185
|
requirements:
|
|
152
186
|
- - "~>"
|
|
153
187
|
- !ruby/object:Gem::Version
|
|
154
|
-
version: '
|
|
188
|
+
version: '1.13'
|
|
189
|
+
type: :development
|
|
190
|
+
prerelease: false
|
|
191
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
192
|
+
requirements:
|
|
193
|
+
- - "~>"
|
|
194
|
+
- !ruby/object:Gem::Version
|
|
195
|
+
version: '1.13'
|
|
196
|
+
- !ruby/object:Gem::Dependency
|
|
197
|
+
name: stone_checksums
|
|
198
|
+
requirement: !ruby/object:Gem::Requirement
|
|
199
|
+
requirements:
|
|
200
|
+
- - "~>"
|
|
201
|
+
- !ruby/object:Gem::Version
|
|
202
|
+
version: '1.0'
|
|
155
203
|
- - ">="
|
|
156
204
|
- !ruby/object:Gem::Version
|
|
157
|
-
version: 0.
|
|
205
|
+
version: 1.0.3
|
|
158
206
|
type: :development
|
|
159
207
|
prerelease: false
|
|
160
208
|
version_requirements: !ruby/object:Gem::Requirement
|
|
161
209
|
requirements:
|
|
162
210
|
- - "~>"
|
|
163
211
|
- !ruby/object:Gem::Version
|
|
164
|
-
version: '0
|
|
212
|
+
version: '1.0'
|
|
165
213
|
- - ">="
|
|
166
214
|
- !ruby/object:Gem::Version
|
|
167
|
-
version: 0.
|
|
215
|
+
version: 1.0.3
|
|
168
216
|
- !ruby/object:Gem::Dependency
|
|
169
|
-
name:
|
|
217
|
+
name: gitmoji-regex
|
|
170
218
|
requirement: !ruby/object:Gem::Requirement
|
|
171
219
|
requirements:
|
|
172
220
|
- - "~>"
|
|
173
221
|
- !ruby/object:Gem::Version
|
|
174
222
|
version: '1.0'
|
|
223
|
+
- - ">="
|
|
224
|
+
- !ruby/object:Gem::Version
|
|
225
|
+
version: 1.0.3
|
|
175
226
|
type: :development
|
|
176
227
|
prerelease: false
|
|
177
228
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -179,25 +230,54 @@ dependencies:
|
|
|
179
230
|
- - "~>"
|
|
180
231
|
- !ruby/object:Gem::Version
|
|
181
232
|
version: '1.0'
|
|
182
|
-
|
|
233
|
+
- - ">="
|
|
234
|
+
- !ruby/object:Gem::Version
|
|
235
|
+
version: 1.0.3
|
|
236
|
+
- !ruby/object:Gem::Dependency
|
|
237
|
+
name: backports
|
|
238
|
+
requirement: !ruby/object:Gem::Requirement
|
|
239
|
+
requirements:
|
|
240
|
+
- - "~>"
|
|
241
|
+
- !ruby/object:Gem::Version
|
|
242
|
+
version: '3.25'
|
|
243
|
+
- - ">="
|
|
244
|
+
- !ruby/object:Gem::Version
|
|
245
|
+
version: 3.25.1
|
|
246
|
+
type: :development
|
|
247
|
+
prerelease: false
|
|
248
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
249
|
+
requirements:
|
|
250
|
+
- - "~>"
|
|
251
|
+
- !ruby/object:Gem::Version
|
|
252
|
+
version: '3.25'
|
|
253
|
+
- - ">="
|
|
254
|
+
- !ruby/object:Gem::Version
|
|
255
|
+
version: 3.25.1
|
|
256
|
+
description: "\U0001F40D A Hashie::Mash joint to make #snakelife better"
|
|
183
257
|
email:
|
|
184
|
-
-
|
|
258
|
+
- floss@galtzo.com
|
|
185
259
|
- oauth-ruby@googlegroups.com
|
|
186
260
|
executables: []
|
|
187
261
|
extensions: []
|
|
188
262
|
extra_rdoc_files:
|
|
189
263
|
- CHANGELOG.md
|
|
264
|
+
- CITATION.cff
|
|
190
265
|
- CODE_OF_CONDUCT.md
|
|
191
266
|
- CONTRIBUTING.md
|
|
267
|
+
- IRP.md
|
|
192
268
|
- LICENSE.txt
|
|
193
269
|
- README.md
|
|
270
|
+
- REEK
|
|
194
271
|
- SECURITY.md
|
|
195
272
|
files:
|
|
196
273
|
- CHANGELOG.md
|
|
274
|
+
- CITATION.cff
|
|
197
275
|
- CODE_OF_CONDUCT.md
|
|
198
276
|
- CONTRIBUTING.md
|
|
277
|
+
- IRP.md
|
|
199
278
|
- LICENSE.txt
|
|
200
279
|
- README.md
|
|
280
|
+
- REEK
|
|
201
281
|
- SECURITY.md
|
|
202
282
|
- lib/snaky_hash.rb
|
|
203
283
|
- lib/snaky_hash/extensions.rb
|
|
@@ -206,30 +286,29 @@ files:
|
|
|
206
286
|
- lib/snaky_hash/string_keyed.rb
|
|
207
287
|
- lib/snaky_hash/symbol_keyed.rb
|
|
208
288
|
- lib/snaky_hash/version.rb
|
|
209
|
-
|
|
289
|
+
- sig/snaky_hash.rbs
|
|
290
|
+
homepage: https://github.com/ruby-oauth/snaky_hash
|
|
210
291
|
licenses:
|
|
211
292
|
- MIT
|
|
212
293
|
metadata:
|
|
213
294
|
homepage_uri: https://snaky-hash.galtzo.com/
|
|
214
|
-
source_code_uri: https://github.com/oauth
|
|
215
|
-
changelog_uri: https://
|
|
216
|
-
bug_tracker_uri: https://
|
|
217
|
-
documentation_uri: https://www.rubydoc.info/gems/snaky_hash/2.0.
|
|
218
|
-
wiki_uri: https://gitlab.com/oauth-xx/snaky_hash/-/wiki
|
|
295
|
+
source_code_uri: https://github.com/ruby-oauth/snaky_hash/tree/v2.0.4
|
|
296
|
+
changelog_uri: https://github.com/ruby-oauth/snaky_hash/blob/v2.0.4/CHANGELOG.md
|
|
297
|
+
bug_tracker_uri: https://github.com/ruby-oauth/snaky_hash/issues
|
|
298
|
+
documentation_uri: https://www.rubydoc.info/gems/snaky_hash/2.0.4
|
|
219
299
|
mailing_list_uri: https://groups.google.com/g/oauth-ruby
|
|
220
|
-
funding_uri: https://
|
|
300
|
+
funding_uri: https://github.com/sponsors/pboling
|
|
301
|
+
wiki_uri: https://gitlab.com/ruby-oauth/snaky_hash/-/wiki
|
|
221
302
|
news_uri: https://www.railsbling.com/tags/snaky_hash
|
|
303
|
+
discord_uri: https://discord.gg/3qme4XHNKN
|
|
222
304
|
rubygems_mfa_required: 'true'
|
|
223
305
|
rdoc_options:
|
|
224
306
|
- "--title"
|
|
225
|
-
- snaky_hash - A very snaky hash
|
|
307
|
+
- "snaky_hash - \U0001F40D A very snaky hash"
|
|
226
308
|
- "--main"
|
|
227
|
-
- CHANGELOG.md
|
|
228
|
-
- CODE_OF_CONDUCT.md
|
|
229
|
-
- CONTRIBUTING.md
|
|
230
|
-
- LICENSE.txt
|
|
231
309
|
- README.md
|
|
232
|
-
-
|
|
310
|
+
- "--exclude"
|
|
311
|
+
- "^sig/"
|
|
233
312
|
- "--line-numbers"
|
|
234
313
|
- "--inline-source"
|
|
235
314
|
- "--quiet"
|
|
@@ -246,7 +325,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
246
325
|
- !ruby/object:Gem::Version
|
|
247
326
|
version: '0'
|
|
248
327
|
requirements: []
|
|
249
|
-
rubygems_version:
|
|
328
|
+
rubygems_version: 4.0.11
|
|
250
329
|
specification_version: 4
|
|
251
|
-
summary: A very snaky hash
|
|
330
|
+
summary: "\U0001F40D A very snaky hash"
|
|
252
331
|
test_files: []
|
metadata.gz.sig
CHANGED
|
Binary file
|