Command line script that runs a method only when it is executed? - ruby

I am building a gem for command line use, and I am aware of the if __FILE__ == $0 method for determining whether the file being run is the current file (from Run code only if script called from the command line), however this doesn't work in my case. I have a module with an initialize function that I would like to run when the gem is called from the command line.
module MyApp
def self.initialize
# do command line stuff
end
def self.test
# run a rake test
end
end
MyApp::initialize
However, when running rake test it calls the initialize function which returns an error:
/Library/WebServer/Documents/myapp ❤ rake test
Options:
-v, --[no-]verbose Run verbosely
-h, --help Show this message
rake aborted!
Command failed with status (255): [ruby -I"lib" -I"/Users/bbriggs/.rvm/gems/ruby-2.0.0-p195/gems/rake-10.1.0/lib" "/Users/bbriggs/.rvm/gems/ruby-2.0.0-p195/gems/rake-10.1.0/lib/rake/rake_test_loader.rb" "test/test_myapp.rb" ]
/Users/bbriggs/.rvm/gems/ruby-2.0.0-p195/bin/ruby_noexec_wrapper:14:in `eval'
/Users/bbriggs/.rvm/gems/ruby-2.0.0-p195/bin/ruby_noexec_wrapper:14:in `<main>'
Tasks: TOP => test
(See full trace by running task with --trace)
I think this is because I am doing MyApp:initialize, because if I take that out of my code the rake test runs as expected, but the command line tool no longer works.
At the moment I am testing my app via bundle exec bin/myapp, and printing out the __FILE__ and $0 variables give me bin/myapp and path/to/lib/myapp.rb respectively, so I was wondering what the best way is to detect whether the module is being required or called directly. Am I even doing this right? I'm a bit of a Ruby newbie. :-)

Finally figured this out. Instead of running MyApp:initialize in lib/myapp.rb I put it in the bin/myapp file. This ensures that it is only run when the app is run from the command line and not when being tested via Rake or required by another script.

Related

How to store rake task call result in shell?

I am newbie in Ruby, Rake and shell script. Here I created one simple task in Rake which parse YAML file and returns its response.
Following is the task in my Rakefile. It works fine and puts prints the yaml value on console.
task :test, [:env] do |t, args|
db_settings = YAML::load(File.open("test.yml"))["#{args[:env]}"]
puts db_settings
end
Following is the result of the task.
{"url"=>"http://test.com", "end"=>"test"}
["test[local]"]
But when I want to call this task from shell script then it didn't return response to script.
not sure ruby not able to send response or script itself doing something wrong.
Following is shell script that I am using to call this rake task.
res= rake test[local]
echo $res
How can I get this parsed yaml from rake task to shell script?
Second question is, will this script be able to use this Parsed yaml. Rake task returns env specific json structure to script and the script supposed to get the element using key.
Can someone help on this to? is the current approach to use Yaml on script.

How can I automate a script [Ruby] to run at a given time every day?

I've written a webcrawler that pulls information into a report and would like to run it every day at 12:00pm. The script is run using:
ruby script.rb
I've tried using the whenever gem (https://github.com/javan/whenever).
My directory structure is this:
/config
schedule.rb
script.rb
In my script.rb file, I have the following:
every :day, :at => '12:00pm' do
command "ruby script.rb"
end
I've modified the time :at to take see if it runs and it doesn't.
I've also tried:
every :day, :at => '12:00pm' do
`ruby script.rb`
end
I've also looked into the "at" linux utility but it appears suited to one-time jobs. I'd like this to generate a report everyday.
Note: the script specifies where to output so I don't need to give it an output.
I've also tried creating a crontab but have encountered a problem with saving.
I use http://crontab-generator.org/ to generate the correct syntax.
Then I run:
crontab -e
Which opens vi and I copy the syntax. However, it exits with a status of 1 and if I run:
crontab -l
It says there's no jobs listed.
I've also tried running this as the super user, and it exits the same.
The error message is
/usr/bin/vi" exited with status 1
I just want a command to run at a given time, what am I missing?
Edit
Does it matter that I'm on a Mac?

How do I configure ruby to enter the debugger on Ctrl-C (SIGINT)?

