0

I am trying to make a command line tool. I already have a ruby script (one file). But I want to project it as a normal command line command.

Right now I have to go into the directory where the script is and type ruby script.rb for it to function but i want to make a command such as script [option] from directory and it should process the required option in the script.

Do I need to make an independent ruby gem for this? I have read about some gems like thor and commander but I am not able to use them properly.

How can I make this command line tool?

PS: An example can be the twitter gem and a command line tool 't' which is also a gem.

  • Why don't you show us a minimal example of your code. That would make it a lot easier for us to show you how it works, rather than expect us to guess what you've done. Ruby is a general programming language, which makes it very easy to write CLI scripts. – the Tin Man Jul 13 '14 at 01:56

3 Answers3

2

Ruby, because it's a general-programming language, makes it easy to create command-line scripts. Here's a basic script you can build upon:

#!/usr/bin/env ruby

require 'optparse'

args = {}
OptionParser.new do |opt|
  opt.on('-i', '--input FILE', 'File to read') { |o| args[:file_in] = o }
  opt.on('-o', '--output FILE', 'File to write') { |o| args[:file_out] = o }
end.parse!

abort "Missing input or output file" unless (args[:file_in] && args[:file_out])

File.write(args[:file_out], File.read(args[:file_in]))

Here's what's happening:

  • #!/usr/bin/env ruby is commonly called a "bang line". The shell will look for this line at the top of a file to determine what application can read the file and execute/interpret it. env is an application that will look through the user's PATH environment variable and return the first Ruby found as the Ruby to execute the script. Using this makes the script work with Rubies in the normal /usr/bin, /usr/local/bin or when managed by rbenv or RVM.
  • require 'opt parse' pulls in Ruby's command-line parser class OptionParser, which makes it easy to set up traditional flags, such as -i path/to/file/to/read, -o path/to/file/to/write, or long parameters, like --input or --output. It also automatically supplies the -h and --help flags to return formatted help text for the script. OptionParser is a bit of a learning-curve, so play with the complete example and you'll figure it out.

The rest should be pretty self-explanatory.

Traditionally, executables that are installed by the system go in /usr/bin. Executables we write, or add, go in /usr/local/bin, and I highly recommend sticking with that.

Some OSes don't automatically supply an entry for /usr/local/bin in the PATH, so you might need to modify your PATH setting in your ~/.bashrc, ~/.bash_profile or ~/.profile to allow the shell to locate the script.

Executable scripts need to have their executable flag set: chmod +x /path/to/executable is the basic command. See man chmod for more information.

I tend to leave the script's extension in place; Ruby scripts are "foo.rb", Python are "bar.py", etc. I do that because I prefer to have that extension as a hint of the language it's written in, but YMMV. The extension isn't necessary so go with what works for you.

Beyond all that, you might want to provide logging output, or output to the system's syslog. In the first case use Ruby's built-in Logger class, or the Syslog class in the second case.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
2

Actually there's two great gems for command line apps in Ruby.

First is methadone which is for simpler command line apps.

Another is gli which is for apps with multiple commands, for example something like bundler.

If you want to know more, you can check out book about creating command line apps build awesome command-line apps in ruby by author of these gems.

0

You do not need to make it a gem, the following suffices:

  • Change its name from script.rb to script
  • Add #!/usr/bin/env ruby as the first line of script
  • Put it somewhere in PATH (e.g. $HOME/bin, making sure it is in PATH), or execute by giving path explicitly, e.g. $HOME/myscriptdir/script
Amadan
  • 191,408
  • 23
  • 240
  • 301
  • It's not necessary to change the name of a script by removing its extension. The extension has no bearing on whether a script works at the command-line. – the Tin Man Jul 13 '14 at 01:57
  • @theTinMan: Of course. But it would have to be invoked as `script.rb`, not as `script` as OP wrote. – Amadan Jul 13 '14 at 02:53