ruby_diff 0.1 → 0.1.5
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 +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
|