Search code examples
rubycapistrano

Define custom methods for Capistrano?


I'm attempting to define custom methods for Capistrano, to be used within my cap tasks. I can define methods, and then use such methods within tasks just fine, until I attempt to call such methods from a namespaced task, as Capistrano then throws an exception.

Sample trace where custom command named capturecmd breaks Capistrano when called from a namespaced task file:replace. Works perfectly fine for any non-namespaced task:

#⚡ cap local file:replace -s dir=./jel-ids/ -s f=deploy -s r=deployed -s ext=.bak
  * 2013-02-13 13:34:08 executing `local'
  * 2013-02-13 13:34:08 executing `file:replace'
Capfile:129:in `capturecmd': uninitialized constant Capistrano::Configuration::Open3 (NameError)
    from /usr/local/opt/rbenv/versions/1.9.3-p385/lib/ruby/gems/1.9.1/gems/capistrano-2.14.2/lib/capistrano/configuration/namespaces.rb:191:in `method_missing'
    from Capfile:41:in `block (2 levels) in load'
    from /usr/local/opt/rbenv/versions/1.9.3-p385/lib/ruby/gems/1.9.1/gems/capistrano-2.14.2/lib/capistrano/configuration/execution.rb:138:in `instance_eval'
    from /usr/local/opt/rbenv/versions/1.9.3-p385/lib/ruby/gems/1.9.1/gems/capistrano-2.14.2/lib/capistrano/configuration/execution.rb:138:in `invoke_task_directly'
    from /usr/local/opt/rbenv/versions/1.9.3-p385/lib/ruby/gems/1.9.1/gems/capistrano-2.14.2/lib/capistrano/configuration/callbacks.rb:25:in `invoke_task_directly_with_callbacks'
    from /usr/local/opt/rbenv/versions/1.9.3-p385/lib/ruby/gems/1.9.1/gems/capistrano-2.14.2/lib/capistrano/configuration/execution.rb:89:in `execute_task'
    from /usr/local/opt/rbenv/versions/1.9.3-p385/lib/ruby/gems/1.9.1/gems/capistrano-2.14.2/lib/capistrano/configuration/execution.rb:101:in `find_and_execute_task'
    from /usr/local/opt/rbenv/versions/1.9.3-p385/lib/ruby/gems/1.9.1/gems/capistrano-2.14.2/lib/capistrano/cli/execute.rb:46:in `block in execute_requested_actions'
    from /usr/local/opt/rbenv/versions/1.9.3-p385/lib/ruby/gems/1.9.1/gems/capistrano-2.14.2/lib/capistrano/cli/execute.rb:45:in `each'
    from /usr/local/opt/rbenv/versions/1.9.3-p385/lib/ruby/gems/1.9.1/gems/capistrano-2.14.2/lib/capistrano/cli/execute.rb:45:in `execute_requested_actions'
    from /usr/local/opt/rbenv/versions/1.9.3-p385/lib/ruby/gems/1.9.1/gems/capistrano-2.14.2/lib/capistrano/cli/help.rb:19:in `execute_requested_actions_with_help'
    from /usr/local/opt/rbenv/versions/1.9.3-p385/lib/ruby/gems/1.9.1/gems/capistrano-2.14.2/lib/capistrano/cli/execute.rb:34:in `execute!'
    from /usr/local/opt/rbenv/versions/1.9.3-p385/lib/ruby/gems/1.9.1/gems/capistrano-2.14.2/lib/capistrano/cli/execute.rb:14:in `execute'
    from /usr/local/opt/rbenv/versions/1.9.3-p385/lib/ruby/gems/1.9.1/gems/capistrano-2.14.2/bin/cap:4:in `<top (required)>'
    from /usr/local/opt/rbenv/versions/1.9.3-p385/bin/cap:23:in `load'
    from /usr/local/opt/rbenv/versions/1.9.3-p385/bin/cap:23:in `<main>'

EDIT: Additionally, if anyone can suggest a proper structure for extending Capistrano, so that my custom methods could exist at the same level as the existing methods for run, capture, etc.


Solution

  • I've never needed it, but here is the deal. When you are in a Capfile, the self is a reference to an instance of Capistrano::Configuration. You can see it by using the following code in your Capfile:

    p self.class
    

    In the scope of self, you have access to the run method: p self.methods.grep :run will return:

    [:run]
    

    So, if you want a method in the same scope as run, you can do the definition in self:

    def self.my_method
      puts "let's go!"
    end
    

    Like I said, I don't know if this is the best way to do it, but this will work. Now you could have some namespaced task like this:

    namespace :borba do
      task :teste do
        my_method
      end
    end