Capture and annotate NoMethodError
schneems opened this issue · comments
Richard Schneeman commented
Currently this code:
class Pet
def initialize
@name = "cinco"
end
def call
puts "Come here #{@neam.upcase}"
end
end
Pet.new.call
Gives us this error message
scratch.rb:7:in `call': undefined method `upcase' for nil:NilClass (NoMethodError)
Which gives us no context or info about the code causing this error. I would love it to instead show:
1 class Pet
6 def call
❯ 7 puts "Come here #{@neam.upcase}"
8 end
9 end
scratch.rb:7:in `call': undefined method `upcase' for nil:NilClass (NoMethodError)
Fable Tales commented
here's a super hacky version:
class NoMethodError
def message
begin
fn = backtrace[0].split(":").first
line = backtrace[0].split(":")[1].to_i
code = File.open(fn).read.split("\n")
nearest_klass, klass_idx = code[0...line-1].each_with_index.select { |x, idx| /class/ === x }.last
nearest_klass_indent = nearest_klass.chars.take_while { |x| x == " "}.length
matching_end, end_idx = code[klass_idx...(code.length-1)].each_with_index.select { |x, idx| x.start_with?("#{" "*nearest_klass_indent}end") }.first
end_idx += klass_idx + 1
nearest_def, def_idx = code[0...line-1].each_with_index.select { |x, idx| /def/ === x }.last
nearest_def_indent = nearest_def.chars.take_while { |x| x == " "}.length
def_matching_end, def_end_idx = code[def_idx...(code.length-1)].each_with_index.select { |x, idx| x.start_with?("#{" "*nearest_def_indent}end") }.first
def_end_idx += def_idx + 1
klass_idx += 1
def_idx += 1
m = "\nSurrounding code was:\n"
m += " #{klass_idx.to_s.rjust(3)} " + nearest_klass + "\n"
m += " #{def_idx.to_s.rjust(3) } " + nearest_def + "\n"
m += " #{line.to_s.rjust(3) } > " + code[line-1] + "\n"
m += " #{def_end_idx.to_s.rjust(3) } " + def_matching_end + "\n"
m += " #{end_idx.to_s.rjust(3) } " + matching_end + "\n"
m + "\n" + super
rescue => e
binding.pry
end
#super
end
end
and output:
Traceback (most recent call last):
1: from hi.rb:13:in `<main>'
hi.rb:9:in `call': (NoMethodError)
Surrounding code was:
3 class Pet
8 def call
9 > puts "Come here #{@neam.upcase}"
10 end
11 end
undefined method `upcase' for nil:NilClass