Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added support for custom formatters

  • Loading branch information...
commit de6b4f2c878ec8c118dfd0285d411bec86358ea5 1 parent 62592f6
@pvande authored
View
14 README.rdoc
@@ -69,9 +69,17 @@ If you would like something a little more inline...
Need a different output format? We've got a few of those too.
- Differ.format(:ascii) # <- Default
- Differ.format(:color)
- Differ.format(:html)
+ Differ.format = :ascii # <- Default
+ Differ.format = :color
+ Differ.format = :html
+
+ Differ.format = MyCustomFormatModule
+
+Don't want to change the system-wide default for only a single diff output?
+Yeah, me either.
+
+ @diff = (@current - @original)
+ @diff.format_as(:color)
== Copyright
View
22 lib/differ.rb
@@ -1,5 +1,8 @@
require 'differ/change'
require 'differ/diff'
+require 'differ/format/ascii'
+require 'differ/format/color'
+require 'differ/format/html'
module Differ
class << self
@@ -32,6 +35,25 @@ def diff_by_line(to, from)
diff(to, from, "\n")
end
+ def format=(f)
+ @format = format_for(f)
+ end
+
+ def format
+ return @format || Format::Ascii
+ end
+
+ def format_for(f)
+ case f
+ when Module then f
+ when :ascii then Format::Ascii
+ when :color then Format::Color
+ when :html then Format::HTML
+ when nil then nil
+ else raise "Unknown format type #{f.inspect}"
+ end
+ end
+
private
def advance(target, source)
del, add = source.shift, target.shift
View
9 lib/differ/change.rb
@@ -18,15 +18,8 @@ def change?
!@insert.empty? && !@delete.empty?
end
- def as_insert ; "+#{@insert.inspect}" ; end
- def as_delete ; "-#{@delete.inspect}" ; end
- def as_change ; "{#{@delete.inspect} >> #{@insert.inspect}}" ; end
-
def to_s
- (change? && self.as_change) ||
- (insert? && self.as_insert) ||
- (delete? && self.as_delete) ||
- ''
+ Differ.format.format(self)
end
alias :inspect :to_s
View
11 lib/differ/diff.rb
@@ -71,6 +71,17 @@ def to_s
@raw.to_s
end
+ def format_as(f)
+ f = Differ.format_for(f)
+ @raw.inject('') do |sum, part|
+ part = case part
+ when String then part
+ when Change then f.format(part)
+ end
+ sum << part
+ end
+ end
+
protected
def raw_array
@raw
View
27 lib/differ/format/ascii.rb
@@ -0,0 +1,27 @@
+module Differ
+ module Format
+ module Ascii
+ class << self
+ def format(change)
+ (change.change? && as_change(change)) ||
+ (change.delete? && as_delete(change)) ||
+ (change.insert? && as_insert(change)) ||
+ ''
+ end
+
+ private
+ def as_insert(change)
+ "{+#{change.insert.inspect}}"
+ end
+
+ def as_delete(change)
+ "{-#{change.delete.inspect}}"
+ end
+
+ def as_change(change)
+ "{#{change.delete.inspect} >> #{change.insert.inspect}}"
+ end
+ end
+ end
+ end
+end
View
27 lib/differ/format/color.rb
@@ -0,0 +1,27 @@
+module Differ
+ module Format
+ module Color
+ class << self
+ def format(change)
+ (change.change? && as_change(change)) ||
+ (change.delete? && as_delete(change)) ||
+ (change.insert? && as_insert(change)) ||
+ ''
+ end
+
+ private
+ def as_insert(change)
+ "\033[32m#{change.insert}\033[0m"
+ end
+
+ def as_delete(change)
+ "\033[31m#{change.delete}\033[0m"
+ end
+
+ def as_change(change)
+ as_delete(change) << as_insert(change)
+ end
+ end
+ end
+ end
+end
View
27 lib/differ/format/html.rb
@@ -0,0 +1,27 @@
+module Differ
+ module Format
+ module HTML
+ class << self
+ def format(change)
+ (change.change? && as_change(change)) ||
+ (change.delete? && as_delete(change)) ||
+ (change.insert? && as_insert(change)) ||
+ ''
+ end
+
+ private
+ def as_insert(change)
+ %Q{<ins class="differ">#{change.insert}</ins>}
+ end
+
+ def as_delete(change)
+ %Q{<del class="differ">#{change.delete}</del>}
+ end
+
+ def as_change(change)
+ as_delete(change) << as_insert(change)
+ end
+ end
+ end
+ end
+end
View
26 spec/differ/change_spec.rb
@@ -1,6 +1,11 @@
require 'spec_helper'
describe Differ::Change do
+ before(:each) do
+ @format = Module.new { def self.format(c); end }
+ Differ.format = @format
+ end
+
describe '(empty)' do
before(:each) do
@change = Differ::Change.new()
@@ -15,6 +20,7 @@
end
it 'should stringify to ""' do
+ @format.should_receive(:format).once.and_return('')
@change.to_s.should == ''
end
end
@@ -32,11 +38,6 @@
@change.delete.should == ''
end
- it 'should stringify via the #as_insert method' do
- @change.should_receive(:as_insert).once.and_return('FORMAT')
- @change.to_s.should == 'FORMAT'
- end
-
it { (@change).should be_an_insert }
end
@@ -53,11 +54,6 @@
@change.delete.should == 'bar'
end
- it 'should stringify via the #as_delete method' do
- @change.should_receive(:as_delete).once.and_return('FORMAT')
- @change.to_s.should == 'FORMAT'
- end
-
it { (@change).should be_a_delete }
end
@@ -74,13 +70,13 @@
@change.delete.should == 'bar'
end
- it 'should stringify via the #as_change method' do
- @change.should_receive(:as_change).once.and_return('FORMAT')
- @change.to_s.should == 'FORMAT'
- end
-
it { (@change).should be_an_insert }
it { (@change).should be_a_delete }
it { (@change).should be_a_change }
end
+
+ it "should stringify via the current format's #format method" do
+ @format.should_receive(:format).once
+ Differ::Change.new.to_s
+ end
end
View
30 spec/differ/diff_spec.rb
@@ -7,6 +7,10 @@
end
describe '#to_s' do
+ before(:each) do
+ @format = Differ.format
+ end
+
it 'should concatenate the result list' do
diff('a', 'b', 'c').to_s.should == 'abc'
end
@@ -16,22 +20,28 @@
diff('a', 'b', 'c').to_s.should == 'abc'
end
- it 'should delegate insertion changes to the Change class' do
+ it 'should delegate insertion changes to Differ#format' do
i = +'b'
- i.should_receive(:as_insert).once.and_return('!')
+ @format.should_receive(:format).once.with(i).and_return('!')
diff('a', i, 'c').to_s.should == 'a!c'
end
+ end
+
+ describe '#format_as' do
+ before(:each) do
+ @change = +'b'
+ Differ.format = Module.new { def self.format(c); raise :error; end }
+ @format = Module.new { def self.format(c); end }
+ end
- it 'should delegate deletion changes to the Change class' do
- d = -'b'
- d.should_receive(:as_delete).once.and_return('!')
- diff('a', d, 'c').to_s.should == 'a!c'
+ it 'should delegate change formatting to the given format' do
+ @format.should_receive(:format).once.with(@change).and_return('!')
+ diff('a', @change, 'c').format_as(@format).should == 'a!c'
end
- it 'should delegate replacement changes to the Change class' do
- r = ('b' >> 'd')
- r.should_receive(:as_change).once.and_return('!')
- diff('a', r, 'c').to_s.should == 'a!c'
+ it 'should use Differ#format_for to grab the correct format' do
+ Differ.should_receive(:format_for).once.with(@format)
+ diff().format_as(@format)
end
end
View
18 spec/differ/format/ascii_spec.rb
@@ -0,0 +1,18 @@
+require 'spec_helper'
+
+describe Differ::Format::Ascii do
+ it 'should format inserts well' do
+ @expected = '{+"SAMPLE"}'
+ Differ::Format::Ascii.format(+'SAMPLE').should == @expected
+ end
+
+ it 'should format deletes well' do
+ @expected = '{-"SAMPLE"}'
+ Differ::Format::Ascii.format(-'SAMPLE').should == @expected
+ end
+
+ it 'should format changes well' do
+ @expected = '{"THEN" >> "NOW"}'
+ Differ::Format::Ascii.format('THEN' >> 'NOW').should == @expected
+ end
+end
View
18 spec/differ/format/color_spec.rb
@@ -0,0 +1,18 @@
+require 'spec_helper'
+
+describe Differ::Format::Color do
+ it 'should format inserts well' do
+ @expected = "\033[32mSAMPLE\033[0m"
+ Differ::Format::Color.format(+'SAMPLE').should == @expected
+ end
+
+ it 'should format deletes well' do
+ @expected = "\033[31mSAMPLE\033[0m"
+ Differ::Format::Color.format(-'SAMPLE').should == @expected
+ end
+
+ it 'should format changes well' do
+ @expected = "\033[31mTHEN\033[0m\033[32mNOW\033[0m"
+ Differ::Format::Color.format('THEN' >> 'NOW').should == @expected
+ end
+end
View
18 spec/differ/format/html_spec.rb
@@ -0,0 +1,18 @@
+require 'spec_helper'
+
+describe Differ::Format::HTML do
+ it 'should format inserts well' do
+ @expected = '<ins class="differ">SAMPLE</ins>'
+ Differ::Format::HTML.format(+'SAMPLE').should == @expected
+ end
+
+ it 'should format deletes well' do
+ @expected = '<del class="differ">SAMPLE</del>'
+ Differ::Format::HTML.format(-'SAMPLE').should == @expected
+ end
+
+ it 'should format changes well' do
+ @expected = '<del class="differ">THEN</del><ins class="differ">NOW</ins>'
+ Differ::Format::HTML.format('THEN' >> 'NOW').should == @expected
+ end
+end
View
59 spec/differ_spec.rb
@@ -1,6 +1,65 @@
require 'spec_helper'
describe Differ do
+ describe '#format' do
+ before(:each) { Differ.format = nil }
+
+ it 'should return the last value it was set to' do
+ Differ.format = Differ::Format::HTML
+ Differ.format.should == Differ::Format::HTML
+ end
+
+ it 'should default to Differ::Format::Ascii' do
+ Differ.format.should == Differ::Format::Ascii
+ end
+ end
+
+ describe '#format=' do
+ it 'should call #format_for with the passed argument' do
+ Differ.should_receive(:format_for).with(:format).once
+ Differ.format = :format
+ end
+
+ it 'should raise an error on undefined behavior' do
+ lambda {
+ Differ.format = 'threeve'
+ }.should raise_error('Unknown format type "threeve"')
+ end
+ end
+
+ describe '#format_for' do
+ before(:each) { Differ.format = nil }
+
+ it 'should store any module passed to it' do
+ formatter = Module.new
+ Differ.format_for(formatter).should == formatter
+ end
+
+ it 'should permit nil (default behavior)' do
+ Differ.format_for(nil).should == nil
+ end
+
+ it 'should raise an error on undefined behavior' do
+ lambda {
+ Differ.format_for('threeve')
+ }.should raise_error('Unknown format type "threeve"')
+ end
+
+ describe 'when passed a symbol' do
+ it 'should translate the symbol :ascii into Differ::Format::Ascii' do
+ Differ.format_for(:ascii).should == Differ::Format::Ascii
+ end
+
+ it 'should translate the symbol :color into Differ::Format::Color' do
+ Differ.format_for(:color).should == Differ::Format::Color
+ end
+
+ it 'should translate the symbol :html into Differ::Format::HTML' do
+ Differ.format_for(:html).should == Differ::Format::HTML
+ end
+ end
+ end
+
describe '#diff_by_char' do
def diff_by_char
Differ.send(:diff_by_char, @to, @from)
Please sign in to comment.
Something went wrong with that request. Please try again.