code_node 0.1.0 → 0.1.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/cog/generators/overview.rb +49 -0
- data/lib/code_node/ir/graph.rb +9 -3
- data/lib/code_node/ir/node.rb +3 -2
- data/lib/code_node/sexp_walker.rb +9 -7
- data/lib/code_node/spec_helpers.rb +23 -0
- data/lib/code_node/spec_helpers/dot_file.rb +114 -0
- data/lib/code_node/spec_helpers/runner.rb +25 -0
- data/lib/code_node/version.rb +1 -1
- metadata +8 -4
@@ -0,0 +1,49 @@
|
|
1
|
+
require '/Users/kevin/bc/code_node/lib/code_node.rb'
|
2
|
+
|
3
|
+
# Makes a graph of the project_source_path.
|
4
|
+
# Nodes in the graph are clases and modules from your project.
|
5
|
+
CodeNode.graph 'overview' do |g|
|
6
|
+
|
7
|
+
# Nodes
|
8
|
+
# =====
|
9
|
+
|
10
|
+
# Ignore nodes with no relations to other nodes
|
11
|
+
g.ignore &:island?
|
12
|
+
|
13
|
+
# Uncomment and change the value to ignore a specific node
|
14
|
+
# g.ignore 'Foo::Bar::Car'
|
15
|
+
|
16
|
+
# Uncomment to ignore nodes named ClassMethods
|
17
|
+
# g.ignore /::ClassMethods$/
|
18
|
+
|
19
|
+
# Uncomment and change the value to ignore all nodes descending
|
20
|
+
# from a specific node
|
21
|
+
# g.ignore {|node| node.inherits_from? 'Foo::Bar::Car'}
|
22
|
+
|
23
|
+
# Apply styles common to all classes
|
24
|
+
g.style :shape => 'ellipse', :fillcolor => '#cccccc', :fontcolor => :black do |node|
|
25
|
+
node.class?
|
26
|
+
end
|
27
|
+
|
28
|
+
# Apply styles common to all nodes
|
29
|
+
g.style :shape => 'box', :fillcolor => '#333333', :fontcolor => :white do |node|
|
30
|
+
node.module?
|
31
|
+
end
|
32
|
+
|
33
|
+
# Apply more specific style here
|
34
|
+
# ...
|
35
|
+
|
36
|
+
# Edges
|
37
|
+
# =====
|
38
|
+
#
|
39
|
+
# There is currently no way to style edges from the DSL.
|
40
|
+
# For now, there are only four categories of edges:
|
41
|
+
# - containment
|
42
|
+
# - inheritance
|
43
|
+
# - inclusion
|
44
|
+
# - extension
|
45
|
+
#
|
46
|
+
# They are style in the template. You can override the template
|
47
|
+
# and change the color if you like.
|
48
|
+
# $ cog -t code_node template new -f code_node/graph.dot
|
49
|
+
end
|
data/lib/code_node/ir/graph.rb
CHANGED
@@ -154,11 +154,17 @@ module CodeNode
|
|
154
154
|
return if name.nil?
|
155
155
|
|
156
156
|
node = if opt[:not_sure_if_nested]
|
157
|
-
|
158
|
-
|
157
|
+
candidate = if name.is_a?(Array)
|
158
|
+
parts = name.dup
|
159
|
+
n = !@scope.empty? && @scope.last.find(parts.shift)
|
160
|
+
while n && !parts.empty?
|
161
|
+
n = n.find parts.shift
|
162
|
+
end
|
163
|
+
n
|
159
164
|
else
|
160
|
-
|
165
|
+
!@scope.empty? && @scope.last.find(name)
|
161
166
|
end
|
167
|
+
candidate || Node.new(name, :node_type => node_type)
|
162
168
|
else
|
163
169
|
Node.new name, :parent => @scope.last, :node_type => node_type
|
164
170
|
end
|
data/lib/code_node/ir/node.rb
CHANGED
@@ -105,14 +105,15 @@ module CodeNode
|
|
105
105
|
# @param path [String] a class or module path in the form <tt>Foo::Bar::Car</tt>
|
106
106
|
# @return [Boolean] does this node inherit from (directly or indirectly) a {#class?} node with the given {#path}? Note that a node inherits from itself according to this method. Recursively checks the ancestry of the node.
|
107
107
|
def inherits_from?(path)
|
108
|
-
|
108
|
+
# TODO: need process all nodes first, marking for deletion on the first pass, because the superclass gets deleting and then the inherits from relation breaks down
|
109
|
+
self.path == path || @inherits_from && @inherits_from.inherits_from?(path)
|
109
110
|
end
|
110
111
|
|
111
112
|
# @return [Boolean] whether or not this node represents a singleton module. A singleton module is one which contains an <tt>extend self</tt> statement.
|
112
113
|
def singleton?
|
113
114
|
@singleton
|
114
115
|
end
|
115
|
-
|
116
|
+
|
116
117
|
# @return [Boolean] whether or not this node is an island. An island is a node with no connections to other nodes.
|
117
118
|
def island?
|
118
119
|
([@parent, @inherits_from].all?(&:nil?) &&
|
@@ -33,16 +33,18 @@ module CodeNode
|
|
33
33
|
walk(c) if c.class == Sexp
|
34
34
|
end
|
35
35
|
end
|
36
|
-
|
36
|
+
unless @graph.scope.empty?
|
37
37
|
@graph.scope.last.contains node
|
38
38
|
end
|
39
39
|
elsif find_relations? && s[0] == :call && s.length >= 4 && [:extend, :include].member?(s[2]) && !@graph.scope.empty?
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
40
|
+
s.slice(3..-1).each do |mod_sexp|
|
41
|
+
node = @graph.node_for :module, mod_sexp, :not_sure_if_nested => true
|
42
|
+
unless node.nil?
|
43
|
+
if s[2] == :extend
|
44
|
+
@graph.scope.last.extends node
|
45
|
+
else
|
46
|
+
@graph.scope.last.includes node
|
47
|
+
end
|
46
48
|
end
|
47
49
|
end
|
48
50
|
else
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'cog/spec_helpers'
|
2
|
+
require 'code_node/spec_helpers/runner'
|
3
|
+
require 'code_node/spec_helpers/dot_file'
|
4
|
+
|
5
|
+
module CodeNode
|
6
|
+
|
7
|
+
# RSpec helpers specific to code_node
|
8
|
+
module SpecHelpers
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
module Cog
|
14
|
+
|
15
|
+
# Customizations to cog RSpec helpers for use with code_node
|
16
|
+
module SpecHelpers
|
17
|
+
|
18
|
+
def spec_root
|
19
|
+
File.expand_path File.join(File.dirname(__FILE__), '..', '..', 'spec')
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module CodeNode
|
2
|
+
module SpecHelpers
|
3
|
+
|
4
|
+
# Represents a generated dot file
|
5
|
+
class DotFile
|
6
|
+
|
7
|
+
include Cog::SpecHelpers
|
8
|
+
|
9
|
+
# @param name [String] name of the dotfile without the <tt>.dot</tt> extension. The file will be looked for in the lib subdirectory of the active fixture dir.
|
10
|
+
def initialize(name)
|
11
|
+
@filename = generated_file "#{name}.dot"
|
12
|
+
@nodes = {} # :node_type => []
|
13
|
+
@edges = {} # :edge_type => []
|
14
|
+
if File.exists? @filename
|
15
|
+
@i = 0
|
16
|
+
@lines = File.read(@filename).split "\n"
|
17
|
+
read_until '/* Module nodes */'
|
18
|
+
read_nodes :module
|
19
|
+
read_until '/* Class nodes */'
|
20
|
+
read_nodes :class
|
21
|
+
read_until '/* A contains B */'
|
22
|
+
read_edges :containment
|
23
|
+
read_until '/* A inherits from B */'
|
24
|
+
read_edges :inheritance
|
25
|
+
read_until '/* A includes B */'
|
26
|
+
read_edges :inclusion
|
27
|
+
read_until '/* A extends B */'
|
28
|
+
read_edges :extension
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [Boolean] does the file exist?
|
33
|
+
def exists?
|
34
|
+
File.exists? @filename
|
35
|
+
end
|
36
|
+
|
37
|
+
def has_match?(pattern)
|
38
|
+
if exists?
|
39
|
+
!!(pattern =~ File.read(@filename))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def has_node?(path)
|
44
|
+
has_class?(path) || has_module?(path)
|
45
|
+
end
|
46
|
+
|
47
|
+
def has_class?(path)
|
48
|
+
key = path.to_s.split('::').join '_'
|
49
|
+
@nodes[:class].member?(key)
|
50
|
+
end
|
51
|
+
|
52
|
+
def has_module?(path)
|
53
|
+
key = path.to_s.split('::').join '_'
|
54
|
+
@nodes[:module].member?(key)
|
55
|
+
end
|
56
|
+
|
57
|
+
def has_edge?(path1, path2)
|
58
|
+
has_containment?(path1, path2) || has_inheritance?(path1, path2) || has_inclusion?(path1, path2) || has_extension?(path1, path2)
|
59
|
+
end
|
60
|
+
|
61
|
+
def has_containment?(path1, path2)
|
62
|
+
key1 = path1.to_s.split('::').join '_'
|
63
|
+
key2 = path2.to_s.split('::').join '_'
|
64
|
+
@edges[:containment].member?([key1, key2])
|
65
|
+
end
|
66
|
+
|
67
|
+
def has_inheritance?(path1, path2)
|
68
|
+
key1 = path1.to_s.split('::').join '_'
|
69
|
+
key2 = path2.to_s.split('::').join '_'
|
70
|
+
@edges[:inheritance].member?([key1, key2])
|
71
|
+
end
|
72
|
+
|
73
|
+
def has_inclusion?(path1, path2)
|
74
|
+
key1 = path1.to_s.split('::').join '_'
|
75
|
+
key2 = path2.to_s.split('::').join '_'
|
76
|
+
@edges[:inclusion].member?([key1, key2])
|
77
|
+
end
|
78
|
+
|
79
|
+
def has_extension?(path1, path2)
|
80
|
+
key1 = path1.to_s.split('::').join '_'
|
81
|
+
key2 = path2.to_s.split('::').join '_'
|
82
|
+
@edges[:extension].member?([key1, key2])
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def read_nodes(type)
|
88
|
+
@nodes[type] ||= []
|
89
|
+
until (line = @lines[@i]).strip.empty?
|
90
|
+
/^([A-Za-z0-9_]+)/ =~ line
|
91
|
+
@nodes[type] << $1 unless $1.nil?
|
92
|
+
@i += 1
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def read_edges(type)
|
97
|
+
@edges[type] ||= []
|
98
|
+
until (line = @lines[@i]).strip.empty?
|
99
|
+
/^([A-Za-z0-9_]+)\s\-\>\s([A-Za-z0-9_]+)/ =~ line
|
100
|
+
@edges[type] << [$1, $2] unless $1.nil?
|
101
|
+
@i += 1
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def read_until(line)
|
106
|
+
while @lines[@i] != line && @i < @lines.length
|
107
|
+
@i += 1
|
108
|
+
end
|
109
|
+
@i += 1
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module Cog
|
4
|
+
module SpecHelpers
|
5
|
+
|
6
|
+
class Runner
|
7
|
+
def initialize(app)
|
8
|
+
@cog = app
|
9
|
+
@tools = []
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Invocation
|
14
|
+
|
15
|
+
# Redefine exec for testing code_node
|
16
|
+
def exec(&block)
|
17
|
+
ENV['COG_TOOLS'] = File.expand_path File.join(File.dirname(__FILE__), '..', 'cog_tool.rb')
|
18
|
+
Open3.popen3 *@cmd do |i,o,e,t|
|
19
|
+
block.call i,o,e
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/code_node/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: code_node
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 1
|
10
|
+
version: 0.1.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Kevin Tonon
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-11-
|
18
|
+
date: 2012-11-27 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: cog
|
@@ -111,6 +111,7 @@ extra_rdoc_files: []
|
|
111
111
|
|
112
112
|
files:
|
113
113
|
- LICENSE
|
114
|
+
- cog/generators/overview.rb
|
114
115
|
- cog/templates/code_node/generator.rb.erb
|
115
116
|
- cog/templates/code_node/graph.dot.erb
|
116
117
|
- cog/templates/code_node/node.dot.erb
|
@@ -122,6 +123,9 @@ files:
|
|
122
123
|
- lib/code_node/ir/node_matcher.rb
|
123
124
|
- lib/code_node/ir.rb
|
124
125
|
- lib/code_node/sexp_walker.rb
|
126
|
+
- lib/code_node/spec_helpers/dot_file.rb
|
127
|
+
- lib/code_node/spec_helpers/runner.rb
|
128
|
+
- lib/code_node/spec_helpers.rb
|
125
129
|
- lib/code_node/version.rb
|
126
130
|
- lib/code_node.rb
|
127
131
|
homepage: https://github.com/ktonon/code_node
|