blogをRe:VIEWで書くことを考える

2015年4月24日金曜日

これまでblogの下書きにEvernoteを使ってきたのですが、最近Mac版Evernoteが重すぎる(日本語タイピング時、文字が数秒遅れて表示される)ので段々と思考の邪魔になってきました。この用途ではEvernote捨てたいです。
一方、Bloggerのエディタもだいぶ酷い出来です。それを補うためにごちゃごちゃしたHTMLタグを手動でいじるのも不毛です。
こういう需要に対して、Markdownが有力な選択肢でしょう。.mdを食わせると.htmlを吐き出してくれるコンバータもひとつやふたつではないし、はてなブログだってMarkdownでの記述をサポートしています(制限もありますが)。利用人口それなりに多そうです。
そんななかRe:VIEWでblogを書きたいと思ったので、要件を考え、下調べをおこない、最低限の手動運用をできるようにしたところまでが今回の話です。

こういうことをしたい

  • Atom+language-reviewで書いた.reなファイルをコマンド一発でBloggerの下書きへと登録する
  • そして、同ファイルの変更に伴い簡単に下書きを更新する

Re:VIEWでblogを書けると嬉しいところ

要件を考える前にまず、「なぜRe:VIEWでblogを書きたいのか」を考えてみます。
私の場合これは単純です。本の原稿や雑誌記事原稿を書くのと同じノリで文章を構築していけるからです。
ドキュメントをサクッと書ける、という点ではRe:VIEWよりも圧倒的にMarkdown(特にgithub-flavored Markdown)へと軍配があがります。これは主に、テキストのマークアップにかかるタイプ数がRe:VIEWより少なく、構文も簡素であるためです。特にMarkdownはソースコードやコマンドラインの解説にとても向いています。本文中へコード片を埋め込む`code`な記法の楽さは圧倒的です。``` code block ```の記法もサクサクと本題だけを書いていけます。Markdownな人々がさっさと本題へ入っている頃にまだRe:VIEW使いは//list[][]うんたんうんたんとやっているわけで、そりゃあ素早さで勝てるわけがありません。
Re:VIEWの価値は、紙または電子の書籍媒体というフォーマットを考えた際に大きく出てきます。書きたいことを比較的ライトに書けて、それでいて図表番号指定や脚注の位置指定、ふんわりと本文中に挟まれるコラム、リード文などのゆるいセマンティクスを持つところです。
このRe:VIEWで書くのが楽と感じるのは、記事執筆など紙や電子書籍を想定した媒体向けの作業フローが自分のなかで確立しているからです。
具体的にはこんな感じです。
マインドマップで元ネタを練る→寝かせる→Re:VIEWへベタッと貼り付ける→日本語をつないで文章の形にしてみる→寝かせる→できたノリでもうしばらく気の向くままにネタを追加したり文章を練ったりしていく→寝かせる→想定読者、ボリュームを改めて考えてみて結構な勢いで削る→寝かせる→オーダーにあったものに仕上がっているか、もう一回考えてみる→原稿提出する
この時、書式面やセマンティクスに対する脳負荷がそこそこ低い状態を維持できているのがポイントな気がします。
どの程度の負荷かというと、ひと通り文章を書いた後でざっと全体を眺めながら言い回し(テイスト)を調整しつつ内容を追記しつつ校正するような並行作業が軽くできるぐらいです。
Re:VIEWを使いたいポイントはもうひとつあります。特に雑誌記事について、原稿へいろんなトピックを盛り込みすぎた結果 1/3ぐらい削られて紙面へ掲載されるということがあります。よくあります。ボツになった部分はもったいないので何かしらの形で再利用したいところですが、blogのフォーマットへと落とすのが面倒でお蔵入りになることもしばしばです。これを救い出して簡単にblogへ投げていければ、多少でも人の役に立つのかなーと思うと、やったほうがよさそうな気がします。

使えそうな武器

Blogger連携

以前、EvernoteからBloggerへとポストできれば便利なのではないかと考えてBloggerのAPIを調べたことがありました。その時は画像アップロードをAPIからできないという致命的なポイントに気付いてそっ閉じしたのですが、今回は文章流し込みをメインと捉えてもう一度調べてみました。
https://developers.google.com/blogger/docs/3.0/getting_started?hl=ja
軽く眺めてみます。
ふむふむと読んだら、定番通りGoogle APIs Explorerの中のBlogger API v3をこねこねして調べていきます。
このへんを使うと下書き管理をある程度簡単にできそうです。
  • blogger.posts.list
  • blogger.posts.get
    • view要素にAUTHORADMINを指定すると下書きも拾える
画像系も軽く調べてみました。blogger.posts.getのfetchImagesをtrueに指定すると画像一覧を取得できるように見えますが、そう見えるだけで実際は最初の1枚しか拾ってくれません。なかなかのトラップです。

Wordpress連携

差し当たりは自分で使うためにBloggerを再優先しますが、うまく運用できるようになったらWordpressぐらいまでなら対応しても良いかなという気持ちになって調べてみました。最近はJSONなREST APIで記事一覧を取得したり書いたりできるようで、そこそこシンプルに実装できそうな感じですね。
続きはそのうち調べることにして一旦置いておきます。

