README.md in diff_matcher-2.3.3 vs README.md in diff_matcher-2.4.0

- old
+ new

@@ -2,31 +2,34 @@ === [![build status](http://travis-ci.org/playup/diff_matcher.png)](http://travis-ci.org/playup/diff_matcher) [![still maintained](http://stillmaintained.com/playupchris/diff_matcher.png)](http://stillmaintained.com/playupchris/diff_matcher) -Generates a diff by matching against expected values, classes, regexes and/or procs. +Generates a diff by matching against user-defined matchers written in ruby. -DiffMatcher performs recursive matches on values contained in hashes, arrays and combinations thereof. +DiffMatcher matches input data (eg. from a JSON API) against values, +ranges, classes, regexes, procs, custom matchers and/or easily composed, +nested combinations thereof to produce an easy to read diff string. -Values in a containing object match when: +Actual input values are matched against expected matchers in the following way: ``` ruby actual.is_a? expected # when expected is a class expected.match actual # when expected is a regexp expected.call actual # when expected is a proc actual == expected # when expected is anything else +expected.diff actual # when expected is a built-in DiffMatcher ``` -Example: +Using these building blocks, more complicated nested matchers can be +composed. +eg. ``` ruby -puts DiffMatcher::difference( - { :a=>{ :a1=>11 }, :b=>[ 21, 22 ], :c=>/\d/, :d=>Fixnum, :e=>lambda { |x| (4..6).include? x } }, - { :a=>{ :a1=>10, :a2=>12 }, :b=>[ 21 ], :c=>'3' , :d=>4 , :e=>5 }, - :color_scheme=>:white_background -) +expected = { :a=>{ :a1=>11 }, :b=>[ 21, 22 ], :c=>/\d/, :d=>Fixnum, :e=>lambda { |x| (4..6).include? x } }, +actual = { :a=>{ :a1=>10, :a2=>12 }, :b=>[ 21 ], :c=>'3' , :d=>4 , :e=>5 }, +puts DiffMatcher::difference(expected, actual, :color_scheme=>:white_background) ``` ![example output](https://raw.github.com/playup/diff_matcher/master/doc/diff_matcher.gif) @@ -40,195 +43,238 @@ --- ``` ruby require 'diff_matcher' -DiffMatcher::difference(actual, expected, opts={}) +DiffMatcher::difference(expected, actual, opts={}) ``` -When `expected` != `actual` +#### Simple matchers -``` ruby -puts DiffMatcher::difference(1, 2) -# => - 1+ 2 -# => Where, - 1 missing, + 1 additional +Using plain ruby objects produces the following diffs: ``` ++-------------+--------+-------------+ +| expected | actual | diff | ++-------------+--------+-------------+ +| 1 | 2 | - 1+ 2 | +| 1 | 1 | | +| String | 1 | - String+ 1 | +| String | "1" | | +| /[a-z]/ | 1 | -/[a-z]/+ 1 | +| /[a-z]/ | "a" | | +| 1..3 | 4 | - 1..3+ 4 | +| 1..3 | 3 | | +| is_boolean | true | | ++-------------+--------+-------------+ -When `expected` == `actual` - -``` ruby -p DiffMatcher::difference(1, 1) -# => nil +Where: + is_boolean = lambda { |x| [FalseClass, TrueClass].include? x.class } ``` -When `actual` is an instance of the `expected` - -``` ruby -p DiffMatcher::difference(String, '1') -# => nil -``` - -When `actual` is a string that matches the `expected` regex - -``` ruby -p DiffMatcher::difference(/[a-z]/, "a") -# => nil -``` - -When `actual` is a fixnum that matches the `expected` range - -``` ruby -p DiffMatcher::difference(1..3, 3) -# => nil -``` - -When `actual` is passed to an `expected` proc and it returns true - -``` ruby -is_boolean = lambda { |x| [FalseClass, TrueClass].include? x.class } -p DiffMatcher::difference(is_boolean, true) -# => nil -``` - When `actual` is missing one of the `expected` values ``` ruby -puts DiffMatcher::difference([1, 2], [1]) +expected = [1, 2] +puts DiffMatcher::difference(expected, [1]) # => [ # => 1 # => - 2 # => ] # => Where, - 1 missing ``` When `actual` has additional values to the `expected` ``` ruby -puts DiffMatcher::difference([1], [1, 2]) +expected = [1] +puts DiffMatcher::difference(expected, [1, 2]) # => [ # => 1 # => + 2 # => ] # => Where, + 1 additional ``` -When `expected` is a `Hash` with optional keys use a `Matcher`. +#### More complicated matchers +Sometimes you'll need to wrap plain ruby objects with DiffMatcher's +built-in matchers, to provide extra matching abilities. + +When `expected` is a `Hash`, but has optional keys, wrap the `Hash` with +a built-in `Matcher` + ``` ruby -puts DiffMatcher::difference( - DiffMatcher::Matcher.new({:name=>String, :age=>Fixnum}, :optional_keys=>[:age]), - {:name=>0} -) -{ - :name=>- String+ 0 -} -Where, - 1 missing, + 1 additional +exp = {:name=>String, :age=>Fixnum} +expected = DiffMatcher::Matcher.new(exp, :optional_keys=>[:age]) +puts DiffMatcher::difference(expected, {:name=>0}) +# => { +# => :name=>- String+ 0 +# => } +# => Where, - 1 missing, + 1 additional ``` +When multiple `expected` values can be matched against, simply wrap them +in `Matcher`s and `||` them together -When `expected` can take multiple forms use some `Matcher`s `||`ed together. - ``` ruby -puts DiffMatcher::difference(DiffMatcher::Matcher.new(Fixnum) || DiffMatcher.new(Float), "3") -- Float+ "3" -Where, - 1 missing, + 1 additional +exp1 = Fixnum +exp2 = Float +expected = DiffMatcher::Matcher.new(exp1) || DiffMatcher::Matcher.new(exp2) +puts DiffMatcher::difference(expected, "3") +# => - Float+ "3" +# => Where, - 1 missing, + 1 additional ``` -(NB. `DiffMatcher::Matcher[Fixnum, Float]` can be used as a shortcut for - `DiffMatcher::Matcher.new(Fixnum) || DiffMatcher.new(Float)` -) +Or to do the same thing using a shorter syntax +``` ruby +exp1 = Fixnum +exp2 = Float +expected = DiffMatcher::Matcher[exp1, exp2] +puts DiffMatcher::difference(expected, "3") +# => - Float+ "3" +# => Where, - 1 missing, + 1 additional +``` + When `actual` is an array of *unknown* size use an `AllMatcher` to match -against *all* the elements in the array. +against *all* the elements in the array ``` ruby -puts DiffMatcher::difference(DiffMatcher::AllMatcher.new(Fixnum), [1, 2, "3"]) -[ - : 1, - : 2, - - Fixnum+ "3" -] -Where, - 1 missing, + 1 additional, : 2 match_class +exp = Fixnum +expected = DiffMatcher::AllMatcher.new(exp) +puts DiffMatcher::difference(expected, [1, 2, "3"]) +# => [ +# => : 1, +# => : 2, +# => - Fixnum+ "3" +# => ] +# => Where, - 1 missing, + 1 additional, : 2 match_class ``` When `actual` is an array with a *limited* size use an `AllMatcher` to match against *all* the elements in the array adhering to the limits of `:min` and or `:max` or `:size` (where `:size` is a Fixnum or range of Fixnum). ``` ruby -puts DiffMatcher::difference(DiffMatcher::AllMatcher.new(Fixnum, :min=>3), [1, 2]) -[ - : 1, - : 2, - - Fixnum -] -Where, - 1 missing, : 2 match_class +exp = Fixnum +expected = DiffMatcher::AllMatcher.new(exp, :min=>3) +puts DiffMatcher::difference(expected, [1, 2]) +# => [ +# => : 1, +# => : 2, +# => - Fixnum +# => ] +# => Where, - 1 missing, : 2 match_class ``` ``` ruby -puts DiffMatcher::difference(DiffMatcher::AllMatcher.new(Fixnum, :size=>3..5), [1, 2]) -[ - : 1, - : 2, - - Fixnum -] -Where, - 1 missing, : 2 match_class +exp = Fixnum +expected = DiffMatcher::AllMatcher.new(exp, :size=>3..5) +puts DiffMatcher::difference(expected, [1, 2]) +# => [ +# => : 1, +# => : 2, +# => - Fixnum +# => ] +# => Where, - 1 missing, : 2 match_class ``` When `actual` is an array of unknown size *and* `expected` can take -multiple forms use a `Matcher` inside of an `AllMatcher` to match -against *all* the elements in the array in any of the forms. +multiple forms use a `Matcher` to `||` them together, then wrap that +with an `AllMatcher` to match against *all* the elements in the array in +any of the forms. ``` ruby -puts DiffMatcher::difference( - DiffMatcher::AllMatcher.new( - DiffMatcher::Matcher[Fixnum, Float] - ), - [1, 2.00, "3"] -) -[ - | 1, - | 2.0, - - Float+ "3" -] -Where, - 1 missing, + 1 additional, | 2 match_matcher +exp1 = Fixnum +exp2 = Float +expected = DiffMatcher::AllMatcher.new( DiffMatcher::Matcher[Fixnum, Float] ) +puts DiffMatcher::difference(expected, [1, 2.00, "3"]) +# => [ +# => | 1, +# => | 2.0, +# => - Float+ "3" +# => ] +# => Where, - 1 missing, + 1 additional, | 2 match_matcher ``` -### Options +### Matcher options -`:ignore_additional=>true` will match even if `actual` has additional items +Matcher options can be passed to `DiffMatcher::difference` or `DiffMatcher::Matcher#diff` +or instances of `DiffMatcher::Matcher` +First consider: + ``` ruby -p DiffMatcher::difference([1], [1, 2], :ignore_additional=>true) +expected = DiffMatcher::Matcher.new([1]) +puts expected.diff([1, 2]) +# => [ +# => 1, +# => + 2 +# => ] +``` + +Using `:ignore_additional=>true` will now match even though `actual` has additional items. + +It can be used in the following ways: + +``` ruby +expected = DiffMatcher::Matcher.new([1]) +puts expected.diff([1, 2], :ignore_additional=>true) # => nil ``` -`:quiet=>true` shows only missing and additional items in the output +or ``` ruby -puts DiffMatcher::difference([Fixnum, 2], [1], :quiet=>true) +expected = DiffMatcher::Matcher.new([1]) +puts DiffMatcher::difference(expected, [1, 2], :ignore_additional=>true) +# => nil +``` + +or + +``` ruby +expected = DiffMatcher::Matcher.new([1], :ignore_additional=>true) +puts expected.diff([1, 2]) +# => nil +``` + +Now consider: + +``` ruby +puts DiffMatcher::Matcher.new([Fixnum, 2]).diff([1]) # => [ +# => : 1, # => - 2 # => ] -# => Where, - 1 missing ``` -`:html_output=>true` will convert ansii escape codes to html spans +Using `:quiet=>true` will only show missing and additional items in the output +``` ruby +puts DiffMatcher::Matcher.new([Fixnum, 2]).diff([1], :quiet=>true) +# => [ +# => - 2 +# => ] +``` +`:html_output=>true` will convert ansii escape colour codes to html spans + ``` ruby puts DiffMatcher::difference(1, 2, :html_output=>true) -<pre> -<span style="color:red">- <b>1</b></span><span style="color:yellow">+ <b>2</b></span> -Where, <span style="color:red">- <b>1 missing</b></span>, <span style="color:yellow">+ <b>1 additional</b></span> -</pre> +# => <pre> +# => <span style="color:red">- <b>1</b></span><span style="color:yellow">+ <b>2</b></span> +# => Where, <span style="color:red">- <b>1 missing</b></span>, <span style="color:yellow">+ <b>1 additional</b></span> +# => </pre> ``` #### Prefixes -The items shown in a difference are prefixed as follows: +A difference string is similar in appereance to the `.inspect` of plain +ruby objects, however the matched elements it contains are prefixed +in the following way: missing => "- " additional => "+ " match value => match regexp => "~ " @@ -374,15 +420,16 @@ Contributing --- -Fork, write some tests and send a pull request (bonus points for topic branches). +Think up something DiffMatcher *can't* do! :) +Fork, write some tests and send a pull request (bonus points for topic branches), or just submit an issue. Status --- -Our company is using this gem to test our JSON API which has got it to a stable v1.0.0 release. +Our company is using this gem to test our JSON API which has got above and beyond a stable v1.0.0 release. There's a [pull request](http://github.com/rspec/rspec-expectations/pull/79) to use this gem in a `be_hash_matching` [rspec matcher](https://www.relishapp.com/rspec/rspec-expectations).