canon 0.2.9 → 0.2.12
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/.rubocop_todo.yml +21 -22
- data/Rakefile +25 -2
- data/lib/canon/cache.rb +18 -27
- data/lib/canon/cli.rb +0 -3
- data/lib/canon/commands/diff_command.rb +0 -6
- data/lib/canon/commands/format_command.rb +0 -4
- data/lib/canon/commands.rb +9 -0
- data/lib/canon/comparison/child_realignment.rb +0 -2
- data/lib/canon/comparison/compare_profile.rb +30 -36
- data/lib/canon/comparison/comparison_result.rb +0 -2
- data/lib/canon/comparison/diff_node_builder.rb +353 -0
- data/lib/canon/comparison/dimensions/dimension.rb +51 -0
- data/lib/canon/comparison/dimensions/dimension_set.rb +49 -0
- data/lib/canon/comparison/dimensions/registry.rb +101 -60
- data/lib/canon/comparison/dimensions.rb +15 -46
- data/lib/canon/comparison/html_comparator.rb +20 -141
- data/lib/canon/comparison/html_compare_profile.rb +15 -18
- data/lib/canon/comparison/json_comparator.rb +4 -165
- data/lib/canon/comparison/json_parser.rb +0 -2
- data/lib/canon/comparison/markup_comparator.rb +14 -210
- data/lib/canon/comparison/match_options/base_resolver.rb +18 -29
- data/lib/canon/comparison/match_options/json_resolver.rb +4 -28
- data/lib/canon/comparison/match_options/xml_resolver.rb +4 -45
- data/lib/canon/comparison/match_options/yaml_resolver.rb +4 -30
- data/lib/canon/comparison/match_options.rb +13 -88
- data/lib/canon/comparison/node_inspector.rb +13 -48
- data/lib/canon/comparison/pipeline.rb +269 -0
- data/lib/canon/comparison/profile_definition.rb +0 -2
- data/lib/canon/comparison/ruby_object_comparator.rb +1 -1
- data/lib/canon/comparison/strategies/match_strategy_factory.rb +9 -58
- data/lib/canon/comparison/strategies/semantic_tree_match_strategy.rb +4 -11
- data/lib/canon/comparison/strategies.rb +16 -0
- data/lib/canon/comparison/xml_comparator/attribute_comparator.rb +19 -5
- data/lib/canon/comparison/xml_comparator/attribute_filter.rb +0 -3
- data/lib/canon/comparison/xml_comparator/child_comparison.rb +0 -6
- data/lib/canon/comparison/xml_comparator/namespace_comparator.rb +1 -6
- data/lib/canon/comparison/xml_comparator/node_parser.rb +2 -6
- data/lib/canon/comparison/xml_comparator.rb +4 -492
- data/lib/canon/comparison/xml_comparator_helpers.rb +21 -0
- data/lib/canon/comparison/xml_node_comparison.rb +4 -119
- data/lib/canon/comparison/yaml_comparator.rb +0 -3
- data/lib/canon/comparison.rb +144 -267
- data/lib/canon/config/config_dsl.rb +159 -0
- data/lib/canon/config/env_provider.rb +0 -3
- data/lib/canon/config/env_schema.rb +48 -58
- data/lib/canon/config/profile_loader.rb +0 -1
- data/lib/canon/config.rb +116 -468
- data/lib/canon/diff/diff_block_builder.rb +0 -2
- data/lib/canon/diff/diff_classifier.rb +0 -5
- data/lib/canon/diff/diff_context.rb +0 -2
- data/lib/canon/diff/diff_context_builder.rb +0 -2
- data/lib/canon/diff/diff_line_builder.rb +2 -3
- data/lib/canon/diff/diff_node_enricher.rb +0 -4
- data/lib/canon/diff/diff_node_mapper.rb +10 -12
- data/lib/canon/diff/diff_report_builder.rb +0 -4
- data/lib/canon/diff/formatting_detector.rb +3 -3
- data/lib/canon/diff/node_serializer.rb +0 -7
- data/lib/canon/diff/xml_serialization_formatter.rb +0 -3
- data/lib/canon/diff.rb +39 -0
- data/lib/canon/diff_formatter/by_line/base_formatter.rb +4 -17
- data/lib/canon/diff_formatter/by_line/html_formatter.rb +7 -19
- data/lib/canon/diff_formatter/by_line/json_formatter.rb +0 -3
- data/lib/canon/diff_formatter/by_line/simple_formatter.rb +0 -3
- data/lib/canon/diff_formatter/by_line/xml_formatter.rb +7 -26
- data/lib/canon/diff_formatter/by_line/yaml_formatter.rb +0 -3
- data/lib/canon/diff_formatter/by_object/base_formatter.rb +20 -17
- data/lib/canon/diff_formatter/by_object/json_formatter.rb +0 -2
- data/lib/canon/diff_formatter/by_object/xml_formatter.rb +119 -3
- data/lib/canon/diff_formatter/by_object/yaml_formatter.rb +0 -2
- data/lib/canon/diff_formatter/by_object_formatter.rb +1 -5
- data/lib/canon/diff_formatter/debug_output.rb +0 -2
- data/lib/canon/diff_formatter/diff_detail_formatter/dimension_formatter.rb +27 -61
- data/lib/canon/diff_formatter/diff_detail_formatter/location_extractor.rb +26 -29
- data/lib/canon/diff_formatter/diff_detail_formatter/node_utils.rb +1 -2
- data/lib/canon/diff_formatter/diff_detail_formatter/text_utils.rb +1 -7
- data/lib/canon/diff_formatter/diff_detail_formatter.rb +0 -7
- data/lib/canon/diff_formatter/diff_detail_formatter_helpers.rb +23 -0
- data/lib/canon/diff_formatter.rb +26 -20
- data/lib/canon/formatters/html4_formatter.rb +0 -2
- data/lib/canon/formatters/html5_formatter.rb +0 -2
- data/lib/canon/formatters/html_formatter.rb +0 -3
- data/lib/canon/formatters/json_formatter.rb +0 -1
- data/lib/canon/formatters/xml_formatter.rb +0 -4
- data/lib/canon/formatters/yaml_formatter.rb +0 -1
- data/lib/canon/formatters.rb +16 -0
- data/lib/canon/html/data_model.rb +1 -11
- data/lib/canon/html.rb +4 -3
- data/lib/canon/options/cli_generator.rb +0 -2
- data/lib/canon/options/registry.rb +0 -2
- data/lib/canon/options.rb +9 -0
- data/lib/canon/pretty_printer/html.rb +0 -1
- data/lib/canon/pretty_printer/xml_normalized.rb +0 -2
- data/lib/canon/pretty_printer.rb +12 -0
- data/lib/canon/tree_diff/adapters/html_adapter.rb +1 -1
- data/lib/canon/tree_diff/adapters.rb +14 -0
- data/lib/canon/tree_diff/core/attribute_comparator.rb +0 -6
- data/lib/canon/tree_diff/core/node_signature.rb +1 -1
- data/lib/canon/tree_diff/core/tree_node.rb +12 -5
- data/lib/canon/tree_diff/core.rb +17 -0
- data/lib/canon/tree_diff/matchers/hash_matcher.rb +0 -7
- data/lib/canon/tree_diff/matchers/similarity_matcher.rb +1 -5
- data/lib/canon/tree_diff/matchers/structural_propagator.rb +1 -5
- data/lib/canon/tree_diff/matchers.rb +15 -0
- data/lib/canon/tree_diff/operation_converter.rb +7 -15
- data/lib/canon/tree_diff/operation_converter_helpers/metadata_enricher.rb +2 -12
- data/lib/canon/tree_diff/operation_converter_helpers/post_processor.rb +13 -7
- data/lib/canon/tree_diff/operation_converter_helpers/reason_builder.rb +2 -2
- data/lib/canon/tree_diff/operation_converter_helpers/update_change_handler.rb +4 -6
- data/lib/canon/tree_diff/operation_converter_helpers.rb +18 -0
- data/lib/canon/tree_diff/operations/operation_detector.rb +6 -5
- data/lib/canon/tree_diff/operations.rb +13 -0
- data/lib/canon/tree_diff.rb +26 -27
- data/lib/canon/validators/base_validator.rb +5 -10
- data/lib/canon/validators/html_validator.rb +2 -8
- data/lib/canon/validators/json_validator.rb +0 -1
- data/lib/canon/validators/xml_validator.rb +2 -8
- data/lib/canon/validators/yaml_validator.rb +0 -1
- data/lib/canon/validators.rb +12 -0
- data/lib/canon/version.rb +1 -1
- data/lib/canon/xml/c14n.rb +0 -4
- data/lib/canon/xml/data_model.rb +5 -15
- data/lib/canon/xml/line_range_mapper.rb +0 -2
- data/lib/canon/xml/nodes/attribute_node.rb +0 -2
- data/lib/canon/xml/nodes/comment_node.rb +0 -2
- data/lib/canon/xml/nodes/element_node.rb +0 -2
- data/lib/canon/xml/nodes/namespace_node.rb +0 -2
- data/lib/canon/xml/nodes/processing_instruction_node.rb +0 -2
- data/lib/canon/xml/nodes/root_node.rb +0 -2
- data/lib/canon/xml/nodes/text_node.rb +0 -2
- data/lib/canon/xml/nodes.rb +19 -0
- data/lib/canon/xml/processor.rb +0 -5
- data/lib/canon/xml/sax_builder.rb +1 -8
- data/lib/canon/xml/whitespace_normalizer.rb +2 -2
- data/lib/canon/xml.rb +33 -0
- data/lib/canon/xml_backend.rb +50 -14
- data/lib/canon/xml_parsing.rb +32 -18
- data/lib/canon.rb +25 -15
- data/lib/tasks/performance.rake +0 -58
- data/lib/tasks/performance_comparator.rb +132 -65
- data/lib/tasks/performance_helpers.rb +4 -249
- data/lib/tasks/performance_report.rb +309 -0
- metadata +28 -15
- data/lib/canon/comparison/dimensions/attribute_order_dimension.rb +0 -64
- data/lib/canon/comparison/dimensions/attribute_presence_dimension.rb +0 -64
- data/lib/canon/comparison/dimensions/attribute_values_dimension.rb +0 -167
- data/lib/canon/comparison/dimensions/base_dimension.rb +0 -107
- data/lib/canon/comparison/dimensions/comments_dimension.rb +0 -117
- data/lib/canon/comparison/dimensions/element_position_dimension.rb +0 -86
- data/lib/canon/comparison/dimensions/structural_whitespace_dimension.rb +0 -115
- data/lib/canon/comparison/dimensions/text_content_dimension.rb +0 -102
- data/lib/canon/comparison/xml_comparator/diff_node_builder.rb +0 -270
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 48895efa0afcaaa525d8dcb9b04c1eb5969aeacd96c2e9b1f575383109229ce8
|
|
4
|
+
data.tar.gz: 12baa3b412f857b7b6038149f8344f2aa295d8b29e96ed2a0401e64010df5478
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9d9e2d1bfce446d850e1c991e161991a5112bdccdcb3d57d28170ba9d3180bcd0897aba7c78c7c2e6fe3ec3f5d5ba0e295c9c80627fd0d3c9e2a8bfef1434125
|
|
7
|
+
data.tar.gz: ec91e939f8d39f21e9c93fcfea178241eb601c6e5f66e9956468bfef0bf480ba05d587b705d108f39de661e184d7aaae3e0b79cf4c907a2d0c98b062d4564ec5
|
data/.rubocop_todo.yml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# This configuration was generated by
|
|
2
2
|
# `rubocop --auto-gen-config`
|
|
3
|
-
# on 2026-
|
|
3
|
+
# on 2026-06-15 09:49:31 UTC using RuboCop version 1.87.0.
|
|
4
4
|
# The point is for the user to remove these configuration records
|
|
5
5
|
# one by one as the offenses are removed from the code base.
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
|
@@ -11,14 +11,14 @@ Gemspec/RequiredRubyVersion:
|
|
|
11
11
|
Exclude:
|
|
12
12
|
- 'canon.gemspec'
|
|
13
13
|
|
|
14
|
-
# Offense count:
|
|
14
|
+
# Offense count: 1272
|
|
15
15
|
# This cop supports safe autocorrection (--autocorrect).
|
|
16
16
|
# Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
|
|
17
17
|
# URISchemes: http, https
|
|
18
18
|
Layout/LineLength:
|
|
19
19
|
Enabled: false
|
|
20
20
|
|
|
21
|
-
# Offense count:
|
|
21
|
+
# Offense count: 57
|
|
22
22
|
# Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches, IgnoreDuplicateElseBranch.
|
|
23
23
|
Lint/DuplicateBranch:
|
|
24
24
|
Enabled: false
|
|
@@ -62,7 +62,7 @@ Lint/UselessConstantScoping:
|
|
|
62
62
|
Exclude:
|
|
63
63
|
- 'lib/canon/diff_formatter/theme.rb'
|
|
64
64
|
|
|
65
|
-
# Offense count:
|
|
65
|
+
# Offense count: 298
|
|
66
66
|
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
|
|
67
67
|
Metrics/AbcSize:
|
|
68
68
|
Enabled: false
|
|
@@ -78,12 +78,12 @@ Metrics/BlockLength:
|
|
|
78
78
|
Metrics/BlockNesting:
|
|
79
79
|
Max: 4
|
|
80
80
|
|
|
81
|
-
# Offense count:
|
|
81
|
+
# Offense count: 261
|
|
82
82
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
|
83
83
|
Metrics/CyclomaticComplexity:
|
|
84
84
|
Enabled: false
|
|
85
85
|
|
|
86
|
-
# Offense count:
|
|
86
|
+
# Offense count: 501
|
|
87
87
|
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
|
88
88
|
Metrics/MethodLength:
|
|
89
89
|
Max: 146
|
|
@@ -93,12 +93,12 @@ Metrics/MethodLength:
|
|
|
93
93
|
Metrics/ParameterLists:
|
|
94
94
|
Max: 10
|
|
95
95
|
|
|
96
|
-
# Offense count:
|
|
96
|
+
# Offense count: 207
|
|
97
97
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
|
98
98
|
Metrics/PerceivedComplexity:
|
|
99
99
|
Enabled: false
|
|
100
100
|
|
|
101
|
-
# Offense count:
|
|
101
|
+
# Offense count: 28
|
|
102
102
|
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
|
|
103
103
|
# AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to
|
|
104
104
|
Naming/MethodParameterName:
|
|
@@ -107,15 +107,13 @@ Naming/MethodParameterName:
|
|
|
107
107
|
- 'lib/canon/comparison/xml_comparator/attribute_comparator.rb'
|
|
108
108
|
- 'lib/canon/xml/namespace_handler.rb'
|
|
109
109
|
|
|
110
|
-
# Offense count:
|
|
111
|
-
# Configuration parameters:
|
|
112
|
-
#
|
|
113
|
-
#
|
|
114
|
-
Naming/
|
|
110
|
+
# Offense count: 1
|
|
111
|
+
# Configuration parameters: Mode, AllowedMethods, AllowedPatterns, AllowBangMethods, WaywardPredicates.
|
|
112
|
+
# AllowedMethods: call
|
|
113
|
+
# WaywardPredicates: infinite?, nonzero?
|
|
114
|
+
Naming/PredicateMethod:
|
|
115
115
|
Exclude:
|
|
116
|
-
- '
|
|
117
|
-
- 'lib/canon/comparison/markup_comparator.rb'
|
|
118
|
-
- 'lib/canon/comparison/xml_comparator/diff_node_builder.rb'
|
|
116
|
+
- 'spec/canon/comparison/xml_attribute_diff_spec.rb'
|
|
119
117
|
|
|
120
118
|
# Offense count: 4
|
|
121
119
|
# Configuration parameters: MinSize.
|
|
@@ -126,13 +124,13 @@ Performance/CollectionLiteralInLoop:
|
|
|
126
124
|
- 'lib/canon/xml/xml_base_handler.rb'
|
|
127
125
|
- 'spec/canon/diff/diff_node_mapper_comments_spec.rb'
|
|
128
126
|
|
|
129
|
-
# Offense count:
|
|
127
|
+
# Offense count: 111
|
|
130
128
|
# Configuration parameters: Prefixes, AllowedPatterns.
|
|
131
129
|
# Prefixes: when, with, without
|
|
132
130
|
RSpec/ContextWording:
|
|
133
131
|
Enabled: false
|
|
134
132
|
|
|
135
|
-
# Offense count:
|
|
133
|
+
# Offense count: 48
|
|
136
134
|
# Configuration parameters: IgnoredMetadata.
|
|
137
135
|
RSpec/DescribeClass:
|
|
138
136
|
Enabled: false
|
|
@@ -143,7 +141,7 @@ RSpec/DescribeMethod:
|
|
|
143
141
|
- 'spec/canon/comparison/multiple_differences_spec.rb'
|
|
144
142
|
- 'spec/canon/diff_formatter/character_map_customization_spec.rb'
|
|
145
143
|
|
|
146
|
-
# Offense count:
|
|
144
|
+
# Offense count: 916
|
|
147
145
|
# Configuration parameters: CountAsOne.
|
|
148
146
|
RSpec/ExampleLength:
|
|
149
147
|
Max: 44
|
|
@@ -195,7 +193,7 @@ RSpec/MultipleDescribes:
|
|
|
195
193
|
Exclude:
|
|
196
194
|
- 'spec/canon/comparison/match_options_spec.rb'
|
|
197
195
|
|
|
198
|
-
# Offense count:
|
|
196
|
+
# Offense count: 783
|
|
199
197
|
RSpec/MultipleExpectations:
|
|
200
198
|
Max: 15
|
|
201
199
|
|
|
@@ -248,7 +246,7 @@ RSpec/SpecFilePathFormat:
|
|
|
248
246
|
- 'spec/canon/yaml/formatter_spec.rb'
|
|
249
247
|
- 'spec/xml_c14n_spec.rb'
|
|
250
248
|
|
|
251
|
-
# Offense count:
|
|
249
|
+
# Offense count: 18
|
|
252
250
|
# Configuration parameters: IgnoreNameless, IgnoreSymbolicNames.
|
|
253
251
|
RSpec/VerifiedDoubles:
|
|
254
252
|
Exclude:
|
|
@@ -274,12 +272,13 @@ Style/HashLikeCase:
|
|
|
274
272
|
- 'lib/canon/diff/diff_block_builder.rb'
|
|
275
273
|
- 'lib/canon/xml/character_encoder.rb'
|
|
276
274
|
|
|
277
|
-
# Offense count:
|
|
275
|
+
# Offense count: 6
|
|
278
276
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
279
277
|
Style/IdenticalConditionalBranches:
|
|
280
278
|
Exclude:
|
|
281
279
|
- 'lib/canon/diff_formatter/by_object/base_formatter.rb'
|
|
282
280
|
- 'lib/canon/diff_formatter/legend.rb'
|
|
281
|
+
- 'lib/canon/xml/whitespace_normalizer.rb'
|
|
283
282
|
|
|
284
283
|
# Offense count: 1
|
|
285
284
|
# Configuration parameters: AllowedMethods.
|
data/Rakefile
CHANGED
|
@@ -7,6 +7,28 @@ RSpec::Core::RakeTask.new(:spec)
|
|
|
7
7
|
|
|
8
8
|
begin
|
|
9
9
|
require "opal/rspec/rake_task"
|
|
10
|
+
|
|
11
|
+
# Configure Opal load paths at load time (same pattern as moxml)
|
|
12
|
+
if defined?(Opal)
|
|
13
|
+
Opal.append_path File.expand_path("lib", __dir__)
|
|
14
|
+
|
|
15
|
+
# moxml gem
|
|
16
|
+
begin
|
|
17
|
+
moxml_spec = Gem::Specification.find_by_name("moxml")
|
|
18
|
+
moxml_lib = moxml_spec.full_require_paths.first
|
|
19
|
+
Opal.append_path moxml_lib
|
|
20
|
+
moxml_compat = File.expand_path("compat/opal", moxml_lib)
|
|
21
|
+
Opal.append_path moxml_compat if File.directory?(moxml_compat)
|
|
22
|
+
rescue Gem::MissingSpecError
|
|
23
|
+
# moxml not installed
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# REXML: bundled gem since Ruby 3.4
|
|
27
|
+
rexml_lib = $LOAD_PATH.find do |p|
|
|
28
|
+
File.exist?(File.join(p, "rexml", "document.rb"))
|
|
29
|
+
end
|
|
30
|
+
Opal.append_path rexml_lib if rexml_lib
|
|
31
|
+
end
|
|
10
32
|
rescue LoadError
|
|
11
33
|
# Opal not available or incompatible with current Ruby version
|
|
12
34
|
end
|
|
@@ -20,9 +42,10 @@ Dir.glob("lib/tasks/**/*.rake").each { |r| load r }
|
|
|
20
42
|
namespace :spec do
|
|
21
43
|
if defined?(Opal::RSpec::RakeTask)
|
|
22
44
|
desc "Run Opal (JavaScript) tests"
|
|
23
|
-
Opal::RSpec::RakeTask.new(:opal) do |
|
|
24
|
-
server.append_path "lib"
|
|
45
|
+
Opal::RSpec::RakeTask.new(:opal) do |_server, runner|
|
|
25
46
|
runner.default_path = "spec"
|
|
47
|
+
runner.requires = %w[rexml_compat rexml/document rexml/xpath
|
|
48
|
+
moxml moxml/adapter/rexml spec_helper]
|
|
26
49
|
runner.pattern = "spec/canon/opal_xml_smoke_spec.rb"
|
|
27
50
|
end
|
|
28
51
|
end
|
data/lib/canon/cache.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "digest"
|
|
3
|
+
require "digest" unless RUBY_ENGINE == "opal"
|
|
4
4
|
|
|
5
5
|
module Canon
|
|
6
6
|
# Cache for expensive operations during document comparison
|
|
@@ -73,50 +73,41 @@ module Canon
|
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
# Generate cache key for document parsing
|
|
76
|
-
#
|
|
77
|
-
# @param content [String] Document content
|
|
78
|
-
# @param format [Symbol] Document format
|
|
79
|
-
# @param preprocessing [Symbol] Preprocessing option
|
|
80
|
-
# @return [String] Cache key
|
|
81
76
|
def key_for_document(content, format, preprocessing)
|
|
82
|
-
|
|
83
|
-
"doc:#{format}:#{preprocessing}:#{digest[0..16]}"
|
|
77
|
+
"doc:#{format}:#{preprocessing}:#{content_hash(content)}"
|
|
84
78
|
end
|
|
85
79
|
|
|
86
80
|
# Generate cache key for format detection
|
|
87
|
-
#
|
|
88
|
-
# @param content [String] Document content
|
|
89
|
-
# @return [String] Cache key
|
|
90
81
|
def key_for_format_detection(content)
|
|
91
|
-
# Use first 100 chars for quick key, plus length
|
|
92
|
-
# Force to binary to avoid encoding compatibility issues
|
|
93
82
|
preview = content[0..100].b
|
|
94
|
-
|
|
95
|
-
"fmt:#{digest[0..16]}"
|
|
83
|
+
"fmt:#{content_hash(preview + content.length.to_s)}"
|
|
96
84
|
end
|
|
97
85
|
|
|
98
86
|
# Generate cache key for XML canonicalization
|
|
99
|
-
#
|
|
100
|
-
# @param content [String] XML content
|
|
101
|
-
# @param with_comments [Boolean] Whether to include comments
|
|
102
|
-
# @return [String] Cache key
|
|
103
87
|
def key_for_c14n(content, with_comments)
|
|
104
|
-
|
|
105
|
-
"c14n:#{with_comments}:#{digest[0..16]}"
|
|
88
|
+
"c14n:#{with_comments}:#{content_hash(content)}"
|
|
106
89
|
end
|
|
107
90
|
|
|
108
91
|
# Generate cache key for preprocessing
|
|
109
|
-
#
|
|
110
|
-
# @param content [String] Original content
|
|
111
|
-
# @param preprocessing [Symbol] Preprocessing type
|
|
112
|
-
# @return [String] Cache key
|
|
113
92
|
def key_for_preprocessing(content, preprocessing)
|
|
114
|
-
|
|
115
|
-
"pre:#{preprocessing}:#{digest[0..16]}"
|
|
93
|
+
"pre:#{preprocessing}:#{content_hash(content)}"
|
|
116
94
|
end
|
|
117
95
|
|
|
118
96
|
private
|
|
119
97
|
|
|
98
|
+
# Generate a hash string for cache keys
|
|
99
|
+
def content_hash(content)
|
|
100
|
+
if defined?(Digest::SHA256)
|
|
101
|
+
Digest::SHA256.hexdigest(content)[0..16]
|
|
102
|
+
else
|
|
103
|
+
# Opal fallback: simple string hash
|
|
104
|
+
h = content.each_char.reduce(0) do |acc, c|
|
|
105
|
+
((acc * 31) + c.ord) & 0xFFFFFFFF
|
|
106
|
+
end
|
|
107
|
+
h.to_s(16).rjust(8, "0")
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
120
111
|
# Get or create cache for a category
|
|
121
112
|
#
|
|
122
113
|
# @param category [Symbol] Cache category
|
data/lib/canon/cli.rb
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "../comparison"
|
|
4
|
-
require_relative "../diff_formatter"
|
|
5
|
-
require_relative "../color_detector"
|
|
6
3
|
require "json"
|
|
7
4
|
require "yaml"
|
|
8
5
|
|
|
@@ -66,7 +63,6 @@ module Canon
|
|
|
66
63
|
|
|
67
64
|
# Show configuration in verbose mode using shared DebugOutput
|
|
68
65
|
if @options[:verbose]
|
|
69
|
-
require_relative "../diff_formatter/debug_output"
|
|
70
66
|
config_output = Canon::DiffFormatter::DebugOutput.verbose_tables_only(
|
|
71
67
|
result,
|
|
72
68
|
{
|
|
@@ -219,12 +215,10 @@ module Canon
|
|
|
219
215
|
|
|
220
216
|
case format
|
|
221
217
|
when :xml
|
|
222
|
-
require_relative "../pretty_printer/xml"
|
|
223
218
|
formatted1 = Canon::PrettyPrinter::Xml.new(indent: 2).format(content1)
|
|
224
219
|
formatted2 = Canon::PrettyPrinter::Xml.new(indent: 2).format(content2)
|
|
225
220
|
[formatted1, formatted2]
|
|
226
221
|
when :html
|
|
227
|
-
require_relative "../pretty_printer/html"
|
|
228
222
|
formatted1 = Canon::PrettyPrinter::Html.new(indent: 2).format(content1)
|
|
229
223
|
formatted2 = Canon::PrettyPrinter::Html.new(indent: 2).format(content2)
|
|
230
224
|
[formatted1, formatted2]
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Canon
|
|
4
|
+
# Thor command implementations invoked by {CLI}. Children are autoloaded.
|
|
5
|
+
module Commands
|
|
6
|
+
autoload :DiffCommand, "canon/commands/diff_command"
|
|
7
|
+
autoload :FormatCommand, "canon/commands/format_command"
|
|
8
|
+
end
|
|
9
|
+
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Canon
|
|
4
4
|
module Comparison
|
|
5
5
|
# CompareProfile encapsulates the policy decisions about how differences
|
|
6
|
-
# in various dimensions should be handled during comparison
|
|
6
|
+
# in various dimensions should be handled during comparison.
|
|
7
7
|
#
|
|
8
8
|
# This class provides separation of concerns:
|
|
9
9
|
# - CompareProfile: Policy decisions (what to track, what affects equivalence)
|
|
@@ -17,69 +17,46 @@ module Canon
|
|
|
17
17
|
@match_options = match_options
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
# Should DiffNodes be created for differences in this dimension?
|
|
21
|
-
#
|
|
22
|
-
# In verbose mode, we want to track ALL differences for reporting.
|
|
23
|
-
# In non-verbose mode, we only need to track normative differences.
|
|
24
|
-
#
|
|
25
|
-
# @param dimension [Symbol] The match dimension to check
|
|
26
|
-
# @return [Boolean] true if differences should be tracked
|
|
27
20
|
def track_dimension?(_dimension)
|
|
28
|
-
# Always track dimensions that affect equivalence
|
|
29
|
-
# In verbose mode, also track informative dimensions
|
|
30
21
|
true
|
|
31
22
|
end
|
|
32
23
|
|
|
33
24
|
# Should differences in this dimension affect equivalence?
|
|
34
25
|
#
|
|
35
|
-
# This determines the return value of the comparison:
|
|
36
|
-
# - true: differences make documents non-equivalent
|
|
37
|
-
# - false: differences are informative only
|
|
38
|
-
#
|
|
39
26
|
# @param dimension [Symbol] The match dimension to check
|
|
40
27
|
# @return [Boolean] true if differences affect equivalence
|
|
41
28
|
def affects_equivalence?(dimension)
|
|
42
29
|
behavior = behavior_for(dimension)
|
|
43
|
-
|
|
44
|
-
# :strict → affects equivalence
|
|
45
|
-
# :normalize → might affect (if normalization fails)
|
|
46
|
-
# :ignore → does NOT affect equivalence
|
|
47
30
|
behavior != :ignore
|
|
48
31
|
end
|
|
49
32
|
|
|
50
33
|
# Is a difference in this dimension normative (affects equivalence)?
|
|
51
34
|
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
# - structural_whitespace: only :strict is normative (:normalize and :ignore are informative)
|
|
56
|
-
# - all other dimensions: normative unless behavior is :ignore
|
|
35
|
+
# Delegates to the Dimension object's normative? rule. Falls back to
|
|
36
|
+
# the default rule (normative unless :ignore) for dimensions not in the
|
|
37
|
+
# format's dimension set (e.g., derived dimensions like :element_structure).
|
|
57
38
|
#
|
|
58
39
|
# @param dimension [Symbol] The match dimension to check
|
|
59
40
|
# @return [Boolean] true if normative, false if informative
|
|
60
41
|
def normative_dimension?(dimension)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
42
|
+
dim = dimension_for(dimension)
|
|
43
|
+
if dim
|
|
44
|
+
dim.normative?(behavior_for(dimension))
|
|
45
|
+
else
|
|
46
|
+
behavior_for(dimension) != :ignore
|
|
66
47
|
end
|
|
67
|
-
|
|
68
|
-
# For all other dimensions, normative if behavior affects equivalence
|
|
69
|
-
affects_equivalence?(dimension)
|
|
70
48
|
end
|
|
71
49
|
|
|
72
50
|
# Can a difference in this dimension be formatting-only?
|
|
73
51
|
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
52
|
+
# Delegates to the Dimension object's supports_formatting_detection?
|
|
53
|
+
# flag. Falls back to false for unknown dimensions.
|
|
76
54
|
#
|
|
77
55
|
# @param dimension [Symbol] The match dimension to check
|
|
78
56
|
# @return [Boolean] true if formatting detection should apply
|
|
79
57
|
def supports_formatting_detection?(dimension)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
%i[text_content structural_whitespace].include?(dimension)
|
|
58
|
+
dim = dimension_for(dimension)
|
|
59
|
+
dim ? dim.supports_formatting_detection? : false
|
|
83
60
|
end
|
|
84
61
|
|
|
85
62
|
# Get the behavior setting for a dimension
|
|
@@ -94,6 +71,23 @@ module Canon
|
|
|
94
71
|
:strict
|
|
95
72
|
end
|
|
96
73
|
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
def dimension_for(name)
|
|
78
|
+
set = Dimensions::Registry.for(extract_format)
|
|
79
|
+
set[name]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def extract_format
|
|
83
|
+
if match_options.is_a?(ResolvedMatchOptions)
|
|
84
|
+
match_options.format
|
|
85
|
+
elsif match_options.is_a?(Hash)
|
|
86
|
+
match_options[:format]
|
|
87
|
+
else
|
|
88
|
+
:xml
|
|
89
|
+
end
|
|
90
|
+
end
|
|
97
91
|
end
|
|
98
92
|
end
|
|
99
93
|
end
|
|
@@ -133,8 +133,6 @@ parse_errors_expected: nil, parse_errors_received: nil)
|
|
|
133
133
|
# @return [String] Formatted diff output
|
|
134
134
|
def diff(use_color: true, context_lines: 3, diff_grouping_lines: nil,
|
|
135
135
|
show_diffs: :all, diff_mode: :separate, legacy_terminal: false)
|
|
136
|
-
require_relative "../diff_formatter"
|
|
137
|
-
|
|
138
136
|
formatter = Canon::DiffFormatter.new(
|
|
139
137
|
use_color: use_color,
|
|
140
138
|
mode: :by_line,
|