1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ruby|it がブロックの中で呼び出せるけど RSpec で使えるの?

Posted at

はじめに

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 を認識していました :thinking:

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 を使うことはないと思いますが :rolling_eyes:

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
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?