PureBuilder Simplyのアップデート (ReST完全対応)
有用なユーティリティコード
- TOP
- Old Archives
- PureBuilder Simplyのアップデート (ReST完全対応)
3ヶ月ぶりとなったPureBuilder Simplyのアップデート。
今回はMimir Yokohamaのウェブサイトの新連載(そもそも連載開始にお金かかるので時期未定)でReSTructured Textを使うため、ReSTに完全対応した。
完全対応のポイントは、従来きちんと対応できていなかったdocinfo(Bibliographic Elements)に対応するようにした。
ただし、これは「対応した」という言い方が適切なのかどうかわからない。 ひとつは、自力でdocinfoを解釈する部分が間違っていたのと、仕様の理解自体正しくなかったので適正にした。
File.open([dir, filename].join("/")) do |f|
l = f.gets- if l =~ /:[A-Za-z]+: .*/ #docinfo
- docinfo_lines = [l.chomp]
+ if l =~ /:([A-Za-z]+): (.*)/ #docinfo
+ frontmatter = { $1 => [$2.chomp] }
+ last_key = $1
# Read docinfo
while(l = f.gets)
break if l =~ /^\s*$/ # End of docinfo- if l =~ /^\s+- / && (docinfo_lines.last.kind_of?(Array) || docinfo_lines.last =~ /^:.*?: +-/) # List items
- if docinfo_lines.last.kind_of?(String)
- docinfo_lines.last =~ /^:(.*?): +- *(.*)/
- docinfo_lines[-1] = [ [$1, $2] ]
- end
- docinfo_lines.last[1].push(l.sub(/^\s+- +/).chomp)
- elsif l =~ /^\s+/ # Continuous line
- docinfo_lines.last << " " + $'.chomp
- elsif l =~ /^:.*?: +.*/
- docinfo_lines.push l.chomp
+ if l =~ /^\s+/ # Continuous line
+ docinfo_lines.last.push($'.chomp)
+ elsif l =~ /:([A-Za-z]+): (.*)/
+ frontmatter[$1] = [$2.chomp]
+ last_key = $1
end
end
- # Convert Hash.
- frontmatter = {}
- docinfo_lines.each do |i|
- if i.kind_of?(Array) #list
- # Array element
- frontmatter[i[0]] = i[1]
- elsif i =~ /^:author: .*[,;]/ #author
- # It work only pandoc style author (not Authors.)
- author = i.sub(/:author: /, "")
- if author.include?(";")
- author = author.split(/ *; */)
- elsif author.include?(",")
- author = author.split(/ *, */)
- end
+ # Treat docinfo lines
+ frontmatter.each do |k,v|
+ v = v.join(" ")
+ if((k == "author" || k == "authors") && v.include?(";")) # Multiple authors.
+ v = v.split(/\s*;\s*/)
- frontmatter["author"] = author
- elsif i =~ /^:(.*?): +(\d{4}-\d{2}-\d{2}[T ]\d{2}[0-9: T+-]*)$/ #datetime
- key = $1
- time = DateTime.parse($2)
- frontmatter[key] = time
- elsif i =~ /^:(.*?): +(\d{4}-\d{2}-\d{2}) *$/ #date
- key = $1
- time = Date.parse($2)
- frontmatter[key] = time
- elsif i =~ /^:(.*?): +/
- key = $1
- value = $'
- frontmatter[key] = value
+ elsif k == "date" # Date?
+ # Datetime?
+ if v =~ /[0-2][0-9]:[0-6][0-9]/
+ v = DateTime.parse(v)
+ else
+ v = Date.parse(v)
+ end
+ else # Simple String.
+ nil # keep v
end+
+ frontmatter[k] = v
end
elsif l && l.chomp == ".." #YAML
# Load ReST YAML that document begins comment and block is yaml.+ @extra_meta_format = true # ReST + YAML is not supported by Pandoc.
lines = []
while(l = f.gets)
考え方自体に大きな変更があったため、変更行数も多い。
ただし、22165f2
よりも8f6e453
のほうが以前のバージョンとの違いは少なくなっている。
ここでひとつポイントだ。ReSTの仕様上、authors
がa,b,c
と書かれた場合は3人の著者になる。a,b,c;
と書かれた場合は1人の著者になる。
だが、Pandocは;
でのみ分割するので、この仕様に従っている。このため非常にシンプルな仕様だ。
基本的にdocinfoの場合、authors
とdate
のみが特別扱いされる。
Pandoc的にもそのような仕様になっており、authors
をauthor
の代わりに書ける点も正式な仕様に従っている。
PureBuilderもこれにならって、それ以外のフィールドについては特別扱いしない。
また、Pandocは仕様にない項目を入れてもエラーにしないため、この点も合わせてある。
この上で、メタデータの解釈はPandocに委ねることにした。
従来は-M
オプションを付加して上書きしていたのだが、解釈の違いからバグにもなったし、Pandocのほうが優秀なのでこのような挙動は取りやめた。
ただし、PureBuilder的にはこれではちょっと困る。 サイトの内容に関する情報をメタデータに記述する風習があるため、メタデータに書ける内容が決められてしまうのは困るのだ。
そこで従来サポートされていた「ReSTでも先頭をコメントにした場合はそのあとYAMLメタデータを書くものとする」という仕様も維持している。
この場合、Pandocは解釈できないため、@extra_meta_format
というインスタンス変数を追加し、これが真の場合のみ-M
オプションでのメタデータを使うことにした。
こうしてReSTも完全対応できることとなった。 asciidocも結構人気があるらしいのだけど、Pandocが入力にasciidocをサポートしていないのでサポートすることはできない。 Textileをサポートしてほしい人がいれば対応は考えなくもないけれど、私が知る限りPureBuilderでTextileを使いたい人はいないはずだ。1
比較的複雑な構造を書けることがPureBuilderの利点であり、また簡易な記述をしたい人にとってもMarkdownが困ることはないはずだからだ。Textileにはコメント機能があるため、サポートすること自体は不可能ではない。↩︎