library_tree 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,518 @@
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] [![library_tree Logo by Aboling0, CC BY-SA 4.0][🖼️library_tree-i]][🖼️library_tree]
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
+ [🖼️library_tree-i]: https://logos.galtzo.com/assets/images/galtzo-floss/library_tree/avatar-192px.svg
8
+ [🖼️library_tree]: https://github.com/galtzo-floss/library_tree
9
+
10
+ # 🌲 LibraryTree
11
+
12
+ [![Version][👽versioni]][👽version] [![License: MIT][📄license-img]][📄license-ref] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![Open Source Helpers][👽oss-helpi]][👽oss-help] [![Coveralls Test Coverage][🔑coveralls-img]][🔑coveralls] [![CodeCov Test Coverage][🔑codecovi♻️]][🔑codecov] [![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
+ ---
15
+
16
+ [![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 to my FLOSS or refugee efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [→ more funding options](#FLOSS-Funding)
17
+
18
+ ## 🌻 Synopsis
19
+
20
+ Understand where modules wander off to when they are bored, in **one line of code**. It is a simple, lightweight (< 100 LOC), easy-to-use tree generator. What kind of tree? A tree representation of where a module ends up being included.
21
+
22
+ ```ruby
23
+ module MyGemLibrary
24
+ include LibraryTree::Watcher # <====== THERE IT IS! ONE LINE OF CODE!
25
+ end
26
+ ```
27
+
28
+ I will find out how far back to support in Ruby versions when this runs in CI GitHub Actions.
29
+
30
+ | 🚚 _Amazing_ test matrix was brought to you by | 🔎 appraisal2 🔎 |
31
+ |------------------------------------------------|-------------------------------------------------------------------------------------|
32
+ | 👟 Check it out! | ✨ [github.com/appraisal-rb/appraisal2][💎appraisal2] ✨ |
33
+
34
+ ## 💡 Info you can shake a stick at
35
+
36
+ ### Federated DVCS
37
+
38
+ <details>
39
+ <summary>Find this repo on other forges (Coming soon!)</summary>
40
+
41
+ | Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
42
+ |-------------------------------------------------------|-------------------------------------------------------------------|---------------------------|--------------------------|---------------------------|--------------------------|------------------------------|
43
+ | 🧪 [galtzo-floss/library_tree on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜wiki] | 🏀 Tiny Matrix | ➖ |
44
+ | 🧊 [galtzo-floss/library_tree on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
45
+ | 🐙 [galtzo-floss/library_tree on GitHub][📜src-gh] | A Dirty Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | ➖ | 💯 Full Matrix | [💚][gh-discussions] |
46
+ | 🎮️ [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] |
47
+
48
+ </details>
49
+
50
+ [gh-discussions]: https://github.com/galtzo-floss/library_tree/discussions
51
+
52
+ ### Enterprise Support [![Tidelift](https://tidelift.com/badges/package/rubygems/library_tree)](https://tidelift.com/subscription/pkg/rubygems-library_tree?utm_source=rubygems-library_tree&utm_medium=referral&utm_campaign=readme)
53
+
54
+ <details>
55
+ <summary>Need enterprise-level guarantees?</summary>
56
+
57
+ [![Get help from me on Tidelift][🏙️entsup-tidelift-img]][🏙️entsup-tidelift]
58
+
59
+ - 💡Subscribe for support guarantees covering _all_ FLOSS dependencies
60
+ - 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar]
61
+ - 💡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
62
+
63
+ Alternatively:
64
+
65
+ - [![Live Chat on Discord][✉️discord-invite-img]][✉️discord-invite]
66
+ - [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork]
67
+ - [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor]
68
+
69
+ </details>
70
+
71
+ | Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |
72
+ |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
73
+ | Works with JRuby | [![JRuby 9.1 Compat][💎jruby-9.1i]][🚎10-j-wf] [![JRuby 9.2 Compat][💎jruby-9.2i]][🚎10-j-wf] [![JRuby 9.3 Compat][💎jruby-9.3i]][🚎10-j-wf] [![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] |
74
+ | Works with Truffle Ruby | [![Truffle Ruby 22.3 Compat][💎truby-22.3i]][🚎9-t-wf] [![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] |
75
+ | 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] |
76
+ | 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] [![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] |
77
+ | Works with MRI Ruby 1 | ![Ruby 1.9 Compat][💎ruby-1.9i] |
78
+ | 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] |
79
+ | 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] |
80
+ | 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] |
81
+ | 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] |
82
+ | 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] |
83
+ | 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] |
84
+ | `...` 💖 | [![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] |
85
+
86
+ ## ✨ Installation
87
+
88
+ Install the gem and add to the application's Gemfile by executing:
89
+
90
+ $ bundle add library_tree
91
+
92
+ If bundler is not being used to manage dependencies, install the gem by executing:
93
+
94
+ $ gem install library_tree
95
+
96
+ ### 🔒 Secure Installation
97
+
98
+ <details>
99
+ <summary>For Medium or High Security Installations</summary>
100
+
101
+ This gem is cryptographically signed, and has verifiable [SHA-256 and SHA-512][💎SHA_checksums] checksums by
102
+ [stone_checksums][💎stone_checksums]. Be sure the gem you install hasn’t been tampered with
103
+ by following the instructions below.
104
+
105
+ Add my public key (if you haven’t already, expires 2045-04-29) as a trusted certificate:
106
+
107
+ ```console
108
+ gem cert --add <(curl -Ls https://raw.github.com/galtzo-floss/certs/main/pboling.pem)
109
+ ```
110
+
111
+ You only need to do that once. Then proceed to install with:
112
+
113
+ ```console
114
+ gem install library_tree -P HighSecurity
115
+ ```
116
+
117
+ The `HighSecurity` trust profile will verify signed gems, and not allow the installation of unsigned dependencies.
118
+
119
+ If you want to up your security game full-time:
120
+
121
+ ```console
122
+ bundle config set --global trust-policy MediumSecurity
123
+ ```
124
+
125
+ `MediumSecurity` instead of `HighSecurity` is necessary if not all the gems you use are signed.
126
+
127
+ NOTE: Be prepared to track down certs for signed gems and add them the same way you added mine.
128
+
129
+ </details>
130
+
131
+ ## 🔧 Basic Usage
132
+
133
+ Usage patterns:
134
+
135
+ 1. Include Watcher into another module.
136
+ ```ruby
137
+ module MyGemLibrary
138
+ module SharedFunctionality
139
+ include LibraryTree::Watcher
140
+ end
141
+ end
142
+ ```
143
+ 2. Include that other module somewhere else:
144
+ ```ruby
145
+ module MyApp
146
+ include MyGemLibrary::SharedFunctionality
147
+ end
148
+ ```
149
+ 3. That's it! If you want to see the tree, do:
150
+ ```ruby
151
+ puts LibraryTree.render
152
+ ```
153
+ 4. You're still done, but if you want more, you can watch other modules with the watcher:
154
+ ```ruby
155
+ module AnotherLibrary
156
+ include LibraryTree::Watcher
157
+ end
158
+ ```
159
+ 5. Or you can let modules that are already watched do the watching:
160
+ ```ruby
161
+ module YetAnotherLibrary
162
+ include MyGemLibrary::SharedFunctionality
163
+ end
164
+ ```
165
+ 6. Want to see the tree again, after those last changes?:
166
+ ```ruby
167
+ puts LibraryTree.render
168
+ ```
169
+ 5. What if we go actually crazy, and do more module stuff:
170
+ ```ruby
171
+ module MyApp
172
+ include YetAnotherLibrary
173
+ end
174
+ ```
175
+ 6. What do you expect to see? The render hasn't changed at all! The root node state of `YetAnotherLibrary` is already fixed, so it doesn't get made a child of `MyApp`. Load order matters, and this isn't a foolproof way to know all of the places a module gets used. This library is *very simple* and doesn't intend to be a full-fledged dependency tree, nor track dependency the way Ruby itself does.
176
+ 7. Why use it?
177
+ 1. Debug infinite recursions (maybe). This library handles them, but, again, load order matters, so maybe it won't hep?
178
+ 2. It might help you understand relationships between things in your code, or library code.
179
+
180
+ Here's something almost cool. In a Rails 8.0.2 app I have this in `config/applicaiton.rb`:
181
+ ```ruby
182
+ require_relative "boot"
183
+
184
+ require "rails/all"
185
+ ```
186
+ I patch it:
187
+ ```diff
188
+ require_relative "boot"
189
+
190
+ +require "active_support/actionable_error"
191
+ +ActiveSupport::ActionableError.send(:include, LibraryTree::Watcher)
192
+ +
193
+ require "rails/all"
194
+ ```
195
+ I run `bin/rails c` and then:
196
+ ```log
197
+ ➜ bin/rails c
198
+ Loading development environment (Rails 8.0.2)
199
+ floss-funding-dev(dev)> puts LibraryTree.render
200
+ * ActiveRecord::NoDatabaseError
201
+ * ActiveSupport::ActionableError
202
+ * ActiveRecord::PendingMigrationError
203
+ * ActiveSupport::ActionableError
204
+ => nil
205
+ ```
206
+
207
+ ActiveSupport already has a `DescendantsTracker` [module](https://api.rubyonrails.org/classes/ActiveSupport/DescendantsTracker.html) which is superceded in Ruby 3.1+ by Ruby's native `Class#subclasses`.
208
+
209
+ This is not that. This tracks up to the "including" parents and down to "including" children (when it does anything at all). Don't expect accurate results!
210
+
211
+ I'm not sure if this is useful to anyone, not even me, but I wanted to explore how it would work.
212
+
213
+ ## FLOSS Funding
214
+
215
+ > How wonderful it is that nobody need wait a single moment before starting to improve the world.<br/>
216
+ >—Anne Frank
217
+
218
+ 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).
219
+
220
+ 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`.
221
+
222
+ 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.
223
+
224
+ **[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
225
+
226
+ [![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]
227
+
228
+ ## 🔐 Security
229
+
230
+ See [SECURITY.md][🔐security].
231
+
232
+ ## 🤝 Contributing
233
+
234
+ If you need some ideas of where to help, you could work on adding more code coverage,
235
+ or if it is already 💯 (see [below](#code-coverage)) check [reek](REEK), [issues][🤝gh-issues], or [PRs][🤝gh-pulls],
236
+ or use the gem and think about how it could be better.
237
+
238
+ We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it.
239
+
240
+ See [CONTRIBUTING.md][🤝contributing] for more detailed instructions.
241
+
242
+ ### 🚀 Release Instructions
243
+
244
+ See [CONTRIBUTING.md][🤝contributing].
245
+
246
+ ### Code Coverage
247
+
248
+ [![Coverage Graph][🔑codecov-g♻️]][🔑codecov]
249
+
250
+ [![Coveralls Test Coverage][🔑coveralls-img]][🔑coveralls]
251
+
252
+ [![QLTY Test Coverage][🔑qlty-covi]][🔑qlty-cov]
253
+
254
+ ### 🪇 Code of Conduct
255
+
256
+ Everyone interacting with this project's codebases, issue trackers,
257
+ chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct].
258
+
259
+ ## 🌈 Contributors
260
+
261
+ [![Contributors][🖐contributors-img]][🖐contributors]
262
+
263
+ Made with [contributors-img][🖐contrib-rocks].
264
+
265
+ Also see GitLab Contributors: [https://gitlab.com/galtzo-floss/library_tree/-/graphs/main][🚎contributors-gl]
266
+
267
+ ## ⭐️ Star History
268
+
269
+ <a href="https://star-history.com/#galtzo-floss/library_tree&Date">
270
+ <picture>
271
+ <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=galtzo-floss/library_tree&type=Date&theme=dark" />
272
+ <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=galtzo-floss/library_tree&type=Date" />
273
+ <img alt="Star History Chart" src="https://api.star-history.com/svg?repos=galtzo-floss/library_tree&type=Date" />
274
+ </picture>
275
+ </a>
276
+
277
+ ## 📌 Versioning
278
+
279
+ This Library adheres to [![Semantic Versioning 2.0.0][📌semver-img]][📌semver].
280
+ Violations of this scheme should be reported as bugs.
281
+ Specifically, if a minor or patch version is released that breaks backward compatibility,
282
+ a new version should be immediately released that restores compatibility.
283
+ Breaking changes to the public API will only be introduced with new major versions.
284
+
285
+ > dropping support for a platform is both obviously and objectively a breaking change <br/>
286
+ >—Jordan Harband ([@ljharb](https://github.com/ljharb), maintainer of SemVer) [in SemVer issue 716][📌semver-breaking]
287
+
288
+ I understand that policy doesn't work universally ("exceptions to every rule!"),
289
+ but it is the policy here.
290
+ As such, in many cases it is good to specify a dependency on this library using
291
+ the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
292
+
293
+ For example:
294
+
295
+ ```ruby
296
+ spec.add_dependency("library_tree", "~> 1.0")
297
+ ```
298
+
299
+ <details>
300
+ <summary>📌 Is "Platform Support" part of the public API? More details inside.</summary>
301
+
302
+ SemVer should, but doesn't explicitly, say that dropping support for specific Platforms
303
+ is a *breaking change* to an API.
304
+ It is obvious to many, but not all, and since the spec is silent, the bike shedding is endless.
305
+
306
+ To get a better understanding of how SemVer is intended to work over a project's lifetime,
307
+ read this article from the creator of SemVer:
308
+
309
+ - ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]
310
+
311
+ </details>
312
+
313
+ See [CHANGELOG.md][📌changelog] for a list of releases.
314
+
315
+ ## 📄 License
316
+
317
+ The gem is available as open source under the terms of
318
+ the [MIT License][📄license] [![License: MIT][📄license-img]][📄license-ref].
319
+ See [LICENSE.txt][📄license] for the official [Copyright Notice][📄copyright-notice-explainer].
320
+
321
+ ### © Copyright
322
+
323
+ <ul>
324
+ <li>
325
+ Copyright (c) 2025 Peter H. Boling, of
326
+ <a href="https://discord.gg/3qme4XHNKN">
327
+ Galtzo.com
328
+ <picture>
329
+ <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">
330
+ </picture>
331
+ </a>, and library_tree contributors
332
+ </li>
333
+ </ul>
334
+
335
+ P.S. If you need help️ or want to say thanks, 👇 Join the Discord.
336
+
337
+ [![Live Chat on Discord][✉️discord-invite-img]][✉️discord-invite]
338
+
339
+ [⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611
340
+ [⛳liberapay]: https://liberapay.com/pboling/donate
341
+ [🖇sponsor-img]: https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github
342
+ [🖇sponsor]: https://github.com/sponsors/pboling
343
+ [🖇polar-img]: https://img.shields.io/badge/polar-donate-a51611.svg
344
+ [🖇polar]: https://polar.sh/pboling
345
+ [🖇kofi-img]: https://img.shields.io/badge/ko--fi-✓-a51611.svg
346
+ [🖇kofi]: https://ko-fi.com/O5O86SNP4
347
+ [🖇patreon-img]: https://img.shields.io/badge/patreon-donate-a51611.svg
348
+ [🖇patreon]: https://patreon.com/galtzo
349
+ [🖇buyme-small-img]: https://img.shields.io/badge/buy_me_a_coffee-✓-a51611.svg?style=flat
350
+ [🖇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
351
+ [🖇buyme]: https://www.buymeacoffee.com/pboling
352
+ [🖇paypal-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=flat&logo=paypal
353
+ [🖇paypal]: https://www.paypal.com/paypalme/peterboling
354
+ [🖇floss-funding.dev]: https://floss-funding.dev
355
+ [🖇floss-funding-gem]: https://github.com/galtzo-floss/floss_funding
356
+ [✉️discord-invite]: https://discord.gg/3qme4XHNKN
357
+ [✉️discord-invite-img]: https://img.shields.io/discord/1373797679469170758?style=for-the-badge
358
+
359
+ [✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
360
+ [⛳️gem-namespace]: https://github.com/galtzo-floss/library_tree
361
+ [⛳️namespace-img]: https://img.shields.io/badge/namespace-LibraryTree-brightgreen.svg?style=flat&logo=ruby&logoColor=white
362
+ [⛳️gem-name]: https://rubygems.org/gems/library_tree
363
+ [⛳️name-img]: https://img.shields.io/badge/name-library__tree-brightgreen.svg?style=flat&logo=rubygems&logoColor=red
364
+ [🚂maint-blog]: http://www.railsbling.com/tags/library_tree
365
+ [🚂maint-blog-img]: https://img.shields.io/badge/blog-railsbling-0093D0.svg?style=for-the-badge&logo=rubyonrails&logoColor=orange
366
+ [🚂maint-contact]: http://www.railsbling.com/contact
367
+ [🚂maint-contact-img]: https://img.shields.io/badge/Contact-Maintainer-0093D0.svg?style=flat&logo=rubyonrails&logoColor=red
368
+ [💖🖇linkedin]: http://www.linkedin.com/in/peterboling
369
+ [💖🖇linkedin-img]: https://img.shields.io/badge/PeterBoling-LinkedIn-0B66C2?style=flat&logo=newjapanprowrestling
370
+ [💖✌️wellfound]: https://wellfound.com/u/peter-boling/u/peter-boling
371
+ [💖✌️wellfound-img]: https://img.shields.io/badge/peter--boling-orange?style=flat&logo=wellfound
372
+ [💖💲crunchbase]: https://www.crunchbase.com/person/peter-boling
373
+ [💖💲crunchbase-img]: https://img.shields.io/badge/peter--boling-purple?style=flat&logo=crunchbase
374
+ [💖🐘ruby-mast]: https://ruby.social/@galtzo
375
+ [💖🐘ruby-mast-img]: https://img.shields.io/mastodon/follow/109447111526622197?domain=https%3A%2F%2Fruby.social&style=flat&logo=mastodon&label=Ruby%20%40galtzo
376
+ [💖🦋bluesky]: https://bsky.app/profile/galtzo.com
377
+ [💖🦋bluesky-img]: https://img.shields.io/badge/@galtzo.com-0285FF?style=flat&logo=bluesky&logoColor=white
378
+ [💖🌳linktree]: https://linktr.ee/galtzo
379
+ [💖🌳linktree-img]: https://img.shields.io/badge/galtzo-purple?style=flat&logo=linktree
380
+ [💖💁🏼‍♂️devto]: https://dev.to/galtzo
381
+ [💖💁🏼‍♂️devto-img]: https://img.shields.io/badge/dev.to-0A0A0A?style=flat&logo=devdotto&logoColor=white
382
+ [💖💁🏼‍♂️aboutme]: https://about.me/peter.boling
383
+ [💖💁🏼‍♂️aboutme-img]: https://img.shields.io/badge/about.me-0A0A0A?style=flat&logo=aboutme&logoColor=white
384
+ [💖🧊berg]: https://codeberg.org/pboling
385
+ [💖🐙hub]: https://github.org/pboling
386
+ [💖🛖hut]: https://sr.ht/~galtzo/
387
+ [💖🧪lab]: https://gitlab.com/pboling
388
+ [👨🏼‍🏫expsup-upwork]: https://www.upwork.com/freelancers/~014942e9b056abdf86?mp_source=share
389
+ [👨🏼‍🏫expsup-upwork-img]: https://img.shields.io/badge/UpWork-13544E?style=for-the-badge&logo=Upwork&logoColor=white
390
+ [👨🏼‍🏫expsup-codementor]: https://www.codementor.io/peterboling?utm_source=github&utm_medium=button&utm_term=peterboling&utm_campaign=github
391
+ [👨🏼‍🏫expsup-codementor-img]: https://img.shields.io/badge/CodeMentor-Get_Help-1abc9c?style=for-the-badge&logo=CodeMentor&logoColor=white
392
+ [🏙️entsup-tidelift]: https://tidelift.com/subscription
393
+ [🏙️entsup-tidelift-img]: https://img.shields.io/badge/Tidelift_and_Sonar-Enterprise_Support-FD3456?style=for-the-badge&logo=sonar&logoColor=white
394
+ [🏙️entsup-tidelift-sonar]: https://blog.tidelift.com/tidelift-joins-sonar
395
+ [💁🏼‍♂️peterboling]: http://www.peterboling.com
396
+ [🚂railsbling]: http://www.railsbling.com
397
+ [📜src-gl-img]: https://img.shields.io/badge/GitLab-FBA326?style=for-the-badge&logo=Gitlab&logoColor=orange
398
+ [📜src-gl]: https://gitlab.com/galtzo-floss/library_tree/
399
+ [📜src-cb-img]: https://img.shields.io/badge/CodeBerg-4893CC?style=for-the-badge&logo=CodeBerg&logoColor=blue
400
+ [📜src-cb]: https://codeberg.org/galtzo-floss/library_tree
401
+ [📜src-gh-img]: https://img.shields.io/badge/GitHub-238636?style=for-the-badge&logo=Github&logoColor=green
402
+ [📜src-gh]: https://github.com/galtzo-floss/library_tree
403
+ [📜docs-cr-rd-img]: https://img.shields.io/badge/RubyDoc-Current_Release-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
404
+ [📜docs-head-rd-img]: https://img.shields.io/badge/YARD_on_Galtzo.com-HEAD-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
405
+ [📜wiki]: https://gitlab.com/galtzo-floss/library_tree/-/wikis/home
406
+ [📜wiki-img]: https://img.shields.io/badge/wiki-examples-943CD2.svg?style=for-the-badge&logo=Wiki&logoColor=white
407
+ [👽dl-rank]: https://rubygems.org/gems/library_tree
408
+ [👽dl-ranki]: https://img.shields.io/gem/rd/library_tree.svg
409
+ [👽oss-help]: https://www.codetriage.com/galtzo-floss/library_tree
410
+ [👽oss-helpi]: https://www.codetriage.com/galtzo-floss/library_tree/badges/users.svg
411
+ [👽version]: https://rubygems.org/gems/library_tree
412
+ [👽versioni]: https://img.shields.io/gem/v/library_tree.svg
413
+ [🔑qlty-mnt]: https://qlty.sh/gh/galtzo-floss/projects/library_tree
414
+ [🔑qlty-mnti]: https://qlty.sh/gh/galtzo-floss/projects/library_tree/maintainability.svg
415
+ [🔑qlty-cov]: https://qlty.sh/gh/galtzo-floss/projects/library_tree/metrics/code?sort=coverageRating
416
+ [🔑qlty-covi]: https://qlty.sh/gh/galtzo-floss/projects/library_tree/coverage.svg
417
+ [🔑codecov]: https://codecov.io/gh/galtzo-floss/library_tree
418
+ [🔑codecovi♻️]: https://codecov.io/gh/galtzo-floss/library_tree/graph/badge.svg?token=hRnUCPqxMu
419
+ [🔑coveralls]: https://coveralls.io/github/galtzo-floss/library_tree?branch=main
420
+ [🔑coveralls-img]: https://coveralls.io/repos/github/galtzo-floss/library_tree/badge.svg?branch=main
421
+ [🖐codeQL]: https://github.com/galtzo-floss/library_tree/security/code-scanning
422
+ [🖐codeQL-img]: https://github.com/galtzo-floss/library_tree/actions/workflows/codeql-analysis.yml/badge.svg
423
+ [🚎1-an-wf]: https://github.com/galtzo-floss/library_tree/actions/workflows/ancient.yml
424
+ [🚎1-an-wfi]: https://github.com/galtzo-floss/library_tree/actions/workflows/ancient.yml/badge.svg
425
+ [🚎2-cov-wf]: https://github.com/galtzo-floss/library_tree/actions/workflows/coverage.yml
426
+ [🚎2-cov-wfi]: https://github.com/galtzo-floss/library_tree/actions/workflows/coverage.yml/badge.svg
427
+ [🚎3-hd-wf]: https://github.com/galtzo-floss/library_tree/actions/workflows/heads.yml
428
+ [🚎3-hd-wfi]: https://github.com/galtzo-floss/library_tree/actions/workflows/heads.yml/badge.svg
429
+ [🚎4-lg-wf]: https://github.com/galtzo-floss/library_tree/actions/workflows/legacy.yml
430
+ [🚎4-lg-wfi]: https://github.com/galtzo-floss/library_tree/actions/workflows/legacy.yml/badge.svg
431
+ [🚎5-st-wf]: https://github.com/galtzo-floss/library_tree/actions/workflows/style.yml
432
+ [🚎5-st-wfi]: https://github.com/galtzo-floss/library_tree/actions/workflows/style.yml/badge.svg
433
+ [🚎6-s-wf]: https://github.com/galtzo-floss/library_tree/actions/workflows/supported.yml
434
+ [🚎6-s-wfi]: https://github.com/galtzo-floss/library_tree/actions/workflows/supported.yml/badge.svg
435
+ [🚎7-us-wf]: https://github.com/galtzo-floss/library_tree/actions/workflows/unsupported.yml
436
+ [🚎7-us-wfi]: https://github.com/galtzo-floss/library_tree/actions/workflows/unsupported.yml/badge.svg
437
+ [🚎8-ho-wf]: https://github.com/galtzo-floss/library_tree/actions/workflows/hoary.yml
438
+ [🚎8-ho-wfi]: https://github.com/galtzo-floss/library_tree/actions/workflows/hoary.yml/badge.svg
439
+ [🚎9-t-wf]: https://github.com/galtzo-floss/library_tree/actions/workflows/truffle.yml
440
+ [🚎9-t-wfi]: https://github.com/galtzo-floss/library_tree/actions/workflows/truffle.yml/badge.svg
441
+ [🚎10-j-wf]: https://github.com/galtzo-floss/library_tree/actions/workflows/jruby.yml
442
+ [🚎10-j-wfi]: https://github.com/galtzo-floss/library_tree/actions/workflows/jruby.yml/badge.svg
443
+ [🚎11-c-wf]: https://github.com/galtzo-floss/library_tree/actions/workflows/current.yml
444
+ [🚎11-c-wfi]: https://github.com/galtzo-floss/library_tree/actions/workflows/current.yml/badge.svg
445
+ [🚎13-🔒️-wf]: https://github.com/galtzo-floss/library_tree/actions/workflows/deps_locked.yml
446
+ [🚎13-🔒️-wfi]: https://github.com/galtzo-floss/library_tree/actions/workflows/deps_locked.yml/badge.svg
447
+ [🚎14-🔓️-wf]: https://github.com/galtzo-floss/library_tree/actions/workflows/deps_unlocked.yml
448
+ [🚎14-🔓️-wfi]: https://github.com/galtzo-floss/library_tree/actions/workflows/deps_unlocked.yml/badge.svg
449
+ [💎ruby-1.9i]: https://img.shields.io/badge/Ruby-1.9-412BD3?style=for-the-badge&logo=ruby&logoColor=white
450
+ [💎ruby-2.0i]: https://img.shields.io/badge/Ruby-2.0-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
451
+ [💎ruby-2.1i]: https://img.shields.io/badge/Ruby-2.1-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
452
+ [💎ruby-2.2i]: https://img.shields.io/badge/Ruby-2.2-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
453
+ [💎ruby-2.3i]: https://img.shields.io/badge/Ruby-2.3-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
454
+ [💎ruby-2.4i]: https://img.shields.io/badge/Ruby-2.4-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
455
+ [💎ruby-2.5i]: https://img.shields.io/badge/Ruby-2.5-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
456
+ [💎ruby-2.6i]: https://img.shields.io/badge/Ruby-2.6-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
457
+ [💎ruby-2.7i]: https://img.shields.io/badge/Ruby-2.7-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
458
+ [💎ruby-3.0i]: https://img.shields.io/badge/Ruby-3.0-CC342D?style=for-the-badge&logo=ruby&logoColor=white
459
+ [💎ruby-3.1i]: https://img.shields.io/badge/Ruby-3.1-CC342D?style=for-the-badge&logo=ruby&logoColor=white
460
+ [💎ruby-3.2i]: https://img.shields.io/badge/Ruby-3.2-CC342D?style=for-the-badge&logo=ruby&logoColor=white
461
+ [💎ruby-3.3i]: https://img.shields.io/badge/Ruby-3.3-CC342D?style=for-the-badge&logo=ruby&logoColor=white
462
+ [💎ruby-c-i]: https://img.shields.io/badge/Ruby-current-CC342D?style=for-the-badge&logo=ruby&logoColor=green
463
+ [💎ruby-headi]: https://img.shields.io/badge/Ruby-HEAD-CC342D?style=for-the-badge&logo=ruby&logoColor=blue
464
+ [💎truby-22.3i]: https://img.shields.io/badge/Truffle_Ruby-22.3-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
465
+ [💎truby-23.0i]: https://img.shields.io/badge/Truffle_Ruby-23.0-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
466
+ [💎truby-23.1i]: https://img.shields.io/badge/Truffle_Ruby-23.1-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
467
+ [💎truby-c-i]: https://img.shields.io/badge/Truffle_Ruby-current-34BCB1?style=for-the-badge&logo=ruby&logoColor=green
468
+ [💎truby-headi]: https://img.shields.io/badge/Truffle_Ruby-HEAD-34BCB1?style=for-the-badge&logo=ruby&logoColor=blue
469
+ [💎jruby-9.1i]: https://img.shields.io/badge/JRuby-9.1-FBE742?style=for-the-badge&logo=ruby&logoColor=red
470
+ [💎jruby-9.2i]: https://img.shields.io/badge/JRuby-9.2-FBE742?style=for-the-badge&logo=ruby&logoColor=red
471
+ [💎jruby-9.3i]: https://img.shields.io/badge/JRuby-9.3-FBE742?style=for-the-badge&logo=ruby&logoColor=red
472
+ [💎jruby-9.4i]: https://img.shields.io/badge/JRuby-9.4-FBE742?style=for-the-badge&logo=ruby&logoColor=red
473
+ [💎jruby-c-i]: https://img.shields.io/badge/JRuby-current-FBE742?style=for-the-badge&logo=ruby&logoColor=green
474
+ [💎jruby-headi]: https://img.shields.io/badge/JRuby-HEAD-FBE742?style=for-the-badge&logo=ruby&logoColor=blue
475
+ [🤝gh-issues]: https://github.com/galtzo-floss/library_tree/issues
476
+ [🤝gh-pulls]: https://github.com/galtzo-floss/library_tree/pulls
477
+ [🤝gl-issues]: https://gitlab.com/galtzo-floss/library_tree/-/issues
478
+ [🤝gl-pulls]: https://gitlab.com/galtzo-floss/library_tree/-/merge_requests
479
+ [🤝cb-issues]: https://codeberg.org/galtzo-floss/library_tree/issues
480
+ [🤝cb-pulls]: https://codeberg.org/galtzo-floss/library_tree/pulls
481
+ [🤝cb-donate]: https://donate.codeberg.org/
482
+ [🤝contributing]: CONTRIBUTING.md
483
+ [🔑codecov-g♻️]: https://codecov.io/gh/galtzo-floss/library_tree/graphs/tree.svg?token=hRnUCPqxMu
484
+ [🖐contrib-rocks]: https://contrib.rocks
485
+ [🖐contributors]: https://github.com/galtzo-floss/library_tree/graphs/contributors
486
+ [🖐contributors-img]: https://contrib.rocks/image?repo=galtzo-floss/library_tree
487
+ [🚎contributors-gl]: https://gitlab.com/galtzo-floss/library_tree/-/graphs/main
488
+ [🪇conduct]: CODE_OF_CONDUCT.md
489
+ [🪇conduct-img]: https://img.shields.io/badge/Contributor_Covenant-2.1-259D6C.svg
490
+ [📌pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint
491
+ [📌semver]: https://semver.org/spec/v2.0.0.html
492
+ [📌semver-img]: https://img.shields.io/badge/semver-2.0.0-259D6C.svg?style=flat
493
+ [📌semver-breaking]: https://github.com/semver/semver/issues/716#issuecomment-869336139
494
+ [📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html
495
+ [📌changelog]: CHANGELOG.md
496
+ [📗keep-changelog]: https://keepachangelog.com/en/1.0.0/
497
+ [📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-34495e.svg?style=flat
498
+ [📌gitmoji]:https://gitmoji.dev
499
+ [📌gitmoji-img]:https://img.shields.io/badge/gitmoji_commits-%20😜%20😍-34495e.svg?style=flat-square
500
+ [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
501
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.094-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
502
+ [🔐security]: SECURITY.md
503
+ [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
504
+ [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
505
+ [📄license]: LICENSE.txt
506
+ [📄license-ref]: https://opensource.org/licenses/MIT
507
+ [📄license-img]: https://img.shields.io/badge/License-MIT-259D6C.svg
508
+ [📄ilo-declaration]: https://www.ilo.org/declaration/lang--en/index.htm
509
+ [📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat
510
+ [🚎yard-current]: http://rubydoc.info/gems/library_tree
511
+ [🚎yard-head]: https://rspec-stubbed-env.galtzo.com
512
+ [💎stone_checksums]: https://github.com/galtzo-floss/stone_checksums
513
+ [💎SHA_checksums]: https://gitlab.com/galtzo-floss/library_tree/-/tree/main/checksums
514
+ [💎rlts]: https://github.com/rubocop-lts/rubocop-lts
515
+ [💎rlts-img]: https://img.shields.io/badge/code_style_%26_linting-rubocop--lts-34495e.svg?plastic&logo=ruby&logoColor=white
516
+ [💎appraisal2]: https://github.com/appraisal-rb/appraisal2
517
+ [💎appraisal2-img]: https://img.shields.io/badge/appraised_by-appraisal2-34495e.svg?plastic&logo=ruby&logoColor=white
518
+ [💎d-in-dvcs]: https://railsbling.com/posts/dvcs/put_the_d_in_dvcs/
data/REEK ADDED
File without changes
data/RUBOCOP.md ADDED
@@ -0,0 +1,60 @@
1
+ # RuboCop Usage Guide
2
+
3
+ ## Overview
4
+
5
+ A tale of two RuboCop plugin gems.
6
+
7
+ ### RuboCop Gradual
8
+
9
+ This project uses `rubocop_gradual` instead of vanilla RuboCop for code style checking. The `rubocop_gradual` tool allows for gradual adoption of RuboCop rules by tracking violations in a lock file.
10
+
11
+ ### RuboCop LTS
12
+
13
+ This project uses `rubocop-lts` to ensure, on a best-effort basis, compatibility with Ruby >= 1.9.2.
14
+ RuboCop rules are meticulously configured by the `rubocop-lts` family of gems to ensure that a project is compatible with a specific version of Ruby. See: https://rubocop-lts.gitlab.io for more.
15
+
16
+ ## Checking RuboCop Violations
17
+
18
+ To check for RuboCop violations in this project, always use:
19
+
20
+ ```bash
21
+ bundle exec rake rubocop_gradual:check
22
+ ```
23
+
24
+ **Do not use** the standard RuboCop commands like:
25
+ - `bundle exec rubocop`
26
+ - `rubocop`
27
+
28
+ ## Understanding the Lock File
29
+
30
+ The `.rubocop_gradual.lock` file tracks all current RuboCop violations in the project. This allows the team to:
31
+
32
+ 1. Prevent new violations while gradually fixing existing ones
33
+ 2. Track progress on code style improvements
34
+ 3. Ensure CI builds don't fail due to pre-existing violations
35
+
36
+ ## Common Commands
37
+
38
+ - **Check violations**
39
+ - `bundle exec rake rubocop_gradual`
40
+ - `bundle exec rake rubocop_gradual:check`
41
+ - **(Safe) Autocorrect violations, and update lockfile if no new violations**
42
+ - `bundle exec rake rubocop_gradual:autocorrect`
43
+ - **Force update the lock file (w/o autocorrect) to match violations present in code**
44
+ - `bundle exec rake rubocop_gradual:force_update`
45
+
46
+ ## Workflow
47
+
48
+ 1. Before submitting a PR, run `bundle exec rake rubocop_gradual:autocorrect`
49
+ a. or just the default `bundle exec rake`, as autocorrection is a pre-requisite of the default task.
50
+ 2. If there are new violations, either:
51
+ - Fix them in your code
52
+ - Run `bundle exec rake rubocop_gradual:force_update` to update the lock file (only for violations you can't fix immediately)
53
+ 3. Commit the updated `.rubocop_gradual.lock` file along with your changes
54
+
55
+ ## Benefits of rubocop_gradual
56
+
57
+ - Allows incremental adoption of code style rules
58
+ - Prevents CI failures due to pre-existing violations
59
+ - Provides a clear record of code style debt
60
+ - Enables focused efforts on improving code quality over time
data/SECURITY.md ADDED
@@ -0,0 +1,21 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ | Version | Supported |
6
+ |----------|-----------|
7
+ | 1.latest | ✅ |
8
+
9
+ ## Security contact information
10
+
11
+ To report a security vulnerability, please use the
12
+ [Tidelift security contact](https://tidelift.com/security).
13
+ Tidelift will coordinate the fix and disclosure.
14
+
15
+ ## Additional Support
16
+
17
+ If you are interested in support for versions older than the latest release,
18
+ please consider sponsoring the project / maintainer @ https://liberapay.com/pboling/donate,
19
+ or find other sponsorship links in the [README].
20
+
21
+ [README]: README.md