はじめに
it がブロックの中で呼び出せるけど RSpec で使えるの?
はい、使えます。RSpec でよく見る it '...' {}
はメソッドです。Ruby 3.4 でブロック内で使えるようになった it
はメソッド it
とはそれぞれ干渉しません。
describe 'Iterate' do
describe "doubles" do
it "doubles each element of the array" do
doubles = [1, 2, 3, 4, 5].map { it * 2 }
expect(doubles).to eq [2, 4, 6, 8, 10]
end
end
end
RSpec のコミュニティの反応は?
RSpec コミュニティからのコメントもありメソッド it
との競合が起きるのでは?と議論が交わされていました。全てを理解しているわけではないのですが、RSpec の it
は引数ありで呼び出しているため、ブロック内の it
と区別することができるので問題ない認識です。ただ、
With the specification in my proposal, existing code seems to break if and only if you call a method #it without an argument. But it seems pretty rare (reminder: a block given to an RSpec test case is also an argument). It almost feels like people are too afraid of compatibility problems that barely exist or have not really thought about options to address them.
cf. https://bugs.ruby-lang.org/issues/18980
issue にもある通り、メソッド it
を引数なしで呼び出したときに問題が起きそうです。検証してみたのですが正しく RSpec のメソッド it
を認識していました
require "debug"
describe 'Iterate' do
describe "doubles" do
binding.break
end
end
❯ bundle exec rspec spec/sample_spec.rb
[1, 7] in ~/Development/private/itruby/spec/sample_spec.rb
1| require "debug"
2|
3| describe 'Iterate' do
4| describe "doubles" do
=> 5| binding.break
6| end
7| end
=>#0 block in <top (required)> (2 levels) at ~/Development/private/itruby/spec/sample_spec.rb:5
#1 [C] Module#module_exec at ~/Development/private/itruby/vendor/bundle/ruby/3.4.0/gems/rspec-core-3.13.2/lib/rspec/core/example_group.rb:398
# and 36 frames (use `bt' command for all frames)
(ruby) m = method(:it)
#<Method: RSpec::ExampleGroups::Iterate::Doubles(RSpec::Core::ExampleGroup).it(*all_args, &block) /Users/guppy0356/Development/private/itruby/vendor/bundle/ruby/3.4.0/gems/rspec-core-3.13.2/lib/rspec/core/example_group.rb:146>
(ruby) m.owner
#<Class:RSpec::Core::ExampleGroup>
(rdbg)
他に面白い話題は?
ローカル変数 it
あがるとローカル変数を優先します。ブロックの中で変数を参照したときブロック外にローカル変数があればそれを参照するのはごく自然なように見えます。RSpec の中でローカル変数 it
を使うことはないと思いますが
describe 'Iterate' do
describe "doubles" do
it "doubles each element of the array" do
it = 10
doubles = [1, 2, 3, 4, 5].map { it * 2 }
expect(doubles).to eq [2, 4, 6, 8, 10]
end
end
end
Failures:
1) Iterate doubles doubles each element of the array
Failure/Error: expect(doubles).to eq [2, 4, 6, 8, 10]
expected: [2, 4, 6, 8, 10]
got: [20, 20, 20, 20, 20]
(compared using ==)
# ./spec/sample_spec.rb:8:in 'block (3 levels) in <top (required)>'
ブロック引数がある場合は it
を参照することは出来ず Syntax Error となります。
describe 'Iterate' do
describe "doubles" do
it "doubles each element of the array" do
doubles = [1, 2, 3, 4, 5].map { |item| p it }
expect(doubles).to eq [2, 4, 6, 8, 10]
end
end
end
Failure/Error: __send__(method, file)
SyntaxError:
--> /Users/guppy0356/Development/private/itruby/spec/sample_spec.rb
`it` is not allowed when an ordinary parameter is defined
3 describe 'Iterate' do
4 describe "doubles" do
5 it "doubles each element of the array" do
> 6 doubles = [1, 2, 3, 4, 5].map { |item| p it }
> 7 expect(doubles).to eq [2, 4, 6, 8, 10]
8 end
9 end
10 end