summaryrefslogtreecommitdiff
path: root/spec/ruby/core/module/ruby2_keywords_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/core/module/ruby2_keywords_spec.rb')
-rw-r--r--spec/ruby/core/module/ruby2_keywords_spec.rb360
1 files changed, 232 insertions, 128 deletions
diff --git a/spec/ruby/core/module/ruby2_keywords_spec.rb b/spec/ruby/core/module/ruby2_keywords_spec.rb
index 6de3fdec80..80a99e2624 100644
--- a/spec/ruby/core/module/ruby2_keywords_spec.rb
+++ b/spec/ruby/core/module/ruby2_keywords_spec.rb
@@ -1,215 +1,319 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "2.7" do
- describe "Module#ruby2_keywords" do
- it "marks the final hash argument as keyword hash" do
- obj = Object.new
+describe "Module#ruby2_keywords" do
+ class << self
+ ruby2_keywords def mark(*args)
+ args
+ end
+ end
- obj.singleton_class.class_exec do
- def foo(*a) a.last end
- ruby2_keywords :foo
+ it "marks the final hash argument as keyword hash" do
+ last = mark(1, 2, a: "a").last
+ Hash.ruby2_keywords_hash?(last).should == true
+ end
+
+ it "makes a copy of the hash and only marks the copy as keyword hash" do
+ obj = Object.new
+ obj.singleton_class.class_exec do
+ def regular(*args)
+ args.last
end
+ end
- last = obj.foo(1, 2, a: "a")
- Hash.ruby2_keywords_hash?(last).should == true
+ h = {a: 1}
+ ruby_version_is "3.0" do
+ obj.regular(**h).should.equal?(h)
end
- it "makes a copy of the hash and only marks the copy as keyword hash" do
- obj = Object.new
- obj.singleton_class.class_exec do
- def regular(*args)
- args.last
- end
+ last = mark(**h).last
+ Hash.ruby2_keywords_hash?(last).should == true
+ Hash.ruby2_keywords_hash?(h).should == false
- ruby2_keywords def foo(*args)
- args.last
- end
- end
+ last2 = mark(**last).last # last is already marked
+ Hash.ruby2_keywords_hash?(last2).should == true
+ Hash.ruby2_keywords_hash?(last).should == true
+ last2.should_not.equal?(last)
+ Hash.ruby2_keywords_hash?(h).should == false
+ end
- h = {a: 1}
- ruby_version_is "3.0" do
- obj.regular(**h).should.equal?(h)
+ it "makes a copy and unmark the Hash when calling a method taking (arg)" do
+ obj = Object.new
+ obj.singleton_class.class_exec do
+ def single(arg)
+ arg
end
+ end
- last = obj.foo(**h)
- Hash.ruby2_keywords_hash?(last).should == true
- Hash.ruby2_keywords_hash?(h).should == false
+ h = { a: 1 }
+ args = mark(**h)
+ marked = args.last
+ Hash.ruby2_keywords_hash?(marked).should == true
+
+ after_usage = obj.single(*args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should_not.equal?(marked)
+ Hash.ruby2_keywords_hash?(after_usage).should == false
+ Hash.ruby2_keywords_hash?(marked).should == true
+ end
- last2 = obj.foo(**last) # last is already marked
- Hash.ruby2_keywords_hash?(last2).should == true
- Hash.ruby2_keywords_hash?(last).should == true
- last2.should_not.equal?(last)
- Hash.ruby2_keywords_hash?(h).should == false
+ it "makes a copy and unmark the Hash when calling a method taking (**kw)" do
+ obj = Object.new
+ obj.singleton_class.class_exec do
+ def kwargs(**kw)
+ kw
+ end
end
- it "makes a copy and unmark at the call site when calling with marked *args" do
+ h = { a: 1 }
+ args = mark(**h)
+ marked = args.last
+ Hash.ruby2_keywords_hash?(marked).should == true
+
+ after_usage = obj.kwargs(*args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should_not.equal?(marked)
+ Hash.ruby2_keywords_hash?(after_usage).should == false
+ Hash.ruby2_keywords_hash?(marked).should == true
+ end
+
+ ruby_version_is "3.2" do
+ it "makes a copy and unmark the Hash when calling a method taking (*args)" do
obj = Object.new
obj.singleton_class.class_exec do
- ruby2_keywords def foo(*args)
- args
- end
-
- def single(arg)
- arg
+ def splat(*args)
+ args.last
end
- def splat(*args)
+ def splat1(arg, *args)
args.last
end
- def kwargs(**kw)
- kw
+ def proc_call(*args)
+ -> *a { a.last }.call(*args)
end
end
h = { a: 1 }
- args = obj.foo(**h)
+ args = mark(**h)
marked = args.last
Hash.ruby2_keywords_hash?(marked).should == true
- after_usage = obj.single(*args)
+ after_usage = obj.splat(*args)
after_usage.should == h
after_usage.should_not.equal?(h)
after_usage.should_not.equal?(marked)
Hash.ruby2_keywords_hash?(after_usage).should == false
Hash.ruby2_keywords_hash?(marked).should == true
- after_usage = obj.splat(*args)
+ args = mark(1, **h)
+ marked = args.last
+ after_usage = obj.splat1(*args)
after_usage.should == h
after_usage.should_not.equal?(h)
after_usage.should_not.equal?(marked)
- ruby_bug "#18625", ""..."3.3" do # might be fixed in 3.2
- Hash.ruby2_keywords_hash?(after_usage).should == false
- end
+ Hash.ruby2_keywords_hash?(after_usage).should == false
Hash.ruby2_keywords_hash?(marked).should == true
- after_usage = obj.kwargs(*args)
+ args = mark(**h)
+ marked = args.last
+ after_usage = obj.proc_call(*args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should_not.equal?(marked)
+ Hash.ruby2_keywords_hash?(after_usage).should == false
+ Hash.ruby2_keywords_hash?(marked).should == true
+
+ args = mark(**h)
+ marked = args.last
+ after_usage = obj.send(:splat, *args)
after_usage.should == h
after_usage.should_not.equal?(h)
after_usage.should_not.equal?(marked)
Hash.ruby2_keywords_hash?(after_usage).should == false
Hash.ruby2_keywords_hash?(marked).should == true
end
+ end
- it "applies to the underlying method and applies across aliasing" do
+ ruby_version_is ""..."3.2" do
+ # https://bugs.ruby-lang.org/issues/18625
+ it "does NOT copy the Hash when calling a method taking (*args)" do
obj = Object.new
-
obj.singleton_class.class_exec do
- def foo(*a) a.last end
- alias_method :bar, :foo
- ruby2_keywords :foo
+ def splat(*args)
+ args.last
+ end
- def baz(*a) a.last end
- ruby2_keywords :baz
- alias_method :bob, :baz
+ def splat1(arg, *args)
+ args.last
+ end
+
+ def proc_call(*args)
+ -> *a { a.last }.call(*args)
+ end
end
- last = obj.foo(1, 2, a: "a")
- Hash.ruby2_keywords_hash?(last).should == true
+ h = { a: 1 }
+ args = mark(**h)
+ marked = args.last
+ Hash.ruby2_keywords_hash?(marked).should == true
- last = obj.bar(1, 2, a: "a")
- Hash.ruby2_keywords_hash?(last).should == true
+ after_usage = obj.splat(*args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should.equal?(marked) # https://bugs.ruby-lang.org/issues/18625
+ Hash.ruby2_keywords_hash?(after_usage).should == true # https://bugs.ruby-lang.org/issues/18625
+ Hash.ruby2_keywords_hash?(marked).should == true
- last = obj.baz(1, 2, a: "a")
- Hash.ruby2_keywords_hash?(last).should == true
+ args = mark(1, **h)
+ marked = args.last
+ after_usage = obj.splat1(*args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should.equal?(marked) # https://bugs.ruby-lang.org/issues/18625
+ Hash.ruby2_keywords_hash?(after_usage).should == true # https://bugs.ruby-lang.org/issues/18625
+ Hash.ruby2_keywords_hash?(marked).should == true
- last = obj.bob(1, 2, a: "a")
- Hash.ruby2_keywords_hash?(last).should == true
+ args = mark(**h)
+ marked = args.last
+ after_usage = obj.proc_call(*args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should.equal?(marked) # https://bugs.ruby-lang.org/issues/18625
+ Hash.ruby2_keywords_hash?(after_usage).should == true # https://bugs.ruby-lang.org/issues/18625
+ Hash.ruby2_keywords_hash?(marked).should == true
+
+ args = mark(**h)
+ marked = args.last
+ after_usage = obj.send(:splat, *args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ send_copies = RUBY_ENGINE == "ruby" # inconsistent with Proc#call above for CRuby
+ after_usage.equal?(marked).should == !send_copies
+ Hash.ruby2_keywords_hash?(after_usage).should == !send_copies
+ Hash.ruby2_keywords_hash?(marked).should == true
end
+ end
- ruby_version_is "2.7" ... "3.0" do
- it "fixes delegation warnings when calling a method accepting keywords" do
- obj = Object.new
+ it "applies to the underlying method and applies across aliasing" do
+ obj = Object.new
- obj.singleton_class.class_exec do
- def foo(*a) bar(*a) end
- def bar(*a, **b) end
- end
+ obj.singleton_class.class_exec do
+ def foo(*a) a.last end
+ alias_method :bar, :foo
+ ruby2_keywords :foo
- -> { obj.foo(1, 2, {a: "a"}) }.should complain(/Using the last argument as keyword parameters is deprecated/)
+ def baz(*a) a.last end
+ ruby2_keywords :baz
+ alias_method :bob, :baz
+ end
- obj.singleton_class.class_exec do
- ruby2_keywords :foo
- end
+ last = obj.foo(1, 2, a: "a")
+ Hash.ruby2_keywords_hash?(last).should == true
- -> { obj.foo(1, 2, {a: "a"}) }.should_not complain
- end
- end
+ last = obj.bar(1, 2, a: "a")
+ Hash.ruby2_keywords_hash?(last).should == true
- it "returns nil" do
+ last = obj.baz(1, 2, a: "a")
+ Hash.ruby2_keywords_hash?(last).should == true
+
+ last = obj.bob(1, 2, a: "a")
+ Hash.ruby2_keywords_hash?(last).should == true
+ end
+
+ ruby_version_is ""..."3.0" do
+ it "fixes delegation warnings when calling a method accepting keywords" do
obj = Object.new
obj.singleton_class.class_exec do
- def foo(*a) end
+ def foo(*a) bar(*a) end
+ def bar(*a, **b) end
+ end
- ruby2_keywords(:foo).should == nil
+ -> { obj.foo(1, 2, {a: "a"}) }.should complain(/Using the last argument as keyword parameters is deprecated/)
+
+ obj.singleton_class.class_exec do
+ ruby2_keywords :foo
end
+
+ -> { obj.foo(1, 2, {a: "a"}) }.should_not complain
end
+ end
- it "raises NameError when passed not existing method name" do
- obj = Object.new
+ it "returns nil" do
+ obj = Object.new
- -> {
- obj.singleton_class.class_exec do
- ruby2_keywords :not_existing
- end
- }.should raise_error(NameError, /undefined method `not_existing'/)
+ obj.singleton_class.class_exec do
+ def foo(*a) end
+
+ ruby2_keywords(:foo).should == nil
end
+ end
- it "accepts String as well" do
- obj = Object.new
+ it "raises NameError when passed not existing method name" do
+ obj = Object.new
+ -> {
obj.singleton_class.class_exec do
- def foo(*a) a.last end
- ruby2_keywords "foo"
+ ruby2_keywords :not_existing
end
+ }.should raise_error(NameError, /undefined method `not_existing'/)
+ end
- last = obj.foo(1, 2, a: "a")
- Hash.ruby2_keywords_hash?(last).should == true
+ it "accepts String as well" do
+ obj = Object.new
+
+ obj.singleton_class.class_exec do
+ def foo(*a) a.last end
+ ruby2_keywords "foo"
end
- it "raises TypeError when passed not Symbol or String" do
- obj = Object.new
+ last = obj.foo(1, 2, a: "a")
+ Hash.ruby2_keywords_hash?(last).should == true
+ end
- -> {
- obj.singleton_class.class_exec do
- ruby2_keywords Object.new
- end
- }.should raise_error(TypeError, /is not a symbol nor a string/)
- end
+ it "raises TypeError when passed not Symbol or String" do
+ obj = Object.new
- it "prints warning when a method does not accept argument splat" do
- obj = Object.new
- def obj.foo(a, b, c) end
+ -> {
+ obj.singleton_class.class_exec do
+ ruby2_keywords Object.new
+ end
+ }.should raise_error(TypeError, /is not a symbol nor a string/)
+ end
- -> {
- obj.singleton_class.class_exec do
- ruby2_keywords :foo
- end
- }.should complain(/Skipping set of ruby2_keywords flag for/)
- end
+ it "prints warning when a method does not accept argument splat" do
+ obj = Object.new
+ def obj.foo(a, b, c) end
- it "prints warning when a method accepts keywords" do
- obj = Object.new
- def obj.foo(a:, b:) end
+ -> {
+ obj.singleton_class.class_exec do
+ ruby2_keywords :foo
+ end
+ }.should complain(/Skipping set of ruby2_keywords flag for/)
+ end
- -> {
- obj.singleton_class.class_exec do
- ruby2_keywords :foo
- end
- }.should complain(/Skipping set of ruby2_keywords flag for/)
- end
+ it "prints warning when a method accepts keywords" do
+ obj = Object.new
+ def obj.foo(a:, b:) end
- it "prints warning when a method accepts keyword splat" do
- obj = Object.new
- def obj.foo(**a) end
+ -> {
+ obj.singleton_class.class_exec do
+ ruby2_keywords :foo
+ end
+ }.should complain(/Skipping set of ruby2_keywords flag for/)
+ end
- -> {
- obj.singleton_class.class_exec do
- ruby2_keywords :foo
- end
- }.should complain(/Skipping set of ruby2_keywords flag for/)
- end
+ it "prints warning when a method accepts keyword splat" do
+ obj = Object.new
+ def obj.foo(**a) end
+
+ -> {
+ obj.singleton_class.class_exec do
+ ruby2_keywords :foo
+ end
+ }.should complain(/Skipping set of ruby2_keywords flag for/)
end
end