Templator – Ruby Template System

Most simulation software is based on a text input file. Mostly I’m doing molecular dynamics simulation using LAMMPS. One input file from the samples is the following

# 3d Lennard-Jones melt

units       lj
atom_style  atomic

lattice     fcc 0.8442
region      box block 0 20 0 20 0 20
create_box  1 box
create_atoms    1
mass        1 1.0

velocity    all create 3.0 87287

pair_style  lj/cut 2.5
pair_coeff  1 1 1.0 1.0 2.5

neighbor    0.3 bin
neigh_modify    every 20 delay 0 check no

fix     1 all nve

dump        id all atom 10 dump.melt

thermo      50
run     250

So the input file has the setup of where the atoms go, what the temperature is, what type of simulation you are doing, where the output files record and what the filenames are. If you are doing a sweep of some parameter over a large range it is a bit annoying to have to make a bunch of copies of the file, tweak them, and keep everything in sync. I usually like to have the output files have the major parameter in the filename and it is very easy to get these out of sync with the actual parameter.

I started looking for a simple template system with Ruby, where I could specify a template file, and then somehow loop over a range of numbers and replace specific parts.

So, what I wanted was something to take a template file like this…

regular text with <% title %> embedded
inside that I want to try to replace
and variable p equals <% velocity %>
along with another <%title %> tag, since
thats the point. And another <% title%> for
good measure.

and pass it to a function, along with an option hash, and have it return this…

regular text with test.0.5 embedded
inside that I want to try to replace
and variable p equals 0.5
along with another test.0.5 tag, since
thats the point. And another test.0.5 for
good measure.

I wrote up some code to take care of this. The base code I came up with is this…

class Templator
  def Templator.generate(template, options)
    #template is text string of the template file
    #options is a hash of things to replace

    #currently not checking they match up

    tag_regex = /<%s*w+_*w*s*%>/
    hits = template.scan(tag_regex)
    tags = hits.map {|item| item.chomp('%>').reverse.chomp('%<').reverse.strip}
    tags.map! {|a| a.intern}
    tags.uniq!

    tags.inject(template) {|ntext,tag|
        ntext.gsub(Templator.symbol_to_tag_regex(tag),
        options[tag].to_s)}
  end

  def Templator.symbol_to_tag_regex(tag_name)
    Regexp.new('<%s*' + tag_name.to_s + 's*%>')
  end
end

This design is one that is going to be called from Ruby code, and not from the command line. I designed this to be extremely flexible, and easy to automate for, say, a hundred files or so. All you have to do is read in the template file, build the options hash, and pass the two to the Templator#generate method. Here is the driver code I used.

require 'templator'

template = File.open('template.txt') {|f| f.read}

0.5.step(1.5, 1.0) do |x|
  opt = {:title => "test." + x.to_s, :velocity => x}
  newtext = Templator.generate(template, opt)
  filename = "test-file-" + x.to_s
  File.open(filename,'w') {|f| f.print newtext }
end

There are certainly more options for different purposes, but this one did what I wanted. Feel free to use this code if you’re in a similar situation, or if there is something you think it should do that it doesn’t, let me know and I’ll take a look at it.

Advertisements

3 Responses to Templator – Ruby Template System

  1. […] the text in an editor and tweak things this way. I can also markup the text and run it through a template engine and generate a whole bunch of files. This was part of the magic behind my rake example, where I […]

  2. Chris says:

    I did something similar to this to generate input files for a FORTRAN program I was using. I used ‘erb’ though, it’s the template system used by default in rails :

    require ‘erb’
    template = File.open( “./input_template.dat” ) { |file| ERB.new( file.read ) }
    @title = “test’
    @velocity = 0.5
    File.open(“./output.dat”, “w”) {|file| file << template.result}

  3. Jim says:

    You could have a look into Jack Herrington’s (quite cool) article in Freshmeat,
    http://freshmeat.net/articles/view/447/
    Probably some ideas will pop up how to simplify your code.

    I really appreciate you sharing the code. Currently wanting to deploy my own (grin:) templating system and hence every example comes handy.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: