code_node 0.0.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/LICENSE ADDED
@@ -0,0 +1,17 @@
1
+ Copyright (c) 2012 Kevin Tonon
2
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
3
+ this software and associated documentation files (the "Software"), to deal in
4
+ the Software without restriction, including without limitation the rights to
5
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
6
+ the Software, and to permit persons to whom the Software is furnished to do so,
7
+ subject to the following conditions:
8
+
9
+ The above copyright notice and this permission notice shall be included in all
10
+ copies or substantial portions of the Software.
11
+
12
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
14
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
15
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
16
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
17
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,8 @@
1
+ <% if tool.explicit_require %>require '<%= tool.path %>'
2
+ <% else %>require '<%= tool.name %>'
3
+ <% end %>
4
+
5
+ # Makes a graph of the project_source_path
6
+ CodeNode.graph '<%= @name %>' do |g|
7
+
8
+ end
@@ -0,0 +1,48 @@
1
+ digraph
2
+ {
3
+ graph [rankdir="LR"]
4
+ node [style="filled"]
5
+
6
+ <% @graph.nodes.each do |node| %>
7
+ <% if node.should_render? %>
8
+ <%= node.key %> [label="<%= node.label %>" shape="<%= node.shape %>" fillcolor="<%= node.fillcolor %>" fontcolor="<%= node.fontcolor %>"];
9
+ <% end %>
10
+ <% end %>
11
+
12
+ /* Contains */
13
+ edge [color="#e8e8e8"]
14
+ <% @graph.nodes.each do |node| %>
15
+ <% if node.parent && node.should_render? && node.parent.should_render? %>
16
+ <%= node.parent.key %> -> <%= node.key %>;
17
+ <% end %>
18
+ <% end %>
19
+
20
+ /* Extended by */
21
+ edge [color="#000000"]
22
+ <% @graph.nodes.each do |node| %>
23
+ <% node.extended_by.values.sort.each do |other| %>
24
+ <% if node.should_render? && other.should_render? %>
25
+ <%= node.key %> -> <%= other.key %>;
26
+ <% end %>
27
+ <% end %>
28
+ <% end %>
29
+
30
+ /* Includes */
31
+ edge [color="#336699"]
32
+ <% @graph.nodes.each do |node| %>
33
+ <% node.includes.values.sort.each do |other| %>
34
+ <% if node.should_render? && other.should_render? %>
35
+ <%= node.key %> -> <%= other.key %>;
36
+ <% end %>
37
+ <% end %>
38
+ <% end %>
39
+
40
+ /* Inherits from */
41
+ edge [color="#996633"]
42
+ <% @graph.nodes.each do |node| %>
43
+ <% if node.should_render? && node.inherits_from && node.inherits_from.should_render? %>
44
+ <%= node.key %> -> <%= node.inherits_from.key %>;
45
+ <% end %>
46
+ <% end %>
47
+
48
+ }
@@ -0,0 +1,15 @@
1
+ require 'cog'
2
+
3
+ # Register code_node as a tool with cog
4
+ Cog::Config.instance.register_tool __FILE__ do |tool|
5
+
6
+ # Define how new code_node generators are created
7
+ #
8
+ # Add context as required by your generator template.
9
+ #
10
+ # When the block is executed, +self+ will be an instance of Cog::Config::Tool::GeneratorStamper
11
+ tool.stamp_generator do
12
+ stamp 'code_node/generator.rb', generator_dest, :absolute_destination => true
13
+ end
14
+
15
+ end
@@ -0,0 +1,13 @@
1
+ module CodeNode
2
+ module DSL
3
+
4
+ class GraphDefiner
5
+
6
+ def initialize(graph)
7
+ @graph = graph
8
+ end
9
+
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ require 'code_node/dsl/graph_definer.rb'
2
+
3
+ module CodeNode
4
+ module DSL
5
+
6
+ end
7
+ end
@@ -0,0 +1,22 @@
1
+ require 'code_node/ir/node'
2
+
3
+ module CodeNode
4
+ module IR
5
+
6
+ class ClassNode < Node
7
+ def inherits_from=(super_node)
8
+ @inherits_from = super_node
9
+ end
10
+ def shape
11
+ :ellipse
12
+ end
13
+ def fillcolor
14
+ '#cccccc'
15
+ end
16
+ def fontcolor
17
+ '#000000'
18
+ end
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,66 @@
1
+ require 'code_node/ir/class_node'
2
+ require 'code_node/ir/module_node'
3
+
4
+ module CodeNode
5
+ module IR
6
+
7
+ class Graph
8
+
9
+ attr_reader :scope
10
+
11
+ def initialize
12
+ @nodes = {}
13
+ @scope = []
14
+ end
15
+
16
+ def node_for(node_type, s, opt={}, &block)
17
+ name = if s.is_a? Symbol
18
+ s
19
+ elsif s[0] == :const
20
+ s[1]
21
+ elsif s[0] == :colon2
22
+ x = []
23
+ while s[0] == :colon2
24
+ x << s[2] ; s = s[1]
25
+ end
26
+ x << s[1]
27
+ x.reverse
28
+ elsif s[0] == :self
29
+ @scope.last.mark_as_singleton
30
+ nil
31
+ end
32
+ return if name.nil?
33
+
34
+ node = if opt[:not_sure_if_nested]
35
+ if @scope.length > 1 && @scope[-2].find(name)
36
+ @scope[-2].find name
37
+ else
38
+ (node_type == :module ? ModuleNode : ClassNode).new(name)
39
+ end
40
+ else
41
+ (node_type == :module ? ModuleNode : ClassNode).new(name, @scope.last)
42
+ end
43
+
44
+ node = self << node
45
+ unless block.nil? || node.nil?
46
+ @scope << node
47
+ block.call node
48
+ @scope.pop
49
+ end
50
+ node
51
+ end
52
+
53
+ def <<(node)
54
+ @nodes[node.key] ||= node
55
+ @nodes[node.key]
56
+ end
57
+ def [](key)
58
+ @nodes[key]
59
+ end
60
+ def nodes
61
+ @nodes.values.sort
62
+ end
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,26 @@
1
+ require 'code_node/ir/node'
2
+
3
+ module CodeNode
4
+ module IR
5
+
6
+ class ModuleNode < Node
7
+ def shape
8
+ :box
9
+ end
10
+ def fillcolor
11
+ if children["#{key}_ClassMethods"] && extended_by['ActiveSupport_Concern']
12
+ '#000000'
13
+ else
14
+ '#666666'
15
+ end
16
+ end
17
+ def fontcolor
18
+ '#ffffff'
19
+ end
20
+ def mark_as_singleton
21
+ @singleton = true
22
+ end
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,51 @@
1
+ module CodeNode
2
+ module IR
3
+
4
+ class Node
5
+ attr_reader :name, :parent, :children, :includes, :extended_by, :inherits_from
6
+ def initialize(name, parent = nil)
7
+ parent_path = parent ? parent.instance_eval {@path} : []
8
+ @path = if name.is_a? Array
9
+ parent_path + name
10
+ else
11
+ parent_path + [name]
12
+ end
13
+ @name = @path.last
14
+ @parent = parent
15
+ parent.children[key] = self unless parent.nil?
16
+ @children = {}
17
+ @includes = {}
18
+ @extended_by = {}
19
+ end
20
+ def find(name)
21
+ key = (@path + [name].flatten).join '_'
22
+ @children[key] || (orphan? ? nil : @parent.find(name))
23
+ end
24
+ def key
25
+ @path.join '_'
26
+ end
27
+ def path
28
+ @path.join '::'
29
+ end
30
+ def label
31
+ orphan? ? path : name
32
+ end
33
+ def to_s
34
+ path
35
+ end
36
+ def <=>(other)
37
+ path <=> other.path
38
+ end
39
+ def orphan?
40
+ @parent.nil?
41
+ end
42
+ def derives_from?(k)
43
+ key == k || @inherits_from && (@inherits_from.key == k || @inherits_from.derives_from?(k))
44
+ end
45
+ def should_render?
46
+ !(orphan? && @children.empty? && @inherits_from.nil? && @extended_by.empty? && @includes.empty?) && key != 'ActiveSupport_Concern' && !derives_from?('ActiveRecord_ActiveRecordError') && name != :ClassMethods
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,9 @@
1
+ require 'code_node/ir/class_node'
2
+ require 'code_node/ir/module_node'
3
+ require 'code_node/ir/graph'
4
+
5
+ module CodeNode
6
+ # Intermediate representation
7
+ module IR
8
+ end
9
+ end
@@ -0,0 +1,40 @@
1
+ module CodeNode
2
+
3
+ class SexpWalker
4
+ def initialize(graph, sexp)
5
+ @graph = graph
6
+ @root = sexp
7
+ end
8
+ def walk(purpose, s = nil)
9
+ s ||= @root
10
+ if [:module, :class].member?(s[0])
11
+ @graph.node_for(s[0], s[1]) do |node|
12
+ if purpose == :find_relations && s[0] == :class && !s[2].nil?
13
+ super_node = @graph.node_for :class, s[2], :not_sure_if_nested => true
14
+ unless super_node.nil?
15
+ node.inherits_from = super_node
16
+ end
17
+ end
18
+ rest = s[0] == :module ? s.slice(2..-1) : s.slice(3..-1)
19
+ rest.each do |c|
20
+ walk(purpose, c) if c.class == Sexp
21
+ end
22
+ end
23
+ elsif purpose == :find_relations && s[0] == :call && s.length >= 4 && [:extend, :include].member?(s[2]) && !@graph.scope.empty?
24
+ node = @graph.node_for :module, s[3], :not_sure_if_nested => true
25
+ unless node.nil?
26
+ if s[2] == :extend
27
+ @graph.scope.last.extended_by[node.key] = node
28
+ else
29
+ @graph.scope.last.includes[node.key] = node
30
+ end
31
+ end
32
+ else
33
+ s.slice(1..-1).each do |c|
34
+ walk(purpose, c) if c.class == Sexp
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,5 @@
1
+ module Code_node
2
+ unless const_defined? :VERSION
3
+ VERSION = '0.0.1'
4
+ end
5
+ end
data/lib/code_node.rb ADDED
@@ -0,0 +1,55 @@
1
+ $LOAD_PATH << File.join(File.dirname(__FILE__))
2
+ require 'code_node/version'
3
+ require 'code_node/dsl'
4
+ require 'code_node/ir'
5
+ require 'code_node/sexp_walker'
6
+ require 'cog'
7
+ require 'ruby_parser'
8
+
9
+ # Create Class and Module graphs for Ruby prjects
10
+ module CodeNode
11
+
12
+ extend Cog::Generator
13
+
14
+ # @param graph_name [String] name of the dot file to generate (without +.dot+ extension)
15
+ # @option opt [Symbol] :ruby_version (:ruby19) either <tt>:ruby18</tt> or <tt>:ruby19</tt>, indicating which parser to use
16
+ # @yield [GraphDefinition] define rules for creating the graph
17
+ def self.graph(graph_name, opt={}, &block)
18
+ root = Cog::Config.instance.project_source_path
19
+ @graph = IR::Graph.new
20
+ graph_definer = DSL::GraphDefiner.new @graph
21
+ block.call graph_definer
22
+
23
+ rp = case opt[:ruby_version]
24
+ when :ruby18
25
+ Ruby18Parser.new
26
+ else
27
+ Ruby19Parser.new
28
+ end
29
+
30
+ sexp = []
31
+ [:find_nodes, :find_relations].each_with_index do |purpose, pass|
32
+ puts "#{(pass+1).ordinalize} pass: #{purpose.to_s.gsub('_', ' ')}".color(:cyan)
33
+ Dir.glob("#{root}/**/*.rb").each_with_index do |filename, i|
34
+ sexp[i] ||= begin
35
+ rp.parse(File.read filename)
36
+ rescue Racc::ParseError
37
+ STDERR.write "{filename.relative_to_project_root}, skipped...\n".color(:red)
38
+ nil
39
+ end
40
+ if sexp[i]
41
+ walker = SexpWalker.new @graph, sexp[i]
42
+ walker.walk purpose
43
+ end
44
+ end
45
+ end
46
+
47
+ # Activate code_node while rendering templates
48
+ # so that cog will be able to find code_node templates
49
+ Cog::Config.instance.activate_tool 'code_node' do
50
+ stamp 'code_node/graph.dot', "#{graph_name}.dot"
51
+ end
52
+
53
+ nil
54
+ end
55
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: code_node
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Kevin Tonon
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-11-18 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: cog
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: ruby_parser
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 3
43
+ segments:
44
+ - 0
45
+ version: "0"
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: rake
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ type: :development
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ name: yard
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ hash: 3
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ type: :development
75
+ version_requirements: *id004
76
+ description:
77
+ email: kevin@betweenconcepts.com
78
+ executables: []
79
+
80
+ extensions: []
81
+
82
+ extra_rdoc_files: []
83
+
84
+ files:
85
+ - LICENSE
86
+ - cog/templates/code_node/generator.rb.erb
87
+ - cog/templates/code_node/graph.dot.erb
88
+ - lib/code_node/cog_tool.rb
89
+ - lib/code_node/dsl/graph_definer.rb
90
+ - lib/code_node/dsl.rb
91
+ - lib/code_node/ir/class_node.rb
92
+ - lib/code_node/ir/graph.rb
93
+ - lib/code_node/ir/module_node.rb
94
+ - lib/code_node/ir/node.rb
95
+ - lib/code_node/ir.rb
96
+ - lib/code_node/sexp_walker.rb
97
+ - lib/code_node/version.rb
98
+ - lib/code_node.rb
99
+ homepage: http://betweenconcepts.com
100
+ licenses: []
101
+
102
+ post_install_message:
103
+ rdoc_options:
104
+ - --title
105
+ - code_node
106
+ - -ri
107
+ require_paths:
108
+ - lib
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ hash: 3
116
+ segments:
117
+ - 0
118
+ version: "0"
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ none: false
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ hash: 3
125
+ segments:
126
+ - 0
127
+ version: "0"
128
+ requirements: []
129
+
130
+ rubyforge_project:
131
+ rubygems_version: 1.8.24
132
+ signing_key:
133
+ specification_version: 3
134
+ summary: Create Class and Module graphs for Ruby projects
135
+ test_files: []
136
+