A typical Ruby project includes a handful of utility scripts for various administrative tasks or setup. These scripts usually start with a shebang followed by a couple lines of Ruby code. Eventually the script begins to grow in complexity, filling with duplicated logic and repeating structures.
At this point I usually extract some methods. But for any script of a certain complexity, a problem emerges. The core of the script is in the root scope, so any functions it depends on must be declared first. This pushes the body of the script downward, obscuring the purpose of the script. Plus, usually functions depend on other functions, which are typically declared lower down, further confusing the order of the script.
One way out of this is to wrap the body in its own function, called run
or main
and move it
back to the top of the script. However, this function must be called , which is easy to miss or
forget. Luckily, Ruby has a helpful hook that can be used to fix this situation. Instead of
declaring the body of the script as a function, I can wrap it in a block passed to at_exit
,
which ensures the script is run. e.g.
#!/usr/bin/env ruby
at_exit do
params = parse_args
greet(params[:name])
end
def parse_args(args = ARGV)
{ name: args.shift || 'world' }
end
def greet(name)
puts "Hello, #{name}!"
end
Now the script reads clearly from top to bottom and has a simple flow for breaking out complex
logic into functions. As a final tweak, for projects with several scripts like this, I can
alias at_exit
to a function called main
, which lives in utils/autorun.rb
and is a little
more obvious to anyone else reading it.