code_node 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+