読者です 読者をやめる 読者になる 読者になる

ファイル保存時に ERb でコンパイルして保存

ちょっと CSS で変数が使えたらなぁ、などと思うことが多々あります。そんなとき、適当なテンプレートエンジン使って CSS 記述しちゃえば!とか思うのですが、わざわざそんなことするまでもないし、と思いとどまってそれ以上何かすることはありませんでした。
CSS に限って云えば、Lucky bag::blog: CSS の値に変数を使用する の方法でサーバサイドで生成したり、その他アプローチで動的、静的に生成など、様々な手法があると云えます。
ちょっと話は変わって ERb。皆さんご存じの方も多いと思われる、ruby 1.8 標準添付のテンプレートエンジンです。ERb を使ってテンプレートファイルをコンパイルしたい場合、 ruby 1.8 以降さえあれば

$ ruby -r erb -e "puts ERB.new(ARGF.read).result" file.template > file

の方法でコンパイルできます*1。と、云うことはです。ファイル保存時にこのコマンドを実行すればテンプレートファイルをコンパイルして別ファイルに保存、といったことができるようになります。そう、そうすれば様々なファイルで変数が使えるようになるのです。
今回は vim のファイル保存時のフックで行い、*.prerb.* というファイル名だったら *.* というファイル名にコンパイルして保存する方法で実装してみました。
例えば、example.prerb.css というファイル名で内容が

<%
  myred = '#FF3333'
  line = "3px solid #{myred}"
%>

p {
  color: <%= myred %>;
  border: <%= line %>;
}

なファイルを保存すると、example.css

p {
  color: #FF3333;
  border: 3px solid #FF3333;
}

と自動でできあがります。css に限らず、ちょっとしたテンプレートを使いたい場合便利、かも知れません。例えばテスト用の Fixture で使う適当な yaml を生成したい場合*2、fixture.prerb.yml を

<%=
require 'yaml'
(0..5).map do |i|
{
  :id => i,
  :name => (1..8).inject('') {|r,| r << ('a'..'z').sort_by{rand}.first }
}
end.to_yaml
%>

とか書けば fixture.yml に

---
- :name: potvdfht
  :id: 0
- :name: esrgnsfl
  :id: 1
- :name: wawbylit
  :id: 2
- :name: bibspxrg
  :id: 3
- :name: jdbwgers
  :id: 4
- :name: iqgxtanj
  :id: 5

と自動で生成されます!便利!というかここまで来ると素直に ruby で書けよとか思いました…。
また ERb テンプレート内でのエラーがおきない前提だったりいろいろアレですが、plugin として放り込んでで置いて、思い出したときに使うと便利かも知れません。
~/.vim/plugin/erb_compile.vim とか名前をつけて下のスクリプトを保存すると使えると思います。

if v:version < 700 || (exists('g:loaded_erb_compile') && g:loaded_erb_compile || &cp)
  finish
endif
let g:loaded_erb_compile = 1

if !exists('g:erb_compile_ruby')
  let g:erb_compile_ruby = '/usr/bin/env ruby'
endif

if !exists('g:erb_compile_prefix_name')
  let g:erb_compile_prefix_name = 'prerb'
endif

function! s:AfterSaveCompile()
  let filename = expand('%:p')
  let output_filename = substitute(filename, '\.' . g:erb_compile_prefix_name . '\(\..\+\)$', '\1', '')
  call g:ErbCompile(filename, output_filename)
endfunction

function! g:ErbCompile(filename, output_filename)
  call system(g:erb_compile_ruby . ' -r erb -e "puts ERB.new(ARGF.read).result" ' . a:filename . ' > ' . a:output_filename)
endfunction

exe 'autocmd BufWritePost *.' . g:erb_compile_prefix_name . '.* call s:AfterSaveCompile()'

あと最近周りがエディタの保存時にフックかけて云々、が割とブームな気がします!さあみんな autocmd BufWritePost まくろう!(vim

ViIMproved‐Vim完全バイブル

ViIMproved‐Vim完全バイブル

*1:erb というコマンドラインのコマンドがあります。コメントで教えていただきました。

*2: Rails のテストでは自動で ERb 通してくれますが…