kettle-wash 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6abf1d5cf0d6d6fec800e3081e6c98583d4189bc7e6165b377412613977a5935
4
+ data.tar.gz: 751642b7fd4d5faa7dff627938ef0499aff89c7b2d6e26e4173f8373c34c1eff
5
+ SHA512:
6
+ metadata.gz: a3abe5b4103a4b95a662a6028f0266d2eb3422c2cd693351fde6a5017e0309aea1c1121f47aac9476ad986845b0768a6cbaeb56ccf3c34a48eae393891ee080b
7
+ data.tar.gz: 62e9b6174cf3476182e3f0c00ab409259f38102861d23087c6bc5f237b10b6dc52b13d397003d56d361ad5fd39e1d7a50ac491c3e1271dfba468db9fab7369c7
checksums.yaml.gz.sig ADDED
Binary file
data/CHANGELOG.md ADDED
@@ -0,0 +1,76 @@
1
+ # Changelog
2
+
3
+ [![SemVer 2.0.0][📌semver-img]][📌semver] [![Keep-A-Changelog 1.0.0][📗keep-changelog-img]][📗keep-changelog]
4
+
5
+ All notable changes to this project will be documented in this file.
6
+
7
+ The format is based on [Keep a Changelog][📗keep-changelog],
8
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
9
+ and [yes][📌major-versions-not-sacred], platform and engine support are part of the [public API][📌semver-breaking].
10
+ Please file a bug if you notice a violation of semantic versioning.
11
+
12
+ [📌semver]: https://semver.org/spec/v2.0.0.html
13
+ [📌semver-img]: https://img.shields.io/badge/semver-2.0.0-FFDD67.svg?style=flat
14
+ [📌semver-breaking]: https://github.com/semver/semver/issues/716#issuecomment-869336139
15
+ [📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html
16
+ [📗keep-changelog]: https://keepachangelog.com/en/1.0.0/
17
+ [📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-FFDD67.svg?style=flat
18
+
19
+ ## [Unreleased]
20
+
21
+ ### Added
22
+
23
+ ### Changed
24
+
25
+ ### Deprecated
26
+
27
+ ### Removed
28
+
29
+ ### Fixed
30
+
31
+ ### Security
32
+
33
+ ## [0.1.0] - 2026-07-19
34
+
35
+ - TAG: [v0.1.0][0.1.0t]
36
+ - COVERAGE: 100.00% -- 63/63 lines in 2 files
37
+ - BRANCH COVERAGE: 86.36% -- 19/22 branches in 2 files
38
+ - 20.00% documented
39
+ - Initial release
40
+
41
+ ### Added
42
+
43
+ - Added support for JRuby 10.1 and TruffleRuby 34.0.
44
+ - Added public constant deletion and reset helpers for test and reload workflows.
45
+ - Added `Kettle::Wash::Change`, an include-based helper for modules that need
46
+ `delete_const` and `reset_const` singleton methods.
47
+ - Added `Kettle::Wash.install` and `Kettle::Wash.validate!` for gems that
48
+ declare washable constant contracts without loading `kettle-wash` at runtime.
49
+
50
+ ### Changed
51
+
52
+ - Documented the primary coverage use case for reloading constants whose values
53
+ are conditionally derived from `ENV`.
54
+ - Added RSpec usage documentation with a link to the `kettle-soup-cover`
55
+ constant reset specs.
56
+ - Updated the RSpec usage example to use `rspec-stubbed_env` instead of
57
+ mutating the real process environment.
58
+
59
+ - Retemplated project metadata and CI/development automation with `kettle-jem` v7.0.0.
60
+
61
+ - kettle-jem-template-20260716-001 - Shim gemspec manifests now include
62
+ `LICENSE.md` instead of nonexistent `LICENSE.txt`.
63
+ - kettle-jem-template-20260716-002 - Generated gemspec manifests now ship fewer
64
+ repository-only files by default to reduce downstream distro packaging churn.
65
+
66
+ ### Fixed
67
+
68
+ - Corrected OpenCollective funding metadata to use the `kettle-dev` collective.
69
+ - Updated generated project metadata links to use the migrated `kettle-dev`
70
+ GitHub organization.
71
+
72
+ - Package configured license files in gem release file lists.
73
+
74
+ [Unreleased]: https://github.com/kettle-dev/kettle-wash/compare/v0.1.0...HEAD
75
+ [0.1.0]: https://github.com/kettle-dev/kettle-wash/compare/9819b1c14789cdd16131ddf8f131a436f702fd4e...v0.1.0
76
+ [0.1.0t]: https://github.com/kettle-dev/kettle-wash/releases/tag/v0.1.0
data/LICENSE.md ADDED
@@ -0,0 +1,23 @@
1
+ # License
2
+
3
+ This project is made available under the following licenses.
4
+ Choose the option that best fits your use case:
5
+
6
+ - [AGPL-3.0-only](AGPL-3.0-only.md)
7
+ - [PolyForm-Small-Business-1.0.0](PolyForm-Small-Business-1.0.0.md)
8
+ - [Big-Time-Public-License](Big-Time-Public-License.md)
9
+
10
+ ## Use-case guide
11
+
12
+ | Use case | License |
13
+ |---|---|
14
+ | Copy-left open source | [AGPL-3.0-only](AGPL-3.0-only.md) |
15
+ | Non-commercial (research, education, personal use) | [PolyForm-Small-Business-1.0.0](PolyForm-Small-Business-1.0.0.md) or [Big-Time-Public-License](Big-Time-Public-License.md) |
16
+ | Small business commercial | [PolyForm-Small-Business-1.0.0](PolyForm-Small-Business-1.0.0.md) or [Big-Time-Public-License](Big-Time-Public-License.md) |
17
+ | Larger business commercial | [Big-Time-Public-License](Big-Time-Public-License.md) or [contact us](mailto:floss@galtzo.com) for a custom license |
18
+
19
+ If none of the above licenses fit your use case, please [contact us](mailto:floss@galtzo.com) to discuss a custom commercial license.
20
+
21
+ ## Copyright Notice
22
+
23
+ - Required Notice: Copyright (c) 2026 Peter H. Boling
data/README.md ADDED
@@ -0,0 +1,539 @@
1
+ <a href="https://github.com/kettle-dev"><img alt="kettle-dev Logo by Aboling0, CC BY-SA 4.0" src="https://logos.galtzo.com/assets/images/kettle-dev/avatar-128px.svg" width="14%" align="right"/></a>
2
+
3
+ # 🚿 Kettle::Wash
4
+
5
+ [![Version][👽versioni]][👽version] [![GitHub tag (latest SemVer)][⛳️tag-img]][⛳️tag] [![License: AGPL-3.0-only OR PolyForm-Small-Business-1.0.0 OR LicenseRef-Big-Time-Public-License][📄license-img]][📄license] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![CodeCov Test Coverage][🏀codecovi]][🏀codecov] [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls] [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov] [![QLTY Maintainability][🏀qlty-mnti]][🏀qlty-mnt] [![CI Heads][🚎3-hd-wfi]][🚎3-hd-wf] [![CI Runtime Dependencies @ HEAD][🚎12-crh-wfi]][🚎12-crh-wf] [![CI Current][🚎11-c-wfi]][🚎11-c-wf] [![CI Truffle Ruby][🚎9-t-wfi]][🚎9-t-wf] [![CI JRuby][🚎10-j-wfi]][🚎10-j-wf] [![Deps Locked][🚎13-🔒️-wfi]][🚎13-🔒️-wf] [![Deps Unlocked][🚎14-🔓️-wfi]][🚎14-🔓️-wf] [![CI Test Coverage][🚎2-cov-wfi]][🚎2-cov-wf] [![CI Style][🚎5-st-wfi]][🚎5-st-wf]
6
+
7
+ `if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know][✉️discord-invite], as I may have missed the [discord notification][✉️discord-invite].
8
+
9
+ ---
10
+
11
+ `if ci_badges.map(&:color).all? { it == "green"}` 👇️ send money so I can do more of this. FLOSS maintenance is now my full-time job.
12
+
13
+ [![OpenCollective Backers][🖇osc-backers-i]][🖇osc-backers] [![OpenCollective Sponsors][🖇osc-sponsors-i]][🖇osc-sponsors] [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Donate on PayPal][🖇paypal-img]][🖇paypal] [![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate at ko-fi.com][🖇kofi-img]][🖇kofi]
14
+
15
+ <details markdown="1">
16
+ <summary>👣 How will this project approach the September 2025 hostile takeover of RubyGems? 🚑️</summary>
17
+
18
+ I've summarized my thoughts in [this blog post](https://dev.to/galtzo/hostile-takeover-of-rubygems-my-thoughts-5hlo).
19
+
20
+ </details>
21
+
22
+ ## 🌻 Synopsis <a href="https://discord.gg/3qme4XHNKN"><img alt="Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0" src="https://logos.galtzo.com/assets/images/galtzo-floss/avatar-128px.svg" width="8%" align="right"/></a> <a href="https://ruby-toolbox.com"><img alt="ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5" src="https://logos.galtzo.com/assets/images/ruby-lang/avatar-128px.svg" width="8%" align="right"/></a>
23
+
24
+ `kettle-wash` is for gems that define runtime behavior in constants, especially
25
+ constants whose values are conditionally derived from `ENV`.
26
+
27
+ Ruby constants are usually loaded once. That is a problem for test suites that
28
+ need to prove every line and branch of a constant definition file, because a
29
+ second example cannot naturally re-run:
30
+
31
+ ```ruby
32
+ DO_COV = ENV.fetch("K_SOUP_COV_DO", "false").casecmp?("true")
33
+ COVERAGE_DIR = ENV.fetch("K_SOUP_COV_DIR", "coverage")
34
+ ```
35
+
36
+ `kettle-wash` gives those constant-owning modules a small reset API. Specs can
37
+ delete the declared constants, mutate `ENV`, reload the source file, and then
38
+ assert the alternate branch. This lets coverage tools see the real constant
39
+ definition lines and branches execute, instead of forcing projects to choose
40
+ between accurate coverage and constant-backed configuration.
41
+
42
+ ## 💡 Info you can shake a stick at
43
+
44
+ | Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |
45
+ |-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
46
+ | Works with JRuby | [![JRuby 10.0 Compat][💎jruby-10.0i]][🚎jruby-10.0-wf] [![JRuby current Compat][💎jruby-c-i]][🚎10-j-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf]|
47
+ | Works with Truffle Ruby | [![Truffle Ruby 24.2 Compat][💎truby-24.2i]][🚎truby-24.2-wf] [![Truffle Ruby 25.0 Compat][💎truby-25.0i]][🚎truby-25.0-wf] [![Truffle Ruby 33.0 Compat][💎truby-33.0i]][🚎truby-33.0-wf] [![Truffle Ruby current Compat][💎truby-c-i]][🚎9-t-wf] [![Truffle Ruby HEAD Compat][💎truby-headi]][🚎3-hd-wf]|
48
+ | Works with MRI Ruby 4 | [![Ruby current Compat][💎ruby-c-i]][🚎11-c-wf] [![Ruby HEAD Compat][💎ruby-headi]][🚎3-hd-wf]|
49
+ | Works with MRI Ruby 3 | [![Ruby 3.2 Compat][💎ruby-3.2i]][🚎ruby-3.2-wf] [![Ruby 3.3 Compat][💎ruby-3.3i]][🚎ruby-3.3-wf] [![Ruby 3.4 Compat][💎ruby-3.4i]][🚎ruby-3.4-wf]|
50
+ | Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork] [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor] |
51
+ | 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] |
52
+ | Documentation | [![Current release on RubyDoc.info][📜docs-cr-rd-img]][🚎yard-current] [![YARD on Galtzo.com][📜docs-head-rd-img]][🚎yard-head] [![Maintainer Blog][🚂maint-blog-img]][🚂maint-blog] [![GitLab Wiki][📜gl-wiki-img]][📜gl-wiki] [![GitHub Wiki][📜gh-wiki-img]][📜gh-wiki] |
53
+ | Compliance | [![License: AGPL-3.0-only OR PolyForm-Small-Business-1.0.0 OR LicenseRef-Big-Time-Public-License][📄license-img]][📄license] [![Apache license compatibility: Category X][📄license-compat-img]][📄license-compat] [![📄ilo-declaration-img]][📄ilo-declaration] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] |
54
+ | Style | [![Enforced Code Style Linter][💎rlts-img]][💎rlts] [![Keep-A-Changelog 1.0.0][📗keep-changelog-img]][📗keep-changelog] [![Gitmoji Commits][📌gitmoji-img]][📌gitmoji] [![Compatibility appraised by: appraisal2][💎appraisal2-img]][💎appraisal2] |
55
+ | Maintainer 🎖️ | [![Follow Me on LinkedIn][💖🖇linkedin-img]][💖🖇linkedin] [![Follow Me on Ruby.Social][💖🐘ruby-mast-img]][💖🐘ruby-mast] [![Follow Me on Bluesky][💖🦋bluesky-img]][💖🦋bluesky] [![Contact Maintainer][🚂maint-contact-img]][🚂maint-contact] [![My technical writing][💖💁🏼‍♂️devto-img]][💖💁🏼‍♂️devto] |
56
+ | `...` 💖 | [![Find Me on WellFound:][💖✌️wellfound-img]][💖✌️wellfound] [![Find Me on CrunchBase][💖💲crunchbase-img]][💖💲crunchbase] [![My LinkTree][💖🌳linktree-img]][💖🌳linktree] [![More About Me][💖💁🏼‍♂️aboutme-img]][💖💁🏼‍♂️aboutme] [🧊][💖🧊berg] [🐙][💖🐙hub] [🛖][💖🛖hut] [🧪][💖🧪lab] |
57
+
58
+ ### Compatibility
59
+
60
+ Compatible with MRI Ruby 3.2.0+, and concordant releases of JRuby, and TruffleRuby.
61
+ CI workflows and Appraisals are generated for MRI Ruby 3.2.0+.
62
+ This test floor is configured by `ruby.test_minimum` in `.kettle-jem.yml` and
63
+ may be higher than the gem's runtime compatibility floor when legacy Rubies are
64
+ not practical for the current toolchain.
65
+
66
+ <a href="https://github.com/kettle-dev"><img alt="kettle-dev Logo by Aboling0, CC BY-SA 4.0" src="https://logos.galtzo.com/assets/images/kettle-dev/avatar-128px.svg" width="14%" align="right"/></a>
67
+
68
+ The _amazing_ test matrix is powered by the kettle-dev stack.
69
+
70
+ <details markdown="1">
71
+ <summary>How kettle-dev manages complexity in tests</summary>
72
+
73
+ | Gem | Source | Role | Daily download rank |
74
+ |-----|--------|------|---------------------|
75
+ | [appraisal2](https://bestgems.org/gems/appraisal2) | [GitHub](https://github.com/appraisal-rb/appraisal2) | multi-dependency Appraisal matrix generation | [![Daily download rank for appraisal2](https://img.shields.io/gem/rd/appraisal2.svg?style=flat-square)](https://bestgems.org/gems/appraisal2) |
76
+ | [appraisal2-rubocop](https://bestgems.org/gems/appraisal2-rubocop) | [GitHub](https://github.com/appraisal-rb/appraisal2-rubocop) | RuboCop Appraisal generator integration | [![Daily download rank for appraisal2-rubocop](https://img.shields.io/gem/rd/appraisal2-rubocop.svg?style=flat-square)](https://bestgems.org/gems/appraisal2-rubocop) |
77
+ | [kettle-dev](https://bestgems.org/gems/kettle-dev) | [GitHub](https://github.com/kettle-dev/kettle-dev) | development, release, and CI workflow tooling | [![Daily download rank for kettle-dev](https://img.shields.io/gem/rd/kettle-dev.svg?style=flat-square)](https://bestgems.org/gems/kettle-dev) |
78
+ | [kettle-jem](https://bestgems.org/gems/kettle-jem) | [GitHub](https://github.com/kettle-dev/kettle-jem) | Appraisals & CI workflow templates | [![Daily download rank for kettle-jem](https://img.shields.io/gem/rd/kettle-jem.svg?style=flat-square)](https://bestgems.org/gems/kettle-jem) |
79
+ | [kettle-soup-cover](https://bestgems.org/gems/kettle-soup-cover) | [GitHub](https://github.com/kettle-dev/kettle-soup-cover) | SimpleCov coverage policy and reporting | [![Daily download rank for kettle-soup-cover](https://img.shields.io/gem/rd/kettle-soup-cover.svg?style=flat-square)](https://bestgems.org/gems/kettle-soup-cover) |
80
+ | [kettle-test](https://bestgems.org/gems/kettle-test) | [GitHub](https://github.com/kettle-dev/kettle-test) | standard test runner and coverage harness | [![Daily download rank for kettle-test](https://img.shields.io/gem/rd/kettle-test.svg?style=flat-square)](https://bestgems.org/gems/kettle-test) |
81
+ | [rubocop-lts](https://bestgems.org/gems/rubocop-lts) | [GitHub](https://github.com/rubocop-lts/rubocop-lts) | Ruby-version-aware linting | [![Daily download rank for rubocop-lts](https://img.shields.io/gem/rd/rubocop-lts.svg?style=flat-square)](https://bestgems.org/gems/rubocop-lts) |
82
+ | [turbo_tests2](https://bestgems.org/gems/turbo_tests2) | [GitHub](https://github.com/galtzo-floss/turbo_tests2) | parallel test execution | [![Daily download rank for turbo_tests2](https://img.shields.io/gem/rd/turbo_tests2.svg?style=flat-square)](https://bestgems.org/gems/turbo_tests2) |
83
+
84
+ </details>
85
+
86
+ ### Federated DVCS
87
+
88
+ <details markdown="1">
89
+ <summary>Find this repo on federated forges (Coming soon!)</summary>
90
+
91
+ | Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
92
+ |-------------------------------------------------|-----------------------------------------------------------------------|---------------------------|--------------------------|---------------------------|--------------------------|------------------------------|
93
+ | 🧪 [kettle-dev/kettle-wash on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix | ➖ |
94
+ | 🧊 [kettle-dev/kettle-wash on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
95
+ | 🐙 [kettle-dev/kettle-wash on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix | [💚][gh-discussions] |
96
+ | 🎮️ [Discord Server][✉️discord-invite] | [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] | [Let's][✉️discord-invite] | [talk][✉️discord-invite] | [about][✉️discord-invite] | [this][✉️discord-invite] | [library!][✉️discord-invite] |
97
+
98
+ </details>
99
+
100
+ [gh-discussions]: https://github.com/kettle-dev/kettle-wash/discussions
101
+
102
+ ### Enterprise Support [![Tidelift](https://tidelift.com/badges/package/rubygems/kettle-wash)](https://tidelift.com/subscription/pkg/rubygems-kettle-wash?utm_source=rubygems-kettle-wash&utm_medium=referral&utm_campaign=readme)
103
+
104
+ Available as part of the Tidelift Subscription.
105
+
106
+ <details markdown="1">
107
+ <summary>Need enterprise-level guarantees?</summary>
108
+
109
+ The maintainers of this and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use.
110
+
111
+ [![Get help from me on Tidelift][🏙️entsup-tidelift-img]][🏙️entsup-tidelift]
112
+
113
+ - 💡Subscribe for support guarantees covering _all_ your FLOSS dependencies
114
+ - 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar]
115
+ - 💡Tidelift pays maintainers to maintain the software you depend on!<br/>📊`@`Pointy Haired Boss: An [enterprise support][🏙️entsup-tidelift] subscription is "[never gonna let you down][🧮kloc]", and *supports* open source maintainers
116
+
117
+ Alternatively:
118
+
119
+ - [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]
120
+ - [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork]
121
+ - [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor]
122
+
123
+ </details>
124
+
125
+ ## ✨ Installation
126
+
127
+ Install the gem and add to the application's Gemfile by executing:
128
+
129
+ ```console
130
+ bundle add kettle-wash
131
+ ```
132
+
133
+ If bundler is not being used to manage dependencies, install the gem by executing:
134
+
135
+ ```console
136
+ gem install kettle-wash
137
+ ```
138
+
139
+ ## ⚙️ Configuration
140
+
141
+ There is no global configuration. Each consumer declares the constants it owns
142
+ and the file that can rebuild them.
143
+
144
+ ## 🔧 Basic Usage
145
+
146
+ Use `Kettle::Wash::Change` when a module has constants derived from environment
147
+ or runtime state and specs need to reset those constants between examples for
148
+ accurate line and branch coverage.
149
+
150
+ ```ruby
151
+ require "kettle/wash"
152
+
153
+ module MyGem
154
+ module Constants
155
+ VALUE = ENV.fetch("MY_GEM_VALUE", "default")
156
+
157
+ include Kettle::Wash::Change.new(
158
+ constants: %w[
159
+ VALUE
160
+ ],
161
+ path: "my_gem/constants.rb"
162
+ )
163
+ end
164
+ end
165
+ ```
166
+
167
+ The generated singleton methods remove only the declared constants:
168
+
169
+ ```ruby
170
+ MyGem::Constants.delete_const
171
+
172
+ MyGem::Constants.reset_const do
173
+ ENV["MY_GEM_VALUE"] = "changed"
174
+ end
175
+ ```
176
+
177
+ ### RSpec Example
178
+
179
+ In specs, use `stub_env` from
180
+ [`rspec-stubbed_env`](https://github.com/galtzo-floss/rspec-stubbed_env) inside
181
+ `reset_const`. The constants are deleted before the block runs, then the
182
+ configured file is loaded again after the block finishes. This avoids modifying
183
+ the real process environment.
184
+
185
+ ```ruby
186
+ require "rspec/stubbed_env"
187
+
188
+ RSpec.describe MyGem::Constants do
189
+ include_context "with stubbed env"
190
+
191
+ it "uses the default value" do
192
+ described_class.reset_const do
193
+ stub_env("MY_GEM_VALUE" => nil)
194
+ end
195
+
196
+ expect(described_class::VALUE).to eq("default")
197
+ end
198
+
199
+ it "uses the configured value" do
200
+ described_class.reset_const do
201
+ stub_env("MY_GEM_VALUE" => "configured")
202
+ end
203
+
204
+ expect(described_class::VALUE).to eq("configured")
205
+ end
206
+ end
207
+ ```
208
+
209
+ That shape lets SimpleCov see both examples execute the actual constant
210
+ definition line. For a production use, see
211
+ [`kettle-soup-cover`'s constants specs](https://github.com/kettle-dev/kettle-soup-cover/blob/main/spec/kettle/soup/cover/constants_spec.rb),
212
+ which reset `Kettle::Soup::Cover::Constants` under different `K_SOUP_COV_*`
213
+ environment values to cover branch-heavy constant definitions.
214
+
215
+ ## 🔐 Security
216
+
217
+ See [SECURITY.md][🔐security].
218
+
219
+ ## 🤝 Contributing
220
+
221
+ If you need some ideas of where to help, you could work on adding more code coverage,
222
+ or if it is already 💯 (see [below](#code-coverage)) check [issues][🤝gh-issues] or [PRs][🤝gh-pulls],
223
+ or use the gem and think about how it could be better.
224
+
225
+ We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it.
226
+
227
+ See [CONTRIBUTING.md][🤝contributing] for more detailed instructions.
228
+
229
+ ### 🚀 Release Instructions
230
+
231
+ See [CONTRIBUTING.md][🤝contributing].
232
+
233
+ ### Code Coverage
234
+
235
+ <details markdown="1">
236
+ <summary>Coverage service badges</summary>
237
+
238
+ [![Coverage Graph][🏀codecov-g]][🏀codecov]
239
+
240
+ [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls]
241
+
242
+ [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov]
243
+
244
+ </details>
245
+
246
+ ### 🪇 Code of Conduct
247
+
248
+ Everyone interacting with this project's codebases, issue trackers,
249
+ chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct].
250
+
251
+ ## 🌈 Contributors
252
+
253
+ [![Contributors][🖐contributors-img]][🖐contributors]
254
+
255
+ Made with [contributors-img][🖐contrib-rocks].
256
+
257
+ Also see GitLab Contributors: [https://gitlab.com/kettle-dev/kettle-wash/-/graphs/main][🚎contributors-gl]
258
+
259
+ <details markdown="1">
260
+ <summary>⭐️ Star History</summary>
261
+
262
+ <a href="https://star-history.com/kettle-dev/kettle-wash&Date">
263
+ <picture>
264
+ <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=kettle-dev/kettle-wash&type=Date&theme=dark" />
265
+ <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=kettle-dev/kettle-wash&type=Date" />
266
+ <img alt="Star History Chart" src="https://api.star-history.com/svg?repos=kettle-dev/kettle-wash&type=Date" />
267
+ </picture>
268
+ </a>
269
+
270
+ </details>
271
+
272
+ ## 📌 Versioning
273
+
274
+ This library follows [![Semantic Versioning 2.0.0][📌semver-img]][📌semver] for its public API where practical.
275
+ For most applications, prefer the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
276
+
277
+ For example:
278
+
279
+ ```ruby
280
+ spec.add_dependency("kettle-wash", "~> 0.1")
281
+ ```
282
+
283
+ <details markdown="1">
284
+ <summary>📌 Is "Platform Support" part of the public API? More details inside.</summary>
285
+
286
+ Dropping support for a platform can be a breaking change for affected users.
287
+ If a release changes supported platforms, it should be called out clearly in the changelog and versioned with that impact in mind.
288
+
289
+ To get a better understanding of how SemVer is intended to work over a project's lifetime,
290
+ read this article from the creator of SemVer:
291
+
292
+ - ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]
293
+
294
+ </details>
295
+
296
+ See [CHANGELOG.md][📌changelog] for a list of releases.
297
+
298
+ ## 📄 License
299
+
300
+ The gem is available under the following licenses: [AGPL-3.0-only](AGPL-3.0-only.md), [PolyForm-Small-Business-1.0.0](PolyForm-Small-Business-1.0.0.md), [Big-Time-Public-License](Big-Time-Public-License.md).
301
+ See [LICENSE.md][📄license] for details.
302
+
303
+ If none of the available licenses suit your use case, please [contact us](mailto:floss@galtzo.com) to discuss a custom commercial license.
304
+
305
+ ### License use-case guide
306
+
307
+ | Use case | License |
308
+ |---|---|
309
+ | Copy-left open source | [AGPL-3.0-only](AGPL-3.0-only.md) |
310
+ | Non-commercial (research, education, personal use) | [PolyForm-Small-Business-1.0.0](PolyForm-Small-Business-1.0.0.md) or [Big-Time-Public-License](Big-Time-Public-License.md) |
311
+ | Small business commercial | [PolyForm-Small-Business-1.0.0](PolyForm-Small-Business-1.0.0.md) or [Big-Time-Public-License](Big-Time-Public-License.md) |
312
+ | Larger business commercial | [Big-Time-Public-License](Big-Time-Public-License.md) or [contact us](mailto:floss@galtzo.com) for a custom license |
313
+
314
+ ### © Copyright
315
+
316
+ See [LICENSE.md][📄license] for the official copyright notice.
317
+
318
+ <details markdown="1">
319
+ <summary>Copyright holders</summary>
320
+
321
+ - Required Notice: Copyright (c) 2026 Peter H. Boling
322
+
323
+ </details>
324
+
325
+ ## 🤑 A request for help
326
+
327
+ Maintainers have teeth and need to pay their dentists.
328
+ After getting laid off in an RIF in March, and encountering difficulty finding a new one,
329
+ I began spending most of my time building open source tools.
330
+ I'm hoping to be able to pay for my kids' health insurance this month,
331
+ so if you value the work I am doing, I need your support.
332
+ Please consider sponsoring me or the project.
333
+
334
+ To join the community or get help 👇️ Join the Discord.
335
+
336
+ [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]
337
+
338
+ To say "thanks!" ☝️ Join the Discord or 👇️ send money.
339
+
340
+ [![Sponsor kettle-dev/kettle-wash on Open Source Collective][🖇osc-all-bottom-img]][🖇osc] 💌 [![Sponsor me on GitHub Sponsors][🖇sponsor-bottom-img]][🖇sponsor] 💌 [![Sponsor me on Liberapay][⛳liberapay-bottom-img]][⛳liberapay] 💌 [![Donate on PayPal][🖇paypal-bottom-img]][🖇paypal]
341
+
342
+ ### Please give the project a star ⭐ ♥.
343
+
344
+ Many parts of this project are actively managed by a [kettle-jem](https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/kettle-jem) smart template utilizing [StructuredMerge.org](https://structuredmerge.org) merge contracts.
345
+
346
+ Thanks for RTFM. ☺️
347
+
348
+ [⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611&style=flat
349
+ [⛳liberapay-bottom-img]: https://img.shields.io/liberapay/goal/pboling.svg?style=for-the-badge&logo=liberapay&color=a51611
350
+ [⛳liberapay]: https://liberapay.com/pboling/donate
351
+ [🖇osc-all-img]: https://img.shields.io/opencollective/all/kettle-dev
352
+ [🖇osc-sponsors-img]: https://img.shields.io/opencollective/sponsors/kettle-dev
353
+ [🖇osc-backers-img]: https://img.shields.io/opencollective/backers/kettle-dev
354
+ [🖇osc-backers]: https://opencollective.com/kettle-dev#backer
355
+ [🖇osc-backers-i]: https://opencollective.com/kettle-dev/backers/badge.svg?style=flat
356
+ [🖇osc-sponsors]: https://opencollective.com/kettle-dev#sponsor
357
+ [🖇osc-sponsors-i]: https://opencollective.com/kettle-dev/sponsors/badge.svg?style=flat
358
+ [🖇osc-all-bottom-img]: https://img.shields.io/opencollective/all/kettle-dev?style=for-the-badge
359
+ [🖇osc-sponsors-bottom-img]: https://img.shields.io/opencollective/sponsors/kettle-dev?style=for-the-badge
360
+ [🖇osc-backers-bottom-img]: https://img.shields.io/opencollective/backers/kettle-dev?style=for-the-badge
361
+ [🖇osc]: https://opencollective.com/kettle-dev
362
+ [🖇sponsor-img]: https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github
363
+ [🖇sponsor-bottom-img]: https://img.shields.io/badge/Sponsor_Me!-pboling-blue?style=for-the-badge&logo=github
364
+ [🖇sponsor]: https://github.com/sponsors/pboling
365
+ [🖇kofi-img]: https://img.shields.io/badge/ko--fi-%E2%9C%93-a51611.svg?style=flat
366
+ [🖇kofi]: https://ko-fi.com/pboling
367
+ [🖇buyme-small-img]: https://img.shields.io/badge/buy_me_a_coffee-%E2%9C%93-a51611.svg?style=flat
368
+ [🖇buyme-img]: https://img.buymeacoffee.com/button-api/?text=Buy%20me%20a%20latte&emoji=&slug=pboling&button_colour=FFDD00&font_colour=000000&font_family=Cookie&outline_colour=000000&coffee_colour=ffffff
369
+ [🖇buyme]: https://www.buymeacoffee.com/pboling
370
+ [🖇paypal-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=flat&logo=paypal
371
+ [🖇paypal-bottom-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=for-the-badge&logo=paypal&color=0A0A0A
372
+ [🖇paypal]: https://www.paypal.com/paypalme/peterboling
373
+ [🖇floss-funding.dev]: https://floss-funding.dev
374
+ [🖇floss-funding-gem]: https://github.com/galtzo-floss/floss_funding
375
+ [✉️discord-invite]: https://discord.gg/3qme4XHNKN
376
+ [✉️discord-invite-img-ftb]: https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord
377
+ [✉️ruby-friends-img]: https://img.shields.io/badge/daily.dev-%F0%9F%92%8E_Ruby_Friends-0A0A0A?style=for-the-badge&logo=dailydotdev&logoColor=white
378
+ [✉️ruby-friends]: https://app.daily.dev/squads/rubyfriends
379
+
380
+ [✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
381
+ [⛳️gem-namespace]: https://github.com/kettle-dev/kettle-wash
382
+ [⛳️namespace-img]: https://img.shields.io/badge/namespace-Kettle::Wash-3C2D2D.svg?style=square&logo=ruby&logoColor=white
383
+ [⛳️gem-name]: https://bestgems.org/gems/kettle-wash
384
+ [⛳️name-img]: https://img.shields.io/badge/name-kettle--wash-3C2D2D.svg?style=square&logo=rubygems&logoColor=red
385
+ [⛳️tag-img]: https://img.shields.io/github/tag/kettle-dev/kettle-wash.svg
386
+ [⛳️tag]: https://github.com/kettle-dev/kettle-wash/releases
387
+ [🚂maint-blog]: http://www.railsbling.com/tags/kettle-wash
388
+ [🚂maint-blog-img]: https://img.shields.io/badge/blog-railsbling-0093D0.svg?style=for-the-badge&logo=rubyonrails&logoColor=orange
389
+ [🚂maint-contact]: http://www.railsbling.com/contact
390
+ [🚂maint-contact-img]: https://img.shields.io/badge/Contact-Maintainer-0093D0.svg?style=flat&logo=rubyonrails&logoColor=red
391
+ [💖🖇linkedin]: http://www.linkedin.com/in/peterboling
392
+ [💖🖇linkedin-img]: https://img.shields.io/badge/LinkedIn-Profile-0B66C2?style=flat&logo=newjapanprowrestling
393
+ [💖✌️wellfound]: https://wellfound.com/u/peter-boling
394
+ [💖✌️wellfound-img]: https://img.shields.io/badge/peter--boling-orange?style=flat&logo=wellfound
395
+ [💖💲crunchbase]: https://www.crunchbase.com/person/peter-boling
396
+ [💖💲crunchbase-img]: https://img.shields.io/badge/peter--boling-purple?style=flat&logo=crunchbase
397
+ [💖🐘ruby-mast]: https://ruby.social/@galtzo
398
+ [💖🐘ruby-mast-img]: https://img.shields.io/mastodon/follow/109447111526622197?domain=https://ruby.social&style=flat&logo=mastodon&label=Ruby%20@galtzo
399
+ [💖🦋bluesky]: https://bsky.app/profile/galtzo.com
400
+ [💖🦋bluesky-img]: https://img.shields.io/badge/@galtzo.com-0285FF?style=flat&logo=bluesky&logoColor=white
401
+ [💖🌳linktree]: https://linktr.ee/galtzo
402
+ [💖🌳linktree-img]: https://img.shields.io/badge/galtzo-purple?style=flat&logo=linktree
403
+ [💖💁🏼‍♂️devto]: https://dev.to/galtzo
404
+ [💖💁🏼‍♂️devto-img]: https://img.shields.io/badge/dev.to-0A0A0A?style=flat&logo=devdotto&logoColor=white
405
+ [💖💁🏼‍♂️aboutme]: https://about.me/peter.boling
406
+ [💖💁🏼‍♂️aboutme-img]: https://img.shields.io/badge/about.me-0A0A0A?style=flat&logo=aboutme&logoColor=white
407
+ [💖🧊berg]: https://codeberg.org/pboling
408
+ [💖🐙hub]: https://github.org/pboling
409
+ [💖🛖hut]: https://sr.ht/~galtzo/
410
+ [💖🧪lab]: https://gitlab.com/pboling
411
+ [👨🏼‍🏫expsup-upwork]: https://www.upwork.com/freelancers/~014942e9b056abdf86?mp_source=share
412
+ [👨🏼‍🏫expsup-upwork-img]: https://img.shields.io/badge/UpWork-13544E?style=for-the-badge&logo=Upwork&logoColor=white
413
+ [👨🏼‍🏫expsup-codementor]: https://www.codementor.io/peterboling?utm_source=github&utm_medium=button&utm_term=peterboling&utm_campaign=github
414
+ [👨🏼‍🏫expsup-codementor-img]: https://img.shields.io/badge/CodeMentor-Get_Help-1abc9c?style=for-the-badge&logo=CodeMentor&logoColor=white
415
+ [🏙️entsup-tidelift]: https://tidelift.com/subscription/pkg/rubygems-kettle-wash?utm_source=rubygems-kettle-wash&utm_medium=referral&utm_campaign=readme
416
+ [🏙️entsup-tidelift-img]: https://img.shields.io/badge/Tidelift_and_Sonar-Enterprise_Support-FD3456?style=for-the-badge&logo=sonar&logoColor=white
417
+ [🏙️entsup-tidelift-sonar]: https://blog.tidelift.com/tidelift-joins-sonar
418
+ [💁🏼‍♂️peterboling]: http://www.peterboling.com
419
+ [🚂railsbling]: http://www.railsbling.com
420
+ [📜src-gl-img]: https://img.shields.io/badge/GitLab-FBA326?style=for-the-badge&logo=Gitlab&logoColor=orange
421
+ [📜src-gl]: https://gitlab.com/kettle-dev/kettle-wash
422
+ [📜src-cb-img]: https://img.shields.io/badge/CodeBerg-4893CC?style=for-the-badge&logo=CodeBerg&logoColor=blue
423
+ [📜src-cb]: https://codeberg.org/kettle-dev/kettle-wash
424
+ [📜src-gh-img]: https://img.shields.io/badge/GitHub-238636?style=for-the-badge&logo=Github&logoColor=green
425
+ [📜src-gh]: https://github.com/kettle-dev/kettle-wash
426
+ [📜docs-cr-rd-img]: https://img.shields.io/badge/RubyDoc-Current_Release-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
427
+ [📜docs-head-rd-img]: https://img.shields.io/badge/YARD_on_Galtzo.com-HEAD-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
428
+ [📜gl-wiki]: https://gitlab.com/kettle-dev/kettle-wash/-/wikis/home
429
+ [📜gh-wiki]: https://github.com/kettle-dev/kettle-wash/wiki
430
+ [📜gl-wiki-img]: https://img.shields.io/badge/wiki-gitlab-943CD2.svg?style=for-the-badge&logo=gitlab&logoColor=white
431
+ [📜gh-wiki-img]: https://img.shields.io/badge/wiki-github-943CD2.svg?style=for-the-badge&logo=github&logoColor=white
432
+ [👽dl-rank]: https://bestgems.org/gems/kettle-wash
433
+ [👽dl-ranki]: https://img.shields.io/gem/rd/kettle-wash.svg
434
+ [👽version]: https://bestgems.org/gems/kettle-wash
435
+ [👽versioni]: https://img.shields.io/gem/v/kettle-wash.svg
436
+ [🏀qlty-mnt]: https://qlty.sh/gh/kettle-dev/projects/kettle-wash
437
+ [🏀qlty-mnti]: https://qlty.sh/gh/kettle-dev/projects/kettle-wash/maintainability.svg
438
+ [🏀qlty-cov]: https://qlty.sh/gh/kettle-dev/projects/kettle-wash/metrics/code?sort=coverageRating
439
+ [🏀qlty-covi]: https://qlty.sh/gh/kettle-dev/projects/kettle-wash/coverage.svg
440
+ [🏀codecov]: https://codecov.io/gh/kettle-dev/kettle-wash
441
+ [🏀codecovi]: https://codecov.io/gh/kettle-dev/kettle-wash/graph/badge.svg
442
+ [🏀coveralls]: https://coveralls.io/github/kettle-dev/kettle-wash?branch=main
443
+ [🏀coveralls-img]: https://coveralls.io/repos/github/kettle-dev/kettle-wash/badge.svg?branch=main
444
+ [🚎ruby-3.2-wf]: https://github.com/kettle-dev/kettle-wash/actions/workflows/ruby-3.2.yml
445
+ [🚎ruby-3.3-wf]: https://github.com/kettle-dev/kettle-wash/actions/workflows/ruby-3.3.yml
446
+ [🚎ruby-3.4-wf]: https://github.com/kettle-dev/kettle-wash/actions/workflows/ruby-3.4.yml
447
+ [🚎jruby-10.0-wf]: https://github.com/kettle-dev/kettle-wash/actions/workflows/jruby-10.0.yml
448
+ [🚎truby-24.2-wf]: https://github.com/kettle-dev/kettle-wash/actions/workflows/truffleruby-24.2.yml
449
+ [🚎truby-25.0-wf]: https://github.com/kettle-dev/kettle-wash/actions/workflows/truffleruby-25.0.yml
450
+ [🚎truby-33.0-wf]: https://github.com/kettle-dev/kettle-wash/actions/workflows/truffleruby-33.0.yml
451
+ [🚎2-cov-wf]: https://github.com/kettle-dev/kettle-wash/actions/workflows/coverage.yml
452
+ [🚎2-cov-wfi]: https://github.com/kettle-dev/kettle-wash/actions/workflows/coverage.yml/badge.svg
453
+ [🚎3-hd-wf]: https://github.com/kettle-dev/kettle-wash/actions/workflows/heads.yml
454
+ [🚎3-hd-wfi]: https://github.com/kettle-dev/kettle-wash/actions/workflows/heads.yml/badge.svg
455
+ [🚎5-st-wf]: https://github.com/kettle-dev/kettle-wash/actions/workflows/style.yml
456
+ [🚎5-st-wfi]: https://github.com/kettle-dev/kettle-wash/actions/workflows/style.yml/badge.svg
457
+ [🚎9-t-wf]: https://github.com/kettle-dev/kettle-wash/actions/workflows/truffle.yml
458
+ [🚎9-t-wfi]: https://github.com/kettle-dev/kettle-wash/actions/workflows/truffle.yml/badge.svg
459
+ [🚎10-j-wf]: https://github.com/kettle-dev/kettle-wash/actions/workflows/jruby.yml
460
+ [🚎10-j-wfi]: https://github.com/kettle-dev/kettle-wash/actions/workflows/jruby.yml/badge.svg
461
+ [🚎11-c-wf]: https://github.com/kettle-dev/kettle-wash/actions/workflows/current.yml
462
+ [🚎11-c-wfi]: https://github.com/kettle-dev/kettle-wash/actions/workflows/current.yml/badge.svg
463
+ [🚎12-crh-wf]: https://github.com/kettle-dev/kettle-wash/actions/workflows/dep-heads.yml
464
+ [🚎12-crh-wfi]: https://github.com/kettle-dev/kettle-wash/actions/workflows/dep-heads.yml/badge.svg
465
+ [🚎13-🔒️-wf]: https://github.com/kettle-dev/kettle-wash/actions/workflows/locked_deps.yml
466
+ [🚎13-🔒️-wfi]: https://github.com/kettle-dev/kettle-wash/actions/workflows/locked_deps.yml/badge.svg
467
+ [🚎14-🔓️-wf]: https://github.com/kettle-dev/kettle-wash/actions/workflows/unlocked_deps.yml
468
+ [🚎14-🔓️-wfi]: https://github.com/kettle-dev/kettle-wash/actions/workflows/unlocked_deps.yml/badge.svg
469
+ [💎ruby-3.2i]: https://img.shields.io/badge/Ruby-3.2-CC342D?style=for-the-badge&logo=ruby&logoColor=white
470
+ [💎ruby-3.3i]: https://img.shields.io/badge/Ruby-3.3-CC342D?style=for-the-badge&logo=ruby&logoColor=white
471
+ [💎ruby-3.4i]: https://img.shields.io/badge/Ruby-3.4-CC342D?style=for-the-badge&logo=ruby&logoColor=white
472
+ [💎ruby-c-i]: https://img.shields.io/badge/Ruby-current-CC342D?style=for-the-badge&logo=ruby&logoColor=green
473
+ [💎ruby-headi]: https://img.shields.io/badge/Ruby-HEAD-CC342D?style=for-the-badge&logo=ruby&logoColor=blue
474
+ [💎truby-24.2i]: https://img.shields.io/badge/Truffle_Ruby-24.2-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
475
+ [💎truby-25.0i]: https://img.shields.io/badge/Truffle_Ruby-25.0-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
476
+ [💎truby-33.0i]: https://img.shields.io/badge/Truffle_Ruby-33.0-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
477
+ [💎truby-c-i]: https://img.shields.io/badge/Truffle_Ruby-current-34BCB1?style=for-the-badge&logo=ruby&logoColor=green
478
+ [💎truby-headi]: https://img.shields.io/badge/Truffle_Ruby-HEAD-34BCB1?style=for-the-badge&logo=ruby&logoColor=blue
479
+ [💎jruby-10.0i]: https://img.shields.io/badge/JRuby-10.0-FBE742?style=for-the-badge&logo=ruby&logoColor=red
480
+ [💎jruby-c-i]: https://img.shields.io/badge/JRuby-current-FBE742?style=for-the-badge&logo=ruby&logoColor=green
481
+ [💎jruby-headi]: https://img.shields.io/badge/JRuby-HEAD-FBE742?style=for-the-badge&logo=ruby&logoColor=blue
482
+ [🤝gh-issues]: https://github.com/kettle-dev/kettle-wash/issues
483
+ [🤝gh-pulls]: https://github.com/kettle-dev/kettle-wash/pulls
484
+ [🤝gl-issues]: https://gitlab.com/kettle-dev/kettle-wash/-/issues
485
+ [🤝gl-pulls]: https://gitlab.com/kettle-dev/kettle-wash/-/merge_requests
486
+ [🤝cb-issues]: https://codeberg.org/kettle-dev/kettle-wash/issues
487
+ [🤝cb-pulls]: https://codeberg.org/kettle-dev/kettle-wash/pulls
488
+ [🤝cb-donate]: https://donate.codeberg.org/
489
+ [🤝contributing]: https://github.com/kettle-dev/kettle-wash/blob/main/CONTRIBUTING.md
490
+ [🏀codecov-g]: https://codecov.io/gh/kettle-dev/kettle-wash/graph/badge.svg
491
+ [🖐contrib-rocks]: https://contrib.rocks
492
+ [🖐contributors]: https://github.com/kettle-dev/kettle-wash/graphs/contributors
493
+ [🖐contributors-img]: https://contrib.rocks/image?repo=kettle-dev/kettle-wash
494
+ [🚎contributors-gl]: https://gitlab.com/kettle-dev/kettle-wash/-/graphs/main
495
+ [🪇conduct]: https://github.com/kettle-dev/kettle-wash/blob/main/CODE_OF_CONDUCT.md
496
+ [🪇conduct-img]: https://img.shields.io/badge/Contributor_Covenant-2.1-259D6C.svg
497
+ [📌pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint
498
+ [📌semver]: https://semver.org/spec/v2.0.0.html
499
+ [📌semver-img]: https://img.shields.io/badge/semver-2.0.0-259D6C.svg?style=flat
500
+ [📌semver-breaking]: https://github.com/semver/semver/issues/716#issuecomment-869336139
501
+ [📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html
502
+ [📌changelog]: https://github.com/kettle-dev/kettle-wash/blob/main/CHANGELOG.md
503
+ [📗keep-changelog]: https://keepachangelog.com/en/1.0.0/
504
+ [📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-34495e.svg?style=flat
505
+ [📌gitmoji]: https://gitmoji.dev
506
+ [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
507
+ [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
508
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.063-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
509
+ [🔐security]: https://github.com/kettle-dev/kettle-wash/blob/main/SECURITY.md
510
+ [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
511
+ [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
512
+ [📄license]: LICENSE.md
513
+ [📄license-ref]: LICENSE.md
514
+ [📄license-img]: https://img.shields.io/badge/License-AGPL--3.0--only_OR_PolyForm--Small--Business--1.0.0_OR_LicenseRef--Big--Time--Public--License-259D6C.svg
515
+ [📄license-compat]: https://www.apache.org/legal/resolved.html#category-x
516
+ [📄license-compat-img]: https://img.shields.io/badge/Apache_Incompatible:_Category_X-%E2%9C%97-C0392B.svg?style=flat&logo=Apache
517
+
518
+ [📄ilo-declaration]: https://www.ilo.org/declaration/lang--en/index.htm
519
+ [📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat
520
+ [🚎yard-current]: http://rubydoc.info/gems/kettle-wash
521
+ [🚎yard-head]: https://kettle-wash.galtzo.com
522
+ [💎stone_checksums]: https://github.com/galtzo-floss/stone_checksums
523
+ [💎SHA_checksums]: https://gitlab.com/kettle-dev/kettle-wash/-/tree/main/checksums
524
+ [💎rlts]: https://github.com/rubocop-lts/rubocop-lts
525
+ [💎rlts-img]: https://img.shields.io/badge/code_style_&_linting-rubocop--lts-34495e.svg?plastic&logo=ruby&logoColor=white
526
+ [💎appraisal2]: https://github.com/appraisal-rb/appraisal2
527
+ [💎appraisal2-img]: https://img.shields.io/badge/appraised_by-appraisal2-34495e.svg?plastic&logo=ruby&logoColor=white
528
+ [💎d-in-dvcs]: https://railsbling.com/posts/dvcs/put_the_d_in_dvcs/
529
+
530
+ <!-- kettle-jem:metadata:start -->
531
+ | Field | Value |
532
+ |---|---|
533
+ | Package | kettle-wash |
534
+ | Description | 🚿 Constant deletion and reset helpers for gems that need repeatable reloads while testing constant-backed runtime configuration. |
535
+ | Homepage | https://github.com/kettle-dev/kettle-wash |
536
+ | Source | https://github.com/kettle-dev/kettle-wash |
537
+ | License | `AGPL-3.0-only` OR `PolyForm-Small-Business-1.0.0` OR `LicenseRef-Big-Time-Public-License` |
538
+ | Funding | https://github.com/sponsors/pboling, https://ko-fi.com/pboling, https://liberapay.com/pboling/donate, https://opencollective.com/kettle-dev, https://thanks.dev/u/gh/pboling, https://tidelift.com/funding/github/rubygems/kettle-wash, https://www.buymeacoffee.com/pboling |
539
+ <!-- kettle-jem:metadata:end -->
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kettle
4
+ module Wash
5
+ module Version
6
+ VERSION = "0.1.0"
7
+ end
8
+ VERSION = Version::VERSION # Traditional Constant Location
9
+ end
10
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "version_gem"
4
+ require_relative "wash/version"
5
+
6
+ Kettle::Wash::Version.class_eval do
7
+ extend VersionGem::Basic
8
+ end
9
+
10
+ module Kettle
11
+ module Wash
12
+ class Error < StandardError; end
13
+
14
+ class << self
15
+ def install(owner, config = nil, constants: nil, path: nil)
16
+ constants, path = normalize_config(config, constants: constants, path: path)
17
+ owner.extend(Change::ConstantChange.to_mod(constants: constants, path: path))
18
+ nil
19
+ end
20
+
21
+ def validate!(owner, config = nil, constants: nil, path: nil)
22
+ constants, path = normalize_config(config, constants: constants, path: path)
23
+ missing = constants.reject { |constant_name| owner.const_defined?(constant_name, false) }
24
+ raise Error, "Missing washable constant(s): #{missing.join(", ")}" unless missing.empty?
25
+ raise Error, "Washable constants path does not exist: #{path}" unless File.file?(path)
26
+
27
+ true
28
+ end
29
+
30
+ def delete_constants(owner, constants)
31
+ Array(constants).each do |constant_name|
32
+ owner.send(:remove_const, constant_name) if owner.const_defined?(constant_name, false)
33
+ end
34
+ nil
35
+ end
36
+
37
+ def reset_constants(owner:, constants:, path:)
38
+ delete_constants(owner, constants)
39
+ load(path)
40
+ nil
41
+ end
42
+
43
+ private
44
+
45
+ def normalize_config(config, constants:, path:)
46
+ config ||= {}
47
+ if config.respond_to?(:fetch)
48
+ constants ||= config.fetch(:constants) { config.fetch("constants", nil) }
49
+ path ||= config.fetch(:path) { config.fetch("path", nil) }
50
+ end
51
+
52
+ constants = Array(constants)
53
+ raise Error, "No washable constants configured" if constants.empty?
54
+ raise Error, "No washable constants path configured" if path.nil? || path.to_s.empty?
55
+
56
+ [constants, path.to_s]
57
+ end
58
+ end
59
+
60
+ class Change < Module
61
+ def initialize(constants: nil, path: nil)
62
+ super()
63
+ @constants = Array(constants) if constants
64
+ @path = path if path
65
+ end
66
+
67
+ def included(base)
68
+ constants = @constants
69
+ path = @path
70
+ return unless constants && path
71
+
72
+ base.extend(ConstantChange.to_mod(constants: constants, path: path))
73
+ end
74
+
75
+ module ConstantChange
76
+ class << self
77
+ def to_mod(constants:, path:)
78
+ Module.new do
79
+ define_method(:delete_const) do |*_args, &block|
80
+ Kettle::Wash.delete_constants(self, constants)
81
+ block&.call
82
+ nil
83
+ end
84
+
85
+ define_method(:reset_const) do |*_args, &block|
86
+ delete_const do
87
+ block&.call
88
+ load(path)
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,24 @@
1
+ module Kettle
2
+ module Wash
3
+ VERSION: String
4
+ def self.install: (Module owner, ?Hash[Symbol | String, untyped] config, ?constants: String | Symbol | Array[String | Symbol], ?path: String) -> nil
5
+ def self.validate!: (Module owner, ?Hash[Symbol | String, untyped] config, ?constants: String | Symbol | Array[String | Symbol], ?path: String) -> true
6
+ def self.delete_constants: (Module owner, String | Symbol | Array[String | Symbol] constants) -> nil
7
+ def self.reset_constants: (owner: Module, constants: String | Symbol | Array[String | Symbol], path: String) -> nil
8
+ class Error < StandardError
9
+ end
10
+
11
+ class Change < Module
12
+ def initialize: (?constants: nil | String | Symbol | Array[String | Symbol], ?path: nil | String) -> void
13
+ def included: (Module base) -> nil
14
+
15
+ module ConstantChange
16
+ def self.to_mod: (constants: Array[String | Symbol], path: String) -> Module
17
+ end
18
+ end
19
+
20
+ module Version
21
+ VERSION: String
22
+ end
23
+ end
24
+ end
data.tar.gz.sig ADDED
Binary file
metadata ADDED
@@ -0,0 +1,298 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kettle-wash
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Peter H. Boling
8
+ bindir: exe
9
+ cert_chain:
10
+ - |
11
+ -----BEGIN CERTIFICATE-----
12
+ MIIEgDCCAuigAwIBAgIBATANBgkqhkiG9w0BAQsFADBDMRUwEwYDVQQDDAxwZXRl
13
+ ci5ib2xpbmcxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkW
14
+ A2NvbTAeFw0yNTA1MDQxNTMzMDlaFw00NTA0MjkxNTMzMDlaMEMxFTATBgNVBAMM
15
+ DHBldGVyLmJvbGluZzEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPy
16
+ LGQBGRYDY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAruUoo0WA
17
+ uoNuq6puKWYeRYiZekz/nsDeK5x/0IEirzcCEvaHr3Bmz7rjo1I6On3gGKmiZs61
18
+ LRmQ3oxy77ydmkGTXBjruJB+pQEn7UfLSgQ0xa1/X3kdBZt6RmabFlBxnHkoaGY5
19
+ mZuZ5+Z7walmv6sFD9ajhzj+oIgwWfnEHkXYTR8I6VLN7MRRKGMPoZ/yvOmxb2DN
20
+ coEEHWKO9CvgYpW7asIihl/9GMpKiRkcYPm9dGQzZc6uTwom1COfW0+ZOFrDVBuV
21
+ FMQRPswZcY4Wlq0uEBLPU7hxnCL9nKK6Y9IhdDcz1mY6HZ91WImNslOSI0S8hRpj
22
+ yGOWxQIhBT3fqCBlRIqFQBudrnD9jSNpSGsFvbEijd5ns7Z9ZMehXkXDycpGAUj1
23
+ to/5cuTWWw1JqUWrKJYoifnVhtE1o1DZ+LkPtWxHtz5kjDG/zR3MG0Ula0UOavlD
24
+ qbnbcXPBnwXtTFeZ3C+yrWpE4pGnl3yGkZj9SMTlo9qnTMiPmuWKQDatAgMBAAGj
25
+ fzB9MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBQE8uWvNbPVNRXZ
26
+ HlgPbc2PCzC4bjAhBgNVHREEGjAYgRZwZXRlci5ib2xpbmdAZ21haWwuY29tMCEG
27
+ A1UdEgQaMBiBFnBldGVyLmJvbGluZ0BnbWFpbC5jb20wDQYJKoZIhvcNAQELBQAD
28
+ ggGBAJbnUwfJQFPkBgH9cL7hoBfRtmWiCvdqdjeTmi04u8zVNCUox0A4gT982DE9
29
+ wmuN12LpdajxZONqbXuzZvc+nb0StFwmFYZG6iDwaf4BPywm2e/Vmq0YG45vZXGR
30
+ L8yMDSK1cQXjmA+ZBKOHKWavxP6Vp7lWvjAhz8RFwqF9GuNIdhv9NpnCAWcMZtpm
31
+ GUPyIWw/Cw/2wZp74QzZj6Npx+LdXoLTF1HMSJXZ7/pkxLCsB8m4EFVdb/IrW/0k
32
+ kNSfjtAfBHO8nLGuqQZVH9IBD1i9K6aSs7pT6TW8itXUIlkIUI2tg5YzW6OFfPzq
33
+ QekSkX3lZfY+HTSp/o+YvKkqWLUV7PQ7xh1ZYDtocpaHwgxe/j3bBqHE+CUPH2vA
34
+ 0V/FwdTRWcwsjVoOJTrYcff8pBZ8r2MvtAc54xfnnhGFzeRHfcltobgFxkAXdE6p
35
+ DVjBtqT23eugOqQ73umLcYDZkc36vnqGxUBSsXrzY9pzV5gGr2I8YUxMqf6ATrZt
36
+ L9nRqA==
37
+ -----END CERTIFICATE-----
38
+ date: 1980-01-02 00:00:00.000000000 Z
39
+ dependencies:
40
+ - !ruby/object:Gem::Dependency
41
+ name: version_gem
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.1'
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 1.1.14
50
+ type: :runtime
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: '1.1'
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: 1.1.14
60
+ - !ruby/object:Gem::Dependency
61
+ name: kettle-dev
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '2.3'
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: 2.3.7
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '2.3'
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: 2.3.7
80
+ - !ruby/object:Gem::Dependency
81
+ name: bundler-audit
82
+ requirement: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - "~>"
85
+ - !ruby/object:Gem::Version
86
+ version: 0.9.3
87
+ type: :development
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - "~>"
92
+ - !ruby/object:Gem::Version
93
+ version: 0.9.3
94
+ - !ruby/object:Gem::Dependency
95
+ name: rake
96
+ requirement: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - "~>"
99
+ - !ruby/object:Gem::Version
100
+ version: '13.0'
101
+ type: :development
102
+ prerelease: false
103
+ version_requirements: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - "~>"
106
+ - !ruby/object:Gem::Version
107
+ version: '13.0'
108
+ - !ruby/object:Gem::Dependency
109
+ name: require_bench
110
+ requirement: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - "~>"
113
+ - !ruby/object:Gem::Version
114
+ version: '1.0'
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: 1.0.4
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.0'
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: 1.0.4
128
+ - !ruby/object:Gem::Dependency
129
+ name: appraisal2
130
+ requirement: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - "~>"
133
+ - !ruby/object:Gem::Version
134
+ version: '3.2'
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: 3.2.0
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '3.2'
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: 3.2.0
148
+ - !ruby/object:Gem::Dependency
149
+ name: kettle-test
150
+ requirement: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - "~>"
153
+ - !ruby/object:Gem::Version
154
+ version: '2.0'
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ version: 2.0.11
158
+ type: :development
159
+ prerelease: false
160
+ version_requirements: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - "~>"
163
+ - !ruby/object:Gem::Version
164
+ version: '2.0'
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: 2.0.11
168
+ - !ruby/object:Gem::Dependency
169
+ name: turbo_tests2
170
+ requirement: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - "~>"
173
+ - !ruby/object:Gem::Version
174
+ version: '3.2'
175
+ - - ">="
176
+ - !ruby/object:Gem::Version
177
+ version: 3.2.0
178
+ type: :development
179
+ prerelease: false
180
+ version_requirements: !ruby/object:Gem::Requirement
181
+ requirements:
182
+ - - "~>"
183
+ - !ruby/object:Gem::Version
184
+ version: '3.2'
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: 3.2.0
188
+ - !ruby/object:Gem::Dependency
189
+ name: ruby-progressbar
190
+ requirement: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: '1.13'
195
+ type: :development
196
+ prerelease: false
197
+ version_requirements: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - "~>"
200
+ - !ruby/object:Gem::Version
201
+ version: '1.13'
202
+ - !ruby/object:Gem::Dependency
203
+ name: stone_checksums
204
+ requirement: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - "~>"
207
+ - !ruby/object:Gem::Version
208
+ version: '1.0'
209
+ - - ">="
210
+ - !ruby/object:Gem::Version
211
+ version: 1.0.6
212
+ type: :development
213
+ prerelease: false
214
+ version_requirements: !ruby/object:Gem::Requirement
215
+ requirements:
216
+ - - "~>"
217
+ - !ruby/object:Gem::Version
218
+ version: '1.0'
219
+ - - ">="
220
+ - !ruby/object:Gem::Version
221
+ version: 1.0.6
222
+ - !ruby/object:Gem::Dependency
223
+ name: gitmoji-regex
224
+ requirement: !ruby/object:Gem::Requirement
225
+ requirements:
226
+ - - "~>"
227
+ - !ruby/object:Gem::Version
228
+ version: '2.0'
229
+ - - ">="
230
+ - !ruby/object:Gem::Version
231
+ version: 2.0.4
232
+ type: :development
233
+ prerelease: false
234
+ version_requirements: !ruby/object:Gem::Requirement
235
+ requirements:
236
+ - - "~>"
237
+ - !ruby/object:Gem::Version
238
+ version: '2.0'
239
+ - - ">="
240
+ - !ruby/object:Gem::Version
241
+ version: 2.0.4
242
+ description: "\U0001F6BF Constant deletion and reset helpers for gems that need repeatable
243
+ reloads while testing constant-backed runtime configuration."
244
+ email:
245
+ - floss@galtzo.com
246
+ executables: []
247
+ extensions: []
248
+ extra_rdoc_files: []
249
+ files:
250
+ - CHANGELOG.md
251
+ - LICENSE.md
252
+ - README.md
253
+ - lib/kettle/wash.rb
254
+ - lib/kettle/wash/version.rb
255
+ - sig/kettle/wash.rbs
256
+ homepage: https://github.com/kettle-dev/kettle-wash
257
+ licenses:
258
+ - AGPL-3.0-only
259
+ - PolyForm-Small-Business-1.0.0
260
+ - LicenseRef-Big-Time-Public-License
261
+ metadata:
262
+ homepage_uri: https://kettle-wash.galtzo.com
263
+ source_code_uri: https://github.com/kettle-dev/kettle-wash/tree/v0.1.0
264
+ changelog_uri: https://github.com/kettle-dev/kettle-wash/blob/v0.1.0/CHANGELOG.md
265
+ bug_tracker_uri: https://github.com/kettle-dev/kettle-wash/issues
266
+ documentation_uri: https://www.rubydoc.info/gems/kettle-wash/0.1.0
267
+ funding_uri: https://github.com/sponsors/pboling
268
+ wiki_uri: https://github.com/kettle-dev/kettle-wash/wiki
269
+ news_uri: https://www.railsbling.com/tags/kettle-wash
270
+ discord_uri: https://discord.gg/3qme4XHNKN
271
+ rubygems_mfa_required: 'true'
272
+ rdoc_options:
273
+ - "--title"
274
+ - "kettle-wash - \U0001F6BF Constant unloading helpers for Ruby test and reload workflows."
275
+ - "--main"
276
+ - README.md
277
+ - "--exclude"
278
+ - "^sig/"
279
+ - "--line-numbers"
280
+ - "--inline-source"
281
+ - "--quiet"
282
+ require_paths:
283
+ - lib
284
+ required_ruby_version: !ruby/object:Gem::Requirement
285
+ requirements:
286
+ - - ">="
287
+ - !ruby/object:Gem::Version
288
+ version: 3.2.0
289
+ required_rubygems_version: !ruby/object:Gem::Requirement
290
+ requirements:
291
+ - - ">="
292
+ - !ruby/object:Gem::Version
293
+ version: '0'
294
+ requirements: []
295
+ rubygems_version: 4.0.16
296
+ specification_version: 4
297
+ summary: "\U0001F6BF Constant unloading helpers for Ruby test and reload workflows."
298
+ test_files: []
metadata.gz.sig ADDED
Binary file