rakeファイルのメソッド共通化
DRYなコードを書く上で、共通化した処理をどこに書くかで結構悩むかと思います。
今回はrakeタスクを書いていて、別ファイルに逃がすまではしたくないけど、共通化したい場合があって調べてみたら同じ境遇の方がいたので備忘録として残しておきます。
namespace :hoge do
top_level = self
using Module.new {
refine(top_level.singleton_class) do
def fuga
p 'hogehoge'
end
end
}
desc 'test task'
task test_task: :environment do |task, args|
fuga
end
end
オブジェクトの確認
[1] pry(main)> top_level
=> main
[2] pry(main)> top_level.singleton_class
=> #<Class:#<Object:0x007fa9470be378>>
[3] pry(main)> top_level.class
=> Object
実行
$ bin/rails hoge:test_task
=> "hogehoge"
トップレベルでオブジェクトを生成すると、Object
クラスのmain
オブジェクトを生成する。
rubyにおけるトップレベル
refinements
引数 klass で指定したクラスだけに対して、ブロックで指定した機能を提供で きるモジュールを定義します。
定義した機能は Module#refine を使用せずに直 接 klass に対して変更を行う場合と異なり、限られた範囲のみ有効にできます。
定義した機能は main.using, Module#using を実行した場合のみ 有効になります。
ドキュメント
class C
def foo
puts "C#foo"
end
end
module M
refine C do
def foo
puts "C#foo in M"
end
end
end
x = C.new
x.foo # => "C#foo"
using M
x = C.new
x.foo # => "C#foo in M"
refine, using
便利だな〜
組み込みクラスとか拡張するときには、逆にこの機能を使わないと不安なレベルではあるかなと。(滅多にないとは思うが...)