class ProcToAst::Parser
Attributes
parser[R]
Public Class Methods
new()
click to toggle source
# File lib/proc_to_ast.rb, line 13 def initialize @parser = ::Parser::CurrentRuby.default_parser @parser.diagnostics.consumer = ->(diagnostic) {} # suppress error message end
Public Instance Methods
parse(filename, linenum)
click to toggle source
Read file and try parsing if success parse, find proc AST
@param filename [String] reading file path @param linenum [Integer] start line number @return [Parser::AST::Node] Proc
AST
# File lib/proc_to_ast.rb, line 24 def parse(filename, linenum) @filename, @linenum = filename, linenum buf = [] File.open(filename, "rb").each_with_index do |line, index| next if index < linenum - 1 buf << line begin return do_parse(buf.join) rescue ::Parser::SyntaxError node = trim_and_retry(buf) return node if node end end fail(::Parser::SyntaxError, 'Unknown error') end
Private Instance Methods
do_parse(source)
click to toggle source
# File lib/proc_to_ast.rb, line 42 def do_parse(source) parser.reset source_buffer = ::Parser::Source::Buffer.new(@filename, @linenum) source_buffer.source = source node = parser.parse(source_buffer) block_nodes = traverse_node(node) if block_nodes.length == 1 block_nodes.first else raise ProcToAst::MultiMatchError end end
traverse_node(node)
click to toggle source
# File lib/proc_to_ast.rb, line 68 def traverse_node(node) if node.type != :block node.children.flat_map { |child| if child.is_a?(AST::Node) traverse_node(child) end }.compact else [node] end end
trim_and_retry(buf)
click to toggle source
Remove tail comma and wrap dummy method, and retry parsing For proc inner Array or Hash
# File lib/proc_to_ast.rb, line 59 def trim_and_retry(buf) *lines, last = buf # For inner Array or Hash or Arguments list. lines << last.gsub(/,\s*$/, "") do_parse("a(#{lines.join})") # wrap dummy method rescue ::Parser::SyntaxError end