Need diffs in your ruby app? Diffy has you covered. It provides a convenient way to generate a diff from two strings or files. Instead of reimplementing the LCS diff algorithm Diffy uses battle tested Unix diff to generate diffs, and focuses on providing a convenient interface, and getting out of your way.
It provides several built in format options which can be passed to
Diffy::Diff#to_s.
:text- Plain text output:color- ANSI colorized text suitable for use in a terminal:html- HTML output. Since version 2.0 this format does inline highlighting of the changes between two the changes within lines.:html_simple- HTML output without inline highlighting. This may be useful in situations where high performance is required or simpler output is desired.
A default format can be set like so:
Diffy::Diff.default_format = :html
sudo gem install diffy
Here's an example of using Diffy to diff two strings
$ irb
>> string1 = <<-TXT
>" Hello how are you
>" I'm fine
>" That's great
>" TXT
=> "Hello how are you\nI'm fine\nThat's great\n"
>> string2 = <<-TXT
>" Hello how are you?
>" I'm fine
>" That's swell
>" TXT
=> "Hello how are you?\nI'm fine\nThat's swell\n"
>> puts Diffy::Diff.new(string1, string2)
-Hello how are you
+Hello how are you?
I'm fine
-That's great
+That's swell
Outputing the diff as html is easy too. Here's an example using the
:html_simple formatter.
>> puts Diffy::Diff.new(string1, string2).to_s(:html_simple)
<div class="diff">
<ul>
<li class="del"><del>Hello how are you</del></li>
<li class="ins"><ins>Hello how are you?</ins></li>
<li class="unchanged"><span>I'm fine</span></li>
<li class="del"><del>That's great</del></li>
<li class="ins"><ins>That's swell</ins></li>
</ul>
</div>
The :html formatter will give you inline highlighting a la github.
>> puts Diffy::Diff.new("foo\n", "Foo\n").to_s(:html)
<div class="diff">
<ul>
<li class="del"><del><strong>f</strong>oo</del></li>
<li class="ins"><ins><strong>F</strong>oo</ins></li>
</ul>
</div>
There's some pretty nice css provided in Diffy::CSS.
>> puts Diffy::CSS
.diff{overflow:auto;}
.diff ul{background:#fff;overflow:auto;font-size:13px;list-style:none;margin:0;padding:0;display:table;width:100%;}
.diff del, .diff ins{display:block;text-decoration:none;}
.diff li{padding:0; display:table-row;margin: 0;height:1em;}
.diff li.ins{background:#dfd; color:#080}
.diff li.del{background:#fee; color:#b00}
.diff li:hover{background:#ffc}
/* try 'whitespace:pre;' if you don't want lines to wrap */
.diff del, .diff ins, .diff span{white-space:pre-wrap;font-family:courier;}
.diff del strong{font-weight:normal;background:#fcc;}
.diff ins strong{font-weight:normal;background:#9f9;}
.diff li.diff-comment { display: none; }
.diff li.diff-block-info { background: none repeat scroll 0 0 gray; }
You can diff files instead of strings by using the :source option.
>> puts Diffy::Diff.new('/tmp/foo', '/tmp/bar', :source => 'files')
By default diffy removes the superfluous diff output. This is because its
default is to show the complete diff'ed file (diff -U 10000 is the default).
Diffy does support full output, just use the :include_diff_info => true
option when initializing:
>> Diffy::Diff.new("foo\nbar\n", "foo\nbar\nbaz\n", :include_diff_info => true).to_s(:text)
=>--- /Users/chaffeqa/Projects/stiwiki/tmp/diffy20111116-82153-ie27ex 2011-11-16 20:16:41.000000000 -0500
+++ /Users/chaffeqa/Projects/stiwiki/tmp/diffy20111116-82153-wzrhw5 2011-11-16 20:16:41.000000000 -0500
@@ -1,2 +1,3 @@
foo
bar
+baz
And even deals a bit with the formatting!
By default Diffy doesn't include the +, -, and at the beginning of line for
HTML output.
You can use the :include_plus_and_minus_in_html option to include those
symbols in the output.
>> puts Diffy::Diff.new(string1, string2, :include_plus_and_minus_in_html => true).to_s(:html_simple)
<div class="diff">
<ul>
<li class="del"><del><span class="symbol">-</span>Hello how are you</del></li>
<li class="ins"><ins><span class="symbol">+</span>Hello how are you?</ins></li>
<li class="unchanged"><span class="symbol"> </span><span>I'm fine</span></li>
<li class="del"><del><span class="symbol">-</span>That's great</del></li>
<li class="ins"><ins><span class="symbol">+</span>That's swell</ins></li>
</ul>
</div>
You can use the :diff option to override the command line options that are
passed to unix diff. They default to -U 10000.
>> puts Diffy::Diff.new(" foo\nbar\n", "foo\nbar\n", :diff => "-w")
foo
bar
You can set the default options for new Diffy::Diffs using the
Diffy::Diff.default_options and Diffy::Diff.default_options= methods.
Options passed to Diffy::Diff.new will be merged into the default options.
>> Diffy::Diff.default_options
=> {:diff=>"-U 10000", :source=>"strings", :include_diff_info=>false, :include_plus_and_minus_in_html=>false}
>> Diffy::Diff.default_options.merge!(:source => 'files')
=> {:diff=>"-U 10000", :source=>"files", :include_diff_info=>false, :include_plus_and_minus_in_html=>false}
Diffy tries to make generating your own custom formatted output easy.
Diffy::Diff provides an enumberable interface which lets you iterate over
lines in the diff.
>> Diffy::Diff.new("foo\nbar\n", "foo\nbar\nbaz\n").each do |line|
>* case line
>> when /^\+/ then puts "line #{line.chomp} added"
>> when /^-/ then puts "line #{line.chomp} removed"
>> end
>> end
line +baz added
=> [" foo\n", " bar\n", "+baz\n"]
You can also use Diffy::Diff#each_chunk to iterate each grouping of additions,
deletions, and unchanged in a diff.
>> Diffy::Diff.new("foo\nbar\nbang\nbaz\n", "foo\nbar\nbing\nbong\n").each_chunk.to_a
=> [" foo\n bar\n", "-bang\n-baz\n", "+bing\n+bong\n"]
Use #map, #inject, or any of Enumerable's methods. Go crazy.
Support for Ruby 1.8.6 was dropped beggining at version 2.0 in order to support the chainable enumerators available in 1.8.7 and 1.9.
If you want to use Diffy and Ruby 1.8.6 then:
$ gem install diffy -v1.1.0
Report bugs or request features at http://github.com/samg/diffy/issues