Class: Markdown::Merge::CodeBlockMerger
- Inherits:
-
Object
- Object
- Markdown::Merge::CodeBlockMerger
- Defined in:
- lib/markdown/merge/code_block_merger.rb
Overview
Merges fenced code blocks using language-specific *-merge gems.
When two code blocks with the same signature are matched, this class delegates the merge to the appropriate language-specific merger:
-
Ruby code → prism-merge
-
YAML code → psych-merge
-
JSON code → json-merge
-
TOML code → toml-merge
Constant Summary collapse
- DEFAULT_MERGERS =
Default language-to-merger mapping Each merger is a lambda that takes (template_content, dest_content, preference) and returns { merged: true/false, content: String, stats: Hash } :nocov: integration - DEFAULT_MERGERS lambdas require external gems
{ # Ruby code blocks "ruby" => ->(template, dest, preference, **opts) { require "prism/merge" CodeBlockMerger.merge_with_prism(template, dest, preference, **opts) }, "rb" => ->(template, dest, preference, **opts) { require "prism/merge" CodeBlockMerger.merge_with_prism(template, dest, preference, **opts) }, # YAML code blocks "yaml" => ->(template, dest, preference, **opts) { require "psych/merge" CodeBlockMerger.merge_with_psych(template, dest, preference, **opts) }, "yml" => ->(template, dest, preference, **opts) { require "psych/merge" CodeBlockMerger.merge_with_psych(template, dest, preference, **opts) }, # JSON code blocks "json" => ->(template, dest, preference, **opts) { require "json/merge" CodeBlockMerger.merge_with_json(template, dest, preference, **opts) }, # TOML code blocks "toml" => ->(template, dest, preference, **opts) { require "toml/merge" CodeBlockMerger.merge_with_toml(template, dest, preference, **opts) }, }.freeze
Instance Attribute Summary collapse
-
#enabled ⇒ Boolean
readonly
Whether inner-merge is enabled.
-
#mergers ⇒ Hash<String, Proc>
readonly
Language to merger mapping.
Class Method Summary collapse
-
.merge_with_json(template, dest, preference, **opts) ⇒ Hash
Merge JSON code using json-merge.
-
.merge_with_prism(template, dest, preference, **opts) ⇒ Hash
Merge Ruby code using prism-merge.
-
.merge_with_psych(template, dest, preference, **opts) ⇒ Hash
Merge YAML code using psych-merge.
-
.merge_with_toml(template, dest, preference, **opts) ⇒ Hash
Merge TOML code using toml-merge.
Instance Method Summary collapse
-
#initialize(mergers: {}, enabled: true) ⇒ CodeBlockMerger
constructor
Creates a new CodeBlockMerger.
-
#merge_code_blocks(template_node, dest_node, preference:, **opts) ⇒ Hash
Merge two code blocks using the appropriate language-specific merger.
-
#supports_language?(language) ⇒ Boolean
Check if inner-merge is available for a language.
Constructor Details
#initialize(mergers: {}, enabled: true) ⇒ CodeBlockMerger
Creates a new CodeBlockMerger.
83 84 85 86 |
# File 'lib/markdown/merge/code_block_merger.rb', line 83 def initialize(mergers: {}, enabled: true) @mergers = DEFAULT_MERGERS.merge(mergers) @enabled = enabled end |
Instance Attribute Details
#enabled ⇒ Boolean (readonly)
Returns Whether inner-merge is enabled.
76 77 78 |
# File 'lib/markdown/merge/code_block_merger.rb', line 76 def enabled @enabled end |
#mergers ⇒ Hash<String, Proc> (readonly)
Returns Language to merger mapping.
73 74 75 |
# File 'lib/markdown/merge/code_block_merger.rb', line 73 def mergers @mergers end |
Class Method Details
.merge_with_json(template, dest, preference, **opts) ⇒ Hash
Errors are handled by merge_code_blocks when called via DEFAULT_MERGERS
Merge JSON code using json-merge.
260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/markdown/merge/code_block_merger.rb', line 260 def merge_with_json(template, dest, preference, **opts) merger = ::Json::Merge::SmartMerger.new( template, dest, preference: preference, add_template_only_nodes: opts.fetch(:add_template_only_nodes, false), ) { merged: true, content: merger.merge, stats: merger.stats, } end |
.merge_with_prism(template, dest, preference, **opts) ⇒ Hash
Errors are handled by merge_code_blocks when called via DEFAULT_MERGERS
Merge Ruby code using prism-merge.
214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/markdown/merge/code_block_merger.rb', line 214 def merge_with_prism(template, dest, preference, **opts) merger = ::Prism::Merge::SmartMerger.new( template, dest, preference: preference, add_template_only_nodes: opts.fetch(:add_template_only_nodes, false), ) { merged: true, content: merger.merge, stats: merger.stats, } end |
.merge_with_psych(template, dest, preference, **opts) ⇒ Hash
Errors are handled by merge_code_blocks when called via DEFAULT_MERGERS
Merge YAML code using psych-merge.
237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
# File 'lib/markdown/merge/code_block_merger.rb', line 237 def merge_with_psych(template, dest, preference, **opts) merger = ::Psych::Merge::SmartMerger.new( template, dest, preference: preference, add_template_only_nodes: opts.fetch(:add_template_only_nodes, false), ) { merged: true, content: merger.merge, stats: merger.stats, } end |
.merge_with_toml(template, dest, preference, **opts) ⇒ Hash
Errors are handled by merge_code_blocks when called via DEFAULT_MERGERS
Merge TOML code using toml-merge.
283 284 285 286 287 288 289 290 291 292 293 294 295 296 |
# File 'lib/markdown/merge/code_block_merger.rb', line 283 def merge_with_toml(template, dest, preference, **opts) merger = ::Toml::Merge::SmartMerger.new( template, dest, preference: preference, add_template_only_nodes: opts.fetch(:add_template_only_nodes, false), ) { merged: true, content: merger.merge, stats: merger.stats, } end |
Instance Method Details
#merge_code_blocks(template_node, dest_node, preference:, **opts) ⇒ Hash
Merge two code blocks using the appropriate language-specific merger.
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/markdown/merge/code_block_merger.rb', line 106 def merge_code_blocks(template_node, dest_node, preference:, **opts) return not_merged("inner-merge disabled") unless @enabled language = extract_language(template_node) || extract_language(dest_node) return not_merged("no language specified") unless language merger = @mergers[language.downcase] return not_merged("no merger for language: #{language}") unless merger template_content = extract_content(template_node) dest_content = extract_content(dest_node) # If content is identical, no need to merge if template_content == dest_content return { merged: true, content: rebuild_code_block(language, dest_content, dest_node), stats: {decision: :identical}, } end begin result = merger.call(template_content, dest_content, preference, **opts) if result[:merged] { merged: true, content: rebuild_code_block(language, result[:content], dest_node), stats: result[:stats] || {}, } else not_merged(result[:reason] || "merger declined") end rescue LoadError => e not_merged("merger gem not available: #{e.message}") rescue TreeHaver::Error => e # TreeHaver::NotAvailable and TreeHaver::Error inherit from Exception (not StandardError) # for safety reasons related to backend conflicts. We catch them here to handle # gracefully when a backend isn't properly configured. not_merged("backend not available: #{e.message}") rescue StandardError => e # :nocov: defensive - Prism::Merge::ParseError handling when prism/merge is loaded # Check for Prism::Merge::ParseError if prism/merge is loaded if defined?(::Prism::Merge::ParseError) && e.is_a?(::Prism::Merge::ParseError) not_merged("Ruby parse error: #{e.message}") else not_merged("merge failed: #{e.class}: #{e.message}") end # :nocov: end end |
#supports_language?(language) ⇒ Boolean
Check if inner-merge is available for a language.
92 93 94 95 96 97 |
# File 'lib/markdown/merge/code_block_merger.rb', line 92 def supports_language?(language) return false unless @enabled return false if language.nil? || language.empty? @mergers.key?(language.downcase) end |