refactoring Re:VIEW メモ

メモです。まだ途中。徐々に追加中。

# クラスの構成

## ReVIEW::Book::*

* lib/review/book/ 内のファイルは以下:
    * base.rb: Book::Baseクラス、「書籍」を管理
    * chapter.rb: Book::Chapterクラス、「章」を管理
    * compilable.rb: Book::Compilableモジュール、「章」「部」共通モジュール
    * image_finder.rb: Book::ImageFinderクラス、画像パス探索用
    * index.rb: Book::*Indexクラス、インデックス参照を何とかする用
    * page_metric.rb: Book::PageMetricクラス、行数ページ数の基準用、要手直し
    * part.rb: Book::Partクラス、「部」を管理
    * volume.rb: Book::Volumeクラス、ページ数等計測要、要手直し

* 書籍の情報は ReVIEW::Book::Base が持つ(`@book`になってる場合が多い)
    * ReVIEW::Book::BaseはReVIEW::Bookに変更した方が名前的にいいような気がするけど、激しく困るわけでもないのでしないかも
    * ちなみにReVIEW::Bookは現状クラスじゃなくてモジュールなのだった…
    * 要するに書籍の階層構造を管理するための名前空間モジュール = Book、ということらしい
* 設定情報 ReVIEW::Configure はbookのインスタンス変数になっている(`@config`)ので、bookから取り出せる

```
config = book.config
```

* `@book`は章(ReVIEW::Book::Chapter)と部(ReVIEW::Book::Part)の中にインスタンス変数として含まれている
    * ので、chapterからbookを取り出せる

```
book = chapter.book
```

* 要するにChapterからはConfigureを（今のところ）直接取り出せない。いったんBookを経由する
* `@book`は部のArray(`@parts`)を持っている
* 部と章は ReVIEW::Book::Compilerable モジュールをインクルードしている

## ReVIEW::Configure

* 設定情報の持ち方は、昔はばらばらだったが、ReVIEW::Configureに集約しつつある
* ReVIEW::ConfigureはHashのサブクラスになっている
    * サブクラスにする必要はいまのところなさそうだけど何かあったら便利かも
    * 現状なら移譲でも十分かとは思う
* デフォルト値は（なぜか）Configure.valuesというクラスメソッドで定義されている
    * Configure#valuesと名前がかぶっているのでちょっと微妙
* 設定情報の元はconfig.ymlに記述する。ここからConfigureを作る
    * ``config=Configure.values;config.merge(YAML.load_file("config.yml"))``みたいな感じ

## ReVIEW::*Builder

* 各出力フォーマットのテキストデータを生成するのは*Builderクラスが行う
    * 共通する処理はReVIEW::Builderクラスで、HTMLならReVIEW::HTMLBuidler、LaTeXならReVIEW::LATEXBuilderが処理する。
    * ReVIEW::HTMLBuidler等はReVIEW::Builderのサブクラスになっている。
* BuilderはBuilder#newとBuilder#bindがある。
    * newはインスタンス生成用、bindはBook::ChapterやCompilerと紐つける用。bindしないと実行できない
    * Builder#newはBuilder#builder_initを、Builder#bindはBuilder#builder_init_fileを呼ぶ。サブクラスである*Builderではinitializeとbindを再定義せず、追加したい処理はbuilder_initとbuilder_init_fileに記述する作法になっている
    * Rubyぽくないので変えたい（サブクラスでinitializeやbindを定義してsuperしたい）けどとりあえずはそのままにしておく？

## ReVIEW::Compiler

* Re:VIEWフォーマットのテキストを解析するのがReVIEW::Compilerクラス
* ReVIEW::Compiler.newは*Builderを引数としてとる
    * 要はインスタンスは特定の*Builder専用になる
* CompilerはBook::Baseをインスタンス変数として**持っていない**。持っているのはBook::Chapterの方。
    * ここが超重要。混乱する（混乱してた）。
    * 必要な時には、Book::ChapterからBook::Baseを取り出して使う

## EPUBMaker

* EPUB生成用の独立した名前空間モジュール。
    * ReVIEW::*には一切依存しない（というルールになっている）
        * 外部RubyGemsを取り込んでいるような感じ（宗教上の理由により他gemなしで動かすことになっているので外部化はしない）
    * ReVIEWに依存する部分はReVIEW::EPUBMakerに置くことで疎結合化して利用している

## Ruby標準クラス（の拡張）
* lib/review/extensions/*.rb で既存クラスを拡張している

### Object
* Object#blank? , Object#present?
    * Railsにあるやつ。blank?は空かどうかを調べる。present?はその逆
        * empty?があればそれを、なければ!objでチェック

### String
* String#lines
    * 1.8でも追加
* String#charsize
    * 文字数を返す。1.9ではsizeのalias、1.8ではsplit(//).sizeする
* String#each
    * 1.9でもeach_lineのaliasとして追加

# 書籍情報(Book::Baseインスタンス)の取得方法

* ReVIEW.bookとか、設定情報ならReVIEW.book.configとかやっていたところは全部変更する
* `@book`があるならReVIEW.bookを`@book`に書き換える
    * ReVIEW.book.config なら @book.config にする
* `@book`がない場合、他のオブジェクトから取得するか、新規に作る
    * 文脈的に新規に作ってるぽいところでは、`@book = ReVIEW::Book::Base.new` とする
        * 冗長だけどReVIEW.bookとやってることは同じはず
    * chapterがあるならchapter.bookとかする
* メソッド定義中で必要になった場合は、メソッド引数にconfig等を追加することもある

# 変更記録 

* ReVIEW::Book::ParametersがReVIEW::Configureと機能的にかぶっている
    * 削除した
* ReVIEW::Book::Chapter.for_stdinとReVIEW::Book::Chapter.for_pathが使われてない
    * 削除した
* ReVIEW.bookが謎のグローバル変数もどきになっている
    * ReVIEW::Book::Baseのインスタンスをキャッシュしている
        * 特に必要がなければBook::Base.newとかBook::Base.load_defaultを律儀に呼ぶ
    * ReVIEW.book.configで情報共有しているところがある
        * `@book.config`でなんとかする
    * 上記のようにして削除した
* bookがenvで参照されている部分がある。
    * ``@chapter.book.foo``が``@chapter.env.foo``みたいな
    * そもそも`@chapter.book`は`@book`で良いはずなので、あとで`@book`に統一したい→統一した