ast-merge 2.0.1 → 2.0.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: 77a90e163c91b44ac5b425a36dc12643f44dcbb67512f1687aa356a25b88aad8
4
- data.tar.gz: 13791029a6b5c52e02d679720342aa291221d6b57c2b952a9affe7096630b639
3
+ metadata.gz: 87b2cf66d0fbccf11852ffad3a967f7b470473a31e47af2e87fab99e57f54d23
4
+ data.tar.gz: 8472ce9175eb6fb14e29bcb4f65775d6557d40206ec5c763800012cf70ff7178
5
5
  SHA512:
6
- metadata.gz: 4cd7681688742d99e088033bc186b576834ea36f3b6a75184761cc0ec762dabe6fdd880829fa97df13dfea7867acd879d1cde372a3b03f7206a84d94770dec32
7
- data.tar.gz: 0523adc4e7a51ff72efe423bfd01d42f9829c1371c1c92e65bc3eea492f52e1096992ed56766c461aa88b037db328758a4b09c7ee0d74c548457449b49ba2b9b
6
+ metadata.gz: 7149ffb09a690608f382f63e9cff91bd85ceb25518b6744cc4617c638fe0acc4bd3a96de17f047c72161a5e4836b615e1721e550e34eee998916ab78b82df380
7
+ data.tar.gz: 0b5b63b49be561c75027767dd850a692d31a047e000aa2404cc83df27bc4304a6d047e434e2402ddf1ffaed63a5044ea60f515b80959284b6faa52222da8e7fa
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,43 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [2.0.3] - 2025-12-30
34
+
35
+ - TAG: [v2.0.3][2.0.3t]
36
+ - COVERAGE: 88.45% -- 2894/3272 lines in 53 files
37
+ - BRANCH COVERAGE: 67.83% -- 698/1029 branches in 53 files
38
+ - 98.82% documented
39
+
40
+ ### Fixed
41
+
42
+ - `Ast::Merge::DebugLogger::BENCHMARK_AVAILABLE` now correctly detects when benchmark gem is unavailable
43
+ - Previous implementation used `autoload` which never raises `LoadError` (it only registers for lazy loading)
44
+ - Now uses `require "benchmark"` which properly catches `LoadError` on Ruby 4.0+ where benchmark is a bundled gem
45
+ - The `#time` method now correctly falls back to non-timed execution when benchmark is unavailable
46
+
47
+ ## [2.0.2] - 2025-12-30
48
+
49
+ - TAG: [v2.0.2][2.0.2t]
50
+ - COVERAGE: 88.47% -- 2894/3271 lines in 53 files
51
+ - BRANCH COVERAGE: 67.83% -- 698/1029 branches in 53 files
52
+ - 98.82% documented
53
+
54
+ ### Added
55
+
56
+ - Backend Platform Compatibility section to README and GEM_FAMILY_SECTION.md
57
+ - Documents which tree_haver backends work on MRI, JRuby, and TruffleRuby
58
+ - Explains why JRuby and TruffleRuby have limited tree-sitter backend support
59
+
60
+ ### Changed
61
+
62
+ - Updated RSpec README documentation for tree_haver dependency tag changes
63
+ - All tags now follow consistent naming conventions with suffixes
64
+ - Backend tags use `*_backend` suffix
65
+ - Engine tags use `*_engine` suffix
66
+ - Grammar tags use `*_grammar` suffix
67
+ - Parsing capability tags use `*_parsing` suffix
68
+ - See [lib/ast/merge/rspec/README.md](lib/ast/merge/rspec/README.md) for complete tag reference
69
+
33
70
  ## [2.0.1] - 2025-12-29
34
71
 
35
72
  - TAG: [v2.0.1][2.0.1t]
@@ -261,7 +298,11 @@ Please file a bug if you notice a violation of semantic versioning.
261
298
 
262
299
  - Initial release
263
300
 
264
- [Unreleased]: https://github.com/kettle-rb/ast-merge/compare/v2.0.1...HEAD
301
+ [Unreleased]: https://github.com/kettle-rb/ast-merge/compare/v2.0.3...HEAD
302
+ [2.0.3]: https://github.com/kettle-rb/ast-merge/compare/v2.0.2...v2.0.3
303
+ [2.0.3t]: https://github.com/kettle-rb/ast-merge/releases/tag/v2.0.3
304
+ [2.0.2]: https://github.com/kettle-rb/ast-merge/compare/v2.0.1...v2.0.2
305
+ [2.0.2t]: https://github.com/kettle-rb/ast-merge/releases/tag/v2.0.2
265
306
  [2.0.1]: https://github.com/kettle-rb/ast-merge/compare/v2.0.0...v2.0.1
266
307
  [2.0.1t]: https://github.com/kettle-rb/ast-merge/releases/tag/v2.0.1
267
308
  [2.0.0]: https://github.com/kettle-rb/ast-merge/compare/v1.1.0...v2.0.0
