yaml-merge 7.0.0 → 7.1.3

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: 861dc2bba17b21e44e3e46b947e458d7e5114c376f1076648cf14f15793e9a7d
4
+ data.tar.gz: 246f068f78244935250454a8f5c4ca38e1735286f48252f17f023083aaeedb0e
5
5
  SHA512:
6
- metadata.gz: e87f09daeb658603e7727073b4bc6d7b8ca5b7d1de4b8e4af26ed6a9c7dc65b52d08541db2c50c53bab791e01021d14b04a1ae95dd2e573428211b08e6d279cc
7
- data.tar.gz: 7c0d7b2f31a4a721385218ada4ad9fe915e041fd03e4f1e9777d07a38f3ebbe1592ee01b61e666a5805ca250440284845b68007de7c780b05e520d67f3c99ef4
6
+ metadata.gz: d87a3509a72a8c7ab1d37e098ff47bd689d1c600228e740cca1dd08565062b17e978d8ffb985d74ef4037227354cf9e75b11f84a392fc672ac97ada2bd11bb29
7
+ data.tar.gz: 49e729482712daec1b3a62fd3851d4e91a728bbeed26ec5af4533adf1c8a7bc1a5f155700099a0fe6ddbf526ab7d059ea738b7d8b79cd946141e7f9652206e64
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,299 @@
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+, 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
+ check [issues][🤝gh-issues] or [PRs][🤝gh-pulls], or use the gem and think about how it could be better.
136
+
137
+ We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it.
138
+
139
+ See [CONTRIBUTING.md][🤝contributing] for more detailed instructions.
140
+
141
+ ## 📌 Versioning
142
+
143
+ This library follows [![Semantic Versioning 2.0.0][📌semver-img]][📌semver] for its public API where practical.
144
+ For most applications, prefer the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
145
+
146
+ For example:
147
+
148
+ ```ruby
149
+ spec.add_dependency("yaml-merge", "~> 7.0")
150
+ ```
151
+
152
+ <details markdown="1">
153
+ <summary>📌 Is "Platform Support" part of the public API? More details inside.</summary>
154
+
155
+ Dropping support for a platform can be a breaking change for affected users.
156
+ If a release changes supported platforms, it should be called out clearly in the changelog and versioned with that impact in mind.
157
+
158
+ To get a better understanding of how SemVer is intended to work over a project's lifetime,
159
+ read this article from the creator of SemVer:
160
+
161
+ - ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]
162
+
163
+ </details>
164
+
165
+ See [CHANGELOG.md][📌changelog] for a list of releases.
166
+
167
+ ## 📄 License
168
+
169
+ 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).
170
+ See [LICENSE.md][📄license] for details.
171
+
172
+ If none of the available licenses suit your use case, please [contact us](mailto:floss@galtzo.com) to discuss a custom commercial license.
173
+
174
+ [⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611&style=flat
175
+ [⛳liberapay-bottom-img]: https://img.shields.io/liberapay/goal/pboling.svg?style=for-the-badge&logo=liberapay&color=a51611
176
+ [⛳liberapay]: https://liberapay.com/pboling/donate
177
+ [🖇sponsor-img]: https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github
178
+ [🖇sponsor-bottom-img]: https://img.shields.io/badge/Sponsor_Me!-pboling-blue?style=for-the-badge&logo=github
179
+ [🖇sponsor]: https://github.com/sponsors/pboling
180
+ [🖇kofi-img]: https://img.shields.io/badge/ko--fi-%E2%9C%93-a51611.svg?style=flat
181
+ [🖇kofi]: https://ko-fi.com/pboling
182
+ [🖇buyme-small-img]: https://img.shields.io/badge/buy_me_a_coffee-%E2%9C%93-a51611.svg?style=flat
183
+ [🖇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
184
+ [🖇buyme]: https://www.buymeacoffee.com/pboling
185
+ [🖇paypal-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=flat&logo=paypal
186
+ [🖇paypal-bottom-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=for-the-badge&logo=paypal&color=0A0A0A
187
+ [🖇paypal]: https://www.paypal.com/paypalme/peterboling
188
+ [🖇floss-funding.dev]: https://floss-funding.dev
189
+ [🖇floss-funding-gem]: https://github.com/galtzo-floss/floss_funding
190
+ [✉️discord-invite]: https://discord.gg/3qme4XHNKN
191
+ [✉️discord-invite-img-ftb]: https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord
192
+ [✉️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
193
+ [✉️ruby-friends]: https://app.daily.dev/squads/rubyfriends
194
+ [✉️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
195
+ [✉️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
196
+ [✉️ruby-forum]: https://www.rubyforum.org/tag/structuredmerge
197
+ [✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
198
+ [⛳️gem-namespace]: https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/yaml-merge
199
+ [⛳️namespace-img]: https://img.shields.io/badge/namespace-Yaml::Merge-3C2D2D.svg?style=square&logo=ruby&logoColor=white
200
+ [⛳️gem-name]: https://clickgems.clickhouse.com/dashboard/yaml-merge
201
+ [⛳️name-img]: https://img.shields.io/badge/name-yaml--merge-3C2D2D.svg?style=square&logo=rubygems&logoColor=red
202
+ [⛳️tag-img]: https://img.shields.io/github/tag/structuredmerge/structuredmerge-ruby.svg
203
+ [⛳️tag]: https://github.com/structuredmerge/structuredmerge-ruby/releases
204
+ [🚂maint-blog]: http://www.railsbling.com/tags/yaml-merge
205
+ [🚂maint-blog-img]: https://img.shields.io/badge/blog-railsbling-0093D0.svg?style=for-the-badge&logo=rubyonrails&logoColor=orange
206
+ [🚂maint-contact]: http://www.railsbling.com/contact
207
+ [🚂maint-contact-img]: https://img.shields.io/badge/Contact-Maintainer-0093D0.svg?style=flat&logo=rubyonrails&logoColor=red
208
+ [💖🖇linkedin]: http://www.linkedin.com/in/peterboling
209
+ [💖🖇linkedin-img]: https://img.shields.io/badge/LinkedIn-Profile-0B66C2?style=flat&logo=newjapanprowrestling
210
+ [💖✌️wellfound]: https://wellfound.com/u/peter-boling
211
+ [💖✌️wellfound-img]: https://img.shields.io/badge/peter--boling-orange?style=flat&logo=wellfound
212
+ [💖💲crunchbase]: https://www.crunchbase.com/person/peter-boling
213
+ [💖💲crunchbase-img]: https://img.shields.io/badge/peter--boling-purple?style=flat&logo=crunchbase
214
+ [💖🐘ruby-mast]: https://ruby.social/@galtzo
215
+ [💖🐘ruby-mast-img]: https://img.shields.io/mastodon/follow/109447111526622197?domain=https://ruby.social&style=flat&logo=mastodon&label=Ruby%20@galtzo
216
+ [💖🦋bluesky]: https://bsky.app/profile/galtzo.com
217
+ [💖🦋bluesky-img]: https://img.shields.io/badge/@galtzo.com-0285FF?style=flat&logo=bluesky&logoColor=white
218
+ [💖🌳linktree]: https://linktr.ee/galtzo
219
+ [💖🌳linktree-img]: https://img.shields.io/badge/galtzo-purple?style=flat&logo=linktree
220
+ [💖💁🏼‍♂️devto]: https://dev.to/galtzo
221
+ [💖💁🏼‍♂️devto-img]: https://img.shields.io/badge/dev.to-0A0A0A?style=flat&logo=devdotto&logoColor=white
222
+ [💖💁🏼‍♂️aboutme]: https://about.me/peter.boling
223
+ [💖💁🏼‍♂️aboutme-img]: https://img.shields.io/badge/about.me-0A0A0A?style=flat&logo=aboutme&logoColor=white
224
+ [💖🧊berg]: https://codeberg.org/pboling
225
+ [💖🐙hub]: https://github.org/pboling
226
+ [💖🛖hut]: https://sr.ht/~galtzo/
227
+ [💖🧪lab]: https://gitlab.com/pboling
228
+ [👨🏼‍🏫expsup-upwork]: https://www.upwork.com/freelancers/~014942e9b056abdf86?mp_source=share
229
+ [👨🏼‍🏫expsup-upwork-img]: https://img.shields.io/badge/UpWork-13544E?style=for-the-badge&logo=Upwork&logoColor=white
230
+ [👨🏼‍🏫expsup-codementor]: https://www.codementor.io/peterboling?utm_source=github&utm_medium=button&utm_term=peterboling&utm_campaign=github
231
+ [👨🏼‍🏫expsup-codementor-img]: https://img.shields.io/badge/CodeMentor-Get_Help-1abc9c?style=for-the-badge&logo=CodeMentor&logoColor=white
232
+ [🏙️entsup-tidelift]: https://tidelift.com/subscription/pkg/rubygems-yaml-merge?utm_source=rubygems-yaml-merge&utm_medium=referral&utm_campaign=readme
233
+ [🏙️entsup-tidelift-img]: https://img.shields.io/badge/Tidelift_and_Sonar-Enterprise_Support-FD3456?style=for-the-badge&logo=sonar&logoColor=white
234
+ [🏙️entsup-tidelift-sonar]: https://blog.tidelift.com/tidelift-joins-sonar
235
+ [💁🏼‍♂️peterboling]: http://www.peterboling.com
236
+ [🚂railsbling]: http://www.railsbling.com
237
+ [📜src-gl-img]: https://img.shields.io/badge/GitLab-FBA326?style=for-the-badge&logo=Gitlab&logoColor=orange
238
+ [📜src-gl]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/tree/main/gems/yaml-merge
239
+ [📜src-cb-img]: https://img.shields.io/badge/CodeBerg-4893CC?style=for-the-badge&logo=CodeBerg&logoColor=blue
240
+ [📜src-cb]: https://codeberg.org/structuredmerge/structuredmerge-ruby/src/branch/main/gems/yaml-merge
241
+ [📜src-gh-img]: https://img.shields.io/badge/GitHub-238636?style=for-the-badge&logo=GitHub&logoColor=green
242
+ [📜src-gh]: https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/yaml-merge
243
+ [📜docs-cr-rd-img]: https://img.shields.io/badge/RubyDoc-Current_Release-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
244
+ [📜docs-head-rd-img]: https://img.shields.io/badge/YARD_on_Galtzo.com-HEAD-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
245
+ [📜gl-wiki]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/wikis/home
246
+ [📜gh-wiki]: https://github.com/structuredmerge/structuredmerge-ruby/wiki
247
+ [📜gl-wiki-img]: https://img.shields.io/badge/wiki-gitlab-943CD2.svg?style=for-the-badge&logo=gitlab&logoColor=white
248
+ [📜gh-wiki-img]: https://img.shields.io/badge/wiki-github-943CD2.svg?style=for-the-badge&logo=github&logoColor=white
249
+ [👽dl-rank]: https://clickgems.clickhouse.com/dashboard/yaml-merge
250
+ [👽dl-ranki]: https://img.shields.io/gem/dt/yaml-merge.svg
251
+ [👽version]: https://clickgems.clickhouse.com/dashboard/yaml-merge
252
+ [👽versioni]: https://img.shields.io/gem/v/yaml-merge.svg
253
+ [🚎11-c-wf]: https://github.com/structuredmerge/structuredmerge-ruby/actions/workflows/current.yml
254
+ [🚎11-c-wfi]: https://github.com/structuredmerge/structuredmerge-ruby/actions/workflows/current.yml/badge.svg
255
+ [💎ruby-c-i]: https://img.shields.io/badge/Ruby-current-CC342D?style=for-the-badge&logo=ruby&logoColor=green
256
+ [🤝gh-issues]: https://github.com/structuredmerge/structuredmerge-ruby/issues
257
+ [🤝gh-pulls]: https://github.com/structuredmerge/structuredmerge-ruby/pulls
258
+ [🤝gl-issues]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/issues
259
+ [🤝gl-pulls]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/merge_requests
260
+ [🤝cb-issues]: https://codeberg.org/structuredmerge/structuredmerge-ruby/issues
261
+ [🤝cb-pulls]: https://codeberg.org/structuredmerge/structuredmerge-ruby/pulls
262
+ [🤝cb-donate]: https://donate.codeberg.org/
263
+ [🤝contributing]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/CONTRIBUTING.md
264
+ [🖐contrib-rocks]: https://contrib.rocks
265
+ [🖐contributors]: https://github.com/structuredmerge/structuredmerge-ruby/graphs/contributors
266
+ [🖐contributors-img]: https://contrib.rocks/image?repo=structuredmerge/structuredmerge-ruby
267
+ [🪇conduct]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/CODE_OF_CONDUCT.md
268
+ [🪇conduct-img]: https://img.shields.io/badge/Contributor_Covenant-2.1-259D6C.svg
269
+ [📌pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint
270
+ [📌semver]: https://semver.org/spec/v2.0.0.html
271
+ [📌semver-img]: https://img.shields.io/badge/semver-2.0.0-259D6C.svg?style=flat
272
+ [📌semver-breaking]: https://github.com/semver/semver/issues/716#issuecomment-869336139
273
+ [📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html
274
+ [📌changelog]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/CHANGELOG.md
275
+ [📗keep-changelog]: https://keepachangelog.com/en/1.0.0/
276
+ [📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-34495e.svg?style=flat
277
+ [📌gitmoji]: https://gitmoji.dev
278
+ [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
279
+ [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
280
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.606-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
281
+ [🔐security]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/SECURITY.md
282
+ [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
283
+ [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
284
+ [📄license]: LICENSE.md
285
+ [📄license-ref]: LICENSE.md
286
+ [📄license-img]: https://img.shields.io/badge/License-AGPL--3.0--only_OR_PolyForm--Small--Business--1.0.0-259D6C.svg
287
+ [📄license-compat]: https://www.apache.org/legal/resolved.html#category-x
288
+ [📄license-compat-img]: https://img.shields.io/badge/Apache_Incompatible:_Category_X-%E2%9C%97-C0392B.svg?style=flat&logo=Apache
289
+ [📄ilo-declaration]: https://www.ilo.org/declaration/lang--en/index.htm
290
+ [📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat
291
+ [🚎yard-current]: http://rubydoc.info/gems/yaml-merge
292
+ [🚎yard-head]: https://yaml-merge.galtzo.com
293
+ [💎stone_checksums]: https://github.com/galtzo-floss/stone_checksums
294
+ [💎SHA_checksums]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/tree/main/checksums
295
+ [💎rlts]: https://github.com/rubocop-lts/rubocop-lts
296
+ [💎rlts-img]: https://img.shields.io/badge/code_style_&_linting-rubocop--lts-34495e.svg?plastic&logo=ruby&logoColor=white
297
+ [💎appraisal2]: https://github.com/appraisal-rb/appraisal2
298
+ [💎appraisal2-img]: https://img.shields.io/badge/appraised_by-appraisal2-34495e.svg?plastic&logo=ruby&logoColor=white
299
+ [💎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