at posts/single.html

tDiary のチラリズム日記 (揮発性日記) プラグインを作ってみたい (3)

前回の続き。 ちょっと間が空いたけど、ゆっくりと作ってたよ。 日記の追加時に直近の日記を漁って古いのを非表示にするほうがいいというツッコミをいただいたので、その方向で作り直してみた。

少し形になったので、揮発性日記プラグインをCodeReposに登録した。

注意

過去に「非表示」としている日記が存在する場合は、このプラグインを使うことで「非表示」の日記が意図せずに公開される危険性がある。 例えば、以下のようにすると、過去に書いた日記が(プラグイン導入前に非表示にしていたものを含めて)すべて公開される。

  • プラグインを導入する
  • プラグインの設定画面で「公開する日記の件数」に大きな数(例: 10000)を入力してOKボタンを押す
  • 最新の10000件の日記が全て公開される

なので、軽い気持ちでこのプラグインを試すのはお奨めしない。 非表示にした日記は元に戻さないくらいの心構えでいないとダメかも。 もう少しキメ細かくコントロールできるといいんだけど、いい方法が思いつかなかったんだよねぇ。

そういう意味では、CodeReposに登録しておくのは危険なのかな?

内部の解説

フィルタを使うのではなく、日記の更新時に add_update_proc をフックして古い日記を非表示にする方針。 add_update_proc では @diaries と @date を使って更新した日記を取得できるけど、これには制限がある。

  • update_proc が実行される時点では IO のトランザクションが完了しているので、 @diaries 変数の内容を書き換えてもファイルに反映されない。
  • @diaries 変数には当月分のデータしか含まれていないので、月をまたぐデータを取得できない。

そこで、 recent_list プラグインや navi_user プラグインを参考にして、プラグイン内で独自に IO を呼び出す仕組みにした。 まず、複数の日記を一括して更新するための、 TDiaryBulkUpdate クラスを作る。 initialize メソッドの中で IO を開き、 DIRTY_DIARY フラグを IO に返すことで日記を更新できる。

module ::TDiary
  class TDiaryBulkUpdate < TDiaryUpdate
    def initialize( cgi, rhtm, conf )
      super
      date = Time::local( *cgi.params['date'][0].scan( /^(\d{4})(\d\d)$/ )[0] )
      @io.transaction( date ) do |diaries|
        yield(diaries)
        # DIRTY_DIARYは@ioへ日記を更新することを伝えるフラグ
        DIRTY_DIARY
      end
    end
  end
end

次に、 @years 変数から取得した年月の一覧(日記を書いた日の一覧)をイテレータで回し、月単位で TDiaryBulkUpdate を呼び出す。

cgi.params['date'] = ["#{year}#{month}"]
m = TDiaryBulkUpdate::new(cgi, '', @conf) {|diaries|
  diaries.sort.reverse_each do |date, diary|
    # ここに diary を更新する処理を書く
  end
}

これで、プラグインの呼び出し時に日記の内容を更新できるようになる。 あとは日にちの条件などを書いておしまい。

関連する日記