Skip to content

Add specs for the it variable in blocks #1224

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
7 changes: 7 additions & 0 deletions core/proc/parameters_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,11 @@
it "returns :nokey for **nil parameter" do
proc { |**nil| }.parameters.should == [[:nokey]]
end

ruby_version_is "3.4" do
it "handles the usage of `it` as a paramater" do
eval("proc { it }").parameters.should == [[:opt, nil]]
eval("lambda { it }").parameters.should == [[:req]]
end
end
end
64 changes: 62 additions & 2 deletions language/block_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1049,6 +1049,12 @@ def all_kwrest(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, **
}.should complain(/warning: `it` calls without arguments will refer to the first block param in Ruby 3.4; use it\(\) or self.it/)
end

it "emits a deprecation warning if numbered parameters are used" do
-> {
eval "proc { it; _1 }"
}.should complain(/warning: `it` calls without arguments will refer to the first block param in Ruby 3.4; use it\(\) or self.it/)
end

it "does not emit a deprecation warning when a block has parameters" do
-> { eval "proc { |a, b| it }" }.should_not complain
-> { eval "proc { |*rest| it }" }.should_not complain
Expand All @@ -1058,21 +1064,75 @@ def all_kwrest(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, **
-> { eval "proc { |**| it }" }.should_not complain
-> { eval "proc { |&block| it }" }.should_not complain
-> { eval "proc { |&| it }" }.should_not complain
-> { eval "proc { || it }" }.should_not complain
end

it "does not emit a deprecation warning when `it` calls with arguments" do
-> { eval "proc { it(42) }" }.should_not complain
-> { eval "proc { it 42 }" }.should_not complain
end

it "does not emit a deprecation warning when `it` calls with a block" do
-> { eval "proc { it {} }" }.should_not complain
end

it "does not emit a deprecation warning when a local variable inside the block named `it` exists" do
-> { eval "proc { it = 42; it }" }.should_not complain
end

it "does not emit a deprecation warning when `it` calls with explicit empty arguments list" do
-> { eval "proc { it() }" }.should_not complain
end

it "calls the method `it` if defined" do
o = Object.new
def o.it
21
end
suppress_warning do
o.instance_eval("proc { it * 2 }").call(1).should == 42
end
end
end

ruby_version_is "3.4" do
it "does not emit a deprecation warning" do
-> {
eval "proc { it }"
}.should_not complain
end

it "acts as the first argument if no local variables exist" do
eval("proc { it * 2 }").call(5).should == 10
end

Copy link
Member

Choose a reason for hiding this comment

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

As for me it might be useful to add tests cases similar to what we have in the 3.3...3.4 section:

  • it "does not emit a deprecation warning when a local variable inside the block named it exists" do
  • it "calls the method it if defined" do
  • and probably it "does not emit a deprecation warning when a block has parameters" do

it "can be reassigned to act as a local variable" do
eval("proc { tmp = it; it = tmp * 2; it }").call(21).should == 42
end

it "can be used in nested calls" do
eval("proc { it.map { it * 2 } }").call([1, 2, 3]).should == [2, 4, 6]
end
Copy link
Member

Choose a reason for hiding this comment

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

In this test it isn't clear whether a block for the map call has its own it variable or it refers the the it variable of the outer scope (a block for the proc call)


it "cannot be mixed with numbered parameters" do
-> {
eval "proc { it + _1 }"
}.should raise_error(SyntaxError, /numbered parameters are not allowed when 'it' is already used|'it' is already used in/)
Copy link
Member

@eregon eregon May 29, 2025

Choose a reason for hiding this comment

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

How does this spec pass given https://bugs.ruby-lang.org/issues/21381 and the fact we have a CI job using parse.y?
In general it's probably best to just accept either message.


-> {
eval "proc { _1 + it }"
}.should raise_error(SyntaxError, /numbered parameter is already used in|`it` is not allowed when a numbered parameter is already used/)
end
end
end

describe "if `it` is defined outside of a block" do
it "treats `it` as a captured variable" do
describe "if `it` is defined as a variable" do
it "treats `it` as a captured variable if defined outside of a block" do
it = 5
proc { it }.call(0).should == 5
end

it "treats `it` as a local variable if defined inside of a block" do
proc { it = 5; it }.call(0).should == 5
end
end