markdown-merge 1.0.3 → 7.1.1
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/LICENSE.md +13 -0
- data/README.md +99 -482
- data/lib/markdown/merge/backend_support.rb +200 -0
- data/lib/markdown/merge/cleanse/block_spacing.rb +18 -23
- data/lib/markdown/merge/cleanse/code_fence_spacing.rb +16 -16
- data/lib/markdown/merge/cleanse/condensed_link_refs.rb +36 -30
- data/lib/markdown/merge/cleanse/list_marker_duplication.rb +66 -0
- data/lib/markdown/merge/cleanse/templating_corruption.rb +86 -0
- data/lib/markdown/merge/cleanse.rb +5 -3
- data/lib/markdown/merge/code_block_match_refiner.rb +111 -0
- data/lib/markdown/merge/code_block_merger.rb +489 -47
- data/lib/markdown/merge/comment_tracker.rb +42 -0
- data/lib/markdown/merge/conflict_resolver.rb +77 -6
- data/lib/markdown/merge/debug_logger.rb +2 -2
- data/lib/markdown/merge/document_problems.rb +3 -3
- data/lib/markdown/merge/file_aligner.rb +433 -133
- data/lib/markdown/merge/file_analysis.rb +387 -51
- data/lib/markdown/merge/file_analysis_base.rb +188 -51
- data/lib/markdown/merge/gap_line_node.rb +14 -8
- data/lib/markdown/merge/link_definition_node.rb +5 -5
- data/lib/markdown/merge/link_parser.rb +60 -60
- data/lib/markdown/merge/link_reference_rehydrator.rb +14 -14
- data/lib/markdown/merge/list_match_refiner.rb +98 -0
- data/lib/markdown/merge/list_merger.rb +322 -0
- data/lib/markdown/merge/markdown_structure.rb +3 -3
- data/lib/markdown/merge/merge_result.rb +321 -4
- data/lib/markdown/merge/node_type_normalizer.rb +6 -6
- data/lib/markdown/merge/output_builder.rb +101 -19
- data/lib/markdown/merge/partial_template_merger.rb +248 -27
- data/lib/markdown/merge/preservation_support.rb +291 -0
- data/lib/markdown/merge/smart_merger.rb +62 -14
- data/lib/markdown/merge/smart_merger_base.rb +929 -60
- data/lib/markdown/merge/table_match_algorithm.rb +22 -27
- data/lib/markdown/merge/table_match_refiner.rb +6 -10
- data/lib/markdown/merge/version.rb +5 -4
- data/lib/markdown/merge/whitespace_normalizer.rb +25 -33
- data/lib/markdown/merge/wrapper_support.rb +194 -0
- data/lib/markdown/merge.rb +669 -122
- data/lib/markdown-merge.rb +9 -4
- data/sig/markdown/merge.rbs +3 -336
- data.tar.gz.sig +0 -0
- metadata +104 -93
- metadata.gz.sig +0 -0
- data/CHANGELOG.md +0 -308
- data/CITATION.cff +0 -20
- data/CODE_OF_CONDUCT.md +0 -134
- data/CONTRIBUTING.md +0 -227
- data/FUNDING.md +0 -74
- data/LICENSE.txt +0 -21
- data/REEK +0 -0
- data/RUBOCOP.md +0 -71
- data/SECURITY.md +0 -21
|
@@ -35,7 +35,7 @@ module Markdown
|
|
|
35
35
|
first_column: 0.20, # (B) First column matching
|
|
36
36
|
row_content: 0.25, # (C) Content in matching rows
|
|
37
37
|
total_cells: 0.15, # (D) Overall cell matching
|
|
38
|
-
position: 0.15
|
|
38
|
+
position: 0.15 # (E) Position distance
|
|
39
39
|
}.freeze
|
|
40
40
|
|
|
41
41
|
# Minimum similarity threshold to consider cells as potentially matching
|
|
@@ -68,7 +68,8 @@ module Markdown
|
|
|
68
68
|
# @param total_tables_b [Integer] Total tables in second document (default: 1)
|
|
69
69
|
# @param weights [Hash] Custom weights for scoring factors
|
|
70
70
|
# @param backend [Symbol] Markdown backend for type normalization (default: :commonmarker)
|
|
71
|
-
def initialize(position_a: nil, position_b: nil, total_tables_a: 1, total_tables_b: 1, weights: {},
|
|
71
|
+
def initialize(position_a: nil, position_b: nil, total_tables_a: 1, total_tables_b: 1, weights: {},
|
|
72
|
+
backend: :commonmarker)
|
|
72
73
|
@position_a = position_a
|
|
73
74
|
@position_b = position_b
|
|
74
75
|
@total_tables_a = [total_tables_a, 1].max
|
|
@@ -93,7 +94,7 @@ module Markdown
|
|
|
93
94
|
first_column: compute_first_column_match(rows_a, rows_b),
|
|
94
95
|
row_content: compute_row_content_match(rows_a, rows_b),
|
|
95
96
|
total_cells: compute_total_cells_match(rows_a, rows_b),
|
|
96
|
-
position: compute_position_score
|
|
97
|
+
position: compute_position_score
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
weighted_average(scores)
|
|
@@ -113,9 +114,7 @@ module Markdown
|
|
|
113
114
|
return str_a.length if str_b.empty?
|
|
114
115
|
|
|
115
116
|
# Ensure str_a is the shorter string for space optimization
|
|
116
|
-
if str_a.length > str_b.length
|
|
117
|
-
str_a, str_b = str_b, str_a
|
|
118
|
-
end
|
|
117
|
+
str_a, str_b = str_b, str_a if str_a.length > str_b.length
|
|
119
118
|
|
|
120
119
|
m = str_a.length
|
|
121
120
|
n = str_b.length
|
|
@@ -128,11 +127,11 @@ module Markdown
|
|
|
128
127
|
curr_row[0] = j
|
|
129
128
|
|
|
130
129
|
(1..m).each do |i|
|
|
131
|
-
cost =
|
|
130
|
+
cost = str_a[i - 1] == str_b[j - 1] ? 0 : 1
|
|
132
131
|
curr_row[i] = [
|
|
133
132
|
curr_row[i - 1] + 1, # insertion
|
|
134
133
|
prev_row[i] + 1, # deletion
|
|
135
|
-
prev_row[i - 1] + cost
|
|
134
|
+
prev_row[i - 1] + cost # substitution
|
|
136
135
|
].min
|
|
137
136
|
end
|
|
138
137
|
|
|
@@ -171,9 +170,7 @@ module Markdown
|
|
|
171
170
|
rows = []
|
|
172
171
|
child = table.first_child
|
|
173
172
|
while child
|
|
174
|
-
if table_row_type?(child)
|
|
175
|
-
rows << extract_cells(child)
|
|
176
|
-
end
|
|
173
|
+
rows << extract_cells(child) if table_row_type?(child)
|
|
177
174
|
child = next_sibling(child)
|
|
178
175
|
end
|
|
179
176
|
rows
|
|
@@ -196,7 +193,7 @@ module Markdown
|
|
|
196
193
|
|
|
197
194
|
# Normalize the type using NodeTypeNormalizer for backend portability
|
|
198
195
|
canonical = NodeTypeNormalizer.canonical_type(node.type, @backend || :commonmarker)
|
|
199
|
-
|
|
196
|
+
%i[table_row table_header].include?(canonical)
|
|
200
197
|
end
|
|
201
198
|
|
|
202
199
|
# Get the next sibling of a node.
|
|
@@ -231,9 +228,7 @@ module Markdown
|
|
|
231
228
|
while child
|
|
232
229
|
if child.respond_to?(:type)
|
|
233
230
|
canonical = NodeTypeNormalizer.canonical_type(child.type, @backend || :commonmarker)
|
|
234
|
-
if canonical == :table_cell
|
|
235
|
-
cells << extract_text_content(child)
|
|
236
|
-
end
|
|
231
|
+
cells << extract_text_content(child) if canonical == :table_cell
|
|
237
232
|
end
|
|
238
233
|
child = next_sibling(child)
|
|
239
234
|
end
|
|
@@ -271,14 +266,14 @@ module Markdown
|
|
|
271
266
|
canonical_type = NodeTypeNormalizer.canonical_type(node.type, @backend || :commonmarker)
|
|
272
267
|
|
|
273
268
|
# Collect text from text and code nodes
|
|
274
|
-
if
|
|
269
|
+
if %i[text code].include?(canonical_type)
|
|
275
270
|
content = if node.respond_to?(:string_content)
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
271
|
+
node.string_content.to_s
|
|
272
|
+
elsif node.respond_to?(:text)
|
|
273
|
+
node.text.to_s
|
|
274
|
+
else
|
|
275
|
+
''
|
|
276
|
+
end
|
|
282
277
|
text_parts << content unless content.empty?
|
|
283
278
|
end
|
|
284
279
|
|
|
@@ -292,10 +287,10 @@ module Markdown
|
|
|
292
287
|
while child
|
|
293
288
|
collect_text_recursive(child, text_parts)
|
|
294
289
|
child = if child.respond_to?(:next_sibling)
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
290
|
+
child.next_sibling
|
|
291
|
+
else
|
|
292
|
+
(child.respond_to?(:next) ? child.next : nil)
|
|
293
|
+
end
|
|
299
294
|
end
|
|
300
295
|
end
|
|
301
296
|
end
|
|
@@ -354,7 +349,7 @@ module Markdown
|
|
|
354
349
|
|
|
355
350
|
# Average over total cells
|
|
356
351
|
total_cells = col_a.size + col_b.size
|
|
357
|
-
|
|
352
|
+
total_cells > 0 ? total_similarity / total_cells : 0.0
|
|
358
353
|
end
|
|
359
354
|
|
|
360
355
|
# (C) Compute average match percentage for rows with matching first column.
|
|
@@ -53,7 +53,7 @@ module Markdown
|
|
|
53
53
|
# @param dest_nodes [Array] Unmatched nodes from destination
|
|
54
54
|
# @param context [Hash] Additional context (may contain :template_analysis, :dest_analysis)
|
|
55
55
|
# @return [Array<MatchResult>] Array of table matches
|
|
56
|
-
def call(template_nodes, dest_nodes,
|
|
56
|
+
def call(template_nodes, dest_nodes, _context = {})
|
|
57
57
|
template_tables = extract_tables(template_nodes)
|
|
58
58
|
dest_tables = extract_tables(dest_nodes)
|
|
59
59
|
|
|
@@ -89,23 +89,19 @@ module Markdown
|
|
|
89
89
|
# @return [Boolean]
|
|
90
90
|
def table_node?(node)
|
|
91
91
|
# Check if it's a typed wrapper node first
|
|
92
|
-
if Ast::Merge::NodeTyping.typed_node?(node)
|
|
93
|
-
return Ast::Merge::NodeTyping.merge_type_for(node) == :table
|
|
94
|
-
end
|
|
92
|
+
return Ast::Merge::NodeTyping.merge_type_for(node) == :table if Ast::Merge::NodeTyping.typed_node?(node)
|
|
95
93
|
|
|
96
94
|
# Check merge_type directly (wrapped nodes from NodeTypeNormalizer)
|
|
97
|
-
if node.respond_to?(:merge_type) && node.merge_type
|
|
98
|
-
return node.merge_type == :table
|
|
99
|
-
end
|
|
95
|
+
return node.merge_type == :table if node.respond_to?(:merge_type) && node.merge_type
|
|
100
96
|
|
|
101
97
|
# Check raw type (string comparison for tree_haver nodes)
|
|
102
98
|
if node.respond_to?(:type)
|
|
103
99
|
node_type = node.type
|
|
104
|
-
return
|
|
100
|
+
return [:table, 'table'].include?(node_type) || node_type.to_s == 'table'
|
|
105
101
|
end
|
|
106
102
|
|
|
107
103
|
# Fallback: class name check
|
|
108
|
-
return true if node.class.name.to_s.include?(
|
|
104
|
+
return true if node.class.name.to_s.include?('Table')
|
|
109
105
|
|
|
110
106
|
false
|
|
111
107
|
end
|
|
@@ -126,7 +122,7 @@ module Markdown
|
|
|
126
122
|
total_tables_a: total_t,
|
|
127
123
|
total_tables_b: total_d,
|
|
128
124
|
backend: @backend,
|
|
129
|
-
**algorithm_options
|
|
125
|
+
**algorithm_options
|
|
130
126
|
)
|
|
131
127
|
|
|
132
128
|
algorithm.call(t_table, d_table)
|
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
module Markdown
|
|
4
4
|
module Merge
|
|
5
|
-
# Version
|
|
5
|
+
# Version namespace for this gem.
|
|
6
6
|
module Version
|
|
7
|
-
# Current version
|
|
8
|
-
VERSION =
|
|
7
|
+
# Current gem version.
|
|
8
|
+
VERSION = '7.1.1'
|
|
9
9
|
end
|
|
10
|
-
|
|
10
|
+
# Current gem version exposed at the traditional constant location.
|
|
11
|
+
VERSION = Version::VERSION # Traditional Constant Location
|
|
11
12
|
end
|
|
12
13
|
end
|
|
@@ -75,9 +75,7 @@ module Markdown
|
|
|
75
75
|
result = collapse_excessive_blank_lines(result)
|
|
76
76
|
|
|
77
77
|
# Remove blank lines between link refs if mode requires it
|
|
78
|
-
if @mode == :link_refs || @mode == :strict
|
|
79
|
-
result = remove_blank_lines_between_link_refs(result)
|
|
80
|
-
end
|
|
78
|
+
result = remove_blank_lines_between_link_refs(result) if @mode == :link_refs || @mode == :strict
|
|
81
79
|
|
|
82
80
|
result
|
|
83
81
|
end
|
|
@@ -107,9 +105,9 @@ module Markdown
|
|
|
107
105
|
when true
|
|
108
106
|
:basic
|
|
109
107
|
when false
|
|
110
|
-
:basic
|
|
108
|
+
:basic # Still do basic normalization
|
|
111
109
|
when Symbol
|
|
112
|
-
raise ArgumentError, "Unknown mode: #{mode}. Valid modes: #{MODES.join(
|
|
110
|
+
raise ArgumentError, "Unknown mode: #{mode}. Valid modes: #{MODES.join(', ')}" unless MODES.include?(mode)
|
|
113
111
|
|
|
114
112
|
mode
|
|
115
113
|
else
|
|
@@ -142,9 +140,7 @@ module Markdown
|
|
|
142
140
|
problem_start_line ||= line_number - 1
|
|
143
141
|
|
|
144
142
|
# Only add up to 1 blank line (which creates the standard paragraph gap)
|
|
145
|
-
if consecutive_blank_count <= 1
|
|
146
|
-
result << line
|
|
147
|
-
end
|
|
143
|
+
result << line if consecutive_blank_count <= 1
|
|
148
144
|
# Skip adding lines when consecutive_blank_count >= 2
|
|
149
145
|
else
|
|
150
146
|
# Record problem if we had 2+ blank lines (which means 3+ newlines)
|
|
@@ -155,7 +151,7 @@ module Markdown
|
|
|
155
151
|
severity: :warning,
|
|
156
152
|
line: problem_start_line,
|
|
157
153
|
newline_count: consecutive_blank_count + 1, # +1 because first line ends with \n too
|
|
158
|
-
collapsed_to: 2
|
|
154
|
+
collapsed_to: 2
|
|
159
155
|
)
|
|
160
156
|
end
|
|
161
157
|
|
|
@@ -172,7 +168,7 @@ module Markdown
|
|
|
172
168
|
severity: :warning,
|
|
173
169
|
line: problem_start_line,
|
|
174
170
|
newline_count: consecutive_blank_count + 1,
|
|
175
|
-
collapsed_to: 2
|
|
171
|
+
collapsed_to: 2
|
|
176
172
|
)
|
|
177
173
|
end
|
|
178
174
|
|
|
@@ -204,29 +200,25 @@ module Markdown
|
|
|
204
200
|
j = i + 1
|
|
205
201
|
while j < lines.length
|
|
206
202
|
next_line = lines[j]
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
end
|
|
227
|
-
else
|
|
228
|
-
break
|
|
229
|
-
end
|
|
203
|
+
break unless next_line.chomp.empty?
|
|
204
|
+
|
|
205
|
+
# Check if there's a link ref definition after the blank line(s)
|
|
206
|
+
k = j + 1
|
|
207
|
+
k += 1 while k < lines.length && lines[k].chomp.empty?
|
|
208
|
+
break unless k < lines.length && link_definition_line?(lines[k])
|
|
209
|
+
|
|
210
|
+
# Skip all blank lines between link refs
|
|
211
|
+
blanks_skipped = k - j
|
|
212
|
+
@problems.add(
|
|
213
|
+
:link_ref_spacing,
|
|
214
|
+
severity: :info,
|
|
215
|
+
line: j + 1,
|
|
216
|
+
blank_lines_removed: blanks_skipped
|
|
217
|
+
)
|
|
218
|
+
j = k
|
|
219
|
+
|
|
220
|
+
# Not followed by a link ref, keep the blank line
|
|
221
|
+
|
|
230
222
|
end
|
|
231
223
|
i = j
|
|
232
224
|
else
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Markdown
|
|
4
|
+
module Merge
|
|
5
|
+
# Shared bootstrap helpers for backend-specific Markdown wrapper gems.
|
|
6
|
+
module WrapperSupport
|
|
7
|
+
SHARED_REEXPORTS = {
|
|
8
|
+
FileAligner: Markdown::Merge::FileAligner,
|
|
9
|
+
ConflictResolver: Markdown::Merge::ConflictResolver,
|
|
10
|
+
MergeResult: Markdown::Merge::MergeResult,
|
|
11
|
+
TableMatchAlgorithm: Markdown::Merge::TableMatchAlgorithm,
|
|
12
|
+
TableMatchRefiner: Markdown::Merge::TableMatchRefiner,
|
|
13
|
+
CodeBlockMerger: Markdown::Merge::CodeBlockMerger,
|
|
14
|
+
NodeTypeNormalizer: Markdown::Merge::NodeTypeNormalizer
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
WRAPPER_AUTOLOADS = {
|
|
18
|
+
DebugLogger: 'debug_logger',
|
|
19
|
+
CommentTracker: 'comment_tracker',
|
|
20
|
+
FreezeNode: 'freeze_node',
|
|
21
|
+
FileAnalysis: 'file_analysis',
|
|
22
|
+
PartialTemplateMerger: 'partial_template_merger',
|
|
23
|
+
SmartMerger: 'smart_merger',
|
|
24
|
+
Backend: 'backend'
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
module_function
|
|
28
|
+
|
|
29
|
+
def install!(
|
|
30
|
+
wrapper_module:,
|
|
31
|
+
require_prefix:,
|
|
32
|
+
default_freeze_token:,
|
|
33
|
+
default_inner_merge_code_blocks:,
|
|
34
|
+
registry_tag:,
|
|
35
|
+
merger_class:,
|
|
36
|
+
test_source: "# Test\n\nParagraph",
|
|
37
|
+
category: :markdown
|
|
38
|
+
)
|
|
39
|
+
define_error_classes!(wrapper_module)
|
|
40
|
+
define_constant_unless_present(wrapper_module, :DEFAULT_FREEZE_TOKEN, default_freeze_token)
|
|
41
|
+
define_constant_unless_present(wrapper_module, :DEFAULT_INNER_MERGE_CODE_BLOCKS,
|
|
42
|
+
default_inner_merge_code_blocks)
|
|
43
|
+
|
|
44
|
+
SHARED_REEXPORTS.each do |name, value|
|
|
45
|
+
define_constant_unless_present(wrapper_module, name, value)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
WRAPPER_AUTOLOADS.each do |name, suffix|
|
|
49
|
+
next if wrapper_module.const_defined?(name, false) || wrapper_module.autoload?(name)
|
|
50
|
+
|
|
51
|
+
wrapper_module.send(:autoload, name, "#{require_prefix}/#{suffix}")
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
install_backend_loader!(wrapper_module)
|
|
55
|
+
register_merge_gem!(
|
|
56
|
+
registry_tag: registry_tag,
|
|
57
|
+
require_path: require_prefix,
|
|
58
|
+
merger_class: merger_class,
|
|
59
|
+
test_source: test_source,
|
|
60
|
+
category: category
|
|
61
|
+
)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def configure_debug_logger!(debug_logger_module:, env_var_name:, log_prefix:)
|
|
65
|
+
debug_logger_module.extend(Ast::Merge::DebugLogger)
|
|
66
|
+
debug_logger_module.env_var_name = env_var_name
|
|
67
|
+
debug_logger_module.log_prefix = log_prefix
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def configure_file_analysis_subclass!(klass, default_backend:, default_parser_options: nil)
|
|
71
|
+
install_singleton_value_method!(klass, :default_backend, default_backend)
|
|
72
|
+
return unless default_parser_options
|
|
73
|
+
|
|
74
|
+
install_singleton_value_method!(klass, :default_parser_options,
|
|
75
|
+
default_parser_options)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def configure_smart_merger_subclass!(
|
|
79
|
+
klass,
|
|
80
|
+
default_backend:,
|
|
81
|
+
default_freeze_token: nil,
|
|
82
|
+
default_inner_merge_code_blocks: nil,
|
|
83
|
+
default_parser_options: nil,
|
|
84
|
+
file_analysis_class: nil,
|
|
85
|
+
template_parse_error_class: nil,
|
|
86
|
+
destination_parse_error_class: nil
|
|
87
|
+
)
|
|
88
|
+
install_singleton_value_method!(klass, :default_backend, default_backend)
|
|
89
|
+
install_singleton_value_method!(klass, :default_freeze_token, default_freeze_token) if default_freeze_token
|
|
90
|
+
unless default_inner_merge_code_blocks.nil?
|
|
91
|
+
install_singleton_value_method!(klass, :default_inner_merge_code_blocks,
|
|
92
|
+
default_inner_merge_code_blocks)
|
|
93
|
+
end
|
|
94
|
+
if default_parser_options
|
|
95
|
+
install_singleton_value_method!(klass, :default_parser_options,
|
|
96
|
+
default_parser_options)
|
|
97
|
+
end
|
|
98
|
+
install_singleton_value_method!(klass, :file_analysis_class, file_analysis_class) if file_analysis_class
|
|
99
|
+
if template_parse_error_class
|
|
100
|
+
install_singleton_value_method!(klass, :template_parse_error_class,
|
|
101
|
+
template_parse_error_class)
|
|
102
|
+
end
|
|
103
|
+
return unless destination_parse_error_class
|
|
104
|
+
|
|
105
|
+
install_singleton_value_method!(klass, :destination_parse_error_class,
|
|
106
|
+
destination_parse_error_class)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def configure_partial_template_merger_subclass!(klass, default_backend:, file_analysis_class:,
|
|
110
|
+
smart_merger_class:)
|
|
111
|
+
install_singleton_value_method!(klass, :default_backend, default_backend)
|
|
112
|
+
install_singleton_value_method!(klass, :file_analysis_class, file_analysis_class)
|
|
113
|
+
install_singleton_value_method!(klass, :smart_merger_class, smart_merger_class)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def install_backend_loader!(wrapper_module)
|
|
117
|
+
return if wrapper_module.respond_to?(:ensure_backend_loaded!)
|
|
118
|
+
|
|
119
|
+
wrapper_module.singleton_class.class_eval do
|
|
120
|
+
define_method(:ensure_backend_loaded!) do
|
|
121
|
+
const_get(:Backend)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
private_class_method :install_backend_loader!
|
|
126
|
+
|
|
127
|
+
def define_error_classes!(wrapper_module)
|
|
128
|
+
define_constant_unless_present(wrapper_module, :Error, Class.new(Markdown::Merge::Error))
|
|
129
|
+
define_constant_unless_present(wrapper_module, :ParseError, Class.new(Markdown::Merge::ParseError))
|
|
130
|
+
define_constant_unless_present(
|
|
131
|
+
wrapper_module,
|
|
132
|
+
:TemplateParseError,
|
|
133
|
+
Class.new(wrapper_module.const_get(:ParseError))
|
|
134
|
+
)
|
|
135
|
+
define_constant_unless_present(
|
|
136
|
+
wrapper_module,
|
|
137
|
+
:DestinationParseError,
|
|
138
|
+
Class.new(wrapper_module.const_get(:ParseError))
|
|
139
|
+
)
|
|
140
|
+
end
|
|
141
|
+
private_class_method :define_error_classes!
|
|
142
|
+
|
|
143
|
+
def install_singleton_value_method!(klass, method_name, value)
|
|
144
|
+
klass.singleton_class.class_eval do
|
|
145
|
+
define_method(method_name) do
|
|
146
|
+
WrapperSupport.send(:resolve_config_value, value, context: self)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
private_class_method :install_singleton_value_method!
|
|
151
|
+
|
|
152
|
+
def resolve_config_value(value, context:)
|
|
153
|
+
return context.instance_exec(&value) if value.respond_to?(:call)
|
|
154
|
+
|
|
155
|
+
duplicate_config_value(value)
|
|
156
|
+
end
|
|
157
|
+
private_class_method :resolve_config_value
|
|
158
|
+
|
|
159
|
+
def duplicate_config_value(value)
|
|
160
|
+
case value
|
|
161
|
+
when Hash
|
|
162
|
+
value.each_with_object({}) do |(key, nested_value), result|
|
|
163
|
+
result[key] = duplicate_config_value(nested_value)
|
|
164
|
+
end
|
|
165
|
+
when Array
|
|
166
|
+
value.map { |nested_value| duplicate_config_value(nested_value) }
|
|
167
|
+
else
|
|
168
|
+
value
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
private_class_method :duplicate_config_value
|
|
172
|
+
|
|
173
|
+
def register_merge_gem!(registry_tag:, require_path:, merger_class:, test_source:, category:)
|
|
174
|
+
return unless defined?(Ast::Merge::RSpec::MergeGemRegistry)
|
|
175
|
+
|
|
176
|
+
Ast::Merge::RSpec::MergeGemRegistry.register(
|
|
177
|
+
registry_tag,
|
|
178
|
+
require_path: require_path,
|
|
179
|
+
merger_class: merger_class,
|
|
180
|
+
test_source: test_source,
|
|
181
|
+
category: category
|
|
182
|
+
)
|
|
183
|
+
end
|
|
184
|
+
private_class_method :register_merge_gem!
|
|
185
|
+
|
|
186
|
+
def define_constant_unless_present(wrapper_module, name, value)
|
|
187
|
+
return if wrapper_module.const_defined?(name, false)
|
|
188
|
+
|
|
189
|
+
wrapper_module.const_set(name, value)
|
|
190
|
+
end
|
|
191
|
+
private_class_method :define_constant_unless_present
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|