yaml-merge 7.0.0 → 7.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39fe59fba26814f205fb26d2d3c0e09ec1a34a308bfe59c0c6ce74f046468711
4
- data.tar.gz: dc2cdbb601a492791ba3da595aa9ec814d543428bddcbb1e0d2bdaa5cc93070c
3
+ metadata.gz: 4c26a79265545e7b520e68b2d4c68c5462968352f99b7bcd084a7135648cfc72
4
+ data.tar.gz: '092b5b792e8e73c4deab1ac3daca37171b8a3b65ae78917369ced3c46536f4d1'
5
5
  SHA512:
6
- metadata.gz: e87f09daeb658603e7727073b4bc6d7b8ca5b7d1de4b8e4af26ed6a9c7dc65b52d08541db2c50c53bab791e01021d14b04a1ae95dd2e573428211b08e6d279cc
7
- data.tar.gz: 7c0d7b2f31a4a721385218ada4ad9fe915e041fd03e4f1e9777d07a38f3ebbe1592ee01b61e666a5805ca250440284845b68007de7c780b05e520d67f3c99ef4
6
+ metadata.gz: 2cc02e011d243ac5c3514df795144d5934b0ce4c144c92f19f946a5e0773c4ecdd97da17218bbfb224fd925e40328c84d64ebea18f7741fc6f5998e5021dc5b2
7
+ data.tar.gz: f2e12622a2ea98eca51165bc28dbe1db6e58c0e9ec5bd3ad115b7be4c075b44787c0cbc3ee4c4315527c44dcf22e13f87932a0163ad1fad6d6038a1f27162bf3
checksums.yaml.gz.sig CHANGED
Binary file
data/LICENSE.md ADDED
@@ -0,0 +1,13 @@
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](https://github.com/structuredmerge/structuredmerge-ruby/blob/main/AGPL-3.0-only.md)
7
+ - [PolyForm-Small-Business-1.0.0](https://github.com/structuredmerge/structuredmerge-ruby/blob/main/PolyForm-Small-Business-1.0.0.md)
8
+
9
+ If none of the above licenses fit your use case, please [contact us](mailto:floss@galtzo.com) to discuss a custom commercial license.
10
+
11
+ ## Copyright Notice
12
+
13
+ - Required Notice: Copyright (c) 2026 Peter H. Boling
data/README.md ADDED
@@ -0,0 +1,307 @@
1
+ <a href="https://github.com/structuredmerge"><img alt="structuredmerge Logo by GitHub" src="https://github.com/structuredmerge.png?size=192" width="14%" align="right"/></a>
2
+
3
+ # ☯️ Yaml::Merge
4
+
5
+ [![Version][👽versioni]][👽version] [![Ruby Users Forum][✉️ruby-forum-top-img]][✉️ruby-forum] [![GitHub tag (latest SemVer)][⛳️tag-img]][⛳️tag] [![License: AGPL-3.0-only OR PolyForm-Small-Business-1.0.0][📄license-img]][📄license] [![Total downloads][👽dl-ranki]][👽dl-rank] [![CI Current][🚎11-c-wfi]][🚎11-c-wf]
6
+
7
+ `if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know on Discord][✉️discord-invite] or [RubyForum][✉️ruby-forum], as I may have missed the notification.
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
+ [![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
+ `Yaml::Merge` is the canonical YAML family package. It is the YAML substrate for
25
+ StructuredMerge Ruby: it registers the tree-sitter YAML path and should own the
26
+ shared YAML merge behavior used by all YAML backends, including `psych-merge`.
27
+ YAML parsing and backend selection enter through `tree_haver`; source-preserving
28
+ partial document insertion, replacement, and removal should enter through
29
+ `ast-crispr`; merge orchestration should use `ast-merge`.
30
+
31
+ Direct parser calls in YAML merge behavior are a smell. Tree-sitter YAML details
32
+ belong behind the TreeHaver backend path, and Psych details belong behind the
33
+ Psych TreeHaver backend. YAML-family code should operate on normalized owners,
34
+ ranges, comments, and edit plans rather than native Ruby Hash/Array round-trips.
35
+
36
+ ### Key Features
37
+
38
+ - YAML mapping-root validation.
39
+ - Backend feature profiles for the shared language-pack parser.
40
+ - Path-based owner matching for mapping entries.
41
+ - Shared YAML-family merge semantics for provider gems such as `psych-merge`.
42
+ - Destination-wins array policy.
43
+ - Hash result API for fixture runners and higher-level tools.
44
+
45
+ ## 💡 Info you can shake a stick at
46
+
47
+ | Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |
48
+ |-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
49
+ | Works with MRI Ruby 4 | [![Ruby current Compat][💎ruby-c-i]][🚎11-c-wf]|
50
+ | Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![Get help from RubyForum][✉️ruby-forum-img]][✉️ruby-forum] [![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][📄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 4.0.0+, and concordant releases of JRuby, and TruffleRuby.
61
+ CI workflows and Appraisals are generated for MRI Ruby 4.0.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 | Total downloads |
74
+ |-----|--------|------|---------------------|
75
+ | [appraisal2](https://clickgems.clickhouse.com/dashboard/appraisal2) | [GitHub](https://github.com/appraisal-rb/appraisal2) | multi-dependency Appraisal matrix generation | [![Total downloads for appraisal2](https://img.shields.io/gem/dt/appraisal2.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/appraisal2) |
76
+ | [appraisal2-rubocop](https://clickgems.clickhouse.com/dashboard/appraisal2-rubocop) | [GitHub](https://github.com/appraisal-rb/appraisal2-rubocop) | RuboCop Appraisal generator integration | [![Total downloads for appraisal2-rubocop](https://img.shields.io/gem/dt/appraisal2-rubocop.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/appraisal2-rubocop) |
77
+ | [kettle-dev](https://clickgems.clickhouse.com/dashboard/kettle-dev) | [GitHub](https://github.com/kettle-dev/kettle-dev) | development, release, and CI workflow tooling | [![Total downloads for kettle-dev](https://img.shields.io/gem/dt/kettle-dev.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/kettle-dev) |
78
+ | [kettle-jem](https://clickgems.clickhouse.com/dashboard/kettle-jem) | [GitHub](https://github.com/kettle-dev/kettle-jem) | Appraisals & CI workflow templates | [![Total downloads for kettle-jem](https://img.shields.io/gem/dt/kettle-jem.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/kettle-jem) |
79
+ | [kettle-soup-cover](https://clickgems.clickhouse.com/dashboard/kettle-soup-cover) | [GitHub](https://github.com/kettle-dev/kettle-soup-cover) | SimpleCov coverage policy and reporting | [![Total downloads for kettle-soup-cover](https://img.shields.io/gem/dt/kettle-soup-cover.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/kettle-soup-cover) |
80
+ | [kettle-test](https://clickgems.clickhouse.com/dashboard/kettle-test) | [GitHub](https://github.com/kettle-dev/kettle-test) | standard test runner and coverage harness | [![Total downloads for kettle-test](https://img.shields.io/gem/dt/kettle-test.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/kettle-test) |
81
+ | [rubocop-lts](https://clickgems.clickhouse.com/dashboard/rubocop-lts) | [GitHub](https://github.com/rubocop-lts/rubocop-lts) | Ruby-version-aware linting | [![Total downloads for rubocop-lts](https://img.shields.io/gem/dt/rubocop-lts.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/rubocop-lts) |
82
+ | [turbo_tests2](https://clickgems.clickhouse.com/dashboard/turbo_tests2) | [GitHub](https://github.com/galtzo-floss/turbo_tests2) | parallel test execution | [![Total downloads for turbo_tests2](https://img.shields.io/gem/dt/turbo_tests2.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/turbo_tests2) |
83
+
84
+ </details>
85
+
86
+ ## ✨ Installation
87
+
88
+ Install the gem and add to the application's Gemfile by executing:
89
+
90
+ ```console
91
+ bundle add yaml-merge
92
+ ```
93
+
94
+ If bundler is not being used to manage dependencies, install the gem by executing:
95
+
96
+ ```console
97
+ gem install yaml-merge
98
+ ```
99
+
100
+ ## ⚙️ Configuration
101
+
102
+ `Yaml::Merge` exposes module-level functions rather than a mutable global configuration object.
103
+
104
+ ```ruby
105
+ profile = Yaml::Merge.yaml_backend_feature_profile
106
+ context = Yaml::Merge.yaml_plan_context
107
+ ```
108
+
109
+ Pass `backend:` when calling `parse_yaml`, `merge_yaml`, or the profile helpers if you need to assert a specific backend. Unsupported backends return structured diagnostics instead of silently falling back.
110
+
111
+ ## 🔧 Basic Usage
112
+
113
+ ```ruby
114
+ require "yaml/merge"
115
+
116
+ result = Yaml::Merge.merge_yaml(
117
+ File.read("template.yml"),
118
+ File.read("config.yml"),
119
+ "yaml",
120
+ )
121
+
122
+ abort result.fetch(:diagnostics).inspect unless result.fetch(:ok)
123
+ File.write("config.yml", result.fetch(:output))
124
+ ```
125
+
126
+ Most module-level merge methods return a Hash with `:ok`, `:diagnostics`, `:output`, and `:policies`. Check `:ok` before writing the result; diagnostics are structured for CI output and fixture conformance reports.
127
+
128
+ ## 🔐 Security
129
+
130
+ See [SECURITY.md][🔐security].
131
+
132
+ ## 🤝 Contributing
133
+
134
+ If you need some ideas of where to help, you could work on adding more code coverage,
135
+ or if it is already 💯 (see [below](#code-coverage)) check [issues][🤝gh-issues] or [PRs][🤝gh-pulls],
136
+ or use the gem and think about how it could be better.
137
+
138
+ We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it.
139
+
140
+ See [CONTRIBUTING.md][🤝contributing] for more detailed instructions.
141
+
142
+ ### Code Coverage
143
+
144
+ <details markdown="1">
145
+ <summary>Coverage service badges</summary>
146
+
147
+ </details>
148
+
149
+ ## 📌 Versioning
150
+
151
+ This library follows [![Semantic Versioning 2.0.0][📌semver-img]][📌semver] for its public API where practical.
152
+ For most applications, prefer the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
153
+
154
+ For example:
155
+
156
+ ```ruby
157
+ spec.add_dependency("yaml-merge", "~> 7.0")
158
+ ```
159
+
160
+ <details markdown="1">
161
+ <summary>📌 Is "Platform Support" part of the public API? More details inside.</summary>
162
+
163
+ Dropping support for a platform can be a breaking change for affected users.
164
+ If a release changes supported platforms, it should be called out clearly in the changelog and versioned with that impact in mind.
165
+
166
+ To get a better understanding of how SemVer is intended to work over a project's lifetime,
167
+ read this article from the creator of SemVer:
168
+
169
+ - ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]
170
+
171
+ </details>
172
+
173
+ See [CHANGELOG.md][📌changelog] for a list of releases.
174
+
175
+ ## 📄 License
176
+
177
+ The gem is available under the following licenses: [AGPL-3.0-only](https://github.com/structuredmerge/structuredmerge-ruby/blob/main/AGPL-3.0-only.md), [PolyForm-Small-Business-1.0.0](https://github.com/structuredmerge/structuredmerge-ruby/blob/main/PolyForm-Small-Business-1.0.0.md).
178
+ See [LICENSE.md][📄license] for details.
179
+
180
+ If none of the available licenses suit your use case, please [contact us](mailto:floss@galtzo.com) to discuss a custom commercial license.
181
+
182
+ [⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611&style=flat
183
+ [⛳liberapay-bottom-img]: https://img.shields.io/liberapay/goal/pboling.svg?style=for-the-badge&logo=liberapay&color=a51611
184
+ [⛳liberapay]: https://liberapay.com/pboling/donate
185
+ [🖇sponsor-img]: https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github
186
+ [🖇sponsor-bottom-img]: https://img.shields.io/badge/Sponsor_Me!-pboling-blue?style=for-the-badge&logo=github
187
+ [🖇sponsor]: https://github.com/sponsors/pboling
188
+ [🖇kofi-img]: https://img.shields.io/badge/ko--fi-%E2%9C%93-a51611.svg?style=flat
189
+ [🖇kofi]: https://ko-fi.com/pboling
190
+ [🖇buyme-small-img]: https://img.shields.io/badge/buy_me_a_coffee-%E2%9C%93-a51611.svg?style=flat
191
+ [🖇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
192
+ [🖇buyme]: https://www.buymeacoffee.com/pboling
193
+ [🖇paypal-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=flat&logo=paypal
194
+ [🖇paypal-bottom-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=for-the-badge&logo=paypal&color=0A0A0A
195
+ [🖇paypal]: https://www.paypal.com/paypalme/peterboling
196
+ [🖇floss-funding.dev]: https://floss-funding.dev
197
+ [🖇floss-funding-gem]: https://github.com/galtzo-floss/floss_funding
198
+ [✉️discord-invite]: https://discord.gg/3qme4XHNKN
199
+ [✉️discord-invite-img-ftb]: https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord
200
+ [✉️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
201
+ [✉️ruby-friends]: https://app.daily.dev/squads/rubyfriends
202
+ [✉️ruby-forum-top-img]: https://img.shields.io/discourse/topics?server=https%3A%2F%2Fwww.rubyforum.org&style=flat&logo=discourse&label=Ruby%20Users%20Forum
203
+ [✉️ruby-forum-img]: https://img.shields.io/discourse/topics?server=https%3A%2F%2Fwww.rubyforum.org&style=for-the-badge&logo=discourse&label=Ruby%20Users%20Forum
204
+ [✉️ruby-forum]: https://www.rubyforum.org/tag/structuredmerge
205
+ [✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
206
+ [⛳️gem-namespace]: https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/yaml-merge
207
+ [⛳️namespace-img]: https://img.shields.io/badge/namespace-Yaml::Merge-3C2D2D.svg?style=square&logo=ruby&logoColor=white
208
+ [⛳️gem-name]: https://clickgems.clickhouse.com/dashboard/yaml-merge
209
+ [⛳️name-img]: https://img.shields.io/badge/name-yaml--merge-3C2D2D.svg?style=square&logo=rubygems&logoColor=red
210
+ [⛳️tag-img]: https://img.shields.io/github/tag/structuredmerge/structuredmerge-ruby.svg
211
+ [⛳️tag]: https://github.com/structuredmerge/structuredmerge-ruby/releases
212
+ [🚂maint-blog]: http://www.railsbling.com/tags/yaml-merge
213
+ [🚂maint-blog-img]: https://img.shields.io/badge/blog-railsbling-0093D0.svg?style=for-the-badge&logo=rubyonrails&logoColor=orange
214
+ [🚂maint-contact]: http://www.railsbling.com/contact
215
+ [🚂maint-contact-img]: https://img.shields.io/badge/Contact-Maintainer-0093D0.svg?style=flat&logo=rubyonrails&logoColor=red
216
+ [💖🖇linkedin]: http://www.linkedin.com/in/peterboling
217
+ [💖🖇linkedin-img]: https://img.shields.io/badge/LinkedIn-Profile-0B66C2?style=flat&logo=newjapanprowrestling
218
+ [💖✌️wellfound]: https://wellfound.com/u/peter-boling
219
+ [💖✌️wellfound-img]: https://img.shields.io/badge/peter--boling-orange?style=flat&logo=wellfound
220
+ [💖💲crunchbase]: https://www.crunchbase.com/person/peter-boling
221
+ [💖💲crunchbase-img]: https://img.shields.io/badge/peter--boling-purple?style=flat&logo=crunchbase
222
+ [💖🐘ruby-mast]: https://ruby.social/@galtzo
223
+ [💖🐘ruby-mast-img]: https://img.shields.io/mastodon/follow/109447111526622197?domain=https://ruby.social&style=flat&logo=mastodon&label=Ruby%20@galtzo
224
+ [💖🦋bluesky]: https://bsky.app/profile/galtzo.com
225
+ [💖🦋bluesky-img]: https://img.shields.io/badge/@galtzo.com-0285FF?style=flat&logo=bluesky&logoColor=white
226
+ [💖🌳linktree]: https://linktr.ee/galtzo
227
+ [💖🌳linktree-img]: https://img.shields.io/badge/galtzo-purple?style=flat&logo=linktree
228
+ [💖💁🏼‍♂️devto]: https://dev.to/galtzo
229
+ [💖💁🏼‍♂️devto-img]: https://img.shields.io/badge/dev.to-0A0A0A?style=flat&logo=devdotto&logoColor=white
230
+ [💖💁🏼‍♂️aboutme]: https://about.me/peter.boling
231
+ [💖💁🏼‍♂️aboutme-img]: https://img.shields.io/badge/about.me-0A0A0A?style=flat&logo=aboutme&logoColor=white
232
+ [💖🧊berg]: https://codeberg.org/pboling
233
+ [💖🐙hub]: https://github.org/pboling
234
+ [💖🛖hut]: https://sr.ht/~galtzo/
235
+ [💖🧪lab]: https://gitlab.com/pboling
236
+ [👨🏼‍🏫expsup-upwork]: https://www.upwork.com/freelancers/~014942e9b056abdf86?mp_source=share
237
+ [👨🏼‍🏫expsup-upwork-img]: https://img.shields.io/badge/UpWork-13544E?style=for-the-badge&logo=Upwork&logoColor=white
238
+ [👨🏼‍🏫expsup-codementor]: https://www.codementor.io/peterboling?utm_source=github&utm_medium=button&utm_term=peterboling&utm_campaign=github
239
+ [👨🏼‍🏫expsup-codementor-img]: https://img.shields.io/badge/CodeMentor-Get_Help-1abc9c?style=for-the-badge&logo=CodeMentor&logoColor=white
240
+ [🏙️entsup-tidelift]: https://tidelift.com/subscription/pkg/rubygems-yaml-merge?utm_source=rubygems-yaml-merge&utm_medium=referral&utm_campaign=readme
241
+ [🏙️entsup-tidelift-img]: https://img.shields.io/badge/Tidelift_and_Sonar-Enterprise_Support-FD3456?style=for-the-badge&logo=sonar&logoColor=white
242
+ [🏙️entsup-tidelift-sonar]: https://blog.tidelift.com/tidelift-joins-sonar
243
+ [💁🏼‍♂️peterboling]: http://www.peterboling.com
244
+ [🚂railsbling]: http://www.railsbling.com
245
+ [📜src-gl-img]: https://img.shields.io/badge/GitLab-FBA326?style=for-the-badge&logo=Gitlab&logoColor=orange
246
+ [📜src-gl]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/tree/main/gems/yaml-merge
247
+ [📜src-cb-img]: https://img.shields.io/badge/CodeBerg-4893CC?style=for-the-badge&logo=CodeBerg&logoColor=blue
248
+ [📜src-cb]: https://codeberg.org/structuredmerge/structuredmerge-ruby/src/branch/main/gems/yaml-merge
249
+ [📜src-gh-img]: https://img.shields.io/badge/GitHub-238636?style=for-the-badge&logo=GitHub&logoColor=green
250
+ [📜src-gh]: https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/yaml-merge
251
+ [📜docs-cr-rd-img]: https://img.shields.io/badge/RubyDoc-Current_Release-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
252
+ [📜docs-head-rd-img]: https://img.shields.io/badge/YARD_on_Galtzo.com-HEAD-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
253
+ [📜gl-wiki]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/wikis/home
254
+ [📜gh-wiki]: https://github.com/structuredmerge/structuredmerge-ruby/wiki
255
+ [📜gl-wiki-img]: https://img.shields.io/badge/wiki-gitlab-943CD2.svg?style=for-the-badge&logo=gitlab&logoColor=white
256
+ [📜gh-wiki-img]: https://img.shields.io/badge/wiki-github-943CD2.svg?style=for-the-badge&logo=github&logoColor=white
257
+ [👽dl-rank]: https://clickgems.clickhouse.com/dashboard/yaml-merge
258
+ [👽dl-ranki]: https://img.shields.io/gem/dt/yaml-merge.svg
259
+ [👽version]: https://clickgems.clickhouse.com/dashboard/yaml-merge
260
+ [👽versioni]: https://img.shields.io/gem/v/yaml-merge.svg
261
+ [🚎11-c-wf]: https://github.com/structuredmerge/structuredmerge-ruby/actions/workflows/current.yml
262
+ [🚎11-c-wfi]: https://github.com/structuredmerge/structuredmerge-ruby/actions/workflows/current.yml/badge.svg
263
+ [💎ruby-c-i]: https://img.shields.io/badge/Ruby-current-CC342D?style=for-the-badge&logo=ruby&logoColor=green
264
+ [🤝gh-issues]: https://github.com/structuredmerge/structuredmerge-ruby/issues
265
+ [🤝gh-pulls]: https://github.com/structuredmerge/structuredmerge-ruby/pulls
266
+ [🤝gl-issues]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/issues
267
+ [🤝gl-pulls]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/merge_requests
268
+ [🤝cb-issues]: https://codeberg.org/structuredmerge/structuredmerge-ruby/issues
269
+ [🤝cb-pulls]: https://codeberg.org/structuredmerge/structuredmerge-ruby/pulls
270
+ [🤝cb-donate]: https://donate.codeberg.org/
271
+ [🤝contributing]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/CONTRIBUTING.md
272
+ [🖐contrib-rocks]: https://contrib.rocks
273
+ [🖐contributors]: https://github.com/structuredmerge/structuredmerge-ruby/graphs/contributors
274
+ [🖐contributors-img]: https://contrib.rocks/image?repo=structuredmerge/structuredmerge-ruby
275
+ [🪇conduct]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/CODE_OF_CONDUCT.md
276
+ [🪇conduct-img]: https://img.shields.io/badge/Contributor_Covenant-2.1-259D6C.svg
277
+ [📌pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint
278
+ [📌semver]: https://semver.org/spec/v2.0.0.html
279
+ [📌semver-img]: https://img.shields.io/badge/semver-2.0.0-259D6C.svg?style=flat
280
+ [📌semver-breaking]: https://github.com/semver/semver/issues/716#issuecomment-869336139
281
+ [📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html
282
+ [📌changelog]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/CHANGELOG.md
283
+ [📗keep-changelog]: https://keepachangelog.com/en/1.0.0/
284
+ [📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-34495e.svg?style=flat
285
+ [📌gitmoji]: https://gitmoji.dev
286
+ [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
287
+ [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
288
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.606-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
289
+ [🔐security]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/SECURITY.md
290
+ [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
291
+ [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
292
+ [📄license]: LICENSE.md
293
+ [📄license-ref]: LICENSE.md
294
+ [📄license-img]: https://img.shields.io/badge/License-AGPL--3.0--only_OR_PolyForm--Small--Business--1.0.0-259D6C.svg
295
+ [📄license-compat]: https://www.apache.org/legal/resolved.html#category-x
296
+ [📄license-compat-img]: https://img.shields.io/badge/Apache_Incompatible:_Category_X-%E2%9C%97-C0392B.svg?style=flat&logo=Apache
297
+ [📄ilo-declaration]: https://www.ilo.org/declaration/lang--en/index.htm
298
+ [📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat
299
+ [🚎yard-current]: http://rubydoc.info/gems/yaml-merge
300
+ [🚎yard-head]: https://yaml-merge.galtzo.com
301
+ [💎stone_checksums]: https://github.com/galtzo-floss/stone_checksums
302
+ [💎SHA_checksums]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/tree/main/checksums
303
+ [💎rlts]: https://github.com/rubocop-lts/rubocop-lts
304
+ [💎rlts-img]: https://img.shields.io/badge/code_style_&_linting-rubocop--lts-34495e.svg?plastic&logo=ruby&logoColor=white
305
+ [💎appraisal2]: https://github.com/appraisal-rb/appraisal2
306
+ [💎appraisal2-img]: https://img.shields.io/badge/appraised_by-appraisal2-34495e.svg?plastic&logo=ruby&logoColor=white
307
+ [💎d-in-dvcs]: https://railsbling.com/posts/dvcs/put_the_d_in_dvcs/
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yaml
4
+ module Merge
5
+ module DebugLogger
6
+ module_function
7
+
8
+ def debug(_message, _details = nil); end
9
+
10
+ def time(_label)
11
+ yield
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yaml
4
+ module Merge
5
+ class Emitter < Ast::Merge::EmitterBase
6
+ include Ast::Merge::EmitterLineMetadataSupport
7
+
8
+ def initialize_subclass_state(**_options)
9
+ initialize_line_metadata_state
10
+ end
11
+
12
+ def clear_subclass_state
13
+ clear_line_metadata_state
14
+ end
15
+
16
+ def emit_blank_line
17
+ append_line('')
18
+ end
19
+
20
+ def emit_tracked_comment(comment)
21
+ indent = ' ' * (comment[:indent] || 0)
22
+ append_line("#{indent}# #{comment[:text]}")
23
+ end
24
+
25
+ def emit_comment(text, inline: false)
26
+ if inline
27
+ return if @lines.empty?
28
+
29
+ @lines[-1] = "#{@lines[-1]} # #{text}"
30
+ else
31
+ append_line("#{current_indent}# #{text}")
32
+ end
33
+ end
34
+
35
+ def emit_raw_lines(raw_lines, metadata: nil)
36
+ raw_lines.each_with_index do |line, index|
37
+ append_line(line.chomp, expanded_line_metadata(metadata, index))
38
+ end
39
+ end
40
+
41
+ def to_yaml
42
+ to_s
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yaml
4
+ module Merge
5
+ class FileAnalysis
6
+ include Ast::Merge::FileAnalyzable
7
+
8
+ attr_reader :ast, :errors
9
+
10
+ def initialize(source, signature_generator: nil, parser_path: nil, **_options)
11
+ @source = source
12
+ @lines = source.lines.map(&:chomp)
13
+ @signature_generator = signature_generator
14
+ @parser_path = parser_path
15
+ @errors = []
16
+
17
+ DebugLogger.time('FileAnalysis#parse_yaml') { parse_yaml }
18
+ @statements = valid? ? documents : []
19
+ end
20
+
21
+ def valid?
22
+ @errors.empty? && !@ast.nil?
23
+ end
24
+
25
+ def root_node
26
+ return unless valid?
27
+
28
+ NodeWrapper.new(@ast.root_node, lines: @lines, source: @source)
29
+ end
30
+
31
+ def documents
32
+ return [] unless valid?
33
+
34
+ index = 0
35
+ @ast.root_node.children.filter_map do |child|
36
+ next unless child.type.to_s == 'document'
37
+
38
+ wrapper = NodeWrapper.new(child, lines: @lines, source: @source, document_index: index)
39
+ index += 1
40
+ wrapper
41
+ end
42
+ end
43
+
44
+ alias nodes statements
45
+
46
+ def fallthrough_node?(value)
47
+ value.is_a?(NodeWrapper) || super
48
+ end
49
+
50
+ def ruleset_owner_selector
51
+ :line_bound_statements
52
+ end
53
+
54
+ def ruleset_render_family
55
+ :yaml_documents_and_mappings
56
+ end
57
+
58
+ private
59
+
60
+ def compute_node_signature(node)
61
+ return node.signature if node.respond_to?(:signature)
62
+
63
+ [node.class.name, node.to_s]
64
+ end
65
+
66
+ def layout_augmenter_default_owners
67
+ statements
68
+ end
69
+
70
+ def parse_yaml
71
+ parser = TreeHaver.parser_for(:yaml, backend_type: :tree_sitter)
72
+ @ast = parser.parse(@source)
73
+ collect_parse_errors(@ast.root_node) if @ast&.root_node
74
+ rescue TreeHaver::Error, StandardError => e
75
+ @errors << e
76
+ @ast = nil
77
+ end
78
+
79
+ def collect_parse_errors(node, found_errors = [])
80
+ if node.type.to_s == 'ERROR' ||
81
+ (node.respond_to?(:has_error?) && node.has_error?) ||
82
+ (node.respond_to?(:missing?) && node.missing?)
83
+ found_errors << node
84
+ end
85
+
86
+ node.children.each { |child| collect_parse_errors(child, found_errors) } if node.respond_to?(:children)
87
+ @errors.concat(found_errors) unless found_errors.empty?
88
+ found_errors
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yaml
4
+ module Merge
5
+ class MergeResult < Ast::Merge::MergeResultBase
6
+ DECISION_KEPT_TEMPLATE = Ast::Merge::MergeResultBase::DECISION_KEPT_TEMPLATE
7
+ DECISION_KEPT_DEST = Ast::Merge::MergeResultBase::DECISION_KEPT_DEST
8
+ DECISION_MERGED = Ast::Merge::MergeResultBase::DECISION_MERGED
9
+ DECISION_ADDED = Ast::Merge::MergeResultBase::DECISION_ADDED
10
+ DECISION_FREEZE_BLOCK = Ast::Merge::MergeResultBase::DECISION_FREEZE_BLOCK
11
+
12
+ attr_reader :statistics
13
+
14
+ def initialize(**options)
15
+ super(**options)
16
+ @statistics = {
17
+ template_lines: 0,
18
+ dest_lines: 0,
19
+ merged_lines: 0,
20
+ freeze_preserved_lines: 0,
21
+ total_decisions: 0
22
+ }
23
+ end
24
+
25
+ def add_line(line, decision:, source:, original_line: nil)
26
+ @lines << {
27
+ content: line,
28
+ decision: decision,
29
+ source: source,
30
+ original_line: original_line
31
+ }
32
+ track_statistics(decision)
33
+ track_decision(decision, source, line: original_line)
34
+ end
35
+
36
+ def to_yaml
37
+ content = @lines.map { |line| line[:content] }.join("\n")
38
+ content += "\n" unless content.empty? || content.end_with?("\n")
39
+ content
40
+ end
41
+
42
+ alias content to_yaml
43
+ alias to_s to_yaml
44
+
45
+ def line_count
46
+ @lines.size
47
+ end
48
+
49
+ private
50
+
51
+ def track_statistics(decision)
52
+ @statistics[:total_decisions] += 1
53
+ case decision
54
+ when DECISION_KEPT_TEMPLATE
55
+ @statistics[:template_lines] += 1
56
+ when DECISION_KEPT_DEST
57
+ @statistics[:dest_lines] += 1
58
+ when DECISION_FREEZE_BLOCK
59
+ @statistics[:freeze_preserved_lines] += 1
60
+ else
61
+ @statistics[:merged_lines] += 1
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end