diffr 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +7 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/README.md +72 -0
- data/Rakefile +26 -0
- data/diffr.gemspec +27 -0
- data/lib/diffr.rb +85 -0
- data/lib/diffr/version.rb +3 -0
- data/test/diffr_test.rb +44 -0
- data/test/helper.rb +11 -0
- metadata +110 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.9.2@diffr --create
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
Diffr
|
2
|
+
======
|
3
|
+
|
4
|
+
A simple diff utility written in Ruby. It works with single or
|
5
|
+
multi-line strings and returns an array of hashes that indicates
|
6
|
+
the line number affected and change: added, deleted, or same.
|
7
|
+
|
8
|
+
Overview
|
9
|
+
--------
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
|
13
|
+
old = "This line of document stays the same.
|
14
|
+
The dokument should be spelled correctly.
|
15
|
+
This line should be deleted."
|
16
|
+
|
17
|
+
new = "The new document has a line break!
|
18
|
+
|
19
|
+
This line of document stays the same.
|
20
|
+
The document should be spelled correctly.
|
21
|
+
Finally, a brand new line."
|
22
|
+
|
23
|
+
Diff.diffs(old, new).each do |diff|
|
24
|
+
puts diff
|
25
|
+
end
|
26
|
+
|
27
|
+
# Produces:
|
28
|
+
|
29
|
+
# {:line => 1, :change => :add, :string => "The new document has a line break!"}
|
30
|
+
# {:line => 2, :change => :add, :string => ""}
|
31
|
+
# {:line => 1, :change => :same, :string => "This line of document stays the same."}
|
32
|
+
# {:line => 2, :change => :delete, :string => "The dokument should be spelled correctly."}
|
33
|
+
# {:line => 3, :change => :delete, :string => "This line should be deleted."}
|
34
|
+
# {:line => 4, :change => :add, :string => "The document should be spelled correctly."}
|
35
|
+
# {:line => 5, :change => :add, :string => "Finally, a brand new line."}
|
36
|
+
|
37
|
+
# With a little formatting, we can produce something very similar to Unix's diff (unified format):
|
38
|
+
|
39
|
+
SYMBOLS = {:add => '+', :delete => '-', :same => ' '}
|
40
|
+
|
41
|
+
Diff.diffs(old, new).each do |diff|
|
42
|
+
puts SYMBOLS[diff[:change]] + diff[:string]
|
43
|
+
end
|
44
|
+
|
45
|
+
# Produces:
|
46
|
+
|
47
|
+
# +The new document has a line break!
|
48
|
+
# +
|
49
|
+
# This line of document stays the same.
|
50
|
+
# -The dokument should be spelled correctly.
|
51
|
+
# -This line should be deleted.
|
52
|
+
# +The document should be spelled correctly.
|
53
|
+
# +Finally, a brand new line.
|
54
|
+
|
55
|
+
```
|
56
|
+
|
57
|
+
Installing Diffr
|
58
|
+
----------------
|
59
|
+
|
60
|
+
### In a Ruby app, as a gem
|
61
|
+
|
62
|
+
First install the gem.
|
63
|
+
|
64
|
+
$ gem install diffr
|
65
|
+
|
66
|
+
Next include it in your application.
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
|
70
|
+
require 'diffr'
|
71
|
+
|
72
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rake/testtask'
|
5
|
+
task :default => :test
|
6
|
+
|
7
|
+
desc 'Run tests (default)'
|
8
|
+
Rake::TestTask.new(:test) do |t|
|
9
|
+
t.test_files = FileList['test/**/*_test.rb']
|
10
|
+
t.ruby_opts = ['-Itest']
|
11
|
+
t.libs << "lib" << "test"
|
12
|
+
t.ruby_opts << '-rubygems' if defined? Gem
|
13
|
+
end
|
14
|
+
|
15
|
+
if ENV['RAILS_ENV']=='development' # yard gem is only in development
|
16
|
+
YARD::Rake::YardocTask.new do |t|
|
17
|
+
t.files = ['lib/**/*.rb']
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
namespace :docs do
|
22
|
+
desc 'Generate documentation for the appliaction with Yard'
|
23
|
+
task :yard do
|
24
|
+
system("yardoc 'lib/**/*.rb' - README.md")
|
25
|
+
end
|
26
|
+
end
|
data/diffr.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "diffr/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "diffr"
|
7
|
+
s.version = Diffr::VERSION
|
8
|
+
s.authors = ["Matt Sears"]
|
9
|
+
s.email = ["matt@mattsears.com"]
|
10
|
+
s.homepage = "http://www.mattsears.com"
|
11
|
+
s.summary = %q{A simple diff utility written in Ruby}
|
12
|
+
s.description = %q{A simple utility that returns the differences between two objects}
|
13
|
+
|
14
|
+
s.rubyforge_project = "diffr"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
s.add_development_dependency "simplecov"
|
23
|
+
s.add_development_dependency "minitest"
|
24
|
+
s.add_development_dependency "yard"
|
25
|
+
s.add_development_dependency "rdiscount"
|
26
|
+
# s.add_runtime_dependency "rest-client"
|
27
|
+
end
|
data/lib/diffr.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require "diffr/version"
|
2
|
+
#
|
3
|
+
# == Diffr Module
|
4
|
+
#
|
5
|
+
# A simple utility that returns the differences between two strings
|
6
|
+
#
|
7
|
+
# == Examples:
|
8
|
+
#
|
9
|
+
# @old = "This line of document stays the same.
|
10
|
+
# The dokument should be spelled correctly.
|
11
|
+
# This line should be deleted."
|
12
|
+
#
|
13
|
+
# @new = "The new document has a line break!
|
14
|
+
#
|
15
|
+
# This line of document stays the same.
|
16
|
+
# The document should be spelled correctly.
|
17
|
+
# Finally, a brand new line."
|
18
|
+
#
|
19
|
+
# Diff.diffs(old, new)
|
20
|
+
#
|
21
|
+
# Produces:
|
22
|
+
# [ {:source=>:new, :line=>1, :change=>:add, :string=>"The new document has a line break!"},
|
23
|
+
# {:source=>:new, :line=>2, :change=>:add, :string=>""},
|
24
|
+
# {:source=>:old, :line=>1, :change=>:same, :string=>"This line of document stays the same."},
|
25
|
+
# {:source=>:old, :line=>2, :change=>:delete, :string=>"The dokument should be spelled correctly."},
|
26
|
+
# {:source=>:old, :line=>3, :change=>:delete, :string=>"This line should be deleted."},
|
27
|
+
# {:source=>:new, :line=>4, :change=>:add, :string=>"The document should be spelled correctly."},
|
28
|
+
# {:source=>:new, :line=>5, :change=>:add, :string=>"Finally, a brand new line."} ]
|
29
|
+
#
|
30
|
+
module Diffr
|
31
|
+
attr_accessor :diffs, :sequences
|
32
|
+
|
33
|
+
# Returns an array of hashes that contain metadata about the differences
|
34
|
+
# between the two given strings.
|
35
|
+
#
|
36
|
+
# @return [Array] of diffs
|
37
|
+
#
|
38
|
+
def self.diffs(old, new)
|
39
|
+
new, old, @diffs = new.lines.to_a, old.lines.to_a, []
|
40
|
+
build_sequences(old, new)
|
41
|
+
find_diffs(old, new, old.size, new.size)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
# Backtrace through the sequences and determine what changed between the old
|
47
|
+
# string and new string
|
48
|
+
#
|
49
|
+
# @return [Array] of diffs
|
50
|
+
#
|
51
|
+
def self.find_diffs(old, new, row, col)
|
52
|
+
if row > 0 && col > 0 && old[row-1] == new[col-1]
|
53
|
+
find_diffs(old, new, row-1, col-1)
|
54
|
+
@diffs << { :source => :old, :line => row, :change => :same, :string => old[row-1].strip }
|
55
|
+
elsif col > 0 && (row == 0 || @sequences[row][col-1] >= @sequences[row-1][col])
|
56
|
+
find_diffs(old, new, row, col-1)
|
57
|
+
@diffs << { :source => :new, :line => col, :change => :add, :string => new[col-1].strip }
|
58
|
+
elsif row > 0 && (col == 0 || @sequences[row][col-1] < @sequences[row-1][col])
|
59
|
+
find_diffs(old, new, row-1, col)
|
60
|
+
@diffs << { :source => :old, :line => row, :change => :delete, :string => old[row-1].strip }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Build a sequence matrix by finding the sequence of items that is present in
|
65
|
+
# both original string in the same order. That is, find a new sequence which
|
66
|
+
# can be obtained from the first sequence by deleting some items, and from the
|
67
|
+
# second sequence by deleting other items.
|
68
|
+
#
|
69
|
+
# @return [Array] of sequences
|
70
|
+
#
|
71
|
+
def self.build_sequences(old, new)
|
72
|
+
rows, cols = old.size+1, new.size+1
|
73
|
+
@sequences = rows.times.map{|x|[0]*(x+1)}
|
74
|
+
rows.times.each do |row|
|
75
|
+
cols.times.each do |col|
|
76
|
+
@sequences[row][col] = if old[row-1] == new[col-1]
|
77
|
+
@sequences[row-1][col-1] + 1
|
78
|
+
else
|
79
|
+
[@sequences[row][col-1].to_i, @sequences[row-1][col].to_i].max
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
data/test/diffr_test.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Diffr do
|
4
|
+
|
5
|
+
describe "how do two strings diffr?" do
|
6
|
+
|
7
|
+
it "should return an array diffs for single line strings" do
|
8
|
+
Diffr.diffs("this is an old string", "this is a new string").must_equal [
|
9
|
+
{:source=>:old, :line=>1, :change=>:delete, :string=>"this is an old string"},
|
10
|
+
{:source=>:new, :line=>1, :change=>:add, :string=>"this is a new string"}
|
11
|
+
]
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "with multiline strings" do
|
15
|
+
before do
|
16
|
+
@old_text = <<-END.gsub(/^ {6}/, '')
|
17
|
+
This line of document stays the same.
|
18
|
+
The dokument should be spelled correctly.
|
19
|
+
This line should be deleted.
|
20
|
+
END
|
21
|
+
@new_text = <<-END.gsub(/^ {6}/, '')
|
22
|
+
The new document has a line break!
|
23
|
+
|
24
|
+
This line of document stays the same.
|
25
|
+
The document should be spelled correctly.
|
26
|
+
Finally, a brand new line.
|
27
|
+
END
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should return the diffs for each line" do
|
31
|
+
Diffr.diffs(@old_text, @new_text).must_equal [
|
32
|
+
{:source=>:new, :line=>1, :change=>:add, :string=>"The new document has a line break!"},
|
33
|
+
{:source=>:new, :line=>2, :change=>:add, :string=>""},
|
34
|
+
{:source=>:old, :line=>1, :change=>:same, :string=>"This line of document stays the same."},
|
35
|
+
{:source=>:old, :line=>2, :change=>:delete, :string=>"The dokument should be spelled correctly."},
|
36
|
+
{:source=>:old, :line=>3, :change=>:delete, :string=>"This line should be deleted."},
|
37
|
+
{:source=>:new, :line=>4, :change=>:add, :string=>"The document should be spelled correctly."},
|
38
|
+
{:source=>:new, :line=>5, :change=>:add, :string=>"Finally, a brand new line."}
|
39
|
+
]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
data/test/helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: diffr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Matt Sears
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-08-24 00:00:00 -04:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: simplecov
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
25
|
+
type: :development
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: "0"
|
36
|
+
type: :development
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: yard
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: rdiscount
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
type: :development
|
59
|
+
version_requirements: *id004
|
60
|
+
description: A simple utility that returns the differences between two objects
|
61
|
+
email:
|
62
|
+
- matt@mattsears.com
|
63
|
+
executables: []
|
64
|
+
|
65
|
+
extensions: []
|
66
|
+
|
67
|
+
extra_rdoc_files: []
|
68
|
+
|
69
|
+
files:
|
70
|
+
- .gitignore
|
71
|
+
- .rvmrc
|
72
|
+
- Gemfile
|
73
|
+
- README.md
|
74
|
+
- Rakefile
|
75
|
+
- diffr.gemspec
|
76
|
+
- lib/diffr.rb
|
77
|
+
- lib/diffr/version.rb
|
78
|
+
- test/diffr_test.rb
|
79
|
+
- test/helper.rb
|
80
|
+
has_rdoc: true
|
81
|
+
homepage: http://www.mattsears.com
|
82
|
+
licenses: []
|
83
|
+
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: "0"
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: "0"
|
101
|
+
requirements: []
|
102
|
+
|
103
|
+
rubyforge_project: diffr
|
104
|
+
rubygems_version: 1.6.2
|
105
|
+
signing_key:
|
106
|
+
specification_version: 3
|
107
|
+
summary: A simple diff utility written in Ruby
|
108
|
+
test_files:
|
109
|
+
- test/diffr_test.rb
|
110
|
+
- test/helper.rb
|