ruby_diff 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 ADDED
@@ -0,0 +1,6 @@
1
+ # Ignore gedit backup files
2
+ *~
3
+ # Ignore rubygems pkg dir
4
+ /pkg
5
+ # Ignore MacOSX .DS_Store
6
+ .DS_Store
data/History.txt ADDED
@@ -0,0 +1,2 @@
1
+ === 0.0.1 / 2008-06-03
2
+ Initial verison of RubyDiff
data/Manifest.txt ADDED
@@ -0,0 +1,19 @@
1
+ .gitignore
2
+ History.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ bin/ruby_diff
7
+ lib/ruby_diff.rb
8
+ lib/ruby_diff/code_comparison.rb
9
+ lib/ruby_diff/file_feeder.rb
10
+ lib/ruby_diff/git_feeder.rb
11
+ lib/ruby_diff/patterns.rb
12
+ lib/ruby_diff/structure_processor.rb
13
+ ruby_diff.gemspec
14
+ test/file_feeder_test.rb
15
+ test/git_feeder_test.rb
16
+ test/git_sample/README
17
+ test/git_sample/book.rb
18
+ test/git_sample/lib/chapter.rb
19
+ test/structure_processor_test.rb
data/README.txt ADDED
@@ -0,0 +1,37 @@
1
+ = RubyDiff
2
+
3
+ RubyDiff does higher level comparisons of ruby code.
4
+
5
+ When looking at large sets of changes between versions of files, it is
6
+ important to get an idea of what classes, modules, and methods change.
7
+ RubyDiff aims to reveal substantive changes to code, and let you ignore
8
+ trivial changes like whitespace being added to a document.
9
+
10
+ Code and Releases:
11
+ http://rubyforge.org/projects/rubydiff
12
+
13
+ Browse or Branch:
14
+ http://github.com/adamsanderson/ruby_diff/tree/master
15
+
16
+ RDoc for internals (a bit sparse at the moment)
17
+ http://rubydiff.rubyforge.org/
18
+
19
+ == Requirements
20
+ RubyDiff depends on ParseTree, the easiest way to get it is via ruby gems:
21
+ gem install ParseTree
22
+
23
+ == Caveats
24
+ This is just the beginnings of an experiment, so all that is captured are
25
+ changes to instance methods. The API is likely to change drastically.
26
+
27
+ == Usage
28
+ This is likely to change a bunch, but for the moment:
29
+ ruby_diff old_file new_file
30
+ Or for git repositories, etc.
31
+ ruby_diff --git HEAD --file ./
32
+
33
+ See help for more information.
34
+
35
+ == Contact
36
+ Feel free to get in touch with me:
37
+ netghost@gmail.com
data/Rakefile ADDED
@@ -0,0 +1,65 @@
1
+ require 'rubygems'
2
+ require 'hoe'
3
+ require './lib/ruby_diff.rb'
4
+
5
+ task :default => "git:changed"
6
+ task :release => "git:push"
7
+
8
+ HOE = Hoe.new('ruby_diff', RubyDiff::VERSION) do |p|
9
+ p.rubyforge_name = 'rubydiff'
10
+ p.developer('Adam Sanderson', 'netghost@gmail.com')
11
+ p.remote_rdoc_dir = '' # Release to root
12
+ p.test_globs = ['test/*_test.rb']
13
+ p.summary = "a higher level diff application for analyzing changes to ruby code"
14
+ p.extra_deps << ['ParseTree', '>= 2.0.2']
15
+ end
16
+ SPEC = HOE.spec
17
+
18
+
19
+ # Add some more dependencies to packaging:
20
+ task :package => ['git:update_manifest','git:update_manifest']
21
+
22
+ desc "Shows what has changed since the last commit"
23
+ namespace :git do
24
+ task :changed do |t|
25
+ _divider
26
+ puts "Changes since last commit:"
27
+ puts `./bin/ruby_diff --git HEAD --file ./`
28
+ _divider
29
+ end
30
+
31
+ desc "Updates the manifest to match the git repository"
32
+ task :update_manifest do |t|
33
+ `git-ls-files > Manifest.txt`
34
+ end
35
+
36
+ desc "Pushes git repository out"
37
+ task :push do |t|
38
+ ['origin', 'rubyforge'].each do |source|
39
+ puts "Pushing to #{source}..."
40
+ puts `git push #{source}`
41
+ end
42
+ end
43
+
44
+ end
45
+
46
+ desc "Exports the gemspec for this project"
47
+ task :gemspec do |t|
48
+ open("ruby_diff.gemspec",'w'){|io| io << SPEC.to_ruby}
49
+ end
50
+
51
+ namespace :github do
52
+ desc "Simulates loading the Gem on GitHub"
53
+ task :simulate_gem => :gemspec do |t|
54
+ require 'rubygems/specification'
55
+ data = File.read('ruby_diff.gemspec')
56
+ spec = nil
57
+ Thread.new { spec = eval("$SAFE = 3\n#{data}") }.join
58
+ puts spec
59
+ end
60
+ end
61
+
62
+ private
63
+ def _divider
64
+ puts "-"*(ENV['COLUMNS'] || 80).to_i
65
+ end
data/bin/ruby_diff ADDED
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'ruby_diff'
4
+ require 'optparse'
5
+
6
+ @options = {}
7
+
8
+ feeder_mapping = {
9
+ :file => FileFeeder,
10
+ :git => GitFeeder
11
+ }
12
+
13
+ feeders = []
14
+
15
+ opts = OptionParser.new
16
+ opts.banner = "Usage: ruby_diff.rb [options]"
17
+
18
+ opts.separator ""
19
+ opts.separator "Specific options:"
20
+
21
+ opts.define_head <<-HEAD
22
+
23
+ Examples:
24
+ Changes between git HEAD and current file system:
25
+ ruby_diff --git HEAD --file ./
26
+
27
+ Changes between HEAD and previous revision:
28
+ ruby_diff --git HEAD~1 --git HEAD
29
+ HEAD
30
+
31
+ opts.on('--sexp', "Show the s expressions for each input"){
32
+ @options[:sexp] = true
33
+ }
34
+
35
+ opts.on('--git PATH', "Use a git repository as a code source"){|path|
36
+ feeders << feeder_mapping[:git].new(path)
37
+ }
38
+ opts.on('--file PATH', "Use a file system path as a code source"){|path|
39
+ feeders << feeder_mapping[:file].new(path)
40
+ }
41
+
42
+ opts.on_tail('-v', '--version') { puts "ruby_diff v:0" ; exit }
43
+ opts.on_tail('-h', '--help') { puts opts; exit }
44
+
45
+ opts.parse!(ARGV)
46
+
47
+ # Map remaining options as file feeders
48
+ ARGV.each do |path|
49
+ feeders << feeder_mapping[:file].new(path)
50
+ end
51
+
52
+ if feeders.length > 2
53
+ puts opts
54
+ puts "Too many code sources (#{feeders.length})"
55
+ exit 1
56
+ elsif feeders.length < 2
57
+ puts opts
58
+ puts "Must supply least 2 code sources (#{feeders.length})"
59
+ exit 1
60
+ end
61
+
62
+ processors = feeders.map do |feeder|
63
+ puts "#{feeder.class}: #{feeder.path}" if @options[:sexp]
64
+ processor = StructureProcessor.new
65
+ feeder.each do |code|
66
+ sexp = ParseTree.new.parse_tree_for_string(code)
67
+ if @options[:sexp]
68
+ pp sexp
69
+ puts "--"
70
+ end
71
+
72
+ processor.process(*sexp)
73
+ end
74
+
75
+ processor
76
+ end
77
+
78
+
79
+ old_processor, new_processor = *processors
80
+
81
+ changes = old_processor.diff(new_processor).sort_by{|c| c.signature}
82
+ changes.each do |change|
83
+ puts change.to_s
84
+ end
data/lib/ruby_diff.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'rubygems'
2
+
3
+ # ParseTree
4
+ require 'parse_tree'
5
+ require 'sexp_processor'
6
+ require 'unified_ruby'
7
+ require 'fileutils'
8
+
9
+ # Standard library
10
+ require 'set'
11
+ require 'pp'
12
+
13
+ module RubyDiff
14
+ VERSION = "0.1"
15
+ end
16
+
17
+ # RubyDiff
18
+ %w(code_comparison structure_processor file_feeder git_feeder).each do |name|
19
+ require File.expand_path(File.dirname(__FILE__) + "/ruby_diff/#{name}")
20
+ end
@@ -0,0 +1,70 @@
1
+ class CodeChange
2
+ attr_reader :signature
3
+ attr_reader :operation
4
+ attr_reader :changes
5
+
6
+ OPERATION_CHARS = {
7
+ :added => "+",
8
+ :removed => "-",
9
+ :changed => "c",
10
+ :moved => "m" #Not used yet
11
+ }
12
+
13
+ def initialize(signature, operation, changes=[])
14
+ @signature = signature
15
+ @operation = operation
16
+ @changes = changes
17
+ end
18
+
19
+ def to_s(depth=1)
20
+ this_change = "#{OPERATION_CHARS[self.operation]}#{" "*depth}#{signature}"
21
+ sub_changes = changes.map{|c| c.to_s(depth+1)}
22
+ [this_change, sub_changes].flatten.join("\n")
23
+ end
24
+ end
25
+
26
+ class CodeComparison
27
+ def initialize(old_signatures, new_signatures)
28
+ @old = old_signatures
29
+ @new = new_signatures
30
+ end
31
+
32
+ def changes
33
+ changes = []
34
+ seen = Set.new
35
+ @old.each do |sig, code_object|
36
+ seen << sig
37
+ if other_code_object = @new[sig]
38
+ if code_object != other_code_object
39
+ changes << changed(sig, code_object, sig, other_code_object)
40
+ end
41
+ else
42
+ changes << removal(sig, code_object)
43
+ end
44
+ end
45
+
46
+ @new.each do |sig, code_object|
47
+ if !seen.include?(sig)
48
+ changes << addition(sig, code_object)
49
+ end
50
+ end
51
+
52
+ changes
53
+ end
54
+
55
+ protected
56
+ def addition(sig, code_object)
57
+ CodeChange.new(sig, :added)
58
+ end
59
+
60
+ def removal(sig, code_object)
61
+ CodeChange.new(sig, :removed)
62
+ end
63
+
64
+ def changed(old_sig, old_code_object, new_sig, new_code_object)
65
+ CodeChange.new(old_sig, :changed, CodeComparison.new(
66
+ old_code_object.child_signatures,
67
+ new_code_object.child_signatures
68
+ ).changes)
69
+ end
70
+ end
@@ -0,0 +1,28 @@
1
+ class FileFeeder
2
+ attr_accessor :files
3
+ attr_accessor :path
4
+
5
+ include Enumerable
6
+
7
+ # Expects something in the form of PATH
8
+ # --file [PATH]
9
+ def initialize(path)
10
+ @path = path
11
+
12
+ if path =~ /^\s+$/
13
+ @file_pattern = "**/*.rb"
14
+ elsif File.file? path
15
+ @file_pattern = path
16
+ else
17
+ @file_pattern = File.join(path, "**/*.rb")
18
+ end
19
+ @files = Dir[@file_pattern]
20
+ end
21
+
22
+ def each
23
+ @files.each do |file|
24
+ yield(open(file, 'r'){|io| io.read})
25
+ end
26
+ end
27
+
28
+ end
@@ -0,0 +1,77 @@
1
+ GitFile = Struct.new :access, :type, :hash, :name
2
+ class GitFeeder
3
+ attr_accessor :files
4
+ attr_accessor :path
5
+
6
+ include Enumerable
7
+
8
+ # Expects something in the form of REV:PATH
9
+ # --git REV:[PATH]
10
+ def initialize(path)
11
+ @path = path
12
+
13
+ rev,path = path.split(":",2)
14
+ raise ArgumentError.new("Must supply a git revision") unless rev
15
+ path = File.expand_path(path) if path
16
+ init_git(path || '.')
17
+ @file_pattern = if @search_path == ''
18
+ "**.rb"
19
+ elsif @search_path =~ /\.rb#{File::SEPARATOR}$/
20
+ # So appending each piece into the search path during init_git
21
+ # causes the search path to always end with a /
22
+ @search_path[0...-1]
23
+ else
24
+ File.join(@search_path,"**.rb")
25
+ end
26
+
27
+ @files = []
28
+
29
+ FileUtils.cd(@working_dir) do
30
+ git_list = git "git-ls-tree -r #{rev}"
31
+ git_list.each_line do |line|
32
+ file = GitFile.new(*line.chomp.split(/\s+/,4))
33
+
34
+ if file.type == 'blob' and File.fnmatch(@file_pattern, file.name)
35
+ @files << file
36
+ end
37
+ end
38
+ end
39
+
40
+ end
41
+
42
+ def each
43
+ FileUtils.cd(@working_dir) do
44
+ @files.each do |file|
45
+ code = git "git-show #{file.hash}"
46
+ yield(code)
47
+ end
48
+ end
49
+ 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
+
77
+ end
@@ -0,0 +1,29 @@
1
+ class SexpWildCard < SexpMatchSpecial
2
+ def === (o)
3
+ return true
4
+ end
5
+
6
+ def == (o)
7
+ return true
8
+ end
9
+
10
+ end
11
+
12
+ def _?
13
+ SexpWildCard.new
14
+ end
15
+
16
+ class Sexp
17
+ def match(pattern, &block)
18
+ if pattern == self
19
+ block.call(self)
20
+ end
21
+
22
+ self.each do |subset|
23
+ case subset
24
+ when Sexp then
25
+ subset.match(pattern, &block)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,144 @@
1
+ class CodeObject
2
+ attr_reader :name
3
+ attr_reader :parent
4
+ attr_reader :children
5
+ attr_reader :sexp
6
+
7
+ def initialize(name, parent, sexp)
8
+ @name = name
9
+ @parent = parent
10
+ @sexp = sexp.deep_clone
11
+ @children = []
12
+ if parent
13
+ parent.children << self
14
+ end
15
+ end
16
+
17
+ def signature
18
+ self.name
19
+ end
20
+
21
+ def child_signatures
22
+ h = {}
23
+ self.children.each{|c| h[c.signature] = c}
24
+ h
25
+ end
26
+
27
+ def to_s
28
+ signature
29
+ end
30
+
31
+ def ==(other)
32
+ return false unless other.class == self.class
33
+ (other.signature == self.signature) and (other.sexp == self.sexp)
34
+ end
35
+ end
36
+
37
+ class ModuleCode < CodeObject
38
+ def signature
39
+ parent_signature = self.parent ? self.parent.signature : nil
40
+ [parent_signature,self.name].compact.join('::')
41
+ end
42
+ end
43
+
44
+ class ClassCode < ModuleCode
45
+ end
46
+
47
+ class MethodCode < CodeObject
48
+ def initialize(name, parent, instance, sexp)
49
+ super(name, parent, sexp)
50
+ @instance = instance
51
+ end
52
+
53
+ def signature
54
+ parent_signature = self.parent ? self.parent.signature : ""
55
+ [parent_signature,self.name].join( @instance ? '#' : ".")
56
+ end
57
+ end
58
+
59
+ class StructureProcessor < SexpProcessor
60
+ attr_accessor :code_objects
61
+ attr_accessor :root_objects
62
+
63
+ attr_accessor :scope_stack
64
+
65
+ def initialize
66
+ super
67
+ self.strict = false
68
+ self.auto_shift_type = true
69
+
70
+ @instance_scope = true
71
+ @code_objects = {}
72
+ @root_objects = {}
73
+ @scope_stack = []
74
+ end
75
+
76
+ def process_class(exp)
77
+ name = exp.shift
78
+ super_class = exp.shift #?
79
+ body = exp.shift
80
+
81
+ record ClassCode.new(name, self.scope, body) do
82
+ s(:class, name, process(super_class), process(body))
83
+ end
84
+ end
85
+
86
+ def process_module(exp)
87
+ name = exp.shift
88
+ body = exp.shift
89
+
90
+ record ModuleCode.new(name, self.scope, body) do
91
+ s(:class, name, process(body))
92
+ end
93
+ end
94
+
95
+ def process_defn(exp)
96
+ name = exp.shift
97
+ body = process exp.shift
98
+
99
+ record MethodCode.new(name, self.scope, @instance_scope, body) do
100
+ s(:defn, name, body)
101
+ end
102
+ end
103
+
104
+ def process_defs(exp)
105
+ exp_scope = process exp.shift
106
+ name = exp.shift
107
+ body = process exp.shift
108
+
109
+ record MethodCode.new(name, self.scope, false, body) do
110
+ s(:defs, exp_scope, name, body)
111
+ end
112
+ end
113
+
114
+ def process_sclass(exp)
115
+ @instance_scope = false
116
+ exp_scope = process exp.shift
117
+ body = process exp.shift
118
+ @instance_scope = true
119
+
120
+ s(:sclass, exp_scope, body)
121
+ end
122
+
123
+ def diff(other_processor)
124
+ method_diff = CodeComparison.new(self.root_objects, other_processor.root_objects).changes
125
+ end
126
+
127
+ protected
128
+ def record obj
129
+ signature = obj.signature
130
+ if !self.code_objects[signature]
131
+ self.code_objects[signature] = obj
132
+ self.root_objects[signature] = obj if obj.parent == nil
133
+ end
134
+
135
+ self.scope_stack << self.code_objects[signature]
136
+ result = yield if block_given?
137
+ self.scope_stack.pop
138
+ result
139
+ end
140
+
141
+ def scope
142
+ self.scope_stack.last
143
+ end
144
+ end
data/ruby_diff.gemspec ADDED
@@ -0,0 +1,20 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{ruby_diff}
3
+ s.version = "0.0.1"
4
+ s.date = %q{2008-06-03}
5
+ s.summary = %q{a higher level diff application for analyzing changes to ruby code}
6
+ s.email = ["netghost@gmail.com"]
7
+ s.homepage = %q{RubyDiff does higher level comparisons of ruby code.}
8
+ s.rubyforge_project = %q{rubydiff}
9
+ s.description = %q{}
10
+ s.default_executable = %q{ruby_diff}
11
+ s.has_rdoc = true
12
+ s.authors = ["Adam Sanderson"]
13
+ s.files = [".gitignore", "README.txt", "Rakefile", "bin/ruby_diff", "lib/ruby_diff.rb", "lib/ruby_diff/code_comparison.rb", "lib/ruby_diff/file_feeder.rb", "lib/ruby_diff/git_feeder.rb", "lib/ruby_diff/patterns.rb", "lib/ruby_diff/structure_processor.rb", "ruby_diff.gemspec", "test/file_feeder_test.rb", "test/git_feeder_test.rb", "test/git_sample/README", "test/git_sample/book.rb", "test/git_sample/lib/chapter.rb", "test/structure_processor_test.rb"]
14
+ s.test_files = ["test/git_feeder_test.rb", "test/file_feeder_test.rb", "test/structure_processor_test.rb"]
15
+ s.rdoc_options = ["--main", "README.txt"]
16
+ s.extra_rdoc_files = ["README.txt"]
17
+ s.executables = ["ruby_diff"]
18
+ s.add_dependency(%q<ParseTree>, [">= 2.0.2"])
19
+ s.add_dependency(%q<hoe>, [">= 1.5.3"])
20
+ end
@@ -0,0 +1,37 @@
1
+ require 'test/unit'
2
+ require 'test/unit/testcase'
3
+ require "ruby_diff"
4
+
5
+ DIR = File.join(File.dirname(__FILE__), "git_sample")
6
+
7
+ class FileFeederTestCase < Test::Unit::TestCase
8
+
9
+ def test_find_all_files
10
+ assert File.exist?(DIR)
11
+ feeder = FileFeeder.new DIR
12
+ assert_equal 2, feeder.files.length
13
+ end
14
+
15
+ def test_find_single_file
16
+ assert File.exist?(DIR)
17
+ feeder = FileFeeder.new(File.join(DIR,'lib','chapter.rb'))
18
+ assert_equal 1, feeder.files.length
19
+ end
20
+
21
+ def test_find_files_in_sub_dir
22
+ feeder = FileFeeder.new(File.join(DIR,'lib'))
23
+ assert_equal 1, feeder.files.length
24
+ end
25
+
26
+ def test_files_are_suitable_for_processing
27
+ feeder = FileFeeder.new DIR
28
+ assert_nothing_raised do
29
+ sexps = feeder.map{|code| ParseTree.new.parse_tree_for_string(code)}
30
+
31
+ sexps.each do |sexp|
32
+ assert sexp.length > 0, "Parsed code should not be empty"
33
+ end
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,44 @@
1
+ require 'test/unit'
2
+ require 'test/unit/testcase'
3
+ require "ruby_diff"
4
+
5
+ GIT_REPO = File.join(File.dirname(__FILE__), "git_sample")
6
+
7
+ class GitFeederTestCase < Test::Unit::TestCase
8
+
9
+ def test_find_all_files
10
+ assert File.exist?(GIT_REPO)
11
+ feeder = GitFeeder.new "HEAD:#{GIT_REPO}"
12
+ assert_equal 2, feeder.files.length
13
+ end
14
+
15
+ def test_find_single_file
16
+ assert File.exist?(GIT_REPO)
17
+ feeder = GitFeeder.new(File.join("HEAD:#{GIT_REPO}",'lib','chapter.rb'))
18
+ assert_equal 1, feeder.files.length
19
+ end
20
+
21
+ def test_find_files_in_sub_dir
22
+ feeder = GitFeeder.new(File.join("HEAD:#{GIT_REPO}",'lib'))
23
+ assert_equal 1, feeder.files.length
24
+ end
25
+
26
+ def test_files_are_suitable_for_processing
27
+ feeder = GitFeeder.new "HEAD:#{GIT_REPO}"
28
+ assert_nothing_raised do
29
+ sexps = feeder.map{|code| ParseTree.new.parse_tree_for_string(code)}
30
+
31
+ sexps.each do |sexp|
32
+ assert sexp.length > 0, "Parsed code should not be empty"
33
+ end
34
+ end
35
+ end
36
+
37
+ def test_revsision_required
38
+ assert_raise RuntimeError do
39
+ GitFeeder.new "hello"
40
+ end
41
+ end
42
+
43
+
44
+ end
@@ -0,0 +1 @@
1
+ This is just a fake git repository
@@ -0,0 +1,5 @@
1
+ class Book
2
+ def chapter
3
+ # this is a silly sample
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ module Sample
2
+ class Chapter
3
+ def name= new_name
4
+ @name = new_name
5
+ end
6
+
7
+ def name
8
+ @name
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,75 @@
1
+ require 'test/unit'
2
+ require 'test/unit/testcase'
3
+ require "ruby_diff"
4
+
5
+ class StructureProcessorTestCase < Test::Unit::TestCase
6
+ def setup
7
+
8
+ end
9
+
10
+ def test_instance_method
11
+ assert_signatures <<-CODE, ["A#method_1"]
12
+ class A
13
+ def method_1
14
+ end
15
+ end
16
+ CODE
17
+ end
18
+
19
+ def test_instance_method_with_module
20
+ assert_signatures <<-CODE, ["B::A#method_1"]
21
+ module B
22
+ class A
23
+ def method_1
24
+ end
25
+ end
26
+ end
27
+ CODE
28
+ end
29
+
30
+ def test_unscoped_method
31
+ assert_signatures <<-CODE, ["#method_1"]
32
+ def method_1
33
+ end
34
+ CODE
35
+ end
36
+
37
+ def test_class_method_self
38
+ assert_signatures <<-CODE, ["A.method_1"]
39
+ class A
40
+ def self.method_1
41
+ end
42
+ end
43
+ CODE
44
+ end
45
+
46
+ def test_class_method_self_explicit
47
+ assert_signatures <<-CODE, ["A.method_1"]
48
+ class A
49
+ def A.method_1
50
+ end
51
+ end
52
+ CODE
53
+ end
54
+
55
+ def test_class_method_append_self
56
+ assert_signatures <<-CODE, ["A.method_1"]
57
+ class A
58
+ class << self
59
+ def method_1
60
+ end
61
+ end
62
+ end
63
+ CODE
64
+ end
65
+
66
+ def assert_signatures(code, signatures, types=[MethodCode])
67
+ sexp = ParseTree.new.parse_tree_for_string(code)
68
+ processor = StructureProcessor.new()
69
+ processor.process(* sexp)
70
+
71
+ found_signatures = processor.code_objects.values.select{|co| types.include?(co.class)}.map{|key| key.signature }.sort
72
+ assert_equal signatures.sort, found_signatures
73
+ end
74
+
75
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.4
3
+ specification_version: 1
4
+ name: ruby_diff
5
+ version: !ruby/object:Gem::Version
6
+ version: "0.1"
7
+ date: 2008-06-04 00:00:00 -07:00
8
+ summary: a higher level diff application for analyzing changes to ruby code
9
+ require_paths:
10
+ - lib
11
+ email:
12
+ - netghost@gmail.com
13
+ homepage: RubyDiff does higher level comparisons of ruby code.
14
+ rubyforge_project: rubydiff
15
+ description: ""
16
+ autorequire:
17
+ default_executable:
18
+ bindir: bin
19
+ has_rdoc: true
20
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
21
+ requirements:
22
+ - - ">"
23
+ - !ruby/object:Gem::Version
24
+ version: 0.0.0
25
+ version:
26
+ platform: ruby
27
+ signing_key:
28
+ cert_chain:
29
+ post_install_message:
30
+ authors:
31
+ - Adam Sanderson
32
+ files:
33
+ - .gitignore
34
+ - History.txt
35
+ - Manifest.txt
36
+ - README.txt
37
+ - Rakefile
38
+ - bin/ruby_diff
39
+ - lib/ruby_diff.rb
40
+ - lib/ruby_diff/code_comparison.rb
41
+ - lib/ruby_diff/file_feeder.rb
42
+ - lib/ruby_diff/git_feeder.rb
43
+ - lib/ruby_diff/patterns.rb
44
+ - lib/ruby_diff/structure_processor.rb
45
+ - ruby_diff.gemspec
46
+ - test/file_feeder_test.rb
47
+ - test/git_feeder_test.rb
48
+ - test/git_sample/README
49
+ - test/git_sample/book.rb
50
+ - test/git_sample/lib/chapter.rb
51
+ - test/structure_processor_test.rb
52
+ test_files:
53
+ - test/git_feeder_test.rb
54
+ - test/file_feeder_test.rb
55
+ - test/structure_processor_test.rb
56
+ rdoc_options:
57
+ - --main
58
+ - README.txt
59
+ extra_rdoc_files:
60
+ - History.txt
61
+ - Manifest.txt
62
+ - README.txt
63
+ executables:
64
+ - ruby_diff
65
+ extensions: []
66
+
67
+ requirements: []
68
+
69
+ dependencies:
70
+ - !ruby/object:Gem::Dependency
71
+ name: ParseTree
72
+ version_requirement:
73
+ version_requirements: !ruby/object:Gem::Version::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: 2.0.2
78
+ version:
79
+ - !ruby/object:Gem::Dependency
80
+ name: hoe
81
+ version_requirement:
82
+ version_requirements: !ruby/object:Gem::Version::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: 1.5.3
87
+ version: