Rocky Mountain Ruby 2012

Ruby on the Command Line

Ruby on the Command Line

by Simon Chiang

The video titled "Ruby on the Command Line" by Simon Chiang, presented at the Rocky Mountain Ruby 2012 event, explores how to effectively use Ruby within a command-line context, creating a polished shell script that integrates seamlessly with existing command-line utilities.

The speaker begins by addressing the misconception that Ruby is only usable through its interpreter and emphasizes the importance of creating user-friendly command-line tools. The presentation progresses through several key points, including:

  • Creating a Basic Script: Demonstrating how to write a simple script that reads and prints file contents in binary format using sprintf. The initial script is basic, but serves as a foundation for further enhancements.
  • Adding Command-Line Options: Discussing the enhancement of user interaction by implementing command-line options using an option processor. This allows the script to accept flags, such as -b for binary output, thereby making the tool more versatile.
  • Improving User Experience: Explaining how to make the script more intuitive by removing the .rb extension, making it executable, and using a shebang line. This change enables users to run the script without needing to prepend the command with ruby.
  • Error Handling: Introducing Ruby's error handling capabilities with the use of begin and rescue blocks. This change improves the way error messages are displayed, providing users with cleaner feedback when issues arise, instead of verbose stack traces.
  • Handling Standard Input and Special Cases: Showing how to accommodate standard input using a dash and addressing scenarios such as empty arguments or handling interrupts gracefully. The speaker also notes how to manage errors related to closed pipes.
  • Making the Script Globally Accessible: Advising viewers on how to add the script to the system's PATH so that it can be executed from anywhere, further enhancing its usability.
  • Documentation: Finally, the presentation covers the importance of including manual pages (man command) for scripts, allowing users to easily access documentation and usage instructions.

Throughout the video, Simon provides practical examples, illustrating each point with working code snippets and relating each step back to user experience on the command line. In conclusion, he encourages viewers to explore the code provided via links and suggests looking into the TS project for those interested in testing shell scripts. The overall message underscores the significance of developing command-line tools that behave predictably and offer user-friendly interaction, ultimately making Ruby more accessible in command-line contexts.

00:00:04.560 Okay, everybody. I’m going to talk a little bit about putting Ruby onto the command line. You may think, 'Well, that's a silly talk to give because Ruby's already on the command line; you can just call ruby.' But what I want to discuss is really making a very nice shell script that looks like it belongs on the command line and behaves like other command line utilities, like cat.
00:00:14.400 So step zero would be to start writing something. Here, I’m writing a little script that will open up a file. It's going to read each byte and reprint it as if it were binary, and that's what sprint f does. If I were to run this, you can see that it now prints out in ones and zeros. The dollar signs are on there because a new line is not printed; we are just printing ones and zeros.
00:00:33.520 Once you have a simple algorithm like that, the next thing you might want to do is to add options to it. Here, I’m using an option processor to add options and usage information so that you can provide help. It also allows you to loop through ARGV to provide all the file names as command line arguments. You'll notice it still has the same basic algorithm.
00:00:45.439 Now, what this allows you to do is, by passing the -b flag, indicate that you want binary output. It will then read the abc.txt file and the xyz.txt file, printing out their binary representations. To make this a little clearer, I won’t add the -b flag for the remainder of the discussion. Instead, I will just call it and print out the contents, which is essentially the same output as cat would provide for abc and xyz.
00:01:04.960 The next step is to enhance the script's appearance on the command line. This means removing the .rb extension from the file, making the file executable, and adding a shebang line at the top of the file. The shebang line allows your system to look up Ruby and execute it for you, which eliminates the need to type 'ruby' in front of the script when you run it. I’ve made the script executable and now I can use sprint f2 to print out abc and xyz.
00:01:38.640 Next, we need to handle errors gracefully. If I run sprint f2 and attempt to read a missing file, I would normally get a big stack trace revealing all of my contents. Instead of that, I’ll add a `begin` block at the top, followed by a `rescue` block at the end. Now, instead of printing a stack trace, I will just display an error message and exit with status 1, unless debugging.
00:02:05.440 With this change, the error message is much cleaner. If you ever want to restore debugging, you can do so by using ruby -d, which will give you all the stack trace information needed for development. Otherwise, the script will simply show the error message.
00:02:34.000 There are also some other handy features we can add. For example, handling standard input with a dash is a Unix convention. This allows you to specify where you want to read from standard input or other files. In this case, I will read from abc using the dash to indicate standard input, and then do the same for xyz. As you can see, abc and xyz are printed out correctly.
00:03:03.120 To implement this, I’ll check for a dash in ARGV and handle it appropriately. The next step involves ensuring that if ARGV is empty, a dash is added by default. Additionally, if you have a long-running input, like the command yes, you may want to handle interrupts gracefully. Ctrl+C should be able to rescue the interrupt and return 130, which is a standard behavior.
00:03:31.360 You may also want to handle the case where a pipe is closed while your script is running. If you were piping input into Ruby and the stream closes, you would encounter an EPIPE error. To prevent an ugly error message, you can rescue this type of error and exit gracefully with status 0.
00:04:10.560 Another important step is adding your script to the PATH. This way, you won't need to prepend ./ when calling it. By exporting the PATH variable, you make your executable accessible from anywhere in the terminal.
00:04:29.680 The last step is to add manual pages for your script. This enables users to access documentation by using the `man` command. Initially, you may not see your command in the manual pages unless it’s added to the PATH. However, if you successfully add it, you will be able to invoke `man sprint f` to view the manual for your script.
00:05:18.080 In summary, you will find that I have included links to my code on Gist for further exploration. If you are looking into testing shell scripts, you might want to check out the TS project I have been working on. Thank you for your attention.