その他連携

他の方面として、はてなブログがサポートしているAtom Publishing APIというのもアリな感じがします。
これはWordpressも2007年からサポートしているので、割と使い勝手が良いかもしれません。というかBloggerがこの方式をサポートしてくれてたら全部丸く収まったやつなのでは…。
「世のblogをあまねくRe:VIEWで書けるようにする!!」といった志は特に持っていないので、連携系はあまり考えません。

review2md

Re:VIEWからMarkdownへ落とすコマンドがあると思い込んでいたのですが、逆方向(MarkdownからRe:VIEWへ; md2review)しかなかったのでアテが外れました。あったら場合によっては軽くショートカットできそうでしたが、まあ大きな影響はありません。
追記: ありました(review-compile --target=markdown)

辛いところ

画像の貼り付け

Re:VIEWから各種blogサービスへの出力において、画像をどうやって公開場所へと配置するかはやはり厄介な問題です。Kobitoを使って偉いなーと感じたのはD&Dした画像の自動アップロード機能でした。
事前調査でblogger APIは画像アップロード機能を持っていないことが分かっているので、ここをうまくやるのは難しいのです。他所のオンラインストレージを併用する方法もアリだとは思いますが、だいたい余計に厄介な事情を抱え込むことになるので今回は避けます。
なお、調査ついでに自blogを過去にさかのぼって調べた感じ、ほとんど画像を貼ってないのでまあそんなもんかという気持ちにもなりました(もう少し増えたほうが良い気もした)。

blog公開後に直した部分のRe:VIEW側へのバックポート

校正はゲラがあがって紙の束にならないと気持ちが入らないという人が一定居るのと同様、blogでもテキストエディタで書いている時には気付かなかったミスを公開後に見つけて直すということが結構あります。
これを元のRe:VIEWへと反映するのは結構厄介な作業です。何より、微調整が複数回に及ぶとそれらの逐次取り込みは精神的な負担が大きいです。
「すべてRe:VIEW側をマスタとしてblog側の編集機能を使わないようにする」という策も考えられはしますが、前述の画像アップロードや下書き後の体裁調整をおこないたいケースを考えるとイマイチです。
これについては、下書きをblogサービス側へアップロードした後の変更をなるべくAPI経由で全リビジョン取得しておき、後で下書き投入時とのdiffを眺めて変更箇所を見つけやすくするぐらいがほどよいように思います。
このdiffをほどよく差分ハイライトできる仕組みがあればとても良いですね(まだ探してない)。

Re:VIEWからのHTML出力

Re:VIEWのHTML(XHTML)出力はほぼePub出力のためのおまけ機能なので、足りないものがそれなりにあります。この点について対応方法をいくつか考えたのですが、結論は「なるべく省力で後処理に必要な情報を補い、あとは出力されたXHTMLから適当に情報を抜き出してblog用に自動整形するのが妥当」というものでした。
コードブロックの貼り付けや表などの見栄えを考えると、Re:VIEWからの出力をほどよくblog用に整えるCSSも必要そうです。コードのシンタックスハイライトなどはなるべく内部では持ちたくない(JSで完結するものへとCSSクラス指定で流すぐらいが良い)ですね。

要件検討

下調べが大体終わったところで、Re:VIEWからblogを書くために作るべき仕組みの要件を考えてみます。このあたりまでやればほどよく気持ち良くblogを書けそう、というものを絞り込みました。
  • 基本的にコマンドラインで操作する
  • Re:VIEWで書いた文書をblogの下書きとして登録できる
  • 既に下書きとして登録した記事を上書きできる
    • 上書きした場合、上書き元のデータを手元のワークディレクトリへとバックアップする
      • 気になる人はgit cleanなりして適当に消してほしい
  • 下書き内に画像が貼り付けられてる場合は画像を全て末尾へ持って行って維持する
    • こうしないと後で仕上げるタイミングで貼り直しになって面倒
  • 公開済みのポスト(isDraftがfalseのもの)は一切いじらない
  • CSSのクラス名に適当なprefixをつけて振り直せる
    • Re:VIEWの出力ではleadとかimageとか、広く使われてそうなものを容赦なく使ってるので結構危険
      • <a id="...">として割り振られているチャプターIDも振り直せたほうが良いかもしれない

手始め(最低限)の処理

