rubydeps 0.9.1.pre → 0.9.2.pre
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 +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
|

|
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
|