canon 0.3.120 → 0.3.122

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: 38a359346723b741f1bc368f5bb563f816a6cce60645fd4329c6a615175492d9
4
- data.tar.gz: f02379429df3da9c8ad8835eeba4ccafb423d4b00e7a0b65ba6dac8acc488aa6
3
+ metadata.gz: 5c8f274f503852b87469eb653b74b16cff4a24313a642ba665f9d00f4ddc5ca2
4
+ data.tar.gz: 1ff259b65b606b03400e5c729ba2384643877a48fdca3e7ff12f6ba5adfae62d
5
5
  SHA512:
6
- metadata.gz: 90794b21762de80ba03846c814a5980da475d156efbb63b6248e76956967408988341145abbec476f253f8113524c87367c343366a875d0eb50008b5b48497f7
7
- data.tar.gz: f26fdd27f3f203dc0da8a612bb421889fee7c2d1823a2c6ccb29aad10dc0dca8876906c7438739296d1db6baac6111a1363ae9f7f0e8a131e42adbe2c06958c4
6
+ metadata.gz: 936d7dd4ca541dc44435294f26ac3f04886668ccfd5c919ef6cd50c033b75d633e33e4fcdbe9cdd809e9400f2c882af7baaf00d1316e6c832b46a87a8c0e6ec7
7
+ data.tar.gz: ae0c2379e7aefd1445bd108aa6533c8570858418e02e35653339618d597bfedab7254af12955a5cd7c8717e29a93591bfd458f6b3920fc343cf8af0a8189b0f8
@@ -637,6 +637,22 @@ module Canon
637
637
  resolved = opts.dup
638
638
  format_hint = resolved[:format]
639
639
 
640
+ # Arrays have no document format of their own: suites extract
641
+ # value lists (attributes, anchors) or node lists and compare
642
+ # them as arrays. Element-wise, order-sensitive, each element
643
+ # recursing through the normal pipeline (strings short-circuit,
644
+ # nodes take their own format path).
645
+ if obj1.is_a?(Array) && obj2.is_a?(Array)
646
+ return array_diff(obj1, obj2, resolved)
647
+ end
648
+
649
+ # Hashes (metadata dumps the equivalent-xml matcher compared
650
+ # generically): key-wise deep comparison through the normal
651
+ # pipeline.
652
+ if obj1.is_a?(Hash) && obj2.is_a?(Hash)
653
+ return hash_diff(obj1, obj2, resolved)
654
+ end
655
+
640
656
  # Detect formats (with explicit hint) and pre-parse HTML strings
641
657
  # through Nokogiri::HTML5 so html4 and html5 share HTML's
642
658
  # whitespace-sensitivity semantics (issue #118). Pre-parsing
@@ -690,6 +706,73 @@ module Canon
690
706
  # @param format1 [Symbol]
691
707
  # @param format2 [Symbol]
692
708
  # @return [Symbol]
709
+ SCALAR_LEAVES = [String, Symbol, Numeric, NilClass,
710
+ TrueClass, FalseClass].freeze
711
+
712
+ def scalar_leaf?(obj)
713
+ SCALAR_LEAVES.any? { |k| obj.is_a?(k) }
714
+ end
715
+
716
+ def array_diff(arr1, arr2, opts = {})
717
+ verbose = opts[:verbose]
718
+ if arr1.size != arr2.size
719
+ return verbose ? [:size_mismatch] : false
720
+ end
721
+
722
+ # Elements are extracted values, not documents: scalar leaves
723
+ # compare literally (a matcher format hint must not turn "ref1"
724
+ # into an XML fragment, where every bare string parses equal,
725
+ # and the detector has no format for numbers at all); containers
726
+ # and nodes recurse through the normal pipeline without the
727
+ # format hint.
728
+ scalar_opts = opts.except(:verbose, :format)
729
+ diffs = []
730
+ arr1.zip(arr2).each_with_index do |(element_before, element_after), i|
731
+ eq = if scalar_leaf?(element_before) && scalar_leaf?(element_after)
732
+ element_before == element_after
733
+ else
734
+ equivalent?(element_before, element_after, scalar_opts)
735
+ end
736
+ next if eq == true
737
+
738
+ return false unless verbose
739
+
740
+ diffs << leaf_diff(i.to_s, element_before, element_after)
741
+ end
742
+ verbose ? diffs : diffs.empty?
743
+ end
744
+
745
+ # Verbose ruby-object entries use the diff-code shape the
746
+ # DiffFormatter's by-object renderers consume.
747
+ def leaf_diff(path, value_before, value_after)
748
+ { path: path, diff_code: UNEQUAL_PRIMITIVES,
749
+ value1: value_before, value2: value_after }
750
+ end
751
+
752
+ def hash_diff(hash1, hash2, opts = {})
753
+ verbose = opts[:verbose]
754
+ if hash1.keys.sort != hash2.keys.sort
755
+ return verbose ? [:key_mismatch] : false
756
+ end
757
+
758
+ scalar_opts = opts.except(:verbose, :format)
759
+ diffs = []
760
+ hash1.each do |key, value_before|
761
+ value_after = hash2[key]
762
+ eq = if scalar_leaf?(value_before) && scalar_leaf?(value_after)
763
+ value_before == value_after
764
+ else
765
+ equivalent?(value_before, value_after, scalar_opts)
766
+ end
767
+ next if eq == true
768
+
769
+ return false unless verbose
770
+
771
+ diffs << leaf_diff(key.to_s, value_before, value_after)
772
+ end
773
+ verbose ? diffs : diffs.empty?
774
+ end
775
+
693
776
  def normalize_comparison_format(format1, format2)
694
777
  return format2 if format1 == :ruby_object &&
695
778
  %i[json yaml].include?(format2)
data/lib/canon/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Canon
4
- VERSION = "0.3.120"
4
+ VERSION = "0.3.122"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: canon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.120
4
+ version: 0.3.122
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-11-02 00:00:00.000000000 Z
11
+ date: 2026-11-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs