ruby_diff 0.1

Sign up to get free protection for your applications and to get access to all the features.
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: