javaclass 0.0.4 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +18 -71
- data/Readme.txt +13 -22
- data/{example_task.rb → dev/example_task.rb} +1 -1
- data/dev/saikuro_task.rb +120 -0
- data/examples/chart_class_dependencies.rb +43 -0
- data/examples/chart_module_dependencies.rb +64 -0
- data/examples/check_interface_names.rb +3 -2
- data/examples/corpus.rb +52 -12
- data/examples/count_classes_in_modules.rb +2 -1
- data/examples/cumulative_dependencies.rb +4 -3
- data/examples/find_all_imported_types.rb +11 -7
- data/examples/find_incoming_dependency_graph.rb +81 -0
- data/examples/find_layers_of_modules.rb +79 -0
- data/examples/find_referenced_modules.rb +4 -6
- data/examples/find_unreferenced_classes.rb +14 -4
- data/examples/generate_class_lists.rb +1 -0
- data/examples/show_jar_api.rb +93 -0
- data/examples/test_corpus.rb +32 -0
- data/history.txt +17 -5
- data/javaclass.gemspec +9 -8
- data/lib/javaclass/analyse/dependencies.rb +1 -1
- data/lib/javaclass/analyse/transitive_dependencies.rb +2 -2
- data/lib/javaclass/classfile/class_magic.rb +1 -1
- data/lib/javaclass/classfile/constant_pool.rb +1 -0
- data/lib/javaclass/classfile/java_class_header_as_java_name.rb +4 -0
- data/lib/javaclass/classfile/java_class_header_shortcuts.rb +2 -0
- data/lib/javaclass/classlist/jar_searcher.rb +11 -5
- data/lib/javaclass/classlist/list.rb +27 -14
- data/lib/javaclass/classpath/any_classpath.rb +1 -1
- data/lib/javaclass/classpath/eclipse_classpath.rb +45 -25
- data/lib/javaclass/classpath/factory.rb +23 -13
- data/lib/javaclass/classpath/maven_artefact.rb +62 -0
- data/lib/javaclass/classpath/tracking_classpath.rb +3 -1
- data/lib/javaclass/dependencies/class_node.rb +36 -0
- data/lib/javaclass/dependencies/classpath_node.rb +37 -0
- data/lib/javaclass/dependencies/edge.rb +41 -0
- data/lib/javaclass/dependencies/graph.rb +53 -0
- data/lib/javaclass/dependencies/graphml_serializer.rb +102 -0
- data/lib/javaclass/dependencies/node.rb +82 -0
- data/lib/javaclass/dependencies/yaml_serializer.rb +103 -0
- data/lib/javaclass/dsl/java_name_factory.rb +2 -2
- data/lib/javaclass/gems/zip_file.rb +41 -33
- data/lib/javaclass/java_name.rb +1 -1
- data/lib/javaclass/java_name_scanner.rb +9 -7
- data/lib/javaclass/string_20.rb +40 -0
- data/lib/javaclass/string_hexdump.rb +18 -2
- data/lib/javaclass/string_ux.rb +3 -7
- data/planned.txt +50 -4
- data/rake_analysis.rb +46 -0
- data/test/data/api/packagename/Broken.class +0 -0
- data/test/logging_folder_classpath.rb +2 -2
- data/test/{test_adder_tree.rb → test_adder_tree_node.rb} +1 -1
- data/test/test_class_magic.rb +1 -1
- data/test/test_eclipse_classpath.rb +1 -1
- data/test/test_edge.rb +60 -0
- data/test/test_factory.rb +1 -1
- data/test/test_graph.rb +28 -0
- data/test/test_java_name.rb +13 -1
- data/test/test_javaclass_api.rb +18 -3
- data/test/test_maven_artefact.rb +37 -0
- data/test/test_node.rb +56 -0
- data/test/test_yaml_serializer.rb +105 -0
- data/test/ts_all_tests.rb +16 -3
- metadata +46 -35
- data/examples/profiler_scratchpad.rb +0 -33
- data/lib/javaclass/analyse/ideas.txt +0 -15
- data/lib/javaclass/classpath/classpaths.txt +0 -2
- data/lib/javaclass/classscanner/ideas.txt +0 -3
@@ -22,6 +22,7 @@ module JavaClass
|
|
22
22
|
# Returns the wrapped classpath element (+self+) of this decorated classpath.
|
23
23
|
def elements
|
24
24
|
if [FolderClasspath, JarClasspath].include?(@classpath.class)
|
25
|
+
# TODO check for any subclass of FileClasspath instead
|
25
26
|
[self]
|
26
27
|
else
|
27
28
|
@classpath.elements
|
@@ -90,11 +91,12 @@ module JavaClass
|
|
90
91
|
class CompositeClasspath
|
91
92
|
|
92
93
|
# Wrap the _elem_ classpath with a new TrackingClasspath and add it to the list of elements.
|
93
|
-
alias __old__add_element__ add_element
|
94
|
+
alias :__old__add_element__ :add_element unless method_defined?('__old__add_element__')
|
94
95
|
|
95
96
|
def add_element(elem)
|
96
97
|
unless @elements.find { |cpe| cpe == elem }
|
97
98
|
if [FolderClasspath, JarClasspath].include?(elem.class)
|
99
|
+
# TODO check for any subclass of FileClasspath instead -> fail a test with ConventionClasspath and Tracker
|
98
100
|
__old__add_element__(TrackingClasspath.new(elem))
|
99
101
|
else
|
100
102
|
__old__add_element__(elem)
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'javaclass/dependencies/node'
|
2
|
+
require 'javaclass/dependencies/edge'
|
3
|
+
|
4
|
+
module JavaClass
|
5
|
+
module Dependencies
|
6
|
+
|
7
|
+
# A concrete Node which contains a ClassFile and its dependencies.
|
8
|
+
# This models a Node as a Java class.
|
9
|
+
# Author:: Peter Kofler
|
10
|
+
class ClassNode < Node
|
11
|
+
|
12
|
+
def initialize(java_class)
|
13
|
+
super(java_class.to_classname)
|
14
|
+
@java_class = java_class
|
15
|
+
end
|
16
|
+
|
17
|
+
# Iterate on a list of Edge dependencies this node has.
|
18
|
+
def outgoing_dependencies
|
19
|
+
@java_class.imported_3rd_party_types.each do |import|
|
20
|
+
yield Edge.new(@java_class.to_classname, import.to_classname)
|
21
|
+
end
|
22
|
+
# later iterate all types/fields/methods and create an edge from the method to the target type.
|
23
|
+
# So Edges make sense and multiplicity in dependencies is possible.
|
24
|
+
end
|
25
|
+
|
26
|
+
# Does this Node satisfy the dependency to _class_name_ ?
|
27
|
+
def satisfies?(class_name)
|
28
|
+
@java_class.to_classname == class_name.to_classname
|
29
|
+
# later class name will be a full qualified class#method or field name.
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
# TODO add tests
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'javaclass/dependencies/node'
|
2
|
+
require 'javaclass/dependencies/edge'
|
3
|
+
|
4
|
+
module JavaClass
|
5
|
+
module Dependencies
|
6
|
+
|
7
|
+
# A concrete Node which contains a Classpath and its dependencies.
|
8
|
+
# This models a Node as a component, maybe an Eclipse plugin, a Maven module or a library.
|
9
|
+
# Dependencies (Edge) contain all references imported by any class of this component.
|
10
|
+
# Author:: Peter Kofler
|
11
|
+
class ClasspathNode < Node
|
12
|
+
|
13
|
+
def initialize(name, classpath)
|
14
|
+
super(name, classpath.count)
|
15
|
+
@classpath = classpath
|
16
|
+
end
|
17
|
+
|
18
|
+
# Iterate on a list of Edge dependencies this node has.
|
19
|
+
def outgoing_dependencies
|
20
|
+
@classpath.values.each do |clazz|
|
21
|
+
clazz.imported_3rd_party_types.each do |import|
|
22
|
+
unless satisfies?(import)
|
23
|
+
yield Edge.new(clazz.to_classname, import)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Does this Node satisfy the dependency _dependency_name_ .
|
30
|
+
def satisfies?(dependency_name)
|
31
|
+
@classpath.includes?(dependency_name)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module JavaClass
|
2
|
+
module Dependencies
|
3
|
+
|
4
|
+
# An edge in the Graph of dependencies. An edge knows it's source and destination details.
|
5
|
+
# Author:: Peter Kofler
|
6
|
+
class Edge
|
7
|
+
|
8
|
+
attr_reader :source
|
9
|
+
attr_reader :target
|
10
|
+
|
11
|
+
def initialize(source, target)
|
12
|
+
@source = source
|
13
|
+
@target = target
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
"#{@target} (#{@source})"
|
18
|
+
end
|
19
|
+
|
20
|
+
def ==(other)
|
21
|
+
@source == other.source && @target == other.target
|
22
|
+
end
|
23
|
+
|
24
|
+
alias eql? ==
|
25
|
+
|
26
|
+
def hash
|
27
|
+
[@source, @target].hash
|
28
|
+
end
|
29
|
+
|
30
|
+
def <=>(other)
|
31
|
+
res = @target <=> other.target
|
32
|
+
if res == 0
|
33
|
+
res = @source <=> other.source
|
34
|
+
end
|
35
|
+
res
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module JavaClass
|
2
|
+
|
3
|
+
# The module Dependencies is for separating namespaces. It contains logic
|
4
|
+
# to analyse and structure general directed dependency graphs. A set of
|
5
|
+
# dependencies build a Graph which can be analysed.
|
6
|
+
# Author:: Peter Kofler
|
7
|
+
module Dependencies
|
8
|
+
|
9
|
+
# A graph contains a list of Node
|
10
|
+
# Author:: Peter Kofler
|
11
|
+
class Graph
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@nodes = []
|
15
|
+
end
|
16
|
+
|
17
|
+
# Add a _node_ to this graph.
|
18
|
+
def add(node)
|
19
|
+
@nodes << node
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_a
|
23
|
+
@nodes.dup
|
24
|
+
end
|
25
|
+
|
26
|
+
# Iterates all nodes and fills the dependency fields of the Node.
|
27
|
+
def resolve_dependencies
|
28
|
+
@nodes.each do |node|
|
29
|
+
puts "processing #{node}"
|
30
|
+
|
31
|
+
node.outgoing_dependencies do |dependency|
|
32
|
+
providers = nodes_satisfying(dependency.target)
|
33
|
+
node.add_dependency(dependency, providers)
|
34
|
+
end
|
35
|
+
|
36
|
+
node.dependencies.values.each { |vals| vals.sort! }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Find the nodes that satisfy the given _dependency_
|
41
|
+
def nodes_satisfying(dependency)
|
42
|
+
@nodes.find_all { |n| n.satisfies?(dependency) }
|
43
|
+
end
|
44
|
+
|
45
|
+
# Iterate all nodes in this Graph and call _block_ for each Node
|
46
|
+
def each_node(&block)
|
47
|
+
@nodes.each { |node| block.call(node) }
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
|
3
|
+
module JavaClass
|
4
|
+
module Dependencies
|
5
|
+
|
6
|
+
# Serializes a Graph of Node to GraphML (XML).
|
7
|
+
# To see the graph, use yED, http://www.yworks.com/en/products_yed_about.html to
|
8
|
+
# * load the graphml file.
|
9
|
+
# * Then select all nodes and apply Tools/Fit Node to Label.
|
10
|
+
# * Finally apply the Layout/Hierarchical or maybe Layout/Organic/Smart.
|
11
|
+
# Author:: Peter Kofler
|
12
|
+
class GraphmlSerializer
|
13
|
+
include REXML
|
14
|
+
|
15
|
+
# Create a serializer with _options_ hash:
|
16
|
+
# edges:: how to chart edge labes, either :no_text or :with_counts
|
17
|
+
def initialize(options = { :edges => :with_counts })
|
18
|
+
@options = options
|
19
|
+
end
|
20
|
+
|
21
|
+
# Save the _graph_ to _filename_ .
|
22
|
+
def save(filename, graph)
|
23
|
+
File.open(filename + '.graphml', 'w') do |f|
|
24
|
+
doc = graph_to_xml(graph)
|
25
|
+
doc.write(out_string = '', 2)
|
26
|
+
f.print out_string
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Return an XML document of the GraphML serialized _graph_ .
|
31
|
+
def graph_to_xml(graph)
|
32
|
+
doc = create_xml_doc
|
33
|
+
container = add_graph_element(doc)
|
34
|
+
graph.to_a.each { |node| add_node_as_xml(container, node) }
|
35
|
+
doc
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def create_xml_doc
|
41
|
+
REXML::Document.new
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_graph_element(doc)
|
45
|
+
root = doc.add_element('graphml',
|
46
|
+
'xmlns' => 'http://graphml.graphdrawing.org/xmlns',
|
47
|
+
'xmlns:y' => 'http://www.yworks.com/xml/graphml')
|
48
|
+
root.add_element('key', 'id' => 'n1', 'for' => 'node', 'yfiles.type' => 'nodegraphics')
|
49
|
+
root.add_element('key', 'id' => 'e1', 'for' => 'edge', 'yfiles.type' => 'edgegraphics')
|
50
|
+
|
51
|
+
root.add_element('graph', 'edgedefault' => 'directed')
|
52
|
+
end
|
53
|
+
|
54
|
+
public
|
55
|
+
|
56
|
+
# Add the _node_ as XML to the _container_ .
|
57
|
+
def add_node_as_xml(container, node)
|
58
|
+
add_node_element(container, node)
|
59
|
+
|
60
|
+
node.dependencies.keys.each do |dep|
|
61
|
+
add_edge_element(container, node, dep)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def add_node_element(container, node)
|
68
|
+
elem = container.add_element('node', 'id' => node.name)
|
69
|
+
elem.add_element('data', 'key' => 'n1').
|
70
|
+
add_element('y:ShapeNode').
|
71
|
+
add_element('y:NodeLabel').
|
72
|
+
add_text(node.to_s)
|
73
|
+
end
|
74
|
+
|
75
|
+
def add_edge_element(container, node, dep)
|
76
|
+
edge = container.add_element('edge')
|
77
|
+
edge.add_attribute('id', node.name + '.' + dep.name)
|
78
|
+
edge.add_attribute('source', node.name)
|
79
|
+
edge.add_attribute('target', dep.name)
|
80
|
+
|
81
|
+
add_edge_label(edge, node.dependencies[dep])
|
82
|
+
end
|
83
|
+
|
84
|
+
def add_edge_label(edge, dependencies_2_dep)
|
85
|
+
if @options[:edges] == :with_counts
|
86
|
+
number_total_dependencies = dependencies_2_dep.size.to_s
|
87
|
+
number_unique_dependencies = dependencies_2_dep.collect { |d| d.target }.uniq.size.to_s
|
88
|
+
edge.add_element('data', 'key' => 'e1').
|
89
|
+
add_element('y:PolyLineEdge').
|
90
|
+
add_element('y:EdgeLabel').
|
91
|
+
add_text("#{number_total_dependencies} (#{number_unique_dependencies})")
|
92
|
+
elsif @options[:edges] == :no_text
|
93
|
+
# do nothing
|
94
|
+
else
|
95
|
+
raise "unknown option for edge labels #{@options[:edges]}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module JavaClass
|
2
|
+
module Dependencies
|
3
|
+
|
4
|
+
# A node in a Graph of dependencies. A node contains a map of dependencies (Edge) to other nodes.
|
5
|
+
# Author:: Peter Kofler
|
6
|
+
class Node
|
7
|
+
|
8
|
+
attr_reader :name
|
9
|
+
attr_reader :size
|
10
|
+
attr_reader :dependencies
|
11
|
+
### attr_reader :incoming
|
12
|
+
|
13
|
+
def initialize(name, size=0)
|
14
|
+
@name = name
|
15
|
+
@size = size
|
16
|
+
@dependencies = Hash.new([])
|
17
|
+
### @incoming = Hash.new([])
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
if @size > 0
|
22
|
+
"#{@name} (#{@size.to_s})"
|
23
|
+
else
|
24
|
+
@name
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def ==(other)
|
29
|
+
other.respond_to?(:name) && @name == other.name
|
30
|
+
end
|
31
|
+
|
32
|
+
def hash
|
33
|
+
@name.hash
|
34
|
+
end
|
35
|
+
|
36
|
+
def <=>(other)
|
37
|
+
@name <=> other.name
|
38
|
+
end
|
39
|
+
|
40
|
+
# Add a _dependency_ Edge for a list of _provider_ Node.
|
41
|
+
def add_dependency(dependency, providers)
|
42
|
+
if providers.size == 0
|
43
|
+
# external dependency, skip this
|
44
|
+
elsif providers.size == 1
|
45
|
+
# add dependency to this provider
|
46
|
+
provider = providers[0]
|
47
|
+
# unless @dependencies[provider].include? dependency
|
48
|
+
@dependencies[provider] = @dependencies[provider] + [dependency]
|
49
|
+
### provider.incoming[self] = provider.incoming[self] + [dependency]
|
50
|
+
# end
|
51
|
+
else
|
52
|
+
warn "dependency to \"#{dependency}\" found more than once: #{providers.join(', ')}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Add a list _dependencies_ of _provider_ .
|
57
|
+
def add_dependencies(dependencies, providers)
|
58
|
+
dependencies.each do |dependency|
|
59
|
+
add_dependency(dependency, providers)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Iterate all providers of dependencies of this Node and call _block_ for each provider with its list of dependencies (Edge).
|
64
|
+
def each_dependency_provider(&block)
|
65
|
+
@dependencies.keys.each do |provider|
|
66
|
+
block.call(provider, @dependencies[provider])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Iterate all dependencies of this Node and call _block_ for each provider with each of its dependencies.
|
71
|
+
def each_edge(&block)
|
72
|
+
each_dependency_provider do |provider, edges|
|
73
|
+
edges.each do |edge|
|
74
|
+
block.call(provider, edge)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'javaclass/dependencies/edge'
|
3
|
+
require 'javaclass/dependencies/node'
|
4
|
+
require 'javaclass/dependencies/graph'
|
5
|
+
|
6
|
+
module JavaClass
|
7
|
+
module Dependencies
|
8
|
+
|
9
|
+
# Serializes a Graph of Nodes to YAML.
|
10
|
+
# Author:: Peter Kofler
|
11
|
+
class YamlSerializer
|
12
|
+
|
13
|
+
# Create a serializer with _options_ hash:
|
14
|
+
# outgoing:: how to persist outgoing dependencies, either :detailed, :summary or :none
|
15
|
+
def initialize(options = {:outgoing => :detailed })
|
16
|
+
@options = options
|
17
|
+
end
|
18
|
+
|
19
|
+
# Exists a YAML serialized _graph_ ?
|
20
|
+
def has_yaml?(filename)
|
21
|
+
File.exist? yaml_file(filename)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Save the _graph_ to YAML _filename_ .
|
25
|
+
def save(filename, graph)
|
26
|
+
File.open(yaml_file(filename), 'w') { |f| f.print graph_to_yaml(graph) }
|
27
|
+
end
|
28
|
+
|
29
|
+
# Return a String of the YAML serialized _graph_ .
|
30
|
+
def graph_to_yaml(graph)
|
31
|
+
"---\n" +
|
32
|
+
graph.to_a.map { |node| node_to_yaml(node) }.join("\n")
|
33
|
+
end
|
34
|
+
|
35
|
+
# Return a String of the YAML serialized _node_ .
|
36
|
+
def node_to_yaml(node)
|
37
|
+
node.name + ":\n" +
|
38
|
+
node.dependencies.keys.map { |dep|
|
39
|
+
' ' + dep.name + dependencies_to_yaml(node.dependencies[dep])
|
40
|
+
}.join("\n")
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def yaml_file(filename)
|
46
|
+
filename + '.yaml'
|
47
|
+
end
|
48
|
+
|
49
|
+
def dependencies_to_yaml(dependencies)
|
50
|
+
if @options[:outgoing] == :detailed
|
51
|
+
":\n" + dependencies.map { |dep| " - #{dep.source}->#{dep.target}" }.join("\n")
|
52
|
+
elsif @options[:outgoing] == :summary
|
53
|
+
":\n" + dependencies.map { |dep| dep.target }.uniq.sort.map { |dep| " - #{dep}" }.join("\n")
|
54
|
+
elsif @options[:outgoing] == :none
|
55
|
+
''
|
56
|
+
else
|
57
|
+
raise "unknown option for outgoing dependencies #{@options[:outgoing]}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def node_with(name)
|
62
|
+
node = @nodes_by_name[name]
|
63
|
+
if node
|
64
|
+
node
|
65
|
+
else
|
66
|
+
@nodes_by_name[name] = Node.new(name)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
public
|
71
|
+
|
72
|
+
# Load the Graph from YAML _filename_ .
|
73
|
+
def load(filename)
|
74
|
+
yaml = File.open(yaml_file(filename)) { |f| YAML.load(f) }
|
75
|
+
# TODO support compressed yaml files, e.g. inside zip
|
76
|
+
yaml_to_graph(yaml)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Return a Graph from the YAML data _yaml_ .
|
80
|
+
def yaml_to_graph(yaml)
|
81
|
+
graph = Graph.new
|
82
|
+
@nodes_by_name = {}
|
83
|
+
|
84
|
+
yaml.keys.each do |name|
|
85
|
+
node = node_with(name)
|
86
|
+
graph.add(node)
|
87
|
+
|
88
|
+
dependency_map = yaml[name] || {}
|
89
|
+
dependency_map.keys.each do |dependency_name|
|
90
|
+
depending_node = node_with(dependency_name)
|
91
|
+
dependencies = dependency_map[dependency_name].collect { |d| Edge.new(*d.split(/->/)) }
|
92
|
+
node.add_dependencies(dependencies, [depending_node])
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
@nodes_by_name = {}
|
97
|
+
graph
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|