最終的にはある程度のツール開発が必要になりますが、既存の仕組みでもなんとかなる部分は先になんとかしたいところです。
Re:VIEWは、コア部分へ手を入れずにカスタマイズできる部分が結構あります。
だいぶ前に13.08.10 7行110bytesで構文を拡張 出来るReVIEWの話として自分で書いた資料が役に立ちました。
いきなりblogger APIへのつなぎこみまでやるのはイマイチ危険が危ない感じがしたので、まずは手元でreview-compileを叩けばほどよくBloggerへコピペするのに向いたHTMLが書き出されるようなところまでやって一旦終了とします。
まず、元々他のチャプターを参照する機能として用意されているchapref構文を他のblog記事への参照用に使えるようにしたかったので、review-ext.rbを簡単に記述しました。
リスト1という感じです。id2blogger_urlという名の通り、BloggerのURL構造を前提にしているのでイマイチなところがありますが、ひとまずよしとします。
リスト1 差し当たりの半手動運用のためのRe:VIEW拡張
module ReVIEW
  class HTMLBuilder
    def id2blogger_url(id)
      id.gsub(/^(\d{2})(\d{2})_/, '/20\1/\2/')
    end
    def inline_chapref(id)
      title = super
      relative_url = id2blogger_url(id)
      %Q(<a href="#{relative_url}#{extname}">#{title}</a>)
    end
  end
  class Builder
    def headline_prefix(level)
      ['', nil]
    end
  end
end
他には、随所に「第n章」と入るのがイマイチだったので入らないようにlocale.ymlを作成してぽちぽちと設定しました(リスト2)。
リスト2 差し当たりの半手動運用のためのlocale.yml
locale: ja
chapter: ""
chapter_postfix: ""
chapter_quote: "%s"
format_number: "%2$d"
format_number_header: "%2$d"
Blogger側でのCSS定義は今のところリスト3という感じです。Bloggerでは貼り付けたpタグが勝手にbrタグへと変換されるので、brタグの見栄えをpタグのようにする(強制改行時のみ空行をあける)ようにしています。
リスト3 Blogger用のRe:VIEW出力CSS定義
.review-post br { margin:0px 0px 12px 0px; }
pre.list { background-color: #def; border: 2px dotted; padding: 4px; }
あとはreview-compile --target=html 1504_blog_using_review.re | pbcopyという具合に実行した結果をBloggerの編集ウィンドウへと貼り付けて完了です。
シンタックスハイライトなどは後から別途考えることにします。
手動運用しているうちに要件が整理されてくるでしょうし。
これでできたblog用のRe:VIEW構成のひな形がhttps://github.com/muojp/review-blog-template/です。

残る懸案事項

最低限はできましたが、自動化していく前に考えておくべきことがいくつか残っています。

ほどよい記事間リンク方法

Evernoteだと、ノート間のリンクがきちんと張れるので地味に重宝していました。
月/日/ident.reというディレクトリ構造にすればBlogger側の構造とマッチしますが、これだとRe:VIEW側でのビルドが辛いです。このため、今回はreview-ext.rbで無理やり参照のリンク位置をいじりました。本来的には、文書IDはIDとして維持したままで次段階(XMLパーサ)へ渡して、その中で出力先(この場合はBlogger。場合によってはWordpressやはてなブログ)にあわせたパス付けをすべきでしょう。
あまりディレクトリ構造まで踏み込んでいじりたくない(複数階層にすると、ある.reファイルをいじっている時にそれのルートディレクトリがどこなのかというのを判定して処理をおこなう系が非常に面倒になる)ので、これは名前付けルールでカバーかなと。
記事は4月に書いたけれど記事を公開用にアップロードしたのが5月で、URLに5月とついた、という場合に対応付けが崩れると面倒です。残念ながらこれは頻発する事態なはずなので、重複するidentが無い限りはほどよくカバーできるようにしておきたいところです。
カテゴリを対応付けに使うという策も考えましたが、意味付けのあり方としてイマイチです。本文中にコメントを突っ込んでおいて使うというのはかなりイマイチだけど現実案の筆頭なので保持しておきます。blogger.posts.insertでURL指定ができない場合は、もう諦めてコメントへ突っ込むようにしようかなと。
アーカイブを別ディレクトリへ階層化して置いていくような仕組み(プログラム的にか、ルール的にかはさておき)はあっても良いかもしれません。

プレビュー

MarkdownはGitHub上でいい感じな見栄えのプレビューをできるところでも価値があるのですが、Re:VIEWだと少々大変です。まあ、元々そんなに脳処理負荷が高い構文ではないのでハイライト程度で良いといえば良いし、Atomから扱う場合にはlanguage-reviewのプレビュー機能で十分なんですが*1、blogのレイアウトにあわせた見た目でのプレビューがあると何かとテンション上がるのであったほうが良いです。
[*1] 執筆時点の最新版であるAtom 0.193.0では、シンタックスハイライトの大半を含めて概ね全機能が一時的に使えなくなっているのがつらいです
ファイルを保存したらBlogger上へ勝手に保存してプレビューするのはさすがにやりすぎな気もするのでほどよい策を考えたいところです。Blogger上にプレビュー用のページ(sandbox的な)をひとつ用意しておいて、そこを使ってプレビュー内容の流し込みができたら十分かもしれません。優先度は低いのでそのうち考えてみます。

他エントリのページ内特定箇所へのリンク

他のblogエントリ内の特定の節への参照を張るのは、今のところサポートしていない気がします(ひょっとするとextname指定がうまく効いているかもしれません)。これはパッと見た感じ、ページ内リンクにTOC的な通番構造を使っているようだったので、そのままだと節構造を変えた際に追従するのが厄介と考えたからです。もう少しchaprefあたりを使い慣れたらうまくできるかもしれません。

既知の不具合

  • Re:VIEWで書けることで、ついついblog記事が長くなる

0 件のコメント:

コメントを投稿