diff --git a/CHANGELOG.md b/CHANGELOG.md index ea926a6..ddd0bd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## HEAD (unreleased) +- Fix windows filename detection (https://github.com/zombocom/dead_end/pull/114) - Update links on readme and code of conduct (https://github.com/zombocom/dead_end/pull/107) ## 3.0.1 diff --git a/lib/dead_end.rb b/lib/dead_end.rb index 566e7d0..fcbcb8b 100644 --- a/lib/dead_end.rb +++ b/lib/dead_end.rb @@ -17,12 +17,14 @@ class Error < StandardError; end TIMEOUT_DEFAULT = ENV.fetch("DEAD_END_TIMEOUT", 1).to_i def self.handle_error(e) - filename = e.message.split(":").first + file = PathnameFromMessage.new(e.message).call.name + raise e unless file + $stderr.sync = true call( - source: Pathname(filename).read, - filename: filename + source: file.read, + filename: file ) raise e @@ -139,21 +141,24 @@ def self.valid?(source) end end -require_relative "dead_end/code_line" -require_relative "dead_end/code_block" +# Integration +require_relative "dead_end/cli" +require_relative "dead_end/auto" + +# Core logic require_relative "dead_end/code_search" require_relative "dead_end/code_frontier" +require_relative "dead_end/explain_syntax" require_relative "dead_end/clean_document" +# Helpers require_relative "dead_end/lex_all" +require_relative "dead_end/code_line" +require_relative "dead_end/code_block" require_relative "dead_end/block_expand" +require_relative "dead_end/ripper_errors" require_relative "dead_end/insertion_sort" require_relative "dead_end/around_block_scan" -require_relative "dead_end/ripper_errors" +require_relative "dead_end/pathname_from_message" require_relative "dead_end/display_invalid_blocks" require_relative "dead_end/parse_blocks_from_indent_line" - -require_relative "dead_end/explain_syntax" - -require_relative "dead_end/auto" -require_relative "dead_end/cli" diff --git a/lib/dead_end/pathname_from_message.rb b/lib/dead_end/pathname_from_message.rb new file mode 100644 index 0000000..e3141eb --- /dev/null +++ b/lib/dead_end/pathname_from_message.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module DeadEnd + # Converts a SyntaxError message to a path + # + # Handles the case where the filename has a colon in it + # such as on a windows file system: https://github.com/zombocom/dead_end/issues/111 + # + # Example: + # + # message = "/tmp/scratch:2:in `require_relative': /private/tmp/bad.rb:1: syntax error, unexpected `end' (SyntaxError)" + # puts PathnameFromMessage.new(message).call.name + # # => "/tmp/scratch.rb" + # + class PathnameFromMessage + attr_reader :name + + def initialize(message, io: $stderr) + @line = message.lines.first + @parts = @line.split(":") + @guess = [] + @name = nil + @io = io + end + + def call + 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 + end + + self + end + + def stop? + return true if @parts.empty? + return false if @guess.empty? + + @name&.exist? + end + end +end diff --git a/spec/unit/pathname_from_message_spec.rb b/spec/unit/pathname_from_message_spec.rb new file mode 100644 index 0000000..e570aac --- /dev/null +++ b/spec/unit/pathname_from_message_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require_relative "../spec_helper" + +module DeadEnd + RSpec.describe "PathnameFromMessage" do + it "handles filenames with colons in them" do + Dir.mktmpdir do |dir| + dir = Pathname(dir) + + file = dir.join("scr:atch.rb").tap { |p| FileUtils.touch(p) } + + message = "#{file}:2:in `require_relative': /private/tmp/bad.rb:1: syntax error, unexpected `end' (SyntaxError)" + file = PathnameFromMessage.new(message).call.name + + expect(file).to be_truthy + end + end + + it "checks if the file exists" do + Dir.mktmpdir do |dir| + dir = Pathname(dir) + + file = dir.join("scratch.rb") + + message = "#{file}:2:in `require_relative': /private/tmp/bad.rb:1: syntax error, unexpected `end' (SyntaxError)" + io = StringIO.new + file = PathnameFromMessage.new(message, io: io).call.name + + expect(io.string).to include(file.to_s) + expect(file).to be_falsey + end + end + end +end