Section 14.10. Conclusion


14.9. Miscellaneous Scripting Tasks

There are a few tidbits left over. These are uncreatively classified as "miscellaneous."

14.9.1. Single-File Ruby Solutions

There are occasions where you may want a quick or temporary Ruby installation. You might even want to distribute Ruby along with your program as a single executable.

We've already looked at Ruby Installer, the "one-click installer" for Windows platforms. There are plans (immature at the time of this writing) to make Linux and Mac OSX versions of the installer.

Erik Veenstra has also made significant progress in packaging Ruby itself as well as Ruby applications. He is the author of AllInOneRuby, Tar2RubyScript, and RubyScript2Exe (all of which can be found on his site at http://www.erikveen.dds.nl).

AllInOneRuby is a single-file Ruby installation. It packages all of the Ruby interpreter, core, and standard libraries in a single archive that is easy to move or copyit can be stored on a USB drive, for example, so that you can carry an entire Ruby installation in your pocket and "install" it on a new machine in a fraction of a second. It runs on Windows or Linux and has experimental support for Mac OSX.

Tar2RubyScript is exactly what the name implies. It takes a directory structure containing your application and creates a self-extracting program (consisting of a Ruby program with a tar archive appended). This is similar to Java's concept of a JAR file. The script to be run should be named init.rb; if the stored item is a library rather than a standalone application, this file can be omitted.

RubyScript2Exe is perhaps slightly misnamed. It does indeed transform an entire Ruby application into a single binary file, but it is cross-platform, running on Windows, Linux, or Mac OSX. You can think of it as a "compiler," but of course it isn't a real one. It collects files from your Ruby installation to produce the package, so there is no need (or possibility) of cross-compiling. Be aware that the executable you get is "stripped" in the sense that any unneeded Ruby libaries are left out.

If you use Tar2RubyScript, the archive created is runnable on any system that has Ruby (and the application's dependencies) installed. RubyScript2Exe doesn't have this limitation because it includes (along with your application) the entire Ruby interpreter and runtime environment and all dependencies. You can use these two tools together or separately.

14.9.2. Piping into the Ruby Interpreter

Because the Ruby interpreter is a single-pass translator, it is possible to pipe code into it and have it executed. One conceivable purpose for this is to use Ruby for more complex tasks when you are required by circumstance to work in a traditional scripting language such as bash.

Listing 14.6, for example, is a bash script that uses Ruby (via a here-document) to calculate the elapsed time in seconds between two dates. The Ruby program prints a single value to standard output, which is then captured by the ksh script.

Listing 14.6. bash Script Invoking Ruby

#!/usr/bin/bash # Let bash find the difference in seconds # between two dates using Ruby... export time1="2007-04-02 15:56:12" export time2="2007-12-08 12:03:19" cat <<EOF | ruby | read elapsed require "parsedate" time1 = ENV["time1"] time2 = ENV["time2"] args1 = ParseDate.parsedate(time1) args2 = ParseDate.parsedate(time2) args1 = args1[0..5] args2 = args2[0..5] t1 = Time.local(*args1) t2 = Time.local(*args2) diff = t2 - t1 puts diff EOF echo "Elapsed seconds = " $elapsed

Note that the two input values in this case are passed as environment variables (which must be exported). The two lines that retrieve these values could also be coded in this way:

time1="$time1"  # Embed the shell variable directly time2="$time2"  #   into a string...


However, the difficulties are obvious. It could get very confusing whether a certain string represents a ksh variable or a Ruby global variable, and there could be a host of problems with quoting and escaping.

It's also possible to use a Ruby "one-liner" with the -e option. Here's a little script that reverses a string using Ruby:

#!/usr/bin/bash string="Francis Bacon" ruby -e "puts '$string'.reverse" | read reversed #  $reversed now has value "nocaB sicnarF"


UNIX geeks will note that awk has been used in a similar way since time immemorial.

14.9.3. Getting and Setting Exit Codes

The exit method will raise a SystemExit exception and ultimately return the specified exit code to the operating system (or to the calling entity). This is a Kernel method. There is also a method exit! that differs in two ways: It doesn't run the exit handlers before quitting, and the default return value is -1.

# ... if (all_OK)   exit      # Normally (0) else   exit!     # In a hurry (-1) end


When a Ruby return code is retrieved by the operating system (for example, by doing echo $?), it is seen as the same integer specified in the code. When a subprocess exits and we use wait2 (or waitpid2) to examine the return code, we will find it left-shifted by eight bits. This is a POSIX quirk that Ruby has inherited.

child = fork { sleep 1; exit 3 } pid, code = Process.wait2         # [12554,768] status = code << 8                # 3


14.9.4. Testing Whether a Program Is Running Interactively

A good way to determine whether a program is interactive is to test its standard input. The method isatty? (historically, "is a teletype") will tell us whether the device is an interactive one as opposed to a disk file or socket. (This is not available on Windows.)

if STDIN.isatty?   puts "Hi! I see you're typing at"   puts "the keyboard." else   puts "Input is not from a keyboard." End


14.9.5. Determining the Current Platform or Operating System

If a program wants to know what operating system it's running on, it can access the global constant RUBY_PLATFORM. This will return a cryptic string (usually something like i386-cygwin or sparc-solaris2.7), telling the platform on which the Ruby interpreter was built.

Because we primarily use UNIX variants (Solaris, AIX, Linux) and Windows variants (98, NT, 2000, XP), we've found the following crude piece of code to be useful. It will distinguish between the UNIX family and the Windows family of operating systems (unceremoniously lumping all others into "other").

def os_family   case RUBY_PLATFORM     when /ix/i, /ux/i, /gnu/i,          /sysv/i, /solaris/i,          /sunos/i, /bsd/i       "unix"     when /win/i, /ming/i       "windows"     else       "other"   end end


This little set of regular expressions will correctly classify the vast majority of platforms. Of course, this is only a clumsy way of determining how to handle OS dependencies. Even if you correctly determine the OS family, that might not always imply the availability (or absence) of any specific feature.

14.9.6. Using the Etc Module

The Etc module retrieves useful information from the /etc/passwd and /etc/group files. Obviously this is only useful in a UNIX environment.

The getlogin method will return the login name of the user. If it fails, getpwuid might work (taking an optional parameter, which is the uid).

myself = getlogin             # hal9000 myname = getpwuid(2001).name  # hal9000 # Without a parameter, getpwuid calls # getuid internally... me2 = getpwuid.name           # hal9000


The getpwnam method returns a passwd struct, which contains relevant entries such as name, dir (home directory), shell (login shell), and others.

   rootshell = getpwnam("root").shell   # /sbin/sh


At the group level, getgrgid or getgrnam behave similarly. They will return a group struct consisting of group name, group passwd, and so on.

The iterator passwd will iterate over all entries in the /etc/passwd file. Each entry passed into the block is a passwd struct.

all_users = [] passwd { |entry| all_users << entry.name }


There is an analogous iterator group for group entries.




The Ruby Way(c) Solutions and Techniques in Ruby Programming
The Ruby Way, Second Edition: Solutions and Techniques in Ruby Programming (2nd Edition)
ISBN: 0672328844
EAN: 2147483647
Year: 2004
Pages: 269
Authors: Hal Fulton

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net