Run a Ruby library from the command-line - ruby

I've just learned the basics of Ruby after being very happy with Python for several years (I'm still using Python for some things), but I'd like to know if there's an idiom or hack to solve this particular problem.
I have a Ruby script which I'd like to be able to do require script_name with, but I'd also like to be able to run ruby script_name.rb from the terminal and have it run as a command line script. In Python this would be done by having the following structure at the bottom of the script:
if __name__ == '__main__':
# do something here
However, I can't seem to find an equivalent in Ruby. Is there a way of detecting whether or not the current script is being run from the command-line? Maybe some Kernel:: method or something? Ideally what I'd like is something like this at the bottom of the script:
if from_command_line?
# do something here
end

You want to use:
if __FILE__ == $0
# do stuff
end
__FILE__ is the source file name and $0 is the name of the script currently being executed.

You can find a similar functionality in ruby.
__FILE__ the current source file name.
$0 Contains the name of the script being executed. May be assignable.
source: Ruby Quick Ref

While
if __FILE__ == $0
Foo.run
end
is the common approach, I'm currently using
if File.identical?(__FILE__, $0)
Foo.run
end
because programs like ruby-prof can make $0 not equal __FILE__ even when you use --replace-progname.

Related

how to build wrapper script

Sort of an odd question, but: how would one go about creating a wrapper shell script that can be used in the #! line in other scripts.
wrap.sh
#!/bin/bash
set -e
echo "wrapper!"
exec ruby "$#"
test.rb
#!/usr/bin/env wrap.sh
puts RUBY_VERSION
puts "the ducks come from the trucks"
wrap.sh is in the path, and test.rb is marked as executable.
Now I do:
./test.rb
wrapper!
ruby: no Ruby script found in input (LoadError)
The goal is to execute the ruby script via the wrapper (The ruby version can be either local or comes from a traveling ruby install that is shipped along with the app).
As far as I can tell ruby is invoked, it's just unhappy with the #! in the test.rb and refuses to run the script. I cannot remove the #! because that's how the script is executed in the first place.
Any workarounds for this?
So, I cannot use rbenv/rvm/etc. There is more logic in the wrapper than this, but this is the gist of it.
Looks to me like the arguments are not being passed to Ruby in "$#". I don't think the bang-hash line is the problem.
I don't see anything in your script which actually passes the contents of test.rb to wrapper.sh, which is the bigger issue.
Perhaps the real problem can be solved by some other means? For example, is the problem you're trying to solve to run arbitrary commands prior to the invocation of any Ruby script from the command line? Perhaps it can be approached that way...
It looks like Ruby just checks that the hash-bang line contains "ruby": https://github.com/ruby/ruby/blob/v2_2_2/ruby.c#L1580 So basically having ruby somewhere in the #! line is all it takes.

Ruby - How to use -r switch with ruby command line tool

I was trying to figure out how to work the command line switch -r.
My understanding is that the code is typed out as follows:
ruby -r*nameOfRequired*
I am finding that this is not the case. When I type out the above and press enter, the terminal expects an "end of input syntax" and does not continue.
What am I missing? Does there need to be a space in between the switch and the name of the required file?
Please and thank you!
EDIT:
I am currently reading "The Well Grounded Rubyist" by David A. Black, and I came up with this question while reading the section on command line switches.
Having said that, I created a "test.rb" file, containing:
puts Date.today
Then, in the terminal, I typed out:
ruby -r date
I thought this would 'require' the date module, and then enable me to run the "test.rb" file, using ruby test.rb (given that I am in the correct directory).
Instead, the terminal cursor moves to a newline, expecting more input. Let me know if I need to clarify anything else. Thanks!
If you just type ruby -rmodule, then Ruby will load the module and wait for you to type the main program that requires that module.
If you just want to run the module and do nothing else, you can do do rubyfull-path-to-module without the -r, or ruby -rmodule -e exit, or ruby -rmodule </dev/null, or similar.
In general, the ruby command does not record any state from one run to the next, so you need to tell it every thing that it needs to know whenever you run it.
Whenever you run it, you need to tell it the main program to run or else it will expect you to type that program on the standard input. The -r does not specify the main program.
Try this:
ruby -rdate test.rb
According to ruby -h:
-rlibrary require the library, before executing your script
Without giving your script file path, it read the script from stdin.
Try following (You can omit script file path when you give -e command):
ruby -r**nameOfRequired** -e ""

Ruby run shell command in a specific directory

I know how to run a shell command in Ruby like:
%x[#{cmd}]
But, how do I specify a directory to run this command?
Is there a similar way of shelling out, similar to subprocess.Popen in Python:
subprocess.Popen(r'c:\mytool\tool.exe', cwd=r'd:\test\local')
Thanks!
You can use the block-version of Dir.chdir. Inside the block you are in the requested directory, after the Block you are still in the previous directory:
Dir.chdir('mydir'){
%x[#{cmd}]
}
Ruby 1.9.3 (blocking call):
require 'open3'
Open3.popen3("pwd", :chdir=>"/") {|i,o,e,t|
p o.read.chomp #=> "/"
}
Dir.pwd #=> "/home/abe"
also, taking the shell route
%x[cd #{dir} && #{cmd}]
The closest I see to backtricks with safe changing dir is capture2:
require 'open3'
output, status = Open3.capture2('pwd', :chdir=>"/tmp")
You can see other useful Open3 methods in ruby docs. One drawback is that jruby support for open3 is rather broken.
Maybe it's not the best solution, but try to use Dir.pwd to get the current directory and save it somewhere. After that use Dir.chdir( destination ), where destination is a directory where you want to run your command from. After running the command use Dir.chdir again, using previously saved directory to restore it.
I had this same problem and solved it by putting both commands in back ticks and separating with '&&':
`cd \desired\directory && command`

Issue One command and Run Multiple Ruby Files

I have to run a whole bunch of ruby scripts to generate some results. In which order does not matter. I just don't want to do Ruby file1.rb, Ruby file2.rb, Ruby file3.rb...one by one.
Could I write a script that group all files together and issue command only once to run them all?
I would do it ruby-style and use rake gem.
I would create file named "rakefile.rb" and this would be its content:
task :default do
FileList['file*.rb'].each { |file| ruby file }
end
Then I would call rake in my favourite shell and I would enjoy it.
Bonus: It's multiplatform.
Assuming you are using bash and all the ruby files you want to run are in the current directory you could do:
for file in `ls ./*.rb`; do
ruby $file
done
Have runall.rb contain:
(1..3).each do |i|
`ruby file#{i}.rb`
end
and call ruby runall.rb.
You could make a sh script called startruby.sh that looks like this (this example doesn't work):
ruby ruby1.rb;
ruby ruby2.rb;
etc.
And then run
sh startruby.sh
And it will lauch all the ruby script after each other.
Offcourse you can also make it more advanced with a for loop and such, but this is the easiest/quickest way.
Depends on what you want, but if you want all the files loaded together, maybe something like ...
ruby -I. -e "ARGV.each {|f| load f}" file*.rb

How to create subcommands for Ruby programs?

I am writing a Ruby CLI (Command Line Interface) program and I would like to be able to call subcommands similar to what rails does when you call rails generate ... or rails server etc. Can anyone point me in the right direction on how to do this?
You just need to get the command line arguments and work with those. They are stored in the global array ARGV:
ARGV.each do|a|
puts "Argv: #{a}"
end
That prints out the arguments sent to the ruby script
The standard library's OptionParser class exists specifically for handling command-line arguments like this. Here's a tutorial. It should simplify your work considerably.

Resources