8225


Rails内で使うRakeタスクに以下のようなものを使おうとしました。

[code]

    namespace :task1 do
      task :do_something => :environment do
        foo
      end
      def foo
        p "task1"
      end
    end
    
    namespace :task2 do
      task :do_something => :environment do
        foo
      end
      def foo
        p "task2"
      end
    end
    
[/code]

`namespace`で区切られているため`foo`メソッドは別のものとして解釈されると思っていたのですがオーバーライドされてしまいました。

特定のRakeタスク内からしか呼び出さないメソッドのスコープを限定するにはどうすればよいのでしょうか？

特に決まった方法がないのであれば`task1_foo`などのような命名規則を適用させようと考えています。


CC BY-SA 3.0
2015-03-22T01:02:13.223
8223
2017-10-17T09:12:59.887
2017-10-17T09:12:59.887
2599
3271
question
ruby ruby-on-rails rake
特定のRakeタスク内でのみ使うメソッドの定義方法


2011年の記事ですが、こちらに同じような質問が出てますね。

<https://stackoverflow.com/questions/6172292/scope-of-rakes-in-a-rails-
project>

基本的にこの問題を回避する方法はなく、設計で回避するように、みたいなことが書かれています。

rakeタスクはcontrollerのように薄く保ち、ライブラリのメソッドを呼び出すだけの設計にするのが良い、ということみたいです。


CC BY-SA 3.0
2015-03-22T02:51:56.597
8225
2015-03-22T02:51:56.597
2017-05-23T12:38:55.250
-1
85
8223
answer


rakeファイル内に定義したメソッドはトップレベルコンテキスト（=selfがmainオブジェクト）で定義されます。

ちょっと格好悪いですが、以下のようにmoduleで包んでincludeしてやれば、当該rakeからしか呼び出せなくなります。

[code]

    namespace :task1 do
      task :do_something => :environment do
        include Task1
        foo
      end
    end
    
    module Task1
      def foo
        p "task1"
      end
    end
    
[/code]

その他にも、外部ファイルにメソッドを定義してrequireするなど、やりようはあると思います。少なくとも、プロダクトコードと関係のないメソッドをモデル側に定義するのは、よろしくないと思います。


CC BY-SA 3.0
2015-05-05T05:20:52.933
9831
2015-05-05T05:20:52.933
9608
8223
answer


同じ問題を抱え、 qiita に記事を2つ書きましたが、  
<http://qiita.com/kuboon/items/26e90800856863c64cdc>  
<http://qiita.com/kuboon/items/dc5f30abee136abcd319>  
結論としては以下のようにしています。

[code]

    module Anonymous
      namespace :task1 do
        # ここで何を宣言しても安全
      end
    end
    self.class.send(:remove_const, :Anonymous)
    
[/code]


CC BY-SA 3.0
2015-11-11T04:40:31.083
18657
2015-11-11T04:40:31.083
65
8223
answer


Refinementsを使うとレキシカルスコープのメソッドを定義できます。

トップレベルのmainオブジェクトの`singleton_class`をrefineする無名モジュールを作り`using`するとそのファイルの中からしか呼び出せないメソッドが定義できます。

Rakeタスクごとにファイルを分割すると、特定のRakeタスクのファイル内でのみ使える同じ名前のメソッドを定義できます。

[code]

    # lib/tasks/task1.rake
    
    top_level = self
    
    using Module.new {
      refine(top_level.singleton_class) do
        def foo
          p "task1"
        end
      end
    }
    
    namespace :task1 do
      task :do_something => :environment do
        foo
      end
    end
    
[/code]

[code]

    # lib/tasks/task2.rake
    
    top_level = self
    
    using Module.new {
      refine(top_level.singleton_class) do
        def foo
          p "task2"
        end
      end
    }
    
    namespace :task2 do
      task :do_something => :environment do
        foo
      end
    end
    
[/code]

参考: <https://qiita.com/hanachin_/items/6cf63dd3987a60e3d264>


CC BY-SA 3.0
2017-10-17T09:12:07.627
38799
2017-10-17T09:12:07.627
2599
8223
answer