canon 0.2.8 → 0.2.9
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
- data/.rspec-opal +7 -0
- data/.rubocop_todo.yml +14 -71
- data/Rakefile +17 -0
- data/lib/canon/cli.rb +1 -1
- data/lib/canon/color_detector.rb +3 -5
- data/lib/canon/comparison/compare_profile.rb +1 -4
- data/lib/canon/comparison/dimensions/attribute_order_dimension.rb +2 -6
- data/lib/canon/comparison/dimensions/attribute_presence_dimension.rb +2 -6
- data/lib/canon/comparison/dimensions/attribute_values_dimension.rb +2 -6
- data/lib/canon/comparison/dimensions/comments_dimension.rb +2 -6
- data/lib/canon/comparison/dimensions/element_position_dimension.rb +2 -6
- data/lib/canon/comparison/dimensions/structural_whitespace_dimension.rb +2 -6
- data/lib/canon/comparison/dimensions/text_content_dimension.rb +3 -5
- data/lib/canon/comparison/format_detector.rb +29 -20
- data/lib/canon/comparison/html_comparator.rb +18 -29
- data/lib/canon/comparison/html_compare_profile.rb +3 -10
- data/lib/canon/comparison/html_parser.rb +1 -1
- data/lib/canon/comparison/json_comparator.rb +8 -0
- data/lib/canon/comparison/node_inspector.rb +146 -80
- data/lib/canon/comparison/strategies/semantic_tree_match_strategy.rb +6 -8
- data/lib/canon/comparison/whitespace_sensitivity.rb +55 -193
- data/lib/canon/comparison/xml_comparator/attribute_filter.rb +5 -10
- data/lib/canon/comparison/xml_comparator/child_comparison.rb +4 -4
- data/lib/canon/comparison/xml_comparator/diff_node_builder.rb +10 -8
- data/lib/canon/comparison/xml_comparator/namespace_comparator.rb +14 -28
- data/lib/canon/comparison/xml_comparator/node_parser.rb +12 -11
- data/lib/canon/comparison/xml_comparator/node_type_comparator.rb +30 -58
- data/lib/canon/comparison/xml_comparator.rb +61 -83
- data/lib/canon/comparison/xml_node_comparison.rb +15 -15
- data/lib/canon/comparison/yaml_comparator.rb +8 -0
- data/lib/canon/comparison.rb +23 -23
- data/lib/canon/config/profile_loader.rb +13 -13
- data/lib/canon/config.rb +29 -5
- data/lib/canon/diff/diff_classifier.rb +7 -41
- data/lib/canon/diff/diff_line.rb +1 -1
- data/lib/canon/diff/diff_node_enricher.rb +22 -24
- data/lib/canon/diff/node_serializer.rb +23 -30
- data/lib/canon/diff/path_builder.rb +24 -37
- data/lib/canon/diff/source_locator.rb +0 -3
- data/lib/canon/diff/xml_serialization_formatter.rb +8 -81
- data/lib/canon/diff_formatter/by_line/base_formatter.rb +7 -7
- data/lib/canon/diff_formatter/by_line/json_formatter.rb +1 -1
- data/lib/canon/diff_formatter/by_line/simple_formatter.rb +1 -1
- data/lib/canon/diff_formatter/by_line/xml_formatter.rb +2 -2
- data/lib/canon/diff_formatter/by_line/yaml_formatter.rb +1 -1
- data/lib/canon/diff_formatter/by_line_formatter.rb +1 -1
- data/lib/canon/diff_formatter/by_object/base_formatter.rb +11 -15
- data/lib/canon/diff_formatter/by_object/xml_formatter.rb +8 -10
- data/lib/canon/diff_formatter/by_object_formatter.rb +1 -1
- data/lib/canon/diff_formatter/debug_output.rb +12 -24
- data/lib/canon/diff_formatter/diff_detail_formatter/color_helper.rb +2 -2
- data/lib/canon/diff_formatter/diff_detail_formatter/node_utils.rb +146 -318
- data/lib/canon/diff_formatter/diff_detail_formatter.rb +28 -20
- data/lib/canon/diff_formatter/legend.rb +2 -2
- data/lib/canon/diff_formatter/pretty_diff_formatter.rb +2 -2
- data/lib/canon/diff_formatter/theme.rb +4 -4
- data/lib/canon/diff_formatter.rb +2 -2
- data/lib/canon/formatters/html_formatter.rb +1 -1
- data/lib/canon/formatters/html_formatter_base.rb +1 -1
- data/lib/canon/formatters/xml_formatter.rb +7 -32
- data/lib/canon/html/data_model.rb +1 -1
- data/lib/canon/pretty_printer/html.rb +1 -1
- data/lib/canon/pretty_printer/xml.rb +16 -7
- data/lib/canon/pretty_printer/xml_normalized.rb +9 -3
- data/lib/canon/rspec_matchers.rb +2 -2
- data/lib/canon/tree_diff/adapters/html_adapter.rb +1 -1
- data/lib/canon/tree_diff/adapters/xml_adapter.rb +1 -1
- data/lib/canon/tree_diff/core/tree_node.rb +1 -3
- data/lib/canon/validators/html_validator.rb +1 -1
- data/lib/canon/validators/xml_validator.rb +1 -1
- data/lib/canon/version.rb +1 -1
- data/lib/canon/xml/data_model.rb +131 -137
- data/lib/canon/xml/namespace_helper.rb +5 -0
- data/lib/canon/xml/node.rb +2 -1
- data/lib/canon/xml/nodes/root_node.rb +4 -0
- data/lib/canon/xml/nodes/text_node.rb +6 -1
- data/lib/canon/xml/sax_builder.rb +4 -6
- data/lib/canon/xml_backend.rb +49 -0
- data/lib/canon/xml_parsing.rb +271 -0
- data/lib/canon.rb +3 -1
- data/lib/tasks/benchmark_runner.rb +1 -1
- data/lib/tasks/performance_helpers.rb +1 -1
- metadata +5 -2
|
@@ -4,59 +4,25 @@ module Canon
|
|
|
4
4
|
module Diff
|
|
5
5
|
# Detects and classifies XML serialization-level formatting differences.
|
|
6
6
|
#
|
|
7
|
-
# Serialization
|
|
8
|
-
#
|
|
9
|
-
# arise from different valid ways to serialize the same semantic content.
|
|
10
|
-
#
|
|
11
|
-
# These differences are ALWAYS non-normative (formatting-only) regardless
|
|
12
|
-
# of match options, because they are purely syntactic variations.
|
|
13
|
-
#
|
|
14
|
-
# Examples:
|
|
15
|
-
# - Self-closing vs explicit closing tags: <tag/> vs <tag></tag>
|
|
16
|
-
# - Attribute quote style: attr="value" vs attr='value' (parser-normalized)
|
|
17
|
-
# - Whitespace within tags: <tag a="1" b="2"> vs <tag a="1" b="2"> (parser-normalized)
|
|
18
|
-
#
|
|
19
|
-
# Note: Some serialization differences are normalized away by XML parsers
|
|
20
|
-
# (attribute quotes, tag spacing). This class focuses on differences that
|
|
21
|
-
# survive parsing and comparison, such as self-closing vs explicit closing.
|
|
7
|
+
# Serialization formatting differences are ALWAYS non-normative (formatting-only)
|
|
8
|
+
# regardless of match options, because they are purely syntactic variations.
|
|
22
9
|
class XmlSerializationFormatter
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
# Serialization formatting differences are ALWAYS non-normative because they
|
|
26
|
-
# represent different valid serializations of the same semantic content.
|
|
27
|
-
#
|
|
28
|
-
# @param diff_node [DiffNode] The diff node to check
|
|
29
|
-
# @return [Boolean] true if this is a serialization formatting difference
|
|
10
|
+
NI = Canon::Comparison::NodeInspector
|
|
11
|
+
|
|
30
12
|
def self.serialization_formatting?(diff_node)
|
|
31
|
-
# Currently only handles text_content dimension
|
|
32
|
-
# Future: add detection for other dimensions
|
|
33
13
|
return false unless diff_node.dimension == :text_content
|
|
34
14
|
|
|
35
15
|
empty_text_content_serialization_diff?(diff_node)
|
|
36
16
|
end
|
|
37
17
|
|
|
38
|
-
# Check if a text_content difference is from XML serialization format.
|
|
39
|
-
#
|
|
40
|
-
# Specifically detects self-closing tags (<tag/>) vs explicit closing tags
|
|
41
|
-
# (<tag></tag>), which create different text node structures:
|
|
42
|
-
# - Self-closing: no text node (nil)
|
|
43
|
-
# - Explicit closing: empty or whitespace-only text node ("", " ", "\n", etc.)
|
|
44
|
-
#
|
|
45
|
-
# Per XML standards, these forms are semantically equivalent.
|
|
46
|
-
#
|
|
47
|
-
# @param diff_node [DiffNode] The diff node to check
|
|
48
|
-
# @return [Boolean] true if this is a serialization formatting difference
|
|
49
18
|
def self.empty_text_content_serialization_diff?(diff_node)
|
|
50
19
|
return false unless diff_node.dimension == :text_content
|
|
51
20
|
|
|
52
21
|
node1 = diff_node.node1
|
|
53
22
|
node2 = diff_node.node2
|
|
54
23
|
|
|
55
|
-
# Both nodes are nil - no actual difference, not a serialization formatting diff
|
|
56
24
|
return false if node1.nil? && node2.nil?
|
|
57
25
|
|
|
58
|
-
# Only one is nil (e.g., one doc has self-closing, other has text)
|
|
59
|
-
# If the non-nil one is blank, it's still serialization formatting
|
|
60
26
|
if node1.nil? || node2.nil?
|
|
61
27
|
non_nil = node1 || node2
|
|
62
28
|
return false unless text_node?(non_nil)
|
|
@@ -65,68 +31,29 @@ module Canon
|
|
|
65
31
|
return blank?(text)
|
|
66
32
|
end
|
|
67
33
|
|
|
68
|
-
# Both must be text nodes
|
|
69
34
|
return false unless text_node?(node1) && text_node?(node2)
|
|
70
35
|
|
|
71
36
|
text1 = extract_text_content(node1)
|
|
72
37
|
text2 = extract_text_content(node2)
|
|
73
38
|
|
|
74
|
-
# Check if both texts are blank/whitespace-only
|
|
75
|
-
# This indicates self-closing vs explicit closing tag syntax
|
|
76
39
|
blank?(text1) && blank?(text2)
|
|
77
40
|
end
|
|
78
41
|
|
|
79
|
-
# Check if a value is blank (nil or whitespace-only)
|
|
80
|
-
# @param value [String, nil] Value to check
|
|
81
|
-
# @return [Boolean] true if blank
|
|
82
42
|
def self.blank?(value)
|
|
83
|
-
value.nil? ||
|
|
84
|
-
(value.respond_to?(:empty?) && value.empty?) ||
|
|
85
|
-
(value.respond_to?(:strip) && value.strip.empty?)
|
|
43
|
+
value.nil? || value.to_s.strip.empty?
|
|
86
44
|
end
|
|
87
45
|
|
|
88
|
-
# Check if a node is a text node
|
|
89
|
-
# @param node [Object] The node to check
|
|
90
|
-
# @return [Boolean] true if the node is a text node
|
|
91
46
|
def self.text_node?(node)
|
|
92
47
|
return false if node.nil?
|
|
48
|
+
return true if node.is_a?(String)
|
|
93
49
|
|
|
94
|
-
|
|
95
|
-
when Canon::Xml::Nodes::TextNode
|
|
96
|
-
true
|
|
97
|
-
when Canon::Xml::Node
|
|
98
|
-
node.node_type == :text
|
|
99
|
-
when Nokogiri::XML::Node
|
|
100
|
-
node.node_type == Nokogiri::XML::Node::TEXT_NODE
|
|
101
|
-
when Moxml::Node
|
|
102
|
-
node.text?
|
|
103
|
-
when String
|
|
104
|
-
true
|
|
105
|
-
else
|
|
106
|
-
false
|
|
107
|
-
end
|
|
50
|
+
NI.text_node?(node)
|
|
108
51
|
end
|
|
109
52
|
|
|
110
|
-
# Extract text content from a node
|
|
111
|
-
# @param node [Object] The node to extract text from
|
|
112
|
-
# @return [String, nil] The text content or nil
|
|
113
53
|
def self.extract_text_content(node)
|
|
114
54
|
return nil if node.nil?
|
|
115
55
|
|
|
116
|
-
|
|
117
|
-
when Canon::Xml::Nodes::TextNode
|
|
118
|
-
node.value
|
|
119
|
-
when Canon::Xml::Node
|
|
120
|
-
node.text_content
|
|
121
|
-
when Nokogiri::XML::Node
|
|
122
|
-
node.content.to_s
|
|
123
|
-
when Moxml::Node
|
|
124
|
-
node.content.to_s
|
|
125
|
-
when String
|
|
126
|
-
node
|
|
127
|
-
else
|
|
128
|
-
node.to_s
|
|
129
|
-
end
|
|
56
|
+
NI.text_content(node)
|
|
130
57
|
rescue StandardError
|
|
131
58
|
nil
|
|
132
59
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "diff/lcs"
|
|
4
|
-
require "diff/lcs/hunk"
|
|
3
|
+
require "diff/lcs" unless RUBY_ENGINE == "opal"
|
|
4
|
+
require "diff/lcs/hunk" unless RUBY_ENGINE == "opal"
|
|
5
5
|
require_relative "../debug_output"
|
|
6
6
|
require_relative "../theme"
|
|
7
7
|
|
|
@@ -233,7 +233,7 @@ module Canon
|
|
|
233
233
|
# @return [Rainbow::Presenter] Colorized presenter
|
|
234
234
|
def apply_color(presenter, color)
|
|
235
235
|
valid_colors = normalize_color_for_rainbow(color)
|
|
236
|
-
valid_colors.each { |c| presenter = presenter.
|
|
236
|
+
valid_colors.each { |c| presenter = presenter.public_send(c) }
|
|
237
237
|
presenter
|
|
238
238
|
end
|
|
239
239
|
|
|
@@ -385,7 +385,7 @@ module Canon
|
|
|
385
385
|
rainbow = Rainbow.new
|
|
386
386
|
rainbow.enabled = true
|
|
387
387
|
presenter = rainbow.wrap(text)
|
|
388
|
-
valid_colors.each { |c| presenter = presenter.
|
|
388
|
+
valid_colors.each { |c| presenter = presenter.public_send(c) }
|
|
389
389
|
presenter.to_s
|
|
390
390
|
end
|
|
391
391
|
|
|
@@ -675,13 +675,13 @@ module Canon
|
|
|
675
675
|
# Handle Rainbow color methods - :bright_blue -> .blue.bright, etc.
|
|
676
676
|
if color.to_s.start_with?("bright_")
|
|
677
677
|
base_color = color.to_s.sub(/^bright_/, "").to_sym
|
|
678
|
-
presenter = presenter.
|
|
678
|
+
presenter = presenter.public_send(base_color).bright
|
|
679
679
|
elsif color.to_s.start_with?("light_")
|
|
680
680
|
# Rainbow doesn't have light_ versions, treat as white on bg
|
|
681
681
|
base_color = color.to_s.sub(/^light_/, "").to_sym
|
|
682
|
-
presenter = presenter.
|
|
682
|
+
presenter = presenter.public_send(base_color)
|
|
683
683
|
else
|
|
684
|
-
presenter = presenter.
|
|
684
|
+
presenter = presenter.public_send(color)
|
|
685
685
|
end
|
|
686
686
|
|
|
687
687
|
presenter.to_s
|
|
@@ -1205,11 +1205,11 @@ informative: false, formatting: false)
|
|
|
1205
1205
|
# Apply effect if specified (map :strikethrough to :cross_out for Rainbow)
|
|
1206
1206
|
if effect
|
|
1207
1207
|
rainbow_effect = effect == :strikethrough ? :cross_out : effect
|
|
1208
|
-
presenter = presenter.
|
|
1208
|
+
presenter = presenter.public_send(rainbow_effect)
|
|
1209
1209
|
end
|
|
1210
1210
|
|
|
1211
1211
|
# Apply color if specified
|
|
1212
|
-
presenter = presenter.
|
|
1212
|
+
presenter = presenter.public_send(color) if color
|
|
1213
1213
|
|
|
1214
1214
|
presenter.to_s
|
|
1215
1215
|
else
|
|
@@ -26,7 +26,7 @@ show_diffs: :all, theme: nil)
|
|
|
26
26
|
# @return [String] Formatted output
|
|
27
27
|
def format(differences, _format)
|
|
28
28
|
# Handle both ComparisonResult (production) and Array (low-level tests)
|
|
29
|
-
if differences.
|
|
29
|
+
if differences.is_a?(Canon::Comparison::ComparisonResult)
|
|
30
30
|
# ComparisonResult object
|
|
31
31
|
return success_message if differences.equivalent?
|
|
32
32
|
|
|
@@ -130,15 +130,11 @@ show_diffs: :all, theme: nil)
|
|
|
130
130
|
return differences if @show_diffs.nil? || @show_diffs == :all
|
|
131
131
|
|
|
132
132
|
differences.select do |diff|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
else
|
|
139
|
-
# Default to normative if unknown
|
|
140
|
-
true
|
|
141
|
-
end
|
|
133
|
+
is_normative = begin
|
|
134
|
+
diff.normative?
|
|
135
|
+
rescue NoMethodError
|
|
136
|
+
diff.is_a?(Hash) && diff.key?(:normative) ? diff[:normative] : true
|
|
137
|
+
end
|
|
142
138
|
|
|
143
139
|
case @show_diffs
|
|
144
140
|
when :normative
|
|
@@ -207,9 +203,9 @@ show_diffs: :all, theme: nil)
|
|
|
207
203
|
parts = []
|
|
208
204
|
current = node
|
|
209
205
|
|
|
210
|
-
while current.
|
|
206
|
+
while Canon::XmlParsing.xml_node?(current) || current.is_a?(Canon::Xml::Node)
|
|
211
207
|
parts.unshift(current.name) if current.name
|
|
212
|
-
current = current.parent
|
|
208
|
+
current = current.parent
|
|
213
209
|
end
|
|
214
210
|
|
|
215
211
|
parts.join(".")
|
|
@@ -328,13 +324,13 @@ show_diffs: :all, theme: nil)
|
|
|
328
324
|
# Handle bright_ colors: :bright_blue -> .blue.bright
|
|
329
325
|
if c.to_s.start_with?("bright_")
|
|
330
326
|
base = c.to_s.sub(/^bright_/, "").to_sym
|
|
331
|
-
presenter = presenter.
|
|
327
|
+
presenter = presenter.public_send(base).bright
|
|
332
328
|
elsif c.to_s.start_with?("light_")
|
|
333
329
|
# Rainbow doesn't have light_ versions
|
|
334
330
|
base = c.to_s.sub(/^light_/, "").to_sym
|
|
335
|
-
presenter = presenter.
|
|
331
|
+
presenter = presenter.public_send(base)
|
|
336
332
|
else
|
|
337
|
-
presenter = presenter.
|
|
333
|
+
presenter = presenter.public_send(c)
|
|
338
334
|
end
|
|
339
335
|
end
|
|
340
336
|
presenter.to_s
|
|
@@ -171,7 +171,8 @@ module Canon
|
|
|
171
171
|
text2 = extract_text(node2)
|
|
172
172
|
|
|
173
173
|
# Show parent element if available
|
|
174
|
-
if
|
|
174
|
+
if (Canon::XmlParsing.xml_node?(node1) || node1.is_a?(Canon::Xml::Node)) &&
|
|
175
|
+
node1.parent
|
|
175
176
|
output << "#{prefix} #{colorize(
|
|
176
177
|
"Element: <#{node1.parent.name}>",
|
|
177
178
|
theme_color(:informative, :content) || :blue,
|
|
@@ -274,9 +275,9 @@ module Canon
|
|
|
274
275
|
parts = []
|
|
275
276
|
current = node
|
|
276
277
|
|
|
277
|
-
while current.
|
|
278
|
+
while Canon::XmlParsing.xml_node?(current) || current.is_a?(Canon::Xml::Node)
|
|
278
279
|
parts.unshift(current.name) if current.name
|
|
279
|
-
current = current.parent
|
|
280
|
+
current = current.parent
|
|
280
281
|
end
|
|
281
282
|
|
|
282
283
|
parts.join(".")
|
|
@@ -287,13 +288,10 @@ module Canon
|
|
|
287
288
|
# @param node [Object] Node with content or text
|
|
288
289
|
# @return [String] Text content
|
|
289
290
|
def extract_text(node)
|
|
290
|
-
if node.
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
node.content.to_s
|
|
295
|
-
elsif node.respond_to?(:text)
|
|
296
|
-
node.text.to_s
|
|
291
|
+
if node.is_a?(Canon::Xml::Node)
|
|
292
|
+
node.text_content.to_s
|
|
293
|
+
elsif Canon::XmlParsing.xml_node?(node)
|
|
294
|
+
Canon::XmlParsing.text_content(node).to_s
|
|
297
295
|
else
|
|
298
296
|
""
|
|
299
297
|
end
|
|
@@ -283,22 +283,8 @@ module Canon
|
|
|
283
283
|
content = node.value.to_s
|
|
284
284
|
preview = content.length > 30 ? "#{content[0..27]}..." : content
|
|
285
285
|
"<!--#{preview}-->"
|
|
286
|
-
elsif node.
|
|
286
|
+
elsif Canon::XmlParsing.xml_node?(node) || node.is_a?(Canon::Xml::Node)
|
|
287
287
|
"<#{node.name}>"
|
|
288
|
-
elsif node.respond_to?(:content)
|
|
289
|
-
content = node.content.to_s
|
|
290
|
-
if content.length > 30
|
|
291
|
-
"\"#{content[0..27]}...\""
|
|
292
|
-
else
|
|
293
|
-
"\"#{content || ''}\""
|
|
294
|
-
end
|
|
295
|
-
elsif node.respond_to?(:text)
|
|
296
|
-
text = node.text.to_s
|
|
297
|
-
if text.length > 30
|
|
298
|
-
"\"#{text[0..27]}...\""
|
|
299
|
-
else
|
|
300
|
-
"\"#{text || ''}\""
|
|
301
|
-
end
|
|
302
288
|
else
|
|
303
289
|
node.class.name
|
|
304
290
|
end
|
|
@@ -311,14 +297,16 @@ module Canon
|
|
|
311
297
|
|
|
312
298
|
# For attribute differences, show which attributes differ
|
|
313
299
|
if diff.dimension == :attribute_whitespace &&
|
|
314
|
-
|
|
300
|
+
(Canon::XmlParsing.xml_node?(node1) || node1.is_a?(Canon::Xml::Node)) &&
|
|
301
|
+
(Canon::XmlParsing.xml_node?(node2) || node2.is_a?(Canon::Xml::Node))
|
|
315
302
|
attrs1 = format_attributes(node1)
|
|
316
303
|
attrs2 = format_attributes(node2)
|
|
317
304
|
return ["<#{node1.name}> #{attrs1}", "<#{node2.name}> #{attrs2}"]
|
|
318
305
|
end
|
|
319
306
|
|
|
320
307
|
# For element differences, show element names
|
|
321
|
-
if
|
|
308
|
+
if (Canon::XmlParsing.xml_node?(node1) || node1.is_a?(Canon::Xml::Node)) &&
|
|
309
|
+
(Canon::XmlParsing.xml_node?(node2) || node2.is_a?(Canon::Xml::Node))
|
|
322
310
|
if node1.name == node2.name
|
|
323
311
|
# Same element name, different content
|
|
324
312
|
end
|
|
@@ -340,7 +328,7 @@ module Canon
|
|
|
340
328
|
end
|
|
341
329
|
|
|
342
330
|
def format_attributes(node)
|
|
343
|
-
return "" unless node.
|
|
331
|
+
return "" unless Canon::XmlParsing.xml_node?(node) || node.is_a?(Canon::Xml::Node)
|
|
344
332
|
|
|
345
333
|
attrs = node.attributes
|
|
346
334
|
return "" if attrs.empty?
|
|
@@ -350,9 +338,9 @@ module Canon
|
|
|
350
338
|
name = if key.is_a?(String)
|
|
351
339
|
key
|
|
352
340
|
else
|
|
353
|
-
|
|
341
|
+
key.name
|
|
354
342
|
end
|
|
355
|
-
value = val.
|
|
343
|
+
value = val.is_a?(String) ? val : val.value
|
|
356
344
|
"#{name}=\"#{value}\""
|
|
357
345
|
end.sort
|
|
358
346
|
|
|
@@ -365,10 +353,10 @@ module Canon
|
|
|
365
353
|
end
|
|
366
354
|
|
|
367
355
|
def get_node_content(node)
|
|
368
|
-
if
|
|
369
|
-
node.
|
|
370
|
-
elsif node.
|
|
371
|
-
node.
|
|
356
|
+
if Canon::XmlParsing.xml_node?(node)
|
|
357
|
+
Canon::XmlParsing.text_content(node).to_s
|
|
358
|
+
elsif node.is_a?(Canon::Xml::Node)
|
|
359
|
+
node.text_content.to_s
|
|
372
360
|
else
|
|
373
361
|
""
|
|
374
362
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "rainbow"
|
|
3
|
+
require "rainbow" unless RUBY_ENGINE == "opal"
|
|
4
4
|
|
|
5
5
|
module Canon
|
|
6
6
|
class DiffFormatter
|
|
@@ -19,7 +19,7 @@ module Canon
|
|
|
19
19
|
def self.colorize(text, color, use_color, bold: false)
|
|
20
20
|
return text unless use_color
|
|
21
21
|
|
|
22
|
-
presenter = Rainbow(text).
|
|
22
|
+
presenter = Rainbow(text).public_send(color)
|
|
23
23
|
presenter = presenter.bright if bold
|
|
24
24
|
presenter.to_s
|
|
25
25
|
end
|