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 したメソッドを使うことができます。