Rakefile task block arg not working - ruby

I have a task in my Rakefile
desc "Create a new person."
task :add_person, :name do |t, args|
sh "echo My name is #{args.name}"
end
When I do $ rake add_person john
I get:
echo My name is
My name is
rake aborted!
Don't know how to......
But I should get:
echo My name is john
My name is john
rake aborted!
Don't know how to......
What's going on?

Call it like this:
rake add_person[john]
or if you're using zsh:
rake add_person\[john\]
edit: response to comment about being able to call it like: rake add_person john
I think you have 2 options.
Use the environment variable method for passing args:
desc "Create a new person."
task :add_person do |t, args|
name = ENV.fetch('NAME')
sh "echo My name is #{name}"
end
then call like this:
$ rake add_person NAME=john
or, Hack using ARGV (not personally recommended):
desc "Create a new person."
task :add_person do
name = ARGV.last
sh "echo My name is #{name}"
# Task does nothing
task name.to_sym do ; end
end
then use like this:
$rake add_person john
personally I'd just use it as in intended though.

Update the task
task :add_person, [:name] => :environment do |_t, args|
puts "My name is #{args[:name]}"
end
and run
rake add_person['john']

Related

Make Thor show message for top level command

Is there any way to make Thor show a general message for the top level command?
$my_command help
I'd like to show a welcome message here.
Commands:
my_command help [COMMAND]
The closest thing I can think of is adding a default task and using it to invoke the help task. You'd get this message when calling $my_command with no arguments
require 'thor'
class MyCLI < Thor
desc "hello NAME", "say hello to NAME"
def hello(name)
puts "Hello #{name}"
end
desc "greeting", "this is just a greeting"
def greeting
puts "Welcome to MyCLI"
invoke :help
end
default_task :greeting
end
MyCLI.start(ARGV)
# $my_command
# output:
# Welcome to MyCLI
# Commands:
# test.rb greeting # this is just a greeting
# test.rb hello NAME # say hello to NAME
# test.rb help [COMMAND] # Describe available commands or one spec...

Command Aliasing in Thor

Is it possible to create aliases for commands in Thor?
Much like command aliasing in Commander. https://github.com/tj/commander#command-aliasing
I am able to find aliases for options, but not for the command itself.
Using the example from Thor,
#!/usr/bin/env ruby
require 'thor'
# cli.rb
class MyCLI < Thor
desc "hello NAME", "say hello to NAME"
def hello(name)
puts "Hello #{name}"
end
end
MyCLI.start(ARGV)
I should be able to run
$ ./cli.rb hello John
Hello John
I would like to alias the command "hello" to "hi" as well.
You can use map for this:
http://www.rubydoc.info/github/wycats/thor/master/Thor#map-class_method
#!/usr/bin/env ruby
require 'thor'
# cli.rb
class MyCLI < Thor
desc "hello NAME", "say hello to NAME"
def hello(name)
puts "Hello #{name}"
end
map hi: :hello
end
MyCLI.start(ARGV)
Use method_option for aliases.
#!/usr/bin/env ruby
require 'thor'
# cli.rb
class MyCLI < Thor
desc "hello NAME", "say hello to NAME"
method_option :hello , :aliases => "-hello" , :desc => "Hello Command"
def hello(name)
puts "Hello #{name}"
end
end
MyCLI.start(ARGV)

Clockwork recipe for Capistrano 3

