Search code examples
rubyruby-on-rails-4terminalthorcommand-line-tool

Ruby Script to Command Line Tool


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.


Solution

  • 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.