summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/syntax_suggest/core_ext.rb89
-rw-r--r--spec/syntax_suggest/integration/ruby_command_line_spec.rb12
-rw-r--r--spec/syntax_suggest/unit/api_spec.rb30
3 files changed, 79 insertions, 52 deletions
diff --git a/lib/syntax_suggest/core_ext.rb b/lib/syntax_suggest/core_ext.rb
index 59e13a149a..aed93e129c 100644
--- a/lib/syntax_suggest/core_ext.rb
+++ b/lib/syntax_suggest/core_ext.rb
@@ -3,6 +3,10 @@
# Ruby 3.2+ has a cleaner way to hook into Ruby that doesn't use `require`
if SyntaxError.method_defined?(:detailed_message)
module SyntaxSuggest
+ # Mini String IO [Private]
+ #
+ # Acts like a StringIO with reduced API, but without having to require that
+ # class.
class MiniStringIO
def initialize(isatty: $stderr.isatty)
@string = +""
@@ -16,52 +20,49 @@ if SyntaxError.method_defined?(:detailed_message)
attr_reader :string
end
- end
-
- SyntaxError.prepend Module.new {
- def detailed_message(highlight: true, syntax_suggest: true, **kwargs)
- return super unless syntax_suggest
-
- require "syntax_suggest/api" unless defined?(SyntaxSuggest::DEFAULT_VALUE)
-
- message = super
-
- file = if respond_to?(:path)
- path
- elsif highlight
- # This branch will be removed when the next Ruby 3.2 preview is released with
- # support for SyntaxError#path
- SyntaxSuggest::PathnameFromMessage.new(super(highlight: false, **kwargs)).call.name
- else
- SyntaxSuggest::PathnameFromMessage.new(message).call.name
- end
- if file
- file = Pathname.new(file)
- io = SyntaxSuggest::MiniStringIO.new
-
- SyntaxSuggest.call(
- io: io,
- source: file.read,
- filename: file,
- terminal: highlight
- )
- annotation = io.string
-
- annotation + message
- else
- message
- end
- rescue => e
- if ENV["SYNTAX_SUGGEST_DEBUG"]
- $stderr.warn(e.message)
- $stderr.warn(e.backtrace)
- end
-
- # Ignore internal errors
- message
+ # SyntaxSuggest.record_dir [Private]
+ #
+ # Used to monkeypatch SyntaxError via Module.prepend
+ def self.module_for_detailed_message
+ Module.new {
+ def detailed_message(highlight: true, syntax_suggest: true, **kwargs)
+ return super unless syntax_suggest
+
+ require "syntax_suggest/api" unless defined?(SyntaxSuggest::DEFAULT_VALUE)
+
+ message = super
+
+ if path
+ file = Pathname.new(path)
+ io = SyntaxSuggest::MiniStringIO.new
+
+ SyntaxSuggest.call(
+ io: io,
+ source: file.read,
+ filename: file,
+ terminal: highlight
+ )
+ annotation = io.string
+
+ annotation + message
+ else
+ message
+ end
+ rescue => e
+ if ENV["SYNTAX_SUGGEST_DEBUG"]
+ $stderr.warn(e.message)
+ $stderr.warn(e.backtrace)
+ end
+
+ # Ignore internal errors
+ message
+ end
+ }
end
- }
+ end
+
+ SyntaxError.prepend(SyntaxSuggest.module_for_detailed_message)
else
autoload :Pathname, "pathname"
diff --git a/spec/syntax_suggest/integration/ruby_command_line_spec.rb b/spec/syntax_suggest/integration/ruby_command_line_spec.rb
index 9e488df93a..5c7ee06d83 100644
--- a/spec/syntax_suggest/integration/ruby_command_line_spec.rb
+++ b/spec/syntax_suggest/integration/ruby_command_line_spec.rb
@@ -76,9 +76,17 @@ module SyntaxSuggest
end
end
- it "annotates a syntax error in Ruby 3.2+ when require is not used" do
- pending("Support for SyntaxError#detailed_message monkeypatch needed https://gist.github.com/schneems/09f45cc23b9a8c46e9af6acbb6e6840d?permalink_comment_id=4172585#gistcomment-4172585")
+ it "gem can be tested when executing on Ruby with default gem included" do
+ skip if ruby_core?
+ skip if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.2")
+
+ out = `ruby -I#{lib_dir} -rsyntax_suggest -e "puts SyntaxError.instance_method(:detailed_message).source_location" 2>&1`
+ expect($?.success?).to be_truthy
+ expect(out).to include(lib_dir.join("syntax_suggest").join("core_ext.rb").to_s).once
+ end
+
+ it "annotates a syntax error in Ruby 3.2+ when require is not used" do
skip if ruby_core?
skip if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.2")
diff --git a/spec/syntax_suggest/unit/api_spec.rb b/spec/syntax_suggest/unit/api_spec.rb
index a89d9f6a33..079a91e46d 100644
--- a/spec/syntax_suggest/unit/api_spec.rb
+++ b/spec/syntax_suggest/unit/api_spec.rb
@@ -65,11 +65,20 @@ module SyntaxSuggest
it "respects highlight API" do
skip if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.2")
- error = SyntaxError.new("#{fixtures_dir.join("this_project_extra_def.rb.txt")}:1 ")
+ core_ext_file = lib_dir.join("syntax_suggest").join("core_ext.rb")
+ require_relative core_ext_file
- skip if error.respond_to?(:path)
+ error_klass = Class.new do
+ def path
+ fixtures_dir.join("this_project_extra_def.rb.txt")
+ end
- require "syntax_suggest/core_ext"
+ def detailed_message(**kwargs)
+ "error"
+ end
+ end
+ error_klass.prepend(SyntaxSuggest.module_for_detailed_message)
+ error = error_klass.new
expect(error.detailed_message(highlight: true)).to include(SyntaxSuggest::DisplayCodeWithLineNumbers::TERMINAL_HIGHLIGHT)
expect(error.detailed_message(highlight: false)).to_not include(SyntaxSuggest::DisplayCodeWithLineNumbers::TERMINAL_HIGHLIGHT)
@@ -78,11 +87,20 @@ module SyntaxSuggest
it "can be disabled via falsey kwarg" do
skip if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.2")
- error = SyntaxError.new("#{fixtures_dir.join("this_project_extra_def.rb.txt")}:1 ")
+ core_ext_file = lib_dir.join("syntax_suggest").join("core_ext.rb")
+ require_relative core_ext_file
- skip if error.respond_to?(:path)
+ error_klass = Class.new do
+ def path
+ fixtures_dir.join("this_project_extra_def.rb.txt")
+ end
- require "syntax_suggest/core_ext"
+ def detailed_message(**kwargs)
+ "error"
+ end
+ end
+ error_klass.prepend(SyntaxSuggest.module_for_detailed_message)
+ error = error_klass.new
expect(error.detailed_message(syntax_suggest: true)).to_not eq(error.detailed_message(syntax_suggest: false))
end