plain-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: fd3d000aba244c2628a3216cb39596c0019700c11ae89568efef00a6aa3aa796
4
- data.tar.gz: 3e2c8c645cc153e6e48194d8ce9860b0adf8c4ce1d5582ab6b9f14d8a85fe2f7
3
+ metadata.gz: eb21dc58d45117871ad2b96d9adaff4775cfdc8e5267e5742a3cf71d09b1ea2c
4
+ data.tar.gz: 896051c7f24220265b0086912e9d91f77ab28e94914720b1b4e795016029d981
5
5
  SHA512:
6
- metadata.gz: f4ac184c99e041ed6b0f0551022fc9e0163b681db893344a07b1f30503220250ffe9fd19092b5b60fe05a5ed78c627fc736ec0c3d7a9884259977a60f03e7278
7
- data.tar.gz: eaf6d3f57d5cf225ef29e5aa9e0f5021df15d6b74d6aaa2b2d62bf9fa495dfe91fbd784b8775fbe443c38756749ea2c1282b6f784eaf69f2158cb3908f7a54ca
6
+ metadata.gz: bb3a96716022df3e9ce9ed6a63638a1c913ec0de744bc74b3c70625a2774a57cac56d17fd9fb766be3528512fa5eed7082f0640561b083718155c722b420eb05
7
+ data.tar.gz: a06b47194805436a93962350698b6f898a9f66cab476fb8929c2c7eedef2a6d1b0d3b4da3142f3cb25bc8424159041fd54fbceddcaf3c410343753e80c0a9fdf
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,285 @@
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
+ # ☯️ Plain::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
+ `Plain::Merge` provides text-family fallback behavior for content without a richer parser. It normalizes paragraphs into blocks, compares block similarity, and reports whether two text bodies are close enough for a safe fallback decision.
25
+ It also registers the StructuredMerge line substrate with `tree_haver`, so
26
+ callers can enter plain text analysis through
27
+ `TreeHaver.parser_for(:text, backend_type: :line)` or
28
+ `TreeHaver.parser_for(:plain, backend_type: :line)`.
29
+
30
+ ### Key Features
31
+
32
+ - Paragraph/block normalization for plain text.
33
+ - Jaccard similarity scoring.
34
+ - Configurable text-refinement threshold and weights.
35
+ - Module-level `merge_text` API for fallback integrations.
36
+ - `TreeHaver.parser_for` registration for `:text` and `:plain` through the
37
+ `:line` backend.
38
+
39
+ ## 💡 Info you can shake a stick at
40
+
41
+ | Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |
42
+ |-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
43
+ | Works with MRI Ruby 4 | [![Ruby current Compat][💎ruby-c-i]][🚎11-c-wf]|
44
+ | 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] |
45
+ | 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] |
46
+ | 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] |
47
+ | 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] |
48
+ | 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] |
49
+ | 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] |
50
+ | `...` 💖 | [![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] |
51
+
52
+ ### Compatibility
53
+
54
+ Compatible with MRI Ruby 4.0.0+, JRuby, and TruffleRuby.
55
+ CI workflows and Appraisals are generated for MRI Ruby 4.0.0+.
56
+ This test floor is configured by `ruby.test_minimum` in `.kettle-jem.yml` and
57
+ may be higher than the gem's runtime compatibility floor when legacy Rubies are
58
+ not practical for the current toolchain.
59
+
60
+ <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>
61
+
62
+ The _amazing_ test matrix is powered by the kettle-dev stack.
63
+
64
+ <details markdown="1">
65
+ <summary>How kettle-dev manages complexity in tests</summary>
66
+
67
+ | Gem | Source | Role | Total downloads |
68
+ |-----|--------|------|---------------------|
69
+ | [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) |
70
+ | [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) |
71
+ | [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) |
72
+ | [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) |
73
+ | [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) |
74
+ | [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) |
75
+ | [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) |
76
+ | [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) |
77
+
78
+ </details>
79
+
80
+ ## ✨ Installation
81
+
82
+ Install the gem and add to the application's Gemfile by executing:
83
+
84
+ ```console
85
+ bundle add plain-merge
86
+ ```
87
+
88
+ If bundler is not being used to manage dependencies, install the gem by executing:
89
+
90
+ ```console
91
+ gem install plain-merge
92
+ ```
93
+
94
+ ## ⚙️ Configuration
95
+
96
+ The default similarity threshold is `Plain::Merge::DEFAULT_TEXT_REFINEMENT_THRESHOLD`. Use `Plain::Merge.is_similar(left, right, threshold)` when a caller needs to decide whether a text fallback is acceptable.
97
+
98
+ `Plain::Merge.text_feature_profile` returns the family profile used by conformance runners.
99
+
100
+ ## 🔧 Basic Usage
101
+
102
+ ```ruby
103
+ require "plain/merge"
104
+
105
+ result = Plain::Merge.merge_text(
106
+ File.read("template.txt"),
107
+ File.read("notes.txt"),
108
+ )
109
+
110
+ abort result.fetch(:diagnostics).inspect unless result.fetch(:ok)
111
+ File.write("notes.txt", result.fetch(:output))
112
+ ```
113
+
114
+ ## 🔐 Security
115
+
116
+ See [SECURITY.md][🔐security].
117
+
118
+ ## 🤝 Contributing
119
+
120
+ If you need some ideas of where to help, you could work on adding more code coverage,
121
+ check [issues][🤝gh-issues] or [PRs][🤝gh-pulls], or use the gem and think about how it could be better.
122
+
123
+ We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it.
124
+
125
+ See [CONTRIBUTING.md][🤝contributing] for more detailed instructions.
126
+
127
+ ## 📌 Versioning
128
+
129
+ This library follows [![Semantic Versioning 2.0.0][📌semver-img]][📌semver] for its public API where practical.
130
+ For most applications, prefer the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
131
+
132
+ For example:
133
+
134
+ ```ruby
135
+ spec.add_dependency("plain-merge", "~> 7.0")
136
+ ```
137
+
138
+ <details markdown="1">
139
+ <summary>📌 Is "Platform Support" part of the public API? More details inside.</summary>
140
+
141
+ Dropping support for a platform can be a breaking change for affected users.
142
+ If a release changes supported platforms, it should be called out clearly in the changelog and versioned with that impact in mind.
143
+
144
+ To get a better understanding of how SemVer is intended to work over a project's lifetime,
145
+ read this article from the creator of SemVer:
146
+
147
+ - ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]
148
+
149
+ </details>
150
+
151
+ See [CHANGELOG.md][📌changelog] for a list of releases.
152
+
153
+ ## 📄 License
154
+
155
+ 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).
156
+ See [LICENSE.md][📄license] for details.
157
+
158
+ If none of the available licenses suit your use case, please [contact us](mailto:floss@galtzo.com) to discuss a custom commercial license.
159
+
160
+ [⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611&style=flat
161
+ [⛳liberapay-bottom-img]: https://img.shields.io/liberapay/goal/pboling.svg?style=for-the-badge&logo=liberapay&color=a51611
162
+ [⛳liberapay]: https://liberapay.com/pboling/donate
163
+ [🖇sponsor-img]: https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github
164
+ [🖇sponsor-bottom-img]: https://img.shields.io/badge/Sponsor_Me!-pboling-blue?style=for-the-badge&logo=github
165
+ [🖇sponsor]: https://github.com/sponsors/pboling
166
+ [🖇kofi-img]: https://img.shields.io/badge/ko--fi-%E2%9C%93-a51611.svg?style=flat
167
+ [🖇kofi]: https://ko-fi.com/pboling
168
+ [🖇buyme-small-img]: https://img.shields.io/badge/buy_me_a_coffee-%E2%9C%93-a51611.svg?style=flat
169
+ [🖇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
170
+ [🖇buyme]: https://www.buymeacoffee.com/pboling
171
+ [🖇paypal-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=flat&logo=paypal
172
+ [🖇paypal-bottom-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=for-the-badge&logo=paypal&color=0A0A0A
173
+ [🖇paypal]: https://www.paypal.com/paypalme/peterboling
174
+ [🖇floss-funding.dev]: https://floss-funding.dev
175
+ [🖇floss-funding-gem]: https://github.com/galtzo-floss/floss_funding
176
+ [✉️discord-invite]: https://discord.gg/3qme4XHNKN
177
+ [✉️discord-invite-img-ftb]: https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord
178
+ [✉️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
179
+ [✉️ruby-friends]: https://app.daily.dev/squads/rubyfriends
180
+ [✉️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
181
+ [✉️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
182
+ [✉️ruby-forum]: https://www.rubyforum.org/tag/structuredmerge
183
+ [✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
184
+ [⛳️gem-namespace]: https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/plain-merge
185
+ [⛳️namespace-img]: https://img.shields.io/badge/namespace-Plain::Merge-3C2D2D.svg?style=square&logo=ruby&logoColor=white
186
+ [⛳️gem-name]: https://clickgems.clickhouse.com/dashboard/plain-merge
187
+ [⛳️name-img]: https://img.shields.io/badge/name-plain--merge-3C2D2D.svg?style=square&logo=rubygems&logoColor=red
188
+ [⛳️tag-img]: https://img.shields.io/github/tag/structuredmerge/structuredmerge-ruby.svg
189
+ [⛳️tag]: https://github.com/structuredmerge/structuredmerge-ruby/releases
190
+ [🚂maint-blog]: http://www.railsbling.com/tags/plain-merge
191
+ [🚂maint-blog-img]: https://img.shields.io/badge/blog-railsbling-0093D0.svg?style=for-the-badge&logo=rubyonrails&logoColor=orange
192
+ [🚂maint-contact]: http://www.railsbling.com/contact
193
+ [🚂maint-contact-img]: https://img.shields.io/badge/Contact-Maintainer-0093D0.svg?style=flat&logo=rubyonrails&logoColor=red
194
+ [💖🖇linkedin]: http://www.linkedin.com/in/peterboling
195
+ [💖🖇linkedin-img]: https://img.shields.io/badge/LinkedIn-Profile-0B66C2?style=flat&logo=newjapanprowrestling
196
+ [💖✌️wellfound]: https://wellfound.com/u/peter-boling
197
+ [💖✌️wellfound-img]: https://img.shields.io/badge/peter--boling-orange?style=flat&logo=wellfound
198
+ [💖💲crunchbase]: https://www.crunchbase.com/person/peter-boling
199
+ [💖💲crunchbase-img]: https://img.shields.io/badge/peter--boling-purple?style=flat&logo=crunchbase
200
+ [💖🐘ruby-mast]: https://ruby.social/@galtzo
201
+ [💖🐘ruby-mast-img]: https://img.shields.io/mastodon/follow/109447111526622197?domain=https://ruby.social&style=flat&logo=mastodon&label=Ruby%20@galtzo
202
+ [💖🦋bluesky]: https://bsky.app/profile/galtzo.com
203
+ [💖🦋bluesky-img]: https://img.shields.io/badge/@galtzo.com-0285FF?style=flat&logo=bluesky&logoColor=white
204
+ [💖🌳linktree]: https://linktr.ee/galtzo
205
+ [💖🌳linktree-img]: https://img.shields.io/badge/galtzo-purple?style=flat&logo=linktree
206
+ [💖💁🏼‍♂️devto]: https://dev.to/galtzo
207
+ [💖💁🏼‍♂️devto-img]: https://img.shields.io/badge/dev.to-0A0A0A?style=flat&logo=devdotto&logoColor=white
208
+ [💖💁🏼‍♂️aboutme]: https://about.me/peter.boling
209
+ [💖💁🏼‍♂️aboutme-img]: https://img.shields.io/badge/about.me-0A0A0A?style=flat&logo=aboutme&logoColor=white
210
+ [💖🧊berg]: https://codeberg.org/pboling
211
+ [💖🐙hub]: https://github.org/pboling
212
+ [💖🛖hut]: https://sr.ht/~galtzo/
213
+ [💖🧪lab]: https://gitlab.com/pboling
214
+ [👨🏼‍🏫expsup-upwork]: https://www.upwork.com/freelancers/~014942e9b056abdf86?mp_source=share
215
+ [👨🏼‍🏫expsup-upwork-img]: https://img.shields.io/badge/UpWork-13544E?style=for-the-badge&logo=Upwork&logoColor=white
216
+ [👨🏼‍🏫expsup-codementor]: https://www.codementor.io/peterboling?utm_source=github&utm_medium=button&utm_term=peterboling&utm_campaign=github
217
+ [👨🏼‍🏫expsup-codementor-img]: https://img.shields.io/badge/CodeMentor-Get_Help-1abc9c?style=for-the-badge&logo=CodeMentor&logoColor=white
218
+ [🏙️entsup-tidelift]: https://tidelift.com/subscription/pkg/rubygems-plain-merge?utm_source=rubygems-plain-merge&utm_medium=referral&utm_campaign=readme
219
+ [🏙️entsup-tidelift-img]: https://img.shields.io/badge/Tidelift_and_Sonar-Enterprise_Support-FD3456?style=for-the-badge&logo=sonar&logoColor=white
220
+ [🏙️entsup-tidelift-sonar]: https://blog.tidelift.com/tidelift-joins-sonar
221
+ [💁🏼‍♂️peterboling]: http://www.peterboling.com
222
+ [🚂railsbling]: http://www.railsbling.com
223
+ [📜src-gl-img]: https://img.shields.io/badge/GitLab-FBA326?style=for-the-badge&logo=Gitlab&logoColor=orange
224
+ [📜src-gl]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/tree/main/gems/plain-merge
225
+ [📜src-cb-img]: https://img.shields.io/badge/CodeBerg-4893CC?style=for-the-badge&logo=CodeBerg&logoColor=blue
226
+ [📜src-cb]: https://codeberg.org/structuredmerge/structuredmerge-ruby/src/branch/main/gems/plain-merge
227
+ [📜src-gh-img]: https://img.shields.io/badge/GitHub-238636?style=for-the-badge&logo=GitHub&logoColor=green
228
+ [📜src-gh]: https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/plain-merge
229
+ [📜docs-cr-rd-img]: https://img.shields.io/badge/RubyDoc-Current_Release-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
230
+ [📜docs-head-rd-img]: https://img.shields.io/badge/YARD_on_Galtzo.com-HEAD-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
231
+ [📜gl-wiki]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/wikis/home
232
+ [📜gh-wiki]: https://github.com/structuredmerge/structuredmerge-ruby/wiki
233
+ [📜gl-wiki-img]: https://img.shields.io/badge/wiki-gitlab-943CD2.svg?style=for-the-badge&logo=gitlab&logoColor=white
234
+ [📜gh-wiki-img]: https://img.shields.io/badge/wiki-github-943CD2.svg?style=for-the-badge&logo=github&logoColor=white
235
+ [👽dl-rank]: https://clickgems.clickhouse.com/dashboard/plain-merge
236
+ [👽dl-ranki]: https://img.shields.io/gem/dt/plain-merge.svg
237
+ [👽version]: https://clickgems.clickhouse.com/dashboard/plain-merge
238
+ [👽versioni]: https://img.shields.io/gem/v/plain-merge.svg
239
+ [🚎11-c-wf]: https://github.com/structuredmerge/structuredmerge-ruby/actions/workflows/current.yml
240
+ [🚎11-c-wfi]: https://github.com/structuredmerge/structuredmerge-ruby/actions/workflows/current.yml/badge.svg
241
+ [💎ruby-c-i]: https://img.shields.io/badge/Ruby-current-CC342D?style=for-the-badge&logo=ruby&logoColor=green
242
+ [🤝gh-issues]: https://github.com/structuredmerge/structuredmerge-ruby/issues
243
+ [🤝gh-pulls]: https://github.com/structuredmerge/structuredmerge-ruby/pulls
244
+ [🤝gl-issues]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/issues
245
+ [🤝gl-pulls]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/merge_requests
246
+ [🤝cb-issues]: https://codeberg.org/structuredmerge/structuredmerge-ruby/issues
247
+ [🤝cb-pulls]: https://codeberg.org/structuredmerge/structuredmerge-ruby/pulls
248
+ [🤝cb-donate]: https://donate.codeberg.org/
249
+ [🤝contributing]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/CONTRIBUTING.md
250
+ [🖐contrib-rocks]: https://contrib.rocks
251
+ [🖐contributors]: https://github.com/structuredmerge/structuredmerge-ruby/graphs/contributors
252
+ [🖐contributors-img]: https://contrib.rocks/image?repo=structuredmerge/structuredmerge-ruby
253
+ [🪇conduct]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/CODE_OF_CONDUCT.md
254
+ [🪇conduct-img]: https://img.shields.io/badge/Contributor_Covenant-2.1-259D6C.svg
255
+ [📌pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint
256
+ [📌semver]: https://semver.org/spec/v2.0.0.html
257
+ [📌semver-img]: https://img.shields.io/badge/semver-2.0.0-259D6C.svg?style=flat
258
+ [📌semver-breaking]: https://github.com/semver/semver/issues/716#issuecomment-869336139
259
+ [📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html
260
+ [📌changelog]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/CHANGELOG.md
261
+ [📗keep-changelog]: https://keepachangelog.com/en/1.0.0/
262
+ [📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-34495e.svg?style=flat
263
+ [📌gitmoji]: https://gitmoji.dev
264
+ [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
265
+ [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
266
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.164-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
267
+ [🔐security]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/SECURITY.md
268
+ [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
269
+ [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
270
+ [📄license]: LICENSE.md
271
+ [📄license-ref]: LICENSE.md
272
+ [📄license-img]: https://img.shields.io/badge/License-AGPL--3.0--only_OR_PolyForm--Small--Business--1.0.0-259D6C.svg
273
+ [📄license-compat]: https://www.apache.org/legal/resolved.html#category-x
274
+ [📄license-compat-img]: https://img.shields.io/badge/Apache_Incompatible:_Category_X-%E2%9C%97-C0392B.svg?style=flat&logo=Apache
275
+ [📄ilo-declaration]: https://www.ilo.org/declaration/lang--en/index.htm
276
+ [📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat
277
+ [🚎yard-current]: http://rubydoc.info/gems/plain-merge
278
+ [🚎yard-head]: https://plain-merge.galtzo.com
279
+ [💎stone_checksums]: https://github.com/galtzo-floss/stone_checksums
280
+ [💎SHA_checksums]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/tree/main/checksums
281
+ [💎rlts]: https://github.com/rubocop-lts/rubocop-lts
282
+ [💎rlts-img]: https://img.shields.io/badge/code_style_&_linting-rubocop--lts-34495e.svg?plastic&logo=ruby&logoColor=white
283
+ [💎appraisal2]: https://github.com/appraisal-rb/appraisal2
284
+ [💎appraisal2-img]: https://img.shields.io/badge/appraised_by-appraisal2-34495e.svg?plastic&logo=ruby&logoColor=white
285
+ [💎d-in-dvcs]: https://railsbling.com/posts/dvcs/put_the_d_in_dvcs/
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Plain
4
+ # StructuredMerge plain text fallback behavior.
5
+ module Merge
6
+ BACKEND_REFERENCE = TreeHaver::BackendReference.new(id: 'plain-line', family: 'line')
7
+
8
+ module Backend
9
+ # TreeHaver language wrapper for plain text parsed into normalized line
10
+ # and paragraph/block ownership data.
11
+ class Language < TreeHaver::Base::Language
12
+ def initialize(name = :text)
13
+ super(name, backend: :line, options: {})
14
+ end
15
+
16
+ def self.text
17
+ new(:text)
18
+ end
19
+
20
+ def self.plain
21
+ new(:plain)
22
+ end
23
+ end
24
+
25
+ # Parser adapter that exposes plain text analysis through TreeHaver's
26
+ # normalized backend registry.
27
+ class Parser < TreeHaver::Base::Parser
28
+ def parse(source)
29
+ raise 'Language not set' unless language
30
+
31
+ Plain::Merge.analyze_text(source)
32
+ end
33
+
34
+ def parse_string(_old_tree, source)
35
+ parse(source)
36
+ end
37
+ end
38
+ end
39
+
40
+ def self.register_backend!
41
+ TreeHaver::BackendRegistry.register(BACKEND_REFERENCE)
42
+ %i[text plain].each do |language_name|
43
+ register_language!(language_name)
44
+ end
45
+ nil
46
+ end
47
+
48
+ def self.register_language!(language_name)
49
+ TreeHaver.register_language(
50
+ language_name,
51
+ backend_module: Backend,
52
+ backend_type: :line,
53
+ gem_name: 'plain-merge',
54
+ contract: :line
55
+ )
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,205 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Plain
4
+ module Merge
5
+ # Coarse whole-document provider for unstructured plain text.
6
+ # rubocop:disable Metrics/ClassLength, Metrics/MethodLength, Metrics/ParameterLists -- provider operations and envelopes form one cohesive boundary
7
+ class Provider
8
+ def provider_id = 'ruby.text'
9
+ def family = 'text'
10
+
11
+ def capabilities
12
+ {
13
+ operations: Ast::Merge::ProviderContract::OPERATIONS,
14
+ dialects: %i[text],
15
+ backends: [Plain::Merge::BACKEND_REFERENCE.id.to_sym],
16
+ profiles: %i[coarse_document],
17
+ role: :workflow,
18
+ source_preservation: %i[exact_source whole_document_conflict]
19
+ }.freeze
20
+ end
21
+
22
+ def analyze(request)
23
+ result(:analyze, request, analysis: Plain::Merge.analyze_text(request.fetch(:source)))
24
+ end
25
+
26
+ def diff2(request)
27
+ before = request.fetch(:before_source)
28
+ after = request.fetch(:after_source)
29
+ changes = before == after ? [] : [classification(before, before, after)]
30
+ result(:diff2, request, changes: changes, diff: { before: before, after: after, changes: changes })
31
+ end
32
+
33
+ def merge2(request)
34
+ merged = Plain::Merge.merge_text(request.fetch(:incoming_source), request.fetch(:current_source))
35
+ result(
36
+ :merge2,
37
+ request,
38
+ output: merged.fetch(:output),
39
+ render_report: { strategy: :normalized_block_merge },
40
+ verification: { output_rendered: true }
41
+ )
42
+ end
43
+
44
+ def merge3(request)
45
+ base = request.fetch(:base_source)
46
+ ours = request.fetch(:ours_source)
47
+ theirs = request.fetch(:theirs_source)
48
+ return exact_merge3(request, :ours, ours, base, ours, theirs) if ours == theirs || base == theirs
49
+ return exact_merge3(request, :theirs, theirs, base, ours, theirs) if base == ours
50
+
51
+ conflicted_merge3(request, base, ours, theirs)
52
+ end
53
+
54
+ private
55
+
56
+ def exact_merge3(request, role, output, base, ours, theirs)
57
+ rendered = render(request, [source_fragment(role, output)])
58
+ result(
59
+ :merge3,
60
+ request,
61
+ output: rendered.content,
62
+ changes: [classification(base, ours, theirs)],
63
+ render_report: render_report(rendered, :exact_revision),
64
+ verification: { base_participated: true, output_reparsed: true, semantic_match: rendered.content == output }
65
+ )
66
+ end
67
+
68
+ def conflicted_merge3(request, base, ours, theirs)
69
+ conflict = {
70
+ conflict_id: 'text-conflict-root',
71
+ category: :edit_edit,
72
+ path: '',
73
+ change_classification: classification(base, ours, theirs)
74
+ }
75
+ rendered = render(
76
+ request,
77
+ [
78
+ Ast::Merge::SourceRender::ConflictFragment.new(
79
+ conflict_id: conflict.fetch(:conflict_id),
80
+ base: [conflict_side(:base, base)],
81
+ ours: [conflict_side(:ours, ours)],
82
+ theirs: [conflict_side(:theirs, theirs)],
83
+ labels: request.fetch(:labels, {}),
84
+ marker_size: request.fetch(:conflict_marker_size, 7),
85
+ metadata: { path: '', category: :edit_edit }
86
+ )
87
+ ]
88
+ )
89
+ failure(
90
+ :merge3,
91
+ request,
92
+ category: :merge_conflict,
93
+ message: 'Plain text changed independently on both sides.',
94
+ changes: [conflict.fetch(:change_classification)],
95
+ conflicts: [conflict],
96
+ conflicted_output: rendered.content,
97
+ render_report: render_report(rendered, :whole_document_conflict),
98
+ verification: { base_participated: true }
99
+ )
100
+ end
101
+
102
+ def classification(base, ours, theirs)
103
+ {
104
+ path: '',
105
+ ours: base == ours ? :unchanged : :edited,
106
+ theirs: base == theirs ? :unchanged : :edited
107
+ }.freeze
108
+ end
109
+
110
+ def render(request, fragments)
111
+ Ast::Merge::SourceRender::Renderer.new.render(
112
+ Ast::Merge::SourceRender::Plan.new(
113
+ sources: {
114
+ base: request[:base_source].to_s,
115
+ ours: request[:ours_source].to_s,
116
+ theirs: request[:theirs_source].to_s
117
+ },
118
+ fragments: fragments,
119
+ metadata: { provider_id: provider_id }
120
+ )
121
+ )
122
+ end
123
+
124
+ def source_fragment(role, source)
125
+ if source.empty?
126
+ return Ast::Merge::SourceRender::SynthesizedFragment.new(
127
+ content: '',
128
+ reason: :exact_empty_source,
129
+ producer: provider_id,
130
+ metadata: { source_role: role }
131
+ )
132
+ end
133
+
134
+ Ast::Merge::SourceRender::SourceFragment.new(
135
+ revision: role,
136
+ start_line: 1,
137
+ end_line: [source.lines.length, 1].max,
138
+ metadata: { source_role: role }
139
+ )
140
+ end
141
+
142
+ def conflict_side(role, source)
143
+ return source_fragment(role, source) if !source.empty? && source.end_with?("\n")
144
+
145
+ Ast::Merge::SourceRender::SynthesizedFragment.new(
146
+ content: source.empty? ? '' : "#{source}\n",
147
+ reason: :conflict_line_boundary,
148
+ producer: provider_id,
149
+ metadata: { source_role: role, copied_source: true }
150
+ )
151
+ end
152
+
153
+ def render_report(rendered, strategy)
154
+ {
155
+ strategy: strategy,
156
+ line_records: rendered.line_records,
157
+ synthesized_fragments: rendered.synthesized_fragments,
158
+ conflicts: rendered.conflicts,
159
+ verification_input: rendered.verification_input
160
+ }
161
+ end
162
+
163
+ def result(operation, request, changes: [], render_report: {}, verification: {}, **payload)
164
+ Ast::Merge::ProviderResult.build(
165
+ operation: operation,
166
+ success: true,
167
+ envelope: envelope(request, changes: changes, render_report: render_report, verification: verification),
168
+ **payload
169
+ )
170
+ end
171
+
172
+ def failure(operation, request, category:, message:, changes: [], conflicts: [], render_report: {},
173
+ verification: {}, **payload)
174
+ Ast::Merge::ProviderResult.build(
175
+ operation: operation,
176
+ success: false,
177
+ envelope: envelope(
178
+ request,
179
+ changes: changes,
180
+ conflicts: conflicts,
181
+ diagnostics: [{ category: category, severity: :error, message: message, blocking: true }],
182
+ render_report: render_report,
183
+ verification: verification
184
+ ),
185
+ **payload
186
+ )
187
+ end
188
+
189
+ def envelope(request, **fields)
190
+ {
191
+ provider: {
192
+ provider_id: provider_id,
193
+ family: family,
194
+ dialect: request[:dialect] || :text,
195
+ backend: request[:backend],
196
+ package: Plain::Merge::PACKAGE_NAME,
197
+ package_version: Plain::Merge::Version::VERSION
198
+ },
199
+ profile: { profile_id: request[:profile_id] || :coarse_document }
200
+ }.merge(fields)
201
+ end
202
+ end
203
+ # rubocop:enable Metrics/ClassLength, Metrics/MethodLength, Metrics/ParameterLists
204
+ end
205
+ end
@@ -2,10 +2,12 @@
2
2
 
3
3
  module Plain
4
4
  module Merge
5
+ # Version namespace for this gem.
5
6
  module Version
6
- VERSION = "7.0.0"
7
+ # Current gem version.
8
+ VERSION = '7.1.3'
7
9
  end
8
-
9
- VERSION = Version::VERSION
10
+ # Current gem version exposed at the traditional constant location.
11
+ VERSION = Version::VERSION # Traditional Constant Location
10
12
  end
11
13
  end
data/lib/plain/merge.rb CHANGED
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "tree_haver"
3
+ require 'ast/merge'
4
+ require 'tree_haver'
5
+ require_relative 'merge/version'
4
6
 
5
7
  module Plain
6
8
  module Merge
7
- PACKAGE_NAME = "plain-merge"
9
+ PACKAGE_NAME = 'plain-merge'
8
10
  DEFAULT_TEXT_REFINEMENT_THRESHOLD = 0.7
9
11
  DEFAULT_TEXT_REFINEMENT_WEIGHTS = {
10
12
  content: 0.7,
@@ -12,18 +14,28 @@ module Plain
12
14
  position: 0.15
13
15
  }.freeze
14
16
 
17
+ autoload :Provider, 'plain/merge/provider'
18
+
15
19
  module_function
16
20
 
17
21
  def text_feature_profile
18
22
  {
19
- family: "text",
23
+ family: 'text',
20
24
  supported_dialects: [],
21
25
  supported_policies: []
22
26
  }
23
27
  end
24
28
 
29
+ def merge_provider
30
+ @merge_provider ||= Provider.new
31
+ end
32
+
33
+ def register_provider!(replace: false)
34
+ Ast::Merge.register_provider(merge_provider, replace: replace)
35
+ end
36
+
25
37
  def text_parse_request(source)
26
- TreeHaver::ParserRequest.new(source: source, language: "text")
38
+ TreeHaver::ParserRequest.new(source: source, language: 'text')
27
39
  end
28
40
 
29
41
  def normalize_text(source)
@@ -31,7 +43,7 @@ module Plain
31
43
  .gsub(/\r\n?/, "\n")
32
44
  .strip
33
45
  .split(/\n\s*\n+/)
34
- .map { |block| block.strip.gsub(/\s+/, " ") }
46
+ .map { |block| block.strip.gsub(/\s+/, ' ') }
35
47
  .reject(&:empty?)
36
48
  .join("\n\n")
37
49
  end
@@ -57,7 +69,7 @@ module Plain
57
69
  end
58
70
 
59
71
  {
60
- kind: "text",
72
+ kind: 'text',
61
73
  normalized_source: normalized_source,
62
74
  blocks: blocks
63
75
  }
@@ -101,20 +113,17 @@ module Plain
101
113
  template_index = template[:blocks].find_index.with_index do |template_block, candidate_index|
102
114
  !matched_template[candidate_index] && template_block[:normalized] == destination_block[:normalized]
103
115
  end
104
- next unless template_index
105
-
106
- matched_template[template_index] = true
107
- matched_destination[destination_index] = true
108
- matched << {
109
- template_index: template_index,
110
- destination_index: destination_index,
111
- phase: "exact",
112
- score: 1.0
113
- }
114
- end
115
-
116
- destination[:blocks].each_with_index do |destination_block, destination_index|
117
- next if matched_destination[destination_index]
116
+ if template_index
117
+ matched_template[template_index] = true
118
+ matched_destination[destination_index] = true
119
+ matched << {
120
+ template_index: template_index,
121
+ destination_index: destination_index,
122
+ phase: 'exact',
123
+ score: 1.0
124
+ }
125
+ next
126
+ end
118
127
 
119
128
  best_template_index = nil
120
129
  best_score = 0.0
@@ -140,7 +149,7 @@ module Plain
140
149
  matched << {
141
150
  template_index: best_template_index,
142
151
  destination_index: destination_index,
143
- phase: "refined",
152
+ phase: 'refined',
144
153
  score: best_score
145
154
  }
146
155
  end
@@ -172,7 +181,8 @@ module Plain
172
181
  }
173
182
  end
174
183
 
175
- def refined_text_similarity(template_block, destination_block, template_total, destination_total, weights = DEFAULT_TEXT_REFINEMENT_WEIGHTS)
184
+ def refined_text_similarity(template_block, destination_block, template_total, destination_total,
185
+ weights = DEFAULT_TEXT_REFINEMENT_WEIGHTS)
176
186
  content = string_similarity(template_block[:normalized], destination_block[:normalized])
177
187
  length = length_similarity(template_block[:normalized], destination_block[:normalized])
178
188
  position = position_similarity(
@@ -239,6 +249,7 @@ module Plain
239
249
 
240
250
  def length_similarity(left, right)
241
251
  return 1.0 if left.length == right.length
252
+
242
253
  max_length = [left.length, right.length].max
243
254
  return 1.0 if max_length.zero?
244
255
 
@@ -260,3 +271,7 @@ module Plain
260
271
  private_class_method :position_similarity
261
272
  end
262
273
  end
274
+
275
+ require_relative 'merge/backend'
276
+ Plain::Merge.register_backend!
277
+ Plain::Merge.register_provider!
data/lib/plain-merge.rb CHANGED
@@ -1,3 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "plain/merge"
3
+ require_relative 'plain/merge'
4
+ require 'version_gem'
5
+ require_relative 'plain/merge/version'
6
+
7
+ Plain::Merge::Version.class_eval do
8
+ extend VersionGem::Basic
9
+ end
@@ -0,0 +1,21 @@
1
+ module Plain
2
+ module Merge
3
+ class Provider
4
+ def provider_id: () -> String
5
+ def family: () -> String
6
+ def capabilities: () -> Ast::Merge::provider_capabilities
7
+ def analyze: (Ast::Merge::provider_request request) -> Ast::Merge::provider_result
8
+ def diff2: (Ast::Merge::provider_request request) -> Ast::Merge::provider_result
9
+ def merge2: (Ast::Merge::provider_request request) -> Ast::Merge::provider_result
10
+ def merge3: (Ast::Merge::provider_request request) -> Ast::Merge::provider_result
11
+ end
12
+
13
+ def self.merge_provider: () -> Provider
14
+ def self.register_provider!: (?replace: bool) -> Ast::Merge::_MergeProvider
15
+
16
+ module Version
17
+ VERSION: String
18
+ end
19
+ VERSION: String
20
+ end
21
+ end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,11 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plain-merge
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.0.0
4
+ version: 7.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
8
- bindir: bin
8
+ bindir: exe
9
9
  cert_chain:
10
10
  - |
11
11
  -----BEGIN CERTIFICATE-----
@@ -43,54 +43,292 @@ dependencies:
43
43
  requirements:
44
44
  - - '='
45
45
  - !ruby/object:Gem::Version
46
- version: 7.0.0
46
+ version: 7.1.3
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - '='
52
52
  - !ruby/object:Gem::Version
53
- version: 7.0.0
53
+ version: 7.1.3
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: tree_haver
56
56
  requirement: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - '='
59
59
  - !ruby/object:Gem::Version
60
- version: 7.0.0
60
+ version: 7.1.3
61
61
  type: :runtime
62
62
  prerelease: false
63
63
  version_requirements: !ruby/object:Gem::Requirement
64
64
  requirements:
65
65
  - - '='
66
66
  - !ruby/object:Gem::Version
67
- version: 7.0.0
68
- description: Portable text normalization, similarity, matching, and merge behavior
69
- for Structured Merge.
67
+ version: 7.1.3
68
+ - !ruby/object:Gem::Dependency
69
+ name: version_gem
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.1'
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: 1.1.15
78
+ type: :runtime
79
+ prerelease: false
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - "~>"
83
+ - !ruby/object:Gem::Version
84
+ version: '1.1'
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: 1.1.15
88
+ - !ruby/object:Gem::Dependency
89
+ name: kettle-dev
90
+ requirement: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '3.0'
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: 3.0.0
98
+ type: :development
99
+ prerelease: false
100
+ version_requirements: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: '3.0'
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: 3.0.0
108
+ - !ruby/object:Gem::Dependency
109
+ name: bundler-audit
110
+ requirement: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - "~>"
113
+ - !ruby/object:Gem::Version
114
+ version: 0.9.3
115
+ type: :development
116
+ prerelease: false
117
+ version_requirements: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - "~>"
120
+ - !ruby/object:Gem::Version
121
+ version: 0.9.3
122
+ - !ruby/object:Gem::Dependency
123
+ name: rake
124
+ requirement: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - "~>"
127
+ - !ruby/object:Gem::Version
128
+ version: '13.0'
129
+ type: :development
130
+ prerelease: false
131
+ version_requirements: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - "~>"
134
+ - !ruby/object:Gem::Version
135
+ version: '13.0'
136
+ - !ruby/object:Gem::Dependency
137
+ name: require_bench
138
+ requirement: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - "~>"
141
+ - !ruby/object:Gem::Version
142
+ version: '1.0'
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: 1.0.4
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '1.0'
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ version: 1.0.4
156
+ - !ruby/object:Gem::Dependency
157
+ name: anonymous_loader
158
+ requirement: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - "~>"
161
+ - !ruby/object:Gem::Version
162
+ version: '0.1'
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: 0.1.3
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - "~>"
171
+ - !ruby/object:Gem::Version
172
+ version: '0.1'
173
+ - - ">="
174
+ - !ruby/object:Gem::Version
175
+ version: 0.1.3
176
+ - !ruby/object:Gem::Dependency
177
+ name: appraisal2
178
+ requirement: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - "~>"
181
+ - !ruby/object:Gem::Version
182
+ version: '3.2'
183
+ - - ">="
184
+ - !ruby/object:Gem::Version
185
+ version: 3.2.2
186
+ type: :development
187
+ prerelease: false
188
+ version_requirements: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - "~>"
191
+ - !ruby/object:Gem::Version
192
+ version: '3.2'
193
+ - - ">="
194
+ - !ruby/object:Gem::Version
195
+ version: 3.2.2
196
+ - !ruby/object:Gem::Dependency
197
+ name: kettle-test
198
+ requirement: !ruby/object:Gem::Requirement
199
+ requirements:
200
+ - - "~>"
201
+ - !ruby/object:Gem::Version
202
+ version: '2.0'
203
+ - - ">="
204
+ - !ruby/object:Gem::Version
205
+ version: 2.0.19
206
+ type: :development
207
+ prerelease: false
208
+ version_requirements: !ruby/object:Gem::Requirement
209
+ requirements:
210
+ - - "~>"
211
+ - !ruby/object:Gem::Version
212
+ version: '2.0'
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ version: 2.0.19
216
+ - !ruby/object:Gem::Dependency
217
+ name: turbo_tests2
218
+ requirement: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - "~>"
221
+ - !ruby/object:Gem::Version
222
+ version: '3.2'
223
+ - - ">="
224
+ - !ruby/object:Gem::Version
225
+ version: 3.2.5
226
+ type: :development
227
+ prerelease: false
228
+ version_requirements: !ruby/object:Gem::Requirement
229
+ requirements:
230
+ - - "~>"
231
+ - !ruby/object:Gem::Version
232
+ version: '3.2'
233
+ - - ">="
234
+ - !ruby/object:Gem::Version
235
+ version: 3.2.5
236
+ - !ruby/object:Gem::Dependency
237
+ name: ruby-progressbar
238
+ requirement: !ruby/object:Gem::Requirement
239
+ requirements:
240
+ - - "~>"
241
+ - !ruby/object:Gem::Version
242
+ version: '1.13'
243
+ type: :development
244
+ prerelease: false
245
+ version_requirements: !ruby/object:Gem::Requirement
246
+ requirements:
247
+ - - "~>"
248
+ - !ruby/object:Gem::Version
249
+ version: '1.13'
250
+ - !ruby/object:Gem::Dependency
251
+ name: stone_checksums
252
+ requirement: !ruby/object:Gem::Requirement
253
+ requirements:
254
+ - - "~>"
255
+ - !ruby/object:Gem::Version
256
+ version: '1.0'
257
+ - - ">="
258
+ - !ruby/object:Gem::Version
259
+ version: 1.0.8
260
+ type: :development
261
+ prerelease: false
262
+ version_requirements: !ruby/object:Gem::Requirement
263
+ requirements:
264
+ - - "~>"
265
+ - !ruby/object:Gem::Version
266
+ version: '1.0'
267
+ - - ">="
268
+ - !ruby/object:Gem::Version
269
+ version: 1.0.8
270
+ - !ruby/object:Gem::Dependency
271
+ name: gitmoji-regex
272
+ requirement: !ruby/object:Gem::Requirement
273
+ requirements:
274
+ - - "~>"
275
+ - !ruby/object:Gem::Version
276
+ version: '2.0'
277
+ - - ">="
278
+ - !ruby/object:Gem::Version
279
+ version: 2.0.11
280
+ type: :development
281
+ prerelease: false
282
+ version_requirements: !ruby/object:Gem::Requirement
283
+ requirements:
284
+ - - "~>"
285
+ - !ruby/object:Gem::Version
286
+ version: '2.0'
287
+ - - ">="
288
+ - !ruby/object:Gem::Version
289
+ version: 2.0.11
290
+ description: "☯️ Portable text normalization, similarity, matching, and merge behavior
291
+ for Structured Merge."
70
292
  email:
71
- - info@structuredmerge.org
293
+ - floss@galtzo.com
72
294
  executables: []
73
295
  extensions: []
74
296
  extra_rdoc_files: []
75
297
  files:
298
+ - LICENSE.md
299
+ - README.md
76
300
  - lib/plain-merge.rb
77
301
  - lib/plain/merge.rb
302
+ - lib/plain/merge/backend.rb
303
+ - lib/plain/merge/provider.rb
78
304
  - lib/plain/merge/version.rb
305
+ - sig/plain/merge.rbs
79
306
  homepage: https://github.com/structuredmerge/structuredmerge-ruby
80
307
  licenses:
81
308
  - AGPL-3.0-only
82
309
  - PolyForm-Small-Business-1.0.0
83
310
  metadata:
84
311
  homepage_uri: https://structuredmerge.org
85
- source_code_uri: https://github.com/structuredmerge/structuredmerge-ruby/tree/v7.0.0
86
- changelog_uri: https://github.com/structuredmerge/structuredmerge-ruby/blob/v7.0.0/CHANGELOG.md
312
+ source_code_uri: https://github.com/structuredmerge/structuredmerge-ruby/tree/v7.1.3
313
+ changelog_uri: https://github.com/structuredmerge/structuredmerge-ruby/blob/v7.1.3/CHANGELOG.md
87
314
  bug_tracker_uri: https://github.com/structuredmerge/structuredmerge-ruby/issues
88
- documentation_uri: https://www.rubydoc.info/gems/plain-merge/7.0.0
315
+ documentation_uri: https://www.rubydoc.info/gems/plain-merge/7.1.3
89
316
  funding_uri: https://github.com/sponsors/pboling
90
317
  wiki_uri: https://github.com/structuredmerge/structuredmerge-ruby/wiki
318
+ news_uri: https://www.railsbling.com/tags/plain-merge
91
319
  discord_uri: https://discord.gg/3qme4XHNKN
320
+ mailing_list_uri: https://www.rubyforum.org/tag/structuredmerge
92
321
  rubygems_mfa_required: 'true'
93
- rdoc_options: []
322
+ rdoc_options:
323
+ - "--title"
324
+ - plain-merge - ☯️ Structured Merge plain text analysis and merge for Ruby
325
+ - "--main"
326
+ - README.md
327
+ - "--exclude"
328
+ - "^sig/"
329
+ - "--line-numbers"
330
+ - "--inline-source"
331
+ - "--quiet"
94
332
  require_paths:
95
333
  - lib
96
334
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -104,7 +342,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
342
  - !ruby/object:Gem::Version
105
343
  version: '0'
106
344
  requirements: []
107
- rubygems_version: 4.0.10
345
+ rubygems_version: 4.0.17
108
346
  specification_version: 4
109
- summary: Structured Merge plain text analysis and merge for Ruby
347
+ summary: "☯️ Structured Merge plain text analysis and merge for Ruby"
110
348
  test_files: []
metadata.gz.sig CHANGED
Binary file