Ruby as a Glue Language ======================= (March 2016) ## Get command line arguments ## first_arg = ARGV[0] second_arg = ARGV[1] final_arg = ARGV[-1] ARGV[0] is not the name of the script. The full path to the current script is in $0. Get the script name only with 'File.basename($0)'. ## Reading a file line by line by line ## File.foreach('/path/to/my/file') do |line| puts line end ## Slurp in an entire (not too large) file at once ## puts File.read('/path/to/my/file') ## Check if a file exists ## File.exists?('/path/to/my/file') ## Write to a file ## f = File.new('/path/to/my/file', 'w') f.puts('The rain in Spain stays mainly in the plain.') f.close (...or, more idiomatically:) File.open('/path/to/my/file', 'w') do |f| f.write('The rain in Spain stays mainly in the plain.') end (Appending works as above, but with 'a' instead of 'w'. 'w+' opens the file for both reading and writing.) ## Recurse through directory tree ## Dir['/path/to/recurse'].each do |f| puts f end # ... or, using find: require 'find' Find.find('/path/to/recurse') do |f| # print file and path to screen if filename ends in .txt puts f if f.match(/\.txt/) end ## All text files in a directory non-recursively ## Dir.glob('/path/to/files/*.txt').each do |f| puts f end ## Print to STDERR ## STDERR.puts "DANGER, Will Robinson!" ## Escape a string for the shell ## require 'shellwords' Shellwords.escape("All the king's horses & all the king's men") ...which is equivalent to: require 'shellwords' "All the king's horses & all the king's men".shellescape ## Run a shell command (system) ## system 'echo "Hello, $USER"' puts $? # $? is the return value; 0 for OK, non-zero for error. ## Get output of a shell command (backticks) ## now = `date` put $?.success? # true or false put $?.to_i (%x{date} is the same, but allows an alternate delimeter to backticks.) ## Hook up to the shell's standard handles (popen3) ## require 'open3' cmd = 'dc' stdin, stdout, stderr = Open3.popen3(cmd) stdin.puts(2) stdin.puts(2) stdin.puts('+') stdin.puts('p') stdout.gets stdin.puts('asdf') stderr.gets stdin.puts('p') stdin.puts('q') ## Spawn a new process, and don't wait for it to exit ## pid = spawn('tar xf foo.tar') Process.wait pid (Use "Process.wait" or "Process.detatch" to avoid zomblie children.) ## Fork a Copy and Communicate via Unix Sockets ## (Forks share all existing objects, including sockets created before the fork.) require 'socket' parent_socket, child_socket = UNIXSocket.pair fork do parent_socket.close child_socket.send("Sent from child (#{$$})", 0) from_parent = child_socket.recv(100) puts from_parent end child_socket.close parent_socket.send("Sent from parent (#{$$}), 0) from_child = parent_socket.recv(100) puts from_child ## Read from and Write to a Unix Named Pipe (FIFO) ## % mkfifo /tmp/my_pipe (Our writing process:) w_pipe = open('/tmp/my_pipe', 'w+') # w+ doesn't block (?) w_pipe.puts 'A very important message!' w_pipe.flush (Our reading process:) r_pipe = open('/tmp/my_pipe', 'r+') puts r_pipe.gets # Blocks if the pipe is empty! ## Web serve the current directory ## % ruby -run -e httpd -- -p 8000 . ## Web serve a simple message ## require 'socket' httpd = TCPServer.new('localhost', 8000) while (session = httpd.accept) msg = (`date` + "\nHello, world.") session.print("HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: #{msg.bytesize}\r\n" + "Connection: close\r\n") session.print("\r\n" + msg + "\r\n") session.close end ## Die! ## Write to STDERR and exit with non-zero status using "abort": abort 'Fatal error: lock file exists!' if File.exists?(lock_file) ## Regular Expressions ## if (my_string =~ /^Jan\s+(\d+).*/) puts $1 end my_matches = /in\s+(\w+)\s+falls/.match('The rain in Japan falls mainly...') place = my_matches[1] # ["in Japan falls", "Japan"] puts place # "Japan". MY_RE = Regexp.new('\wlue') # Omit /slashes/! puts 'We found a clue in the parlor!'.scan MY_RE # "clue" if ('glue the vase back together'.match MY_RE) puts "Found glue." end ## Links ## - http://ruby-doc.org/