data/README.md CHANGED
@@ -1,16 +1,16 @@
1
- | 📍 NOTE |
2
- |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
3
- | RubyGems (the [GitHub org][rubygems-org], not the website) [suffered][draper-security] a [hostile takeover][ellen-takeover] in September 2025. |
4
- | Ultimately [4 maintainers][simi-removed] were [hard removed][martin-removed] and a reason has been given for only 1 of those, while 2 others resigned in protest. |
5
- | It is a [complicated story][draper-takeover] which is difficult to [parse quickly][draper-lies]. |
6
- | Simply put - there was active policy for adding or removing maintainers/owners of [rubygems][rubygems-maint-policy] and [bundler][bundler-maint-policy], and those [policies were not followed][policy-fail]. |
7
- | I'm adding notes like this to gems because I [don't condone theft][draper-theft] of repositories or gems from their rightful owners. |
8
- | If a similar theft happened with my repos/gems, I'd hope some would stand up for me. |
9
- | Disenfranchised former-maintainers have started [gem.coop][gem-coop]. |
10
- | Once available I will publish there exclusively; unless RubyCentral makes amends with the community. |
11
- | The ["Technology for Humans: Joel Draper"][reinteractive-podcast] podcast episode by [reinteractive][reinteractive] is the most cogent summary I'm aware of. |
12
- | See [here][gem-naming], [here][gem-coop] and [here][martin-ann] for more info on what comes next. |
13
- | What I'm doing: A (WIP) proposal for [bundler/gem scopes][gem-scopes], and a (WIP) proposal for a federated [gem server][gem-server]. |
1
+ | 📍 NOTE |
2
+ | --- |
3
+ | RubyGems (the [GitHub org](https://github.com/rubygems/), not the website) [suffered](https://joel.drapper.me/p/ruby-central-security-measures/) a [hostile takeover](https://pup-e.com/blog/goodbye-rubygems/) in September 2025. |
4
+ | Ultimately [4 maintainers](https://www.reddit.com/r/ruby/s/gOk42POCaV) were [hard removed](https://bsky.app/profile/martinemde.com/post/3m3occezxxs2q) and a reason has been given for only 1 of those, while 2 others resigned in protest. |
5
+ | It is a [complicated story](https://joel.drapper.me/p/ruby-central-takeover/) which is difficult to [parse quickly](https://joel.drapper.me/p/ruby-central-fact-check/). |
6
+ | Simply put - there was active policy for adding or removing maintainers/owners of [rubygems](https://github.com/ruby/rubygems/blob/b1ab33a3d52310a84d16b193991af07f5a6a07c0/doc/rubygems/POLICIES.md?plain=1#L187-L196) and [bundler](https://github.com/ruby/rubygems/blob/b1ab33a3d52310a84d16b193991af07f5a6a07c0/doc/bundler/playbooks/TEAM_CHANGES.md), and those [policies were not followed](https://www.reddit.com/r/ruby/comments/1ove9vp/rubycentral_hates_this_one_fact/). |
7
+ | I'm adding notes like this to gems because I [don't condone theft](https://joel.drapper.me/p/ruby-central/) of repositories or gems from their rightful owners. |
8
+ | If a similar theft happened with my repos/gems, I'd hope some would stand up for me. |
9
+ | Disenfranchised former-maintainers have started [gem.coop](https://gem.coop). |
10
+ | Once available I will publish there exclusively; unless RubyCentral makes amends with the community. |
11
+ | The ["Technology for Humans: Joel Draper"](https://youtu.be/_H4qbtC5qzU?si=BvuBU90R2wAqD2E6) podcast episode by [reinteractive](https://reinteractive.com/ruby-on-rails) is the most cogent summary I'm aware of. |
12
+ | See [here](https://github.com/gem-coop/gem.coop/issues/12), [here](https://gem.coop) and [here](https://martinemde.com/2025/10/05/announcing-gem-coop.html) for more info on what comes next. |
13
+ | What I'm doing: A (WIP) proposal for [bundler/gem scopes](https://github.com/galtzo-floss/bundle-namespace), and a (WIP) proposal for a federated [gem server](https://github.com/galtzo-floss/gem-server). |
14
14
 
15
15
  [rubygems-org]: https://github.com/rubygems/
16
16
  [draper-security]: https://joel.drapper.me/p/ruby-central-security-measures/
@@ -31,7 +31,7 @@
31
31
  [rubygems-maint-policy]: https://github.com/ruby/rubygems/blob/b1ab33a3d52310a84d16b193991af07f5a6a07c0/doc/rubygems/POLICIES.md?plain=1#L187-L196
32
32
  [policy-fail]: https://www.reddit.com/r/ruby/comments/1ove9vp/rubycentral_hates_this_one_fact/
33
33
 
34
- [![Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0][🖼️galtzo-i]][🖼️galtzo-discord] [![ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5][🖼️ruby-lang-i]][🖼️ruby-lang] [![kettle-rb Logo by Aboling0, CC BY-SA 4.0][🖼️kettle-rb-i]][🖼️kettle-rb]
34
+ [![Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0](https://logos.galtzo.com/assets/images/galtzo-floss/avatar-192px.svg)](https://discord.gg/3qme4XHNKN) [![ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5](https://logos.galtzo.com/assets/images/ruby-lang/avatar-192px.svg)](https://www.ruby-lang.org/) [![kettle-rb Logo by Aboling0, CC BY-SA 4.0](https://logos.galtzo.com/assets/images/kettle-rb/avatar-192px.svg)](https://github.com/kettle-rb)
35
35
 
36
36
  [🖼️galtzo-i]: https://logos.galtzo.com/assets/images/galtzo-floss/avatar-192px.svg
37
37
  [🖼️galtzo-discord]: https://discord.gg/3qme4XHNKN
@@ -42,20 +42,20 @@
42
42
 
43
43
  # ☯️ Ast::Merge
44
44
 
45
- [![Version][👽versioni]][👽version] [![GitHub tag (latest SemVer)][⛳️tag-img]][⛳️tag] [![License: MIT][📄license-img]][📄license-ref] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![Open Source Helpers][👽oss-helpi]][👽oss-help] [![CodeCov Test Coverage][🏀codecovi]][🏀codecov] [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls] [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov] [![QLTY Maintainability][🏀qlty-mnti]][🏀qlty-mnt] [![CI Heads][🚎3-hd-wfi]][🚎3-hd-wf] [![CI Runtime Dependencies @ HEAD][🚎12-crh-wfi]][🚎12-crh-wf] [![CI Current][🚎11-c-wfi]][🚎11-c-wf] [![CI Truffle Ruby][🚎9-t-wfi]][🚎9-t-wf] [![Deps Locked][🚎13-🔒️-wfi]][🚎13-🔒️-wf] [![Deps Unlocked][🚎14-🔓️-wfi]][🚎14-🔓️-wf] [![CI Supported][🚎6-s-wfi]][🚎6-s-wf] [![CI Test Coverage][🚎2-cov-wfi]][🚎2-cov-wf] [![CI Style][🚎5-st-wfi]][🚎5-st-wf] [![CodeQL][🖐codeQL-img]][🖐codeQL] [![Apache SkyWalking Eyes License Compatibility Check][🚎15-🪪-wfi]][🚎15-🪪-wf]
45
+ [![Version](https://img.shields.io/gem/v/ast-merge.svg)](https://bestgems.org/gems/ast-merge) [![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/kettle-rb/ast-merge.svg)](http://github.com/kettle-rb/ast-merge/releases) [![License: MIT](https://img.shields.io/badge/License-MIT-259D6C.svg)](https://opensource.org/licenses/MIT) [![Downloads Rank](https://img.shields.io/gem/rd/ast-merge.svg)](https://bestgems.org/gems/ast-merge) [![Open Source Helpers](https://www.codetriage.com/kettle-rb/ast-merge/badges/users.svg)](https://www.codetriage.com/kettle-rb/ast-merge) [![CodeCov Test Coverage](https://codecov.io/gh/kettle-rb/ast-merge/graph/badge.svg)](https://codecov.io/gh/kettle-rb/ast-merge) [![Coveralls Test Coverage](https://coveralls.io/repos/github/kettle-rb/ast-merge/badge.svg?branch=main)](https://coveralls.io/github/kettle-rb/ast-merge?branch=main) [![QLTY Test Coverage](https://qlty.sh/gh/kettle-rb/projects/ast-merge/coverage.svg)](https://qlty.sh/gh/kettle-rb/projects/ast-merge/metrics/code?sort=coverageRating) [![QLTY Maintainability](https://qlty.sh/gh/kettle-rb/projects/ast-merge/maintainability.svg)](https://qlty.sh/gh/kettle-rb/projects/ast-merge) [![CI Heads](https://github.com/kettle-rb/ast-merge/actions/workflows/heads.yml/badge.svg)](https://github.com/kettle-rb/ast-merge/actions/workflows/heads.yml) [![CI Runtime Dependencies @ HEAD](https://github.com/kettle-rb/ast-merge/actions/workflows/dep-heads.yml/badge.svg)](https://github.com/kettle-rb/ast-merge/actions/workflows/dep-heads.yml) [![CI Current](https://github.com/kettle-rb/ast-merge/actions/workflows/current.yml/badge.svg)](https://github.com/kettle-rb/ast-merge/actions/workflows/current.yml) [![CI Truffle Ruby](https://github.com/kettle-rb/ast-merge/actions/workflows/truffle.yml/badge.svg)](https://github.com/kettle-rb/ast-merge/actions/workflows/truffle.yml) [![Deps Locked](https://github.com/kettle-rb/ast-merge/actions/workflows/locked_deps.yml/badge.svg)](https://github.com/kettle-rb/ast-merge/actions/workflows/locked_deps.yml) [![Deps Unlocked](https://github.com/kettle-rb/ast-merge/actions/workflows/unlocked_deps.yml/badge.svg)](https://github.com/kettle-rb/ast-merge/actions/workflows/unlocked_deps.yml) [![CI Supported](https://github.com/kettle-rb/ast-merge/actions/workflows/supported.yml/badge.svg)](https://github.com/kettle-rb/ast-merge/actions/workflows/supported.yml) [![CI Test Coverage](https://github.com/kettle-rb/ast-merge/actions/workflows/coverage.yml/badge.svg)](https://github.com/kettle-rb/ast-merge/actions/workflows/coverage.yml) [![CI Style](https://github.com/kettle-rb/ast-merge/actions/workflows/style.yml/badge.svg)](https://github.com/kettle-rb/ast-merge/actions/workflows/style.yml) [![CodeQL](https://github.com/kettle-rb/ast-merge/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/kettle-rb/ast-merge/security/code-scanning) [![Apache SkyWalking Eyes License Compatibility Check](https://github.com/kettle-rb/prism-merge/actions/workflows/license-eye.yml/badge.svg)](https://github.com/kettle-rb/ast-merge/actions/workflows/license-eye.yml)
46
46
 
47
- `if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know][🖼️galtzo-discord], as I may have missed the [discord notification][🖼️galtzo-discord].
48
-
49
- ---
47
+ `if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know](https://discord.gg/3qme4XHNKN), as I may have missed the [discord notification](https://discord.gg/3qme4XHNKN).
50
48
 
49
+ -----
51
50
  `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.
52
51
 
53
- [![OpenCollective Backers][🖇osc-backers-i]][🖇osc-backers] [![OpenCollective Sponsors][🖇osc-sponsors-i]][🖇osc-sponsors] [![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 on Polar][🖇polar-img]][🖇polar] [![Donate at ko-fi.com][🖇kofi-img]][🖇kofi]
52
+ [![OpenCollective Backers](https://opencollective.com/kettle-rb/backers/badge.svg?style=flat)](https://opencollective.com/kettle-rb#backer) [![OpenCollective Sponsors](https://opencollective.com/kettle-rb/sponsors/badge.svg?style=flat)](https://opencollective.com/kettle-rb#sponsor) [![Sponsor Me on Github](https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github)](https://github.com/sponsors/pboling) [![Liberapay Goal Progress](https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611&style=flat)](https://liberapay.com/pboling/donate) [![Donate on PayPal](https://img.shields.io/badge/donate-paypal-a51611.svg?style=flat&logo=paypal)](https://www.paypal.com/paypalme/peterboling) [![Buy me a coffee](https://img.shields.io/badge/buy_me_a_coffee-%E2%9C%93-a51611.svg?style=flat)](https://www.buymeacoffee.com/pboling) [![Donate on Polar](https://img.shields.io/badge/polar-donate-a51611.svg?style=flat)](https://polar.sh/pboling) [![Donate at ko-fi.com](https://img.shields.io/badge/ko--fi-%E2%9C%93-a51611.svg?style=flat)](https://ko-fi.com/O5O86SNP4)
54
53
 
55
54
  ## 🌻 Synopsis
56
55
 
57
56
  Ast::Merge is **not typically used directly** - instead, use one of the format-specific gems built on top of it.
58
57
 
58
+
59
59
  ### The `*-merge` Gem Family
60
60
 
61
61
  The `*-merge` gem family provides intelligent, AST-based merging for various file formats. At the foundation is [tree_haver][tree_haver], which provides a unified cross-Ruby parsing API that works seamlessly across MRI, JRuby, and TruffleRuby.
@@ -79,9 +79,9 @@ The `*-merge` gem family provides intelligent, AST-based merging for various fil
79
79
  **Example implementations** for the gem templating use case:
80
80
 
81
81
  | Gem | Purpose | Description |
82
- |-----|---------|-------------|
83
- | [kettle-dev][kettle-dev] | Gem Development | Gem templating tool using `*-merge` gems |
84
- | [kettle-jem][kettle-jem] | Gem Templating | Gem template library with smart merge support |
82
+ | --- | --- | --- |
83
+ | [kettle-dev](https://github.com/kettle-rb/kettle-dev) | Gem Development | Gem templating tool using `*-merge` gems |
84
+ | [kettle-jem](https://github.com/kettle-rb/kettle-jem) | Gem Templating | Gem template library with smart merge support |
85
85
 
86
86
  [tree_haver]: https://github.com/kettle-rb/tree_haver
87
87
  [ast-merge]: https://github.com/kettle-rb/ast-merge
@@ -107,84 +107,112 @@ The `*-merge` gem family provides intelligent, AST-based merging for various fil
107
107
  [toml-rb]: https://github.com/emancu/toml-rb
108
108
  [markly]: https://github.com/ioquatix/markly
109
109
  [commonmarker]: https://github.com/gjtorikian/commonmarker
110
+ [ruby_tree_sitter]: https://github.com/Faveod/ruby-tree-sitter
111
+ [tree_stump]: https://github.com/joker1007/tree_stump
112
+ [jtreesitter]: https://central.sonatype.com/artifact/io.github.tree-sitter/jtreesitter
110
113
 
111
- ### Architecture: tree_haver + ast-merge
112
114
 
113
- The `*-merge` gem family is built on a two-layer architecture:
115
+ [ts-jsonc]: https://gitlab.com/WhyNotHugo/tree-sitter-jsonc
116
+ [dotenv]: https://github.com/bkeepers/dotenv
114
117
 
115
- #### Layer 1: tree_haver (Parsing Foundation)
118
+ #### Backend Platform Compatibility
116
119
 
117
- [tree_haver][tree_haver] provides cross-Ruby parsing capabilities:
120
+ tree\_haver supports multiple parsing backends, but not all backends work on all Ruby platforms:
118
121
 
119
- - **Universal Backend Support**: Automatically selects the best parsing backend for your Ruby implementation (MRI, JRuby, TruffleRuby)
120
- - **10 Backend Options**: MRI C extensions, Rust bindings, FFI, Java (JRuby), language-specific parsers (Prism, Psych, Commonmarker, Markly), and pure Ruby fallback (Citrus)
121
- - **Unified API**: Write parsing code once, run on any Ruby implementation
122
- - **Grammar Discovery**: Built-in `GrammarFinder` for platform-aware grammar library discovery
123
- - **Thread-Safe**: Language registry with thread-safe caching
122
+ | Backend | MRI | JRuby | TruffleRuby | Notes |
123
+ | --- | :-: | :-: | :-: | --- |
124
+ | **MRI** ([ruby\_tree\_sitter](https://github.com/Faveod/ruby-tree-sitter)) | | | | C extension, MRI only |
125
+ | **Rust** ([tree\_stump](https://github.com/joker1007/tree_stump)) | | ❌ | ❌ | Rust extension via magnus/rb-sys, MRI only |
126
+ | **FFI** | | | ❌ | TruffleRuby's FFI doesn't support `STRUCT_BY_VALUE` |
127
+ | **Java** ([jtreesitter](https://central.sonatype.com/artifact/io.github.tree-sitter/jtreesitter)) | ❌ | ✅ | ❌ | JRuby only, requires grammar JARs |
128
+ | **Prism** | ✅ | ✅ | ✅ | Ruby parsing, stdlib in Ruby 3.4+ |
129
+ | **Psych** | ✅ | ✅ | ✅ | YAML parsing, stdlib |
130
+ | **Citrus** | ✅ | ✅ | ✅ | Pure Ruby, no native dependencies |
131
+ | **Commonmarker** | ✅ | ❌ | ❓ | Rust extension for Markdown |
132
+ | **Markly** | ✅ | ❌ | ❓ | C extension for Markdown |
124
133
 
125
- #### Layer 2: ast-merge (Merge Infrastructure)
134
+ **Legend**: = Works, = Does not work, ❓ = Untested
135
+
136
+ **Why some backends don't work on certain platforms**:
137
+
138
+ - **JRuby**: Runs on the JVM; cannot load native C/Rust extensions (`.so` files)
139
+ - **TruffleRuby**: Has C API emulation via Sulong/LLVM, but it doesn't expose all MRI internals that native extensions require (e.g., `RBasic.flags`, `rb_gc_writebarrier`)
140
+ - **FFI on TruffleRuby**: TruffleRuby's FFI implementation doesn't support returning structs by value, which tree-sitter's C API requires
141
+ ### Architecture: tree\_haver + ast-merge
142
+
143
+ The `*-merge` gem family is built on a two-layer architecture:
126
144
 
127
- Ast::Merge builds on tree_haver to provide:
145
+ #### Layer 1: tree\_haver (Parsing Foundation)
128
146
 
129
- - **Base Classes**: `FreezeNode`, `MergeResult` base classes with unified constructors
130
- - **Shared Modules**: `FileAnalysisBase`, `FileAnalyzable`, `MergerConfig`, `DebugLogger`
131
- - **Freeze Block Support**: Configurable marker patterns for multiple comment syntaxes (preserve sections during merge)
132
- - **Node Typing System**: `NodeTyping` for canonical node type identification across different parsers
133
- - **Conflict Resolution**: `ConflictResolverBase` with pluggable strategies
134
- - **Error Classes**: `ParseError`, `TemplateParseError`, `DestinationParseError`
135
- - **Region Detection**: `RegionDetectorBase`, `FencedCodeBlockDetector` for text-based analysis
136
- - **RSpec Shared Examples**: Test helpers for implementing new merge gems
147
+ [tree\_haver](https://github.com/kettle-rb/tree_haver) provides cross-Ruby parsing capabilities:
137
148
 
149
+ - **Universal Backend Support**: Automatically selects the best parsing backend for your Ruby implementation (MRI, JRuby, TruffleRuby)
150
+ - **10 Backend Options**: MRI C extensions, Rust bindings, FFI, Java (JRuby), language-specific parsers (Prism, Psych, Commonmarker, Markly), and pure Ruby fallback (Citrus)
151
+ - **Unified API**: Write parsing code once, run on any Ruby implementation
152
+ - **Grammar Discovery**: Built-in `GrammarFinder` for platform-aware grammar library discovery
153
+ - **Thread-Safe**: Language registry with thread-safe caching
154
+ #### Layer 2: ast-merge (Merge Infrastructure)
155
+
156
+ Ast::Merge builds on tree\_haver to provide:
157
+
158
+ - **Base Classes**: `FreezeNode`, `MergeResult` base classes with unified constructors
159
+ - **Shared Modules**: `FileAnalysisBase`, `FileAnalyzable`, `MergerConfig`, `DebugLogger`
160
+ - **Freeze Block Support**: Configurable marker patterns for multiple comment syntaxes (preserve sections during merge)
161
+ - **Node Typing System**: `NodeTyping` for canonical node type identification across different parsers
162
+ - **Conflict Resolution**: `ConflictResolverBase` with pluggable strategies
163
+ - **Error Classes**: `ParseError`, `TemplateParseError`, `DestinationParseError`
164
+ - **Region Detection**: `RegionDetectorBase`, `FencedCodeBlockDetector` for text-based analysis
165
+ - **RSpec Shared Examples**: Test helpers for implementing new merge gems
138
166
  ### Creating a New Merge Gem
139
167
 
140
- ```ruby
168
+ ``` ruby
141
169
  require "ast/merge"
142
170
 
143
171
  module MyFormat
144
172
  module Merge
145
173
  # Inherit from base classes and pass **options for forward compatibility
146
-
174
+
147
175
  class SmartMerger < Ast::Merge::SmartMergerBase
148
176
  DEFAULT_FREEZE_TOKEN = "myformat-merge"
149
-
177
+
150
178
  def initialize(template, dest, my_custom_option: nil, **options)
151
179
  @my_custom_option = my_custom_option
152
180
  super(template, dest, **options)
153
181
  end
154
-
182
+
155
183
  protected
156
-
184
+
157
185
  def analysis_class
158
186
  FileAnalysis
159
187
  end
160
-
188
+
161
189
  def default_freeze_token
162
190
  DEFAULT_FREEZE_TOKEN
163
191
  end
164
-
192
+
165
193
  def perform_merge
166
194
  # Implement format-specific merge logic
167
195
  # Returns a MergeResult
168
196
  end
169
197
  end
170
-
198
+
171
199
  class FileAnalysis
172
200
  include Ast::Merge::FileAnalyzable
173
-
201
+
174
202
  def initialize(source, freeze_token: nil, signature_generator: nil, **options)
175
203
  @source = source
176
204
  @freeze_token = freeze_token
177
205
  @signature_generator = signature_generator
178
206
  # Process source...
179
207
  end
180
-
208
+
181
209
  def compute_node_signature(node)
182
210
  # Return signature array for node matching
183
211
  end
184
212
  end
185
-
213
+
186
214
  class ConflictResolver < Ast::Merge::ConflictResolverBase
187
- def initialize(template_analysis, dest_analysis, preference: :destination,
215
+ def initialize(template_analysis, dest_analysis, preference: :destination,
188
216
  add_template_only_nodes: false, match_refiner: nil, **options)
189
217
  super(
190
218
  strategy: :batch, # or :node, :boundary
@@ -196,30 +224,30 @@ module MyFormat
196
224
  **options
197
225
  )
198
226
  end
199
-
227
+
200
228
  protected
201
-
229
+
202
230
  def resolve_batch(result)
203
231
  # Implement batch resolution logic
204
232
  end
205
233
  end
206
-
234
+
207
235
  class MergeResult < Ast::Merge::MergeResultBase
208
236
  def initialize(**options)
209
237
  super(**options)
210
238
  @statistics = { merged_count: 0 }
211
239
  end
212
-
240
+
213
241
  def to_my_format
214
242
  to_s
215
243
  end
216
244
  end
217
-
245
+
218
246
  class MatchRefiner < Ast::Merge::MatchRefinerBase
219
247
  def initialize(threshold: 0.7, node_types: nil, **options)
220
248
  super(threshold: threshold, node_types: node_types, **options)
221
249
  end
222
-
250
+
223
251
  def similarity(template_node, dest_node)
224
252
  # Return similarity score between 0.0 and 1.0
225
253
  end
@@ -231,7 +259,7 @@ end
231
259
  ### Base Classes Reference
232
260
 
233
261
  | Base Class | Purpose | Key Methods to Implement |
234
- |------------|---------|-------------------------|
262
+ | --- | --- | --- |
235
263
  | `SmartMergerBase` | Main merge orchestration | `analysis_class`, `perform_merge` |
236
264
  | `ConflictResolverBase` | Resolve node conflicts | `resolve_batch` or `resolve_node_pair` |
237
265
  | `MergeResultBase` | Track merge results | `to_s`, format-specific output |
@@ -243,7 +271,7 @@ end
243
271
 
244
272
  `Ast::Merge::ContentMatchRefiner` is a built-in match refiner for fuzzy text content matching using Levenshtein distance. Unlike signature-based matching which requires exact content hashes, this refiner allows matching nodes with similar (but not identical) content.
245
273
 
246
- ```ruby
274
+ ``` ruby
247
275
  # Basic usage - match nodes with 70% similarity
248
276
  refiner = Ast::Merge::ContentMatchRefiner.new(threshold: 0.7)
249
277
 
@@ -279,17 +307,16 @@ merger = MyFormat::SmartMerger.new(
279
307
  ```
280
308
 
281
309
  This is particularly useful for:
282
- - Paragraphs with minor edits (typos, rewording)
283
- - Headings with slight changes
284
- - Comments with updated text
285
- - Any text-based node that may have been slightly modified
286
-
310
+ - Paragraphs with minor edits (typos, rewording)
311
+ - Headings with slight changes
312
+ - Comments with updated text
313
+ - Any text-based node that may have been slightly modified
287
314
  ### Namespace Reference
288
315
 
289
316
  The `Ast::Merge` module is organized into several namespaces, each with detailed documentation:
290
317
 
291
318
  | Namespace | Purpose | Documentation |
292
- |-----------|---------|---------------|
319
+ | --- | --- | --- |
293
320
  | `Ast::Merge::Detector` | Region detection and merging | [lib/ast/merge/detector/README.md](lib/ast/merge/detector/README.md) |
294
321
  | `Ast::Merge::Recipe` | YAML-based merge recipes | [lib/ast/merge/recipe/README.md](lib/ast/merge/recipe/README.md) |
295
322
  | `Ast::Merge::Comment` | Comment parsing and representation | [lib/ast/merge/comment/README.md](lib/ast/merge/comment/README.md) |
@@ -298,46 +325,45 @@ The `Ast::Merge` module is organized into several namespaces, each with detailed
298
325
 
299
326
  **Key Classes by Namespace:**
300
327
 
301
- - **Detector**: `Region`, `Base`, `Mergeable`, `FencedCodeBlock`, `YamlFrontmatter`, `TomlFrontmatter`
302
- - **Recipe**: `Config`, `Runner`, `ScriptLoader`
303
- - **Comment**: `Line`, `Block`, `Empty`, `Parser`, `Style`
304
- - **Text**: `SmartMerger`, `FileAnalysis`, `LineNode`, `WordNode`, `Section`
305
- - **RSpec**: Shared examples and dependency tags for testing `*-merge` implementations
306
-
328
+ - **Detector**: `Region`, `Base`, `Mergeable`, `FencedCodeBlock`, `YamlFrontmatter`, `TomlFrontmatter`
329
+ - **Recipe**: `Config`, `Runner`, `ScriptLoader`
330
+ - **Comment**: `Line`, `Block`, `Empty`, `Parser`, `Style`
331
+ - **Text**: `SmartMerger`, `FileAnalysis`, `LineNode`, `WordNode`, `Section`
332
+ - **RSpec**: Shared examples and dependency tags for testing `*-merge` implementations
307
333
  ## 💡 Info you can shake a stick at
308
334
 
309
- | Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |
310
- |-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
311
- | Works with JRuby | [![JRuby 10.0 Compat][💎jruby-c-i]][🚎11-c-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf] |
312
- | Works with Truffle Ruby | [![Truffle Ruby 23.1 Compat][💎truby-23.1i]][🚎9-t-wf] [![Truffle Ruby 24.1 Compat][💎truby-c-i]][🚎11-c-wf] |
313
- | Works with MRI Ruby 3 | [![Ruby 3.2 Compat][💎ruby-3.2i]][🚎6-s-wf] [![Ruby 3.3 Compat][💎ruby-3.3i]][🚎6-s-wf] [![Ruby 3.4 Compat][💎ruby-c-i]][🚎11-c-wf] [![Ruby HEAD Compat][💎ruby-headi]][🚎3-hd-wf] |
314
- | Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![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] |
315
- | 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] |
316
- | 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] |
317
- | Compliance | [![License: MIT][📄license-img]][📄license-ref] [![Compatible with Apache Software Projects: Verified by SkyWalking Eyes][📄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] |
318
- | 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] |
319
- | 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] |
320
- | `...` 💖 | [![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] |
335
+ | Tokens to Remember | [![Gem name](https://img.shields.io/badge/name-ast--merge-3C2D2D.svg?style=square&logo=rubygems&logoColor=red)](https://bestgems.org/gems/ast-merge) [![Gem namespace](https://img.shields.io/badge/namespace-Ast::Merge-3C2D2D.svg?style=square&logo=ruby&logoColor=white)](https://github.com/kettle-rb/ast-merge) |
336
+ | --- | --- |
337
+ | Works with JRuby | [![JRuby 10.0 Compat](https://img.shields.io/badge/JRuby-current-FBE742?style=for-the-badge&logo=ruby&logoColor=green)](https://github.com/kettle-rb/ast-merge/actions/workflows/current.yml) [![JRuby HEAD Compat](https://img.shields.io/badge/JRuby-HEAD-FBE742?style=for-the-badge&logo=ruby&logoColor=blue)](https://github.com/kettle-rb/ast-merge/actions/workflows/heads.yml) |
338
+ | Works with Truffle Ruby | [![Truffle Ruby 23.1 Compat](https://img.shields.io/badge/Truffle_Ruby-23.1-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink)](https://github.com/kettle-rb/ast-merge/actions/workflows/truffle.yml) [![Truffle Ruby 24.1 Compat](https://img.shields.io/badge/Truffle_Ruby-current-34BCB1?style=for-the-badge&logo=ruby&logoColor=green)](https://github.com/kettle-rb/ast-merge/actions/workflows/current.yml) |
339
+ | Works with MRI Ruby 3 | [![Ruby 3.2 Compat](https://img.shields.io/badge/Ruby-3.2-CC342D?style=for-the-badge&logo=ruby&logoColor=white)](https://github.com/kettle-rb/ast-merge/actions/workflows/supported.yml) [![Ruby 3.3 Compat](https://img.shields.io/badge/Ruby-3.3-CC342D?style=for-the-badge&logo=ruby&logoColor=white)](https://github.com/kettle-rb/ast-merge/actions/workflows/supported.yml) [![Ruby 3.4 Compat](https://img.shields.io/badge/Ruby-current-CC342D?style=for-the-badge&logo=ruby&logoColor=green)](https://github.com/kettle-rb/ast-merge/actions/workflows/current.yml) [![Ruby HEAD Compat](https://img.shields.io/badge/Ruby-HEAD-CC342D?style=for-the-badge&logo=ruby&logoColor=blue)](https://github.com/kettle-rb/ast-merge/actions/workflows/heads.yml) |
340
+ | Support & Community | [![Join Me on Daily.dev's RubyFriends](https://img.shields.io/badge/daily.dev-%F0%9F%92%8E_Ruby_Friends-0A0A0A?style=for-the-badge&logo=dailydotdev&logoColor=white)](https://app.daily.dev/squads/rubyfriends) [![Live Chat on Discord](https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord)](https://discord.gg/3qme4XHNKN) [![Get help from me on Upwork](https://img.shields.io/badge/UpWork-13544E?style=for-the-badge&logo=Upwork&logoColor=white)](https://www.upwork.com/freelancers/~014942e9b056abdf86?mp_source=share) [![Get help from me on Codementor](https://img.shields.io/badge/CodeMentor-Get_Help-1abc9c?style=for-the-badge&logo=CodeMentor&logoColor=white)](https://www.codementor.io/peterboling?utm_source=github&utm_medium=button&utm_term=peterboling&utm_campaign=github) |
341
+ | Source | [![Source on GitLab.com](https://img.shields.io/badge/GitLab-FBA326?style=for-the-badge&logo=Gitlab&logoColor=orange)](https://gitlab.com/kettle-rb/ast-merge/) [![Source on CodeBerg.org](https://img.shields.io/badge/CodeBerg-4893CC?style=for-the-badge&logo=CodeBerg&logoColor=blue)](https://codeberg.org/kettle-rb/ast-merge) [![Source on Github.com](https://img.shields.io/badge/GitHub-238636?style=for-the-badge&logo=Github&logoColor=green)](https://github.com/kettle-rb/ast-merge) [![The best SHA: dQw4w9WgXcQ\!](https://img.shields.io/badge/KLOC-3.271-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue)](https://www.youtube.com/watch?v=dQw4w9WgXcQ) |
342
+ | Documentation | [![Current release on RubyDoc.info](https://img.shields.io/badge/RubyDoc-Current_Release-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white)](http://rubydoc.info/gems/ast-merge) [![YARD on Galtzo.com](https://img.shields.io/badge/YARD_on_Galtzo.com-HEAD-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white)](https://ast-merge.galtzo.com) [![Maintainer Blog](https://img.shields.io/badge/blog-railsbling-0093D0.svg?style=for-the-badge&logo=rubyonrails&logoColor=orange)](http://www.railsbling.com/tags/ast-merge) [![GitLab Wiki](https://img.shields.io/badge/wiki-examples-943CD2.svg?style=for-the-badge&logo=gitlab&logoColor=white)](https://gitlab.com/kettle-rb/ast-merge/-/wikis/home) [![GitHub Wiki](https://img.shields.io/badge/wiki-examples-943CD2.svg?style=for-the-badge&logo=github&logoColor=white)](https://github.com/kettle-rb/ast-merge/wiki) |
343
+ | Compliance | [![License: MIT](https://img.shields.io/badge/License-MIT-259D6C.svg)](https://opensource.org/licenses/MIT) [![Compatible with Apache Software Projects: Verified by SkyWalking Eyes](https://img.shields.io/badge/Apache_Compatible:_Category_A-%E2%9C%93-259D6C.svg?style=flat&logo=Apache)](https://dev.to/galtzo/how-to-check-license-compatibility-41h0) [![📄ilo-declaration-img](https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat)](https://www.ilo.org/declaration/lang--en/index.htm) [![Security Policy](https://img.shields.io/badge/security-policy-259D6C.svg?style=flat)](SECURITY.md) [![Contributor Covenant 2.1](https://img.shields.io/badge/Contributor_Covenant-2.1-259D6C.svg)](CODE_OF_CONDUCT.md) [![SemVer 2.0.0](https://img.shields.io/badge/semver-2.0.0-259D6C.svg?style=flat)](https://semver.org/spec/v2.0.0.html) |
344
+ | Style | [![Enforced Code Style Linter](https://img.shields.io/badge/code_style_&_linting-rubocop--lts-34495e.svg?plastic&logo=ruby&logoColor=white)](https://github.com/rubocop-lts/rubocop-lts) [![Keep-A-Changelog 1.0.0](https://img.shields.io/badge/keep--a--changelog-1.0.0-34495e.svg?style=flat)](https://keepachangelog.com/en/1.0.0/) [![Gitmoji Commits](https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square)](https://gitmoji.dev) [![Compatibility appraised by: appraisal2](https://img.shields.io/badge/appraised_by-appraisal2-34495e.svg?plastic&logo=ruby&logoColor=white)](https://github.com/appraisal-rb/appraisal2) |
345
+ | Maintainer 🎖️ | [![Follow Me on LinkedIn](https://img.shields.io/badge/PeterBoling-LinkedIn-0B66C2?style=flat&logo=newjapanprowrestling)](http://www.linkedin.com/in/peterboling) [![Follow Me on Ruby.Social](https://img.shields.io/mastodon/follow/109447111526622197?domain=https://ruby.social&style=flat&logo=mastodon&label=Ruby%20@galtzo)](https://ruby.social/@galtzo) [![Follow Me on Bluesky](https://img.shields.io/badge/@galtzo.com-0285FF?style=flat&logo=bluesky&logoColor=white)](https://bsky.app/profile/galtzo.com) [![Contact Maintainer](https://img.shields.io/badge/Contact-Maintainer-0093D0.svg?style=flat&logo=rubyonrails&logoColor=red)](http://www.railsbling.com/contact) [![My technical writing](https://img.shields.io/badge/dev.to-0A0A0A?style=flat&logo=devdotto&logoColor=white)](https://dev.to/galtzo) |
346
+ | `...` 💖 | [![Find Me on WellFound:](https://img.shields.io/badge/peter--boling-orange?style=flat&logo=wellfound)](https://wellfound.com/u/peter-boling) [![Find Me on CrunchBase](https://img.shields.io/badge/peter--boling-purple?style=flat&logo=crunchbase)](https://www.crunchbase.com/person/peter-boling) [![My LinkTree](https://img.shields.io/badge/galtzo-purple?style=flat&logo=linktree)](https://linktr.ee/galtzo) [![More About Me](https://img.shields.io/badge/about.me-0A0A0A?style=flat&logo=aboutme&logoColor=white)](https://about.me/peter.boling) [🧊](https://codeberg.org/pboling) [🐙](https://github.org/pboling) [🛖](https://sr.ht/~galtzo/) [🧪](https://gitlab.com/pboling) |
321
347
 
322
348
  ### Compatibility
323
349
 
324
350
  Compatible with MRI Ruby 3.2.0+, and concordant releases of JRuby, and TruffleRuby.
325
351
 
326
- | 🚚 _Amazing_ test matrix was brought to you by | 🔎 appraisal2 🔎 and the color 💚 green 💚 |
327
- |------------------------------------------------|--------------------------------------------------------|
328
- | 👟 Check it out! | ✨ [github.com/appraisal-rb/appraisal2][💎appraisal2] ✨ |
352
+ | 🚚 *Amazing* test matrix was brought to you by | 🔎 appraisal2 🔎 and the color 💚 green 💚 |
353
+ | --- | --- |
354
+ | 👟 Check it out\! | ✨ [github.com/appraisal-rb/appraisal2](https://github.com/appraisal-rb/appraisal2) ✨ |
329
355
 
330
356
  ### Federated DVCS
331
357
 
332
358
  <details markdown="1">
333
359
  <summary>Find this repo on federated forges (Coming soon!)</summary>
334
360
 
335
- | Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
336
- |-------------------------------------------------|-----------------------------------------------------------------------|---------------------------|--------------------------|---------------------------|--------------------------|------------------------------|
337
- | 🧪 [kettle-rb/ast-merge on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix | ➖ |
338
- | 🧊 [kettle-rb/ast-merge on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
339
- | 🐙 [kettle-rb/ast-merge on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix | [💚][gh-discussions] |
340
- | 🎮️ [Discord Server][✉️discord-invite] | [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] | [Let's][✉️discord-invite] | [talk][✉️discord-invite] | [about][✉️discord-invite] | [this][✉️discord-invite] | [library!][✉️discord-invite] |
361
+ | Federated [DVCS](https://railsbling.com/posts/dvcs/put_the_d_in_dvcs/) Repository | Status | Issues | PRs | Wiki | CI | Discussions |
362
+ | --- | --- | --- | --- | --- | --- | --- |
363
+ | 🧪 [kettle-rb/ast-merge on GitLab](https://gitlab.com/kettle-rb/ast-merge/) | The Truth | [💚](https://gitlab.com/kettle-rb/ast-merge/-/issues) | [💚](https://gitlab.com/kettle-rb/ast-merge/-/merge_requests) | [💚](https://gitlab.com/kettle-rb/ast-merge/-/wikis/home) | 🐭 Tiny Matrix | ➖ |
364
+ | 🧊 [kettle-rb/ast-merge on CodeBerg](https://codeberg.org/kettle-rb/ast-merge) | An Ethical Mirror ([Donate](https://donate.codeberg.org/)) | [💚](https://codeberg.org/kettle-rb/ast-merge/issues) | [💚](https://codeberg.org/kettle-rb/ast-merge/pulls) | ➖ | ⭕️ No Matrix | ➖ |
365
+ | 🐙 [kettle-rb/ast-merge on GitHub](https://github.com/kettle-rb/ast-merge) | Another Mirror | [💚](https://github.com/kettle-rb/ast-merge/issues) | [💚](https://github.com/kettle-rb/ast-merge/pulls) | [💚](https://github.com/kettle-rb/ast-merge/wiki) | 💯 Full Matrix | [💚](https://github.com/kettle-rb/ast-merge/discussions) |
366
+ | 🎮️ [Discord Server](https://discord.gg/3qme4XHNKN) | [![Live Chat on Discord](https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord)](https://discord.gg/3qme4XHNKN) | [Let's](https://discord.gg/3qme4XHNKN) | [talk](https://discord.gg/3qme4XHNKN) | [about](https://discord.gg/3qme4XHNKN) | [this](https://discord.gg/3qme4XHNKN) | [library\!](https://discord.gg/3qme4XHNKN) |
341
367
 
342
368
  </details>
343
369
 
@@ -352,31 +378,29 @@ Available as part of the Tidelift Subscription.
352
378
 
353
379
  The maintainers of this and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use.
354
380
 
355
- [![Get help from me on Tidelift][🏙️entsup-tidelift-img]][🏙️entsup-tidelift]
356
-
357
- - 💡Subscribe for support guarantees covering _all_ your FLOSS dependencies
358
- - 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar]
359
- - 💡Tidelift pays maintainers to maintain the software you depend on!<br/>📊`@`Pointy Haired Boss: An [enterprise support][🏙️entsup-tidelift] subscription is "[never gonna let you down][🧮kloc]", and *supports* open source maintainers
381
+ [![Get help from me on Tidelift](https://img.shields.io/badge/Tidelift_and_Sonar-Enterprise_Support-FD3456?style=for-the-badge&logo=sonar&logoColor=white)](https://tidelift.com/subscription/pkg/rubygems-ast-merge?utm_source=rubygems-ast-merge&utm_medium=referral&utm_campaign=readme)
360
382
 
383
+ - 💡Subscribe for support guarantees covering *all* your FLOSS dependencies
384
+ - 💡Tidelift is part of [Sonar](https://blog.tidelift.com/tidelift-joins-sonar)
385
+ - 💡Tidelift pays maintainers to maintain the software you depend on\!<br/>📊`@`Pointy Haired Boss: An [enterprise support](https://tidelift.com/subscription/pkg/rubygems-ast-merge?utm_source=rubygems-ast-merge&utm_medium=referral&utm_campaign=readme) subscription is "[never gonna let you down](https://www.youtube.com/watch?v=dQw4w9WgXcQ)", and *supports* open source maintainers
361
386
  Alternatively:
362
387
 
363
- - [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]
364
- - [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork]
365
- - [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor]
366
-
388
+ - [![Live Chat on Discord](https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord)](https://discord.gg/3qme4XHNKN)
389
+ - [![Get help from me on Upwork](https://img.shields.io/badge/UpWork-13544E?style=for-the-badge&logo=Upwork&logoColor=white)](https://www.upwork.com/freelancers/~014942e9b056abdf86?mp_source=share)
390
+ - [![Get help from me on Codementor](https://img.shields.io/badge/CodeMentor-Get_Help-1abc9c?style=for-the-badge&logo=CodeMentor&logoColor=white)](https://www.codementor.io/peterboling?utm_source=github&utm_medium=button&utm_term=peterboling&utm_campaign=github)
367
391
  </details>
368
392
 
369
393
  ## ✨ Installation
370
394
 
371
395
  Install the gem and add to the application's Gemfile by executing:
372
396
 
373
- ```console
397
+ ``` console
374
398
  bundle add ast-merge
375
399
  ```
376
400
 
377
401
  If bundler is not being used to manage dependencies, install the gem by executing:
378
402
 
379
- ```console
403
+ ``` console
380
404
  gem install ast-merge
381
405
  ```
382
406
 
@@ -385,19 +409,19 @@ gem install ast-merge
385
409
  <details markdown="1">
386
410
  <summary>For Medium or High Security Installations</summary>
387
411
 
388
- This gem is cryptographically signed, and has verifiable [SHA-256 and SHA-512][💎SHA_checksums] checksums by
389
- [stone_checksums][💎stone_checksums]. Be sure the gem you install hasn’t been tampered with
412
+ This gem is cryptographically signed, and has verifiable [SHA-256 and SHA-512](https://gitlab.com/kettle-rb/ast-merge/-/tree/main/checksums) checksums by
413
+ [stone\_checksums](https://github.com/galtzo-floss/stone_checksums). Be sure the gem you install hasn’t been tampered with
390
414
  by following the instructions below.
391
415
 
392
416
  Add my public key (if you haven’t already, expires 2045-04-29) as a trusted certificate:
393
417
 
394
- ```console
418
+ ``` console
395
419
  gem cert --add <(curl -Ls https://raw.github.com/galtzo-floss/certs/main/pboling.pem)
396
420
  ```
397
421
 
398
422
  You only need to do that once. Then proceed to install with:
399
423
 
400
- ```console
424
+ ``` console
401
425
  gem install ast-merge -P HighSecurity
402
426
  ```
403
427
 
@@ -405,7 +429,7 @@ The `HighSecurity` trust profile will verify signed gems, and not allow the inst
405
429
 
406
430
  If you want to up your security game full-time:
407
431
 
408
- ```console
432
+ ``` console
409
433
  bundle config set --global trust-policy MediumSecurity
410
434
  ```
411
435
 
@@ -424,7 +448,7 @@ Each implementation (like `prism-merge`, `psych-merge`, etc.) has its own SmartM
424
448
 
425
449
  All SmartMerger implementations share these configuration options:
426
450
 
427
- ```ruby
451
+ ``` ruby
428
452
  merger = SomeFormat::Merge::SmartMerger.new(
429
453
  template,
430
454
  destination,
@@ -441,23 +465,21 @@ merger = SomeFormat::Merge::SmartMerger.new(
441
465
 
442
466
  Control which source wins when both files have the same structural element:
443
467
 
444
- - **`:template`** - Template values replace destination values
445
- - **`:destination`** (default) - Destination values are preserved
446
- - **Hash** - Per-node-type preference (see Advanced Configuration)
447
-
468
+ - **`:template`** - Template values replace destination values
469
+ - **`:destination`** (default) - Destination values are preserved
470
+ - **Hash** - Per-node-type preference (see Advanced Configuration)
448
471
  ### Template-Only Nodes
449
472
 
450
473
  Control whether to add nodes that only exist in the template:
451
474
 
452
- - **`true`** - Add all template-only nodes
453
- - **`false`** (default) - Skip template-only nodes
454
- - **Callable** - Filter which template-only nodes to add
455
-
475
+ - **`true`** - Add all template-only nodes
476
+ - **`false`** (default) - Skip template-only nodes
477
+ - **Callable** - Filter which template-only nodes to add
456
478
  #### Callable Filter
457
479
 
458
480
  When you need fine-grained control over which template-only nodes are added, pass a callable (Proc/Lambda) that receives `(node, entry)` and returns truthy to add or falsey to skip:
459
481
 
460
- ```ruby
482
+ ``` ruby
461
483
  # Only add nodes with gem_family signatures
462
484
  merger = SomeFormat::Merge::SmartMerger.new(
463
485
  template,
@@ -480,16 +502,15 @@ merger = Markly::Merge::SmartMerger.new(
480
502
  ```
481
503
 
482
504
  The `entry` hash contains:
483
- - `:template_node` - The node being considered for addition
484
- - `:signature` - The node's signature (Array or other value)
485
- - `:template_index` - Index in the template statements
486
- - `:dest_index` - Always `nil` for template-only nodes
487
-
505
+ - `:template_node` - The node being considered for addition
506
+ - `:signature` - The node's signature (Array or other value)
507
+ - `:template_index` - Index in the template statements
508
+ - `:dest_index` - Always `nil` for template-only nodes
488
509
  ## 🔧 Basic Usage
489
510
 
490
511
  ### Using Shared Examples in Tests
491
512
 
492
- ```ruby
513
+ ``` ruby
493
514
  # spec/spec_helper.rb
494
515
  require "ast/merge/rspec/shared_examples"
495
516
 
@@ -509,12 +530,11 @@ end
509
530
 
510
531
  ### Available Shared Examples
511
532
 
512
- - `"Ast::Merge::FreezeNode"` - Tests for FreezeNode implementations
513
- - `"Ast::Merge::MergeResult"` - Tests for MergeResult implementations
514
- - `"Ast::Merge::DebugLogger"` - Tests for DebugLogger implementations
515
- - `"Ast::Merge::FileAnalysisBase"` - Tests for FileAnalysis implementations
516
- - `"Ast::Merge::MergerConfig"` - Tests for SmartMerger implementations
517
-
533
+ - `"Ast::Merge::FreezeNode"` - Tests for FreezeNode implementations
534
+ - `"Ast::Merge::MergeResult"` - Tests for MergeResult implementations
535
+ - `"Ast::Merge::DebugLogger"` - Tests for DebugLogger implementations
536
+ - `"Ast::Merge::FileAnalysisBase"` - Tests for FileAnalysis implementations
537
+ - `"Ast::Merge::MergerConfig"` - Tests for SmartMerger implementations
518
538
  ## 🎛️ Advanced Configuration
519
539
 
520
540
  ### Freeze Blocks
@@ -524,11 +544,12 @@ to preserve content exactly as-is, preventing any changes from the template.
524
544
  This is useful for hand-edited customizations you never want overwritten.
525
545
 
526
546
  A freeze block consists of:
527
- - A **start marker** comment (e.g., `# mytoken:freeze`)
528
- - The protected content
529
- - An **end marker** comment (e.g., `# mytoken:unfreeze`)
547
+ - A **start marker** comment (e.g., `# mytoken:freeze`)
548
+ - The protected content
549
+ - An **end marker** comment (e.g., `# mytoken:unfreeze`)
530
550
 
531
- ```ruby
551
+ <!-- end list -->
552
+ ``` ruby
532
553
  # In a Ruby file with prism-merge:
533
554
  class MyApp
534
555
  # prism-merge:freeze
@@ -550,16 +571,16 @@ Different file formats use different comment syntaxes. The merge tools detect fr
550
571
  using the appropriate pattern for each format:
551
572
 
552
573
  | Pattern Type | Start Marker | End Marker | Languages |
553
- |--------------|--------------|------------|-----------|
574
+ | --- | --- | --- | --- |
554
575
  | `:hash_comment` | `# token:freeze` | `# token:unfreeze` | Ruby, Python, YAML, Bash, Shell |
555
576
  | `:html_comment` | `<!-- token:freeze -->` | `<!-- token:unfreeze -->` | HTML, XML, Markdown |
556
- | `:c_style_line` | `// token:freeze` | `// token:unfreeze` | C (C99+), C++, JavaScript, TypeScript, Java, C#, Go, Rust, Swift, Kotlin, PHP, JSONC |
557
- | `:c_style_block` | `/* token:freeze */` | `/* token:unfreeze */` | C, C++, JavaScript, TypeScript, Java, C#, Go, Rust, Swift, Kotlin, PHP, CSS |
577
+ | `:c_style_line` | `// token:freeze` | `// token:unfreeze` | C (C99+), C++, JavaScript, TypeScript, Java, C\#, Go, Rust, Swift, Kotlin, PHP, JSONC |
578
+ | `:c_style_block` | `/* token:freeze */` | `/* token:unfreeze */` | C, C++, JavaScript, TypeScript, Java, C\#, Go, Rust, Swift, Kotlin, PHP, CSS |
558
579
 
559
- | 📍 NOTE |
560
- |-----------------------------------------------------------------------------------------------------|
561
- | CSS only supports block comments (`/* */`), not line comments. |
562
- | JSON does not support comments; use JSONC for JSON with comments. |
580
+ | 📍 NOTE |
581
+ | --- |
582
+ | CSS only supports block comments (`/* */`), not line comments. |
583
+ | JSON does not support comments; use JSONC for JSON with comments. |
563
584
 
564
585
  ### Per-Node-Type Preference with `node_typing`
565
586
 
@@ -569,15 +590,18 @@ preferences for different types of nodes (e.g., prefer template for linter confi
569
590
 
570
591
  #### How It Works
571
592
 
572
- 1. **Define a `node_typing`**: A Hash mapping node type symbols to callables that receive a node and return either:
573
- - The original node (no special handling)
574
- - A wrapped node with a `merge_type` attribute (via `Ast::Merge::NodeTyping::Wrapper`)
593
+ 1. **Define a `node_typing`**: A Hash mapping node type symbols to callables that receive a node and return either:
594
+
595
+ - The original node (no special handling)
596
+ - A wrapped node with a `merge_type` attribute (via `Ast::Merge::NodeTyping::Wrapper`)
575
597
 
576
- 2. **Use a Hash-based preference**: Instead of a simple `:destination` or `:template` Symbol, pass a Hash with:
577
- - `:default` key for the fallback preference
578
- - Custom keys matching the `merge_type` values from your `node_typing`
598
+ 2. **Use a Hash-based preference**: Instead of a simple `:destination` or `:template` Symbol, pass a Hash with:
579
599
 
580
- ```ruby
600
+ - `:default` key for the fallback preference
601
+ - Custom keys matching the `merge_type` values from your `node_typing`
602
+
603
+ <!-- end list -->
604
+ ``` ruby
581
605
  # Example: Prefer template for lint gem configs, destination for everything else
582
606
  node_typing = {
583
607
  call_node: ->(node) {
@@ -605,7 +629,7 @@ merger = Prism::Merge::SmartMerger.new(
605
629
  The `Ast::Merge::NodeTyping::Wrapper` class wraps an AST node and adds a `merge_type` attribute.
606
630
  It delegates all method calls to the wrapped node, so it can be used transparently in place of the original node.
607
631
 
608
- ```ruby
632
+ ``` ruby
609
633
  # Wrap a node with a custom merge_type
610
634
  wrapped = Ast::Merge::NodeTyping::Wrapper.new(original_node, :special_config)
611
635
  wrapped.merge_type # => :special_config
@@ -615,7 +639,7 @@ wrapped.location # => delegates to original_node.location
615
639
 
616
640
  #### NodeTyping Utility Methods
617
641
 
618
- ```ruby
642
+ ``` ruby
619
643
  # Process a node through the node_typing configuration
620
644
  processed = Ast::Merge::NodeTyping.process(node, node_typing_config)
621
645
 
@@ -629,12 +653,12 @@ Ast::Merge::NodeTyping.merge_type_for(node) # => Symbol or nil
629
653
  Ast::Merge::NodeTyping.unwrap(wrapped_node) # => original_node
630
654
  ```
631
655
 
632
- ### Hash-Based Preference (without node_typing)
656
+ ### Hash-Based Preference (without node\_typing)
633
657
 
634
658
  Even without `node_typing`, you can use a Hash-based preference to set a default
635
659
  and document your intention for future per-type customization:
636
660
 
637
- ```ruby
661
+ ``` ruby
638
662
  # Simple Hash preference (functionally equivalent to preference: :destination)
639
663
  merger = MyMerger.new(
640
664
  template_content,
@@ -647,7 +671,7 @@ merger = MyMerger.new(
647
671
 
648
672
  The `MergerConfig` class provides factory methods that support all options:
649
673
 
650
- ```ruby
674
+ ``` ruby
651
675
  # Create config preferring destination
652
676
  config = Ast::Merge::MergerConfig.destination_wins(
653
677
  freeze_token: "my-freeze",
@@ -668,42 +692,42 @@ config = Ast::Merge::MergerConfig.template_wins(
668
692
  While kettle-rb tools are free software and will always be, the project would benefit immensely from some funding.
669
693
  Raising a monthly budget of... "dollars" would make the project more sustainable.
670
694
 
671
- We welcome both individual and corporate sponsors! We also offer a
695
+ We welcome both individual and corporate sponsors\! We also offer a
672
696
  wide array of funding channels to account for your preferences
673
- (although currently [Open Collective][🖇osc] is our preferred funding platform).
697
+ (although currently [Open Collective](https://opencollective.com/kettle-rb) is our preferred funding platform).
674
698
 
675
699
  **If you're working in a company that's making significant use of kettle-rb tools we'd
676
700
  appreciate it if you suggest to your company to become a kettle-rb sponsor.**
677
701
 
678
702
  You can support the development of kettle-rb tools via
679
- [GitHub Sponsors][🖇sponsor],
680
- [Liberapay][⛳liberapay],
681
- [PayPal][🖇paypal],
682
- [Open Collective][🖇osc]
683
- and [Tidelift][🏙️entsup-tidelift].
684
-
685
- | 📍 NOTE |
686
- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
703
+ [GitHub Sponsors](https://github.com/sponsors/pboling),
704
+ [Liberapay](https://liberapay.com/pboling/donate),
705
+ [PayPal](https://www.paypal.com/paypalme/peterboling),
706
+ [Open Collective](https://opencollective.com/kettle-rb)
707
+ and [Tidelift](https://tidelift.com/subscription/pkg/rubygems-ast-merge?utm_source=rubygems-ast-merge&utm_medium=referral&utm_campaign=readme).
708
+
709
+ | 📍 NOTE |
710
+ | --- |
687
711
  | If doing a sponsorship in the form of donation is problematic for your company <br/> from an accounting standpoint, we'd recommend the use of Tidelift, <br/> where you can get a support-like subscription instead. |
688
712
 
689
713
  ### Open Collective for Individuals
690
714
 
691
- Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/kettle-rb#backer)]
715
+ Support us with a monthly donation and help us continue our activities. \[[Become a backer](https://opencollective.com/kettle-rb#backer)\]
692
716
 
693
- NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
717
+ NOTE: [kettle-readme-backers](https://github.com/kettle-rb/ast-merge/blob/main/exe/kettle-readme-backers) updates this list every day, automatically.
694
718
 
695
719
  <!-- OPENCOLLECTIVE-INDIVIDUALS:START -->
696
- No backers yet. Be the first!
720
+ No backers yet. Be the first\!
697
721
  <!-- OPENCOLLECTIVE-INDIVIDUALS:END -->
698
722
 
699
723
  ### Open Collective for Organizations
700
724
 
701
- Become a sponsor and get your logo on our README on GitHub with a link to your site. [[Become a sponsor](https://opencollective.com/kettle-rb#sponsor)]
725
+ Become a sponsor and get your logo on our README on GitHub with a link to your site. \[[Become a sponsor](https://opencollective.com/kettle-rb#sponsor)\]
702
726
 
703
- NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
727
+ NOTE: [kettle-readme-backers](https://github.com/kettle-rb/ast-merge/blob/main/exe/kettle-readme-backers) updates this list every day, automatically.
704
728
 
705
729
  <!-- OPENCOLLECTIVE-ORGANIZATIONS:START -->
706
- No sponsors yet. Be the first!
730
+ No sponsors yet. Be the first\!
707
731
  <!-- OPENCOLLECTIVE-ORGANIZATIONS:END -->
708
732
 
709
733
  [kettle-readme-backers]: https://github.com/kettle-rb/ast-merge/blob/main/exe/kettle-readme-backers
@@ -714,50 +738,50 @@ I’m driven by a passion to foster a thriving open-source community – a space
714
738
 
715
739
  If you work at a company that uses my work, please encourage them to support me as a corporate sponsor. My work on gems you use might show up in `bundle fund`.
716
740
 
717
- I’m developing a new library, [floss_funding][🖇floss-funding-gem], designed to empower open-source developers like myself to get paid for the work we do, in a sustainable way. Please give it a look.
741
+ I’m developing a new library, [floss\_funding](https://github.com/galtzo-floss/floss_funding), designed to empower open-source developers like myself to get paid for the work we do, in a sustainable way. Please give it a look.
718
742
 
719
- **[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
743
+ **[Floss-Funding.dev](https://floss-funding.dev): 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
720
744
 
721
- [![OpenCollective Backers][🖇osc-backers-i]][🖇osc-backers] [![OpenCollective Sponsors][🖇osc-sponsors-i]][🖇osc-sponsors] [![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 on Polar][🖇polar-img]][🖇polar] [![Donate to my FLOSS efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS efforts using Patreon][🖇patreon-img]][🖇patreon]
745
+ [![OpenCollective Backers](https://opencollective.com/kettle-rb/backers/badge.svg?style=flat)](https://opencollective.com/kettle-rb#backer) [![OpenCollective Sponsors](https://opencollective.com/kettle-rb/sponsors/badge.svg?style=flat)](https://opencollective.com/kettle-rb#sponsor) [![Sponsor Me on Github](https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github)](https://github.com/sponsors/pboling) [![Liberapay Goal Progress](https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611&style=flat)](https://liberapay.com/pboling/donate) [![Donate on PayPal](https://img.shields.io/badge/donate-paypal-a51611.svg?style=flat&logo=paypal)](https://www.paypal.com/paypalme/peterboling) [![Buy me a coffee](https://img.shields.io/badge/buy_me_a_coffee-%E2%9C%93-a51611.svg?style=flat)](https://www.buymeacoffee.com/pboling) [![Donate on Polar](https://img.shields.io/badge/polar-donate-a51611.svg?style=flat)](https://polar.sh/pboling) [![Donate to my FLOSS efforts at ko-fi.com](https://img.shields.io/badge/ko--fi-%E2%9C%93-a51611.svg?style=flat)](https://ko-fi.com/O5O86SNP4) [![Donate to my FLOSS efforts using Patreon](https://img.shields.io/badge/patreon-donate-a51611.svg?style=flat)](https://patreon.com/galtzo)
722
746
 
723
747
  ## 🔐 Security
724
748
 
725
- See [SECURITY.md][🔐security].
749
+ See [SECURITY.md](SECURITY.md).
726
750
 
727
751
  ## 🤝 Contributing
728
752
 
729
753
  If you need some ideas of where to help, you could work on adding more code coverage,
730
- or if it is already 💯 (see [below](#code-coverage)) check [reek](REEK), [issues][🤝gh-issues], or [PRs][🤝gh-pulls],
754
+ or if it is already 💯 (see [below](#code-coverage)) check [reek](REEK), [issues](https://github.com/kettle-rb/ast-merge/issues), or [PRs](https://github.com/kettle-rb/ast-merge/pulls),
731
755
  or use the gem and think about how it could be better.
732
756
 
733
- We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it.
757
+ We [![Keep A Changelog](https://img.shields.io/badge/keep--a--changelog-1.0.0-34495e.svg?style=flat)](https://keepachangelog.com/en/1.0.0/) so if you make changes, remember to update it.
734
758
 
735
- See [CONTRIBUTING.md][🤝contributing] for more detailed instructions.
759
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for more detailed instructions.
736
760
 
737
761
  ### 🚀 Release Instructions
738
762
 
739
- See [CONTRIBUTING.md][🤝contributing].
763
+ See [CONTRIBUTING.md](CONTRIBUTING.md).
740
764
 
741
765
  ### Code Coverage
742
766
 
743
- [![Coverage Graph][🏀codecov-g]][🏀codecov]
767
+ [![Coverage Graph](https://codecov.io/gh/kettle-rb/ast-merge/graphs/tree.svg)](https://codecov.io/gh/kettle-rb/ast-merge)
744
768
 
745
- [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls]
769
+ [![Coveralls Test Coverage](https://coveralls.io/repos/github/kettle-rb/ast-merge/badge.svg?branch=main)](https://coveralls.io/github/kettle-rb/ast-merge?branch=main)
746
770
 
747
- [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov]
771
+ [![QLTY Test Coverage](https://qlty.sh/gh/kettle-rb/projects/ast-merge/coverage.svg)](https://qlty.sh/gh/kettle-rb/projects/ast-merge/metrics/code?sort=coverageRating)
748
772
 
749
773
  ### 🪇 Code of Conduct
750
774
 
751
775
  Everyone interacting with this project's codebases, issue trackers,
752
- chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct].
776
+ chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1](https://img.shields.io/badge/Contributor_Covenant-2.1-259D6C.svg)](CODE_OF_CONDUCT.md).
753
777
 
754
778
  ## 🌈 Contributors
755
779
 
756
- [![Contributors][🖐contributors-img]][🖐contributors]
780
+ [![Contributors](https://contrib.rocks/image?repo=kettle-rb/ast-merge)](https://github.com/kettle-rb/ast-merge/graphs/contributors)
757
781
 
758
- Made with [contributors-img][🖐contrib-rocks].
782
+ Made with [contributors-img](https://contrib.rocks).
759
783
 
760
- Also see GitLab Contributors: [https://gitlab.com/kettle-rb/ast-merge/-/graphs/main][🚎contributors-gl]
784
+ Also see GitLab Contributors: <https://gitlab.com/kettle-rb/ast-merge/-/graphs/main>
761
785
 
762
786
  <details>
763
787
  <summary>⭐️ Star History</summary>
@@ -774,24 +798,24 @@ Also see GitLab Contributors: [https://gitlab.com/kettle-rb/ast-merge/-/graphs/m
774
798
 
775
799
  ## 📌 Versioning
776
800
 
777
- This Library adheres to [![Semantic Versioning 2.0.0][📌semver-img]][📌semver].
801
+ This Library adheres to [![Semantic Versioning 2.0.0](https://img.shields.io/badge/semver-2.0.0-259D6C.svg?style=flat)](https://semver.org/spec/v2.0.0.html).
778
802
  Violations of this scheme should be reported as bugs.
779
803
  Specifically, if a minor or patch version is released that breaks backward compatibility,
780
804
  a new version should be immediately released that restores compatibility.
781
805
  Breaking changes to the public API will only be introduced with new major versions.
782
806
 
783
807
  > dropping support for a platform is both obviously and objectively a breaking change <br/>
784
- >—Jordan Harband ([@ljharb](https://github.com/ljharb), maintainer of SemVer) [in SemVer issue 716][📌semver-breaking]
808
+ > —Jordan Harband ([@ljharb](https://github.com/ljharb), maintainer of SemVer) [in SemVer issue 716](https://github.com/semver/semver/issues/716#issuecomment-869336139)
785
809
 
786
- I understand that policy doesn't work universally ("exceptions to every rule!"),
810
+ I understand that policy doesn't work universally ("exceptions to every rule\!"),
787
811
  but it is the policy here.
788
812
  As such, in many cases it is good to specify a dependency on this library using
789
- the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
813
+ the [Pessimistic Version Constraint](http://guides.rubygems.org/patterns/#pessimistic-version-constraint) with two digits of precision.
790
814
 
791
815
  For example:
792
816
 
793
- ```ruby
794
- spec.add_dependency("ast-merge", "~> 1.0")
817
+ ``` ruby
818
+ spec.add_dependency("ast-merge", "~> 2.0", ">= 2.0.1") # ruby >= 3.2.0
795
819
  ```
796
820
 
797
821
  <details markdown="1">
@@ -803,17 +827,16 @@ is a *breaking change* to an API, and for that reason the bike shedding is endle
803
827
  To get a better understanding of how SemVer is intended to work over a project's lifetime,
804
828
  read this article from the creator of SemVer:
805
829
 
806
- - ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]
807
-
830
+ - ["Major Version Numbers are Not Sacred"](https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html)
808
831
  </details>
809
832
 
810
- See [CHANGELOG.md][📌changelog] for a list of releases.
833
+ See [CHANGELOG.md](CHANGELOG.md) for a list of releases.
811
834
 
812
835
  ## 📄 License
813
836
 
814
837
  The gem is available as open source under the terms of
815
- the [MIT License][📄license] [![License: MIT][📄license-img]][📄license-ref].
816
- See [LICENSE.txt][📄license] for the official [Copyright Notice][📄copyright-notice-explainer].
838
+ the [MIT License](LICENSE.txt) [![License: MIT](https://img.shields.io/badge/License-MIT-259D6C.svg)](https://opensource.org/licenses/MIT).
839
+ See [LICENSE.txt](LICENSE.txt) for the official [Copyright Notice](https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year).
817
840
 
818
841
  ### © Copyright
819
842
 
@@ -840,11 +863,11 @@ Please consider sponsoring me or the project.
840
863
 
841
864
  To join the community or get help 👇️ Join the Discord.
842
865
 
843
- [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]
866
+ [![Live Chat on Discord](https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord)](https://discord.gg/3qme4XHNKN)
844
867
 
845
- To say "thanks!" ☝️ Join the Discord or 👇️ send money.
868
+ To say "thanks\!" ☝️ Join the Discord or 👇️ send money.
846
869
 
847
- [![Sponsor kettle-rb/ast-merge on Open Source Collective][🖇osc-all-bottom-img]][🖇osc] 💌 [![Sponsor me on GitHub Sponsors][🖇sponsor-bottom-img]][🖇sponsor] 💌 [![Sponsor me on Liberapay][⛳liberapay-bottom-img]][⛳liberapay] 💌 [![Donate on PayPal][🖇paypal-bottom-img]][🖇paypal]
870
+ [![Sponsor kettle-rb/ast-merge on Open Source Collective](https://img.shields.io/opencollective/all/kettle-rb?style=for-the-badge)](https://opencollective.com/kettle-rb) 💌 [![Sponsor me on GitHub Sponsors](https://img.shields.io/badge/Sponsor_Me!-pboling-blue?style=for-the-badge&logo=github)](https://github.com/sponsors/pboling) 💌 [![Sponsor me on Liberapay](https://img.shields.io/liberapay/goal/pboling.svg?style=for-the-badge&logo=liberapay&color=a51611)](https://liberapay.com/pboling/donate) 💌 [![Donate on PayPal](https://img.shields.io/badge/donate-paypal-a51611.svg?style=for-the-badge&logo=paypal&color=0A0A0A)](https://www.paypal.com/paypalme/peterboling)
848
871
 
849
872
  ### Please give the project a star ⭐ ♥.
850
873
 
@@ -1009,7 +1032,7 @@ Thanks for RTFM. ☺️
1009
1032
  [📌gitmoji]: https://gitmoji.dev
1010
1033
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
1011
1034
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
1012
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-3.271-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1035
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-3.272-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1013
1036
  [🔐security]: SECURITY.md
1014
1037
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1015
1038
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -70,16 +70,15 @@ module Ast
70
70
  #
71
71
  # @note Shared examples require +silent_stream+ and +rspec-stubbed_env+ gems.
72
72
  module DebugLogger
73
- # Benchmark is optional - gracefully degrade if not available
74
- # Use autoload to defer loading until actually needed
73
+ # Benchmark is optional - gracefully degrade if not available.
74
+ # As of Ruby 4.0, benchmark is a bundled gem (not default), so it may not be available.
75
+ # We attempt to require it at load time and set a flag for later use.
75
76
  BENCHMARK_AVAILABLE = begin
76
- autoload(:Benchmark, "benchmark")
77
+ require "benchmark"
77
78
  true
78
79
  rescue LoadError
79
- # :nocov:
80
- # Platform-specific: benchmark is part of Ruby stdlib, LoadError only on unusual Ruby builds
80
+ # benchmark gem not available (Ruby 4.0+ without explicit dependency, or unusual Ruby builds)
81
81
  false
82
- # :nocov:
83
82
  end
84
83
 
85
84
  class << self
@@ -5,7 +5,7 @@ module Ast
5
5
  # Version information for Ast::Merge
6
6
  module Version
7
7
  # Current version of the ast-merge gem
8
- VERSION = "2.0.1"
8
+ VERSION = "2.0.3"
9
9
  end
10
10
  VERSION = Version::VERSION # traditional location
11
11
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ast-merge
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -63,20 +63,20 @@ dependencies:
63
63
  requirements:
64
64
  - - "~>"
65
65
  - !ruby/object:Gem::Version
66
- version: '3.1'
66
+ version: '3.2'
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: 3.1.2
69
+ version: 3.2.0
70
70
  type: :runtime
71
71
  prerelease: false
72
72
  version_requirements: !ruby/object:Gem::Requirement
73
73
  requirements:
74
74
  - - "~>"
75
75
  - !ruby/object:Gem::Version
76
- version: '3.1'
76
+ version: '3.2'
77
77
  - - ">="
78
78
  - !ruby/object:Gem::Version
79
- version: 3.1.2
79
+ version: 3.2.0
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: kettle-dev
82
82
  requirement: !ruby/object:Gem::Requirement
@@ -352,10 +352,10 @@ licenses:
352
352
  - MIT
353
353
  metadata:
354
354
  homepage_uri: https://ast-merge.galtzo.com/
355
- source_code_uri: https://github.com/kettle-rb/ast-merge/tree/v2.0.1
356
- changelog_uri: https://github.com/kettle-rb/ast-merge/blob/v2.0.1/CHANGELOG.md
355
+ source_code_uri: https://github.com/kettle-rb/ast-merge/tree/v2.0.3
356
+ changelog_uri: https://github.com/kettle-rb/ast-merge/blob/v2.0.3/CHANGELOG.md
357
357
  bug_tracker_uri: https://github.com/kettle-rb/ast-merge/issues
358
- documentation_uri: https://www.rubydoc.info/gems/ast-merge/2.0.1
358
+ documentation_uri: https://www.rubydoc.info/gems/ast-merge/2.0.3
359
359
  funding_uri: https://github.com/sponsors/pboling
360
360
  wiki_uri: https://github.com/kettle-rb/ast-merge/wiki
361
361
  news_uri: https://www.railsbling.com/tags/ast-merge
metadata.gz.sig CHANGED
Binary file