#!/usr/bin/env ruby require 'ostruct' require 'optparse' require 'tilt' usage = < Process template and write output to stdout. With no or when is '-', read template from stdin and use the --type option to determine the template's type. Options -l, --list List template engines + file patterns and exit -t, --type= Use this template engine; required if no -y, --layout= Use as a layout template -D= Define variable as -d, --define-file= Load YAML from and use for variables --vars= Evaluate to Hash and use for variables -h, --help Show this help message Convert markdown to HTML: $ tilt foo.markdown > foo.html Process ERB template: $ echo "Answer: <%= 2 + 2 %>" | tilt -t erb Answer: 4 Define variables: $ echo "Answer: <%= 2 + n %>" | tilt -t erb --vars="{:n=>40}" Answer: 42 $ echo "Answer: <%= 2 + n.to_i %>" | tilt -t erb -Dn=40 Answer: 42 USAGE script_name = File.basename($0) pattern = nil layout = nil locals = {} ARGV.options do |o| o.program_name = script_name # list all available template engines o.on("-l", "--list") do groups = {} Tilt.lazy_map.each do |pattern,engines| engines.each do |engine| key = engine[0].split('::').last.sub(/Template$/, '') (groups[key] ||= []) << pattern end end groups.sort { |(k1,v1),(k2,v2)| k1 <=> k2 }.each do |engine,files| printf "%-15s %s\n", engine, files.sort.join(', ') end exit end # the template type / pattern o.on("-t", "--type=PATTERN", String) do |val| abort "unknown template type: #{val}" if Tilt[val].nil? pattern = val end # pass template output into the specified layout template o.on("-y", "--layout=FILE", String) do |file| paths = [file, "~/.tilt/#{file}", "/etc/tilt/#{file}"] layout = paths. map { |p| File.expand_path(p) }. find { |p| File.exist?(p) } abort "no such layout: #{file}" if layout.nil? end # define a local variable o.on("-D", "--define=PAIR", String) do |pair| key, value = pair.split(/[=:]/, 2) locals[key.to_sym] = value end # define local variables from YAML or JSON o.on("-d", "--define-file=FILE", String) do |file| require 'yaml' abort "no such define file: #{file}" unless File.exist? file hash = File.open(file, 'r:bom|utf-8') { |f| YAML.load f, file } abort "vars must be a Hash, not #{hash.inspect}" if !hash.is_a?(Hash) hash.each { |key, value| locals[key.to_sym] = value } end # define local variables using a Ruby hash o.on("--vars=RUBY") do |ruby| hash = eval(ruby) abort "vars must be a Hash, not #{hash.inspect}" if !hash.is_a?(Hash) hash.each { |key, value| locals[key.to_sym] = value } end o.on_tail("-h", "--help") { puts usage; exit } o.parse! end file = ARGV.first || '-' pattern = file if pattern.nil? abort "template type not given. see: #{$0} --help" if ['-', ''].include?(pattern) engine = Tilt[pattern] abort "template engine not found for: #{pattern}" if engine.nil? template = engine.new(file) { if file == '-' $stdin.read else File.read(file) end } output = template.render(self, locals) # process layout output = Tilt.new(layout).render(self, locals) { output } if layout $stdout.write(output)