Skip to content

Conversation

@Earlopain
Copy link
Contributor

It used to not emit this token type, but now it does. So when a newer version of prism is present, we can fall back to the same code that ripper uses.

Ref:

@Earlopain Earlopain marked this pull request as draft January 20, 2026 11:35
@Earlopain Earlopain marked this pull request as ready for review January 20, 2026 11:47
@eregon eregon requested a review from schneems January 20, 2026 11:56
last&.type == :on_tstring_end
return false unless last

last.type == :on_tstring_end || (last.type == :on_sp && last.token == TRAILING_SLASH)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The (last.type == :on_sp && last.token == TRAILING_SLASH) part is to handle the fact there is no Prism 1.8.1/1.9.0 yet and so no easy way to detect Prism has :on_sp vs not, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's right. I tried feature detection (Prism.lex_compat(" ").value.dig(0, 1) == :on_sp) but then some other test here fails because prism loads delegate and that adds a method to Kernel which it didn't like

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's right. I tried feature detection (Prism.lex_compat(" ").value.dig(0, 1) == :on_sp) but then some other test here fails because prism loads delegate and that adds a method to Kernel which it didn't like

Explaining that test a bit: I have regression tests that make sure I'm not accidentally messing with people's requires so they don't come to rely on me loading something by accident. Otherwise, if I require pathname someone might come to rely on that always being available and have their code break if I were to change usage.

The two ways to use syntax suggest is either by requiring syntax_suggest which sets up core extensions that only trigger those loads on syntax error. Or you can also require syntax_suggest/api which was added for support for sorbet (not sure if they ended up using it or not) so they can manually invoke syntax suggest on parsing.

The test that fails is when requiring syntax_suggest/api, which is less worrisome than the more common syntax_suggest (loaded by default). But it's still better not to do it at all.

Copy link
Member

@eregon eregon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good and safe to me.

@eregon
Copy link
Member

eregon commented Jan 20, 2026

Some CI jobs are failing, the 4.0 job failures seem unrelated & pre-existing but https://github.com/ruby/syntax_suggest/actions/runs/21170190500/job/60887146934?pr=241 needs a changelog entry or so

@Earlopain
Copy link
Contributor Author

CI should be green with #242. I added a changelog entry

It used to not emit this token type, but now it does.
So when a newer version of prism is present, we can fall back
to the same code that ripper uses.

Ref:
* ruby/ruby#15914
* ruby/prism#3859
@eregon
Copy link
Member

eregon commented Jan 20, 2026

What's the order here, I suppose we could merge this PR, and that will then auto-push/sync a commit to ruby/ruby and then we only need the Reapply commit from ruby/ruby#15914?

Also not sure how urgent it is, I suppose it can get messy if other PRs are merged in ruby/prism as then that sync might not work either. If it's not urgent I would probably wait for @schneems' review.

@Earlopain
Copy link
Contributor Author

I think we can merge the ruby PR, leave this open, and then apply any desired changes on top of this PR so that those get synced over.

We should not merge much in prism related to ripper until the commit is reapplied. Since we know, we can wait a bit until we get a review here.

@eregon
Copy link
Member

eregon commented Jan 20, 2026

Makes sense, I merged the ruby/ruby PR.

schneems added a commit that referenced this pull request Jan 20, 2026
The reason this logic for different methods branches in the class instead of internally was to be eagerly aggressive about runtime performance. This code is currently only used once for the document where it's invoked ~N times (where N is number of lines):

```ruby
module SyntaxSuggest
  class CleanDocument
    # ...
    def join_trailing_slash!
      trailing_groups = @document.select(&:trailing_slash?).map do |code_line|
        take_while_including(code_line.index..) { |x| x.trailing_slash? }
      end
      join_groups(trailing_groups)
      self
    end
```

Since this is not currently a hot-spot I think merging the branches and using a case statement is a reasonable tradeoff and avoids the need to do specific version testing. 

An alternative idea was presented in #241 of behavior-based testing for branch logic (which I would prefer), however, calling the code triggered requiring a `DelegateClass` when the `syntax_suggest/api` is being required.
@schneems
Copy link
Collaborator

I added tests for multiple prism versions in #243 then cherry-picked your commit on top, and re-worked the implementation a bit after reviewing why I split my branching logic like that.

Can we flip the script and have you all review my changes in #243 to make sure things are clear (and suggestions welcome).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants