ファイルの中に別のファイルの一部を変えて読み込むスクリプト

ファイルの中に別のファイルの一部を変えて読み込むようなスクリプトが欲しい

バナーとかサイドバーのように複数のWebページで共通する要素を別ファイルに出しておき、それをインクルードできると便利だ。というわけで、ファイルの中に別のファイルを読み込むスクリプトを作ったのが前回までのお話。

共通する要素を別ファイルにどんどん出していたところ、次のようなものがあることに気付いた。

  1. 全ページに「前ページ」「次ページ」というナビゲーションボタンをつける。
  2. ボタンの形状やソースのHTMLはほとんど同じ。
  3. ただし、前ページ、次ページのリンク先はページによって異なる。

リンク先が異なるから、前回のスクリプトでは対応できない。ほとんど同じなのに共通化できない。なんとかしたい!

スクリプト

というわけで、引数をとれるようにスクリプトを改造した。相変わらずRubyっぽくないが反省はしていないw

include.rb:

#!ruby -Ks

# include.rb: ファイル中に別のファイルをインクルードして出力する。
# Usage: ruby include.rb [inputfile] [outputfile]
# inputfile, outputfileが省略された場合は
# それぞれ標準入力、標準出力が使われる。
# 読み込み指定は行に単独で
# <!--#include file="includefile" "arg1" "arg2" ... "argX" --> と書く。
# 読み込んだファイル中の$1, $2, ... がarg1, arg2, ... に置換される。

def main
  outputfile.puts(inputfile.readlines.map { |line| includefile(line) })
end

def inputfile
  ARGV.length >= 1 ? open(ARGV[0], "r") : $stdin
end

def outputfile
  ARGV.length >= 2 ? open(ARGV[1], "w") : $stdout
end

# includefile: include a file and replace with arguments.
#
def includefile(line)
  line =~ /<!--#include file="([^"]*)"(.*) -->/ ?
    replaceargs(open($1, "r").read, parseargs($2)) : line
end

# parseargs: parse arguments and return as array.
# ex. '"arg1" "arg2" "arg3"' -> ["arg1", "arg2", "arg3"]
#
def parseargs(str)
  str.strip.scan(/"[^"]*"/).map{ |arg| arg[1..-2] }
end

# replaceargs: replace $1, $2, ... in string with arguments.
#
def replaceargs(str, args)
  indexedargs(args).inject(str) { |result, arg|
    result.gsub("$#{arg[0]}", arg[1]) }
end

# indexedargs: return indexed arguments.
# ex. ["arg1", "arg2", "arg3"] -> [[1, "arg1"], [2, "arg2"], [3, "arg3"]]
#
def indexedargs(args)
  (1..args.length).zip(args)
end

main

実行結果

たとえば次のようなwelcome.txtがあるとする(これが読み込まれる共通部分になる)。

Hello $1. Nice to meet you.
Welcome to the $2.

これを読み込むtest.txtが次の内容だとして

<!--#include file="welcome.txt" "Neo" "Real World" -->

<!--#include file="welcome.txt" "Kitty" "SANRIO PUROLAND" -->

スクリプトを実行すると

ruby include.rb test.txt

出力は次のようになる。

Hello Neo. Nice to meet you.
Welcome to the Real World.

Hello Kitty. Nice to meet you.
Welcome to the SANRIO PUROLAND.

<追記>

はてなのバグにより、記事表示ではプログラム中のHTMLコメント部が正しく表示されないようです。以下のボックスが空欄の場合は、日付表示にして見てください。

<!-- コメントです -->