Module: ProcSource

Defined in:
lib/proc_source.rb

Overview

Based heavily on code from github.com/imedo/background Big thanks to the imedo dev team!

Class Method Summary collapse

Class Method Details

.find(filename, start_line = 0, block_only = true) ⇒ Object



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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/proc_source.rb', line 46

def self.find(filename, start_line=0, 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.instance_variable_get(:@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::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 = 0) ⇒ Object



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/proc_source.rb', line 135

def self.get_lines(filename, start_line = 0)
  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) ⇒ Boolean

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”.

Returns:



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/proc_source.rb', line 109

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::TkCONSTANT
      if token.instance_variable_get(:@name) == "Proc" &&
         lexer.token.is_a?(RubyToken::TkDOT)
        method = lexer.token
        if method.is_a?(RubyToken::TkIDENTIFIER) &&
           method.instance_variable_get(:@name) == "new"
          success = true
        end
      end
    end
  end
  success
end