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.
@@ -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