Class: Dependencytree::TreeInterpreter
- Inherits:
-
Object
- Object
- Dependencytree::TreeInterpreter
- Defined in:
- lib/dependencytree/treeinterpreter.rb
Overview
Interprets AST trees from the Ruby parser and maintains a list of seen classes, modules, constants and methods.
Instance Attribute Summary collapse
-
#classes_and_modules ⇒ Object
readonly
Returns the value of attribute classes_and_modules.
Instance Method Summary collapse
-
#_casgn(node) ⇒ Object
Handle a def expression.
-
#_class(node) ⇒ Object
Handle a class expression.
-
#_const(node) ⇒ Object
Handle a const expression.
-
#_def(node) ⇒ Object
Handle a def expression.
-
#_handle_class_module_common(type, name, node) ⇒ Object
Handle the common parts of a module or class definition.
-
#_module(node) ⇒ Object
Handle a module expression.
-
#_resolve(full_name) ⇒ Object
Finds a class or module by its full name.
-
#flatten_const_tree(node) ⇒ Object
Make an array of strings out of a encapsulated tree of :const expressions.
-
#initialize(log) ⇒ TreeInterpreter
constructor
A new instance of TreeInterpreter.
-
#top_of_stack ⇒ Object
Gets the top of stack class/module or Kernel if nothing set.
-
#visit(path, tree) ⇒ Object
Visits all children of the AST tree.
-
#visit_children(children) ⇒ Object
Visit all children of a node.
-
#visit_node(node) ⇒ Object
Visit a AST node and do the appropriate actions.
Constructor Details
#initialize(log) ⇒ TreeInterpreter
Returns a new instance of TreeInterpreter.
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/dependencytree/treeinterpreter.rb', line 11 def initialize(log) # the logging instance @@log = log # path will be the file system path of the source file @path = nil # context_stack is the stack of modules/classes loaded (namespacing) @context_stack = [] # this is a flat list of all classes / modules seen @classes_and_modules = [] # force adding the Kernel module to the list of classes _handle_class_module_common(:module, "Kernel", nil) @kernel = _resolve("Kernel") end |
Instance Attribute Details
#classes_and_modules ⇒ Object (readonly)
Returns the value of attribute classes_and_modules.
9 10 11 |
# File 'lib/dependencytree/treeinterpreter.rb', line 9 def classes_and_modules @classes_and_modules end |
Instance Method Details
#_casgn(node) ⇒ Object
Handle a def expression.
142 143 144 145 146 147 148 149 150 |
# File 'lib/dependencytree/treeinterpreter.rb', line 142 def _casgn(node) raise ArgumentError, "Children count for casgn is != 3 (#{node.children.length})" if node.children.length != 3 @@log.debug("casgn #{node.children[1]}") top_of_stack.add_constant(node.children[1]) visit_children(node.children[1..-1]) end |
#_class(node) ⇒ Object
Handle a class expression.
83 84 85 86 87 88 89 90 |
# File 'lib/dependencytree/treeinterpreter.rb', line 83 def _class(node) raise ArgumentError, "Children count for class is != 3 (#{node.children.length})" if node.children.length != 3 raise ArgumentError, "First class child needs to be a const (#{node.children[0].type} #{node.children[0].type})" if node.children[0].type != :const @@log.debug("class #{node.children[0].children[1]}") current_class_name = node.children[0].children[1] _handle_class_module_common(:class, current_class_name, node) end |
#_const(node) ⇒ Object
Handle a const expression.
57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/dependencytree/treeinterpreter.rb', line 57 def _const(node) @@log.debug("const") raise ArgumentError, "type needs to be const (#{node.type})" if node.type != :const raise ArgumentError, "Children count needs to be 2 (#{node.children.length})" if node.children.length != 2 reference = flatten_const_tree(node) @@log.debug("Reference to #{reference.to_s}") top_of_stack.add_reference(reference) end |
#_def(node) ⇒ Object
Handle a def expression.
130 131 132 133 134 135 136 137 138 |
# File 'lib/dependencytree/treeinterpreter.rb', line 130 def _def(node) raise ArgumentError, "Children count for def is != 3 (#{node.children.length})" if node.children.length != 3 @@log.debug("def #{node.children[0]}") top_of_stack.add_method(node.children[0]) visit_children(node.children[1..-1]) end |
#_handle_class_module_common(type, name, node) ⇒ Object
Handle the common parts of a module or class definition. Will try to resolve the instance or create it if not found.
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/dependencytree/treeinterpreter.rb', line 96 def _handle_class_module_common(type, name, node) full_name = name parent = nil if ! @context_stack.empty? parent = @context_stack[-1] full_name = parent.full_name.to_s + "::" + name.to_s end @@log.debug("Full name is #{full_name}") resolved = _resolve(full_name) if ! resolved.nil? # found an existing module/class with the full_name model = resolved else # found no existing module/class with the full_name model = ClassModel.new(type, @path, name) if parent model.set_parent(parent) end @classes_and_modules << model end if resolved.nil? @@log.debug("Created new ClassModel for #{model.full_name}") end @context_stack << model # recurse over the contents of the module visit_children(node.children[1..-1]) if node @context_stack.pop end |
#_module(node) ⇒ Object
Handle a module expression.
71 72 73 74 75 76 77 78 79 |
# File 'lib/dependencytree/treeinterpreter.rb', line 71 def _module(node) raise ArgumentError, "Children count for module is != 2 (#{node.children.length})" if node.children.length != 2 raise ArgumentError, "First module child needs to be a const (#{node.children[0].type} #{node.children[0].type})" if node.children[0].type != :const @@log.debug("module #{node.children[0].children[1]}") current_module_name = node.children[0].children[1] _handle_class_module_common(:module, current_module_name, node) end |
#_resolve(full_name) ⇒ Object
Finds a class or module by its full name.
51 52 53 |
# File 'lib/dependencytree/treeinterpreter.rb', line 51 def _resolve(full_name) @classes_and_modules.find { |clazz| clazz.full_name.to_s == full_name.to_s } end |
#flatten_const_tree(node) ⇒ Object
Make an array of strings out of a encapsulated tree of :const expressions.
38 39 40 41 42 43 44 45 46 47 |
# File 'lib/dependencytree/treeinterpreter.rb', line 38 def flatten_const_tree(node) raise ArgumentError, "type needs to be const (#{node.type})" if node.type != :const raise ArgumentError, "Children count needs to be 2 (#{node.children.length})" if node.children.length != 2 result = node.children[1..1] if node.children[0] && node.children[0].type == :const result = flatten_const_tree(node.children[0]) + result end result end |
#top_of_stack ⇒ Object
Gets the top of stack class/module or Kernel if nothing set.
28 29 30 31 32 33 34 |
# File 'lib/dependencytree/treeinterpreter.rb', line 28 def top_of_stack if @context_stack.empty? @kernel else @context_stack[-1] end end |
#visit(path, tree) ⇒ Object
Visits all children of the AST tree.
183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/dependencytree/treeinterpreter.rb', line 183 def visit(path, tree) begin @@log.debug("Visiting path #{path}") @path = path visit_node(tree) @path = nil rescue Exception => e @@log.error("Error in path #{path}") puts "Error in path #{path}" raise e end end |
#visit_children(children) ⇒ Object
Visit all children of a node. Will call #visit_node on each node child.
173 174 175 176 177 178 |
# File 'lib/dependencytree/treeinterpreter.rb', line 173 def visit_children(children) return if ! children children.each do |child| visit_node(child) if child.respond_to?(:children) end end |
#visit_node(node) ⇒ Object
Visit a AST node and do the appropriate actions.
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/dependencytree/treeinterpreter.rb', line 154 def visit_node(node) case node.type when :const _const(node) when :class _class(node) when :module _module(node) when :def _def(node) when :casgn _casgn(node) else visit_children(node.children) end end |