電柱日報

日々の由無し事

Prawn

前々から、利用者への通知を印刷するのにRubyからPDFを作れないものかと考え、イロイロと試しては見たのですが、日本語フォントの埋め込み関係が巧くゆかず、しばらくペンディングになっていました。
先だってRGhostが良いらしいという記事を読んだものの、GhostScriptのラッパーなのが少々厄介だな、と思っていたところで、Prawnというライブラリもあるらしいという記事を見つけまして。
調べてみると、pure ruby製でRubyGemsからインストールする以外のプロダクトを必要とせず、Ruby1.9の環境でも問題なく動いているらしい事が判り、ちょっと試してみたんですが、阿久的にはドンピシャの一品でした。
凝ったデザインが必要なく、基本文字情報を載せれば良い通知文などの自動生成にはかなり力を発揮すると思います。

require "prawn"

Prawn::Document.generate "test.pdf" do |pdf|
  pdf.font "./M+2VM+IPAG_circle.ttf" # フォントファイル指定
  pdf.text "日本語も通る"            # テキスト記述
end

正直、これだけの記述で、test.pdfという名前で日本語入りのPDFファイルが生成された時には、少し感動してしまいました。
サンプルドキュメントだけだと、やや情報不足な感は否めませんが、pure rubyですから疑問があってもソースを読めばある程度解決できてしまいます。
たとえば、デフォルトの状態ではテキストの行間がかなり詰まって見えたので、何とかして行間を調整する事はできないモノか、と思ってソースを眺めていたところ、ドキュメントには記述が見当たらないものの、 prawn/document/text.rb 内で、テキストオブジェクトのオプションに :spacing(最新のソースだと:leadingになってますね)があって、行送り時の調整をしている事が判明しました。(ちなみに、:kerning というオプションも定義されているようですので、文字間隔の調整もできそうな感じ)
「もしかして文字色変更できない?」とか「座標が用紙の左下→右上方向なのが慣れん」とか、細かな違和感はあるものの、さしあたり今抱えてる要件はクリアできそうな感じで万々歳です。
余談ですが、pure rubyであることのもう一つの利点は、最悪、自分の都合のいいようにソースを書き換えてしまえる、という点ですよね。(ただし動作するかは自己責任)
Prawnでは、各種単位変換(cm2ptとか、cm2inとか)メソッドを集めたPrawn::Measurementsというモジュールが定義されているのですが、なぜか、変換メソッドがすべてインスタンスメソッドになっており、prawn/measurement_extensions.rb を require すると、NumericクラスにPrawn::Measurementsがincludeされる仕組みになっています。
ただ、ソースを良く見てみると微妙に実装がチグハグな印象を受けました。
例えば、mmをptに変換する mm2ptメソッドはこんな実装になっています。

module Prawn
  module Measurements
    def mm2pt(mm)
        return mm*(72 / 25.4)
    end
  end
end

インスタンスメソッドですので、Numeric の継承先である Fixnum などのインスタンス経由で呼び出すことになるのですが、呼び出し元のインスタンスとは無関係に、引数で与えた別の数値を変換して返すことになって何となく気分が良くありません。

require "prawn/measurement_extensions"

a = 2
b = 3
a.mm2pt(b) # この場合、a(=2)とは関係なくb(=3)を変換した値が返る

もちろん、a.mm2pt(a) みたいな書き方は可能ですが、変換したい数値があって呼び出しているんですから、それも冗長かなと思い、変換メソッドのパラメータはデフォルトでselfを採るように変更してしまいました。

# 変更後
module Prawn
  module Measurements
    def mm2pt(mm = self)
        return mm*(72 / 25.4)
    end
  end
end

こうしてしまえば、引数無しの場合に、呼び出し側の数値を変換した値が返ってきてなんとなくスッキリ。

require "prawn/measurement_extensions"

a = 2
a.mm2pt # これで2mmをpt換算した値が返ってくる