rubydeps 0.9.1.pre → 0.9.2.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/README.md +36 -36
- data/VERSION +1 -1
- data/bin/rubydeps +5 -67
- data/ext/call_site_analyzer/call_site_analyzer.c +16 -16
- data/lib/rubydeps.rb +68 -36
- data/rubydeps.gemspec +1 -1
- data/spec/rubydeps_spec.rb +57 -62
- metadata +1 -2
- data/lib/call_site_analyzer.bundle +0 -0
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,10 @@
|
|
2
2
|
rubydeps
|
3
3
|
========
|
4
4
|
|
5
|
-
A tool to create class dependency graphs from test suites
|
5
|
+
A tool to create class dependency graphs from test suites.
|
6
|
+
|
7
|
+
I think this is more useful than static analysis of the code base because of the high dynamic aspects of the language
|
8
|
+
|
6
9
|
|
7
10
|
Sample output
|
8
11
|
-------------
|
@@ -10,60 +13,57 @@ Sample output
|
|
10
13
|
This is the result of running rubydeps on the [Rake](https://github.com/jimweirich/rake) tests:
|
11
14
|
|
12
15
|
```bash
|
13
|
-
rubydeps
|
16
|
+
rubydeps --class_name_filter='^Rake'
|
14
17
|
```
|
15
18
|
|
16
19
|
![Rake dependencies](https://github.com/dcadenas/rubydeps/raw/master/rake-deps.png)
|
17
20
|
|
21
|
+
Usage
|
22
|
+
---------------
|
18
23
|
|
19
|
-
|
20
|
-
------------------
|
24
|
+
Rubydeps will run your test suite to record the call graph of your project and use it to create a [Graphviz](http://www.graphviz.org) dot graph.
|
21
25
|
|
26
|
+
1. Add Rubydeps to your `Gemfile` and `bundle install`:
|
22
27
|
|
23
|
-
|
28
|
+
gem 'rubydeps', :group => :test
|
24
29
|
|
25
|
-
|
26
|
-
|
30
|
+
2. Launch Rubydeps by inserting this line in your `test/test_helper.rb` (*or `spec_helper.rb`, cucumber `env.rb`, or whatever
|
31
|
+
your preferred test framework uses*):
|
27
32
|
|
28
|
-
|
29
|
-
rubydeps testunit #to run Test::Unit tests
|
30
|
-
```
|
33
|
+
Rubydeps.start
|
31
34
|
|
32
|
-
or
|
35
|
+
Notice that this will slow down your tests so consider adding a conditional bound to some ENV variable or just remove the line when you are done.
|
33
36
|
|
34
|
-
|
35
|
-
rubydeps rspec #to run RSpec tests
|
36
|
-
```
|
37
|
+
3. Run your tests, a file named rubydeps.dump will be created in the project root.
|
37
38
|
|
38
|
-
|
39
|
+
4. The next step is reading the dump file to generate the graphviz dot graph `rubydeps.dot` with any filter you specify.
|
39
40
|
|
40
|
-
```bash
|
41
|
-
rubydeps
|
42
|
-
```
|
41
|
+
```bash
|
42
|
+
rubydeps --path_filter='app/models'
|
43
|
+
```
|
43
44
|
|
44
|
-
|
45
|
+
5. Now you are in [Graphviz](http://www.graphviz.org) realm. You can convert the dot file to any image format with your prefered orientations and layouts with the dot utility that comes with the graphviz installation e.g.:
|
45
46
|
|
46
|
-
```bash
|
47
|
-
dot -Tsvg rubydeps.dot > rubydeps.svg
|
48
|
-
```
|
47
|
+
```bash
|
48
|
+
dot -Tsvg rubydeps.dot > rubydeps.svg
|
49
|
+
```
|
49
50
|
|
50
|
-
Notice that sometimes you may have missing dependencies as we graph the dependencies exercised by your tests so it
|
51
|
+
Notice that sometimes you may have missing dependencies as we graph the dependencies exercised by your tests so you can use it as a quick bird's eye view of your project test coverage.
|
51
52
|
|
52
53
|
### Command line options
|
53
54
|
|
54
|
-
The `--path_filter` option specifies a regexp that matches the path of the files you are interested in analyzing. For example you could have filters like `'project_name/app|project_name/lib'` to analyze only code that is located in the `app` and `lib` dirs or as an alternative you could just exclude some directory you are not interested using a negative regexp like `'project_name(?!.*test)'`
|
55
|
+
* The `--path_filter` option specifies a regexp that matches the path of the files you are interested in analyzing. For example you could have filters like `'project_name/app|project_name/lib'` to analyze only code that is located in the `app` and `lib` dirs or as an alternative you could just exclude some directory you are not interested using a negative regexp like `'project_name(?!.*test)'`
|
55
56
|
|
56
|
-
The `--class_name_filter` option is similar to the `--path_filter` options except that the regexp is matched against the class names (i.e. graph node names).
|
57
|
+
* The `--class_name_filter` option is similar to the `--path_filter` options except that the regexp is matched against the class names (i.e. graph node names).
|
57
58
|
|
58
|
-
The `--
|
59
|
+
* The `--from_file` option is used to specify the dump file generated after the test (or block) run so you can try different filters without needing to rerun the tests. e.g.:
|
59
60
|
|
60
|
-
|
61
|
+
```bash
|
62
|
+
rubydeps --from_file='rubydeps.dump' --path_filter='app/models'
|
63
|
+
rubydeps --from_file='rubydeps.dump' --path_filter='app/models|app/controllers'
|
64
|
+
```
|
61
65
|
|
62
|
-
|
63
|
-
rubydeps rspec2 --to_file='dependencies.dump'
|
64
|
-
rubydeps --from_file='dependencies.dump' --path_filter='app/models'
|
65
|
-
rubydeps --from_file='dependencies.dump' --path_filter='app/models|app/controllers'
|
66
|
-
```
|
66
|
+
If you didn't rename the file you can skip this option as it will use the default `rubydeps.dump`
|
67
67
|
|
68
68
|
Library usage
|
69
69
|
-------------
|
@@ -73,7 +73,7 @@ Just require rubydeps and pass a block to analyze to the `analyze` method.
|
|
73
73
|
```ruby
|
74
74
|
require 'rubydeps'
|
75
75
|
|
76
|
-
Rubydeps.analyze(:path_filter => path_filter_regexp, :class_name_filter => class_name_filter_regexp, :to_file => "
|
76
|
+
Rubydeps.analyze(:path_filter => path_filter_regexp, :class_name_filter => class_name_filter_regexp, :to_file => "rubydeps.dump") do
|
77
77
|
# your code goes here
|
78
78
|
end
|
79
79
|
```
|
@@ -85,20 +85,20 @@ Installation
|
|
85
85
|
gem install rubydeps --pre
|
86
86
|
```
|
87
87
|
|
88
|
-
Rubydeps now only supports ruby 1.9. If you need 1.8.x support then:
|
88
|
+
Rubydeps now only supports ruby 1.9.x. If you need 1.8.x support then:
|
89
89
|
|
90
90
|
```bash
|
91
91
|
gem install rubydeps -v0.2.0
|
92
92
|
```
|
93
93
|
|
94
|
-
Notice that in 0.2.0 you should use dot_for instead of analyze.
|
94
|
+
Notice that in 0.2.0 you should use `dot_for` instead of `analyze` and the dump functionality is missing.
|
95
95
|
|
96
96
|
Dependencies
|
97
97
|
------------
|
98
98
|
|
99
|
-
* rcov (only for version 0.2.0)
|
100
99
|
* graphviz
|
101
100
|
* ruby-graphviz
|
101
|
+
* rcov (only for version 0.2.0)
|
102
102
|
|
103
103
|
Note on Patches/Pull Requests
|
104
104
|
-----------------------------
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.9.
|
1
|
+
0.9.2.pre
|
data/bin/rubydeps
CHANGED
@@ -4,78 +4,16 @@ require 'thor'
|
|
4
4
|
|
5
5
|
module Rubydeps
|
6
6
|
class Runner < Thor
|
7
|
-
desc "
|
8
|
-
method_option :
|
7
|
+
desc "", "Loads dependencies saved by a previous test run"
|
8
|
+
method_option :from_file, :type => :string, :default => Rubydeps.default_dump_file_name, :required => true
|
9
9
|
method_option :path_filter, :type => :string, :default => `pwd`.chomp, :required => true
|
10
10
|
method_option :class_name_filter, :type => :string, :default => '', :required => true
|
11
|
-
|
12
|
-
|
13
|
-
require 'test/unit/assertions'
|
14
|
-
require 'test/unit/testcase'
|
15
|
-
|
16
|
-
$LOAD_PATH.unshift("#{`pwd`.chomp}/lib")
|
17
|
-
|
18
|
-
#dirty hack so that minitest doesn't install the at_exit hook and we can run the tests in this same process
|
19
|
-
::MiniTest::Unit.class_variable_set("@@installed_at_exit", true)
|
20
|
-
|
21
|
-
(Dir["./test/**/*_test.rb"] + Dir["./test/**/test_*.rb"]).each { |f| load f unless f =~ /^-/ }
|
22
|
-
|
23
|
-
create_dependencies_dot_for(options) do
|
24
|
-
::MiniTest::Unit.new.run([])
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
desc "rspec", "Create the dependency graph after runnning the rspec tests"
|
29
|
-
method_option :to_file, :type => :string
|
30
|
-
#TODO: this breaks when using underscores, investigate
|
31
|
-
method_option :path_filter, :type => :string, :default => `pwd`.chomp, :required => true
|
32
|
-
method_option :class_name_filter, :type => :string, :default => '', :required => true
|
33
|
-
def rspec
|
34
|
-
require 'spec'
|
35
|
-
|
36
|
-
p = ::Spec::Runner::OptionParser.new($stderr, $stdout)
|
37
|
-
p.parse(Dir["./spec/**/*_spec.rb"])
|
38
|
-
op = p.options
|
39
|
-
|
40
|
-
create_dependencies_dot_for(options) do
|
41
|
-
::Spec::Runner::CommandLine.run(op)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
desc "", "Loads dependencies saved by a --to_file option in a previous run. Doesn't run tests"
|
46
|
-
method_option :from_file, :type => :string, :required => true
|
47
|
-
method_option :path_filter, :type => :string, :default => `pwd`.chomp, :required => true
|
48
|
-
method_option :class_name_filter, :type => :string, :default => '', :required => true
|
49
|
-
default_task :load_deps
|
50
|
-
def load_deps
|
51
|
-
create_dependencies_dot_for(options)
|
52
|
-
end
|
53
|
-
|
54
|
-
desc "rspec2", "Create the dependency graph after runnning the rspec 2 tests"
|
55
|
-
method_option :to_file, :type => :string
|
56
|
-
method_option :path_filter, :type => :string, :default => `pwd`.chomp, :required => true
|
57
|
-
method_option :class_name_filter, :type => :string, :default => '', :required => true
|
58
|
-
def rspec2
|
59
|
-
require 'rspec'
|
60
|
-
|
61
|
-
op = ::RSpec::Core::ConfigurationOptions.new(Dir["./spec/**/*_spec.rb"])
|
62
|
-
op.parse_options
|
63
|
-
|
64
|
-
create_dependencies_dot_for(options) do
|
65
|
-
::RSpec::Core::CommandLine.new(op).run($stderr, $stdout)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
def create_dependencies_dot_for(options)
|
11
|
+
default_task :create_dot
|
12
|
+
def create_dot
|
72
13
|
ARGV.clear
|
73
14
|
Rubydeps.analyze(:path_filter => Regexp.new(options[:path_filter]),
|
74
15
|
:class_name_filter => Regexp.new(options[:class_name_filter]),
|
75
|
-
:
|
76
|
-
:from_file => options[:from_file]) do
|
77
|
-
yield if block_given?
|
78
|
-
end
|
16
|
+
:from_file => options[:from_file])
|
79
17
|
end
|
80
18
|
end
|
81
19
|
end
|
@@ -116,25 +116,24 @@ static int uniq_calling_arrays(VALUE called_class, VALUE calling_class_array, VA
|
|
116
116
|
return ST_CONTINUE;
|
117
117
|
}
|
118
118
|
|
119
|
-
static VALUE
|
120
|
-
|
121
|
-
|
122
|
-
rb_global_variable(&dependency_array);
|
119
|
+
static VALUE start(VALUE self){
|
120
|
+
dependency_array = rb_ary_new();
|
121
|
+
rb_global_variable(&dependency_array);
|
123
122
|
|
124
|
-
|
125
|
-
|
123
|
+
VALUE dependency_hash = rb_hash_new();
|
124
|
+
rb_ary_push(dependency_array, dependency_hash);
|
126
125
|
|
127
|
-
|
128
|
-
|
126
|
+
VALUE class_location_hash = rb_hash_new();
|
127
|
+
rb_ary_push(dependency_array, class_location_hash);
|
129
128
|
|
130
|
-
|
131
|
-
rb_yield(Qnil);
|
132
|
-
rb_remove_event_hook(event_hook);
|
129
|
+
rb_add_event_hook(event_hook, RUBY_EVENT_CALL, Qnil);
|
133
130
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
131
|
+
return Qnil;
|
132
|
+
}
|
133
|
+
|
134
|
+
static VALUE result(VALUE self){
|
135
|
+
rb_remove_event_hook(event_hook);
|
136
|
+
rb_hash_foreach(rb_ary_entry(dependency_array, 0), uniq_calling_arrays, 0);
|
138
137
|
|
139
138
|
return dependency_array;
|
140
139
|
}
|
@@ -143,5 +142,6 @@ static VALUE rb_cCallSiteAnalyzer;
|
|
143
142
|
|
144
143
|
void Init_call_site_analyzer(){
|
145
144
|
rb_cCallSiteAnalyzer = rb_define_module("CallSiteAnalyzer");
|
146
|
-
rb_define_singleton_method(rb_cCallSiteAnalyzer, "
|
145
|
+
rb_define_singleton_method(rb_cCallSiteAnalyzer, "start", start, 0);
|
146
|
+
rb_define_singleton_method(rb_cCallSiteAnalyzer, "result", result, 0);
|
147
147
|
}
|
data/lib/rubydeps.rb
CHANGED
@@ -1,44 +1,61 @@
|
|
1
1
|
require 'graphviz'
|
2
|
-
require 'set'
|
3
2
|
require 'call_site_analyzer'
|
4
3
|
|
5
4
|
module Rubydeps
|
5
|
+
def self.start(install_at_exit = true)
|
6
|
+
CallSiteAnalyzer.start
|
7
|
+
at_exit { self.do_at_exit } if install_at_exit
|
8
|
+
end
|
9
|
+
|
6
10
|
def self.analyze(options = {}, &block_to_analyze)
|
7
11
|
dependency_hash, class_location_hash = dependency_hash_for(options, &block_to_analyze)
|
12
|
+
create_output_file(dependency_hash, class_location_hash, options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.dependency_hash_for(options = {}, &block_to_analyze)
|
16
|
+
dependency_hash, class_location_hash = calculate_or_load_dependencies(options, &block_to_analyze)
|
17
|
+
|
18
|
+
apply_filters(dependency_hash, class_location_hash, options)
|
8
19
|
|
20
|
+
[normalize_class_names(dependency_hash), class_location_hash]
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.create_output_file(dependency_hash, class_location_hash, options)
|
9
24
|
if options[:to_file]
|
10
25
|
File.open(options[:to_file], 'wb') do |f|
|
11
26
|
f.write Marshal.dump([dependency_hash, class_location_hash])
|
12
27
|
end
|
13
28
|
else
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
if !k.empty? && !vs.empty?
|
18
|
-
n1 = g.add_nodes(k.to_s)
|
19
|
-
if vs.respond_to?(:each)
|
20
|
-
vs.each do |v|
|
21
|
-
unless v.empty?
|
22
|
-
n2 = g.add_nodes(v.to_s)
|
23
|
-
g.add_edges(n2, n1)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
+
create_dot_file(dependency_hash)
|
30
|
+
end
|
31
|
+
end
|
29
32
|
|
30
|
-
|
31
|
-
|
33
|
+
def self.do_at_exit
|
34
|
+
# Store the exit status of the test run since it goes away after calling the at_exit proc...
|
35
|
+
exit_status = if $!
|
36
|
+
$!.is_a?(SystemExit) ? $!.status : 1
|
32
37
|
end
|
38
|
+
|
39
|
+
dependency_hash, class_location_hash = CallSiteAnalyzer.result
|
40
|
+
create_output_file(dependency_hash, class_location_hash, :to_file => Rubydeps.default_dump_file_name, :class_name_filter => /.*/, :path_filter => /.*/)
|
41
|
+
|
42
|
+
exit exit_status if exit_status
|
33
43
|
end
|
34
44
|
|
35
|
-
def self.
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
45
|
+
def self.calculate_or_load_dependencies(options, &block_to_analyze)
|
46
|
+
if options[:from_file]
|
47
|
+
Marshal.load(File.binread(options[:from_file]))
|
48
|
+
else
|
49
|
+
begin
|
50
|
+
self.start(false)
|
51
|
+
block_to_analyze.call()
|
52
|
+
ensure
|
53
|
+
return CallSiteAnalyzer.result
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
41
57
|
|
58
|
+
def self.apply_filters(dependency_hash, class_location_hash, options)
|
42
59
|
path_filter = options.fetch(:path_filter, /.*/)
|
43
60
|
class_name_filter = options.fetch(:class_name_filter, /.*/)
|
44
61
|
classes_to_remove = get_classes_to_remove(dependency_hash, class_location_hash, path_filter, class_name_filter)
|
@@ -50,13 +67,6 @@ module Rubydeps
|
|
50
67
|
dependency_hash[called_class].member? klass_to_remove
|
51
68
|
end
|
52
69
|
|
53
|
-
#transitive dependencies, hmmm, not sure is a good idea
|
54
|
-
#if classes_calling_class_to_remove && !classes_calling_class_to_remove.empty?
|
55
|
-
# classes_called_by_class_to_remove.each do |called_class|
|
56
|
-
# dependency_hash[called_class] |= classes_calling_class_to_remove
|
57
|
-
# end
|
58
|
-
#end
|
59
|
-
|
60
70
|
dependency_hash.delete(klass_to_remove)
|
61
71
|
classes_called_by_class_to_remove.each do |called_class|
|
62
72
|
if dependency_hash[called_class]
|
@@ -67,10 +77,34 @@ module Rubydeps
|
|
67
77
|
end
|
68
78
|
end
|
69
79
|
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.normalize_class_name(klass)
|
84
|
+
good_class_name = klass.gsub(/#<(.+):(.+)>/, 'Instance of \1')
|
85
|
+
good_class_name.gsub!(/\([^\)]*\)/, "")
|
86
|
+
good_class_name.gsub(/0x[\da-fA-F]+/, '(hex number)')
|
87
|
+
end
|
70
88
|
|
89
|
+
def self.create_dot_file(dependency_hash)
|
90
|
+
return unless dependency_hash
|
91
|
+
|
92
|
+
g = GraphViz::new( "G", :use => 'dot', :mode => 'major', :rankdir => 'LR', :concentrate => 'true', :fontname => 'Arial')
|
93
|
+
dependency_hash.each do |k,vs|
|
94
|
+
if !k.empty? && !vs.empty?
|
95
|
+
n1 = g.add_nodes(k.to_s)
|
96
|
+
if vs.respond_to?(:each)
|
97
|
+
vs.each do |v|
|
98
|
+
unless v.empty?
|
99
|
+
n2 = g.add_nodes(v.to_s)
|
100
|
+
g.add_edges(n2, n1)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
71
105
|
end
|
72
106
|
|
73
|
-
|
107
|
+
g.output( :dot => "rubydeps.dot" )
|
74
108
|
end
|
75
109
|
|
76
110
|
def self.get_classes_to_remove(dependency_hash, class_location_hash, path_filter, class_name_filter)
|
@@ -84,9 +118,7 @@ module Rubydeps
|
|
84
118
|
Hash[dependency_hash.map { |k,v| [normalize_class_name(k), v.map{|c| c == k ? nil : normalize_class_name(c)}.compact] }]
|
85
119
|
end
|
86
120
|
|
87
|
-
def self.
|
88
|
-
|
89
|
-
good_class_name.gsub!(/\([^\)]*\)/, "")
|
90
|
-
good_class_name.gsub(/0x[\da-fA-F]+/, '(hex number)')
|
121
|
+
def self.default_dump_file_name
|
122
|
+
"rubydeps.dump"
|
91
123
|
end
|
92
124
|
end
|
data/rubydeps.gemspec
CHANGED
data/spec/rubydeps_spec.rb
CHANGED
@@ -48,7 +48,7 @@ class Son
|
|
48
48
|
end
|
49
49
|
|
50
50
|
describe "Rubydeps" do
|
51
|
-
|
51
|
+
|
52
52
|
it "should show the class level dependencies" do
|
53
53
|
dependencies, _ = ::Rubydeps.dependency_hash_for do
|
54
54
|
class IHaveAClassLevelDependency
|
@@ -59,18 +59,6 @@ describe "Rubydeps" do
|
|
59
59
|
dependencies.should == {"Parent"=>["Son"]}
|
60
60
|
end
|
61
61
|
|
62
|
-
it "should create a dot file" do
|
63
|
-
with_files do
|
64
|
-
::Rubydeps.analyze do
|
65
|
-
class IHaveAClassLevelDependency
|
66
|
-
Son.class_method
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
File.read("rubydeps.dot").should match("digraph G")
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
62
|
it "should be idempotent" do
|
75
63
|
::Rubydeps.dependency_hash_for do
|
76
64
|
class IHaveAClassLevelDependency
|
@@ -112,73 +100,80 @@ describe "Rubydeps" do
|
|
112
100
|
dependencies["GrandparentModule"].should == ["Grandparent"]
|
113
101
|
end
|
114
102
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
def depend_on_b_and_c
|
120
|
-
B.new.b
|
121
|
-
C.new.c
|
122
|
-
end
|
123
|
-
end
|
124
|
-
CLASSA
|
125
|
-
'path1/class_b.rb' => 'class B; def b; end end',
|
126
|
-
'path2/class_c.rb' => 'class C; def c; end end'}
|
103
|
+
it "should create correct dependencies for 2 instance methods called in a row" do
|
104
|
+
dependencies, _ = ::Rubydeps.dependency_hash_for do
|
105
|
+
Son.new.instance_method_calling_another_instance_method(Parent.new)
|
106
|
+
end
|
127
107
|
|
128
|
-
|
129
|
-
|
130
|
-
load './path1/class_a.rb'
|
108
|
+
dependencies.should == {"Parent"=>["Son"]}
|
109
|
+
end
|
131
110
|
|
132
|
-
|
133
|
-
|
134
|
-
end
|
111
|
+
context "with a dumped dependencies file" do
|
112
|
+
include FileTestHelper
|
135
113
|
|
136
|
-
|
137
|
-
|
138
|
-
end
|
114
|
+
sample_dir_structure = {'path1/class_a.rb' => <<-CLASSA,
|
115
|
+
require '#{File.dirname(__FILE__)}/../lib/rubydeps'
|
139
116
|
|
140
|
-
|
141
|
-
|
142
|
-
|
117
|
+
require './path1/class_b'
|
118
|
+
require './path2/class_c'
|
119
|
+
class A
|
120
|
+
def depend_on_b_and_c
|
121
|
+
B.new.b
|
122
|
+
C.new.c
|
123
|
+
end
|
124
|
+
end
|
143
125
|
|
144
|
-
|
145
|
-
|
146
|
-
|
126
|
+
Rubydeps.start
|
127
|
+
A.new.depend_on_b_and_c
|
128
|
+
CLASSA
|
129
|
+
'path1/class_b.rb' => 'class B; def b; end end',
|
130
|
+
'path2/class_c.rb' => 'class C; def c; end end'}
|
147
131
|
|
148
|
-
|
132
|
+
def run(command)
|
133
|
+
system("ruby -I#{File.dirname(__FILE__)}/../lib #{command}")
|
149
134
|
end
|
150
|
-
end
|
151
135
|
|
152
|
-
|
153
|
-
|
154
|
-
|
136
|
+
it "should create a dot file" do
|
137
|
+
with_files(sample_dir_structure) do
|
138
|
+
run("./path1/class_a.rb")
|
139
|
+
run("#{File.dirname(__FILE__)}/../bin/rubydeps")
|
155
140
|
|
156
|
-
|
157
|
-
A.new.depend_on_b_and_c
|
141
|
+
File.read("rubydeps.dot").should match("digraph G")
|
158
142
|
end
|
143
|
+
end
|
159
144
|
|
160
|
-
|
145
|
+
it "should be a correct test file" do
|
146
|
+
with_files(sample_dir_structure) do
|
147
|
+
status = run("./path1/class_a.rb")
|
148
|
+
status.should be_true
|
149
|
+
end
|
161
150
|
end
|
162
|
-
end
|
163
151
|
|
164
|
-
|
165
|
-
|
166
|
-
|
152
|
+
it "should not filter classes when no filter is specified" do
|
153
|
+
with_files(sample_dir_structure) do
|
154
|
+
run("./path1/class_a.rb")
|
167
155
|
|
168
|
-
|
169
|
-
A
|
156
|
+
dependencies, _ = ::Rubydeps.dependency_hash_for(:from_file => 'rubydeps.dump')
|
157
|
+
dependencies.should == {"B"=>["A"], "C"=>["A"]}
|
170
158
|
end
|
171
|
-
|
172
|
-
dependencies, _ = ::Rubydeps.dependency_hash_for(:from_file => 'dependencies.file', :class_name_filter => /C|A/)
|
173
|
-
dependencies.should == {"C"=>["A"]}
|
174
159
|
end
|
175
|
-
end
|
176
160
|
|
177
|
-
|
178
|
-
|
179
|
-
|
161
|
+
it "should filter classes when a path filter is specified" do
|
162
|
+
with_files(sample_dir_structure) do
|
163
|
+
run("./path1/class_a.rb")
|
164
|
+
|
165
|
+
dependencies, _ = ::Rubydeps.dependency_hash_for(:from_file => 'rubydeps.dump', :path_filter => /path1/)
|
166
|
+
dependencies.should == {"B"=>["A"]}
|
167
|
+
end
|
180
168
|
end
|
181
169
|
|
182
|
-
|
170
|
+
it "should filter classes when a class name filter is specified" do
|
171
|
+
with_files(sample_dir_structure) do
|
172
|
+
run("./path1/class_a.rb")
|
173
|
+
|
174
|
+
dependencies, _ = ::Rubydeps.dependency_hash_for(:from_file => 'rubydeps.dump', :class_name_filter => /C|A/)
|
175
|
+
dependencies.should == {"C"=>["A"]}
|
176
|
+
end
|
177
|
+
end
|
183
178
|
end
|
184
179
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: rubydeps
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease: 6
|
5
|
-
version: 0.9.
|
5
|
+
version: 0.9.2.pre
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Daniel Cadenas
|
@@ -99,7 +99,6 @@ files:
|
|
99
99
|
- bin/rubydeps
|
100
100
|
- ext/call_site_analyzer/call_site_analyzer.c
|
101
101
|
- ext/call_site_analyzer/extconf.rb
|
102
|
-
- lib/call_site_analyzer.bundle
|
103
102
|
- lib/rubydeps.rb
|
104
103
|
- rake-deps.png
|
105
104
|
- rubydeps.gemspec
|
Binary file
|