code_node 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -154,11 +154,17 @@ module CodeNode
154
154
  return if name.nil?
155
155
 
156
156
  node = if opt[:not_sure_if_nested]
157
- if @scope.length > 1 && @scope[-2].find(name)
158
- @scope[-2].find name
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
- Node.new name, :node_type => node_type
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
@@ -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
- self.path == path || @inherits_from && (@inherits_from.path == path || @inherits_from.inherits_from?(path))
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
- if find_relations? && !@graph.scope.empty?
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
- node = @graph.node_for :module, s[3], :not_sure_if_nested => true
41
- unless node.nil?
42
- if s[2] == :extend
43
- @graph.scope.last.extends node
44
- else
45
- @graph.scope.last.includes node
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
@@ -1,5 +1,5 @@
1
1
  module Code_node
2
2
  unless const_defined? :VERSION
3
- VERSION = '0.1.0'
3
+ VERSION = '0.1.1'
4
4
  end
5
5
  end
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: 27
4
+ hash: 25
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 0
10
- version: 0.1.0
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-20 00:00:00 Z
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