module ProcSource
Based heavily on code from github.com/imedo/background Big thanks to the imedo dev team!
Public Class Methods
find(filename, start_line=1, block_only=true)
click to toggle source
# File lib/proc_source.rb, line 69 def self.find(filename, start_line=1, block_only=true) lines, lexer = nil, nil retried = 0 loop do lines = get_lines(filename, start_line) return nil if lines.nil? #p [start_line, lines[0]] if !line_has_open?(lines.join) && start_line >= 0 start_line -= 1 and retried +=1 and redo end lexer = RubyLex.new lexer.set_input(StringIO.new(lines.join)) break end stoken, etoken, nesting = nil, nil, 0 while token = lexer.token n = token.name if RubyToken::TkIDENTIFIER === token #nothing elsif token.open_tag? || RubyToken::TkfLBRACE === token nesting += 1 stoken = token if nesting == 1 elsif RubyToken::TkEND === token || RubyToken::TkRBRACE === token if nesting == 1 etoken = token break end nesting -= 1 elsif RubyToken::TkLBRACE === token nesting += 1 elsif RubyToken::TkBITOR === token && stoken #nothing elsif RubyToken::TkNL === token && stoken && etoken break if nesting <= 0 else #p token end end # puts lines if etoken.nil? lines = lines[stoken.line_no-1 .. etoken.line_no-1] # Remove the crud before the block definition. if block_only spaces = lines.last.match(/^\s+/)[0] rescue '' lines[0] = spaces << lines[0][stoken.char_no .. -1] end ps = ProcString.new lines.join ps.file, ps.lines = filename, start_line .. start_line+etoken.line_no-1 ps end
get_lines(filename, start_line = 1)
click to toggle source
# File lib/proc_source.rb, line 162 def self.get_lines(filename, start_line = 1) case filename when nil nil when "(irb)" # special "(irb)" descriptor? IRB.conf[:MAIN_CONTEXT].io.line(start_line .. -2) when /^\(eval.+\)$/ # special "(eval...)" descriptor? EVAL_LINES__[filename][start_line .. -2] else # regular file # Ruby already parsed this file? (see disclaimer above) if defined?(SCRIPT_LINES__) && SCRIPT_LINES__[filename] SCRIPT_LINES__[filename][(start_line - 1) .. -1] # If the file exists we're going to try reading it in elsif File.exist?(filename) begin File.readlines(filename)[(start_line - 1) .. -1] rescue nil end end end end
line_has_open?(str)
click to toggle source
A hack for Ruby 1.9, otherwise returns true.
Ruby 1.9 returns an incorrect line number when a block is specified with do/end. It happens b/c the line number returned by Ruby 1.9 is based on the first line in the block which contains a token (i.e. not a new line or comment etc…).
NOTE: This won't work in cases where the incorrect line also contains a “do”.
# File lib/proc_source.rb, line 134 def self.line_has_open?(str) return true unless RUBY_VERSION >= '1.9' lexer = RubyLex.new lexer.set_input(StringIO.new(str)) success = false while token = lexer.token case token when RubyToken::TkNL break when RubyToken::TkDO success = true when RubyToken::TkfLBRACE success = true when RubyToken::TkCONSTANT if token.name == "Proc" && lexer.token.is_a?(RubyToken::TkDOT) method = lexer.token if method.is_a?(RubyToken::TkIDENTIFIER) && method.name == "new" success = true end end end end success end