dependency_grapher 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f703f45032c65c0ea7fa64d6b056dbc6eff04299
4
+ data.tar.gz: 3c683aed6c7cc579fe3d11515cd5825845a4c973
5
+ SHA512:
6
+ metadata.gz: 29f659bd377cf01bd32e9596fa2a2305bc1f263f0b03ee40b76e7330f2a8eef8b7574cff9f21f15a6bc3406ab8267141fdc2e8c9b8dec5028e62706a21d76200
7
+ data.tar.gz: 938740dfb0b5abb0bc1b450a6e3a249f297ced830479cc1a194d7ea948575174c2d8c0cb1fd5eb791feb51cbb041e3b0ce4210b58e77e6e018177e06255dae92
data/.byebug_history ADDED
@@ -0,0 +1,35 @@
1
+ quit
2
+ pry
3
+ method
4
+ help
5
+ var all
6
+ var
7
+ help
8
+ info instance_variables
9
+ quit
10
+ string = DependencyGrapher::DependencyFilter.extract_class(@string4)
11
+ quit
12
+ @expected3
13
+ string
14
+ string == @expected3
15
+ string = DependencyGrapher::DependencyFilter.extract_class(@string3)
16
+ quit
17
+ quite
18
+ s
19
+ s = DependencyGrapher::DependencyFilter.extract_class(e)
20
+ s
21
+ e
22
+ e = @expected3
23
+ s = DependencyGrapher::DependencyFilter.extract_class(@string3)
24
+ a
25
+ a = 3
26
+ @expected3
27
+ quit
28
+ yaml_string
29
+ @file
30
+ quit
31
+ rake test
32
+ @receiver_1
33
+ loaded_dependency.receiver
34
+ loaded_dependency
35
+ yaml_string
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /bin/
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.0
4
+ before_install: gem install bundler -v 1.11.2
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at abstract.wolf@gmail.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dependency_grapher.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,43 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ ## Uncomment and set this to only include directories you want to watch
5
+ #directories %w(app lib config test spec features) \
6
+ directories %w(lib test) \
7
+ .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
8
+
9
+ ## Note: if you are using the `directories` clause above and you are not
10
+ ## watching the project directory ('.'), then you will want to move
11
+ ## the Guardfile to a watched dir and symlink it back, e.g.
12
+ #
13
+ # $ mkdir config
14
+ # $ mv Guardfile config/
15
+ # $ ln -s config/Guardfile .
16
+ #
17
+ # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
18
+
19
+ guard :minitest do
20
+ # with Minitest::Unit
21
+ watch(%r{^test/(.*)\/?test_(.*)\.rb$})
22
+ watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
23
+ watch(%r{^test/test_helper\.rb$}) { 'test' }
24
+
25
+ # with Minitest::Spec
26
+ # watch(%r{^spec/(.*)_spec\.rb$})
27
+ # watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
28
+ # watch(%r{^spec/spec_helper\.rb$}) { 'spec' }
29
+
30
+ # Rails 4
31
+ # watch(%r{^app/(.+)\.rb$}) { |m| "test/#{m[1]}_test.rb" }
32
+ # watch(%r{^app/controllers/application_controller\.rb$}) { 'test/controllers' }
33
+ # watch(%r{^app/controllers/(.+)_controller\.rb$}) { |m| "test/integration/#{m[1]}_test.rb" }
34
+ # watch(%r{^app/views/(.+)_mailer/.+}) { |m| "test/mailers/#{m[1]}_mailer_test.rb" }
35
+ # watch(%r{^lib/(.+)\.rb$}) { |m| "test/lib/#{m[1]}_test.rb" }
36
+ # watch(%r{^test/.+_test\.rb$})
37
+ # watch(%r{^test/test_helper\.rb$}) { 'test' }
38
+
39
+ # Rails < 4
40
+ # watch(%r{^app/controllers/(.*)\.rb$}) { |m| "test/functional/#{m[1]}_test.rb" }
41
+ # watch(%r{^app/helpers/(.*)\.rb$}) { |m| "test/helpers/#{m[1]}_test.rb" }
42
+ # watch(%r{^app/models/(.*)\.rb$}) { |m| "test/unit/#{m[1]}_test.rb" }
43
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 tmzhuang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # DependencyGrapher
2
+ DependencyGrapher is a tool for highlighting certain method calls in your Rails application. Specifically, it highlights cases where classes makes calls to external frameworks that are already being referenced to by service objects. DependencyGrapher tries to use your testing framework to infer method dependencies between classes. It assumes that all service objects are in the `app/services/' folder.
3
+
4
+ DependencyGrapher will only show classes that are direct neighbours of "known classes". Known classes are inferred from ruby files under `Rails.application.config.eager_load_paths`. Furthermore, all services are assumed be in the /app/services/folder. A "violation" is when there exists a receiver of a service class that is being called by a non-service class. There edges are shown in red in the resulting graph.
5
+
6
+ Example:
7
+ `app/controllers/users_controller.rb`:
8
+ ```ruby
9
+ ...
10
+ def get_logger
11
+ logger = DependencyGrapher::Logger.new
12
+ logger.enable
13
+ logger.disable
14
+ end
15
+ ...
16
+ ```
17
+
18
+ `app/models/user.rb`:
19
+ ```ruby
20
+ ...
21
+ def get_logger
22
+ logger = GetLogger.call
23
+ end
24
+ ...
25
+ ```
26
+
27
+ `app/services/get_logger.rb`:
28
+ ```ruby
29
+ class GetLogger
30
+ def self.call
31
+ DepedencyGrapher::Logger.new
32
+ end
33
+ end
34
+ ```
35
+
36
+ `user_test.rb`:
37
+ ```ruby
38
+ class UserTest < ActiveSupport::TestCase
39
+ test "dep1" do
40
+ #p "in UserTest the truth"
41
+ @user = users(:tianming)
42
+ @skill = skills(:ruby)
43
+ @user.add_skill(@skill)
44
+ @user.get_logger
45
+ assert @user.has_skill?(@skill)
46
+ end
47
+
48
+ test "dep2" do
49
+ #p "in UserTest the truth"
50
+ UsersController.new.get_logger
51
+ assert true
52
+ end
53
+ end
54
+ def get_logger
55
+ logger = GetLogger.call
56
+ end
57
+ ```
58
+ Sample output:
59
+ ![sample output](http://imgh.us/dependencies_4.svg)
60
+
61
+
62
+ ## Installation
63
+
64
+ Add this line to your application's Gemfile:
65
+
66
+ ```ruby
67
+ gem 'dependency_grapher'
68
+ ```
69
+
70
+ And run `bundle install`.
71
+
72
+ ## Usage
73
+ In your test helpers file `test/test_helper`, include `DependencyGrapher::TestHelpers` to your tests as shown below:
74
+ ```ruby
75
+ class ActionController::TestCase
76
+ include DependencyGrapher::TestHelpers
77
+ #include DependencyGrapher::TestHelpers
78
+ end
79
+
80
+ class ActiveSupport::TestCase
81
+ include DependencyGrapher::TestHelpers
82
+ # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
83
+ fixtures :all
84
+ end
85
+ ```
86
+ DependencyGrapher requires you first to run your unit tests to produce set of dependencies (outputted to your project folder as dependencies.yml). The parts of your system that are not touched by the tests will not be shown in the graph.
87
+
88
+ After the tests have complete, run `rake dep:graph` to produce a svg graph. You may specify the name format of the graph output by using `rake dep:graph[name.format]`. For example, `rake dep:graph[graph.dot]` produces a DOT file of the graph. Acceptable formats can be found on the [GraphViz site](http://www.graphviz.org/doc/info/output.html).
89
+ ## Contributing
90
+
91
+ Bug reports and pull requests are welcome on GitHub at https://github.com/tmzhuang/dependency_grapher. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
92
+
93
+
94
+ ## License
95
+
96
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
97
+
data/README.md.orig ADDED
@@ -0,0 +1,101 @@
1
+ # DependencyGrapher
2
+ DependencyGrapher is a tool for highlighting certain method calls in your Rails application. Specifically, it highlights cases where classes makes calls to external frameworks that are already being referenced to by service objects. DependencyGrapher tries to use your testing framework to infer method dependencies between classes. It assumes that all service objects are in the `app/services/' folder.
3
+
4
+ DependencyGrapher will only show classes that are direct neighbours of "known classes". Known classes are inferred from ruby files under `Rails.application.config.eager_load_paths`. Furthermore, all services are assumed be in the /app/services/folder. A "violation" is when there exists a receiver of a service class that is being called by a non-service class. There edges are shown in red in the resulting graph.
5
+
6
+ Example:
7
+ `app/controllers/users_controller.rb`:
8
+ ```ruby
9
+ ...
10
+ def get_logger
11
+ logger = DependencyGrapher::Logger.new
12
+ logger.enable
13
+ logger.disable
14
+ end
15
+ ...
16
+ ```
17
+
18
+ `app/models/user.rb`:
19
+ ```ruby
20
+ ...
21
+ def get_logger
22
+ logger = GetLogger.call
23
+ end
24
+ ...
25
+ ```
26
+
27
+ `app/services/get_logger.rb`:
28
+ ```ruby
29
+ class GetLogger
30
+ def self.call
31
+ DepedencyGrapher::Logger.new
32
+ end
33
+ end
34
+ ```
35
+
36
+ `user_test.rb`:
37
+ ```ruby
38
+ class UserTest < ActiveSupport::TestCase
39
+ test "dep1" do
40
+ #p "in UserTest the truth"
41
+ @user = users(:tianming)
42
+ @skill = skills(:ruby)
43
+ @user.add_skill(@skill)
44
+ @user.get_logger
45
+ assert @user.has_skill?(@skill)
46
+ end
47
+
48
+ test "dep2" do
49
+ #p "in UserTest the truth"
50
+ UsersController.new.get_logger
51
+ assert true
52
+ end
53
+ end
54
+ def get_logger
55
+ logger = GetLogger.call
56
+ end
57
+ ```
58
+ Sample output:
59
+ ![sample output](http://imgh.us/dependencies_4.svg)
60
+
61
+
62
+ ## Installation
63
+
64
+ Add this line to your application's Gemfile:
65
+
66
+ ```ruby
67
+ gem 'dependency_grapher'
68
+ ```
69
+
70
+ And run `bundle install`.
71
+
72
+ ## Usage
73
+ In your test helpers file `test/test_helper`, include `DependencyGrapher::TestHelpers` to your tests as shown below:
74
+ ```ruby
75
+ class ActionController::TestCase
76
+ include DependencyGrapher::TestHelpers
77
+ #include DependencyGrapher::TestHelpers
78
+ end
79
+
80
+ class ActiveSupport::TestCase
81
+ include DependencyGrapher::TestHelpers
82
+ # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
83
+ fixtures :all
84
+ end
85
+ ```
86
+ DependencyGrapher requires you first to run your unit tests to produce set of dependencies (outputted to your project folder as dependencies.yml). The parts of your system that are not touched by the tests will not be shown in the graph.
87
+
88
+ <<<<<<< HEAD
89
+ After the tests have complete, run `rake dep:graph` to produce a svg graph. You may specify the name format of the graph output by using `rake dep:graph[name.format]`. For example, `rake dep:graph[graph.dot]` produces a DOT file of the graph. Acceptable formats can be found on the [GraphViz site](http://www.graphviz.org/doc/info/output.html).
90
+ =======
91
+ After the tests have complete, run `rake dep:graph` to produce a svg graph.
92
+ >>>>>>> 90740a521c84f26b243c2df79166265c730bb0fb
93
+ ## Contributing
94
+
95
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/dependency_grapher. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
96
+
97
+
98
+ ## License
99
+
100
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
101
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/test_*.rb']
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "dependency_grapher"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/dependency.yml ADDED
@@ -0,0 +1,13 @@
1
+ --- !ruby/object:DependencyGrapher::Dependency
2
+ caller: !ruby/object:DependencyGrapher::Method
3
+ defined_class: Module1::Class1
4
+ method_id: the_method_1
5
+ types: !ruby/object:Set
6
+ hash: {}
7
+ receiver: !ruby/object:DependencyGrapher::Method
8
+ defined_class: Class2
9
+ method_id: the_method_2
10
+ types: !ruby/object:Set
11
+ hash: {}
12
+ flags: !ruby/object:Set
13
+ hash: {}
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dependency_grapher/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "dependency_grapher"
8
+ spec.version = DependencyGrapher::VERSION
9
+ spec.authors = ["Tianming Zhuang"]
10
+ spec.email = ["tianming.zhuang@gmail.com"]
11
+
12
+ spec.summary = %q{Graphical vizualization of Ruby application dependencies.}
13
+ spec.description = %q{For applications that use minitest as the automated test framework. This gem provides a class for logging the dependencies of the application while the test runs, and another for analyzing those dependencies and producing a graph.}
14
+ spec.homepage = "https://github.com/tmzhuang/dependency_grapher"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency "ruby-graphviz"
23
+ spec.add_dependency "activesupport"
24
+ #spec.add_dependency "ruby-xslt"
25
+ spec.add_development_dependency "minitest"
26
+ spec.add_development_dependency "minitest-reporters"
27
+ spec.add_development_dependency "guard-minitest"
28
+ spec.add_development_dependency "mocha"
29
+ spec.add_development_dependency "bundler"
30
+ spec.add_development_dependency "rake"
31
+ spec.add_development_dependency "byebug"
32
+ spec.add_development_dependency "pry"
33
+ end
@@ -0,0 +1,47 @@
1
+ require 'set'
2
+
3
+ module DependencyGrapher
4
+ class Analyzer
5
+ attr_accessor :dependencies
6
+
7
+ def initialize(dependencies = nil)
8
+ @dependencies = dependencies
9
+ end
10
+
11
+ def load_dependencies(dependencies)
12
+ @dependencies = dependencies
13
+ end
14
+
15
+ def set_dependency_flags
16
+ @dependencies.each do |dep|
17
+ if dep.receiver.types.include?(:framework)
18
+ dep.flags << :violation unless dep.kaller.types.include?(:service)
19
+ end
20
+ end
21
+ end
22
+
23
+ # OPTIMIZE
24
+ def set_method_types
25
+ services = GetKnownClasses.call(:services)
26
+ framework_roots = Set.new
27
+ # Marks all receiver of service objects as :framework
28
+ @dependencies.each do |dep|
29
+ if services.include?(dep.kaller.root)
30
+ dep.kaller.types << :service
31
+ dep.receiver.types << :framework
32
+ framework_roots << dep.receiver.root
33
+ end
34
+ end
35
+
36
+ # Marks all methods with a root that is shared with
37
+ # methods in the frameworks list as :framework
38
+ @dependencies.each do |dep|
39
+ if framework_roots.include?(dep.kaller.root)
40
+ dep.kaller.types << :framework
41
+ elsif framework_roots.include?(dep.receiver.root)
42
+ dep.receiver.types << :framework
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,26 @@
1
+ require 'set'
2
+ require_relative 'serialize_helpers'
3
+
4
+ module DependencyGrapher
5
+ class Dependency
6
+ include DependencyGrapher::SerializeHelpers
7
+ attr_reader :kaller, :receiver, :count
8
+ # TODO Fix LOD violation (flag should not be directly exposed)
9
+ attr_accessor :flags
10
+
11
+ def initialize(kaller, receiver)
12
+ @kaller = kaller
13
+ @receiver = receiver
14
+ @flags = Set.new
15
+ @count = 1
16
+ end
17
+
18
+ def id
19
+ @kaller.id + @receiver.id
20
+ end
21
+
22
+ def touch
23
+ @count += 1
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,21 @@
1
+ require 'set'
2
+
3
+ module DependencyGrapher
4
+ module DeserializeDependencies
5
+ module_function
6
+
7
+ # TODO: extract filename defaults to constants
8
+ def call(filename = "dependencies.yml")
9
+ dependencies = Set.new
10
+ $/="\n\n"
11
+ File.open(filename, "r").each do |object|
12
+ begin
13
+ dependencies << Dependency.deserialize(object)
14
+ rescue
15
+ raise $!, "Could not load object from #{filename}", $!.backtrace
16
+ end
17
+ end
18
+ dependencies
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,39 @@
1
+ require 'set'
2
+ require_relative 'deserialize_dependencies'
3
+
4
+ module DependencyGrapher
5
+ class Filter
6
+ attr_accessor :dependencies
7
+ def initialize
8
+ @dependencies = nil
9
+ end
10
+
11
+ def filter
12
+ tmp_deps = Set.new
13
+ receiver = {}
14
+
15
+ # Crawl ActiveSupport::Dependencies.autoload_paths for known classes
16
+ known_classes = GetKnownClasses.call
17
+
18
+ @dependencies.each_with_index do |dep, i|
19
+ kaller = dep.kaller
20
+ receiver = dep.receiver
21
+ # all pass_conds must be true for dependency to be added to calculated_dependencies
22
+ pass_conds = true
23
+ pass_conds &&= kaller.id != receiver.id
24
+ pass_conds &&= (known_classes.include?(kaller.root) || known_classes.include?(receiver.root))
25
+ tmp_deps << dep if pass_conds
26
+ end
27
+
28
+ @dependencies = tmp_deps
29
+ end
30
+
31
+ def load_file(filename = "dependencies.yml")
32
+ @dependencies = DeserializeDependencies.call(filename)
33
+ end
34
+
35
+ def load_dependencies(dependencies)
36
+ @dependencies = dependencies
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,30 @@
1
+ require 'set'
2
+
3
+ module DependencyGrapher
4
+ module GetKnownClasses
5
+ module_function
6
+ def call(folder = nil)
7
+ result = Set.new
8
+ #ActiveSupport::Dependencies.autoload_paths.each do |folder|
9
+ if folder
10
+ full_folder = "app/" + folder.to_s
11
+ result = get_classes_in(full_folder)
12
+ else
13
+ Rails.application.config.eager_load_paths.each do |folder|
14
+ result.merge get_classes_in(folder)
15
+ end
16
+ end
17
+ result
18
+ end
19
+
20
+ private_class_method
21
+ def get_classes_in(folder)
22
+ classes = Set.new
23
+ files = File.join("#{folder}", "**", "*.rb")
24
+ Dir.glob(files).map do |file|
25
+ classes << file[/#{folder}\/(.*).rb/,1].camelize
26
+ end
27
+ classes
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,82 @@
1
+ require 'graphviz'
2
+ require 'set'
3
+
4
+ module DependencyGrapher
5
+ class Grapher
6
+ def initialize(dependencies)
7
+ @dependencies = dependencies
8
+ generate_graph_from_dependencies
9
+ end
10
+
11
+ def output(format)
12
+ @graph.output(format)
13
+ end
14
+
15
+ def generate_graph_from_dependencies
16
+ # Initialize a directional graph
17
+ @graph = GraphViz.digraph( :G, type: :digraph, tooltip: " ")
18
+
19
+ # Iterate through dependency set to get edges and methods
20
+ @dependencies.each do |dependency|
21
+ # Methods from the dependencies
22
+ kaller = dependency.kaller
23
+ receiver = dependency.receiver
24
+ # Add edges to set
25
+ #@graph.add_edges(kaller.method_id, receiver.method_id, color: :red)
26
+ add_node(kaller)
27
+ add_node(receiver)
28
+ add_edge(dependency)
29
+ end
30
+ end
31
+
32
+ def add_edge(dependency)
33
+ options = {}
34
+ normal_color = get_normal_color(dependency.count)
35
+ options[:color] = dependency.flags.include?(:violation) ? :red : normal_color
36
+ options[:label] = dependency.count > 1 ? dependency.count : ""
37
+ @graph.add_edges(dependency.kaller.id, dependency.receiver.id, options)
38
+ end
39
+
40
+ def get_normal_color(count)
41
+ code = 80 - count * 5
42
+ binding.pry if code < 0
43
+ code = 0 if code < 0
44
+ "gray#{code}"
45
+ end
46
+
47
+ # Add a method to the structure of stored graph. Defined classes are stored
48
+ # as clusters (subgraphs) and method id is used to identify the node
49
+ def add_node(method)
50
+ graph = create_clusters(method)
51
+ # Node
52
+ options = {}
53
+ options[:label] = method.method_id
54
+ options[:tooltip] = method.full_path
55
+ graph.add_nodes(method.id, options)
56
+ end
57
+
58
+ def create_clusters(method)
59
+ cluster_options = {tooltip: " "}
60
+ if method.types.include?(:service)
61
+ cluster_options[:bgcolor] = :azure3
62
+ elsif method.types.include?(:framework)
63
+ cluster_options[:bgcolor] = :brown
64
+ end
65
+
66
+ # Iterate over ancestors (eg. Minitest::Unit yields Minitest, # Unit)
67
+ # This variable is used to reference the immediate parent of the
68
+ # current graph. Initializes to the root; updates on each iteration.
69
+ prev_graph = @graph
70
+ method.ancestors.each_with_index do |klass, i|
71
+ # Prepending "cluster_" is mandatory according to ruby-graphviz API
72
+ graph_id = "cluster_" + method.ancestors[0..i].join("_")
73
+ # add_graph returns an existing graph if it exists
74
+ subgraph = prev_graph.add_graph(graph_id, cluster_options)
75
+ subgraph[:label] = klass
76
+ # Update parent for next iteration
77
+ prev_graph = subgraph
78
+ end
79
+ prev_graph
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,70 @@
1
+ require_relative "method"
2
+ require_relative "dependency"
3
+ require_relative "parse_class"
4
+
5
+ require 'pry'
6
+ module DependencyGrapher
7
+ class Logger
8
+ attr_reader :dependencies
9
+ def initialize
10
+ @dependencies = {}
11
+ @keys = Set.new
12
+ @call_stack = []
13
+ @methods = {}
14
+ @trace = get_trace_point
15
+ end
16
+
17
+ def enable
18
+ @trace.enable
19
+ end
20
+
21
+ def disable
22
+ @trace.disable
23
+ end
24
+
25
+ def dump(filename = "dependencies.yml")
26
+ file = File.open(filename, "w")
27
+ @keys.each do |key|
28
+ file.puts @dependencies[key].serialize
29
+ file.puts
30
+ end
31
+ end
32
+
33
+ private
34
+ def get_trace_point
35
+ # Define a tracepoint for tacking ruby calls and returns
36
+ tp = TracePoint.trace(:call, :return) do |tp|
37
+ case tp.event
38
+ when :call
39
+ handle_call(tp.defined_class, tp.method_id, tp.path, tp.lineno)
40
+ when :return
41
+ handle_return
42
+ end
43
+ end
44
+ tp.disable # Disable tp by default
45
+ tp
46
+ end
47
+
48
+ def handle_call(defined_class, method_id, path, lineno)
49
+ method = Method.new(ParseClass.call(defined_class), method_id.to_s, path, lineno.to_s)
50
+ @methods[method.id] = method unless @methods[method.id]
51
+ @call_stack << @methods[method.id]
52
+ end
53
+
54
+ def handle_return
55
+ kaller = @call_stack[-2] # Second last item on stack is the kaller
56
+ receiver = @call_stack.pop # First item on stack is receiver
57
+ # Ignore case where kaller is nil (ie. main)
58
+ if kaller
59
+ dep = Dependency.new(kaller, receiver)
60
+ key = dep.id
61
+ if @keys.include?(key)
62
+ @dependencies[key].touch
63
+ else
64
+ @dependencies[key] = dep
65
+ @keys << key
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,47 @@
1
+ require 'yaml'
2
+ require 'set'
3
+ require_relative 'serialize_helpers'
4
+
5
+ module DependencyGrapher
6
+ class Method
7
+ include DependencyGrapher::SerializeHelpers
8
+
9
+ Limit = 50
10
+
11
+ attr_reader :defined_class, :method_id, :path, :lineno
12
+
13
+ # TODO Fix LOD violation (types should not be directly exposed)
14
+ attr_accessor :types
15
+
16
+ def initialize(defined_class, method_id, path, lineno)
17
+ # Truncate class name to limit characters if too long
18
+ defined_class = defined_class[0,Limit] + "..." if defined_class.length > Limit
19
+ @defined_class = defined_class
20
+ @method_id = method_id
21
+ @path = path
22
+ @lineno = lineno
23
+ @types = Set.new
24
+ end
25
+
26
+ def full_path
27
+ @path + ":" + @lineno
28
+ end
29
+
30
+ def ancestors
31
+ binding.pry if @defined_class.nil?
32
+ @defined_class.split("::")
33
+ end
34
+
35
+ def root
36
+ ancestors.first
37
+ end
38
+
39
+ def leaf
40
+ ancestors.last
41
+ end
42
+
43
+ def id
44
+ @defined_class + @method_id
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,40 @@
1
+ module DependencyGrapher
2
+ module ParseClass
3
+ module_function
4
+ def call(klass)
5
+ anon_class_pattern?(klass.inspect) ? parse_anon_class_name(klass.inspect) : klass.inspect
6
+ end
7
+
8
+ private_class_method
9
+ # #<#<Class:0x007fd550c04338>:0x007fd550c04450> matches with groups:
10
+ # 1.#<Class:0x007fd550c04338>
11
+ # 2.0x007fd550c04450
12
+ def nested_anon_pattern
13
+ /#<(#<.*>):(.*)>/
14
+ end
15
+
16
+ # #<Class:0x007fd550c04338> matches with groups:
17
+ # 1.Class
18
+ # 2.0x007fd550c04338
19
+ def anon_pattern
20
+ /#<(Class|Module):([^>]*)>/
21
+ end
22
+
23
+ def anon_class_pattern?(name)
24
+ name.match(nested_anon_pattern) || name.match(anon_pattern)
25
+ end
26
+
27
+ # Given #<#<Class:0x007fd550c04338>:0x007fd550c04450>, returns string
28
+ # "0x007fd550c04338::0x007fd550c04450" using a recursive function
29
+ def parse_anon_class_name(name)
30
+ if match = name.match(nested_anon_pattern)
31
+ parse_anon_class_name(match[1]) + "::#{match[2]}"
32
+ elsif match = name.match(anon_pattern)
33
+ match[2]
34
+ else
35
+ raise "Unrecognized format for Class or Module: #{name}."
36
+ end
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,11 @@
1
+ require 'dependency_grapher'
2
+ require 'rails'
3
+ module DependencyGrapher
4
+ class Railtie < Rails::Railtie
5
+ railtie_name :dependency_grapher
6
+
7
+ rake_tasks do
8
+ load "tasks/dependency_grapher.rake"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ require 'active_support'
2
+ require 'yaml'
3
+
4
+ module DependencyGrapher
5
+ module SerializeHelpers
6
+ extend ActiveSupport::Concern
7
+ included do
8
+ def serialize
9
+ to_yaml
10
+ end
11
+
12
+ def self.deserialize(string)
13
+ self.from_yaml(string)
14
+ end
15
+
16
+ private
17
+ def to_yaml
18
+ YAML.dump(self)
19
+ end
20
+
21
+ def self.from_yaml(yaml_string)
22
+ YAML.load(yaml_string)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ require 'active_support'
2
+
3
+ module DependencyGrapher
4
+ module TestHelpers
5
+ extend ActiveSupport::Concern
6
+ included do
7
+ @@dependency_logger = DependencyGrapher::Logger.new
8
+
9
+ setup do
10
+ @@dependency_logger.enable
11
+ end
12
+
13
+ teardown do
14
+ @@dependency_logger.disable
15
+ end
16
+
17
+ Minitest.after_run do
18
+ @@dependency_logger.dump
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module DependencyGrapher
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,14 @@
1
+ module DependencyGrapher
2
+ require 'dependency_grapher/analyzer'
3
+ require 'dependency_grapher/dependency'
4
+ require 'dependency_grapher/deserialize_dependencies'
5
+ require 'dependency_grapher/filter'
6
+ require 'dependency_grapher/get_known_classes'
7
+ require 'dependency_grapher/grapher'
8
+ require 'dependency_grapher/logger'
9
+ require 'dependency_grapher/method'
10
+ require 'dependency_grapher/parse_class'
11
+ require 'dependency_grapher/test_helpers'
12
+ require "dependency_grapher/version"
13
+ require 'dependency_grapher/railtie' if defined?(Rails)
14
+ end
@@ -0,0 +1,46 @@
1
+ namespace :dep do desc 'Produces a graph output from dependencies.yml (outputs to dependencies.yml by default)'
2
+ task :graph, [:name] do |t, args|
3
+ name = args[:name] || "dependencies.svg"
4
+
5
+ format = name[/^.*\.(\w*)$/, 1].to_sym
6
+
7
+ # Remove Rails classes, self-calls, and inter-class calls
8
+ filter = DependencyGrapher::Filter.new
9
+ filter.load_file
10
+ filter.filter
11
+
12
+ # Tag methods in dependcies as
13
+ analyzer = DependencyGrapher::Analyzer.new(filter.dependencies)
14
+ analyzer.set_method_types
15
+ analyzer.set_dependency_flags
16
+
17
+ grapher = DependencyGrapher::Grapher.new(analyzer.dependencies)
18
+ grapher.output(format => name)
19
+ end
20
+
21
+ namespace :list do
22
+ desc 'List known classes in project from autoload_paths'
23
+ task :all do
24
+ classes = DependencyGrapher::GetKnownClasses.call
25
+ classes.each do |klass|
26
+ p klass
27
+ end
28
+ end
29
+
30
+ desc 'List known classes in app/services'
31
+ task :services do
32
+ classes = DependencyGrapher::GetKnownClasses.call(:services)
33
+ classes.each do |klass|
34
+ p klass
35
+ end
36
+ end
37
+
38
+ desc 'List known classes in app/controllers'
39
+ task :controllers do
40
+ classes = DependencyGrapher::GetKnownClasses.call(:controllers)
41
+ classes.each do |klass|
42
+ p klass
43
+ end
44
+ end
45
+ end
46
+ end
data/tags ADDED
@@ -0,0 +1,84 @@
1
+ !_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
2
+ !_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
3
+ !_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
4
+ !_TAG_PROGRAM_NAME Exuberant Ctags //
5
+ !_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
6
+ !_TAG_PROGRAM_VERSION 5.9~svn20110310 //
7
+ Dependency lib/dependency_grapher/dependency.rb /^ class Dependency$/;" c class:DependencyGrapher
8
+ DependencyFilter lib/dependency_grapher/dependency_filter.rb /^ class DependencyFilter$/;" c class:DependencyGrapher
9
+ DependencyFilterTest test/dependency_filter_test.rb /^class DependencyFilterTest < Minitest::Test$/;" c
10
+ DependencyGrapher lib/dependency_grapher.rb /^module DependencyGrapher$/;" m
11
+ DependencyGrapher lib/dependency_grapher/dependency.rb /^module DependencyGrapher$/;" m
12
+ DependencyGrapher lib/dependency_grapher/dependency_filter.rb /^module DependencyGrapher$/;" m
13
+ DependencyGrapher lib/dependency_grapher/dot_generator.rb /^module DependencyGrapher$/;" m
14
+ DependencyGrapher lib/dependency_grapher/get_known_classes.rb /^module DependencyGrapher$/;" m
15
+ DependencyGrapher lib/dependency_grapher/grapher.rb /^module DependencyGrapher$/;" m
16
+ DependencyGrapher lib/dependency_grapher/logger.rb /^module DependencyGrapher$/;" m
17
+ DependencyGrapher lib/dependency_grapher/method.rb /^module DependencyGrapher$/;" m
18
+ DependencyGrapher lib/dependency_grapher/parse_class.rb /^module DependencyGrapher$/;" m
19
+ DependencyGrapher lib/dependency_grapher/railtie.rb /^module DependencyGrapher$/;" m
20
+ DependencyGrapher lib/dependency_grapher/serialize_helpers.rb /^module DependencyGrapher$/;" m
21
+ DependencyGrapher lib/dependency_grapher/test_helpers.rb /^module DependencyGrapher$/;" m
22
+ DependencyGrapher lib/dependency_grapher/version.rb /^module DependencyGrapher$/;" m
23
+ DependencyGrapherTest test/dependency_grapher_test.rb /^class DependencyGrapherTest < Minitest::Test$/;" c
24
+ DependencyTest test/dependency_test.rb /^class DependencyTest < Minitest::Test$/;" c
25
+ DotGenerator lib/dependency_grapher/dot_generator.rb /^ class DotGenerator$/;" c class:DependencyGrapher
26
+ GetKnownClasses lib/dependency_grapher/get_known_classes.rb /^ class GetKnownClasses$/;" c class:DependencyGrapher
27
+ Grapher lib/dependency_grapher/grapher.rb /^ class Grapher$/;" c class:DependencyGrapher
28
+ Logger lib/dependency_grapher/logger.rb /^ class Logger$/;" c class:DependencyGrapher
29
+ LoggerTest test/logger_test.rb /^class LoggerTest < Minitest::Test$/;" c
30
+ Method lib/dependency_grapher/method.rb /^ class Method$/;" c class:DependencyGrapher
31
+ MethodTest test/method_test.rb /^class MethodTest < Minitest::Test$/;" c
32
+ ParseClass lib/dependency_grapher/parse_class.rb /^ class ParseClass$/;" c class:DependencyGrapher
33
+ ParseClassTest test/parse_class_test.rb /^class ParseClassTest < Minitest::Test$/;" c
34
+ Railtie lib/dependency_grapher/railtie.rb /^ class Railtie < Rails::Railtie$/;" c class:DependencyGrapher
35
+ SerializeHelpers lib/dependency_grapher/serialize_helpers.rb /^ module SerializeHelpers$/;" m class:DependencyGrapher
36
+ TestHelpers lib/dependency_grapher/test_helpers.rb /^ module TestHelpers$/;" m class:DependencyGrapher
37
+ add_filters lib/dependency_grapher/dependency_filter.rb /^ def add_filters(*filters)$/;" f class:DependencyGrapher.DependencyFilter
38
+ add_to_graph lib/dependency_grapher/dot_generator.rb /^ def add_to_graph(method)$/;" f class:DependencyGrapher.DotGenerator
39
+ ancestors lib/dependency_grapher/method.rb /^ def ancestors$/;" f class:DependencyGrapher.Method
40
+ anon_class_pattern? lib/dependency_grapher/parse_class.rb /^ def anon_class_pattern?(name)$/;" f class:DependencyGrapher.ParseClass
41
+ anon_pattern lib/dependency_grapher/parse_class.rb /^ def anon_pattern $/;" f class:DependencyGrapher.ParseClass
42
+ apply_filter lib/dependency_grapher/dependency_filter.rb /^ def apply_filter(filter)$/;" f class:DependencyGrapher.DependencyFilter
43
+ apply_filters lib/dependency_grapher/dependency_filter.rb /^ def apply_filters$/;" f class:DependencyGrapher.DependencyFilter
44
+ call lib/dependency_grapher/get_known_classes.rb /^ def self.call$/;" F class:DependencyGrapher.GetKnownClasses
45
+ call lib/dependency_grapher/parse_class.rb /^ def call(klass)$/;" f class:DependencyGrapher.ParseClass
46
+ call test/logger_test.rb /^ def self.call$/;" F class:LoggerTest.setup
47
+ dependencies lib/dependency_grapher/dependency_filter.rb /^ def dependencies$/;" f class:DependencyGrapher.DependencyFilter
48
+ deserialize lib/dependency_grapher/serialize_helpers.rb /^ def self.deserialize(string)$/;" F class:DependencyGrapher.SerializeHelpers
49
+ disable lib/dependency_grapher/logger.rb /^ def disable$/;" f class:DependencyGrapher.Logger
50
+ dump lib/dependency_grapher/grapher.rb /^ def dump(format = :dot, name = @name)$/;" f class:DependencyGrapher.Grapher
51
+ enable lib/dependency_grapher/logger.rb /^ def enable$/;" f class:DependencyGrapher.Logger
52
+ from_yaml lib/dependency_grapher/serialize_helpers.rb /^ def self.from_yaml(yaml_string)$/;" F class:DependencyGrapher.SerializeHelpers
53
+ generate_graph_from_dependencies lib/dependency_grapher/dot_generator.rb /^ def generate_graph_from_dependencies$/;" f class:DependencyGrapher.DotGenerator
54
+ initialize lib/dependency_grapher/dependency.rb /^ def initialize(caller, receiver)$/;" f class:DependencyGrapher.Dependency
55
+ initialize lib/dependency_grapher/dependency_filter.rb /^ def initialize(dependencies, *filters)$/;" f class:DependencyGrapher.DependencyFilter
56
+ initialize lib/dependency_grapher/dot_generator.rb /^ def initialize(dependencies)$/;" f class:DependencyGrapher.DotGenerator
57
+ initialize lib/dependency_grapher/grapher.rb /^ def initialize(name = "dependencies")$/;" f class:DependencyGrapher.Grapher
58
+ initialize lib/dependency_grapher/logger.rb /^ def initialize$/;" f class:DependencyGrapher.Logger
59
+ initialize lib/dependency_grapher/method.rb /^ def initialize(defined_class, method_id)$/;" f class:DependencyGrapher.Method
60
+ leaf lib/dependency_grapher/method.rb /^ def leaf$/;" f class:DependencyGrapher.Method
61
+ load lib/dependency_grapher/grapher.rb /^ def load(name = @name)$/;" f class:DependencyGrapher.Grapher
62
+ nested_anon_pattern lib/dependency_grapher/parse_class.rb /^ def nested_anon_pattern $/;" f class:DependencyGrapher.ParseClass
63
+ parse_anon_class_name lib/dependency_grapher/parse_class.rb /^ def parse_anon_class_name(name)$/;" f class:DependencyGrapher.ParseClass
64
+ push_call lib/dependency_grapher/logger.rb /^ def push_call(defined_class, method)$/;" f class:DependencyGrapher.Logger
65
+ remove_filters lib/dependency_grapher/dependency_filter.rb /^ def remove_filters(*filters)$/;" f class:DependencyGrapher.DependencyFilter
66
+ root lib/dependency_grapher/method.rb /^ def root$/;" f class:DependencyGrapher.Method
67
+ serialize lib/dependency_grapher/serialize_helpers.rb /^ def serialize$/;" f class:DependencyGrapher.SerializeHelpers
68
+ setup test/dependency_filter_test.rb /^ def setup$/;" f class:DependencyFilterTest
69
+ setup test/dependency_test.rb /^ def setup$/;" f class:DependencyTest
70
+ setup test/logger_test.rb /^ def setup$/;" f class:LoggerTest
71
+ setup test/method_test.rb /^ def setup$/;" f class:MethodTest
72
+ setup test/parse_class_test.rb /^ def setup$/;" f class:ParseClassTest
73
+ teardown test/dependency_filter_test.rb /^ def teardown $/;" f class:DependencyFilterTest
74
+ teardown test/dependency_test.rb /^ def teardown $/;" f class:DependencyTest
75
+ teardown test/logger_test.rb /^ def teardown $/;" f class:LoggerTest
76
+ teardown test/method_test.rb /^ def teardown $/;" f class:MethodTest
77
+ teardown test/parse_class_test.rb /^ def teardown $/;" f class:ParseClassTest
78
+ test_deserialize_from_file test/dependency_test.rb /^ def test_deserialize_from_file$/;" f class:DependencyTest
79
+ test_enable test/logger_test.rb /^ def test_enable$/;" f class:LoggerTest
80
+ test_parse test/parse_class_test.rb /^ def test_parse$/;" f class:ParseClassTest
81
+ test_serialize test/dependency_test.rb /^ def test_serialize$/;" f class:DependencyTest
82
+ test_serialize test/method_test.rb /^ def test_serialize$/;" f class:MethodTest
83
+ test_that_it_has_a_version_number test/dependency_grapher_test.rb /^ def test_that_it_has_a_version_number$/;" f class:DependencyGrapherTest
84
+ to_yaml lib/dependency_grapher/serialize_helpers.rb /^ def to_yaml$/;" f class:DependencyGrapher.SerializeHelpers
metadata ADDED
@@ -0,0 +1,216 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dependency_grapher
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tianming Zhuang
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-03-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ruby-graphviz
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest-reporters
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard-minitest
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: mocha
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: bundler
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: byebug
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: pry
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ description: For applications that use minitest as the automated test framework. This
154
+ gem provides a class for logging the dependencies of the application while the test
155
+ runs, and another for analyzing those dependencies and producing a graph.
156
+ email:
157
+ - tianming.zhuang@gmail.com
158
+ executables: []
159
+ extensions: []
160
+ extra_rdoc_files: []
161
+ files:
162
+ - ".byebug_history"
163
+ - ".gitignore"
164
+ - ".travis.yml"
165
+ - CODE_OF_CONDUCT.md
166
+ - Gemfile
167
+ - Guardfile
168
+ - LICENSE.txt
169
+ - README.md
170
+ - README.md.orig
171
+ - Rakefile
172
+ - bin/console
173
+ - bin/setup
174
+ - dependency.yml
175
+ - dependency_grapher.gemspec
176
+ - lib/dependency_grapher.rb
177
+ - lib/dependency_grapher/analyzer.rb
178
+ - lib/dependency_grapher/dependency.rb
179
+ - lib/dependency_grapher/deserialize_dependencies.rb
180
+ - lib/dependency_grapher/filter.rb
181
+ - lib/dependency_grapher/get_known_classes.rb
182
+ - lib/dependency_grapher/grapher.rb
183
+ - lib/dependency_grapher/logger.rb
184
+ - lib/dependency_grapher/method.rb
185
+ - lib/dependency_grapher/parse_class.rb
186
+ - lib/dependency_grapher/railtie.rb
187
+ - lib/dependency_grapher/serialize_helpers.rb
188
+ - lib/dependency_grapher/test_helpers.rb
189
+ - lib/dependency_grapher/version.rb
190
+ - lib/tasks/dependency_grapher.rake
191
+ - tags
192
+ homepage: https://github.com/tmzhuang/dependency_grapher
193
+ licenses:
194
+ - MIT
195
+ metadata: {}
196
+ post_install_message:
197
+ rdoc_options: []
198
+ require_paths:
199
+ - lib
200
+ required_ruby_version: !ruby/object:Gem::Requirement
201
+ requirements:
202
+ - - ">="
203
+ - !ruby/object:Gem::Version
204
+ version: '0'
205
+ required_rubygems_version: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - ">="
208
+ - !ruby/object:Gem::Version
209
+ version: '0'
210
+ requirements: []
211
+ rubyforge_project:
212
+ rubygems_version: 2.5.1
213
+ signing_key:
214
+ specification_version: 4
215
+ summary: Graphical vizualization of Ruby application dependencies.
216
+ test_files: []