dotenv-merge 1.0.0 → 1.0.2

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: 59de455da6b9e74b0f8ccb9801d67788fb7d2130e00b6a563d8e941d017c7d21
4
- data.tar.gz: 3abe5e613b532885ac9ba11ea430f75a6d7b613ca447bf9240718a426e17892c
3
+ metadata.gz: 9c982a0bec61937d370eb9b353e1da52cc960fb76e20e477922a9edbed7ec064
4
+ data.tar.gz: 4463c4e011c866bb24cfe3031ba2f1017372aede506f065c0c1a7aa88a5929df
5
5
  SHA512:
6
- metadata.gz: 728968cd1fd6a830b58a4c65d6c28cd59ad493d297c0b5bf39ea5cbd2b07eb3c1d8aa695c1a8b0b856f99db8c1f0a84dde6030dd1235052d772f0ab6feb744c0
7
- data.tar.gz: e04a360dea42ee200664ec3cd60ed78e5d754c327e1724c11c29d771b158bd5ff5006f4b39af8bb2ffaf4bc88b3c56f4f7a344b4846765aee1115d26379346f8
6
+ metadata.gz: 2e9f2c6b34e2dbb1c9f303f48a40762ff7c4c06c33cfe223f65cde1e96938e80c894c7f4571e0da6aff84052d8911ef3c1de4b2bd08eb93dc4963fd191b8e50c
7
+ data.tar.gz: b68ac2aa403de2eb8ca7d795bbb1a51d522cb25426c9ffea0ccea6e38819c618234c1e606f8ae7d2a9fe83361f486161b486c7e92f03184117e532a3af7f2d50
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,51 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [1.0.2] - 2026-02-01
34
+
35
+ - TAG: [v1.0.2][1.0.2t]
36
+ - COVERAGE: 97.73% -- 345/353 lines in 8 files
37
+ - BRANCH COVERAGE: 83.06% -- 103/124 branches in 8 files
38
+ - 96.83% documented
39
+
40
+ ### Added
41
+
42
+ - Utilizes `Ast::Merge::RSpec::MergeGemRegistry` when running RSpec tests
43
+
44
+ ### Changed
45
+
46
+ - Documentation cleanup
47
+ - Upgrade to [ast-merge v4.0.5](https://github.com/kettle-rb/ast-merge/releases/tag/v4.0.5)
48
+ - Upgrade to [tree_haver v5.0.3](https://github.com/kettle-rb/tree_haver/releases/tag/v5.0.3)
49
+
50
+ ## [1.0.1] - 2026-01-01
51
+
52
+ - TAG: [v1.0.1][1.0.1t]
53
+ - COVERAGE: 97.72% -- 343/351 lines in 8 files
54
+ - BRANCH COVERAGE: 83.61% -- 102/122 branches in 8 files
55
+ - 96.83% documented
56
+
57
+ ### Added
58
+
59
+ - `node_typing` parameter for per-node-type merge preferences
60
+ - Enables `preference: { default: :destination, special_type: :template }` pattern
61
+ - Works with custom merge_types assigned via node_typing lambdas
62
+ - `match_refiner` parameter for fuzzy matching support
63
+ - `regions` and `region_placeholder` parameters for nested content merging
64
+ - `EnvLine#type` method returning `"env_line"` for TreeHaver::Node protocol compatibility
65
+
66
+ ### Changed
67
+
68
+ - **SmartMerger**: Added `**options` for forward compatibility
69
+ - Accepts additional options that may be added to base class in future
70
+ - Passes all options through to `SmartMergerBase`
71
+ - **MergeResult**: Added `**options` for forward compatibility
72
+ - **BREAKING**: `SmartMerger` now inherits from `Ast::Merge::SmartMergerBase`
73
+ - Provides standardized options API consistent with all other `*-merge` gems
74
+ - All keyword arguments are now explicit (no more positional-only arguments)
75
+ - Gains automatic support for new SmartMergerBase features
76
+ - Renamed `EnvLine#type` attribute to `EnvLine#line_type` to avoid conflict with TreeHaver::Node protocol
77
+
33
78
  ## [1.0.0] - 2025-12-12
34
79
 
35
80
  - TAG: [v1.0.0][1.0.0t]
@@ -41,6 +86,10 @@ Please file a bug if you notice a violation of semantic versioning.
41
86
 
42
87
  - Initial release
43
88
 
44
- [Unreleased]: https://github.com/kettle-rb/dotenv-merge/compare/v1.0.0...HEAD
89
+ [Unreleased]: https://github.com/kettle-rb/dotenv-merge/compare/v1.0.2...HEAD
90
+ [1.0.2]: https://github.com/kettle-rb/dotenv-merge/compare/v1.0.1...v1.0.2
91
+ [1.0.2t]: https://github.com/kettle-rb/dotenv-merge/releases/tag/v1.0.2
92
+ [1.0.1]: https://github.com/kettle-rb/dotenv-merge/compare/v1.0.0...v1.0.1
93
+ [1.0.1t]: https://github.com/kettle-rb/dotenv-merge/releases/tag/v1.0.1
45
94
  [1.0.0]: https://github.com/kettle-rb/dotenv-merge/compare/a34c8f20c877a45d03b9f0b83b973614e123a92b...v1.0.0
46
95
  [1.0.0t]: https://github.com/kettle-rb/dotenv-merge/tags/v1.0.0
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2025 Peter H. Boling
3
+ Copyright (c) 2025-2026 Peter H. Boling
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -42,11 +42,11 @@
42
42
 
43
43
  # ☯️ Dotenv::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][👽versioni]][👽dl-rank] [![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]
46
46
 
47
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
48
 
49
- ---
49
+ -----
50
50
 
51
51
  `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
52
 
@@ -54,7 +54,7 @@
54
54
 
55
55
  ## 🌻 Synopsis
56
56
 
57
- Dotenv::Merge is a standalone Ruby module that intelligently merges two versions of a dotenv (`.env`) file. It's like a smart "git merge" specifically designed for environment configuration files. Built on top of [ast-merge](https://github.com/kettle-rb/ast-merge), it shares the same architecture as [prism-merge](https://github.com/kettle-rb/prism-merge) for Ruby source files.
57
+ Dotenv::Merge is a standalone Ruby module that intelligently merges two versions of a dotenv (`.env`) file. It's like a smart "git merge" specifically designed for environment configuration files. Built on top of [ast-merge][ast-merge], it shares the same architecture as [prism-merge][prism-merge] for Ruby source files.
58
58
 
59
59
  ### Key Features
60
60
 
@@ -65,16 +65,16 @@ Dotenv::Merge is a standalone Ruby module that intelligently merges two versions
65
65
  - **Full Provenance**: Tracks origin of every line
66
66
  - **Standalone**: Minimal dependencies - just `ast-merge`
67
67
  - **Customizable**:
68
- - `signature_generator` - callable custom signature generators
69
- - `preference` - setting of `:template`, `:destination`, or a Hash for per-node-type preferences
70
- - `node_splitter` - Hash mapping node types to callables for per-node-type merge customization (see [ast-merge](https://github.com/kettle-rb/ast-merge) docs)
71
- - `add_template_only_nodes` - setting to retain variables that do not exist in destination
72
- - `freeze_token` - customize freeze block markers (default: `"dotenv-merge"`)
68
+ - `signature_generator` - callable custom signature generators
69
+ - `preference` - setting of `:template`, `:destination`, or a Hash for per-node-type preferences
70
+ - `node_splitter` - Hash mapping node types to callables for per-node-type merge customization (see [ast-merge][ast-merge] docs)
71
+ - `add_template_only_nodes` - setting to retain variables that do not exist in destination
72
+ - `freeze_token` - customize freeze block markers (default: `"dotenv-merge"`)
73
73
 
74
74
  ### Supported Line Types
75
75
 
76
76
  | Line Type | Format | Matching Behavior |
77
- |-----------|--------|-------------------|
77
+ | --- | --- | --- |
78
78
  | Assignment | `KEY=value` | Variables match by key name |
79
79
  | Export | `export KEY=value` | Treated as assignment with export flag |
80
80
  | Comment | `# comment text` | Preserved in context |
@@ -97,139 +97,59 @@ result = merger.merge
97
97
  File.write("merged.env", result.to_s)
98
98
  ```
99
99
 
100
- ### Part of a gem family
101
-
102
- | Gem | File Type | Parser |
103
- |-----|-----------|--------|
104
- | [ast-merge](https://github.com/kettle-rb/ast-merge) | Text | internal |
105
- | [prism-merge](https://github.com/kettle-rb/prism-merge) | Ruby | Prism |
106
- | [psych-merge](https://github.com/kettle-rb/psych-merge) | YAML | Psych |
107
- | [json-merge](https://github.com/kettle-rb/json-merge) | JSON | tree-sitter-json |
108
- | [jsonc-merge](https://github.com/kettle-rb/jsonc-merge) | JSONC | ⚠️ [tree-sitter-jsonc](https://gitlab.com/WhyNotHugo/tree-sitter-jsonc) (PoC) |
109
- | [bash-merge](https://github.com/kettle-rb/bash-merge) | Shell | tree-sitter-bash |
110
- | [rbs-merge](https://github.com/kettle-rb/rbs-merge) | RBS Types | RBS |
111
- | **dotenv-merge** | Dotenv | internal |
112
- | [toml-merge](https://github.com/kettle-rb/toml-merge) | TOML | tree-sitter-toml |
113
- | [markdown-merge](https://github.com/kettle-rb/markdown-merge) | Markdown | _base classes_ |
114
- | [markly-merge](https://github.com/kettle-rb/markly-merge) | Markdown | Markly (cmark-gfm) |
115
- | [commonmarker-merge](https://github.com/kettle-rb/commonmarker-merge) | Markdown | Commonmarker (Comrak) |
116
-
117
- **Example implementations** for the gem templating use case:
118
-
119
- | Gem | Purpose |
120
- |-----|---------|
121
- | [kettle-dev](https://github.com/kettle-rb/kettle-dev) | Gem templating tool |
122
- | [kettle-jem](https://github.com/kettle-rb/kettle-jem) | Gem template library |
123
-
124
- ### Configuration
125
-
126
- ```ruby
127
- merger = Dotenv::Merge::SmartMerger.new(
128
- template_content,
129
- dest_content,
130
- # Which version to prefer when variables match
131
- # :destination (default) - keep destination values
132
- # :template - use template values
133
- preference: :destination,
134
-
135
- # Whether to add template-only variables to the result
136
- # false (default) - only include variables that exist in destination
137
- # true - include all template variables
138
- add_template_only_nodes: false,
139
-
140
- # Token for freeze block markers
141
- # Default: "dotenv-merge"
142
- # Looks for: # dotenv-merge:freeze / # dotenv-merge:unfreeze
143
- freeze_token: "dotenv-merge",
144
-
145
- # Custom signature generator (optional)
146
- # Receives an EnvLine, returns a signature array or nil
147
- signature_generator: ->(line) { [:env, line.key] if line.assignment? },
148
- )
149
- ```
150
-
151
- ### Basic Usage
152
-
153
- #### Simple Merge
154
-
155
- ```ruby
156
- require "dotenv/merge"
157
-
158
- # Template defines the structure
159
- template = <<~ENV
160
- # Database configuration
161
- DATABASE_URL=postgres://localhost/myapp_dev
162
- DATABASE_POOL=5
163
-
164
- # API keys
165
- API_KEY=your_api_key_here
166
- API_SECRET=your_secret_here
167
- ENV
168
-
169
- # Destination has customizations
170
- destination = <<~ENV
171
- # Database configuration
172
- DATABASE_URL=postgres://production.example.com/myapp
173
- DATABASE_POOL=25
174
-
175
- # Custom setting not in template
176
- CUSTOM_SETTING=my_value
177
- ENV
178
-
179
- merger = Dotenv::Merge::SmartMerger.new(template, destination)
180
- result = merger.merge
181
- puts result
182
- ```
183
-
184
- #### Using Freeze Blocks
185
-
186
- Freeze blocks protect sections from being overwritten during merge:
187
-
188
- ```env
189
- # Database configuration
190
- DATABASE_URL=postgres://localhost/myapp_dev
191
-
192
- # dotenv-merge:freeze Custom API credentials
193
- API_KEY=my_secret_production_key
194
- API_SECRET=super_secret_value
195
- # dotenv-merge:unfreeze
196
-
197
- # Other settings
198
- DEBUG=false
199
- ```
200
-
201
- Content between `# dotenv-merge:freeze` and `# dotenv-merge:unfreeze` markers is preserved from the destination file, regardless of what the template contains.
100
+ ### The `*-merge` Gem Family
202
101
 
203
- #### Adding Template-Only Variables
102
+ 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.
103
+
104
+ | Gem | Version / CI | Language<br>/ Format | Parser Backend(s) | Description |
105
+ |------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------:|----------------------|-------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
106
+ | [tree_haver][tree_haver] | [![Version][tree_haver-gem-i]][tree_haver-gem] <br/> [![CI][tree_haver-ci-i]][tree_haver-ci] | Multi | Supported Backends: MRI C, Rust, FFI, Java, Prism, Psych, Commonmarker, Markly, Citrus, Parslet | **Foundation**: Cross-Ruby adapter for parsing libraries (like Faraday for HTTP) |
107
+ | [ast-merge][ast-merge] | [![Version][ast-merge-gem-i]][ast-merge-gem] <br/> [![CI][ast-merge-ci-i]][ast-merge-ci] | Text | internal | **Infrastructure**: Shared base classes and merge logic for all `*-merge` gems |
108
+ | [bash-merge][bash-merge] | [![Version][bash-merge-gem-i]][bash-merge-gem] <br/> [![CI][bash-merge-ci-i]][bash-merge-ci] | Bash | [tree-sitter-bash][ts-bash] (via tree_haver) | Smart merge for Bash scripts |
109
+ | [commonmarker-merge][commonmarker-merge] | [![Version][commonmarker-merge-gem-i]][commonmarker-merge-gem] <br/> [![CI][commonmarker-merge-ci-i]][commonmarker-merge-ci] | Markdown | [Commonmarker][commonmarker] (via tree_haver) | Smart merge for Markdown (CommonMark via comrak Rust) |
110
+ | [dotenv-merge][dotenv-merge] | [![Version][dotenv-merge-gem-i]][dotenv-merge-gem] <br/> [![CI][dotenv-merge-ci-i]][dotenv-merge-ci] | Dotenv | internal | Smart merge for `.env` files |
111
+ | [json-merge][json-merge] | [![Version][json-merge-gem-i]][json-merge-gem] <br/> [![CI][json-merge-ci-i]][json-merge-ci] | JSON | [tree-sitter-json][ts-json] (via tree_haver) | Smart merge for JSON files |
112
+ | [jsonc-merge][jsonc-merge] | [![Version][jsonc-merge-gem-i]][jsonc-merge-gem] <br/> [![CI][jsonc-merge-ci-i]][jsonc-merge-ci] | JSONC | [tree-sitter-jsonc][ts-jsonc] (via tree_haver) | ⚠️ Proof of concept; Smart merge for JSON with Comments |
113
+ | [markdown-merge][markdown-merge] | [![Version][markdown-merge-gem-i]][markdown-merge-gem] <br/> [![CI][markdown-merge-ci-i]][markdown-merge-ci] | Markdown | [Commonmarker][commonmarker] / [Markly][markly] (via tree_haver), [Parslet][parslet] | **Foundation**: Shared base for Markdown mergers with inner code block merging |
114
+ | [markly-merge][markly-merge] | [![Version][markly-merge-gem-i]][markly-merge-gem] <br/> [![CI][markly-merge-ci-i]][markly-merge-ci] | Markdown | [Markly][markly] (via tree_haver) | Smart merge for Markdown (CommonMark via cmark-gfm C) |
115
+ | [prism-merge][prism-merge] | [![Version][prism-merge-gem-i]][prism-merge-gem] <br/> [![CI][prism-merge-ci-i]][prism-merge-ci] | Ruby | [Prism][prism] (`prism` std lib gem) | Smart merge for Ruby source files |
116
+ | [psych-merge][psych-merge] | [![Version][psych-merge-gem-i]][psych-merge-gem] <br/> [![CI][psych-merge-ci-i]][psych-merge-ci] | YAML | [Psych][psych] (`psych` std lib gem) | Smart merge for YAML files |
117
+ | [rbs-merge][rbs-merge] | [![Version][rbs-merge-gem-i]][rbs-merge-gem] <br/> [![CI][rbs-merge-ci-i]][rbs-merge-ci] | RBS | [tree-sitter-bash][ts-rbs] (via tree_haver), [RBS][rbs] (`rbs` std lib gem) | Smart merge for Ruby type signatures |
118
+ | [toml-merge][toml-merge] | [![Version][toml-merge-gem-i]][toml-merge-gem] <br/> [![CI][toml-merge-ci-i]][toml-merge-ci] | TOML | [Parslet + toml][toml], [Citrus + toml-rb][toml-rb], [tree-sitter-toml][ts-toml] (all via tree_haver) | Smart merge for TOML files |
119
+
120
+ #### Backend Platform Compatibility
121
+
122
+ tree_haver supports multiple parsing backends, but not all backends work on all Ruby platforms:
123
+
124
+ | Platform 👉️<br> TreeHaver Backend 👇️ | MRI | JRuby | TruffleRuby | Notes |
125
+ |-------------------------------------------------|:---:|:-----:|:-----------:|----------------------------------------------------------------------------|
126
+ | **MRI** ([ruby_tree_sitter][ruby_tree_sitter]) | ✅ | ❌ | ❌ | C extension, MRI only |
127
+ | **Rust** ([tree_stump][tree_stump]) | ✅ | ❌ | ❌ | Rust extension via magnus/rb-sys, MRI only |
128
+ | **FFI** ([ffi][ffi]) | ✅ | ✅ | ❌ | TruffleRuby's FFI doesn't support `STRUCT_BY_VALUE` |
129
+ | **Java** ([jtreesitter][jtreesitter]) | ❌ | ✅ | ❌ | JRuby only, requires grammar JARs |
130
+ | **Prism** ([prism][prism]) | ✅ | ✅ | ✅ | Ruby parsing, stdlib in Ruby 3.4+ |
131
+ | **Psych** ([psych][psych]) | ✅ | ✅ | ✅ | YAML parsing, stdlib |
132
+ | **Citrus** ([citrus][citrus]) | ✅ | ✅ | ✅ | Pure Ruby PEG parser, no native dependencies |
133
+ | **Parslet** ([parslet][parslet]) | ✅ | ✅ | ✅ | Pure Ruby PEG parser, no native dependencies |
134
+ | **Commonmarker** ([commonmarker][commonmarker]) | ✅ | ❌ | ❓ | Rust extension for Markdown (via [commonmarker-merge][commonmarker-merge]) |
135
+ | **Markly** ([markly][markly]) | ✅ | ❌ | ❓ | C extension for Markdown (via [markly-merge][markly-merge]) |
136
+
137
+ **Legend**: ✅ = Works, ❌ = Does not work, ❓ = Untested
138
+
139
+ **Why some backends don't work on certain platforms**:
140
+
141
+ - **JRuby**: Runs on the JVM; cannot load native C/Rust extensions (`.so` files)
142
+ - **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`)
143
+ - **FFI on TruffleRuby**: TruffleRuby's FFI implementation doesn't support returning structs by value, which tree-sitter's C API requires
204
144
 
205
- ```ruby
206
- merger = Dotenv::Merge::SmartMerger.new(
207
- template,
208
- destination,
209
- add_template_only_nodes: true,
210
- )
211
- result = merger.merge
212
- # Result includes variables from template that don't exist in destination
213
- ```
214
-
215
- ### The `*-merge` Gem Family
145
+ **Example implementations** for the gem templating use case:
216
146
 
217
- This gem is part of a family of gems that provide intelligent merging for various file formats:
218
-
219
- | Gem | Format | Parser | Description |
220
- |-----|--------|--------|-------------|
221
- | [ast-merge][ast-merge] | Text | internal | Shared infrastructure for all `*-merge` gems |
222
- | [prism-merge][prism-merge] | Ruby | [Prism][prism] | Smart merge for Ruby source files |
223
- | [psych-merge][psych-merge] | YAML | [Psych][psych] | Smart merge for YAML files |
224
- | [json-merge][json-merge] | JSON | [tree-sitter-json][ts-json] | Smart merge for JSON files |
225
- | [jsonc-merge][jsonc-merge] | JSONC | [tree-sitter-jsonc][ts-jsonc] | ⚠️ Proof of concept; Smart merge for JSON with Comments |
226
- | [bash-merge][bash-merge] | Bash | [tree-sitter-bash][ts-bash] | Smart merge for Bash scripts |
227
- | [rbs-merge][rbs-merge] | RBS | [RBS][rbs] | Smart merge for Ruby type signatures |
228
- | [dotenv-merge][dotenv-merge] | Dotenv | internal ([dotenv][dotenv]) | Smart merge for `.env` files |
229
- | [toml-merge][toml-merge] | TOML | [tree-sitter-toml][ts-toml] | Smart merge for TOML files |
230
- | [markly-merge][markly-merge] | Markdown | [Markly][markly] | Smart merge for Markdown (CommonMark via libcmark-gfm) |
231
- | [commonmarker-merge][commonmarker-merge] | Markdown | [Commonmarker][commonmarker] | Smart merge for Markdown (CommonMark via comrak) |
147
+ | Gem | Purpose | Description |
148
+ |--------------------------|-----------------|-----------------------------------------------|
149
+ | [kettle-dev][kettle-dev] | Gem Development | Gem templating tool using `*-merge` gems |
150
+ | [kettle-jem][kettle-jem] | Gem Templating | Gem template library with smart merge support |
232
151
 
152
+ [tree_haver]: https://github.com/kettle-rb/tree_haver
233
153
  [ast-merge]: https://github.com/kettle-rb/ast-merge
234
154
  [prism-merge]: https://github.com/kettle-rb/prism-merge
235
155
  [psych-merge]: https://github.com/kettle-rb/psych-merge
@@ -239,59 +159,131 @@ This gem is part of a family of gems that provide intelligent merging for variou
239
159
  [rbs-merge]: https://github.com/kettle-rb/rbs-merge
240
160
  [dotenv-merge]: https://github.com/kettle-rb/dotenv-merge
241
161
  [toml-merge]: https://github.com/kettle-rb/toml-merge
162
+ [markdown-merge]: https://github.com/kettle-rb/markdown-merge
242
163
  [markly-merge]: https://github.com/kettle-rb/markly-merge
243
164
  [commonmarker-merge]: https://github.com/kettle-rb/commonmarker-merge
165
+ [kettle-dev]: https://github.com/kettle-rb/kettle-dev
166
+ [kettle-jem]: https://github.com/kettle-rb/kettle-jem
167
+ [tree_haver-gem]: https://bestgems.org/gems/tree_haver
168
+ [ast-merge-gem]: https://bestgems.org/gems/ast-merge
169
+ [prism-merge-gem]: https://bestgems.org/gems/prism-merge
170
+ [psych-merge-gem]: https://bestgems.org/gems/psych-merge
171
+ [json-merge-gem]: https://bestgems.org/gems/json-merge
172
+ [jsonc-merge-gem]: https://bestgems.org/gems/jsonc-merge
173
+ [bash-merge-gem]: https://bestgems.org/gems/bash-merge
174
+ [rbs-merge-gem]: https://bestgems.org/gems/rbs-merge
175
+ [dotenv-merge-gem]: https://bestgems.org/gems/dotenv-merge
176
+ [toml-merge-gem]: https://bestgems.org/gems/toml-merge
177
+ [markdown-merge-gem]: https://bestgems.org/gems/markdown-merge
178
+ [markly-merge-gem]: https://bestgems.org/gems/markly-merge
179
+ [commonmarker-merge-gem]: https://bestgems.org/gems/commonmarker-merge
180
+ [kettle-dev-gem]: https://bestgems.org/gems/kettle-dev
181
+ [kettle-jem-gem]: https://bestgems.org/gems/kettle-jem
182
+ [tree_haver-gem-i]: https://img.shields.io/gem/v/tree_haver.svg
183
+ [ast-merge-gem-i]: https://img.shields.io/gem/v/ast-merge.svg
184
+ [prism-merge-gem-i]: https://img.shields.io/gem/v/prism-merge.svg
185
+ [psych-merge-gem-i]: https://img.shields.io/gem/v/psych-merge.svg
186
+ [json-merge-gem-i]: https://img.shields.io/gem/v/json-merge.svg
187
+ [jsonc-merge-gem-i]: https://img.shields.io/gem/v/jsonc-merge.svg
188
+ [bash-merge-gem-i]: https://img.shields.io/gem/v/bash-merge.svg
189
+ [rbs-merge-gem-i]: https://img.shields.io/gem/v/rbs-merge.svg
190
+ [dotenv-merge-gem-i]: https://img.shields.io/gem/v/dotenv-merge.svg
191
+ [toml-merge-gem-i]: https://img.shields.io/gem/v/toml-merge.svg
192
+ [markdown-merge-gem-i]: https://img.shields.io/gem/v/markdown-merge.svg
193
+ [markly-merge-gem-i]: https://img.shields.io/gem/v/markly-merge.svg
194
+ [commonmarker-merge-gem-i]: https://img.shields.io/gem/v/commonmarker-merge.svg
195
+ [kettle-dev-gem-i]: https://img.shields.io/gem/v/kettle-dev.svg
196
+ [kettle-jem-gem-i]: https://img.shields.io/gem/v/kettle-jem.svg
197
+ [tree_haver-ci-i]: https://github.com/kettle-rb/tree_haver/actions/workflows/current.yml/badge.svg
198
+ [ast-merge-ci-i]: https://github.com/kettle-rb/ast-merge/actions/workflows/current.yml/badge.svg
199
+ [prism-merge-ci-i]: https://github.com/kettle-rb/prism-merge/actions/workflows/current.yml/badge.svg
200
+ [psych-merge-ci-i]: https://github.com/kettle-rb/psych-merge/actions/workflows/current.yml/badge.svg
201
+ [json-merge-ci-i]: https://github.com/kettle-rb/json-merge/actions/workflows/current.yml/badge.svg
202
+ [jsonc-merge-ci-i]: https://github.com/kettle-rb/jsonc-merge/actions/workflows/current.yml/badge.svg
203
+ [bash-merge-ci-i]: https://github.com/kettle-rb/bash-merge/actions/workflows/current.yml/badge.svg
204
+ [rbs-merge-ci-i]: https://github.com/kettle-rb/rbs-merge/actions/workflows/current.yml/badge.svg
205
+ [dotenv-merge-ci-i]: https://github.com/kettle-rb/dotenv-merge/actions/workflows/current.yml/badge.svg
206
+ [toml-merge-ci-i]: https://github.com/kettle-rb/toml-merge/actions/workflows/current.yml/badge.svg
207
+ [markdown-merge-ci-i]: https://github.com/kettle-rb/markdown-merge/actions/workflows/current.yml/badge.svg
208
+ [markly-merge-ci-i]: https://github.com/kettle-rb/markly-merge/actions/workflows/current.yml/badge.svg
209
+ [commonmarker-merge-ci-i]: https://github.com/kettle-rb/commonmarker-merge/actions/workflows/current.yml/badge.svg
210
+ [kettle-dev-ci-i]: https://github.com/kettle-rb/kettle-dev/actions/workflows/current.yml/badge.svg
211
+ [kettle-jem-ci-i]: https://github.com/kettle-rb/kettle-jem/actions/workflows/current.yml/badge.svg
212
+ [tree_haver-ci]: https://github.com/kettle-rb/tree_haver/actions/workflows/current.yml
213
+ [ast-merge-ci]: https://github.com/kettle-rb/ast-merge/actions/workflows/current.yml
214
+ [prism-merge-ci]: https://github.com/kettle-rb/prism-merge/actions/workflows/current.yml
215
+ [psych-merge-ci]: https://github.com/kettle-rb/psych-merge/actions/workflows/current.yml
216
+ [json-merge-ci]: https://github.com/kettle-rb/json-merge/actions/workflows/current.yml
217
+ [jsonc-merge-ci]: https://github.com/kettle-rb/jsonc-merge/actions/workflows/current.yml
218
+ [bash-merge-ci]: https://github.com/kettle-rb/bash-merge/actions/workflows/current.yml
219
+ [rbs-merge-ci]: https://github.com/kettle-rb/rbs-merge/actions/workflows/current.yml
220
+ [dotenv-merge-ci]: https://github.com/kettle-rb/dotenv-merge/actions/workflows/current.yml
221
+ [toml-merge-ci]: https://github.com/kettle-rb/toml-merge/actions/workflows/current.yml
222
+ [markdown-merge-ci]: https://github.com/kettle-rb/markdown-merge/actions/workflows/current.yml
223
+ [markly-merge-ci]: https://github.com/kettle-rb/markly-merge/actions/workflows/current.yml
224
+ [commonmarker-merge-ci]: https://github.com/kettle-rb/commonmarker-merge/actions/workflows/current.yml
225
+ [kettle-dev-ci]: https://github.com/kettle-rb/kettle-dev/actions/workflows/current.yml
226
+ [kettle-jem-ci]: https://github.com/kettle-rb/kettle-jem/actions/workflows/current.yml
244
227
  [prism]: https://github.com/ruby/prism
245
228
  [psych]: https://github.com/ruby/psych
229
+ [ffi]: https://github.com/ffi/ffi
246
230
  [ts-json]: https://github.com/tree-sitter/tree-sitter-json
247
231
  [ts-jsonc]: https://gitlab.com/WhyNotHugo/tree-sitter-jsonc
248
232
  [ts-bash]: https://github.com/tree-sitter/tree-sitter-bash
233
+ [ts-rbs]: https://github.com/joker1007/tree-sitter-rbs
249
234
  [ts-toml]: https://github.com/tree-sitter-grammars/tree-sitter-toml
250
- [rbs]: https://github.com/ruby/rbs
251
235
  [dotenv]: https://github.com/bkeepers/dotenv
252
- [markly]: https://github.com/kivikakk/markly
236
+ [rbs]: https://github.com/ruby/rbs
237
+ [toml-rb]: https://github.com/emancu/toml-rb
238
+ [toml]: https://github.com/jm/toml
239
+ [markly]: https://github.com/ioquatix/markly
253
240
  [commonmarker]: https://github.com/gjtorikian/commonmarker
241
+ [ruby_tree_sitter]: https://github.com/Faveod/ruby-tree-sitter
242
+ [tree_stump]: https://github.com/joker1007/tree_stump
243
+ [jtreesitter]: https://central.sonatype.com/artifact/io.github.tree-sitter/jtreesitter
244
+ [citrus]: https://github.com/mjackson/citrus
245
+ [parslet]: https://github.com/kschiess/parslet
254
246
 
255
247
  ## 💡 Info you can shake a stick at
256
248
 
257
- | Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |
258
- |-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
259
- | Works with JRuby | [![JRuby 10.0 Compat][💎jruby-c-i]][🚎11-c-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf] |
260
- | 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] |
261
- | 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] |
262
- | 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] |
263
- | 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] |
264
- | 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] |
265
- | 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] |
266
- | 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] |
267
- | 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] |
268
- | `...` 💖 | [![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] |
249
+ | Tokens to Remember | [![Gem name][⛳️name-img]][👽dl-rank] [![Gem namespace][⛳️namespace-img]][📜src-gh] |
250
+ |-------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
251
+ | Works with JRuby | [![JRuby 10.0 Compat][💎jruby-c-i]][🚎11-c-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf] |
252
+ | 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] |
253
+ | 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] |
254
+ | Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord] [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork] [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor] |
255
+ | 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\!](https://img.shields.io/badge/KLOC-0.326-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue)][🧮kloc] |
256
+ | 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] |
257
+ | 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-img]][📄ilo-declaration] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] |
258
+ | 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] |
259
+ | 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] |
260
+ | `...` 💖 | [![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] |
269
261
 
270
262
  ### Compatibility
271
263
 
272
264
  Compatible with MRI Ruby 3.2.0+, and concordant releases of JRuby, and TruffleRuby.
273
265
 
274
- | 🚚 _Amazing_ test matrix was brought to you by | 🔎 appraisal2 🔎 and the color 💚 green 💚 |
266
+ | 🚚 *Amazing* test matrix was brought to you by | 🔎 appraisal2 🔎 and the color 💚 green 💚 |
275
267
  |------------------------------------------------|--------------------------------------------------------|
276
- | 👟 Check it out! | ✨ [github.com/appraisal-rb/appraisal2][💎appraisal2] ✨ |
268
+ | 👟 Check it out\! | ✨ [github.com/appraisal-rb/appraisal2][💎appraisal2] ✨ |
277
269
 
278
270
  ### Federated DVCS
279
271
 
280
272
  <details markdown="1">
281
273
  <summary>Find this repo on federated forges (Coming soon!)</summary>
282
274
 
283
- | Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
284
- |-------------------------------------------------|-----------------------------------------------------------------------|---------------------------|--------------------------|---------------------------|--------------------------|------------------------------|
285
- | 🧪 [kettle-rb/dotenv-merge on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix | ➖ |
286
- | 🧊 [kettle-rb/dotenv-merge on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
287
- | 🐙 [kettle-rb/dotenv-merge on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix | [💚][gh-discussions] |
288
- | 🎮️ [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] |
275
+ | Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
276
+ |---------------------------------------------------|------------------------------------------------------------------------|----------------------------|---------------------------|----------------------------|---------------------------|--------------------------------|
277
+ | 🧪 [kettle-rb/dotenv-merge on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix | ➖ |
278
+ | 🧊 [kettle-rb/dotenv-merge on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
279
+ | 🐙 [kettle-rb/dotenv-merge on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix | [💚][gh-discussions] |
280
+ | 🎮️ [Discord Server][🖼️galtzo-discord] | [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord] | [Let's][🖼️galtzo-discord] | [talk][🖼️galtzo-discord] | [about][🖼️galtzo-discord] | [this][🖼️galtzo-discord] | [library\!][🖼️galtzo-discord] |
289
281
 
290
282
  </details>
291
283
 
292
284
  [gh-discussions]: https://github.com/kettle-rb/dotenv-merge/discussions
293
285
 
294
- ### Enterprise Support [![Tidelift](https://tidelift.com/badges/package/rubygems/dotenv-merge)](https://tidelift.com/subscription/pkg/rubygems-dotenv-merge?utm_source=rubygems-dotenv-merge&utm_medium=referral&utm_campaign=readme)
286
+ ### Enterprise Support [![Tidelift](https://tidelift.com/badges/package/rubygems/dotenv-merge)][🏙️entsup-tidelift]
295
287
 
296
288
  Available as part of the Tidelift Subscription.
297
289
 
@@ -302,13 +294,12 @@ The maintainers of this and thousands of other packages are working with Tidelif
302
294
 
303
295
  [![Get help from me on Tidelift][🏙️entsup-tidelift-img]][🏙️entsup-tidelift]
304
296
 
305
- - 💡Subscribe for support guarantees covering _all_ your FLOSS dependencies
297
+ - 💡Subscribe for support guarantees covering *all* your FLOSS dependencies
306
298
  - 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar]
307
- - 💡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
308
-
309
- Alternatively:
299
+ - 💡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
300
+ Alternatively:
310
301
 
311
- - [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]
302
+ - [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord]
312
303
  - [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork]
313
304
  - [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor]
314
305
 
@@ -334,7 +325,7 @@ gem install dotenv-merge
334
325
  <summary>For Medium or High Security Installations</summary>
335
326
 
336
327
  This gem is cryptographically signed, and has verifiable [SHA-256 and SHA-512][💎SHA_checksums] checksums by
337
- [stone_checksums][💎stone_checksums]. Be sure the gem you install hasn’t been tampered with
328
+ [stone\_checksums][💎stone_checksums]. Be sure the gem you install hasn’t been tampered with
338
329
  by following the instructions below.
339
330
 
340
331
  Add my public key (if you haven’t already, expires 2045-04-29) as a trusted certificate:
@@ -381,24 +372,28 @@ merger = Dotenv::Merge::SmartMerger.new(
381
372
  Control which source wins when both files have the same key:
382
373
 
383
374
  - **`:template`** - Template values replace destination values
384
- - Version files (`VERSION=2.0.0` should replace `VERSION=1.0.0`)
385
- - API endpoint updates (`API_URL=https://new-api.example.com`)
375
+
376
+ - Version files (`VERSION=2.0.0` should replace `VERSION=1.0.0`)
377
+ - API endpoint updates (`API_URL=https://new-api.example.com`)
386
378
 
387
379
  - **`:destination`** (default) - Destination values are preserved
388
- - Local development settings
389
- - Project-specific customizations
380
+
381
+ - Local development settings
382
+ - Project-specific customizations
390
383
 
391
384
  ### Template-Only Nodes
392
385
 
393
386
  Control whether to add entries that only exist in the template:
394
387
 
395
388
  - **`true`** - Add new entries from template
396
- - New required environment variables
397
- - New configuration options
389
+
390
+ - New required environment variables
391
+ - New configuration options
398
392
 
399
393
  - **`false`** (default) - Skip template-only entries
400
- - Template has placeholder values
401
- - Destination is authoritative
394
+
395
+ - Template has placeholder values
396
+ - Destination is authoritative
402
397
 
403
398
  ## 🔧 Basic Usage
404
399
 
@@ -420,15 +415,13 @@ File.write("merged.env", result)
420
415
 
421
416
  Freeze blocks protect sections of your `.env` file from being modified during merges:
422
417
 
423
- ```
424
- # << FREEZE: project_secrets
425
- DATABASE_URL=postgresql://localhost/myapp_dev
426
- SECRET_KEY_BASE=my_local_secret_key_value
427
- # >> FREEZE: project_secrets
418
+ # << FREEZE: project_secrets
419
+ DATABASE_URL=postgresql://localhost/myapp_dev
420
+ SECRET_KEY_BASE=my_local_secret_key_value
421
+ # >> FREEZE: project_secrets
428
422
 
429
- # These entries can be updated by template
430
- API_VERSION=v2
431
- ```
423
+ # These entries can be updated by template
424
+ API_VERSION=v2
432
425
 
433
426
  ### Adding Template-Only Entries
434
427
 
@@ -457,7 +450,7 @@ result = merger.merge
457
450
  While kettle-rb tools are free software and will always be, the project would benefit immensely from some funding.
458
451
  Raising a monthly budget of... "dollars" would make the project more sustainable.
459
452
 
460
- We welcome both individual and corporate sponsors! We also offer a
453
+ We welcome both individual and corporate sponsors\! We also offer a
461
454
  wide array of funding channels to account for your preferences
462
455
  (although currently [Open Collective][🖇osc] is our preferred funding platform).
463
456
 
@@ -471,13 +464,13 @@ You can support the development of kettle-rb tools via
471
464
  [Open Collective][🖇osc]
472
465
  and [Tidelift][🏙️entsup-tidelift].
473
466
 
474
- | 📍 NOTE |
475
- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
467
+ | 📍 NOTE |
468
+ | --- |
476
469
  | 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. |
477
470
 
478
471
  ### Open Collective for Individuals
479
472
 
480
- Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/kettle-rb#backer)]
473
+ Support us with a monthly donation and help us continue our activities. \[[Become a backer][🖇osc-backers]\]
481
474
 
482
475
  NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
483
476
 
@@ -487,7 +480,7 @@ No backers yet. Be the first!
487
480
 
488
481
  ### Open Collective for Organizations
489
482
 
490
- 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)]
483
+ Become a sponsor and get your logo on our README on GitHub with a link to your site. \[[Become a sponsor][🖇osc-sponsors]\]
491
484
 
