Turns out Ruby is great for scripting!

Earlier last year, I gave myself two challenges:

  • write automation scripts in Ruby (instead of giving up on writing them in shell)
  • use system debugging tools (strace, lsof, gdb, etc.) more often to figure out why programs are behaving some way

Of course, I was almost immediately stymied on the second one:

[code lang=text] sudo dtruss -t write ruby -e "puts 'hi!'" Password:

dtrace: failed to execute ruby: dtrace cannot control executables signed with restricted entitlements [/code]

dtruss is the dtrace-powered macOS-equivalent of strace. It is very cool when it works. But. It turns out Apple has a thing that protects users from code injection hijinks, which makes dtrace not work. You can turn it off but that requires hijinks of its own.

I did end up troubleshooting some production problems via strace and lsof. That was fun, very educational, and slightly helpful. Would do again.

I did not end up using gdb to poke inside any Ruby programs. On the whole, this is probably for the better.

I was more successful in using Ruby as a gasp scripting language. I gave myself some principles for writing Ruby automation:

  • only use core/standard library; no gem requires, no bundles, etc.
  • thus, shell out to programs likely to be available, e.g. curl
  • if a script starts to get involved, add subcommands
  • don’t worry about Ruby’s (weird-to-me) flags for emulating sed and awk; stick to the IRB-friendly stuff I’m used to

These were good principles.

At first I tried writing Ruby scripts as command suites via sub. sub is a really cool idea, very easy to start with, makes discovery of functionality easy for others, and Just Works. You should try it some time!

That said, often I didn’t need anything fancy. Just run a few commands. Sometimes I even wrote those with bash!

But if I needed to do something less straightforward, I used template like this:

[code lang=text] #!/usr/bin/env ruby

HELP = <<-HELP test # Run the test suite test ci # Run test with CI options enabled test acceptance # Run acceptance tests (grab a coffee….) HELP

module Test module_function

def test rspec spec end

… more methods for each subcommand


if __FILE == $0 cmd = ARGV.first

case cmd when "ci" Test.ci

… a block for each subcommand

else Test.test end end [/code]

This was a good, friction-eliminating starting skeleton.

The template I settled on eliminated the friction of starting something new. I’d write down the subcommands or workflow I imagined I needed and get started. I wrote several scripts, delete or consolidated a few of them after a while, and still use a few of them daily.

If you’re using a “scripting” language to build apps and have never tried using it to “script” things I “recommend” you try it!

Adam Keys @therealadam