[ruby/syntax_suggest] Fix missing line break due to puts logic

In #225 it was reported that the output looks incorrect:

```
$ cat /tmp/4a71c7e417cc9eac0971e3a2519b295c/scratch.rb
def x.y.z
end
$ ruby /tmp/4a71c7e417cc9eac0971e3a2519b295c/scratch.rb
/tmp/4a71c7e417cc9eac0971e3a2519b295c/scratch.rb: --> /tmp/4a71c7e417cc9eac0971e3a2519b295c/scratch.rb
expected a delimiter to close the parametersunexpected '.', ignoring it
> 1  def x.y.z
> 2  end
```

Specifically:

```
expected a delimiter to close the parametersunexpected '.', ignoring it
```

However this does not show up when executing the debug executable:

```
$ bin/bundle exec exe/syntax_suggest /tmp/4a71c7e417cc9eac0971e3a2519b295c/scratch.rb
--> /tmp/4a71c7e417cc9eac0971e3a2519b295c/scratch.rb

expected a delimiter to close the parameters
unexpected '.', ignoring it

> 1  def x.y.z
> 2  end
```

This is because `exe/syntax_suggest` uses STDOUT.puts while calling `ruby` with the filename uses a fake IO object represented by MiniStringIO. This class was incorrectly not adding a newline to the end of the print.

The fix was to move the class to it's own file where it can be tested and then fix the behavior.

close https://github.com/ruby/syntax_suggest/pull/225

https://github.com/ruby/syntax_suggest/commit/d2ecd94a3b

Co-authored-by: Andy Yong <andyywz@gmail.com>
This commit is contained in:
Schneems 2024-11-14 18:54:46 -06:00 committed by git
parent 51666c827b
commit 226cfda306
4 changed files with 50 additions and 18 deletions

View File

@ -227,6 +227,7 @@ require_relative "lex_all"
require_relative "code_line"
require_relative "code_block"
require_relative "block_expand"
require_relative "mini_stringio"
require_relative "priority_queue"
require_relative "unvisited_lines"
require_relative "around_block_scan"

View File

@ -3,24 +3,6 @@
# 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 = +""
@isatty = isatty
end
attr_reader :isatty
def puts(value = $/, **)
@string << value
end
attr_reader :string
end
# SyntaxSuggest.module_for_detailed_message [Private]
#
# Used to monkeypatch SyntaxError via Module.prepend

View File

@ -0,0 +1,24 @@
module SyntaxSuggest
# Mini String IO [Private]
#
# Acts like a StringIO with reduced API, but without having to require that
# class.
class MiniStringIO
EMPTY_ARG = Object.new
def initialize(isatty: $stderr.isatty)
@string = +""
@isatty = isatty
end
attr_reader :isatty
def puts(value = EMPTY_ARG, **)
if !value.equal?(EMPTY_ARG)
@string << value
end
@string << $/
end
attr_reader :string
end
end

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
require_relative "../spec_helper"
module SyntaxSuggest
RSpec.describe "MiniStringIO" do
it "#puts with no inputs" do
io = MiniStringIO.new
io.puts
expect(io.string).to eq($/)
end
it "#puts with an input" do
io = MiniStringIO.new
io.puts "Hello"
expect(io.string).to eq(["Hello", $/].join)
end
it "#puts with an input with a newline" do
io = MiniStringIO.new
io.puts "Hello\n"
expect(io.string).to eq(["Hello\n", $/].join)
end
end
end