deps_grapher 1.0.0
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +16 -0
- data/LICENSE.txt +21 -0
- data/README.md +327 -0
- data/Rakefile +12 -0
- data/bin/console +15 -0
- data/bin/deps_grapher +96 -0
- data/bin/setup +8 -0
- data/deps_grapher.gemspec +34 -0
- data/lefthook.yml +14 -0
- data/lib/deps_grapher/ast_processor.rb +211 -0
- data/lib/deps_grapher/ast_processor_policy.rb +45 -0
- data/lib/deps_grapher/cache_file.rb +48 -0
- data/lib/deps_grapher/cli.rb +29 -0
- data/lib/deps_grapher/command/analyzer.rb +89 -0
- data/lib/deps_grapher/command/init.rb +49 -0
- data/lib/deps_grapher/configuration.rb +99 -0
- data/lib/deps_grapher/context.rb +48 -0
- data/lib/deps_grapher/cytoscape/cose.rb +36 -0
- data/lib/deps_grapher/cytoscape/fcose.rb +36 -0
- data/lib/deps_grapher/cytoscape/klay.rb +27 -0
- data/lib/deps_grapher/cytoscape/template.erb +61 -0
- data/lib/deps_grapher/cytoscape.rb +88 -0
- data/lib/deps_grapher/dsl.rb +50 -0
- data/lib/deps_grapher/edge.rb +58 -0
- data/lib/deps_grapher/errors.rb +8 -0
- data/lib/deps_grapher/event.rb +63 -0
- data/lib/deps_grapher/graph.rb +71 -0
- data/lib/deps_grapher/graphile/generator.rb +42 -0
- data/lib/deps_grapher/graphile/graphile.erb +119 -0
- data/lib/deps_grapher/graphile/graphile.temp.erb +23 -0
- data/lib/deps_grapher/html_writer.rb +16 -0
- data/lib/deps_grapher/input.rb +40 -0
- data/lib/deps_grapher/layer/registry.rb +32 -0
- data/lib/deps_grapher/layer.rb +75 -0
- data/lib/deps_grapher/logging.rb +21 -0
- data/lib/deps_grapher/matcher.rb +28 -0
- data/lib/deps_grapher/node.rb +65 -0
- data/lib/deps_grapher/plugin_dsl.rb +12 -0
- data/lib/deps_grapher/plugin_loader.rb +29 -0
- data/lib/deps_grapher/source.rb +51 -0
- data/lib/deps_grapher/source_cache/class_name_extractor.rb +60 -0
- data/lib/deps_grapher/source_cache/registry.rb +64 -0
- data/lib/deps_grapher/source_cache.rb +49 -0
- data/lib/deps_grapher/version.rb +5 -0
- data/lib/deps_grapher/vis/box.rb +21 -0
- data/lib/deps_grapher/vis/dot.rb +17 -0
- data/lib/deps_grapher/vis/template.erb +36 -0
- data/lib/deps_grapher/vis.rb +69 -0
- data/lib/deps_grapher/visualizer/base.rb +74 -0
- data/lib/deps_grapher/visualizer/color/registry.rb +30 -0
- data/lib/deps_grapher/visualizer/color.rb +62 -0
- data/lib/deps_grapher/visualizer/command_option.rb +22 -0
- data/lib/deps_grapher/visualizer/downloader.rb +42 -0
- data/lib/deps_grapher/visualizer/js_option.rb +39 -0
- data/lib/deps_grapher/visualizer/registry.rb +37 -0
- data/lib/deps_grapher/visualizer.rb +11 -0
- data/lib/deps_grapher.rb +42 -0
- metadata +135 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../cytoscape"
|
4
|
+
|
5
|
+
module DepsGrapher
|
6
|
+
class Cytoscape
|
7
|
+
class Klay < self
|
8
|
+
command_option "cy:klay", default: true
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def required_js
|
13
|
+
super.tap do |js|
|
14
|
+
js << "https://unpkg.com/klayjs/klay.js"
|
15
|
+
js << "https://raw.githubusercontent.com/cytoscape/cytoscape.js-klay/master/cytoscape-klay.js"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def layout_options
|
20
|
+
Visualizer::JsOption.new(
|
21
|
+
name: :klay,
|
22
|
+
nodeDimensionsIncludeLabels: true
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<title>Cytoscape</title>
|
6
|
+
<meta name=”viewport” content=”width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no″>
|
7
|
+
<% required_js.each do |js| -%>
|
8
|
+
<script src="<%= File.basename js %>"></script>
|
9
|
+
<% end -%>
|
10
|
+
<style>
|
11
|
+
#cy {
|
12
|
+
width: 100vw;
|
13
|
+
height: 100vh;
|
14
|
+
}
|
15
|
+
</style>
|
16
|
+
<script>
|
17
|
+
const backgroundColorMap = <%= color_map(:background).to_json %>;
|
18
|
+
document.addEventListener('DOMContentLoaded', function () {
|
19
|
+
const cy = cytoscape({
|
20
|
+
container: document.getElementById('cy'),
|
21
|
+
elements: <%= data.to_json %>,
|
22
|
+
layout: <%= layout_options %>,
|
23
|
+
style: [
|
24
|
+
{
|
25
|
+
selector: 'node',
|
26
|
+
style: {
|
27
|
+
'background-color': function(ele) {
|
28
|
+
return backgroundColorMap[ele.data('layer')];
|
29
|
+
},
|
30
|
+
'label': 'data(label)',
|
31
|
+
'font-size': '6%',
|
32
|
+
'width': function(ele) {
|
33
|
+
return Math.max(<%= min_width %>, ele.data('deps_count') * <%= coefficient %>);
|
34
|
+
},
|
35
|
+
'height': function(ele) {
|
36
|
+
return Math.max(<%= min_height %>, ele.data('deps_count') * <%= coefficient %>);
|
37
|
+
}
|
38
|
+
}
|
39
|
+
},
|
40
|
+
<% Layer.names.each do |layer_name| -%>
|
41
|
+
{
|
42
|
+
selector: 'edge[layer="<%= layer_name %>"]',
|
43
|
+
style: {
|
44
|
+
'width': 1,
|
45
|
+
'line-color': '<%= arrow_color(layer_name) %>',
|
46
|
+
'target-arrow-color': '<%= arrow_color(layer_name) %>',
|
47
|
+
'target-arrow-shape': 'triangle',
|
48
|
+
'curve-style': 'bezier'
|
49
|
+
}
|
50
|
+
},
|
51
|
+
<% end -%>
|
52
|
+
],
|
53
|
+
});
|
54
|
+
<%= advanced_render %>
|
55
|
+
});
|
56
|
+
</script>
|
57
|
+
</head>
|
58
|
+
<body>
|
59
|
+
<div id="cy"></div>
|
60
|
+
</body>
|
61
|
+
</html>
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "visualizer/base"
|
4
|
+
|
5
|
+
module DepsGrapher
|
6
|
+
class Cytoscape < Visualizer::Base
|
7
|
+
def required_js
|
8
|
+
[
|
9
|
+
"https://unpkg.com/cytoscape/dist/cytoscape.min.js",
|
10
|
+
"https://unpkg.com/layout-base/layout-base.js"
|
11
|
+
]
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def template_path
|
17
|
+
File.expand_path File.join("cytoscape", "template.erb"), __dir__
|
18
|
+
end
|
19
|
+
|
20
|
+
def min_width
|
21
|
+
"10"
|
22
|
+
end
|
23
|
+
|
24
|
+
def min_height
|
25
|
+
"10"
|
26
|
+
end
|
27
|
+
|
28
|
+
def coefficient
|
29
|
+
"0.2 * 10"
|
30
|
+
end
|
31
|
+
|
32
|
+
def layout_options
|
33
|
+
raise NotImplementedError
|
34
|
+
end
|
35
|
+
|
36
|
+
def advanced_render
|
37
|
+
""
|
38
|
+
end
|
39
|
+
|
40
|
+
def data
|
41
|
+
[].tap do |array|
|
42
|
+
@nodes.each do |node|
|
43
|
+
next if skip_node?(node)
|
44
|
+
|
45
|
+
array << convert_node(node)
|
46
|
+
end
|
47
|
+
|
48
|
+
@edges.each do |edge|
|
49
|
+
next if skip_edge?(edge)
|
50
|
+
|
51
|
+
array << convert_edge(edge)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def convert_node(node)
|
57
|
+
{
|
58
|
+
group: :nodes,
|
59
|
+
data: {
|
60
|
+
id: node.id,
|
61
|
+
layer: node.layer,
|
62
|
+
label: node.label,
|
63
|
+
deps_count: node.deps_count
|
64
|
+
}
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def convert_edge(edge)
|
69
|
+
{
|
70
|
+
group: :edges,
|
71
|
+
data: {
|
72
|
+
id: edge.id,
|
73
|
+
source: edge.from.id,
|
74
|
+
target: edge.to.id,
|
75
|
+
layer: edge.from.layer
|
76
|
+
}
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
def skip_node?(node)
|
81
|
+
options[:layers].present? && !options[:layers].include?(node.layer)
|
82
|
+
end
|
83
|
+
|
84
|
+
def skip_edge?(edge)
|
85
|
+
skip_node?(edge.from) || skip_node?(edge.to)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DepsGrapher
|
4
|
+
class DSL
|
5
|
+
def initialize(obj)
|
6
|
+
@obj = obj
|
7
|
+
end
|
8
|
+
|
9
|
+
def respond_to_missing?(symbol, include_private = false)
|
10
|
+
["#{symbol}=", symbol].each do |method_name|
|
11
|
+
return true if @obj.respond_to?(method_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def method_missing(symbol, *args, &block)
|
20
|
+
["#{symbol}=", symbol].each do |method_name|
|
21
|
+
next unless @obj.respond_to?(method_name)
|
22
|
+
|
23
|
+
parameters = @obj.method(method_name).parameters
|
24
|
+
|
25
|
+
return @obj.send(method_name) if parameters.empty?
|
26
|
+
|
27
|
+
if parameters.size == 1
|
28
|
+
parameter = parameters.first
|
29
|
+
case parameter[0]
|
30
|
+
when :req, :opt
|
31
|
+
return @obj.send(method_name, args.first.freeze)
|
32
|
+
when :block
|
33
|
+
return @obj.send(method_name, &block)
|
34
|
+
else
|
35
|
+
raise ArgumentError, "unsupported parameter type: #{parameter[0]}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
next unless parameters.size == 2
|
40
|
+
|
41
|
+
arg_type_1st, arg_type_2nd = parameters.flat_map(&:first)
|
42
|
+
return @obj.send(method_name, args.first.freeze, &block) if %i[req opt].include?(arg_type_1st) && arg_type_2nd == :block
|
43
|
+
|
44
|
+
raise ArgumentError, "unsupported parameter types: #{arg_type_1st}, #{arg_type_2nd}"
|
45
|
+
end
|
46
|
+
|
47
|
+
super
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DepsGrapher
|
4
|
+
class Edge
|
5
|
+
class << self
|
6
|
+
def fetch(from, to)
|
7
|
+
id = generate_id from, to
|
8
|
+
registry.fetch id
|
9
|
+
end
|
10
|
+
|
11
|
+
def add(from, to)
|
12
|
+
return nil if from.nil? || to.nil?
|
13
|
+
|
14
|
+
id = generate_id from, to
|
15
|
+
|
16
|
+
return nil if registry.key?(id) || from.id == to.id
|
17
|
+
|
18
|
+
to.parent = from.id
|
19
|
+
to.increment_deps_count!
|
20
|
+
|
21
|
+
registry[id] = new id, from, to
|
22
|
+
end
|
23
|
+
|
24
|
+
def all
|
25
|
+
registry.values
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def generate_id(from, to)
|
31
|
+
"e:#{from.id}:#{to.id}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def registry
|
35
|
+
@registry ||= {}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private_class_method :new
|
40
|
+
|
41
|
+
attr_accessor :id, :from, :to
|
42
|
+
|
43
|
+
def initialize(id, from, to)
|
44
|
+
@id = id
|
45
|
+
@from = from
|
46
|
+
@to = to
|
47
|
+
end
|
48
|
+
|
49
|
+
def eql?(other)
|
50
|
+
other.is_a?(self.class) && id == other.id
|
51
|
+
end
|
52
|
+
alias == eql?
|
53
|
+
|
54
|
+
def hash
|
55
|
+
id.hash
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DepsGrapher
|
4
|
+
class Event
|
5
|
+
class << self
|
6
|
+
def generate_key(name, const_name, method)
|
7
|
+
return nil if const_name.nil? && method.nil?
|
8
|
+
|
9
|
+
key = name.to_s.dup
|
10
|
+
key << ".#{const_name}" if const_name
|
11
|
+
key << ".#{method}" if method
|
12
|
+
key
|
13
|
+
end
|
14
|
+
|
15
|
+
def add(name:, const_name:, location:, method: nil)
|
16
|
+
key = generate_key name, const_name, method
|
17
|
+
|
18
|
+
return nil if key.nil?
|
19
|
+
|
20
|
+
registry[key] ||= new(
|
21
|
+
name: name,
|
22
|
+
const_name: const_name,
|
23
|
+
location: location,
|
24
|
+
method: method
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def registry
|
31
|
+
@registry ||= {}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private_class_method :new
|
36
|
+
|
37
|
+
attr_accessor :name, :const_name, :location, :method
|
38
|
+
|
39
|
+
def initialize(name:, const_name:, location:, method:)
|
40
|
+
@name = name
|
41
|
+
@const_name = const_name
|
42
|
+
@location = location
|
43
|
+
@method = method
|
44
|
+
@skip_processing = false
|
45
|
+
end
|
46
|
+
|
47
|
+
def key
|
48
|
+
self.class.generate_key name, const_name, method
|
49
|
+
end
|
50
|
+
|
51
|
+
def processing!
|
52
|
+
@skip_processing = false
|
53
|
+
end
|
54
|
+
|
55
|
+
def skip_processing!
|
56
|
+
@skip_processing = true
|
57
|
+
end
|
58
|
+
|
59
|
+
def processing?
|
60
|
+
!@skip_processing
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DepsGrapher
|
4
|
+
class NullGraph
|
5
|
+
def add_edge(_); end
|
6
|
+
end
|
7
|
+
|
8
|
+
class Graph
|
9
|
+
def initialize
|
10
|
+
@graph = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_edge(edge)
|
14
|
+
@graph[edge.from] ||= []
|
15
|
+
@graph[edge.from] << edge.to
|
16
|
+
end
|
17
|
+
|
18
|
+
def find_path(source_path_matcher, target_path_matcher)
|
19
|
+
paths = []
|
20
|
+
visited = {}
|
21
|
+
|
22
|
+
@graph.each_key do |start_node|
|
23
|
+
next if source_path_matcher && !source_path_matcher.match?(start_node.class_name)
|
24
|
+
|
25
|
+
dfs start_node, target_path_matcher, visited, [start_node], paths
|
26
|
+
end
|
27
|
+
|
28
|
+
nodes = Set.new
|
29
|
+
edges = Set.new
|
30
|
+
|
31
|
+
paths.each do |path|
|
32
|
+
collect! path, nodes, edges
|
33
|
+
end
|
34
|
+
|
35
|
+
[nodes, edges]
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def dfs(current, target_path_matcher, visited, path, paths)
|
41
|
+
return if visited[current]
|
42
|
+
|
43
|
+
visited[current] = true
|
44
|
+
|
45
|
+
if target_path_matcher.match?(current.class_name)
|
46
|
+
paths << path
|
47
|
+
else
|
48
|
+
@graph[current]&.each do |node|
|
49
|
+
dfs node, target_path_matcher, visited, path + [node], paths
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
visited[current] = false
|
54
|
+
end
|
55
|
+
|
56
|
+
def collect!(path, nodes, edges)
|
57
|
+
current_node = nil
|
58
|
+
path.each do |node|
|
59
|
+
nodes << node
|
60
|
+
|
61
|
+
if current_node.nil?
|
62
|
+
current_node = node
|
63
|
+
next
|
64
|
+
end
|
65
|
+
|
66
|
+
edges << Edge.fetch(current_node, node)
|
67
|
+
current_node = node
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DepsGrapher
|
4
|
+
module Graphile
|
5
|
+
class Generator
|
6
|
+
def initialize(config)
|
7
|
+
@config = config
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(dest)
|
11
|
+
if dest
|
12
|
+
File.write dest, read_template(temp: false)
|
13
|
+
return dest
|
14
|
+
end
|
15
|
+
|
16
|
+
path = nil
|
17
|
+
|
18
|
+
# unlink this temp file by GC
|
19
|
+
Tempfile.open("graphile_generator", config.cache_dir) do |f|
|
20
|
+
f.write read_template(temp: true)
|
21
|
+
path = f.path
|
22
|
+
end
|
23
|
+
|
24
|
+
path
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
attr_reader :config
|
30
|
+
|
31
|
+
def read_template(temp:)
|
32
|
+
b = config.instance_eval { binding }
|
33
|
+
ERB.new(File.read(resolve_path(temp)), trim_mode: "-").result(b)
|
34
|
+
end
|
35
|
+
|
36
|
+
def resolve_path(temp)
|
37
|
+
file_name = temp ? "graphile.temp.erb" : "graphile.erb"
|
38
|
+
File.expand_path(file_name, __dir__)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# directory settings
|
4
|
+
# customize for your project
|
5
|
+
output_dir File.expand_path File.join("tmp", "deps_grapher", "graph")
|
6
|
+
cache_dir File.expand_path File.join("tmp", "deps_grapher", "cache")
|
7
|
+
|
8
|
+
root_dir = "<%= root_dir %>"
|
9
|
+
lib_root_dir = File.join(root_dir, "lib")
|
10
|
+
layer_root_dir = File.join(lib_root_dir, "deps_grapher")
|
11
|
+
|
12
|
+
# default visualizer setting
|
13
|
+
visualizer "<%= visualizer %>"
|
14
|
+
|
15
|
+
ast_processor_policy do
|
16
|
+
exclude_const /\ADepsGrapher\z/
|
17
|
+
|
18
|
+
# advanced_const_resolver do |ast_node|
|
19
|
+
# # some advanced logic using ast_node of parser gem
|
20
|
+
# # this block should return a string of const name or nil
|
21
|
+
# # if return nil, the const name will be resolved by default logic
|
22
|
+
# end
|
23
|
+
end
|
24
|
+
|
25
|
+
layer do
|
26
|
+
name :deps_grapher
|
27
|
+
visible true
|
28
|
+
|
29
|
+
source do
|
30
|
+
root lib_root_dir
|
31
|
+
exclude_pattern %r{/(command|cytoscape|vis|visualizer)}
|
32
|
+
end
|
33
|
+
|
34
|
+
color do
|
35
|
+
background "#FF5252"
|
36
|
+
border "#EF5350"
|
37
|
+
font "#FF5252"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
layer do
|
42
|
+
name :command
|
43
|
+
visible true
|
44
|
+
|
45
|
+
source do
|
46
|
+
root File.join(layer_root_dir, "command")
|
47
|
+
end
|
48
|
+
|
49
|
+
color do
|
50
|
+
background "#512DA8"
|
51
|
+
border "#673AB7"
|
52
|
+
font "#512DA8"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
layer do
|
57
|
+
name :cytoscape
|
58
|
+
visible true
|
59
|
+
|
60
|
+
source do
|
61
|
+
root layer_root_dir
|
62
|
+
glob_pattern ["cytoscape.rb", "cytoscape/**/*.rb"]
|
63
|
+
end
|
64
|
+
|
65
|
+
color do
|
66
|
+
background "#448AFF"
|
67
|
+
border "#42A5F5"
|
68
|
+
font "#448AFF"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
layer do
|
73
|
+
name :vis
|
74
|
+
visible true
|
75
|
+
|
76
|
+
source do
|
77
|
+
root layer_root_dir
|
78
|
+
glob_pattern ["vis.rb", "vis/**/*.rb"]
|
79
|
+
end
|
80
|
+
|
81
|
+
color do
|
82
|
+
background "#00B8D4"
|
83
|
+
border "#00ACC1"
|
84
|
+
font "#00B8D4"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
layer do
|
89
|
+
name :visualizer
|
90
|
+
visible true
|
91
|
+
|
92
|
+
source do
|
93
|
+
root layer_root_dir
|
94
|
+
glob_pattern ["visualizer.rb", "visualizer/**/*.rb"]
|
95
|
+
end
|
96
|
+
|
97
|
+
color do
|
98
|
+
background "#00C853"
|
99
|
+
border "#4CAF50"
|
100
|
+
font "#00C853"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
with_plugin do |plugin_dir|
|
105
|
+
layer do
|
106
|
+
name :plugin
|
107
|
+
visible true
|
108
|
+
|
109
|
+
source do
|
110
|
+
root plugin_dir
|
111
|
+
end
|
112
|
+
|
113
|
+
color do
|
114
|
+
background "#607D8B"
|
115
|
+
border "#78909C"
|
116
|
+
font "#607D8B"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
output_dir File.join(Dir.home, ".deps_grapher", "graph")
|
4
|
+
cache_dir File.join(Dir.home, ".deps_grapher", "cache")
|
5
|
+
cache_ttl 60 * 5 # 5 minutes
|
6
|
+
|
7
|
+
root_dir = "<%= root_dir %>"
|
8
|
+
|
9
|
+
layer do
|
10
|
+
name :<%= File.basename(root_dir) %>
|
11
|
+
visible true
|
12
|
+
|
13
|
+
source do
|
14
|
+
root root_dir
|
15
|
+
exclude_pattern %r{/(?:vendor|spec)/}
|
16
|
+
end
|
17
|
+
|
18
|
+
color do
|
19
|
+
background "#448AFF"
|
20
|
+
border "#42A5F5"
|
21
|
+
font "#448AFF"
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DepsGrapher
|
4
|
+
class HtmlWriter
|
5
|
+
attr_reader :path
|
6
|
+
|
7
|
+
def initialize(output_dir)
|
8
|
+
FileUtils.mkdir_p output_dir
|
9
|
+
@path = File.join output_dir, "index.html"
|
10
|
+
end
|
11
|
+
|
12
|
+
def write(content)
|
13
|
+
File.write path, content
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DepsGrapher
|
4
|
+
class Input
|
5
|
+
def initialize(config)
|
6
|
+
@config = config
|
7
|
+
end
|
8
|
+
|
9
|
+
def files
|
10
|
+
FileUtils.rm_rf File.dirname(config.cache_dir) if config.clean
|
11
|
+
|
12
|
+
set_layers_visibility!
|
13
|
+
extract_files_from_layers
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
attr_reader :config
|
19
|
+
|
20
|
+
def set_layers_visibility!
|
21
|
+
layer_visibility = config.visualizer_options[:layers]
|
22
|
+
|
23
|
+
config.layers.each_value do |layer|
|
24
|
+
layer.visible = layer_visibility.include? layer.name
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def extract_files_from_layers
|
29
|
+
config.layers.values.select(&:visible).each_with_object([]) do |layer, files|
|
30
|
+
source = layer.source
|
31
|
+
|
32
|
+
source.files.each do |file|
|
33
|
+
next if file == config.path
|
34
|
+
|
35
|
+
files << file
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DepsGrapher
|
4
|
+
class Layer
|
5
|
+
module Registry
|
6
|
+
class << self
|
7
|
+
def fetch(file_path)
|
8
|
+
registry[file_path] || Layer::Default
|
9
|
+
end
|
10
|
+
alias [] fetch
|
11
|
+
|
12
|
+
def register(file_path, layer)
|
13
|
+
registry[file_path] ||= layer
|
14
|
+
end
|
15
|
+
|
16
|
+
def exist?(file_path)
|
17
|
+
registry.key? file_path
|
18
|
+
end
|
19
|
+
|
20
|
+
def all
|
21
|
+
registry.values
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def registry
|
27
|
+
@registry ||= {}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|