I'm trying to write a Clockwork recipe for Capistrano 3. After having a look at Sidekiq's recipe I've come up with this:
namespace :load do
task :defaults do
set :clockwork_default_hooks, -> { true }
set :clockwork_pid, -> { 'tmp/pids/clockwork.pid' }
set :clockwork_log, -> { "#{current_path}/log/clockwork.log" }
set :clockwork_roles, -> { :app }
set :clockwork_config, -> { 'clock.rb' }
end
end
namespace :deploy do
before :starting, :check_clockwork_hooks do
invoke 'clockwork:add_default_hooks' if fetch(:clockwork_default_hooks)
end
end
namespace :clockwork do
def clockwork_pid_full_path
if fetch(:clockwork_pid).start_with?('/')
fetch(:clockwork_pid)
else
"#{current_path}/#{fetch(:clockwork_pid)}"
end
end
task :add_default_hooks do
after 'deploy:updated', 'clockwork:stop'
after 'deploy:reverted', 'clockwork:stop'
after 'deploy:published', 'clockwork:start'
end
desc 'Stop clockwork'
task :stop do
on roles fetch(:clockwork_roles) do
if test "[ -f #{clockwork_pid_full_path} ]"
within current_path do
execute "kill -int $(cat #{clockwork_pid_full_path}) 2>/dev/null"
end
else
execute "echo 'clockwork was not running'"
end
end
end
desc 'Start clockwork'
task :start do
on roles fetch(:clockwork_roles) do
within current_path do
with rails_env: fetch(:rails_env, 'production') do
execute "export RAILS_ENV=$RAILS_ENV"
execute :bundle, :exec, :clockwork, "#{fetch(:clockwork_config)} >> #{fetch(:clockwork_log)} 2>&1 &"
end
execute "ps -eo pid,command | grep clockwork | grep -v grep | awk '{print $1}' > #{clockwork_pid_full_path}"
end
end
end
desc 'Restart clockwork'
task :restart do
invoke 'clockwork:stop'
invoke 'clockwork:start'
end
end
However, the clockwork:start task only works if I remove the 2>&1 & part at the end. If I try to start the process in the background, nothing seems to happen.
What am I doing wrong?
This is what I ended up with. I adapted it from a Gist I found.
namespace :clockwork do
desc "Stop clockwork"
task :stop do
on roles(:app) do
within release_path do
with rails_env: fetch(:rails_env) do
execute :bundle, :exec, :clockworkd, "-c clock.rb --pid-dir=#{cw_pid_dir} --log-dir=#{cw_log_dir} --log stop"
end
end
end
end
desc "Clockwork status"
task :status do
on roles(:app) do
within release_path do
with rails_env: fetch(:rails_env) do
execute :bundle, :exec, :clockworkd, "-c clock.rb --pid-dir=#{cw_pid_dir} --log-dir=#{cw_log_dir} --log status"
end
end
end
end
desc "Start clockwork"
task :start do
on roles(:app) do
within release_path do
with rails_env: fetch(:rails_env) do
execute :bundle, :exec, :clockworkd, "-c clock.rb --pid-dir=#{cw_pid_dir} --log-dir=#{cw_log_dir} --log start"
end
end
end
end
desc "Restart clockwork"
task :restart do
on roles(:app) do
within release_path do
with rails_env: fetch(:rails_env) do
execute :bundle, :exec, :clockworkd, "-c clock.rb --pid-dir=#{cw_pid_dir} --log-dir=#{cw_log_dir} --log restart"
end
end
end
end
def cw_log_dir
"#{shared_path}/log"
end
def cw_pid_dir
"#{shared_path}/tmp/pids"
end
def rails_env
fetch(:rails_env, false) ? "RAILS_ENV=#{fetch(:rails_env)}" : ''
end
end
Try this gem capistrano-clockwork.
It's the most easy way that worked very well to me. I tried several options of 'gists' but no success.
You just need update this files Gemfile, Capifile and deploy.rb.
Gemfile:
gem 'daemons'
gem 'capistrano-clockwork', group: :development
Capfile:
require 'capistrano/clockwork'
deploy.rb:
set :clockwork_file, "lib/name_of_your_clockwork_config.rb"
Remember to execute bundle install before deploy ;)

How can I get "thor list" to list methods in ruby class

I have problems listing my tasks in thor, even with the simplest program:
class Mytest < Thor
desc "Hello world", "Puts 'hello world' on the console"
def hello
puts "Hello world"
end
end
Here is the console output when i run thor list
$ thor list
mytest
------
thor mytest:world # Puts 'hello world' on the console
As you can see the "hello" method name is omitted from the output. Can you help me out please?
Thank you,
Paul
Just change the 'desc' line to:
desc "hello", "Puts 'hello world' on the console"
Hope it helps.

Rake clean raise error when the file does not exist

I have a Rakefile like this
task :clean do
sh 'rm ./foo'
end
I want to prevent it from reporting error when the file 'foo' does not exist. How to do that?
I think what I want is: Is there a way to check the file first and then decide what to do next.
For example:
file 'aaa' => 'bbb' do
sh 'cp bbb aaa'
end
This task depends on the existence of file 'bbb', so I want to know can I tell Rake that my task depends on the non-existence of file 'foo' ?
You can do this by extending rake a bit:
Rakefile:
require File.join(File.dirname(__FILE__), 'unfile_rake_ext')
unfile 'target.txt' do
File.delete('target.txt')
end
unfile_rake_ext.rb:
class UnFileTask < Rake::FileTask
def needed?
File.exist?(name)
end
end
def unfile(*args, &block)
UnFileTask.define_task(*args, &block)
end
And my console output:
D:\Projects\ZPersonal\tmp>ls
Rakefile unfile_rake_ext.rb
D:\Projects\ZPersonal\tmp>touch target.txt && ls
Rakefile target.txt unfile_rake_ext.rb
D:\Projects\ZPersonal\tmp>rake target.txt --trace
** Invoke target.txt (first_time)
** Execute target.txt
D:\Projects\ZPersonal\tmp>ls
Rakefile unfile_rake_ext.rb
D:\Projects\ZPersonal\tmp>rake target.txt --trace
** Invoke target.txt (first_time, not_needed)
D:\Projects\ZPersonal\tmp>ls
Rakefile unfile_rake_ext.rb
Hope this helps.
In your rakefile:
task :clean do
rm 'foo' if File.exists? 'foo'
end
file 'aaa' => ['bbb', :clean] do |t|
cp t.prerequisites[0], t.name
end
Now at the command line:
echo 'test' > bbb
rake aaa
=> cp bbb aaa
touch foo
rake aaa
=> rm foo
=> cp bbb aaa
How about this?
if File.exists? './foo/'
sh 'rm -f ./foo'
end

Resources