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.
June 20, 2007 at 4:44 pm
[...] 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 [...]
November 21, 2007 at 12:00 pm
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’
{|file| file << template.result}
template = File.open( “./input_template.dat” ) { |file| ERB.new( file.read ) }
@title = “test’
@velocity = 0.5
File.open(”./output.dat”, “w”
December 30, 2007 at 7:26 pm
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.