ruby_diff 0.1 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -1
- data/History.txt +9 -2
- data/Manifest.txt +4 -0
- data/README.txt +6 -2
- data/Rakefile +1 -1
- data/bin/ruby_diff +57 -28
- data/lib/ruby_diff.rb +2 -2
- data/lib/ruby_diff/code_comparison.rb +5 -0
- data/lib/ruby_diff/file_feeder.rb +7 -1
- data/lib/ruby_diff/git_feeder.rb +12 -30
- data/lib/ruby_diff/git_support.rb +33 -0
- data/lib/ruby_diff/git_working_dir_feeder.rb +53 -0
- data/lib/ruby_diff/structure_processor.rb +65 -3
- data/test/code_comparison_test.rb +65 -0
- data/test/file_feeder_test.rb +2 -3
- data/test/git_feeder_test.rb +2 -3
- data/test/git_working_dir_feeder_test.rb +36 -0
- data/test/structure_processor_test.rb +16 -0
- metadata +8 -2
data/.gitignore
CHANGED
data/History.txt
CHANGED
@@ -1,2 +1,9 @@
|
|
1
|
-
=== 0.
|
2
|
-
|
1
|
+
=== 0.1.5 / --
|
2
|
+
Making everything a little better:
|
3
|
+
- Merged changes from kballard to fix the git feeder
|
4
|
+
- Added support for git working directory (use --git-wd)
|
5
|
+
- Added support for multiple inputs
|
6
|
+
- Metamethods such as 'attr_reader' are now processed
|
7
|
+
|
8
|
+
=== 0.1 / 2008-06-03
|
9
|
+
Initial verison of RubyDiff
|
data/Manifest.txt
CHANGED
@@ -8,12 +8,16 @@ lib/ruby_diff.rb
|
|
8
8
|
lib/ruby_diff/code_comparison.rb
|
9
9
|
lib/ruby_diff/file_feeder.rb
|
10
10
|
lib/ruby_diff/git_feeder.rb
|
11
|
+
lib/ruby_diff/git_support.rb
|
12
|
+
lib/ruby_diff/git_working_dir_feeder.rb
|
11
13
|
lib/ruby_diff/patterns.rb
|
12
14
|
lib/ruby_diff/structure_processor.rb
|
13
15
|
ruby_diff.gemspec
|
16
|
+
test/code_comparison_test.rb
|
14
17
|
test/file_feeder_test.rb
|
15
18
|
test/git_feeder_test.rb
|
16
19
|
test/git_sample/README
|
17
20
|
test/git_sample/book.rb
|
18
21
|
test/git_sample/lib/chapter.rb
|
22
|
+
test/git_working_dir_feeder_test.rb
|
19
23
|
test/structure_processor_test.rb
|
data/README.txt
CHANGED
@@ -27,9 +27,13 @@ changes to instance methods. The API is likely to change drastically.
|
|
27
27
|
== Usage
|
28
28
|
This is likely to change a bunch, but for the moment:
|
29
29
|
ruby_diff old_file new_file
|
30
|
+
|
30
31
|
Or for git repositories, etc.
|
31
|
-
ruby_diff --git HEAD --
|
32
|
-
|
32
|
+
ruby_diff --git HEAD --git-wd
|
33
|
+
|
34
|
+
Compare three different release tags.
|
35
|
+
ruby_diff --git v0.1 --git v0.2 --git v0.3
|
36
|
+
|
33
37
|
See help for more information.
|
34
38
|
|
35
39
|
== Contact
|
data/Rakefile
CHANGED
data/bin/ruby_diff
CHANGED
@@ -1,13 +1,26 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'rubygems'
|
3
|
-
require '
|
4
|
-
require '
|
3
|
+
require 'optparse'
|
4
|
+
require 'enumerator'
|
5
|
+
|
6
|
+
# If we're loading ruby_diff directly for development,
|
7
|
+
# don't require it through rubygems. Is there a better
|
8
|
+
# way to do this?
|
9
|
+
|
10
|
+
if $0 == __FILE__
|
11
|
+
# loaded directly (dev)
|
12
|
+
require File.dirname(__FILE__)+"/../lib/ruby_diff"
|
13
|
+
else
|
14
|
+
# loaded via ruby_gems
|
15
|
+
require 'ruby_diff'
|
16
|
+
end
|
5
17
|
|
6
18
|
@options = {}
|
7
19
|
|
8
20
|
feeder_mapping = {
|
9
21
|
:file => FileFeeder,
|
10
|
-
:git => GitFeeder
|
22
|
+
:git => GitFeeder,
|
23
|
+
:git_wd => GitWorkingDirFeeder,
|
11
24
|
}
|
12
25
|
|
13
26
|
feeders = []
|
@@ -21,25 +34,35 @@ opts.separator "Specific options:"
|
|
21
34
|
opts.define_head <<-HEAD
|
22
35
|
|
23
36
|
Examples:
|
24
|
-
Changes between git HEAD and current
|
25
|
-
ruby_diff --git HEAD --
|
37
|
+
Changes between git HEAD and current working directory:
|
38
|
+
ruby_diff --git HEAD --git-wd ./
|
39
|
+
|
40
|
+
Changes between two sets of files:
|
41
|
+
ruby_diff --file old_dir --file new_dir
|
26
42
|
|
27
|
-
Changes between HEAD and previous revision:
|
28
|
-
ruby_diff --git HEAD~1 --git HEAD
|
29
43
|
HEAD
|
30
44
|
|
31
|
-
opts.on('--sexp', "Show the s expressions for each input"){
|
45
|
+
opts.on('--sexp', "Show the s expressions for each input (mostly for debugging)"){
|
32
46
|
@options[:sexp] = true
|
33
47
|
}
|
34
48
|
|
49
|
+
opts.on('--verbose', "Shows more information while processing files"){
|
50
|
+
@options[:verbose] = true
|
51
|
+
}
|
52
|
+
|
35
53
|
opts.on('--git PATH', "Use a git repository as a code source"){|path|
|
36
54
|
feeders << feeder_mapping[:git].new(path)
|
37
55
|
}
|
56
|
+
|
57
|
+
opts.on('--git-wd PATH', "Use the git working directory as a code source"){|path|
|
58
|
+
feeders << feeder_mapping[:git_wd].new(path)
|
59
|
+
}
|
60
|
+
|
38
61
|
opts.on('--file PATH', "Use a file system path as a code source"){|path|
|
39
62
|
feeders << feeder_mapping[:file].new(path)
|
40
63
|
}
|
41
64
|
|
42
|
-
opts.on_tail('-v', '--version') { puts "ruby_diff
|
65
|
+
opts.on_tail('-v', '--version') { puts "ruby_diff #{RubyDiff::VERSION}" ; exit }
|
43
66
|
opts.on_tail('-h', '--help') { puts opts; exit }
|
44
67
|
|
45
68
|
opts.parse!(ARGV)
|
@@ -49,36 +72,42 @@ ARGV.each do |path|
|
|
49
72
|
feeders << feeder_mapping[:file].new(path)
|
50
73
|
end
|
51
74
|
|
52
|
-
if feeders.length
|
75
|
+
if feeders.length < 2
|
53
76
|
puts opts
|
54
|
-
puts "
|
55
|
-
exit 1
|
56
|
-
elsif feeders.length < 2
|
57
|
-
puts opts
|
58
|
-
puts "Must supply least 2 code sources (#{feeders.length})"
|
77
|
+
puts "Must supply at least 2 code sources (found #{feeders.length})"
|
59
78
|
exit 1
|
60
79
|
end
|
61
80
|
|
62
81
|
processors = feeders.map do |feeder|
|
63
82
|
puts "#{feeder.class}: #{feeder.path}" if @options[:sexp]
|
64
|
-
processor = StructureProcessor.new
|
65
|
-
feeder.
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
83
|
+
processor = StructureProcessor.new(feeder.path)
|
84
|
+
puts "\n#{feeder.path}" if @options[:verbose]
|
85
|
+
|
86
|
+
feeder.each do |code, path|
|
87
|
+
puts path if @options[:verbose]
|
88
|
+
begin
|
89
|
+
sexp = ParseTree.new.parse_tree_for_string(code,path)
|
90
|
+
if @options[:sexp]
|
91
|
+
pp sexp
|
92
|
+
puts "--"
|
93
|
+
end
|
71
94
|
|
72
|
-
|
95
|
+
processor.process(*sexp) unless sexp.empty?
|
96
|
+
rescue Exception => ex
|
97
|
+
STDERR << "Could not parse input (#{path}):\n#{ex}"
|
98
|
+
end
|
73
99
|
end
|
74
100
|
|
75
101
|
processor
|
76
102
|
end
|
77
103
|
|
78
|
-
|
79
|
-
old_processor, new_processor = *processors
|
80
104
|
|
81
|
-
|
82
|
-
|
83
|
-
|
105
|
+
processors.each_cons(2) do |old_processor, new_processor|
|
106
|
+
if processors.length > 2 or @options[:verbose]
|
107
|
+
puts "# #{old_processor.name} to #{new_processor.name}"
|
108
|
+
end
|
109
|
+
changes = old_processor.diff(new_processor).sort_by{|c| c.signature}
|
110
|
+
changes.each do |change|
|
111
|
+
puts change.to_s
|
112
|
+
end
|
84
113
|
end
|
data/lib/ruby_diff.rb
CHANGED
@@ -11,10 +11,10 @@ require 'set'
|
|
11
11
|
require 'pp'
|
12
12
|
|
13
13
|
module RubyDiff
|
14
|
-
VERSION = "0.1"
|
14
|
+
VERSION = "0.1.5"
|
15
15
|
end
|
16
16
|
|
17
17
|
# RubyDiff
|
18
|
-
%w(code_comparison structure_processor file_feeder git_feeder).each do |name|
|
18
|
+
%w(code_comparison structure_processor file_feeder git_support git_feeder git_working_dir_feeder).each do |name|
|
19
19
|
require File.expand_path(File.dirname(__FILE__) + "/ruby_diff/#{name}")
|
20
20
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# A CodeChange represents a difference between two sets of ruby
|
2
|
+
# code. It may contain child changes.
|
1
3
|
class CodeChange
|
2
4
|
attr_reader :signature
|
3
5
|
attr_reader :operation
|
@@ -23,12 +25,15 @@ class CodeChange
|
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
28
|
+
# Compares two sets of parsed CodeObjects. A CodeComparison
|
29
|
+
# Expects sets of CodeObjects hashed by their signature.
|
26
30
|
class CodeComparison
|
27
31
|
def initialize(old_signatures, new_signatures)
|
28
32
|
@old = old_signatures
|
29
33
|
@new = new_signatures
|
30
34
|
end
|
31
35
|
|
36
|
+
# Returns the set of changes.
|
32
37
|
def changes
|
33
38
|
changes = []
|
34
39
|
seen = Set.new
|
@@ -1,3 +1,9 @@
|
|
1
|
+
# A Feeder reads in files for RubyDiff's processor to
|
2
|
+
# run over. FileFeeder reads them from the file system.
|
3
|
+
#
|
4
|
+
# Example Usage:
|
5
|
+
# ruby_diff --file old_version.rb --file new_version.rb
|
6
|
+
# ruby_diff --file old_dir/ --file new_dir
|
1
7
|
class FileFeeder
|
2
8
|
attr_accessor :files
|
3
9
|
attr_accessor :path
|
@@ -21,7 +27,7 @@ class FileFeeder
|
|
21
27
|
|
22
28
|
def each
|
23
29
|
@files.each do |file|
|
24
|
-
yield(open(file, 'r'){|io| io.read})
|
30
|
+
yield(open(file, 'r'){|io| io.read}, file)
|
25
31
|
end
|
26
32
|
end
|
27
33
|
|
data/lib/ruby_diff/git_feeder.rb
CHANGED
@@ -1,9 +1,17 @@
|
|
1
|
-
|
1
|
+
# A Feeder reads in files for RubyDiff's processor to
|
2
|
+
# run over. GitFeeder reads them from a git repository.
|
3
|
+
#
|
4
|
+
# Example Usage:
|
5
|
+
# ruby_diff --git v0.1:lib --git v0.1:lib
|
6
|
+
# ruby_diff --git HEAD^2 --git HEAD^1 --git HEAD
|
2
7
|
class GitFeeder
|
8
|
+
GitFile = Struct.new :access, :type, :hash, :name
|
9
|
+
|
3
10
|
attr_accessor :files
|
4
11
|
attr_accessor :path
|
5
12
|
|
6
13
|
include Enumerable
|
14
|
+
include GitSupport
|
7
15
|
|
8
16
|
# Expects something in the form of REV:PATH
|
9
17
|
# --git REV:[PATH]
|
@@ -27,7 +35,7 @@ class GitFeeder
|
|
27
35
|
@files = []
|
28
36
|
|
29
37
|
FileUtils.cd(@working_dir) do
|
30
|
-
git_list = git "
|
38
|
+
git_list = git "ls-tree -r #{rev}"
|
31
39
|
git_list.each_line do |line|
|
32
40
|
file = GitFile.new(*line.chomp.split(/\s+/,4))
|
33
41
|
|
@@ -42,36 +50,10 @@ class GitFeeder
|
|
42
50
|
def each
|
43
51
|
FileUtils.cd(@working_dir) do
|
44
52
|
@files.each do |file|
|
45
|
-
code = git "
|
46
|
-
yield(code)
|
53
|
+
code = git "show #{file.hash}"
|
54
|
+
yield(code, file.name)
|
47
55
|
end
|
48
56
|
end
|
49
57
|
end
|
50
|
-
|
51
|
-
def init_git(path, search_path='')
|
52
|
-
if File.exist?(File.join(path, ".git"))
|
53
|
-
# If this is the git repository
|
54
|
-
@working_dir = path
|
55
|
-
@search_path = search_path
|
56
|
-
|
57
|
-
else
|
58
|
-
next_search = File.join( File.split(path).last, search_path )
|
59
|
-
next_path = File.dirname(path)
|
60
|
-
|
61
|
-
if next_path == path # We have reached the root, and can go no further
|
62
|
-
raise "Could not find a git working directory"
|
63
|
-
else
|
64
|
-
init_git(next_path, next_search)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def git command
|
70
|
-
output = `#{command} 2>&1`.chomp
|
71
|
-
unless $?.success?
|
72
|
-
raise RuntimeError, output
|
73
|
-
end
|
74
|
-
output
|
75
|
-
end
|
76
58
|
|
77
59
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Common feeder support for working with git repositories.
|
2
|
+
module GitSupport
|
3
|
+
|
4
|
+
# Finds root of a git repository. If the repository is the parent of the
|
5
|
+
# supplied path, then the remainder is made into the search path.
|
6
|
+
def init_git(path, search_path='')
|
7
|
+
path = File.expand_path(path)
|
8
|
+
if File.exist?(File.join(path, ".git"))
|
9
|
+
# If this is the git repository
|
10
|
+
@working_dir = path
|
11
|
+
@search_path = search_path
|
12
|
+
|
13
|
+
else
|
14
|
+
next_search = File.join( File.basename(path), search_path )
|
15
|
+
next_path = File.dirname(path)
|
16
|
+
|
17
|
+
if next_path == path # We have reached the root, and can go no further
|
18
|
+
raise "Could not find a git working directory"
|
19
|
+
else
|
20
|
+
init_git(next_path, next_search)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# issues a command to git
|
26
|
+
def git command
|
27
|
+
output = `git #{command} 2>&1`.chomp
|
28
|
+
unless $?.success?
|
29
|
+
raise RuntimeError, output
|
30
|
+
end
|
31
|
+
output
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# A Feeder reads in files for RubyDiff's processor to
|
2
|
+
# run over. GitWorkingDirFeeder reads them from a git repository. Usually
|
3
|
+
# used in conjunction with the GitFeeder.
|
4
|
+
#
|
5
|
+
# Example Usage:
|
6
|
+
# ruby_diff --git v0.1:lib --git-wd lib
|
7
|
+
class GitWorkingDirFeeder
|
8
|
+
attr_accessor :files
|
9
|
+
attr_accessor :path
|
10
|
+
|
11
|
+
include Enumerable
|
12
|
+
include GitSupport
|
13
|
+
|
14
|
+
# Expects something in the form of PATH
|
15
|
+
# --file [PATH]
|
16
|
+
def initialize(path)
|
17
|
+
@path = path
|
18
|
+
|
19
|
+
path = File.expand_path(path) if path
|
20
|
+
init_git(path || '.')
|
21
|
+
@file_pattern = if @search_path == ''
|
22
|
+
"**.rb"
|
23
|
+
elsif @search_path =~ /\.rb#{File::SEPARATOR}$/
|
24
|
+
# So appending each piece into the search path during init_git
|
25
|
+
# causes the search path to always end with a /
|
26
|
+
@search_path[0...-1]
|
27
|
+
else
|
28
|
+
File.join(@search_path,"**.rb")
|
29
|
+
end
|
30
|
+
|
31
|
+
@files = []
|
32
|
+
|
33
|
+
FileUtils.cd(@working_dir) do
|
34
|
+
git_list = git "ls-files"
|
35
|
+
git_list.each_line do |line|
|
36
|
+
file = line.chomp
|
37
|
+
if File.fnmatch(@file_pattern, file)
|
38
|
+
@files << file
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
def each
|
46
|
+
FileUtils.cd(@working_dir) do
|
47
|
+
@files.each do |file|
|
48
|
+
yield(open(file, 'r'){|io| io.read}, file)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -4,7 +4,7 @@ class CodeObject
|
|
4
4
|
attr_reader :children
|
5
5
|
attr_reader :sexp
|
6
6
|
|
7
|
-
def initialize(name, parent, sexp)
|
7
|
+
def initialize(name, parent=nil, sexp=Sexp.new)
|
8
8
|
@name = name
|
9
9
|
@parent = parent
|
10
10
|
@sexp = sexp.deep_clone
|
@@ -56,14 +56,58 @@ class MethodCode < CodeObject
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
+
# Meta method support
|
60
|
+
class MetaCode < CodeObject
|
61
|
+
def initialize(name, parent, label, sexp=s() )
|
62
|
+
super(name, parent, sexp)
|
63
|
+
@label = label
|
64
|
+
end
|
65
|
+
|
66
|
+
def signature
|
67
|
+
parent_signature = self.parent ? self.parent.signature : ""
|
68
|
+
"#{parent_signature} {#{@label} #{self.name}}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class AccessorHandler
|
73
|
+
def initialize(label)
|
74
|
+
@label = label
|
75
|
+
end
|
76
|
+
|
77
|
+
def meta_codes(args_sexp, scope)
|
78
|
+
meta_codes = []
|
79
|
+
args_sexp.sexp_body.each do |arg|
|
80
|
+
if name = name_for_arg(arg)
|
81
|
+
meta_codes << MetaCode.new(name, scope, @label)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
meta_codes
|
85
|
+
end
|
86
|
+
|
87
|
+
def name_for_arg(name_sexp)
|
88
|
+
identifier = name_sexp.to_a
|
89
|
+
case identifier.first
|
90
|
+
when :lit then identifier.last
|
91
|
+
when :str then identifier.last.to_sym
|
92
|
+
else nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# StructureProcessor is a SexpProcessor which will generate a logical
|
98
|
+
# model of the ruby code. It can be fooled by metaprogramming and method
|
99
|
+
# redefinition, but in most cases should be fairly accurate.
|
59
100
|
class StructureProcessor < SexpProcessor
|
101
|
+
attr_reader :name
|
60
102
|
attr_accessor :code_objects
|
61
103
|
attr_accessor :root_objects
|
62
104
|
|
63
105
|
attr_accessor :scope_stack
|
106
|
+
attr_reader :meta_methods
|
64
107
|
|
65
|
-
def initialize
|
66
|
-
super
|
108
|
+
def initialize(name='')
|
109
|
+
super()
|
110
|
+
@name = name
|
67
111
|
self.strict = false
|
68
112
|
self.auto_shift_type = true
|
69
113
|
|
@@ -71,6 +115,11 @@ class StructureProcessor < SexpProcessor
|
|
71
115
|
@code_objects = {}
|
72
116
|
@root_objects = {}
|
73
117
|
@scope_stack = []
|
118
|
+
@meta_methods = {
|
119
|
+
:attr_accessor => AccessorHandler.new("accessor"),
|
120
|
+
:attr_writer => AccessorHandler.new("writer"),
|
121
|
+
:attr_reader => AccessorHandler.new("reader")
|
122
|
+
}
|
74
123
|
end
|
75
124
|
|
76
125
|
def process_class(exp)
|
@@ -120,6 +169,18 @@ class StructureProcessor < SexpProcessor
|
|
120
169
|
s(:sclass, exp_scope, body)
|
121
170
|
end
|
122
171
|
|
172
|
+
def process_fcall(exp)
|
173
|
+
name = exp.shift
|
174
|
+
args = process exp.shift
|
175
|
+
|
176
|
+
if meta_handler = @meta_methods[name]
|
177
|
+
meta_codes = meta_handler.meta_codes(args, self.scope)
|
178
|
+
meta_codes.each{|m| record(m)}
|
179
|
+
end
|
180
|
+
|
181
|
+
return s(:fcall, name, args)
|
182
|
+
end
|
183
|
+
|
123
184
|
def diff(other_processor)
|
124
185
|
method_diff = CodeComparison.new(self.root_objects, other_processor.root_objects).changes
|
125
186
|
end
|
@@ -141,4 +202,5 @@ class StructureProcessor < SexpProcessor
|
|
141
202
|
def scope
|
142
203
|
self.scope_stack.last
|
143
204
|
end
|
205
|
+
|
144
206
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'test/unit/testcase'
|
3
|
+
require "ruby_diff"
|
4
|
+
|
5
|
+
class CodeComparisonTestCase < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@old_objects = []
|
8
|
+
@new_objects = []
|
9
|
+
@changes = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_empty_set
|
13
|
+
assert_changes
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_removed
|
17
|
+
@old_objects << DummyCodeObject.new('m')
|
18
|
+
assert_changes 'm' => :removed
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_added
|
22
|
+
@new_objects << DummyCodeObject.new('m')
|
23
|
+
assert_changes 'm' => :added
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_changed
|
27
|
+
@old_objects << DummyCodeObject.new('m',nil,s(:a))
|
28
|
+
@new_objects << DummyCodeObject.new('m',nil,s(:b))
|
29
|
+
assert_changes 'm' => :changed
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_no_change
|
33
|
+
@old_objects << DummyCodeObject.new('m',nil,s(:a))
|
34
|
+
@new_objects << DummyCodeObject.new('m',nil,s(:a))
|
35
|
+
assert_changes
|
36
|
+
assert @changes.empty?
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
class DummyCodeObject < CodeObject
|
41
|
+
def signature
|
42
|
+
name
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def assert_changes(sig_hash={})
|
47
|
+
c = CodeComparison.new(
|
48
|
+
code_objects_by_sig(@old_objects),
|
49
|
+
code_objects_by_sig(@new_objects)
|
50
|
+
)
|
51
|
+
|
52
|
+
change_hash = {}
|
53
|
+
@changes = c.changes
|
54
|
+
@changes.each{|change| change_hash[change.signature] = change.operation}
|
55
|
+
sig_hash.each do |sig, operation|
|
56
|
+
assert_equal operation, change_hash[sig], "#{sig} should have been #{operation}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def code_objects_by_sig(code_objects)
|
61
|
+
h = {}
|
62
|
+
code_objects.each{|o| h[o.signature] = o}
|
63
|
+
h
|
64
|
+
end
|
65
|
+
end
|
data/test/file_feeder_test.rb
CHANGED
@@ -2,9 +2,8 @@ require 'test/unit'
|
|
2
2
|
require 'test/unit/testcase'
|
3
3
|
require "ruby_diff"
|
4
4
|
|
5
|
-
DIR = File.join(File.dirname(__FILE__), "git_sample")
|
6
|
-
|
7
5
|
class FileFeederTestCase < Test::Unit::TestCase
|
6
|
+
DIR = File.join(File.dirname(__FILE__), "git_sample")
|
8
7
|
|
9
8
|
def test_find_all_files
|
10
9
|
assert File.exist?(DIR)
|
@@ -26,7 +25,7 @@ class FileFeederTestCase < Test::Unit::TestCase
|
|
26
25
|
def test_files_are_suitable_for_processing
|
27
26
|
feeder = FileFeeder.new DIR
|
28
27
|
assert_nothing_raised do
|
29
|
-
sexps = feeder.map{|code| ParseTree.new.parse_tree_for_string(code)}
|
28
|
+
sexps = feeder.map{|code,name| ParseTree.new.parse_tree_for_string(code)}
|
30
29
|
|
31
30
|
sexps.each do |sexp|
|
32
31
|
assert sexp.length > 0, "Parsed code should not be empty"
|
data/test/git_feeder_test.rb
CHANGED
@@ -2,9 +2,8 @@ require 'test/unit'
|
|
2
2
|
require 'test/unit/testcase'
|
3
3
|
require "ruby_diff"
|
4
4
|
|
5
|
-
GIT_REPO = File.join(File.dirname(__FILE__), "git_sample")
|
6
|
-
|
7
5
|
class GitFeederTestCase < Test::Unit::TestCase
|
6
|
+
GIT_REPO = File.join(File.dirname(__FILE__), "git_sample")
|
8
7
|
|
9
8
|
def test_find_all_files
|
10
9
|
assert File.exist?(GIT_REPO)
|
@@ -26,7 +25,7 @@ class GitFeederTestCase < Test::Unit::TestCase
|
|
26
25
|
def test_files_are_suitable_for_processing
|
27
26
|
feeder = GitFeeder.new "HEAD:#{GIT_REPO}"
|
28
27
|
assert_nothing_raised do
|
29
|
-
sexps = feeder.map{|code| ParseTree.new.parse_tree_for_string(code)}
|
28
|
+
sexps = feeder.map{|code,name| ParseTree.new.parse_tree_for_string(code)}
|
30
29
|
|
31
30
|
sexps.each do |sexp|
|
32
31
|
assert sexp.length > 0, "Parsed code should not be empty"
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'test/unit/testcase'
|
3
|
+
require "ruby_diff"
|
4
|
+
|
5
|
+
class GitWorkingDirFeederTestCase < Test::Unit::TestCase
|
6
|
+
DIR = File.join(File.dirname(__FILE__), "git_sample")
|
7
|
+
|
8
|
+
def test_find_all_files
|
9
|
+
assert File.exist?(DIR)
|
10
|
+
feeder = GitWorkingDirFeeder.new DIR
|
11
|
+
assert_equal 2, feeder.files.length
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_find_single_file
|
15
|
+
assert File.exist?(DIR)
|
16
|
+
feeder = GitWorkingDirFeeder.new(File.join(DIR,'lib','chapter.rb'))
|
17
|
+
assert_equal 1, feeder.files.length
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_find_files_in_sub_dir
|
21
|
+
feeder = GitWorkingDirFeeder.new(File.join(DIR,'lib'))
|
22
|
+
assert_equal 1, feeder.files.length
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_files_are_suitable_for_processing
|
26
|
+
feeder = GitWorkingDirFeeder.new DIR
|
27
|
+
assert_nothing_raised do
|
28
|
+
sexps = feeder.map{|code,name| ParseTree.new.parse_tree_for_string(code)}
|
29
|
+
|
30
|
+
sexps.each do |sexp|
|
31
|
+
assert sexp.length > 0, "Parsed code should not be empty"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -63,6 +63,22 @@ class StructureProcessorTestCase < Test::Unit::TestCase
|
|
63
63
|
CODE
|
64
64
|
end
|
65
65
|
|
66
|
+
def test_reader_attribute
|
67
|
+
assert_signatures <<-CODE, ["A {reader b}"], [MetaCode]
|
68
|
+
class A
|
69
|
+
attr_reader :b
|
70
|
+
end
|
71
|
+
CODE
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_multiple_writer_attributes
|
75
|
+
assert_signatures <<-CODE, ["A {writer b}", "A {writer c}"], [MetaCode]
|
76
|
+
class A
|
77
|
+
attr_writer :b, 'c'
|
78
|
+
end
|
79
|
+
CODE
|
80
|
+
end
|
81
|
+
|
66
82
|
def assert_signatures(code, signatures, types=[MethodCode])
|
67
83
|
sexp = ParseTree.new.parse_tree_for_string(code)
|
68
84
|
processor = StructureProcessor.new()
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: ruby_diff
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version:
|
7
|
-
date: 2008-06-
|
6
|
+
version: 0.1.5
|
7
|
+
date: 2008-06-09 00:00:00 -07:00
|
8
8
|
summary: a higher level diff application for analyzing changes to ruby code
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -40,19 +40,25 @@ files:
|
|
40
40
|
- lib/ruby_diff/code_comparison.rb
|
41
41
|
- lib/ruby_diff/file_feeder.rb
|
42
42
|
- lib/ruby_diff/git_feeder.rb
|
43
|
+
- lib/ruby_diff/git_support.rb
|
44
|
+
- lib/ruby_diff/git_working_dir_feeder.rb
|
43
45
|
- lib/ruby_diff/patterns.rb
|
44
46
|
- lib/ruby_diff/structure_processor.rb
|
45
47
|
- ruby_diff.gemspec
|
48
|
+
- test/code_comparison_test.rb
|
46
49
|
- test/file_feeder_test.rb
|
47
50
|
- test/git_feeder_test.rb
|
48
51
|
- test/git_sample/README
|
49
52
|
- test/git_sample/book.rb
|
50
53
|
- test/git_sample/lib/chapter.rb
|
54
|
+
- test/git_working_dir_feeder_test.rb
|
51
55
|
- test/structure_processor_test.rb
|
52
56
|
test_files:
|
53
57
|
- test/git_feeder_test.rb
|
54
58
|
- test/file_feeder_test.rb
|
59
|
+
- test/code_comparison_test.rb
|
55
60
|
- test/structure_processor_test.rb
|
61
|
+
- test/git_working_dir_feeder_test.rb
|
56
62
|
rdoc_options:
|
57
63
|
- --main
|
58
64
|
- README.txt
|