diff_matcher 2.1.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
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