492
485
  NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
493
486
 
@@ -503,7 +496,7 @@ I’m driven by a passion to foster a thriving open-source community – a space
503
496
 
504
497
  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`.
505
498
 
506
- 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.
499
+ 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.
507
500
 
508
501
  **[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
509
502
 
@@ -546,7 +539,7 @@ chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][
546
539
 
547
540
  Made with [contributors-img][🖐contrib-rocks].
548
541
 
549
- Also see GitLab Contributors: [https://gitlab.com/kettle-rb/dotenv-merge/-/graphs/main][🚎contributors-gl]
542
+ Also see GitLab Contributors: <https://gitlab.com/kettle-rb/dotenv-merge/-/graphs/main>
550
543
 
551
544
  <details>
552
545
  <summary>⭐️ Star History</summary>
@@ -570,9 +563,9 @@ a new version should be immediately released that restores compatibility.
570
563
  Breaking changes to the public API will only be introduced with new major versions.
571
564
 
572
565
  > dropping support for a platform is both obviously and objectively a breaking change <br/>
573
- >—Jordan Harband ([@ljharb](https://github.com/ljharb), maintainer of SemVer) [in SemVer issue 716][📌semver-breaking]
566
+ > —Jordan Harband ([@ljharb](https://github.com/ljharb), maintainer of SemVer) [in SemVer issue 716][📌semver-breaking]
574
567
 
575
- I understand that policy doesn't work universally ("exceptions to every rule!"),
568
+ I understand that policy doesn't work universally ("exceptions to every rule\!"),
576
569
  but it is the policy here.
577
570
  As such, in many cases it is good to specify a dependency on this library using
578
571
  the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
@@ -608,7 +601,7 @@ See [LICENSE.txt][📄license] for the official [Copyright Notice][📄copyright
608
601
 
609
602
  <ul>
610
603
  <li>
611
- Copyright (c) 2025 Peter H. Boling, of
604
+ Copyright (c) 2025-2026 Peter H. Boling, of
612
605
  <a href="https://discord.gg/3qme4XHNKN">
613
606
  Galtzo.com
614
607
  <picture>
@@ -629,9 +622,9 @@ Please consider sponsoring me or the project.
629
622
 
630
623
  To join the community or get help 👇️ Join the Discord.
631
624
 
632
- [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]
625
+ [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord]
633
626
 
634
- To say "thanks!" ☝️ Join the Discord or 👇️ send money.
627
+ To say "thanks\!" ☝️ Join the Discord or 👇️ send money.
635
628
 
636
629
  [![Sponsor kettle-rb/dotenv-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]
637
630
 
@@ -674,7 +667,6 @@ Thanks for RTFM. ☺️
674
667
  [✉️discord-invite-img-ftb]: https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord
675
668
  [✉️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
676
669
  [✉️ruby-friends]: https://app.daily.dev/squads/rubyfriends
677
-
678
670
  [✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
679
671
  [⛳️gem-namespace]: https://github.com/kettle-rb/dotenv-merge
680
672
  [⛳️namespace-img]: https://img.shields.io/badge/namespace-Dotenv::Merge-3C2D2D.svg?style=square&logo=ruby&logoColor=white
@@ -798,7 +790,7 @@ Thanks for RTFM. ☺️
798
790
  [📌gitmoji]: https://gitmoji.dev
799
791
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
800
792
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
801
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.326-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
793
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.353-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
802
794
  [🔐security]: SECURITY.md
803
795
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
804
796
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -6,7 +6,8 @@ module Dotenv
6
6
  # Parses and categorizes lines as assignments, comments, blank lines, or invalid.
7
7
  #
8
8
  # Inherits from Ast::Merge::AstNode for a normalized API across all ast-merge
9
- # content nodes. This provides #slice, #location, #unwrap, and other standard methods.
9
+ # content nodes. This provides TreeHaver::Node protocol compatibility including
10
+ # #slice, #location, #unwrap, #type, #text, and other standard methods.
10
11
  #
11
12
  # Dotenv files follow a simple format where each line is one of:
12
13
  # - `KEY=value` - Environment variable assignment
@@ -46,7 +47,7 @@ module Dotenv
46
47
  attr_reader :line_number
47
48
 
48
49
  # @return [Symbol, nil] The line type (:assignment, :comment, :blank, :invalid)
49
- attr_reader :type
50
+ attr_reader :line_type
50
51
 
51
52
  # @return [String, nil] The environment variable key (for assignments)
52
53
  attr_reader :key
@@ -64,7 +65,7 @@ module Dotenv
64
65
  def initialize(raw, line_number)
65
66
  @raw = raw
66
67
  @line_number = line_number
67
- @type = nil
68
+ @line_type = nil
68
69
  @key = nil
69
70
  @value = nil
70
71
  @export = false
@@ -80,11 +81,17 @@ module Dotenv
80
81
  super(slice: @raw, location: location)
81
82
  end
82
83
 
84
+ # TreeHaver::Node protocol: type
85
+ # @return [String] "env_line"
86
+ def type
87
+ "env_line"
88
+ end
89
+
83
90
  # Generate a unique signature for this line (used for merge matching)
84
91
  #
85
92
  # @return [Array<Symbol, String>, nil] Signature array [:env, key] for assignments, nil otherwise
86
93
  def signature
87
- return unless @type == :assignment
94
+ return unless @line_type == :assignment
88
95
 
89
96
  [:env, @key]
90
97
  end
@@ -93,28 +100,28 @@ module Dotenv
93
100
  #
94
101
  # @return [Boolean] true if the line is a valid KEY=value assignment
95
102
  def assignment?
96
- @type == :assignment
103
+ @line_type == :assignment
97
104
  end
98
105
 
99
106
  # Check if this line is a comment
100
107
  #
101
108
  # @return [Boolean] true if the line starts with #
102
109
  def comment?
103
- @type == :comment
110
+ @line_type == :comment
104
111
  end
105
112
 
106
113
  # Check if this line is blank (empty or whitespace only)
107
114
  #
108
115
  # @return [Boolean] true if the line is blank
109
116
  def blank?
110
- @type == :blank
117
+ @line_type == :blank
111
118
  end
112
119
 
113
120
  # Check if this line is invalid (unparseable)
114
121
  #
115
122
  # @return [Boolean] true if the line could not be parsed
116
123
  def invalid?
117
- @type == :invalid
124
+ @line_type == :invalid
118
125
  end
119
126
 
120
127
  # Check if this line has the export prefix
@@ -144,20 +151,20 @@ module Dotenv
144
151
  #
145
152
  # @return [String] A debug representation of this EnvLine
146
153
  def inspect
147
- "#<#{self.class.name} line=#{@line_number} type=#{@type} key=#{@key.inspect}>"
154
+ "#<#{self.class.name} line=#{@line_number} line_type=#{@line_type} key=#{@key.inspect}>"
148
155
  end
149
156
 
150
157
  private
151
158
 
152
- # Parse the raw line content and set type, key, value, and export
159
+ # Parse the raw line content and set line_type, key, value, and export
153
160
  #
154
161
  # @return [void]
155
162
  def parse!
156
163
  stripped = @raw.strip
157
164
  if stripped.empty?
158
- @type = :blank
165
+ @line_type = :blank
159
166
  elsif stripped.start_with?("#")
160
- @type = :comment
167
+ @line_type = :comment
161
168
  else
162
169
  parse_assignment!(stripped)
163
170
  end
@@ -178,14 +185,14 @@ module Dotenv
178
185
  key_part, value_part = line.split("=", 2)
179
186
  key_part = key_part.strip
180
187
  if valid_key?(key_part)
181
- @type = :assignment
188
+ @line_type = :assignment
182
189
  @key = key_part
183
190
  @value = unquote(value_part || "")
184
191
  else
185
- @type = :invalid
192
+ @line_type = :invalid
186
193
  end
187
194
  else
188
- @type = :invalid
195
+ @line_type = :invalid
189
196
  end
190
197
  end
191
198
 
@@ -33,10 +33,12 @@ module Dotenv
33
33
  # @param source [String] Dotenv source code to analyze
34
34
  # @param freeze_token [String] Token for freeze block markers (default: "dotenv-merge")
35
35
  # @param signature_generator [Proc, nil] Custom signature generator
36
- def initialize(source, freeze_token: DEFAULT_FREEZE_TOKEN, signature_generator: nil)
36
+ # @param options [Hash] Additional options (forward compatibility - ignored by FileAnalysis)
37
+ def initialize(source, freeze_token: DEFAULT_FREEZE_TOKEN, signature_generator: nil, **options)
37
38
  @source = source
38
39
  @freeze_token = freeze_token
39
40
  @signature_generator = signature_generator
41
+ # **options captures any additional parameters (e.g., node_typing) for forward compatibility
40
42
 
41
43
  # Parse all lines
42
44
  @lines = parse_lines(source)
@@ -35,8 +35,9 @@ module Dotenv
35
35
  # Initialize a new merge result
36
36
  # @param template_analysis [FileAnalysis] Analysis of the template file
37
37
  # @param dest_analysis [FileAnalysis] Analysis of the destination file
38
- def initialize(template_analysis, dest_analysis)
39
- super(template_analysis: template_analysis, dest_analysis: dest_analysis)
38
+ # @param options [Hash] Additional options for forward compatibility
39
+ def initialize(template_analysis, dest_analysis, **options)
40
+ super(template_analysis: template_analysis, dest_analysis: dest_analysis, **options)
40
41
  end
41
42
 
42
43
  # Add content from the template at the given statement index
@@ -19,78 +19,108 @@ module Dotenv
19
19
  # add_template_only_nodes: true,
20
20
  # )
21
21
  # result = merger.merge
22
- class SmartMerger
23
- # @return [FileAnalysis] Analysis of template file
24
- attr_reader :template_analysis
25
-
26
- # @return [FileAnalysis] Analysis of destination file
27
- attr_reader :dest_analysis
28
-
22
+ #
23
+ # @example With node_typing for per-node-type preferences
24
+ # merger = SmartMerger.new(template, dest,
25
+ # node_typing: { "EnvLine" => ->(n) { NodeTyping.with_merge_type(n, :secret) } },
26
+ # preference: { default: :destination, secret: :template })
27
+ class SmartMerger < ::Ast::Merge::SmartMergerBase
29
28
  # Initialize a new SmartMerger
30
29
  #
31
30
  # @param template_content [String] Content of the template dotenv file
32
31
  # @param dest_content [String] Content of the destination dotenv file
33
- # @param preference [Symbol] Which version to prefer on match
34
- # (:template or :destination, default: :destination)
32
+ # @param signature_generator [Proc, nil] Custom signature generator
33
+ # @param preference [Symbol, Hash] :destination, :template, or per-type Hash
35
34
  # @param add_template_only_nodes [Boolean] Whether to add template-only env vars
36
35
  # (default: false)
37
36
  # @param freeze_token [String] Token for freeze block markers
38
37
  # (default: "dotenv-merge")
39
- # @param signature_generator [Proc, nil] Custom signature generator
38
+ # @param match_refiner [#call, nil] Match refiner for fuzzy matching
39
+ # @param regions [Array<Hash>, nil] Region configurations for nested merging
40
+ # @param region_placeholder [String, nil] Custom placeholder for regions
41
+ # @param node_typing [Hash{Symbol,String => #call}, nil] Node typing configuration
42
+ # for per-node-type merge preferences
43
+ # @param options [Hash] Additional options for forward compatibility
40
44
  def initialize(
41
45
  template_content,
42
46
  dest_content,
47
+ signature_generator: nil,
43
48
  preference: :destination,
44
49
  add_template_only_nodes: false,
45
- freeze_token: FileAnalysis::DEFAULT_FREEZE_TOKEN,
46
- signature_generator: nil
50
+ freeze_token: nil,
51
+ match_refiner: nil,
52
+ regions: nil,
53
+ region_placeholder: nil,
54
+ node_typing: nil,
55
+ **options
47
56
  )
48
- @preference = preference
49
- @add_template_only_nodes = add_template_only_nodes
50
-
51
- # Parse template
52
- @template_analysis = FileAnalysis.new(
57
+ super(
53
58
  template_content,
54
- freeze_token: freeze_token,
55
- signature_generator: signature_generator,
56
- )
57
-
58
- # Parse destination
59
- @dest_analysis = FileAnalysis.new(
60
59
  dest_content,
61
- freeze_token: freeze_token,
62
60
  signature_generator: signature_generator,
61
+ preference: preference,
62
+ add_template_only_nodes: add_template_only_nodes,
63
+ freeze_token: freeze_token,
64
+ match_refiner: match_refiner,
65
+ regions: regions,
66
+ region_placeholder: region_placeholder,
67
+ node_typing: node_typing,
68
+ **options
63
69
  )
70
+ end
71
+
72
+ protected
64
73
 
65
- @result = MergeResult.new(@template_analysis, @dest_analysis)
74
+ # @return [Class] The analysis class for dotenv files
75
+ def analysis_class
76
+ FileAnalysis
66
77
  end
67
78
 
68
- # Perform the merge operation
69
- #
70
- # @return [String] The merged content as a string
71
- def merge
72
- merge_result.to_s
79
+ # @return [String] The default freeze token
80
+ def default_freeze_token
81
+ "dotenv-merge"
82
+ end
83
+
84
+ # @return [Class, nil] No separate resolver class for dotenv
85
+ def resolver_class
86
+ nil
87
+ end
88
+
89
+ # @return [Class, nil] Result class (built with analysis args)
90
+ def result_class
91
+ nil
92
+ end
93
+
94
+ # Build the result with required analysis arguments
95
+ def build_result
96
+ MergeResult.new(@template_analysis, @dest_analysis)
73
97
  end
74
98
 
75
- # Perform the merge operation and return the full result object
99
+ # @return [Class] The template parse error class for dotenv
100
+ def template_parse_error_class
101
+ ParseError
102
+ end
103
+
104
+ # @return [Class] The destination parse error class for dotenv
105
+ def destination_parse_error_class
106
+ ParseError
107
+ end
108
+
109
+ # Perform the dotenv-specific merge with custom alignment logic
76
110
  #
77
- # @return [MergeResult] The merge result containing merged content
78
- def merge_result
79
- return @merge_result if @merge_result
80
-
81
- @merge_result = DebugLogger.time("SmartMerger#merge") do
82
- alignment = align_statements
83
-
84
- DebugLogger.debug("Alignment complete", {
85
- total_entries: alignment.size,
86
- matches: alignment.count { |e| e[:type] == :match },
87
- template_only: alignment.count { |e| e[:type] == :template_only },
88
- dest_only: alignment.count { |e| e[:type] == :dest_only },
89
- })
90
-
91
- process_alignment(alignment)
92
- @result
93
- end
111
+ # @return [MergeResult] The merge result
112
+ def perform_merge
113
+ alignment = align_statements
114
+
115
+ DebugLogger.debug("Alignment complete", {
116
+ total_entries: alignment.size,
117
+ matches: alignment.count { |e| e[:type] == :match },
118
+ template_only: alignment.count { |e| e[:type] == :template_only },
119
+ dest_only: alignment.count { |e| e[:type] == :dest_only },
120
+ })
121
+
122
+ process_alignment(alignment)
123
+ @result
94
124
  end
95
125
 
96
126
  private
@@ -211,8 +241,10 @@ module Dotenv
211
241
  return
212
242
  end
213
243
 
214
- # Apply preference
215
- case @preference
244
+ # Resolve preference (handles both Symbol and Hash preferences)
245
+ resolved_pref = resolve_preference(entry[:template_stmt], entry[:dest_stmt])
246
+
247
+ case resolved_pref
216
248
  when :template
217
249
  @result.add_from_template(entry[:template_index], decision: MergeResult::DECISION_TEMPLATE)
218
250
  when :destination
@@ -222,6 +254,47 @@ module Dotenv
222
254
  end
223
255
  end
224
256
 
257
+ # Resolve preference for a matched pair
258
+ # @param template_stmt [Object] Template statement
259
+ # @param dest_stmt [Object] Destination statement
260
+ # @return [Symbol] :template or :destination
261
+ def resolve_preference(template_stmt, dest_stmt)
262
+ return @preference if @preference.is_a?(Symbol)
263
+
264
+ # Hash preference - check for node_typing-based merge_types
265
+ if @preference.is_a?(Hash)
266
+ # Apply node_typing if configured
267
+ typed_template = apply_node_typing(template_stmt)
268
+ apply_node_typing(dest_stmt)
269
+
270
+ # Check template merge_type first
271
+ if Ast::Merge::NodeTyping.typed_node?(typed_template)
272
+ merge_type = typed_template.merge_type
273
+ return @preference[merge_type] if @preference.key?(merge_type)
274
+ end
275
+
276
+ # Fall back to default
277
+ return @preference[:default] || :destination
278
+ end
279
+
280
+ :destination
281
+ end
282
+
283
+ # Apply node typing to a statement if node_typing is configured
284
+ # @param stmt [Object] The statement
285
+ # @return [Object] The statement, possibly wrapped with merge_type
286
+ def apply_node_typing(stmt)
287
+ return stmt unless @node_typing
288
+ return stmt unless stmt
289
+
290
+ # Check by class name
291
+ type_key = stmt.class.name&.split("::")&.last
292
+ callable = @node_typing[type_key] || @node_typing[type_key&.to_sym]
293
+ return callable.call(stmt) if callable
294
+
295
+ stmt
296
+ end
297
+
225
298
  # Process a template-only entry
226
299
  # @param entry [Hash] Alignment entry
227
300
  # @return [void]
@@ -5,7 +5,7 @@ module Dotenv
5
5
  # Version information for Dotenv::Merge
6
6
  module Version
7
7
  # Current version of the dotenv-merge gem
8
- VERSION = "1.0.0"
8
+ VERSION = "1.0.2"
9
9
  end
10
10
  VERSION = Version::VERSION # traditional location
11
11
  end
data/lib/dotenv/merge.rb CHANGED
@@ -68,6 +68,18 @@ module Dotenv
68
68
  end
69
69
  end
70
70
 
71
+ # Register with ast-merge's MergeGemRegistry for RSpec dependency tags
72
+ # Only register if MergeGemRegistry is loaded (i.e., in test environment)
73
+ if defined?(Ast::Merge::RSpec::MergeGemRegistry)
74
+ Ast::Merge::RSpec::MergeGemRegistry.register(
75
+ :dotenv_merge,
76
+ require_path: "dotenv/merge",
77
+ merger_class: "Dotenv::Merge::SmartMerger",
78
+ test_source: "KEY=value",
79
+ category: :config,
80
+ )
81
+ end
82
+
71
83
  Dotenv::Merge::Version.class_eval do
72
84
  extend VersionGem::Basic
73
85
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dotenv-merge
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -37,20 +37,46 @@ cert_chain:
37
37
  -----END CERTIFICATE-----
38
38
  date: 1980-01-02 00:00:00.000000000 Z
39
39
  dependencies:
40
+ - !ruby/object:Gem::Dependency
41
+ name: tree_haver
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '5.0'
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 5.0.3
50
+ type: :runtime
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: '5.0'
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: 5.0.3
40
60
  - !ruby/object:Gem::Dependency
41
61
  name: ast-merge
42
62
  requirement: !ruby/object:Gem::Requirement
43
63
  requirements:
44
64
  - - "~>"
45
65
  - !ruby/object:Gem::Version
46
- version: '1.0'
66
+ version: '4.0'
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: 4.0.5
47
70
  type: :runtime
48
71
  prerelease: false
49
72
  version_requirements: !ruby/object:Gem::Requirement
50
73
  requirements:
51
74
  - - "~>"
52
75
  - !ruby/object:Gem::Version
53
- version: '1.0'
76
+ version: '4.0'
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: 4.0.5
54
80
  - !ruby/object:Gem::Dependency
55
81
  name: version_gem
56
82
  requirement: !ruby/object:Gem::Requirement
@@ -266,10 +292,10 @@ licenses:
266
292
  - MIT
267
293
  metadata:
268
294
  homepage_uri: https://dotenv-merge.galtzo.com/
269
- source_code_uri: https://github.com/kettle-rb/dotenv-merge/tree/v1.0.0
270
- changelog_uri: https://github.com/kettle-rb/dotenv-merge/blob/v1.0.0/CHANGELOG.md
295
+ source_code_uri: https://github.com/kettle-rb/dotenv-merge/tree/v1.0.2
296
+ changelog_uri: https://github.com/kettle-rb/dotenv-merge/blob/v1.0.2/CHANGELOG.md
271
297
  bug_tracker_uri: https://github.com/kettle-rb/dotenv-merge/issues
272
- documentation_uri: https://www.rubydoc.info/gems/dotenv-merge/1.0.0
298
+ documentation_uri: https://www.rubydoc.info/gems/dotenv-merge/1.0.2
273
299
  funding_uri: https://github.com/sponsors/pboling
274
300
  wiki_uri: https://github.com/kettle-rb/dotenv-merge/wiki
275
301
  news_uri: https://www.railsbling.com/tags/dotenv-merge
@@ -298,7 +324,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
298
324
  - !ruby/object:Gem::Version
299
325
  version: '0'
300
326
  requirements: []
301
- rubygems_version: 4.0.1
327
+ rubygems_version: 4.0.5
302
328
  specification_version: 4
303
329
  summary: "☯️ Intelligent .env file merging using structured parsing"
304
330
  test_files: []
metadata.gz.sig CHANGED
Binary file