Rake タスクが複雑になりかけていたので、分割してモジュールに収めることにした。
環境
- Rake 10.5.0
- Ruby 2.2.3
失敗例
とりあえず、タスク定義をそのまま特異メソッドの中に移してみる。
module TaskHelper
def self.add_default()
task :default do
puts "ok"
end
end
end
TaskHelper.add_default
しかしこれはエラー。
$ rake
rake aborted!
NoMethodError: undefined method `task' for TaskHelper:Module
なぜ
探してみると Rake の DSL 定義は lib/rake/rake/dsl_definition.rb の最下部にあった。
lib/rake/dsl_definition.rb
module Rake
module DSL
...
def task(*args, &block)
Rake::Task.define_task(*args, &block)
end
...
end
end
self.extend Rake::DSL
一番外側の self に extend している。先ほどのエラーは、モジュール内モジュールが、モジュール名を付けずに外側のメソッドを使えないのと同じ理由だろうか。
task
等の機能はグローバルな関数として定義されているものだと思い込んでいた。
def task(*args, &block)
Rake::Task.define_task(*args, &block)
end
module TaskHelper
def self.add_default()
task :default do
puts "ok"
end
end
end
TaskHelper.add_default
これだと動く。
ただし、現実の定義は違う。
解決策
仕組みがわかれば簡単。
Rake の機能を使いたいモジュールやクラスに Rake::DSL を取り込めばいい。
module TaskHelper
extend Rake::DSL
def self.add_default()
task :default do
puts "ok"
end
end
end
TaskHelper.add_default
$ rake
ok
特異メソッドではなくインスタンスのメソッドとして使う場合は include を使用する。