Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/actions/setup/directories/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ runs:
path: ${{ inputs.srcdir }}
fetch-depth: ${{ inputs.fetch-depth }}

- uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
- uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with:
path: ${{ inputs.srcdir }}/.downloaded-cache
key: ${{ runner.os }}-${{ runner.arch }}-downloaded-cache
Expand Down
9 changes: 9 additions & 0 deletions lib/prism/parse_result.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@ def slice(byte_offset, length)
source.byteslice(byte_offset, length) or raise
end

# Converts the line number to a byte offset corresponding to the start of that line
def line_to_byte_offset(line)
l = line - @start_line
if l < 0 || l >= offsets.size
raise ArgumentError, "line #{line} is out of range"
end
offsets[l]
end

# Binary search through the offsets to find the line number for the given
# byte offset.
def line(byte_offset)
Expand Down
4 changes: 4 additions & 0 deletions lib/rubygems/commands/pristine_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ def description # :nodoc:
will revert them. All extensions are rebuilt and all bin stubs for the gem
are regenerated after checking for modifications.
Rebuilding extensions also refreshes C-extension gems against updated system
libraries (for example after OS or package upgrades) to avoid mismatches like
outdated library version warnings.
If the cached gem cannot be found it will be downloaded.
If --no-extensions is provided pristine will not attempt to restore a gem
Expand Down
1 change: 1 addition & 0 deletions lib/rubygems/util/atomic_file_writer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def self.open(file_name)
flags |= File::SHARE_DELETE if defined?(File::SHARE_DELETE)

File.open(tmp_path, flags) do |temp_file|
temp_file.binmode
if old_stat
# Set correct permissions on new file
begin
Expand Down
8 changes: 4 additions & 4 deletions prism/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1269,17 +1269,17 @@ nodes:
- name: opening_loc
type: location
comment: |
Represents the location of the opening `|`.
Represents the location of the opening `{` or `do`.
[1, 2, 3].each { |i| puts x }
^
^
- name: closing_loc
type: location
comment: |
Represents the location of the closing `|`.
Represents the location of the closing `}` or `end`.
[1, 2, 3].each { |i| puts x }
^
^
comment: |
Represents a block of ruby code.
Expand Down
17 changes: 3 additions & 14 deletions prism/templates/lib/prism/node.rb.erb
Original file line number Diff line number Diff line change
Expand Up @@ -184,24 +184,13 @@ module Prism
queue = [self] #: Array[Prism::node]
result = [] #: Array[Prism::node]

search_offset = source.line_to_byte_offset(line) + column

while (node = queue.shift)
result << node

node.each_child_node do |child_node|
child_location = child_node.location

start_line = child_location.start_line
end_line = child_location.end_line

if start_line == end_line
if line == start_line && column >= child_location.start_column && column < child_location.end_column
queue << child_node
break
end
elsif (line == start_line && column >= child_location.start_column) || (line == end_line && column < child_location.end_column)
queue << child_node
break
elsif line > start_line && line < end_line
if child_node.start_offset <= search_offset && search_offset < child_node.end_offset
queue << child_node
break
end
Expand Down
52 changes: 5 additions & 47 deletions test/prism/lex_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,6 @@

module Prism
class LexTest < TestCase
except = [
# https://bugs.ruby-lang.org/issues/21756
"spanning_heredoc.txt",
# Prism emits a single string in some cases when ripper splits them up
"whitequark/dedenting_heredoc.txt",
"heredocs_with_fake_newlines.txt",
# Prism emits BEG for `on_regexp_end`
"spanning_heredoc_newlines.txt",
]

if RUBY_VERSION < "3.3.0"
# This file has changed behavior in Ripper in Ruby 3.3, so we skip it if
# we're on an earlier version.
except << "seattlerb/pct_w_heredoc_interp_nested.txt"

# Ruby < 3.3.0 cannot parse heredocs where there are leading whitespace
# characters in the heredoc start.
# Example: <<~' EOF' or <<-' EOF'
# https://bugs.ruby-lang.org/issues/19539
except << "heredocs_leading_whitespace.txt"
except << "whitequark/ruby_bug_19539.txt"

# https://bugs.ruby-lang.org/issues/19025
except << "whitequark/numparam_ruby_bug_19025.txt"
# https://bugs.ruby-lang.org/issues/18878
except << "whitequark/ruby_bug_18878.txt"
# https://bugs.ruby-lang.org/issues/19281
except << "whitequark/ruby_bug_19281.txt"
end

# https://bugs.ruby-lang.org/issues/21168#note-5
except << "command_method_call_2.txt"

Fixture.each_for_current_ruby(except: except) do |fixture|
define_method(fixture.test_name) { assert_lex(fixture) }
end

def test_lex_file
assert_nothing_raised do
Prism.lex_file(__FILE__)
Expand Down Expand Up @@ -83,16 +46,11 @@ def test_parse_lex_file
end
end

private

def assert_lex(fixture)
source = fixture.read

result = Prism.lex_compat(source, version: "current")
assert_equal [], result.errors

Prism.lex_ripper(source).zip(result.value).each do |(ripper, prism)|
assert_equal ripper, prism
if RUBY_VERSION >= "3.3"
def test_lex_compare
prism = Prism.lex_compat(File.read(__FILE__), version: "current").value
ripper = Prism.lex_ripper(File.read(__FILE__))
assert_equal(ripper, prism)
end
end
end
Expand Down
47 changes: 47 additions & 0 deletions test/prism/ruby/source_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# frozen_string_literal: true

require_relative "../test_helper"

module Prism
class SourceTest < TestCase
def test_line_to_byte_offset
parse_result = Prism.parse(<<~SRC)
abcd
efgh
ijkl
SRC
source = parse_result.source

assert_equal 0, source.line_to_byte_offset(1)
assert_equal 5, source.line_to_byte_offset(2)
assert_equal 10, source.line_to_byte_offset(3)
assert_equal 15, source.line_to_byte_offset(4)
e = assert_raise(ArgumentError) { source.line_to_byte_offset(5) }
assert_equal "line 5 is out of range", e.message
e = assert_raise(ArgumentError) { source.line_to_byte_offset(0) }
assert_equal "line 0 is out of range", e.message
e = assert_raise(ArgumentError) { source.line_to_byte_offset(-1) }
assert_equal "line -1 is out of range", e.message
end

def test_line_to_byte_offset_with_start_line
parse_result = Prism.parse(<<~SRC, line: 11)
abcd
efgh
ijkl
SRC
source = parse_result.source

assert_equal 0, source.line_to_byte_offset(11)
assert_equal 5, source.line_to_byte_offset(12)
assert_equal 10, source.line_to_byte_offset(13)
assert_equal 15, source.line_to_byte_offset(14)
e = assert_raise(ArgumentError) { source.line_to_byte_offset(15) }
assert_equal "line 15 is out of range", e.message
e = assert_raise(ArgumentError) { source.line_to_byte_offset(10) }
assert_equal "line 10 is out of range", e.message
e = assert_raise(ArgumentError) { source.line_to_byte_offset(9) }
assert_equal "line 9 is out of range", e.message
end
end
end
12 changes: 12 additions & 0 deletions test/rubygems/test_gem_util_atomic_file_writer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

require_relative "helper"
require "rubygems/util/atomic_file_writer"

class TestGemUtilAtomicFileWriter < Gem::TestCase
def test_external_encoding
Gem::AtomicFileWriter.open(File.join(@tempdir, "test.txt")) do |file|
assert_equal(Encoding::ASCII_8BIT, file.external_encoding)
end
end
end