diff_matcher 2.1.1 → 2.2.0

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.
data/README.md CHANGED
@@ -105,20 +105,37 @@ puts DiffMatcher::difference([1], [1, 2])
105
105
  ```
106
106
 
107
107
 
108
- When `expected` can take multiple forms use a `Matcher`
108
+ When `expected` is a `Hash` with optional keys use a `Matcher`.
109
109
 
110
110
  ``` ruby
111
- puts DiffMatcher::difference(DiffMatcher::Matcher[Fixnum,Float], "3")
111
+ puts DiffMatcher::difference(
112
+ DiffMatcher::Matcher.new({:name=>String, :age=>Fixnum}, :optional_keys=>[:age]),
113
+ {:name=>0}
114
+ )
115
+ {
116
+ :name=>- String+ 0
117
+ }
118
+ Where, - 1 missing, + 1 additional
119
+ ```
120
+
121
+
122
+ When `expected` can take multiple forms use some `Matcher`s `||`ed together.
123
+
124
+ ``` ruby
125
+ puts DiffMatcher::difference(DiffMatcher::Matcher.new(Fixnum) || DiffMatcher.new(Float), "3")
112
126
  - Float+ "3"
113
127
  Where, - 1 missing, + 1 additional
114
128
  ```
129
+ (NB. `DiffMatcher::Matcher[Fixnum, Float]` can be used as a shortcut for
130
+ `DiffMatcher::Matcher.new(Fixnum) || DiffMatcher.new(Float)`
131
+ )
115
132
 
116
133
 
117
- When `actual` is an array of unknown size use an `AllMatcher` to match
134
+ When `actual` is an array of *unknown* size use an `AllMatcher` to match
118
135
  against *all* the elements in the array.
119
136
 
120
137
  ``` ruby
121
- puts DiffMatcher::difference(DiffMatcher::AllMatcher[Fixnum], [1, 2, "3"])
138
+ puts DiffMatcher::difference(DiffMatcher::AllMatcher.new(Fixnum), [1, 2, "3"])
122
139
  [
123
140
  : 1,
124
141
  : 2,
@@ -128,15 +145,30 @@ Where, - 1 missing, + 1 additional, : 2 match_class
128
145
  ```
129
146
 
130
147
 
148
+ When `actual` is an array with a *limited* size use an `AllMatcher` to match
149
+ against *all* the elements in the array adhering to the limits of `:min`
150
+ and or `:max`.
151
+
152
+ ``` ruby
153
+ puts DiffMatcher::difference(DiffMatcher::AllMatcher.new(Fixnum, :min=>3), [1, 2])
154
+ [
155
+ : 1,
156
+ : 2,
157
+ - Fixnum
158
+ ]
159
+ Where, - 1 missing, : 2 match_class
160
+ ```
161
+
162
+
131
163
  When `actual` is an array of unknown size *and* `expected` can take
132
164
  multiple forms use a `Matcher` inside of an `AllMatcher` to match
133
165
  against *all* the elements in the array in any of the forms.
134
166
 
135
167
  ``` ruby
136
168
  puts DiffMatcher::difference(
137
- DiffMatcher::AllMatcher[
169
+ DiffMatcher::AllMatcher.new(
138
170
  DiffMatcher::Matcher[Fixnum, Float]
139
- ],
171
+ ),
140
172
  [1, 2.00, "3"]
141
173
  )
142
174
  [
@@ -175,6 +207,8 @@ The items shown in a difference are prefixed as follows:
175
207
  match value =>
176
208
  match regexp => "~ "
177
209
  match class => ": "
210
+ match matcher => "| "
211
+ match proc => ". "
178
212
  match proc => "{ "
179
213
 
180
214
 
@@ -189,6 +223,8 @@ Using the `:default` colour scheme items shown in a difference are coloured as f
189
223
  match value =>
190
224
  match regexp => green
191
225
  match class => blue
226
+ match matcher => blue
227
+ match range => cyan
192
228
  match proc => cyan
193
229
 
194
230
  Other colour schemes, eg. `:color_scheme=>:white_background` will use different colour mappings.
@@ -8,13 +8,13 @@ module DiffMatcher
8
8
  class Matcher
9
9
  attr_reader :expecteds
10
10
 
11
- def self.[](*expected)
12
- new(*expected)
11
+ def self.[](*expecteds)
12
+ expecteds.inject(nil) { |obj, e| obj ? obj | new(e) : new(e) }
13
13
  end
14
14
 
15
- def initialize(*expected)
16
- @expecteds = [expected].flatten
17
- @opts = {}
15
+ def initialize(expected, opts={})
16
+ @expecteds = [expected]
17
+ @expected_opts = {expected => opts}
18
18
  end
19
19
 
20
20
  def |(other)
@@ -22,25 +22,39 @@ module DiffMatcher
22
22
  tap { @expecteds += other.expecteds }
23
23
  end
24
24
 
25
- def expected(expected, actual)
26
- expected
25
+ def expected(e, actual)
26
+ e
27
+ end
28
+
29
+ def expected_opts(e)
30
+ @expected_opts.fetch(e, {})
27
31
  end
28
32
 
29
33
  def diff(actual, opts={})
30
- dif = nil
31
- @expecteds.any? { |e|
32
- d = DiffMatcher::Difference.new(expected(e, actual), actual, opts)
33
- dif = d.matching? ? nil : d.dif
34
+ difs = []
35
+ matched = @expecteds.any? { |e|
36
+ d = DiffMatcher::Difference.new(expected(e, actual), actual, opts.merge(expected_opts(e)))
37
+ unless d.matching?
38
+ difs << [ d.dif_count, d.dif ]
39
+ end
34
40
  d.matching?
35
41
  }
36
- dif
42
+ unless matched
43
+ count, dif = difs.sort.last
44
+ dif
45
+ end
37
46
  end
38
47
  end
39
48
 
40
49
  class NotAnArray < Exception; end
41
50
  class AllMatcher < Matcher
42
- def expected(expected, actual)
43
- [expected]*actual.size
51
+ def expected(e, actual)
52
+ opts = expected_opts(e)
53
+ size = actual.size
54
+ min = opts[:min] || 0
55
+ max = opts[:max] || 1_000_000 # MAXINT?
56
+ size = size > min ? (size < max ? size : max) : min
57
+ [e]*size
44
58
  end
45
59
 
46
60
  def diff(actual, opts={})
@@ -67,6 +81,7 @@ module DiffMatcher
67
81
  :match_regexp => [GREEN , "~"],
68
82
  :match_class => [BLUE , ":"],
69
83
  :match_matcher => [BLUE , "|"],
84
+ :match_range => [CYAN , "."],
70
85
  :match_proc => [CYAN , "{"]
71
86
  }
72
87
 
@@ -83,6 +98,8 @@ module DiffMatcher
83
98
  @quiet = opts[:quiet]
84
99
  @color_enabled = opts[:color_enabled] || !!opts[:color_scheme]
85
100
  @color_scheme = COLOR_SCHEMES[opts[:color_scheme] || :default]
101
+ @optional_keys = opts.delete(:optional_keys) || []
102
+ @dif_count = 0
86
103
  @difference = difference(expected, actual)
87
104
  end
88
105
 
@@ -101,6 +118,7 @@ module DiffMatcher
101
118
  unless item_type == :match_value
102
119
  color, prefix = @color_scheme[item_type]
103
120
  count = msg.scan("#{color}#{prefix}").size
121
+ @dif_count += count if [:missing, :additional].include? item_type
104
122
  "#{color}#{prefix} #{BOLD}#{count} #{item_type}#{RESET}" if count > 0
105
123
  end
106
124
  }.compact.join(", ")
@@ -110,6 +128,10 @@ module DiffMatcher
110
128
  end
111
129
  end
112
130
 
131
+ def dif_count
132
+ @dif_count
133
+ end
134
+
113
135
  def dif
114
136
  @difference
115
137
  end
@@ -132,7 +154,7 @@ module DiffMatcher
132
154
  @matches_shown ||= lambda {
133
155
  ret = []
134
156
  unless @quiet
135
- ret += [:match_matcher, :match_class, :match_proc, :match_regexp]
157
+ ret += [:match_matcher, :match_class, :match_range, :match_proc, :match_regexp]
136
158
  ret += [:match_value]
137
159
  end
138
160
  ret
@@ -185,7 +207,7 @@ module DiffMatcher
185
207
 
186
208
  def missing(left, right, expected_class)
187
209
  compare(left, expected_class) { |k|
188
- "#{"#{k.inspect}=>" if expected_class == Hash}#{left[k].inspect}" unless right.has_key?(k)
210
+ "#{"#{k.inspect}=>" if expected_class == Hash}#{left[k].inspect}" unless right.has_key?(k) || @optional_keys.include?(k)
189
211
  }
190
212
  end
191
213
 
@@ -199,6 +221,7 @@ module DiffMatcher
199
221
  d = expected.diff(actual, @opts)
200
222
  [d.nil? , :match_matcher, d]
201
223
  when Class ; [actual.is_a?(expected) , :match_class ]
224
+ when Range ; [expected.include?(actual) , :match_range ]
202
225
  when Proc ; [expected.call(actual) , :match_proc ]
203
226
  when Regexp ; [actual.is_a?(String) && actual.match(expected) , :match_regexp ]
204
227
  else [actual == expected , :match_value ]
@@ -1,3 +1,3 @@
1
1
  module DiffMatcher
2
- VERSION = "2.1.1"
2
+ VERSION = "2.2.0"
3
3
  end
@@ -9,13 +9,15 @@ def fix_EOF_problem(s)
9
9
  # <<-EOF isn't working like its meant to :(
10
10
  whitespace = s.split("\n")[-1][/^[ ]+/]
11
11
  indentation = whitespace ? whitespace.size : 0
12
- s.gsub("\n#{" " * indentation}", "\n").strip
12
+ s.gsub("\n#{" " * indentation}", "\n").tap { |result|
13
+ result.strip! if whitespace
14
+ }
13
15
  end
14
16
 
15
17
 
16
- shared_examples_for "a matcher" do |expected, expected2, same, different, difference, opts|
18
+ shared_examples_for "an or-ed matcher" do |expected, expected2, same, different, difference, opts|
17
19
  opts ||= {}
18
- context "with #{opts.size > 0 ? opts_to_s(opts) : "no opts"}" do
20
+ context "where expected=#{expected.inspect}, expected2=#{expected2.inspect}" do
19
21
  describe "diff(#{same.inspect}#{opts_to_s(opts)})" do
20
22
  let(:expected ) { expected }
21
23
  let(:expected2) { expected }
@@ -32,7 +34,7 @@ shared_examples_for "a matcher" do |expected, expected2, same, different, differ
32
34
  let(:opts ) { opts }
33
35
 
34
36
  it { should_not be_nil } unless RUBY_1_9
35
- it { should == fix_EOF_problem(difference)+"\n" } if RUBY_1_9
37
+ it { should == fix_EOF_problem(difference) } if RUBY_1_9
36
38
  end
37
39
  end
38
40
  end
@@ -44,23 +46,24 @@ describe DiffMatcher::Matcher do
44
46
  {:name => String , :age => Integer },
45
47
  {:name => "Peter" , :age => 21 },
46
48
  {:name => 21 , :age => 21 },
47
- <<-EOF
48
- {
49
- :name=>\e[31m- \e[1mString\e[0m\e[33m+ \e[1m21\e[0m,
50
- :age=>\e[34m: \e[1m21\e[0m
51
- }
52
- EOF
49
+ "{\n :name=>\e[31m- \e[1mString\e[0m\e[33m+ \e[1m21\e[0m,\n :age=>\e[34m: \e[1m21\e[0m\n}\n"
53
50
 
54
51
  describe "DiffMatcher::Matcher[expected, expected2]," do
55
52
  subject { DiffMatcher::Matcher[expected, expected2].diff(actual) }
56
53
 
57
- it_behaves_like "a matcher", expected, expected2, same, different, difference
58
- end
54
+ it_behaves_like "an or-ed matcher", expected, expected2, same, different, difference
59
55
 
60
- describe "DiffMatcher::Matcher[expected] | DiffMatcher::Matcher[expected2])" do
61
- subject { (DiffMatcher::Matcher[expected] | DiffMatcher::Matcher[expected2]).diff(actual) }
56
+ context "when Matchers are or-ed it works the same" do
57
+ subject { (DiffMatcher::Matcher[expected] | DiffMatcher::Matcher[expected2]).diff(actual) }
58
+
59
+ it_behaves_like "an or-ed matcher", expected, expected2, same, different, difference
60
+ end
62
61
 
63
- it_behaves_like "a matcher", expected, expected2, same, different, difference
62
+ context "expecteds are in different order it still uses the closest dif" do
63
+ subject { DiffMatcher::Matcher[expected2, expected].diff(actual) }
64
+
65
+ it_behaves_like "an or-ed matcher", expected2, expected, same, different, difference
66
+ end
64
67
  end
65
68
  end
66
69
 
@@ -119,6 +122,36 @@ shared_examples_for "a diff matcher" do |expected, same, different, difference,
119
122
  end
120
123
  end
121
124
 
125
+ describe "DiffMatcher::Matcher[expected].diff(actual, opts)" do
126
+ subject { DiffMatcher::Matcher[expected].diff(actual, opts) }
127
+
128
+ describe "when expected is an instance," do
129
+ context "of Fixnum," do
130
+ expected, same, different =
131
+ 1,
132
+ 1,
133
+ 2
134
+
135
+ it_behaves_like "a diff matcher", expected, same, different,
136
+ "\e[31m- \e[1m1\e[0m\e[33m+ \e[1m2\e[0m", {}
137
+ end
138
+ end
139
+
140
+ describe "when expected is an instance," do
141
+ context "of Hash, with optional keys" do
142
+ expected, same, different =
143
+ {:a=>1, :b=>Fixnum},
144
+ {:a=>1},
145
+ {:a=>2}
146
+
147
+ it_behaves_like "a diff matcher", expected, same, different,
148
+ "{\n :a=>\e[31m- \e[1m1\e[0m\e[33m+ \e[1m2\e[0m\n}\n",
149
+ {:optional_keys=>[:b]}
150
+ end
151
+ end
152
+ end
153
+
154
+
122
155
  describe "DiffMatcher::difference(expected, actual, opts)" do
123
156
  subject { DiffMatcher::difference(expected, actual, opts) }
124
157
 
@@ -247,6 +280,19 @@ describe "DiffMatcher::difference(expected, actual, opts)" do
247
280
  end
248
281
  end
249
282
 
283
+ context "of Range," do
284
+ expected, same, different =
285
+ (1..3),
286
+ 2,
287
+ 4
288
+
289
+ it_behaves_like "a diff matcher", expected, same, different,
290
+ <<-EOF
291
+ - 1..3+ 4
292
+ Where, - 1 missing, + 1 additional
293
+ EOF
294
+ end
295
+
250
296
  context "of Hash," do
251
297
  expected, same, different =
252
298
  { "a"=>1 },
@@ -396,6 +442,40 @@ describe "DiffMatcher::difference(expected, actual, opts)" do
396
442
  EOF
397
443
 
398
444
  end
445
+
446
+ context "with a min restriction" do
447
+ expected, same, different =
448
+ DiffMatcher::AllMatcher.new(String, :min=>3),
449
+ %w(ay be ci),
450
+ %w(ay be)
451
+
452
+ it_behaves_like "a diff matcher", expected, same, different,
453
+ <<-EOF
454
+ [
455
+ : "ay",
456
+ : "be",
457
+ - String
458
+ ]
459
+ Where, - 1 missing, : 2 match_class
460
+ EOF
461
+ end
462
+
463
+ context "with a max restriction" do
464
+ expected, same, different =
465
+ DiffMatcher::AllMatcher.new(String, :max=>2),
466
+ %w(ay be),
467
+ %w(ay be ci)
468
+
469
+ it_behaves_like "a diff matcher", expected, same, different,
470
+ <<-EOF
471
+ [
472
+ : "ay",
473
+ : "be",
474
+ + "ci"
475
+ ]
476
+ Where, + 1 additional, : 2 match_class
477
+ EOF
478
+ end
399
479
  end
400
480
 
401
481
  context "a DiffMatcher::AllMatcher using an or-ed DiffMatcher::Matcher," do
@@ -450,11 +530,11 @@ describe "DiffMatcher::difference(expected, actual, opts)" do
450
530
 
451
531
  context "when expected has multiple items," do
452
532
  expected, same, different =
453
- [ 1, 2, /\d/, Fixnum, lambda { |x| (4..6).include? x } ],
454
- [ 1, 2, "3" , 4 , 5 ],
455
- [ 0, 2, "3" , 4 , 5 ]
533
+ [ 1, 2, /\d/, Fixnum, 4..6 , lambda { |x| x % 6 == 0 } ],
534
+ [ 1, 2, "3" , 4 , 5 , 6 ],
535
+ [ 0, 2, "3" , 4 , 5 , 6 ]
456
536
 
457
- describe "it shows regex, class, proc matches and matches" do
537
+ describe "it shows regex, class, range, proc matches and matches" do
458
538
  it_behaves_like "a diff matcher", expected, same, different,
459
539
  <<-EOF
460
540
  [
@@ -462,9 +542,10 @@ describe "DiffMatcher::difference(expected, actual, opts)" do
462
542
  2,
463
543
  ~ "(3)",
464
544
  : 4,
465
- { 5
545
+ . 5,
546
+ { 6
466
547
  ]
467
- Where, - 1 missing, + 1 additional, ~ 1 match_regexp, : 1 match_class, { 1 match_proc
548
+ Where, - 1 missing, + 1 additional, ~ 1 match_regexp, : 1 match_class, . 1 match_range, { 1 match_proc
468
549
  EOF
469
550
  end
470
551
 
@@ -486,9 +567,10 @@ describe "DiffMatcher::difference(expected, actual, opts)" do
486
567
  2,
487
568
  ~ "(3)",
488
569
  : 4,
489
- { 5
570
+ . 5,
571
+ { 6
490
572
  ]
491
- Where, - 1 missing, + 1 additional, ~ 1 match_regexp, : 1 match_class, { 1 match_proc
573
+ Where, - 1 missing, + 1 additional, ~ 1 match_regexp, : 1 match_class, . 1 match_range, { 1 match_proc
492
574
  EOF
493
575
  end
494
576
 
@@ -500,9 +582,10 @@ describe "DiffMatcher::difference(expected, actual, opts)" do
500
582
  \e[0m 2,
501
583
  \e[0m \e[32m~ \e[0m"\e[32m(\e[1m3\e[0m\e[32m)\e[0m"\e[0m,
502
584
  \e[0m \e[34m: \e[1m4\e[0m,
503
- \e[0m \e[36m{ \e[1m5\e[0m
585
+ \e[0m \e[36m. \e[1m5\e[0m,
586
+ \e[0m \e[36m{ \e[1m6\e[0m
504
587
  \e[0m]
505
- Where, \e[31m- \e[1m1 missing\e[0m, \e[33m+ \e[1m1 additional\e[0m, \e[32m~ \e[1m1 match_regexp\e[0m, \e[34m: \e[1m1 match_class\e[0m, \e[36m{ \e[1m1 match_proc\e[0m
588
+ Where, \e[31m- \e[1m1 missing\e[0m, \e[33m+ \e[1m1 additional\e[0m, \e[32m~ \e[1m1 match_regexp\e[0m, \e[34m: \e[1m1 match_class\e[0m, \e[36m. \e[1m1 match_range\e[0m, \e[36m{ \e[1m1 match_proc\e[0m
506
589
  EOF
507
590
 
508
591
  context "on a white background" do
@@ -513,9 +596,10 @@ describe "DiffMatcher::difference(expected, actual, opts)" do
513
596
  \e[0m 2,
514
597
  \e[0m \e[32m~ \e[0m"\e[32m(\e[1m3\e[0m\e[32m)\e[0m"\e[0m,
515
598
  \e[0m \e[34m: \e[1m4\e[0m,
516
- \e[0m \e[36m{ \e[1m5\e[0m
599
+ \e[0m \e[36m. \e[1m5\e[0m,
600
+ \e[0m \e[36m{ \e[1m6\e[0m
517
601
  \e[0m]
518
- Where, \e[31m- \e[1m1 missing\e[0m, \e[35m+ \e[1m1 additional\e[0m, \e[32m~ \e[1m1 match_regexp\e[0m, \e[34m: \e[1m1 match_class\e[0m, \e[36m{ \e[1m1 match_proc\e[0m
602
+ Where, \e[31m- \e[1m1 missing\e[0m, \e[35m+ \e[1m1 additional\e[0m, \e[32m~ \e[1m1 match_regexp\e[0m, \e[34m: \e[1m1 match_class\e[0m, \e[36m. \e[1m1 match_range\e[0m, \e[36m{ \e[1m1 match_proc\e[0m
519
603
  EOF
520
604
  end
521
605
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: diff_matcher
3
3
  version: !ruby/object:Gem::Version
4
- hash: 9
4
+ hash: 7
5
5
  prerelease:
6
6
  segments:
7
7
  - 2
8
- - 1
9
- - 1
10
- version: 2.1.1
8
+ - 2
9
+ - 0
10
+ version: 2.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Playup
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-01-13 00:00:00 +11:00
18
+ date: 2012-01-19 00:00:00 +11:00
19
19
  default_executable:
20
20
  dependencies: []
21
21