OpenAPI の YAML および JSON から PDF を生成

はじめに

OpenAPI の YAMLJSON から、openapi-generator-cli を使って、リファレンスを HTML や Markdown を出力したりしている。

ただ、リファレンスを PDF で配りたいという要望もあり、どうしたものかと思案中。

openapi-generator-cli だけでは、直接 PDF は出力できないけど、いったん AsciiDocに出力することで、AsciiDoc から PDF を作れそうだった。

OpenAPI Spec から AsciiDoc

OpenAPI サンプルの定番、Petstore の YAML から AsciiDoc を出力。

openapi-generator-cli generate -i petstore.yaml -g asciidoc -o dest

AsciiDoc から PDF

AsciiDoc から PDF を作成するには、asciidoctor-pdf を使う。Ruby の gem なので、Ruby の環境が必要。

Windows なら、Ruby Installer でインストールするのが手っ取り早い。

rubyinstaller.org

そして asciidoctor-pdf もインストール。執筆時のバージョンは 2.0.17 だった。

gem install asciidoctor
gem install asciidoctor-pdf

組み込みの日本語フォントでよければ、次のコマンドで日本語の PDF を生成できた。

asciidoctor-pdf -a scripts=cjk -a pdf-theme=default-with-fallback-font dest\\index.adoc -o petstore.pdf

おわりに

10MB 超あるお化け swagger.json でも試してみたところ、メモリ 1GB 弱使いながら、かなりの時間をかけて、なんとか PDF 出力できた。

本格的に体裁を整えるとしたら、asciidoc ジェネレーターのカスタムテンプレートと asciidoctor-pdf のテーマを作ることになるだろうな。やりたくない。

Windows10 で gem をインストールしようとしたら SSL のエラーが発生した

Middleman を Windows10 にインストールしようと思ったので

tnakamura.hatenablog.com

を参考に

  • RubyInstaller の Ruby2.3.1(x64)
  • DevKit-mingw64-64-4.7.2-20130224-1432-sfx.exe

をインストールしてみた。

インストールは何事もなく終了したので、次に bundler をインストールしようとしたら

D:\src>gem install --no-ri --no-rdoc bundler
ERROR:  Could not find a valid gem 'bundler' (>= 0), here is why:
          Unable to download data from https://rubygems.org/ - SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed (https://api.rubygems.org/specs.4.8.gz)

というエラーが発生。 SSL 証明書の検証に失敗しているけど、 rubygems が使っている SSL 証明書が古かったりするのか?

rubygems を更新すると解決するようだったので、 rubygems を更新するための gem をインストール。 https が使えないので http でアクセスするように指定しておく。

> gem install rubygems-update --source http://rubygems.org/

rubygems を更新。

> rubygems_update

2.6.7 に更新され、今度は

> gem install --no-document bundler

が成功した。

余談だけど、gem のドキュメントをインストールしないオプションは --no-ri --no-rdoc ではなく --no-document を使うようになったのか。 こっちの方がわかりやすくていいね。

Windows に Middleman をインストールする手順メモ

WindowsMiddleman をインストールして動かせたので手順をメモしておく。 といっても難しいことはやってない。 スンナリ動いて拍子抜けしてくらいだ。

RubyInstaller と DevKit をダウンロード。

http://rubyinstaller.org/downloads

Ruby は 2.2.3 をダウンロードした。

Ruby をインストール

インストーラーを実行して、Ruby を C:\Ruby22 にインストール。

DevKit をインストール

DevKit は C:\Ruby22\devkit に解凍した。

cd C:\Ruby22\devkit
ruby dk.rb init

を実行すると Ruby のインストールパスが書かれた config.yml が作成される。

パスが間違っていないか一応確認。

# This configuration file contains the absolute path locations of all
# installed Rubies to be enhanced to work with the DevKit. This config
# file is generated by the 'ruby dk.rb init' step and may be modified
# before running the 'ruby dk.rb install' step. To include any installed
# Rubies that were not automagically discovered, simply add a line below
# the triple hyphens with the absolute path to the Ruby root directory.
#
# Example:
#
# ---
# - C:/ruby19trunk
# - C:/ruby192dev
#
---
- C:/Ruby22

間違っていないので

ruby dk.rb install

を実行して DevKit インストール完了。

Middleman をインストール

コマンド一発。

gem install middleman

Middleman の動作確認

Middleman がちゃんと動くか、念のため動作確認しておく。

middleman init sample
cd sample
middleman build
middleman server

あたりが動いたんで問題なさそう。

Rails 4.2 に移行していて decimal 型の属性のバリデーションで嵌った

例えば、decimal 型の weight という属性を持つ Item クラスがあるとする。

class Item < ActiveRecord::Base
  validates :weight, inclusion: { in: [0.2, 0.4, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0] }
end

Rails 4.1.2 までは下記のようなバリデーションが成功していたのに、 4.2.0 に上げたら失敗するようになった。

item = Item.new(weight: 1.2)
item.valid? #=> false
item.weight #=> #<BigDecimal:7f0319279bd8,'0.1199999999 9999999555 9107901499 3738383E1',45(54)>

環境は次の通り。

decimal 型の属性は BigDecimal で保持するみたいで、 初期値として渡した Float の値を BigDecimal に変換した結果、誤差が発生してしまっていた。

BigDecimal は文字列から作成できるので

item = Item.new(weight: "1.2")
item.valid? #=> true
item.weight #=> #<BigDecimal:7f031937dbd8,'0.12E1',18(18)>

という風に文字列でセットして回避。

rspec-mocks の and_raise で嵌った

rspec-mocks を使って

allow_any_instance_of(User).to receive(:save!).and_raise(ActiveRecord::RecordNotSaved)

という風にモデルの保存に失敗するテストを書いていたけど、 Rails 4.2 に更新したら実際に save! を呼び出すところで ArgumentError が発生するようになって嵌った。

ちなみに gem のバージョンは次の通り。

pry-bybug でステップ実行しつつ調べたら原因判明。 rspec-mocks では、and_raise で指定した例外クラスをスローするとき、 例外クラスの exception メソッドを使ってインスタンスを生成していた。

で、and_raise の引数でメッセージを渡さなかった場合は、引数なしの exception が呼ばれるんだけど、 ActiveRecord::RecordNotFound の exception は引数が必須。 だから ArgumentError が発生してしまっていた。

ひとまず

allow_any_instance_of(User).to receive(:save!).and_raise(ActiveRecord::RecordNotSaved, "error")

という風にメッセージを渡すことで回避に成功。

Vagrant の port forwarding を設定してもゲスト OS 側の Rails 4.2 の開発サーバーに接続できなくて嵌った

Rails 4.2 へのアップグレード作業中、下記のトラブルに遭遇。

  1. Vagrant でホストの 3000 番ポートをゲストの 3000 番ポートに port forwarding している
  2. ゲスト側で rails server でサーバー起動
  3. ホスト側の Web ブラウザで localhost:3000 にアクセス
  4. サーバーに接続できない\(^o^)/

rails server 実行時に出力されるメッセージを見ると、 Rails 4.1.2 まで開発サーバーは 0.0.0.0 で待ち受けていたけど、 Rails 4.2 では 127.0.0.1 で待ち受けるように変わっていた。

bin/rails server -b 0.0.0.0

という風に、バインドする IP アドレスを指定することで、以前と同じように Web ブラウザで表示できることを確認。