I'd like to enter the debugger upon typing ctrl-C (or sending a SIGINT). I have installed the debugger (I'm running Ruby 1.9.3) and verified that it works. I've added this to my setup files (this is for Padrino, but I assume it would be similar for Rails):
# file: config/boot.rb
Padrino.before_load do
trap("SIGINT") { debugger } if Padrino.env == :development
end
... but typing Ctrl-C does not invoke the debugger. In fact, if I replace debugger with puts "saw an interrupt!", typing Ctrl-C doesn't cause a print to happen either.
update
Following this suggestion from Mike Dunlavey, I tried explicitly calling catch Interrupt from within the debugger:
$ rdebug `which padrino` console
^Z^Z$HOME/usr/bin/padrino:9
require 'rubygems'
(rdb:1) catch Interrupt
Catch exception Interrupt.
(rdb:1) c
=> Loading development console (Padrino v.0.10.7)
=> Loading Application BlueDotAe
=> Loading Application Admin
irb(main):001:0> C-c C-c^C
irb(main):001:0>
No joy -- interrupt did not enter the debugger.
What am I missing?
If you want to trap SIGINT while running in the console, the short answer is: you cannot unless you monkey-patch IRB. Every Ruby app (whether padrino, or rails or whatnot) that uses the console will end up calling usr/lib/ruby/1.9.1/irb.rb, and in IRB.start, it does:
trap("SIGINT") do
irb.signal_handle
end
... just before entering the main loop. This will override any trap("SIGINT") you might have put in your startup code.
But if you want to trap SIGINT in a script file (for example, if you want to profile your code as described by Mike Dunlavey here), you can create a script file such as:
# File: profile_complex_operation.rb
trap("SIGINT") { debugger }
MyApp.complex_operation
and then invoke it as in:
$ ruby profile_complex_operation.rb
Now, when you hit ^C (or send SIGINT from another process), it will enter the debugger.
You may try to use GDB wrapper for Ruby (GitHub).
Install on Linux via:
sudo apt-get install gdb python-dev ncurses-dev ruby-rvm
gem install gdb.rb
Basic usage:
require 'gdb'
# create a new GDB::Ruby instance and attach it to
# pid 12345
gdb = GDB::Ruby.new(12345)
# print the (ruby) backtrace of the remote process
gdb.backtrace.each { |line| puts line }
# show the current local variables, and their values
p gdb.local_variables
# evaluate arbitrary ruby code in the remote process
p gdb.eval('%(pid #{$$})')
# show how many instances of each class exist in the
# remote process
p gdb.object_space
# raise an exception in the remote process
gdb.raise Exception, "go boom!"
# close the connection to the remote process
gdb.quit
Or to debug the hung process, attach it via:
rvmsudo gdb.rb PID
then:
# in gdb get a ruby stacktrace with file names and line numbers
# here I'm filtering by files that are actually in my app dir
(gdb) ruby eval caller.select{|l| l =~ /app\//}
Source: Using gdb to inspect a hung ruby process
Some alternatives:
rbtrace - like strace, but for ruby code (usage: rbtrace -p <PID> --firehose).
debug.rb script by tmm1 (author of gdb.rb) which can help to debug a process using strace/gdb.
See also:
Debugging Ruby Tools
Check why ruby script hangs

How to print to stdout from system command in Rake?

I have the following Rakefile
desc "Runs tests"
namespace :test do
task :api do
`mocha`
end
end
When I run the command rake test:api, I don't get the nice output of dots that I would if I just ran the command mocha.
How do I print the output of a command real-time in a rake task?
You can just put the output:
puts `mocha`
The backticks ` are calling the command mocha and return the output of the command.
You may also use %x{}:
puts %x{mocha}
Or you use system:
system('mocha')
Or you store the output for later use in a variable:
output = `mocha`
puts output

Why can't i run rake -f?

I really have no idea what im doing. I'm trying to get rake to work so I can run rake workers:start but without having to have the working directory be the same as the folder of the rake file.
for example if i'm in my app directory, the above command works fine, but if i run rake -f ~/Code/my-app/Rakefile workers:start it says "Cannot load such file -- ./database
I'm using Sinatra (rack), and ultimately my goal is to try and install god so I can create a resque worker in production
require File.dirname(__FILE__) + "/main"
require 'resque/tasks'
namespace :workers do
desc "Launch single worker for processing jobs"
task :start do
ENV['QUEUE'] ||= '*'
puts "=== Launching single worker on '#{ENV['QUEUE']}' queue(s) with PID #{Process.pid}"
Rake::Task['resque:work'].invoke
end
end
rake -f ~/Code/my-app/Rakefile rake:workers:start
^ shouldn't need this one.
Also you might want to cd to appropriate dir before running rake.
cd ~/Code/my-app && rake workers:start

Resources