Class: CodeWeb::CodeParser
- Inherits:
-
Object
- Object
- CodeWeb::CodeParser
- Extended by:
- Forwardable
- Defined in:
- lib/code_web/code_parser.rb
Constant Summary collapse
- SPACES =
Hash.new {|h, n| h[n] = " " * n.to_i }
Instance Attribute Summary collapse
-
#debug ⇒ Object
Returns the value of attribute debug.
-
#exit_on_error ⇒ Object
Returns the value of attribute exit_on_error.
-
#file_count ⇒ Object
Returns the value of attribute file_count.
-
#method_cache ⇒ Object
Returns the value of attribute method_cache.
-
#verbose ⇒ Object
Returns the value of attribute verbose.
Instance Method Summary collapse
-
#collapse_ast(ast, max = 20) ⇒ Object
TODO: add collapse_ast this one creates the true classes, not the string versions (so don’t add double quotes, or do ‘nil’).
- #collapse_asts(ast, max = 20) ⇒ Object
- #debug? ⇒ Boolean
- #handle_method_call(ast, is_yield = false) ⇒ Object
-
#initialize ⇒ CodeParser
constructor
A new instance of CodeParser.
- #method_name_from_ast(ast) ⇒ Object
- #parse(file_name, file_data = nil, required_string = nil) ⇒ Object
- #traverse(ast, has_yield = false) ⇒ Object
- #traverse_nodes(ast, *ranges) ⇒ Object
- #verbose? ⇒ Boolean
Constructor Details
#initialize ⇒ CodeParser
Returns a new instance of CodeParser.
17 18 19 20 21 22 23 |
# File 'lib/code_web/code_parser.rb', line 17 def initialize @cur_method=[] @indent = 0 @file_count = 0 @exit_on_error = false @method_cache = CodeWeb::MethodCache.new end |
Instance Attribute Details
#debug ⇒ Object
Returns the value of attribute debug.
11 12 13 |
# File 'lib/code_web/code_parser.rb', line 11 def debug @debug end |
#exit_on_error ⇒ Object
Returns the value of attribute exit_on_error.
10 11 12 |
# File 'lib/code_web/code_parser.rb', line 10 def exit_on_error @exit_on_error end |
#file_count ⇒ Object
Returns the value of attribute file_count.
9 10 11 |
# File 'lib/code_web/code_parser.rb', line 9 def file_count @file_count end |
#method_cache ⇒ Object
Returns the value of attribute method_cache.
8 9 10 |
# File 'lib/code_web/code_parser.rb', line 8 def method_cache @method_cache end |
#verbose ⇒ Object
Returns the value of attribute verbose.
12 13 14 |
# File 'lib/code_web/code_parser.rb', line 12 def verbose @verbose end |
Instance Method Details
#collapse_ast(ast, max = 20) ⇒ Object
TODO: add collapse_ast this one creates the true classes, not the string versions (so don’t add double quotes, or do ‘nil’)
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/code_web/code_parser.rb', line 111 def collapse_ast(ast, max=20) if ast.is_a?(Sexp) if static? ast = ast.gsub(Sexp.new(:self), Sexp.new(:const, self_name)) else ast = ast.gsub(Sexp.new(:call, Sexp.new(:self),:class), Sexp.new(:const, self_name)) end case ast.node_type when :hash #name, value, name, value, ... if ast[1].is_a?(Sexp) && (ast[1].node_type == :kwsplat || ast[1].node_type == :lit) ast[1..-1].map { |i| collapse_ast(i) } else Hash[*ast[1..-1].map { |i| collapse_ast(i) }] end when :array ast[1..-1].map {|node| collapse_ast(node)} when :lit, :lvar, :const, :str, :ivar, :cvar ast[1] when :true true when :false false when :nil nil when :self ast[0] when :call if ast[2] == :[] "#{method_name_from_ast(ast[1..1]).join('.')}[#{collapse_ast(ast[3])}]" else "#{method_name_from_ast(ast[1..2]).join('.')}#{'(...)' if ast.length > 3}" end when :evstr "#"+"{#{collapse_asts(ast[1..-1]).join}}" when :colon2 "#{method_name_from_ast(ast[1..-1]).join('::')}" when :dot2 "#{collapse_ast(ast[1])}..#{collapse_ast(ast[2])}" when :colon3 "::#{collapse_asts(ast[1..-1]).join}" when :[] "[#{collapse_asts(ast[1..-1]).join}]" when :dstr "#{collapse_asts(ast[1..-1]).join}" #backref? else if max > 0 ast.map {|node| collapse_ast(node, max-1)} else "#{ast.node_type}[]" end end elsif ast.nil? nil else ast end end |
#collapse_asts(ast, max = 20) ⇒ Object
170 171 172 |
# File 'lib/code_web/code_parser.rb', line 170 def collapse_asts(ast, max=20) ast.map {|node| collapse_ast(node)} end |
#debug? ⇒ Boolean
14 |
# File 'lib/code_web/code_parser.rb', line 14 def debug? ; @debug ; end |
#handle_method_call(ast, is_yield = false) ⇒ Object
93 94 95 96 97 98 99 100 |
# File 'lib/code_web/code_parser.rb', line 93 def handle_method_call(ast, is_yield=false) method_name = method_name_from_ast(ast[1..2]) args = ast[3..-1].map {|arg| collapse_ast(arg,1)} mc = MethodCall.new(ast.file, ast.line, method_name, args, is_yield) method_cache << mc puts mc.to_s(spaces) if debug? # && method_cache.detect?(mc) end |
#method_name_from_ast(ast) ⇒ Object
102 103 104 105 106 |
# File 'lib/code_web/code_parser.rb', line 102 def method_name_from_ast(ast) ast.map { |node| collapse_ast(node) }.compact end |
#parse(file_name, file_data = nil, required_string = nil) ⇒ Object
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/code_web/code_parser.rb', line 174 def parse(file_name, file_data=nil, required_string=nil) #may make more sense to get this into cli (and an option for absolute path) file_name = File.realpath(file_name) file_data ||= File.binread(file_name) begin if required_string.nil? || file_data.include?(required_string) in_context file_name do traverse RubyParser.new.process(file_data, file_name) end end @file_count += 1 rescue => e if defined?(Pry) binding.pry elsif defined?(Byebug) byebug end STDERR.puts("#{e}: [#{file_data.size}] #{file_name}") end end |
#traverse(ast, has_yield = false) ⇒ Object
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/code_web/code_parser.rb', line 25 def traverse(ast, has_yield=false) puts "#{spaces}||#{collapse_ast(ast,1)}||" if verbose? puts src if ast.nil? case ast.node_type #dstr = define string ("abc#{here}"), #evstr evaluate string (#{HERE}) #attrasgn = attribute assignment when :block, :lambda, :if, :ensure, :rescue, :case, :when, :begin, :while, :until, :defined, :resbody, :match2, :match3, :dot2, :dot3, :dstr, :evstr, :dsym, :dregx, :hash, :array, :return, :and, :or, :next, :to_ary, :splat, :block_pass, :until, :yield, /asgn/, :ivar, :arglist, :args, :kwarg, :kwargs, :kwsplat, :zsuper, :not, #statements[] :super, :xstr, :for, :until, :dxstr, :lit, #these end up being no-ops: :lvar, :const, :str, :nil, :gvar, :back_ref, :true, :false, :colon2, :colon3, :next, :alias, :nth_ref, :sclass, :cvdecl, :break, :retry, :undef, #random :svalue, :cvar traverse_nodes(ast, 1..-1) when :self traverse_nodes(ast, 1..-1) when :module, #name, statements[] :class #name, parent, statements[] in_context ast[1], true, true do traverse_nodes(ast, 2..-1) end when :cdecl, #name, statements[] :defn #name, args[], call[] in_context ast[1], true do traverse_nodes(ast, 2..-1) end when :defs #self[], name, args[], call[] # static method in_context ast[2], :static do traverse_nodes(ast, 2..-1) end when :iter #call[], yield_args[], yield_{block|call}[] traverse(ast[1], :has_yield) in_context 'yield', true do traverse_nodes(ast, 2..-1) end when :call, :safe_call # object, statement? || const symbol, args handle_method_call(ast, has_yield) traverse_nodes(ast, 1..-1) else STDERR.puts "#{src}\n unknown node: #{ast.node_type} #{collapse_ast(ast,1)}" if exit_on_error if defined?(Pry) binding.pry elsif defined?(Byebug) byebug end raise "error" end traverse_nodes(ast, 1..-1) end end |
#traverse_nodes(ast, *ranges) ⇒ Object
83 84 85 86 87 88 89 90 91 |
# File 'lib/code_web/code_parser.rb', line 83 def traverse_nodes(ast, *ranges) ranges = [0..-1] if ranges.empty? ranges.each do |range| ast[range].each do |node| should_call = node.is_a?(Sexp) traverse(node) if should_call end end end |
#verbose? ⇒ Boolean
13 |
# File 'lib/code_web/code_parser.rb', line 13 def verbose? ; @verbose ; end |