Rakeタスク内でメソッド定義するとObjectのprivateメソッドとして定義されます。なので下のような書き方は一見namespace配下にメソッドを定義しているように見えますがObjectのメソッドとして定義されてしまっています。
def outside_method
puts 'outside method'
end
namespace :foo do
def inside_method
puts 'inside method'
end
desc "bar"
task :bar do
outside_method # "outside_method"
inside_method # "inside_method"
puts method(:outside_method).owner # => Object
puts method(:inside_method).owner # => Object
end
end
Rakeは各タスクの定義ファイルをKernel.loadしていて、namespaceはインスタンス変数の@scopeに名前空間を設定しつつ、与えられたブロックを普通にyieldしています↓
module Rake
module TaskManager
# ...
def in_namespace(name)
name ||= generate_name
@scope = Scope.new(name, @scope)
ns = NameSpace.new(self, @scope)
yield(ns)
ns
ensure
@scope = @scope.tail
end
なので、block内のメソッド定義はnamespace外のメソッド定義と同じです。
同様にCapistranoもRake::Applicationクラスを継承して作られているので、namespace内で記述されたメソッドはObjectのメソッドとして定義されます。
ちなみにrspecのdescribeのブロックは動的に作成されるクラスのmodule_execメソッドの引数として渡されるので、そのクラスのメソッドを定義していることになります。なのでObjectのメソッド定義になりません。
module RSpec
module Core
class ExampleGroup
def self.define_example_group_method(name, metadata={})
idempotently_define_singleton_method(name) do |*args, &example_group_block|
# ...
subclass(self, description, args, registration_collection, &example_group_block)
# ...
end
RSpec::Core::DSL.expose_example_group_alias(name)
end
def self.subclass(parent, description, args, registration_collection, &example_group_block)
subclass = Class.new(parent)
subclass.set_it_up(description, args, registration_collection, &example_group_block)
subclass.module_exec(&example_group_block) if example_group_block
MemoizedHelpers.define_helpers_on(subclass)
subclass
end