Skip to content

Commit

Permalink
Added support for custom formatters
Browse files Browse the repository at this point in the history
  • Loading branch information
pvande committed Mar 20, 2009
1 parent 62592f6 commit de6b4f2
Show file tree
Hide file tree
Showing 13 changed files with 270 additions and 36 deletions.
14 changes: 11 additions & 3 deletions README.rdoc
Expand Up @@ -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. Need a different output format? We've got a few of those too.


Differ.format(:ascii) # <- Default Differ.format = :ascii # <- Default
Differ.format(:color) Differ.format = :color
Differ.format(:html) 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 == Copyright


Expand Down
22 changes: 22 additions & 0 deletions lib/differ.rb
@@ -1,5 +1,8 @@
require 'differ/change' require 'differ/change'
require 'differ/diff' require 'differ/diff'
require 'differ/format/ascii'
require 'differ/format/color'
require 'differ/format/html'


module Differ module Differ
class << self class << self
Expand Down Expand Up @@ -32,6 +35,25 @@ def diff_by_line(to, from)
diff(to, from, "\n") diff(to, from, "\n")
end 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 private
def advance(target, source) def advance(target, source)
del, add = source.shift, target.shift del, add = source.shift, target.shift
Expand Down
9 changes: 1 addition & 8 deletions lib/differ/change.rb
Expand Up @@ -18,15 +18,8 @@ def change?
!@insert.empty? && !@delete.empty? !@insert.empty? && !@delete.empty?
end end


def as_insert ; "+#{@insert.inspect}" ; end
def as_delete ; "-#{@delete.inspect}" ; end
def as_change ; "{#{@delete.inspect} >> #{@insert.inspect}}" ; end

def to_s def to_s
(change? && self.as_change) || Differ.format.format(self)
(insert? && self.as_insert) ||
(delete? && self.as_delete) ||
''
end end
alias :inspect :to_s alias :inspect :to_s


Expand Down
11 changes: 11 additions & 0 deletions lib/differ/diff.rb
Expand Up @@ -71,6 +71,17 @@ def to_s
@raw.to_s @raw.to_s
end 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 protected
def raw_array def raw_array
@raw @raw
Expand Down
27 changes: 27 additions & 0 deletions 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
27 changes: 27 additions & 0 deletions 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
27 changes: 27 additions & 0 deletions 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
26 changes: 11 additions & 15 deletions spec/differ/change_spec.rb
@@ -1,6 +1,11 @@
require 'spec_helper' require 'spec_helper'


describe Differ::Change do describe Differ::Change do
before(:each) do
@format = Module.new { def self.format(c); end }
Differ.format = @format
end

describe '(empty)' do describe '(empty)' do
before(:each) do before(:each) do
@change = Differ::Change.new() @change = Differ::Change.new()
Expand All @@ -15,6 +20,7 @@
end end


it 'should stringify to ""' do it 'should stringify to ""' do
@format.should_receive(:format).once.and_return('')
@change.to_s.should == '' @change.to_s.should == ''
end end
end end
Expand All @@ -32,11 +38,6 @@
@change.delete.should == '' @change.delete.should == ''
end 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 } it { (@change).should be_an_insert }
end end


Expand All @@ -53,11 +54,6 @@
@change.delete.should == 'bar' @change.delete.should == 'bar'
end 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 } it { (@change).should be_a_delete }
end end


Expand All @@ -74,13 +70,13 @@
@change.delete.should == 'bar' @change.delete.should == 'bar'
end 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_an_insert }
it { (@change).should be_a_delete } it { (@change).should be_a_delete }
it { (@change).should be_a_change } it { (@change).should be_a_change }
end end

it "should stringify via the current format's #format method" do
@format.should_receive(:format).once
Differ::Change.new.to_s
end
end end
30 changes: 20 additions & 10 deletions spec/differ/diff_spec.rb
Expand Up @@ -7,6 +7,10 @@
end end


describe '#to_s' do describe '#to_s' do
before(:each) do
@format = Differ.format
end

it 'should concatenate the result list' do it 'should concatenate the result list' do
diff('a', 'b', 'c').to_s.should == 'abc' diff('a', 'b', 'c').to_s.should == 'abc'
end end
Expand All @@ -16,22 +20,28 @@
diff('a', 'b', 'c').to_s.should == 'abc' diff('a', 'b', 'c').to_s.should == 'abc'
end end


it 'should delegate insertion changes to the Change class' do it 'should delegate insertion changes to Differ#format' do
i = +'b' 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' diff('a', i, 'c').to_s.should == 'a!c'
end 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 it 'should delegate change formatting to the given format' do
d = -'b' @format.should_receive(:format).once.with(@change).and_return('!')
d.should_receive(:as_delete).once.and_return('!') diff('a', @change, 'c').format_as(@format).should == 'a!c'
diff('a', d, 'c').to_s.should == 'a!c'
end end


it 'should delegate replacement changes to the Change class' do it 'should use Differ#format_for to grab the correct format' do
r = ('b' >> 'd') Differ.should_receive(:format_for).once.with(@format)
r.should_receive(:as_change).once.and_return('!') diff().format_as(@format)
diff('a', r, 'c').to_s.should == 'a!c'
end end
end end


Expand Down
18 changes: 18 additions & 0 deletions 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
18 changes: 18 additions & 0 deletions 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
18 changes: 18 additions & 0 deletions 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

0 comments on commit de6b4f2

Please sign in to comment.