callgraphy 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 29225780635c57496566adb69881751e4adbbcdc
4
+ data.tar.gz: 18dbbff30817c6990c76bfeb00067c73d39f2e5d
5
+ SHA512:
6
+ metadata.gz: 3f44b0e5c67c16f6a061312e1372d67ea97cbafe60d48a62eaa16c03aba34c19d7d248dde30061c5965e6311c78a8c57391b0f8b0c66d5d2f50951438bd56584
7
+ data.tar.gz: 39885e30e554d0b1528d246e928a91b75d75692a28b7152f7a9f9802bcb565828dabc7f3378a5598541fd7b5e68c19c16712e42252fecaaff2d922640b1a40c8
data/.envrc ADDED
@@ -0,0 +1,2 @@
1
+ # Enables the project's binstubs
2
+ PATH_add bin
@@ -0,0 +1,6 @@
1
+ /pkg
2
+ /.bundle/
3
+ /Gemfile.lock
4
+ /coverage/
5
+ /pkg/
6
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format documentation
3
+ --require spec_helper
@@ -0,0 +1,41 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.1
3
+
4
+ Exclude:
5
+ - "bin/**/*"
6
+
7
+ Metrics/LineLength:
8
+ Max: 120
9
+
10
+ # I like to use the hash rocket in rake files and the sample.
11
+ Style/HashSyntax:
12
+ Exclude:
13
+ - "Rakefile"
14
+ - "sample/rule_service_graph.rb"
15
+
16
+ # I like to use a difference alignment for the sample.
17
+ Style/AlignParameters:
18
+ Exclude:
19
+ - "sample/rule_service_graph.rb"
20
+
21
+ # I'll just use double quotes everywhere.
22
+ Style/StringLiterals:
23
+ EnforcedStyle: double_quotes
24
+
25
+ # I am not going to optimize by freezing strings.
26
+ Style/MutableConstant:
27
+ Enabled: false
28
+
29
+ # I am not going to distinguish between fail and raise.
30
+ Style/SignalException:
31
+ Enabled: false
32
+
33
+ # I'm not so fond of %w for word arrays.
34
+ Style/WordArray:
35
+ Enabled: false
36
+
37
+ # I'm okay with more complex methods in specs.
38
+ Metrics/AbcSize:
39
+ Max: 25
40
+ Include:
41
+ - "spec/**/*"
@@ -0,0 +1 @@
1
+ 2.2.4
@@ -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 alistairm@nulogy.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,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Alistair McKinnell
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.
@@ -0,0 +1,64 @@
1
+ # Callgraphy
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/callgraphy.svg)](https://badge.fury.io/rb/callgraphy)
4
+
5
+ Callgraphy is a simple tool that provides a DSL for creating call tree graphs for a target class.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem "callgraphy"
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install callgraphy
20
+
21
+ ## Usage
22
+
23
+ require "callgraphy"
24
+
25
+ Callgraphy.draw target: "rule_service" do
26
+ methods_to_graph :public,
27
+ :generate_lot_code => [:generate_lot_code_fragments, :reference_value_for],
28
+ :interpret_mfg_date_from_lot => [:earliest_date, :interpret_from]
29
+
30
+ methods_to_graph :private,
31
+ :earliest_date => [:validate_length],
32
+ :generate_lot_code_fragments => [],
33
+ :interpret_from => [:validate_length],
34
+ :reference_value_for => [],
35
+ :validate_length => []
36
+
37
+ constants_to_graph :callers,
38
+ :code_generation_service => [:generate_lot_code, :interpret_mfg_date_from_lot]
39
+
40
+ constants_to_graph :dependencies,
41
+ :earliest_date => [:earliest_date_interpreter]
42
+ end
43
+
44
+ ![RuleService Call Graph](https://github.com/amckinnell/callgraphy/blob/master/sample/rule_service.png)
45
+
46
+ ## Development
47
+
48
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests.
49
+ You can also run `bin/console` for an interactive prompt that will allow you to experiment.
50
+
51
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version,
52
+ update the version number in `version.rb`, and then run `bundle exec rake release`,
53
+ which will create a git tag for the version, push git commits and tags, and push the `.gem` file
54
+ to [rubygems.org](https://rubygems.org).
55
+
56
+ ## Contributing
57
+
58
+ Bug reports and pull requests are welcome on GitHub at https://github.com/amckinnell/callgraphy.
59
+ This project is intended to be a safe, welcoming space for collaboration, and contributors are
60
+ expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
61
+
62
+ ## License
63
+
64
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require "rubocop/rake_task"
4
+
5
+ RuboCop::RakeTask.new
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task :default => [:rubocop, :spec]
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'bundler' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require "pathname"
10
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require "rubygems"
14
+ require "bundler/setup"
15
+
16
+ load Gem.bin_path("bundler", "bundler")
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "calligraphy"
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
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'dot2ruby' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require "pathname"
10
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require "rubygems"
14
+ require "bundler/setup"
15
+
16
+ load Gem.bin_path("ruby-graphviz", "dot2ruby")
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'gem2gv' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require "pathname"
10
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require "rubygems"
14
+ require "bundler/setup"
15
+
16
+ load Gem.bin_path("ruby-graphviz", "gem2gv")
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'git2gv' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require "pathname"
10
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require "rubygems"
14
+ require "bundler/setup"
15
+
16
+ load Gem.bin_path("ruby-graphviz", "git2gv")
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'htmldiff' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require "pathname"
10
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require "rubygems"
14
+ require "bundler/setup"
15
+
16
+ load Gem.bin_path("diff-lcs", "htmldiff")
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'ldiff' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require "pathname"
10
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require "rubygems"
14
+ require "bundler/setup"
15
+
16
+ load Gem.bin_path("diff-lcs", "ldiff")
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'mutant' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require "pathname"
10
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require "rubygems"
14
+ require "bundler/setup"
15
+
16
+ load Gem.bin_path("mutant", "mutant")
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rake' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require "pathname"
10
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require "rubygems"
14
+ require "bundler/setup"
15
+
16
+ load Gem.bin_path("rake", "rake")
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rspec' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require "pathname"
10
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require "rubygems"
14
+ require "bundler/setup"
15
+
16
+ load Gem.bin_path("rspec-core", "rspec")
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rubocop' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require "pathname"
10
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require "rubygems"
14
+ require "bundler/setup"
15
+
16
+ load Gem.bin_path("rubocop", "rubocop")
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'ruby-parse' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require "pathname"
10
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require "rubygems"
14
+ require "bundler/setup"
15
+
16
+ load Gem.bin_path("parser", "ruby-parse")
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'ruby-rewrite' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require "pathname"
10
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require "rubygems"
14
+ require "bundler/setup"
15
+
16
+ load Gem.bin_path("parser", "ruby-rewrite")
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'ruby2gv' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require "pathname"
10
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require "rubygems"
14
+ require "bundler/setup"
15
+
16
+ load Gem.bin_path("ruby-graphviz", "ruby2gv")
@@ -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
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'unparser' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require "pathname"
10
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require "rubygems"
14
+ require "bundler/setup"
15
+
16
+ load Gem.bin_path("unparser", "unparser")
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'xml2gv' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require "pathname"
10
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require "rubygems"
14
+ require "bundler/setup"
15
+
16
+ load Gem.bin_path("ruby-graphviz", "xml2gv")
@@ -0,0 +1,30 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "callgraphy/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "callgraphy"
7
+ spec.version = Callgraphy::VERSION
8
+ spec.authors = ["Alistair McKinnell"]
9
+ spec.email = ["alistair.mckinnell@gmail.com"]
10
+
11
+ spec.summary = "A command line tool for creating a call graph for a target class."
12
+ spec.homepage = "https://github.com/amckinnell/callgraphy"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
+ spec.bindir = "exe"
17
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.required_ruby_version = "~> 2.1"
21
+
22
+ spec.add_runtime_dependency "ruby-graphviz", "~> 1.2", ">= 1.2.0"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.11", ">= 1.11.0"
25
+ spec.add_development_dependency "mutant-rspec", "~> 0.8.0"
26
+ spec.add_development_dependency "rake", "~> 11.1", ">= 11.1.0"
27
+ spec.add_development_dependency "rspec", "~> 3.4", ">= 3.4.0"
28
+ spec.add_development_dependency "rubocop", "~> 0.38"
29
+ spec.add_development_dependency "simplecov", "~> 0.11"
30
+ end
@@ -0,0 +1,13 @@
1
+ require "callgraphy/call_graph"
2
+ require "callgraphy/definition"
3
+ require "callgraphy/registry"
4
+ require "callgraphy/utils"
5
+ require "callgraphy/version"
6
+
7
+ # Provides a DSL for creating call graphs for a target class.
8
+ #
9
+ module Callgraphy
10
+ def self.draw(target:, output_directory: ".", &block)
11
+ CallGraph.draw(target, output_directory, Definition.register(&block))
12
+ end
13
+ end
@@ -0,0 +1,77 @@
1
+ require "ruby-graphviz"
2
+
3
+ module Callgraphy
4
+ # Knows how to graph the target class call graph given the specified registry.
5
+ #
6
+ class CallGraph
7
+ NODE_OPTIONS = {
8
+ public: { style: "filled", fillcolor: "palegreen" },
9
+ private: {},
10
+ callers: { style: "filled", fillcolor: "lightblue" },
11
+ dependencies: { style: "filled", fillcolor: "lightcoral" }
12
+ }
13
+
14
+ attr_reader :registry
15
+
16
+ def self.draw(target, output_directory, registry)
17
+ new(target, output_directory, registry).graph
18
+ end
19
+
20
+ def initialize(target, output_directory, registry)
21
+ @target = target
22
+ @output_directory = output_directory
23
+ @registry = registry
24
+
25
+ @nodes = {}
26
+ end
27
+
28
+ def graph
29
+ add_methods
30
+ add_constants
31
+ add_calls
32
+
33
+ generate_graph
34
+ end
35
+
36
+ private
37
+
38
+ def add_methods
39
+ registry.all_public_methods.each { |name| add_node(name, NODE_OPTIONS[:public]) }
40
+ registry.all_private_methods.each { |name| add_node(name, NODE_OPTIONS[:private]) }
41
+ end
42
+
43
+ def add_constants
44
+ registry.all_callers.each { |name| add_node(name, add_constant_label(name, NODE_OPTIONS[:callers])) }
45
+ registry.all_dependencies.each { |name| add_node(name, add_constant_label(name, NODE_OPTIONS[:dependencies])) }
46
+ end
47
+
48
+ def add_node(node_name, node_opts)
49
+ @nodes[node_name] = graphviz.add_nodes(node_name, node_opts.dup)
50
+ end
51
+
52
+ def add_constant_label(constant_name, node_opts)
53
+ node_opts.merge(label: Utils.pascal_case(constant_name))
54
+ end
55
+
56
+ def add_calls
57
+ registry.all_calls.each { |caller, callee| add_call(caller, callee) }
58
+ end
59
+
60
+ def add_call(caller, callee)
61
+ graphviz.add_edges(@nodes.fetch(caller), @nodes.fetch(callee))
62
+ end
63
+
64
+ def generate_graph
65
+ graphviz.output(png: graph_filename)
66
+ end
67
+
68
+ def graph_filename
69
+ File.join(@output_directory, "#{@target}.png")
70
+ end
71
+
72
+ def graphviz
73
+ @graphviz ||= GraphViz.new(:G, type: :digraph, labelloc: "b", label:
74
+ "Target class is #{Utils.pascal_case(@target)}")
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,69 @@
1
+ module Callgraphy
2
+ # Exposes a DSL to describe call graphs for a target class.
3
+ #
4
+ class Definition
5
+ attr_reader :registry
6
+
7
+ def self.register(&block)
8
+ definition = Definition.new(Registry.new)
9
+ definition.instance_eval(&block)
10
+ definition.registry
11
+ end
12
+
13
+ def initialize(registry)
14
+ @registry = registry
15
+ end
16
+
17
+ def methods_to_graph(method_scope, calls)
18
+ validate_scope(method_scope, :public, :private)
19
+ register_methods_to_graph(method_scope, calls)
20
+ end
21
+
22
+ def constants_to_graph(constant_scope, calls)
23
+ validate_scope(constant_scope, :callers, :dependencies)
24
+ register_constants_to_graph(constant_scope, calls)
25
+ end
26
+
27
+ private
28
+
29
+ def register_methods_to_graph(method_scope, calls)
30
+ register_calls(calls) do |caller, _callees|
31
+ register_method(method_scope, caller)
32
+ end
33
+ end
34
+
35
+ def register_constants_to_graph(constant_scope, calls)
36
+ register_calls(calls) do |caller, callees|
37
+ register_constants(constant_scope, caller, callees)
38
+ end
39
+ end
40
+
41
+ def register_constants(constant_scope, caller, callees)
42
+ constants = constant_scope == :callers ? caller : callees
43
+ register_constant(constant_scope, constants)
44
+ end
45
+
46
+ def register_calls(calls)
47
+ calls.each do |caller, callees|
48
+ yield(caller, callees)
49
+ register_each_call(caller, callees)
50
+ end
51
+ end
52
+
53
+ def register_each_call(caller, callees)
54
+ callees.each { |callee| registry.register_call(caller, callee) }
55
+ end
56
+
57
+ def register_method(method_scope, caller)
58
+ registry.register_method(method_scope, caller)
59
+ end
60
+
61
+ def register_constant(constant_scope, constants)
62
+ Array(constants).each { |constant| registry.register_constant(constant_scope, constant) }
63
+ end
64
+
65
+ def validate_scope(scope, *valid_scopes)
66
+ raise "Invalid scope: #{scope}" unless valid_scopes.include?(scope)
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,44 @@
1
+ module Callgraphy
2
+ # Records the information that describes a call graph.
3
+ #
4
+ class Registry
5
+ def initialize
6
+ @registry = { public: [], private: [], callers: [], dependencies: [], calls: [] }
7
+ end
8
+
9
+ def register_method(scope, caller)
10
+ @registry.fetch(scope).push(caller.to_s)
11
+ end
12
+ alias register_constant register_method
13
+
14
+ def register_call(caller, callee)
15
+ @registry.fetch(:calls).push([caller.to_s, callee.to_s])
16
+ end
17
+
18
+ def all_public_methods
19
+ normalized :public
20
+ end
21
+
22
+ def all_private_methods
23
+ normalized :private
24
+ end
25
+
26
+ def all_calls
27
+ normalized :calls
28
+ end
29
+
30
+ def all_callers
31
+ normalized :callers
32
+ end
33
+
34
+ def all_dependencies
35
+ normalized :dependencies
36
+ end
37
+
38
+ private
39
+
40
+ def normalized(category)
41
+ @registry.fetch(category).sort.uniq
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,9 @@
1
+ module Callgraphy
2
+ # Utility methods.
3
+ #
4
+ module Utils
5
+ def self.pascal_case(snake_case)
6
+ snake_case.split("_").map(&:capitalize).join
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module Callgraphy
2
+ VERSION = "0.2.0"
3
+ end
Binary file
@@ -0,0 +1,20 @@
1
+ require "callgraphy"
2
+
3
+ Callgraphy.draw target: "rule_service" do
4
+ methods_to_graph :public,
5
+ :generate_lot_code => [:generate_lot_code_fragments, :reference_value_for],
6
+ :interpret_mfg_date_from_lot => [:earliest_date, :interpret_from]
7
+
8
+ methods_to_graph :private,
9
+ :earliest_date => [:validate_length],
10
+ :generate_lot_code_fragments => [],
11
+ :interpret_from => [:validate_length],
12
+ :reference_value_for => [],
13
+ :validate_length => []
14
+
15
+ constants_to_graph :callers,
16
+ :code_generation_service => [:generate_lot_code, :interpret_mfg_date_from_lot]
17
+
18
+ constants_to_graph :dependencies,
19
+ :earliest_date => [:earliest_date_interpreter]
20
+ end
metadata ADDED
@@ -0,0 +1,202 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: callgraphy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Alistair McKinnell
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-03-24 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: '1.2'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.2.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.2'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.2.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: bundler
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.11'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 1.11.0
43
+ type: :development
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '1.11'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 1.11.0
53
+ - !ruby/object:Gem::Dependency
54
+ name: mutant-rspec
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: 0.8.0
60
+ type: :development
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: 0.8.0
67
+ - !ruby/object:Gem::Dependency
68
+ name: rake
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '11.1'
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: 11.1.0
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '11.1'
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: 11.1.0
87
+ - !ruby/object:Gem::Dependency
88
+ name: rspec
89
+ requirement: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - "~>"
92
+ - !ruby/object:Gem::Version
93
+ version: '3.4'
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 3.4.0
97
+ type: :development
98
+ prerelease: false
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.4'
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: 3.4.0
107
+ - !ruby/object:Gem::Dependency
108
+ name: rubocop
109
+ requirement: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - "~>"
112
+ - !ruby/object:Gem::Version
113
+ version: '0.38'
114
+ type: :development
115
+ prerelease: false
116
+ version_requirements: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - "~>"
119
+ - !ruby/object:Gem::Version
120
+ version: '0.38'
121
+ - !ruby/object:Gem::Dependency
122
+ name: simplecov
123
+ requirement: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - "~>"
126
+ - !ruby/object:Gem::Version
127
+ version: '0.11'
128
+ type: :development
129
+ prerelease: false
130
+ version_requirements: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - "~>"
133
+ - !ruby/object:Gem::Version
134
+ version: '0.11'
135
+ description:
136
+ email:
137
+ - alistair.mckinnell@gmail.com
138
+ executables: []
139
+ extensions: []
140
+ extra_rdoc_files: []
141
+ files:
142
+ - ".envrc"
143
+ - ".gitignore"
144
+ - ".rspec"
145
+ - ".rubocop.yml"
146
+ - ".ruby-version"
147
+ - CODE_OF_CONDUCT.md
148
+ - Gemfile
149
+ - LICENSE.txt
150
+ - README.md
151
+ - Rakefile
152
+ - bin/bundler
153
+ - bin/console
154
+ - bin/dot2ruby
155
+ - bin/gem2gv
156
+ - bin/git2gv
157
+ - bin/htmldiff
158
+ - bin/ldiff
159
+ - bin/mutant
160
+ - bin/rake
161
+ - bin/rspec
162
+ - bin/rubocop
163
+ - bin/ruby-parse
164
+ - bin/ruby-rewrite
165
+ - bin/ruby2gv
166
+ - bin/setup
167
+ - bin/unparser
168
+ - bin/xml2gv
169
+ - callgraphy.gemspec
170
+ - lib/callgraphy.rb
171
+ - lib/callgraphy/call_graph.rb
172
+ - lib/callgraphy/definition.rb
173
+ - lib/callgraphy/registry.rb
174
+ - lib/callgraphy/utils.rb
175
+ - lib/callgraphy/version.rb
176
+ - sample/rule_service.png
177
+ - sample/rule_service_graph.rb
178
+ homepage: https://github.com/amckinnell/callgraphy
179
+ licenses:
180
+ - MIT
181
+ metadata: {}
182
+ post_install_message:
183
+ rdoc_options: []
184
+ require_paths:
185
+ - lib
186
+ required_ruby_version: !ruby/object:Gem::Requirement
187
+ requirements:
188
+ - - "~>"
189
+ - !ruby/object:Gem::Version
190
+ version: '2.1'
191
+ required_rubygems_version: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - ">="
194
+ - !ruby/object:Gem::Version
195
+ version: '0'
196
+ requirements: []
197
+ rubyforge_project:
198
+ rubygems_version: 2.4.8
199
+ signing_key:
200
+ specification_version: 4
201
+ summary: A command line tool for creating a call graph for a target class.
202
+ test_files: []