diff --git a/CHANGELOG.md b/CHANGELOG.md index b34e235..73ad939 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## HEAD (unreleased) +- Code that does not have an associated file (eval and streamed) no longer produce a warning saying that the file could not be found. To produce a warning with these code types run with DEBUG=1 environment variable. (https://github.com/zombocom/dead_end/pull/143) - [Breaking] Lazy load DeadEnd internals only if there is a Syntax error. Use `require "dead_end"; require "dead_end/api"` to load eagerly all internals. Otherwise `require "dead_end"` will set up an autoload for the first time the DeadEnd module is used in code. This should only happen on a syntax error. (https://github.com/zombocom/dead_end/pull/142) - Monkeypatch `SyntaxError#detailed_message` in Ruby 3.2+ instead of `require`, `load`, and `require_relative` (https://github.com/zombocom/dead_end/pull/139) diff --git a/lib/dead_end/pathname_from_message.rb b/lib/dead_end/pathname_from_message.rb index 1ee9f53..b45b6b8 100644 --- a/lib/dead_end/pathname_from_message.rb +++ b/lib/dead_end/pathname_from_message.rb @@ -13,6 +13,8 @@ module DeadEnd # # => "/tmp/scratch.rb" # class PathnameFromMessage + EVAL_RE = /^\(eval\):\d+/ + STREAMING_RE = /^-:\d+/ attr_reader :name def initialize(message, io: $stderr) @@ -24,14 +26,20 @@ def initialize(message, io: $stderr) end def call - until stop? - @guess << @parts.shift - @name = Pathname(@guess.join(":")) - end + if skip_missing_file_name? + if ENV["DEBUG"] + @io.puts "DeadEnd: Could not find filename from #{@line.inspect}" + end + else + until stop? + @guess << @parts.shift + @name = Pathname(@guess.join(":")) + end - if @parts.empty? - @io.puts "DeadEnd: Could not find filename from #{@line.inspect}" - @name = nil + if @parts.empty? + @io.puts "DeadEnd: Could not find filename from #{@line.inspect}" + @name = nil + end end self @@ -43,5 +51,9 @@ def stop? @name&.exist? end + + def skip_missing_file_name? + @line.match?(EVAL_RE) || @line.match?(STREAMING_RE) + end end end diff --git a/spec/integration/ruby_command_line_spec.rb b/spec/integration/ruby_command_line_spec.rb index 7b779d5..98d1ef9 100644 --- a/spec/integration/ruby_command_line_spec.rb +++ b/spec/integration/ruby_command_line_spec.rb @@ -146,5 +146,24 @@ class Dog expect(out).to include("DeadEnd is NOT loaded").once end end + + it "ignores eval" do + Dir.mktmpdir do |dir| + tmpdir = Pathname(dir) + script = tmpdir.join("script.rb") + script.write <<~'EOM' + $stderr = STDOUT + eval("def lol") + EOM + + out = `ruby -I#{lib_dir} -rdead_end #{script} 2>&1` + + expect($?.success?).to be_falsey + expect(out).to include("(eval):1") + + expect(out).to_not include("DeadEnd") + expect(out).to_not include("Could not find filename") + end + end end end diff --git a/spec/unit/pathname_from_message_spec.rb b/spec/unit/pathname_from_message_spec.rb index e570aac..c12aeeb 100644 --- a/spec/unit/pathname_from_message_spec.rb +++ b/spec/unit/pathname_from_message_spec.rb @@ -22,6 +22,8 @@ module DeadEnd dir = Pathname(dir) file = dir.join("scratch.rb") + # No touch, file does not exist + expect(file.exist?).to be_falsey message = "#{file}:2:in `require_relative': /private/tmp/bad.rb:1: syntax error, unexpected `end' (SyntaxError)" io = StringIO.new @@ -31,5 +33,24 @@ module DeadEnd expect(file).to be_falsey end end + + it "does not output error message on syntax error inside of an (eval)" do + message = "(eval):1: invalid multibyte char (UTF-8) (SyntaxError)\n" + io = StringIO.new + file = PathnameFromMessage.new(message, io: io).call.name + + expect(io.string).to eq("") + expect(file).to be_falsey + end + + it "does not output error message on syntax error inside of streamed code" do + # An example of streamed code is: $ echo "def foo" | ruby + message = "-:1: syntax error, unexpected end-of-input\n" + io = StringIO.new + file = PathnameFromMessage.new(message, io: io).call.name + + expect(io.string).to eq("") + expect(file).to be_falsey + end end end