Simple string interpolation

Safe and straightforward markup, for renaming files.

It's often useful for a script to allow the specification of how an output file is named, e.g. myscript.rb -o file.out. At the same time, it would be nice to have the output name based on the an input file name, and have easy and consistent naming over multiple files. So, what we need is some sort of string markup or template pattern that the user can use to specify how names are produced or transformed. But this markup should be simple (not a fully-blown language) and safe (because we are executing input from users). below is a simple script that interpolates and substitutes markup in strings that is delimited by curly braces, e.g. myfile{time}.txt. Several sample substitutions are supplied, it would be easy to create others. Some examples:

% ruby demo-iinterp.rb "foo.{ext}" bar.txt
'bar.txt' would be renamed as 'foo.txt' ...

% ruby demo-iinterp.rb "foo.{ext}" bar.txt
'bar.txt' would be renamed as 'foo.txt' ...

% ruby demo-iinterp.rb "foo.{ext}" bar.txt
'bar.txt' would be renamed as 'foo.txt' ...

% ruby demo-iinterp.rb "{base}.2" bar.txt
'bar.txt' would be renamed as 'bar.txt.2' ...

% ruby demo-iinterp.rb "{root}.2.{date}.{ext}" bar.txt
'bar.txt' would be renamed as 'bar.2.2010-05-27.txt' ...

The script:

#!/usr/bin/env ruby
# Show how files would be renamed according to a "template" string,
# demonstrating how a "safe" and simple template can be defined on
# the commandline. Call as:
#
# demo-interp.rb template infile1 [infile2 ...]

require 'date'
require 'time'
require 'pp'

def interpolate (str, sub_hash)
        return str.gsub(/{([^}]+)}/) { |m| sub_hash[$1] }
end

tmpl_str = ARGV[0]
infiles = ARGV.slice (1, ARGV.size())
infiles.each { |f|
        ext = File.extname(f)
        subs = {
                "ext"=> ext[1, ext.length],
                "base" => File.basename(f),
                "root" => File.basename(f, ext),
                "date" => Date.today.to_s(),
                "time" => Time.now.strftime(fmt='%T'),
                "datetime" => DateTime.now.strftime (fmt='%F T%T'),
        }
        out_name = interpolate(tmpl_str, subs)
        print "'#{f}' would be renamed as '#{out_name}' ... "
}