kettle-test 1.0.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.
data/README.md ADDED
@@ -0,0 +1,676 @@
1
+ [![Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0][🖼️galtzo-i]][🖼️galtzo-discord] [![ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5][🖼️ruby-lang-i]][🖼️ruby-lang] [![kettle-test Logo by Aboling0, CC BY-SA 4.0][🖼️kettle-test-i]][🖼️kettle-test]
2
+
3
+ [🖼️galtzo-i]: https://logos.galtzo.com/assets/images/galtzo-floss/avatar-192px.svg
4
+ [🖼️galtzo-discord]: https://discord.gg/3qme4XHNKN
5
+ [🖼️ruby-lang-i]: https://logos.galtzo.com/assets/images/ruby-lang/avatar-192px.svg
6
+ [🖼️ruby-lang]: https://www.ruby-lang.org/
7
+ [🖼️kettle-test-i]: https://logos.galtzo.com/assets/images/kettle-rb/kettle-test/avatar-192px.svg
8
+ [🖼️kettle-test]: https://github.com/kettle-rb/kettle-test
9
+
10
+ # ⌚️ Kettle::Test
11
+
12
+ [![Version][👽versioni]][👽version] [![License: MIT][📄license-img]][📄license-ref] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![Open Source Helpers][👽oss-helpi]][👽oss-help] [![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 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 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]
13
+
14
+ If ☝️ `ci_badges.map(&:color).detect { it != "green"}` [let me know][🖼️galtzo-discord], as I may have missed the [discord notification][🖼️galtzo-discord].
15
+
16
+ ---
17
+
18
+ OTOH, if `ci_badges.map(&:color).all? { it == "green"}` 👇️ send money so I can do more of this. FLOSS is now my full-time job.
19
+
20
+ [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate on Polar][🖇polar-img]][🖇polar] [![Donate to my FLOSS or refugee efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS or refugee efforts using Patreon][🖇patreon-img]][🖇patreon]
21
+
22
+ ## 🌻 Synopsis
23
+
24
+ Add to your `spec/spec_helper.rb`:
25
+
26
+ ```ruby
27
+ require "kettle/test/rspec"
28
+ ```
29
+
30
+ Now you have many powerful testing tools at your disposal, all fully [documented](#-configuration) and tested.
31
+
32
+ I expect the current release of this gem to be compatible with Ruby 2.3+,
33
+ and concordant releases of JRuby, and TruffleRuby.
34
+
35
+ | 🚚 _Amazing_ test matrix was brought to you by | 🔎 appraisal2 🔎 |
36
+ |------------------------------------------------|-------------------------------------------------------------------------------------|
37
+ | 👟 Check it out! | ✨ [github.com/appraisal-rb/appraisal2][💎appraisal2] ✨ |
38
+
39
+ ## 💡 Info you can shake a stick at
40
+
41
+ ### Federated DVCS
42
+
43
+ <details>
44
+ <summary>Find this repo on other forges (Coming soon!)</summary>
45
+
46
+ | Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
47
+ |-------------------------------------------------------|-------------------------------------------------------------------|---------------------------|--------------------------|---------------------------|--------------------------|------------------------------|
48
+ | 🧪 [kettle-rb/kettle-test on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜wiki] | 🏀 Tiny Matrix | ➖ |
49
+ | 🧊 [kettle-rb/kettle-test on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
50
+ | 🐙 [kettle-rb/kettle-test on GitHub][📜src-gh] | A Dirty Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | ➖ | 💯 Full Matrix | [💚][gh-discussions] |
51
+ | 🎮️ [Discord Server][✉️discord-invite] | [![Live Chat on Discord][✉️discord-invite-img]][✉️discord-invite] | [Let's][✉️discord-invite] | [talk][✉️discord-invite] | [about][✉️discord-invite] | [this][✉️discord-invite] | [library!][✉️discord-invite] |
52
+
53
+ </details>
54
+
55
+ [gh-discussions]: https://github.com/kettle-rb/kettle-test/discussions
56
+
57
+ ### Enterprise Support [![Tidelift](https://tidelift.com/badges/package/rubygems/kettle-test)](https://tidelift.com/subscription/pkg/rubygems-kettle-test?utm_source=rubygems-kettle-test&utm_medium=referral&utm_campaign=readme)
58
+
59
+ <details>
60
+ <summary>Need enterprise-level guarantees?</summary>
61
+
62
+ [![Get help from me on Tidelift][🏙️entsup-tidelift-img]][🏙️entsup-tidelift]
63
+
64
+ - 💡Subscribe for support guarantees covering _all_ FLOSS dependencies
65
+ - 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar]
66
+ - 💡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
67
+
68
+ Alternatively:
69
+
70
+ - [![Live Chat on Discord][✉️discord-invite-img]][✉️discord-invite]
71
+ - [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork]
72
+ - [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor]
73
+
74
+ </details>
75
+
76
+ | Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |
77
+ |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
78
+ | Works with JRuby | ![JRuby 9.1 Compat][💎jruby-9.1i] ![JRuby 9.2 Compat][💎jruby-9.2i] ![JRuby 9.3 Compat][💎jruby-9.3i] <br/> [![JRuby 9.4 Compat][💎jruby-9.4i]][🚎10-j-wf] [![JRuby 10.0 Compat][💎jruby-c-i]][🚎11-c-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf] |
79
+ | Works with Truffle Ruby | ![Truffle Ruby 22.3 Compat][💎truby-22.3i] <br/> [![Truffle Ruby 23.0 Compat][💎truby-23.0i]][🚎9-t-wf] [![Truffle Ruby 23.1 Compat][💎truby-23.1i]][🚎9-t-wf] [![Truffle Ruby 24.1 Compat][💎truby-c-i]][🚎11-c-wf] |
80
+ | 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] |
81
+ | Works with MRI Ruby 2 | ![Ruby 2.0 Compat][💎ruby-2.0i] ![Ruby 2.1 Compat][💎ruby-2.1i] ![Ruby 2.2 Compat][💎ruby-2.2i] <br/> [![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] |
82
+ | Works with MRI Ruby 1 | ![Ruby 1.9 Compat][💎ruby-1.9i] |
83
+ | 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] |
84
+ | 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] [![Wiki][📜wiki-img]][📜wiki] |
85
+ | 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] |
86
+ | 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] |
87
+ | 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] |
88
+ | 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] |
89
+ | `...` 💖 | [![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] |
90
+
91
+ ## ✨ Installation
92
+
93
+ Install the gem and add to the application's Gemfile by executing:
94
+
95
+ $ bundle add kettle-test
96
+
97
+ If bundler is not being used to manage dependencies, install the gem by executing:
98
+
99
+ $ gem install kettle-test
100
+
101
+ ### 🔒 Secure Installation
102
+
103
+ <details>
104
+ <summary>For Medium or High Security Installations</summary>
105
+
106
+ This gem is cryptographically signed, and has verifiable [SHA-256 and SHA-512][💎SHA_checksums] checksums by
107
+ [stone_checksums][💎stone_checksums]. Be sure the gem you install hasn’t been tampered with
108
+ by following the instructions below.
109
+
110
+ Add my public key (if you haven’t already, expires 2045-04-29) as a trusted certificate:
111
+
112
+ ```console
113
+ gem cert --add <(curl -Ls https://raw.github.com/galtzo-floss/certs/main/pboling.pem)
114
+ ```
115
+
116
+ You only need to do that once. Then proceed to install with:
117
+
118
+ ```console
119
+ gem install kettle-test -P HighSecurity
120
+ ```
121
+
122
+ The `HighSecurity` trust profile will verify signed gems, and not allow the installation of unsigned dependencies.
123
+
124
+ If you want to up your security game full-time:
125
+
126
+ ```console
127
+ bundle config set --global trust-policy MediumSecurity
128
+ ```
129
+
130
+ `MediumSecurity` instead of `HighSecurity` is necessary if not all the gems you use are signed.
131
+
132
+ NOTE: Be prepared to track down certs for signed gems and add them the same way you added mine.
133
+
134
+ </details>
135
+
136
+ ## ⚙️ Configuration
137
+
138
+ Add to your `spec/spec_helper.rb`:
139
+
140
+ ```ruby
141
+ require "kettle/test/rspec"
142
+ ```
143
+
144
+ That's it! Additional customizations can be done by setting environment variables.
145
+
146
+ ### Environment Variables
147
+
148
+ Below are the environment variables recognized by kettle-test. Unless otherwise specified, set values to the string "true" to enable a boolean feature, or provide the noted type.
149
+
150
+ - DEBUG (String: "true"/"false")
151
+ - Overrides default silencing for the entire run; when true, STDOUT/STDERR are not silenced by this library.
152
+ - Default: "false". If KETTLE_TEST_DEBUG is not set, DEBUG is used.
153
+ - GLOBAL_TIME_TRAVEL_TIME (String: Date/Time)
154
+ - Global start time for Timecop across examples when using time travel.
155
+ - Example: "2014-11-15" or "2014-11-15 13:45:00".
156
+ - Default: falls back to GLOBAL_TIME_TRAVEL_DATE if set, else today.
157
+ - GLOBAL_TIME_TRAVEL_DATE (String: Date)
158
+ - Alternate way to set a global date used when GLOBAL_TIME_TRAVEL_TIME is not provided.
159
+ - Default: today (Date.today.to_s).
160
+ - KETTLE_TEST_DEBUG (String: "true"/"false")
161
+ - Same as DEBUG but namespaced for this gem. Takes precedence over DEBUG.
162
+ - Default: "false".
163
+ - CI (String: "true"/"false")
164
+ - Signals a CI environment. When true, examples tagged :skip_ci are excluded.
165
+ - Also used as the default for KETTLE_TEST_SILENT when not set.
166
+ - Default: unset/empty → treated as false.
167
+ - KETTLE_TEST_SILENT (String: "true"/"false")
168
+ - Controls silencing of STDOUT/STDERR during specs (unless :check_output is used or DEBUG is true).
169
+ - Default: value of CI (true on CI, false locally unless CI=true).
170
+ - KETTLE_TEST_VERBOSE (String: "true"/"false")
171
+ - Reserved for future verbose logging toggles. Default: "false".
172
+ - KETTLE_TEST_FULL_BACKTRACE (String: "true"/"false")
173
+ - When true, enables RSpec full backtraces.
174
+ - Default: "false".
175
+ - KETTLE_TEST_RSPEC_PROFILE_EXAMPLES (Integer as String)
176
+ - When > 0, RSpec will profile the slowest N examples or example groups.
177
+ - Example: KETTLE_TEST_RSPEC_PROFILE_EXAMPLES=10
178
+ - Default: "0" (disabled).
179
+ - KETTLE_TEST_TM_SEQUENTIAL (String: "true"/"false")
180
+ - Controls Timecop sequential time machine mode for RSpec examples (see below).
181
+ - Default: "true".
182
+ - PARALLEL_TEST_FIRST_IS_1 (String: "true"/"false") and TEST_ENV_NUMBER (String)
183
+ - Used to detect parallel test runs via Kettle::Test.is_parallel_test?. Not generally required to set manually.
184
+ - Default: unset (treated as non-parallel unless provided by your parallel test runner).
185
+
186
+ ### TimeCop-RSpec
187
+
188
+ #### Global Time Travel
189
+
190
+ Using global time travel will `Timecop.travel` any example that isn't
191
+ already time traveling. I.e. example level timecop metadata will take
192
+ precedence.
193
+
194
+ ```sh
195
+ GLOBAL_TIME_TRAVEL_TIME=2014-11-15 bundle exec rspec spec/some_directory/
196
+ ```
197
+
198
+ The global time travel can also be skipped. You may want to skip
199
+ time travel when testing with some external service, such as redis,
200
+ where you can't modify time the same way as within ruby.
201
+
202
+ ```ruby
203
+ it "some example that can't time travel", :skip_global_travel do
204
+ # Time.now will be real time
205
+ end
206
+ ```
207
+
208
+ #### Regular Time Machine
209
+
210
+ ```ruby
211
+ ENV["KETTLE_TEST_TM_SEQUENTIAL"] = "false"
212
+ ```
213
+
214
+ The regular time machine will run each example at the time specified by the
215
+ RSpec metadata, or the global travel time.
216
+
217
+ #### Sequential Time Machine
218
+
219
+ ```ruby
220
+ ENV["KETTLE_TEST_TM_SEQUENTIAL"] = "true"
221
+ ```
222
+
223
+ The sequential time machine is almost the same as the regular time machine,
224
+ except that it will sometimes resume time travel.
225
+
226
+ Global travel will always resume from when the previous global traveled
227
+ example ended. E.g.
228
+ ```ruby
229
+ # GLOBAL_TIME_TRAVEL_TIME=2014-11-15 bundle exec rspec some_spec.rb
230
+
231
+ it "example 1" do
232
+ Time.now # => 2014-11-15 00:00:00
233
+ sleep 6
234
+ end
235
+
236
+ it "example 2" do
237
+ Time.now # => 2014-11-15 00:00:06 (resumed from end of previous example)
238
+ end
239
+ ```
240
+
241
+ ## 🔧 Basic Usage
242
+
243
+ ### RSpec Time Machine Tags :freeze and :travel
244
+
245
+ Timecop.travel/freeze any RSpec (describe|context|example) with
246
+ `:travel` or `:freeze` metadata.
247
+
248
+ ```ruby
249
+ # Timecop.travel
250
+ it "some description", travel: Time.new(2014, 11, 15) do
251
+ Time.now # 2014-11-15 00:00:00
252
+ sleep 6
253
+ Time.now # 2014-11-15 00:00:06 (6 seconds later)
254
+ end
255
+
256
+ # Timecop.freeze
257
+ it "some description", freeze: Time.new(2014, 11, 15) do
258
+ Time.now # 2014-11-15 00:00:00
259
+ sleep 6
260
+ Time.now # 2014-11-15 00:00:00 (Ruby's time hasn't advanced)
261
+ end
262
+ ```
263
+
264
+ Following spec's local travel will resume when specified time is the same as the
265
+ previous examples specified time. If the time is different, it will
266
+ start from the current examples specified time.
267
+ ```ruby
268
+ describe SomeUnit, travel: Time.new(2014, 11, 15) do
269
+ it "example 1" do
270
+ Time.now # => 2014-11-15 00:00:00
271
+ sleep 6
272
+ end
273
+
274
+ it "example 2" do
275
+ Time.now # => 2014-11-15 00:00:06 (resumed from end of previous example)
276
+ end
277
+
278
+ it "example 3", travel: Time.new(1982, 6, 16) do
279
+ Time.now # => 1982-06-16 00:00:00
280
+ end
281
+ end
282
+ ```
283
+
284
+ ### Stubbed ENV in examples
285
+
286
+ Use rspec-stubbed_env to safely set and restore environment variables in specs.
287
+
288
+ ```ruby
289
+ RSpec.describe("stubbed env") do
290
+ include_context "with stubbed env"
291
+
292
+ before do
293
+ stub_env("FOO" => "is bar")
294
+ end
295
+
296
+ it "uses the stubbed value" do
297
+ expect(ENV["FOO"]).to(eq("is bar"))
298
+ end
299
+ end
300
+ ```
301
+
302
+ ### Silencing output and checking output
303
+
304
+ STDOUT/STDERR are silenced by default when KETTLE_TEST_SILENT is true (defaults to true on CI). To assert output from the code under test, tag examples/groups with :check_output, or run with DEBUG=true to disable silencing globally.
305
+
306
+ ```ruby
307
+ RSpec.describe("output", :check_output) do
308
+ it "prints" do
309
+ puts "This will be visible in test output"
310
+ expect(true).to(be(true))
311
+ end
312
+ end
313
+ ```
314
+
315
+ Or run:
316
+
317
+ ```sh
318
+ DEBUG=true bundle exec rspec
319
+ ```
320
+
321
+ ### CI-only filtering
322
+
323
+ Examples or groups tagged with :skip_ci are excluded on CI (CI=true).
324
+
325
+ ```ruby
326
+ RSpec.describe("flaky external call", :skip_ci) do
327
+ it "runs locally but is skipped on CI" do
328
+ # ...
329
+ end
330
+ end
331
+ ```
332
+
333
+ ### Profile slowest examples
334
+
335
+ Set KETTLE_TEST_RSPEC_PROFILE_EXAMPLES to a positive integer to enable RSpec profiling.
336
+
337
+ ```sh
338
+ KETTLE_TEST_RSPEC_PROFILE_EXAMPLES=10 bundle exec rspec
339
+ ```
340
+
341
+ ### Full backtraces
342
+
343
+ Enable full backtraces from RSpec to aid debugging.
344
+
345
+ ```sh
346
+ KETTLE_TEST_FULL_BACKTRACE=true bundle exec rspec
347
+ ```
348
+
349
+ ## 🦷 FLOSS Funding
350
+
351
+ > How wonderful it is that nobody need wait a single moment before starting to improve the world.<br/>
352
+ >—Anne Frank
353
+
354
+ I’m driven by a passion to foster a thriving open-source community – a space where people can tackle complex problems, no matter how small. Revitalizing libraries that have fallen into disrepair, and building new libraries focused on solving real-world challenges, are my passions — totaling 79 hours of FLOSS coding over just the past seven days, a pretty regular week for me. I was recently affected by layoffs, and the tech jobs market is unwelcoming. I’m reaching out here because your support would significantly aid my efforts to provide for my family, and my farm (11 🐔 chickens, 2 🐶 dogs, 3 🐰 rabbits, 8 🐈‍ cats).
355
+
356
+ If you work at a company that uses my work, please encourage them to support me as a corporate sponsor. My work on gems you use might show up in `bundle fund`.
357
+
358
+ I’m developing a new library, [floss_funding][🖇floss-funding-gem], designed to empower open-source developers like myself to get paid for the work we do, in a sustainable way. Please give it a look.
359
+
360
+ **[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
361
+
362
+ [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Donate on PayPal][🖇paypal-img]][🖇paypal] [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate on Polar][🖇polar-img]][🖇polar] [![Donate to my FLOSS or refugee efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS or refugee efforts using Patreon][🖇patreon-img]][🖇patreon]
363
+
364
+ ## 🔐 Security
365
+
366
+ See [SECURITY.md][🔐security].
367
+
368
+ ## 🤝 Contributing
369
+
370
+ If you need some ideas of where to help, you could work on adding more code coverage,
371
+ or if it is already 💯 (see [below](#code-coverage)) check [reek](REEK), [issues][🤝gh-issues], or [PRs][🤝gh-pulls],
372
+ or use the gem and think about how it could be better.
373
+
374
+ We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it.
375
+
376
+ See [CONTRIBUTING.md][🤝contributing] for more detailed instructions.
377
+
378
+ ### 🚀 Release Instructions
379
+
380
+ See [CONTRIBUTING.md][🤝contributing].
381
+
382
+ ### Code Coverage
383
+
384
+ [![Coverage Graph][🔑codecov-g♻️]][🔑codecov]
385
+
386
+ [![Coveralls Test Coverage][🔑coveralls-img]][🔑coveralls]
387
+
388
+ [![QLTY Test Coverage][🔑qlty-covi]][🔑qlty-cov]
389
+
390
+ ### 🪇 Code of Conduct
391
+
392
+ Everyone interacting with this project's codebases, issue trackers,
393
+ chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct].
394
+
395
+ ## 🌈 Contributors
396
+
397
+ [![Contributors][🖐contributors-img]][🖐contributors]
398
+
399
+ Made with [contributors-img][🖐contrib-rocks].
400
+
401
+ Also see GitLab Contributors: [https://gitlab.com/kettle-rb/kettle-test/-/graphs/main][🚎contributors-gl]
402
+
403
+ <details>
404
+ <summary>⭐️ Star History</summary>
405
+
406
+ <a href="https://star-history.com/#kettle-rb/kettle-test&Date">
407
+ <picture>
408
+ <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=kettle-rb/kettle-test&type=Date&theme=dark" />
409
+ <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=kettle-rb/kettle-test&type=Date" />
410
+ <img alt="Star History Chart" src="https://api.star-history.com/svg?repos=kettle-rb/kettle-test&type=Date" />
411
+ </picture>
412
+ </a>
413
+
414
+ </details>
415
+
416
+ ## 📌 Versioning
417
+
418
+ This Library adheres to [![Semantic Versioning 2.0.0][📌semver-img]][📌semver].
419
+ Violations of this scheme should be reported as bugs.
420
+ Specifically, if a minor or patch version is released that breaks backward compatibility,
421
+ a new version should be immediately released that restores compatibility.
422
+ Breaking changes to the public API will only be introduced with new major versions.
423
+
424
+ > dropping support for a platform is both obviously and objectively a breaking change <br/>
425
+ >—Jordan Harband ([@ljharb](https://github.com/ljharb), maintainer of SemVer) [in SemVer issue 716][📌semver-breaking]
426
+
427
+ I understand that policy doesn't work universally ("exceptions to every rule!"),
428
+ but it is the policy here.
429
+ As such, in many cases it is good to specify a dependency on this library using
430
+ the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
431
+
432
+ For example:
433
+
434
+ ```ruby
435
+ spec.add_dependency("kettle-test", "~> 1.0")
436
+ ```
437
+
438
+ <details>
439
+ <summary>📌 Is "Platform Support" part of the public API? More details inside.</summary>
440
+
441
+ SemVer should, but doesn't explicitly, say that dropping support for specific Platforms
442
+ is a *breaking change* to an API.
443
+ It is obvious to many, but not all, and since the spec is silent, the bike shedding is endless.
444
+
445
+ To get a better understanding of how SemVer is intended to work over a project's lifetime,
446
+ read this article from the creator of SemVer:
447
+
448
+ - ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]
449
+
450
+ </details>
451
+
452
+ See [CHANGELOG.md][📌changelog] for a list of releases.
453
+
454
+ ## 📄 License
455
+
456
+ The gem is available as open source under the terms of
457
+ the [MIT License][📄license] [![License: MIT][📄license-img]][📄license-ref].
458
+ See [LICENSE.txt][📄license] for the official [Copyright Notice][📄copyright-notice-explainer].
459
+
460
+ ### © Copyright
461
+
462
+ <ul>
463
+ <li>
464
+ Copyright (c) 2025 Peter H. Boling, of
465
+ <a href="https://discord.gg/3qme4XHNKN">
466
+ Galtzo.com
467
+ <picture>
468
+ <img src="https://logos.galtzo.com/assets/images/galtzo-floss/avatar-128px-blank.svg" alt="Galtzo.com Logo (Wordless) by Aboling0, CC BY-SA 4.0" width="24">
469
+ </picture>
470
+ </a>, and kettle-test contributors.
471
+ </li>
472
+ <li>Copyright (c) 2014-2017 Zach Taylor & Avant</li>
473
+ </ul>
474
+
475
+ ## 🤑 A request for help
476
+
477
+ Maintainers have teeth, and need to pay their dentists.
478
+ After getting laid off in an RIF in March, and filled with many dozens of rejections,
479
+ I'm now spending ~80 hours a week building open source tools.
480
+ I'm hoping to be able to pay for my kids' health insurance this month,
481
+ so if you value the work I am doing, please help.
482
+ I need your support. Please consider sponsoring me.
483
+
484
+ [![Sponsor me on GitHub Sponsors][🖇sponsor-bottom-img]][🖇sponsor] 💌 [![Sponsor me on Liberapay][⛳liberapay-bottom-img]][⛳liberapay-img] 💌 [![Donate on PayPal][🖇paypal-bottom-img]][🖇paypal-img]
485
+
486
+ To say "thanks for maintaining such a great tool" 👇️ Join the Discord or ☝️ send money.
487
+
488
+ To join the community or get help 👇️ Join the Discord.
489
+
490
+ [![Live Chat on Discord][✉️discord-invite-img]][✉️discord-invite]
491
+
492
+ Thanks for RTFM. ☺️
493
+
494
+ [⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611
495
+ [⛳liberapay-bottom-img]: https://img.shields.io/liberapay/goal/pboling.svg?style=for-the-badge&logo=liberapay&color=a51611
496
+ [⛳liberapay]: https://liberapay.com/pboling/donate
497
+ [🖇sponsor-img]: https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github
498
+ [🖇sponsor-bottom-img]: https://img.shields.io/badge/Sponsor_Me!-pboling-blue?style=for-the-badge&logo=github
499
+ [🖇sponsor]: https://github.com/sponsors/pboling
500
+ [🖇polar-img]: https://img.shields.io/badge/polar-donate-a51611.svg
501
+ [🖇polar]: https://polar.sh/pboling
502
+ [🖇kofi-img]: https://img.shields.io/badge/ko--fi-✓-a51611.svg
503
+ [🖇kofi]: https://ko-fi.com/O5O86SNP4
504
+ [🖇patreon-img]: https://img.shields.io/badge/patreon-donate-a51611.svg
505
+ [🖇patreon]: https://patreon.com/galtzo
506
+ [🖇buyme-small-img]: https://img.shields.io/badge/buy_me_a_coffee-✓-a51611.svg?style=flat
507
+ [🖇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
508
+ [🖇buyme]: https://www.buymeacoffee.com/pboling
509
+ [🖇paypal-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=flat&logo=paypal
510
+ [🖇paypal-bottom-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=for-the-badge&logo=paypal&color=0A0A0A
511
+ [🖇paypal]: https://www.paypal.com/paypalme/peterboling
512
+ [🖇floss-funding.dev]: https://floss-funding.dev
513
+ [🖇floss-funding-gem]: https://github.com/galtzo-floss/floss_funding
514
+ [✉️discord-invite]: https://discord.gg/3qme4XHNKN
515
+ [✉️discord-invite-img]: https://img.shields.io/discord/1373797679469170758?style=for-the-badge
516
+
517
+ [✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
518
+ [⛳️gem-namespace]: https://github.com/kettle-rb/kettle-test
519
+ [⛳️namespace-img]: https://img.shields.io/badge/namespace-Timecop%3A%3ARspec-3C2D2D.svg?style=square&logo=ruby&logoColor=white
520
+ [⛳️gem-name]: https://rubygems.org/gems/kettle-test
521
+ [⛳️name-img]: https://img.shields.io/badge/name-timecop--rspec-3C2D2D.svg?style=square&logo=rubygems&logoColor=red
522
+ [🚂maint-blog]: http://www.railsbling.com/tags/kettle-test
523
+ [🚂maint-blog-img]: https://img.shields.io/badge/blog-railsbling-0093D0.svg?style=for-the-badge&logo=rubyonrails&logoColor=orange
524
+ [🚂maint-contact]: http://www.railsbling.com/contact
525
+ [🚂maint-contact-img]: https://img.shields.io/badge/Contact-Maintainer-0093D0.svg?style=flat&logo=rubyonrails&logoColor=red
526
+ [💖🖇linkedin]: http://www.linkedin.com/in/peterboling
527
+ [💖🖇linkedin-img]: https://img.shields.io/badge/PeterBoling-LinkedIn-0B66C2?style=flat&logo=newjapanprowrestling
528
+ [💖✌️wellfound]: https://wellfound.com/u/peter-boling/u/peter-boling
529
+ [💖✌️wellfound-img]: https://img.shields.io/badge/peter--boling-orange?style=flat&logo=wellfound
530
+ [💖💲crunchbase]: https://www.crunchbase.com/person/peter-boling
531
+ [💖💲crunchbase-img]: https://img.shields.io/badge/peter--boling-purple?style=flat&logo=crunchbase
532
+ [💖🐘ruby-mast]: https://ruby.social/@galtzo
533
+ [💖🐘ruby-mast-img]: https://img.shields.io/mastodon/follow/109447111526622197?domain=https%3A%2F%2Fruby.social&style=flat&logo=mastodon&label=Ruby%20%40galtzo
534
+ [💖🦋bluesky]: https://bsky.app/profile/galtzo.com
535
+ [💖🦋bluesky-img]: https://img.shields.io/badge/@galtzo.com-0285FF?style=flat&logo=bluesky&logoColor=white
536
+ [💖🌳linktree]: https://linktr.ee/galtzo
537
+ [💖🌳linktree-img]: https://img.shields.io/badge/galtzo-purple?style=flat&logo=linktree
538
+ [💖💁🏼‍♂️devto]: https://dev.to/galtzo
539
+ [💖💁🏼‍♂️devto-img]: https://img.shields.io/badge/dev.to-0A0A0A?style=flat&logo=devdotto&logoColor=white
540
+ [💖💁🏼‍♂️aboutme]: https://about.me/peter.boling
541
+ [💖💁🏼‍♂️aboutme-img]: https://img.shields.io/badge/about.me-0A0A0A?style=flat&logo=aboutme&logoColor=white
542
+ [💖🧊berg]: https://codeberg.org/pboling
543
+ [💖🐙hub]: https://github.org/pboling
544
+ [💖🛖hut]: https://sr.ht/~galtzo/
545
+ [💖🧪lab]: https://gitlab.com/pboling
546
+ [👨🏼‍🏫expsup-upwork]: https://www.upwork.com/freelancers/~014942e9b056abdf86?mp_source=share
547
+ [👨🏼‍🏫expsup-upwork-img]: https://img.shields.io/badge/UpWork-13544E?style=for-the-badge&logo=Upwork&logoColor=white
548
+ [👨🏼‍🏫expsup-codementor]: https://www.codementor.io/peterboling?utm_source=github&utm_medium=button&utm_term=peterboling&utm_campaign=github
549
+ [👨🏼‍🏫expsup-codementor-img]: https://img.shields.io/badge/CodeMentor-Get_Help-1abc9c?style=for-the-badge&logo=CodeMentor&logoColor=white
550
+ [🏙️entsup-tidelift]: https://tidelift.com/subscription
551
+ [🏙️entsup-tidelift-img]: https://img.shields.io/badge/Tidelift_and_Sonar-Enterprise_Support-FD3456?style=for-the-badge&logo=sonar&logoColor=white
552
+ [🏙️entsup-tidelift-sonar]: https://blog.tidelift.com/tidelift-joins-sonar
553
+ [💁🏼‍♂️peterboling]: http://www.peterboling.com
554
+ [🚂railsbling]: http://www.railsbling.com
555
+ [📜src-gl-img]: https://img.shields.io/badge/GitLab-FBA326?style=for-the-badge&logo=Gitlab&logoColor=orange
556
+ [📜src-gl]: https://gitlab.com/kettle-rb/kettle-test/
557
+ [📜src-cb-img]: https://img.shields.io/badge/CodeBerg-4893CC?style=for-the-badge&logo=CodeBerg&logoColor=blue
558
+ [📜src-cb]: https://codeberg.org/kettle-rb/kettle-test
559
+ [📜src-gh-img]: https://img.shields.io/badge/GitHub-238636?style=for-the-badge&logo=Github&logoColor=green
560
+ [📜src-gh]: https://github.com/kettle-rb/kettle-test
561
+ [📜docs-cr-rd-img]: https://img.shields.io/badge/RubyDoc-Current_Release-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
562
+ [📜docs-head-rd-img]: https://img.shields.io/badge/YARD_on_Galtzo.com-HEAD-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
563
+ [📜wiki]: https://gitlab.com/kettle-rb/kettle-test/-/wikis/home
564
+ [📜wiki-img]: https://img.shields.io/badge/wiki-examples-943CD2.svg?style=for-the-badge&logo=Wiki&logoColor=white
565
+ [👽dl-rank]: https://rubygems.org/gems/kettle-test
566
+ [👽dl-ranki]: https://img.shields.io/gem/rd/kettle-test.svg
567
+ [👽oss-help]: https://www.codetriage.com/kettle-rb/kettle-test
568
+ [👽oss-helpi]: https://www.codetriage.com/kettle-rb/kettle-test/badges/users.svg
569
+ [👽version]: https://rubygems.org/gems/kettle-test
570
+ [👽versioni]: https://img.shields.io/gem/v/kettle-test.svg
571
+ [🔑qlty-mnt]: https://qlty.sh/gh/kettle-rb/projects/kettle-test
572
+ [🔑qlty-mnti]: https://qlty.sh/gh/kettle-rb/projects/kettle-test/maintainability.svg
573
+ [🔑qlty-cov]: https://qlty.sh/gh/kettle-rb/projects/kettle-test/metrics/code?sort=coverageRating
574
+ [🔑qlty-covi]: https://qlty.sh/gh/kettle-rb/projects/kettle-test/coverage.svg
575
+ [🔑codecov]: https://codecov.io/gh/kettle-rb/kettle-test
576
+ [🔑codecovi♻️]: https://codecov.io/gh/kettle-rb/kettle-test/graph/badge.svg?token=4YOMR0SJRI
577
+ [🔑coveralls]: https://coveralls.io/github/kettle-rb/kettle-test?branch=main
578
+ [🔑coveralls-img]: https://coveralls.io/repos/github/kettle-rb/kettle-test/badge.svg?branch=main
579
+ [🖐codeQL]: https://github.com/kettle-rb/kettle-test/security/code-scanning
580
+ [🖐codeQL-img]: https://github.com/kettle-rb/kettle-test/actions/workflows/codeql-analysis.yml/badge.svg
581
+ [🚎1-an-wf]: https://github.com/kettle-rb/kettle-test/actions/workflows/ancient.yml
582
+ [🚎1-an-wfi]: https://github.com/kettle-rb/kettle-test/actions/workflows/ancient.yml/badge.svg
583
+ [🚎2-cov-wf]: https://github.com/kettle-rb/kettle-test/actions/workflows/coverage.yml
584
+ [🚎2-cov-wfi]: https://github.com/kettle-rb/kettle-test/actions/workflows/coverage.yml/badge.svg
585
+ [🚎3-hd-wf]: https://github.com/kettle-rb/kettle-test/actions/workflows/heads.yml
586
+ [🚎3-hd-wfi]: https://github.com/kettle-rb/kettle-test/actions/workflows/heads.yml/badge.svg
587
+ [🚎4-lg-wf]: https://github.com/kettle-rb/kettle-test/actions/workflows/legacy.yml
588
+ [🚎4-lg-wfi]: https://github.com/kettle-rb/kettle-test/actions/workflows/legacy.yml/badge.svg
589
+ [🚎5-st-wf]: https://github.com/kettle-rb/kettle-test/actions/workflows/style.yml
590
+ [🚎5-st-wfi]: https://github.com/kettle-rb/kettle-test/actions/workflows/style.yml/badge.svg
591
+ [🚎6-s-wf]: https://github.com/kettle-rb/kettle-test/actions/workflows/supported.yml
592
+ [🚎6-s-wfi]: https://github.com/kettle-rb/kettle-test/actions/workflows/supported.yml/badge.svg
593
+ [🚎7-us-wf]: https://github.com/kettle-rb/kettle-test/actions/workflows/unsupported.yml
594
+ [🚎7-us-wfi]: https://github.com/kettle-rb/kettle-test/actions/workflows/unsupported.yml/badge.svg
595
+ [🚎8-ho-wf]: https://github.com/kettle-rb/kettle-test/actions/workflows/hoary.yml
596
+ [🚎8-ho-wfi]: https://github.com/kettle-rb/kettle-test/actions/workflows/hoary.yml/badge.svg
597
+ [🚎9-t-wf]: https://github.com/kettle-rb/kettle-test/actions/workflows/truffle.yml
598
+ [🚎9-t-wfi]: https://github.com/kettle-rb/kettle-test/actions/workflows/truffle.yml/badge.svg
599
+ [🚎10-j-wf]: https://github.com/kettle-rb/kettle-test/actions/workflows/jruby.yml
600
+ [🚎10-j-wfi]: https://github.com/kettle-rb/kettle-test/actions/workflows/jruby.yml/badge.svg
601
+ [🚎11-c-wf]: https://github.com/kettle-rb/kettle-test/actions/workflows/current.yml
602
+ [🚎11-c-wfi]: https://github.com/kettle-rb/kettle-test/actions/workflows/current.yml/badge.svg
603
+ [🚎13-🔒️-wf]: https://github.com/kettle-rb/kettle-test/actions/workflows/locked_deps.yml
604
+ [🚎13-🔒️-wfi]: https://github.com/kettle-rb/kettle-test/actions/workflows/locked_deps.yml/badge.svg
605
+ [🚎14-🔓️-wf]: https://github.com/kettle-rb/kettle-test/actions/workflows/unlocked_deps.yml
606
+ [🚎14-🔓️-wfi]: https://github.com/kettle-rb/kettle-test/actions/workflows/unlocked_deps.yml/badge.svg
607
+ [💎ruby-1.9i]: https://img.shields.io/badge/Ruby-1.9_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=white
608
+ [💎ruby-2.0i]: https://img.shields.io/badge/Ruby-2.0_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=white
609
+ [💎ruby-2.1i]: https://img.shields.io/badge/Ruby-2.1_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=white
610
+ [💎ruby-2.2i]: https://img.shields.io/badge/Ruby-2.2_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=white
611
+ [💎ruby-2.3i]: https://img.shields.io/badge/Ruby-2.3-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
612
+ [💎ruby-2.4i]: https://img.shields.io/badge/Ruby-2.4-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
613
+ [💎ruby-2.5i]: https://img.shields.io/badge/Ruby-2.5-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
614
+ [💎ruby-2.6i]: https://img.shields.io/badge/Ruby-2.6-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
615
+ [💎ruby-2.7i]: https://img.shields.io/badge/Ruby-2.7-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
616
+ [💎ruby-3.0i]: https://img.shields.io/badge/Ruby-3.0-CC342D?style=for-the-badge&logo=ruby&logoColor=white
617
+ [💎ruby-3.1i]: https://img.shields.io/badge/Ruby-3.1-CC342D?style=for-the-badge&logo=ruby&logoColor=white
618
+ [💎ruby-3.2i]: https://img.shields.io/badge/Ruby-3.2-CC342D?style=for-the-badge&logo=ruby&logoColor=white
619
+ [💎ruby-3.3i]: https://img.shields.io/badge/Ruby-3.3-CC342D?style=for-the-badge&logo=ruby&logoColor=white
620
+ [💎ruby-c-i]: https://img.shields.io/badge/Ruby-current-CC342D?style=for-the-badge&logo=ruby&logoColor=green
621
+ [💎ruby-headi]: https://img.shields.io/badge/Ruby-HEAD-CC342D?style=for-the-badge&logo=ruby&logoColor=blue
622
+ [💎truby-22.3i]: https://img.shields.io/badge/Truffle_Ruby-22.3_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=pink
623
+ [💎truby-23.0i]: https://img.shields.io/badge/Truffle_Ruby-23.0-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
624
+ [💎truby-23.1i]: https://img.shields.io/badge/Truffle_Ruby-23.1-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
625
+ [💎truby-c-i]: https://img.shields.io/badge/Truffle_Ruby-current-34BCB1?style=for-the-badge&logo=ruby&logoColor=green
626
+ [💎truby-headi]: https://img.shields.io/badge/Truffle_Ruby-HEAD-34BCB1?style=for-the-badge&logo=ruby&logoColor=blue
627
+ [💎jruby-9.1i]: https://img.shields.io/badge/JRuby-9.1_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=red
628
+ [💎jruby-9.2i]: https://img.shields.io/badge/JRuby-9.2_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=red
629
+ [💎jruby-9.3i]: https://img.shields.io/badge/JRuby-9.3_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=red
630
+ [💎jruby-9.4i]: https://img.shields.io/badge/JRuby-9.4-FBE742?style=for-the-badge&logo=ruby&logoColor=red
631
+ [💎jruby-c-i]: https://img.shields.io/badge/JRuby-current-FBE742?style=for-the-badge&logo=ruby&logoColor=green
632
+ [💎jruby-headi]: https://img.shields.io/badge/JRuby-HEAD-FBE742?style=for-the-badge&logo=ruby&logoColor=blue
633
+ [🤝gh-issues]: https://github.com/kettle-rb/kettle-test/issues
634
+ [🤝gh-pulls]: https://github.com/kettle-rb/kettle-test/pulls
635
+ [🤝gl-issues]: https://gitlab.com/kettle-rb/kettle-test/-/issues
636
+ [🤝gl-pulls]: https://gitlab.com/kettle-rb/kettle-test/-/merge_requests
637
+ [🤝cb-issues]: https://codeberg.org/kettle-rb/kettle-test/issues
638
+ [🤝cb-pulls]: https://codeberg.org/kettle-rb/kettle-test/pulls
639
+ [🤝cb-donate]: https://donate.codeberg.org/
640
+ [🤝contributing]: CONTRIBUTING.md
641
+ [🔑codecov-g♻️]: https://codecov.io/gh/kettle-rb/kettle-test/graphs/tree.svg?token=4YOMR0SJRI
642
+ [🖐contrib-rocks]: https://contrib.rocks
643
+ [🖐contributors]: https://github.com/kettle-rb/kettle-test/graphs/contributors
644
+ [🖐contributors-img]: https://contrib.rocks/image?repo=kettle-rb/kettle-test
645
+ [🚎contributors-gl]: https://gitlab.com/kettle-rb/kettle-test/-/graphs/main
646
+ [🪇conduct]: CODE_OF_CONDUCT.md
647
+ [🪇conduct-img]: https://img.shields.io/badge/Contributor_Covenant-2.1-259D6C.svg
648
+ [📌pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint
649
+ [📌semver]: https://semver.org/spec/v2.0.0.html
650
+ [📌semver-img]: https://img.shields.io/badge/semver-2.0.0-259D6C.svg?style=flat
651
+ [📌semver-breaking]: https://github.com/semver/semver/issues/716#issuecomment-869336139
652
+ [📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html
653
+ [📌changelog]: CHANGELOG.md
654
+ [📗keep-changelog]: https://keepachangelog.com/en/1.0.0/
655
+ [📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-34495e.svg?style=flat
656
+ [📌gitmoji]:https://gitmoji.dev
657
+ [📌gitmoji-img]:https://img.shields.io/badge/gitmoji_commits-%20😜%20😍-34495e.svg?style=flat-square
658
+ [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
659
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.069-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
660
+ [🔐security]: SECURITY.md
661
+ [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
662
+ [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
663
+ [📄license]: LICENSE.txt
664
+ [📄license-ref]: https://opensource.org/licenses/MIT
665
+ [📄license-img]: https://img.shields.io/badge/License-MIT-259D6C.svg
666
+ [📄ilo-declaration]: https://www.ilo.org/declaration/lang--en/index.htm
667
+ [📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat
668
+ [🚎yard-current]: http://rubydoc.info/gems/kettle-test
669
+ [🚎yard-head]: https://rspec-stubbed-env.galtzo.com
670
+ [💎stone_checksums]: https://github.com/galtzo-floss/stone_checksums
671
+ [💎SHA_checksums]: https://gitlab.com/kettle-rb/kettle-test/-/tree/main/checksums
672
+ [💎rlts]: https://github.com/rubocop-lts/rubocop-lts
673
+ [💎rlts-img]: https://img.shields.io/badge/code_style_%26_linting-rubocop--lts-34495e.svg?plastic&logo=ruby&logoColor=white
674
+ [💎appraisal2]: https://github.com/appraisal-rb/appraisal2
675
+ [💎appraisal2-img]: https://img.shields.io/badge/appraised_by-appraisal2-34495e.svg?plastic&logo=ruby&logoColor=white
676
+ [💎d-in-dvcs]: https://railsbling.com/posts/dvcs/put_the_d_in_dvcs/