diff options
Diffstat (limited to 'spec/ruby/core/proc')
| -rw-r--r-- | spec/ruby/core/proc/arity_spec.rb | 16 | ||||
| -rw-r--r-- | spec/ruby/core/proc/clone_spec.rb | 24 | ||||
| -rw-r--r-- | spec/ruby/core/proc/curry_spec.rb | 9 | ||||
| -rw-r--r-- | spec/ruby/core/proc/dup_spec.rb | 22 | ||||
| -rw-r--r-- | spec/ruby/core/proc/element_reference_spec.rb | 2 | ||||
| -rw-r--r-- | spec/ruby/core/proc/fixtures/common.rb | 23 | ||||
| -rw-r--r-- | spec/ruby/core/proc/fixtures/proc_aref.rb | 1 | ||||
| -rw-r--r-- | spec/ruby/core/proc/lambda_spec.rb | 8 | ||||
| -rw-r--r-- | spec/ruby/core/proc/parameters_spec.rb | 73 | ||||
| -rw-r--r-- | spec/ruby/core/proc/ruby2_keywords_spec.rb | 14 | ||||
| -rw-r--r-- | spec/ruby/core/proc/shared/dup.rb | 29 | ||||
| -rw-r--r-- | spec/ruby/core/proc/shared/to_s.rb | 14 | ||||
| -rw-r--r-- | spec/ruby/core/proc/source_location_spec.rb | 59 |
13 files changed, 227 insertions, 67 deletions
diff --git a/spec/ruby/core/proc/arity_spec.rb b/spec/ruby/core/proc/arity_spec.rb index f7cb5ad0f8..5c7728cb30 100644 --- a/spec/ruby/core/proc/arity_spec.rb +++ b/spec/ruby/core/proc/arity_spec.rb @@ -268,6 +268,14 @@ describe "Proc#arity" do @a.arity.should == 3 @b.arity.should == 3 end + + # implicit rest + evaluate <<-ruby do + @a = lambda { |a, | } + ruby + + @a.arity.should == 1 + end end context "returns negative values" do @@ -530,6 +538,14 @@ describe "Proc#arity" do @a.arity.should == 1 @b.arity.should == 5 end + + # implicit rest + evaluate <<-ruby do + @a = proc { |a, | } + ruby + + @a.arity.should == 1 + end end context "returns negative values" do diff --git a/spec/ruby/core/proc/clone_spec.rb b/spec/ruby/core/proc/clone_spec.rb index a1a1292654..730dc421a8 100644 --- a/spec/ruby/core/proc/clone_spec.rb +++ b/spec/ruby/core/proc/clone_spec.rb @@ -1,6 +1,30 @@ require_relative '../../spec_helper' +require_relative 'fixtures/common' require_relative 'shared/dup' describe "Proc#clone" do it_behaves_like :proc_dup, :clone + + ruby_bug "cloning a frozen proc is broken on Ruby 3.3", "3.3"..."3.4" do + it "preserves frozen status" do + proc = Proc.new { } + proc.freeze + proc.frozen?.should == true + proc.clone.frozen?.should == true + end + end + + ruby_version_is "3.3" do + it "calls #initialize_clone on subclass" do + obj = ProcSpecs::MyProc2.new(:a, 2) { } + dup = obj.clone + + dup.should_not equal(obj) + dup.class.should == ProcSpecs::MyProc2 + + dup.first.should == :a + dup.second.should == 2 + dup.initializer.should == :clone + end + end end diff --git a/spec/ruby/core/proc/curry_spec.rb b/spec/ruby/core/proc/curry_spec.rb index 24df2a8a72..6daabe0ee1 100644 --- a/spec/ruby/core/proc/curry_spec.rb +++ b/spec/ruby/core/proc/curry_spec.rb @@ -159,15 +159,14 @@ describe "Proc#curry with arity argument" do end it "can be passed more than _arity_ arguments if created from a proc" do - -> { @proc_add.curry(3)[1,2,3,4].should == 6 }.should_not - raise_error(ArgumentError) - -> { @proc_add.curry(1)[1,2].curry(3)[3,4,5,6].should == 6 }.should_not - raise_error(ArgumentError) + @proc_add.curry(3)[1,2,3,4].should == 6 + + @proc_add.curry(3)[1,2].curry(3)[3,4,5,6].should == 6 end it "raises an ArgumentError if passed more than _arity_ arguments when created from a lambda" do -> { @lambda_add.curry(3)[1,2,3,4] }.should raise_error(ArgumentError) - -> { @lambda_add.curry(1)[1,2].curry(3)[3,4,5,6] }.should raise_error(ArgumentError) + -> { @lambda_add.curry(3)[1,2].curry(3)[3,4,5,6] }.should raise_error(ArgumentError) end it "returns Procs with arities of -1 regardless of the value of _arity_" do diff --git a/spec/ruby/core/proc/dup_spec.rb b/spec/ruby/core/proc/dup_spec.rb index 6da2f3080c..716357d1f0 100644 --- a/spec/ruby/core/proc/dup_spec.rb +++ b/spec/ruby/core/proc/dup_spec.rb @@ -1,6 +1,28 @@ require_relative '../../spec_helper' +require_relative 'fixtures/common' require_relative 'shared/dup' describe "Proc#dup" do it_behaves_like :proc_dup, :dup + + it "resets frozen status" do + proc = Proc.new { } + proc.freeze + proc.frozen?.should == true + proc.dup.frozen?.should == false + end + + ruby_version_is "3.3" do + it "calls #initialize_dup on subclass" do + obj = ProcSpecs::MyProc2.new(:a, 2) { } + dup = obj.dup + + dup.should_not equal(obj) + dup.class.should == ProcSpecs::MyProc2 + + dup.first.should == :a + dup.second.should == 2 + dup.initializer.should == :dup + end + end end diff --git a/spec/ruby/core/proc/element_reference_spec.rb b/spec/ruby/core/proc/element_reference_spec.rb index 9077e44c34..81ceb91af5 100644 --- a/spec/ruby/core/proc/element_reference_spec.rb +++ b/spec/ruby/core/proc/element_reference_spec.rb @@ -17,7 +17,7 @@ describe "Proc#call on a Proc created with Kernel#lambda or Kernel#proc" do it_behaves_like :proc_call_on_proc_or_lambda, :call end -describe "Proc#[] with frozen_string_literals" do +describe "Proc#[] with frozen_string_literal: true/false" do it "doesn't duplicate frozen strings" do ProcArefSpecs.aref.frozen?.should be_false ProcArefSpecs.aref_freeze.frozen?.should be_true diff --git a/spec/ruby/core/proc/fixtures/common.rb b/spec/ruby/core/proc/fixtures/common.rb index 6e27a2dee7..dfe67d7ba8 100644 --- a/spec/ruby/core/proc/fixtures/common.rb +++ b/spec/ruby/core/proc/fixtures/common.rb @@ -32,7 +32,28 @@ module ProcSpecs @second = b end - attr_reader :first, :second + attr_reader :first, :second, :initializer + + def initialize_copy(other) + super + @initializer = :copy + @first = other.first + @second = other.second + end + + def initialize_dup(other) + super + @initializer = :dup + @first = other.first + @second = other.second + end + + def initialize_clone(other, **options) + super + @initializer = :clone + @first = other.first + @second = other.second + end end class Arity diff --git a/spec/ruby/core/proc/fixtures/proc_aref.rb b/spec/ruby/core/proc/fixtures/proc_aref.rb index a305667797..8ee355b14c 100644 --- a/spec/ruby/core/proc/fixtures/proc_aref.rb +++ b/spec/ruby/core/proc/fixtures/proc_aref.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: false module ProcArefSpecs def self.aref proc {|a| a }["sometext"] diff --git a/spec/ruby/core/proc/lambda_spec.rb b/spec/ruby/core/proc/lambda_spec.rb index b2d3f50350..5c3c38fc2a 100644 --- a/spec/ruby/core/proc/lambda_spec.rb +++ b/spec/ruby/core/proc/lambda_spec.rb @@ -14,9 +14,11 @@ describe "Proc#lambda?" do Proc.new {}.lambda?.should be_false end - it "is preserved when passing a Proc with & to the lambda keyword" do - suppress_warning {lambda(&->{})}.lambda?.should be_true - suppress_warning {lambda(&proc{})}.lambda?.should be_false + ruby_version_is ""..."3.3" do + it "is preserved when passing a Proc with & to the lambda keyword" do + suppress_warning {lambda(&->{})}.lambda?.should be_true + suppress_warning {lambda(&proc{})}.lambda?.should be_false + end end it "is preserved when passing a Proc with & to the proc keyword" do diff --git a/spec/ruby/core/proc/parameters_spec.rb b/spec/ruby/core/proc/parameters_spec.rb index 1ffaf17315..cf8a8f5b12 100644 --- a/spec/ruby/core/proc/parameters_spec.rb +++ b/spec/ruby/core/proc/parameters_spec.rb @@ -20,19 +20,27 @@ describe "Proc#parameters" do proc {|x| }.parameters.first.first.should == :opt end - ruby_version_is "3.2" do - it "sets the first element of each sub-Array to :req if argument would be required if a lambda if lambda keyword used" do - proc {|x| }.parameters(lambda: true).first.first.should == :req - proc {|y,*x| }.parameters(lambda: true).first.first.should == :req - end + it "sets the first element of each sub-Array to :req for required argument if lambda keyword used" do + proc {|x| }.parameters(lambda: true).first.first.should == :req + proc {|y,*x| }.parameters(lambda: true).first.first.should == :req + end - it "regards named parameters in procs as required if lambda keyword used" do - proc {|x| }.parameters(lambda: true).first.first.should == :req - end + it "regards named parameters in procs as required if lambda keyword used" do + proc {|x| }.parameters(lambda: true).first.first.should == :req + end - it "regards named parameters in lambda as optional if lambda: false keyword used" do - -> x { }.parameters(lambda: false).first.first.should == :opt - end + it "regards named parameters in lambda as optional if lambda: false keyword used" do + -> x { }.parameters(lambda: false).first.first.should == :opt + end + + it "regards named parameters in procs and lambdas as required if lambda keyword is truthy" do + proc {|x| }.parameters(lambda: 123).first.first.should == :req + -> x { }.parameters(lambda: 123).first.first.should == :req + end + + it "ignores the lambda keyword if it is nil" do + proc {|x|}.parameters(lambda: nil).first.first.should == :opt + -> x { }.parameters(lambda: nil).first.first.should == :req end it "regards optional keyword parameters in procs as optional" do @@ -54,7 +62,7 @@ describe "Proc#parameters" do end it "regards keyword parameters in lambdas as required" do - eval("lambda {|x:| }").parameters.first.first.should == :keyreq + -> x: { }.parameters.first.first.should == :keyreq end it "sets the first element of each sub-Array to :rest for parameters prefixed with asterisks" do @@ -91,20 +99,25 @@ describe "Proc#parameters" do proc {|&block| }.parameters.first.last.should == :block end - it "ignores unnamed rest args" do + it "ignores unnamed rest arguments" do -> x {}.parameters.should == [[:req, :x]] end - ruby_version_is '3.2' do - it "adds * rest arg for \"star\" argument" do - -> x, * {}.parameters.should == [[:req, :x], [:rest, :*]] - end + it "ignores implicit rest arguments" do + proc { |x, | }.parameters.should == [[:opt, :x]] + -> x { }.parameters.should == [[:req, :x]] end - ruby_version_is ''...'3.2' do - it "adds nameless rest arg for \"star\" argument" do - -> x, * {}.parameters.should == [[:req, :x], [:rest]] - end + it "adds rest arg with name * for \"star\" argument" do + -> * {}.parameters.should == [[:rest, :*]] + end + + it "adds keyrest arg with ** as a name for \"double star\" argument" do + -> ** {}.parameters.should == [[:keyrest, :**]] + end + + it "adds block arg with name & for anonymous block argument" do + -> & {}.parameters.should == [[:block, :&]] end it "does not add locals as block options with a block and splat" do @@ -141,4 +154,22 @@ describe "Proc#parameters" do [:block, :_] ] end + + it "returns :nokey for **nil parameter" do + proc { |**nil| }.parameters.should == [[:nokey]] + end + + ruby_version_is "3.4"..."4.0" do + it "handles the usage of `it` as a parameter" do + eval("proc { it }").parameters.should == [[:opt, nil]] + eval("lambda { it }").parameters.should == [[:req]] + end + end + + ruby_version_is "4.0" do + it "handles the usage of `it` as a parameter" do + eval("proc { it }").parameters.should == [[:opt]] + eval("lambda { it }").parameters.should == [[:req]] + end + end end diff --git a/spec/ruby/core/proc/ruby2_keywords_spec.rb b/spec/ruby/core/proc/ruby2_keywords_spec.rb index ab67302231..d7f8f592e1 100644 --- a/spec/ruby/core/proc/ruby2_keywords_spec.rb +++ b/spec/ruby/core/proc/ruby2_keywords_spec.rb @@ -39,7 +39,7 @@ describe "Proc#ruby2_keywords" do end it "prints warning when a proc accepts keywords" do - f = -> a:, b: { } + f = -> *a, b: { } -> { f.ruby2_keywords @@ -47,10 +47,20 @@ describe "Proc#ruby2_keywords" do end it "prints warning when a proc accepts keyword splat" do - f = -> **a { } + f = -> *a, **b { } -> { f.ruby2_keywords }.should complain(/Skipping set of ruby2_keywords flag for/) end + + ruby_version_is "4.0" do + it "prints warning when a proc accepts post arguments" do + f = -> *a, b { } + + -> { + f.ruby2_keywords + }.should complain(/Skipping set of ruby2_keywords flag for/) + end + end end diff --git a/spec/ruby/core/proc/shared/dup.rb b/spec/ruby/core/proc/shared/dup.rb index 4480f3d0c9..1266337f94 100644 --- a/spec/ruby/core/proc/shared/dup.rb +++ b/spec/ruby/core/proc/shared/dup.rb @@ -8,11 +8,32 @@ describe :proc_dup, shared: true do a.call.should == b.call end - ruby_version_is "3.2" do - it "returns an instance of subclass" do - cl = Class.new(Proc) + it "returns an instance of subclass" do + cl = Class.new(Proc) - cl.new{}.send(@method).class.should == cl + cl.new{}.send(@method).class.should == cl + end + + ruby_version_is "3.4" do + it "copies instance variables" do + proc = -> { "hello" } + proc.instance_variable_set(:@ivar, 1) + cl = proc.send(@method) + cl.instance_variables.should == [:@ivar] + end + + it "copies the finalizer" do + code = <<-'RUBY' + obj = Proc.new { } + + ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" }) + + obj.clone + + exit 0 + RUBY + + ruby_exe(code).lines.sort.should == ["finalized\n", "finalized\n"] end end end diff --git a/spec/ruby/core/proc/shared/to_s.rb b/spec/ruby/core/proc/shared/to_s.rb index f1e2f416fc..a52688a89f 100644 --- a/spec/ruby/core/proc/shared/to_s.rb +++ b/spec/ruby/core/proc/shared/to_s.rb @@ -31,13 +31,13 @@ describe :proc_to_s, shared: true do describe "for a proc created with UnboundMethod#to_proc" do it "returns a description including '(lambda)' and optionally including file and line number" do - def hello; end - s = method("hello").to_proc.send(@method) - if s.include? __FILE__ - s.should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ - 3} \(lambda\)>$/ - else - s.should =~ /^#<Proc:([^ ]*?) \(lambda\)>$/ - end + def hello; end + s = method("hello").to_proc.send(@method) + if s.include? __FILE__ + s.should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ - 3} \(lambda\)>$/ + else + s.should =~ /^#<Proc:([^ ]*?) \(lambda\)>$/ + end end it "has a binary encoding" do diff --git a/spec/ruby/core/proc/source_location_spec.rb b/spec/ruby/core/proc/source_location_spec.rb index a5895a7fcb..fd33f21a26 100644 --- a/spec/ruby/core/proc/source_location_spec.rb +++ b/spec/ruby/core/proc/source_location_spec.rb @@ -17,57 +17,64 @@ describe "Proc#source_location" do end it "sets the first value to the path of the file in which the proc was defined" do - file = @proc.source_location.first + file = @proc.source_location[0] file.should be_an_instance_of(String) - file.should == File.realpath('../fixtures/source_location.rb', __FILE__) + file.should == File.realpath('fixtures/source_location.rb', __dir__) - file = @proc_new.source_location.first + file = @proc_new.source_location[0] file.should be_an_instance_of(String) - file.should == File.realpath('../fixtures/source_location.rb', __FILE__) + file.should == File.realpath('fixtures/source_location.rb', __dir__) - file = @lambda.source_location.first + file = @lambda.source_location[0] file.should be_an_instance_of(String) - file.should == File.realpath('../fixtures/source_location.rb', __FILE__) + file.should == File.realpath('fixtures/source_location.rb', __dir__) - file = @method.source_location.first + file = @method.source_location[0] file.should be_an_instance_of(String) - file.should == File.realpath('../fixtures/source_location.rb', __FILE__) + file.should == File.realpath('fixtures/source_location.rb', __dir__) end - it "sets the last value to an Integer representing the line on which the proc was defined" do - line = @proc.source_location.last + it "sets the second value to an Integer representing the line on which the proc was defined" do + line = @proc.source_location[1] line.should be_an_instance_of(Integer) line.should == 4 - line = @proc_new.source_location.last + line = @proc_new.source_location[1] line.should be_an_instance_of(Integer) line.should == 12 - line = @lambda.source_location.last + line = @lambda.source_location[1] line.should be_an_instance_of(Integer) line.should == 8 - line = @method.source_location.last + line = @method.source_location[1] line.should be_an_instance_of(Integer) line.should == 15 end it "works even if the proc was created on the same line" do - proc { true }.source_location.should == [__FILE__, __LINE__] - Proc.new { true }.source_location.should == [__FILE__, __LINE__] - -> { true }.source_location.should == [__FILE__, __LINE__] + ruby_version_is(""..."4.1") do + proc { true }.source_location.should == [__FILE__, __LINE__] + Proc.new { true }.source_location.should == [__FILE__, __LINE__] + -> { true }.source_location.should == [__FILE__, __LINE__] + end + ruby_version_is("4.1") do + proc { true }.source_location.should == [__FILE__, __LINE__, 11, __LINE__, 19] + Proc.new { true }.source_location.should == [__FILE__, __LINE__, 15, __LINE__, 23] + -> { true }.source_location.should == [__FILE__, __LINE__, 6, __LINE__, 17] + end end it "returns the first line of a multi-line proc (i.e. the line containing 'proc do')" do - ProcSpecs::SourceLocation.my_multiline_proc.source_location.last.should == 20 - ProcSpecs::SourceLocation.my_multiline_proc_new.source_location.last.should == 34 - ProcSpecs::SourceLocation.my_multiline_lambda.source_location.last.should == 27 + ProcSpecs::SourceLocation.my_multiline_proc.source_location[1].should == 20 + ProcSpecs::SourceLocation.my_multiline_proc_new.source_location[1].should == 34 + ProcSpecs::SourceLocation.my_multiline_lambda.source_location[1].should == 27 end it "returns the location of the proc's body; not necessarily the proc itself" do - ProcSpecs::SourceLocation.my_detached_proc.source_location.last.should == 41 - ProcSpecs::SourceLocation.my_detached_proc_new.source_location.last.should == 51 - ProcSpecs::SourceLocation.my_detached_lambda.source_location.last.should == 46 + ProcSpecs::SourceLocation.my_detached_proc.source_location[1].should == 41 + ProcSpecs::SourceLocation.my_detached_proc_new.source_location[1].should == 51 + ProcSpecs::SourceLocation.my_detached_lambda.source_location[1].should == 46 end it "returns the same value for a proc-ified method as the method reports" do @@ -86,6 +93,12 @@ describe "Proc#source_location" do it "works for eval with a given line" do proc = eval('-> {}', nil, "foo", 100) - proc.source_location.should == ["foo", 100] + location = proc.source_location + ruby_version_is(""..."4.1") do + location.should == ["foo", 100] + end + ruby_version_is("4.1") do + location.should == ["foo", 100, 0, 100, 5] + end end end |
