Skip to content

Use Prism gem instead of Parser gem when Ruby 3.4+ #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 2, 2025
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
13 changes: 5 additions & 8 deletions lib/rspec/parameterized/core.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
require "rspec/parameterized/core/version"
require 'parser'
require 'unparser'
require 'proc_to_ast'
require 'rspec/parameterized/core/helper_methods'
require 'rspec/parameterized/core/example_helper_methods'
require 'rspec/parameterized/core/errors'
require 'rspec/parameterized/core/composite_parser'

module RSpec
module Parameterized
Expand Down Expand Up @@ -143,11 +142,9 @@ def define_cases(parameter, *args, &block)
end

def params_inspect(obj)
begin
obj.is_a?(Proc) ? obj.to_raw_source : obj.inspect
rescue Parser::SyntaxError
return obj.inspect
end
RSpec::Parameterized::Core::CompositeParser.to_raw_source(obj)
rescue ParserSyntaxError
return obj.inspect
end

def set_verbose_parameters(&block)
Expand Down
75 changes: 75 additions & 0 deletions lib/rspec/parameterized/core/composite_parser.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
module RSpec
module Parameterized
module Core
# Proxy class for parser and prism
module CompositeParser
# @param obj [Object]
# @return [String]
# @raise [RSpec::Parameterized::Core::ParserSyntaxError]
def self.to_raw_source(obj)
return to_raw_source_with_prism(obj) if use_prism?

to_raw_source_with_parser(obj)
end

# Whether use parser or prism
#
# @return [true] Use prism
# @return [false] Use parser
def self.use_prism?
Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0")
end

# @param obj [Object]
# @return [String]
# @raise [RSpec::Parameterized::Core::ParserSyntaxError]
def self.to_raw_source_with_parser(obj)
obj.is_a?(Proc) ? obj.to_raw_source : obj.inspect
rescue Parser::SyntaxError => e
raise ParserSyntaxError
end
private_class_method :to_raw_source_with_parser

# @param obj [Object]
# @return [String]
def self.to_raw_source_with_prism(obj)
return obj.inspect unless obj.is_a?(Proc)

filename, linenum = obj.source_location
ast = parse_with_prism(filename, linenum)

return "" unless ast

ast.source.source.strip
end
private_class_method :to_raw_source_with_prism

# @param filename [String]
# @param linenum [Integer]
#
# @return [Prism::ParseResult,nil]
def self.parse_with_prism(filename, linenum)
buf = []
File.open(filename, "rb").each_with_index do |line, index|
next if index < linenum - 1
buf << line

ret = Prism.parse(buf.join)
return ret if ret.success?
end

nil
end
private_class_method :parse_with_prism
end
end
end
end

if RSpec::Parameterized::Core::CompositeParser.use_prism?
require 'prism'
else
require 'parser'
require 'unparser'
require 'proc_to_ast'
end
9 changes: 9 additions & 0 deletions lib/rspec/parameterized/core/errors.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module RSpec
module Parameterized
module Core
class Error < StandardError; end

class ParserSyntaxError < Error; end
end
end
end
4 changes: 2 additions & 2 deletions lib/rspec/parameterized/core/lazy_arg.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ def apply(obj)
end

def inspect
"#{@block.to_raw_source}"
rescue Parser::SyntaxError
CompositeParser.to_raw_source(@block)
rescue ParserSyntaxError
super.inspect
end
end
Expand Down
8 changes: 7 additions & 1 deletion rspec-parameterized-core.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,18 @@ I was inspired by [udzura's mock](https://gist.github.com/1881139).}
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]

spec.add_dependency "rspec", ">= 2.13", "< 4"

# parser dependencies
spec.add_dependency "parser"
spec.add_dependency "proc_to_ast", ">= 0.2.0"
spec.add_dependency "rspec", ">= 2.13", "< 4"
spec.add_dependency "unparser"

# prism dependencies
spec.add_dependency "prism"

spec.add_development_dependency "rake", ">= 12.0.0"
spec.add_development_dependency "rspec-its"

# For more information and examples about making a new gem, check out our
# guide at: https://bundler.io/guides/creating_gem.html
Expand Down
45 changes: 45 additions & 0 deletions spec/rspec/parameterized/core/composite_parser_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
describe RSpec::Parameterized::Core::CompositeParser do
describe ".to_raw_source" do
subject { RSpec::Parameterized::Core::CompositeParser.to_raw_source(arg) }

context "arg is not proc" do
let(:arg) do
123
end

it { should eq "123" }
end

context "arg is proc" do
context "simple case" do
let(:arg) do
->(a) { a + 1 }
end

it { should eq "->(a) { a + 1 }" }
its(:encoding) { should eq Encoding::UTF_8 }
end

context "arg is multibyte characters" do
let(:arg) do
->(a) { a + "ほげほげ" }
end

it { should eq '->(a) { a + "ほげほげ" }' }
its(:encoding) { should eq Encoding::UTF_8 }
end

context "multiple lines" do
let(:arg) do
->(a) {
a +
1
}
end

it { should eq "->(a) {\n a +\n 1\n }" }
its(:encoding) { should eq Encoding::UTF_8 }
end
end
end
end
2 changes: 2 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
require 'rspec-parameterized-core'

require 'rspec/its'

RSpec.configure do |config|
config.treat_symbols_as_metadata_keys_with_true_values = true
config.run_all_when_everything_filtered = true
Expand Down