Ruby

RSpec.configure の extend 、 include はどうなっているのか

More than 5 years have passed since last update.

RSpec で

module M1

def hoge
p 'hoge'
end
end

module M2
def fuga
p 'fuga'
end
end

RSpec.configure do |c|
c.extend M1
c.include M2
end

describe 'test' do
hoge

it do
fuga
end
end

のように extend で DSL を、 include で example 内で使えるメソッドを追加することができます。

これをどのようにして実現しているのか調べてみました。


RSpec::Core::Configuration#extend 、 include

RSpec.configure のブロック引数である c は RSpec::Core::Configuraion のインスタンスです。

ここで呼び出している extend は、RSpec::Core::Configuraion でオーバーライドしてあります。

Object#extend ではないです。

RSpec::Core::Configuration#extend、include によって extend や include するべきモジュールが登録されます。


extend 、 include 先のクラス

describe もしくは context を呼び出すと、RSpec::Core::ExampleGroup を継承したクラスを作成します。

クラスを作る際に、そのクラスに RSpec::Core::Configuration#extend、include で登録したモジュールが extend 、 include されます。


実行

DSL 部分の解釈は describe 時に作ったクラスに module_eval しているので extend したメソッドを使うことができます。

example 部分の実行は describe 時に作ったクラスのインスタンスに instance_eval しているので include したメソッドを使うことができます。