YAMLとSlimで論文リストを作る

# 概要

以下のようなYAMLファイル(`publication.yaml`)を食わせて、

```yaml
-
  title: How to write web sites with slim
  author: R. Robota, T. Tanaka
  journal: Ruby Journal
  year: 2010
  volume: 10
  page: 1-7
  arxiv: 1234.56789

-
  title: Using YAML file with slim
  author: R. Robota
  journal: Journal of Slim
  year: 2018
  volume: 8
  page: 1275

-
  title: This is a sample file for Slim and YAML
  author: S. Yaml, T. XML and R. Robota
  journal: J. Yaml. Phys.
  year: 2017
  volume: 3
  page: 12-18
  arxiv: 1908.01234
```

以下のようなHTMLを吐くSlimテンプレートのサンプルです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79744/baff2be1-f3d8-e7bb-c0fb-33c499117d20.png)

ソースは以下においておきます。

[github.com/kaityo256/yamlslim](https://github.com/kaityo256/yamlslim)

# 何をしたいか

論文リストとかそうですが、とりあえずなんかリストがあり、それを静的なHTMLにしたい、ということはよくあります。とりあえず論文リストはJSONかYAMLで用意されてるとしましょう。これをHTMLにしたい。さほど更新頻度も高くないので、CMSとかデータベースを導入するほどでもない、でもHTMLを直書きするのは嫌だ、という気持ち、わかっていただけますよね？

で、どうしましょう。

そういう用途では、とりあえずPHPでゴリゴリ書いちゃう、という方法が考えられます。PHPはそれが本職の言語なので、わりとまっとうな気がします。

もしくはJSON+JavaScriptというのもありな気がしますね。JSのテンプレートエンジンは豊富にあるので、好きなのを使ってなんとかする、というのが最近では良い気がします。

ですが、個人的に母国語がRubyということもあって、Rubyスクリプトの埋め込みができる軽量テンプレートエンジン、Slimを使うことにします。

# Slimとは

[Slim](https://github.com/slim-template/slim)は軽量テンプレート言語です。おそらくRuby on Railsと一緒に使われることが多いと思いますが、ローカルでHTMLを吐くのにも使えます。[日本語の公式ドキュメント](https://github.com/slim-template/slim/blob/master/README.jp.md)がわかりやすいので、使うのは簡単だと思います。

Rubyとgemが入っていればSlimのインストールは簡単です。

```sh
$ sudo gem install slim
```

このあと、

```sh
$ slimrb -v
```

とかやってバージョン情報が出てきたらインストールされています。

例えば、

```slim:test.slim
doctype html
html
  head
    title My first Slim
  body
    h1 This is test
    h2 Hello Slim
```

こんなファイルを作って、

```sh
$ slimrb test.slim
```

とslimに食わせると、

```html
<!DOCTYPE html><html><head><title>My first Slim</title></head><body><h1>This is test</h1><h2>Hello Slim</h2></body></html>
```

と、HTMLにしてくれます。`-p`オプションをつけると人間が読みやすい形にしてくれます。

```sh
$ slimrb -p test.slim
```

```html
<!DOCTYPE html>
<html>
  <head>
    <title>My first Slim</title>
  </head>
  <body>
    <h1>
      This is test
    </h1>
    <h2>
      Hello Slim
    </h2>
  </body>
</html>
```

さて、Slimの特徴は、Rubyスクリプトをそのまま埋め込めることです。ハイフン`-`のあとにRubyスクリプトが書けます。また、`=`を使って、HTML要素にRubyの実行結果を代入できます。たとえば変数`a`を定義して、`h1`に突っ込むにはこうします。

```slim:test2.slim
doctype html
html
  head
    title My first Slim
  body
    - a = "Hello"
    h1 = a
```

```html:test2.html
<!DOCTYPE html>
<html>
  <head>
    <title>My first Slim</title>
  </head>
  <body>
    <h1>
      Hello
    </h1>
  </body>
</html>
```

上記のように`a`に代入された値を、`h1`要素に突っ込むことができました。

また、配列などに対して`each`を使い、その要素を列挙できます。

```slim:test3.slim
doctype html
html
  head
    title My first Slim
  body
    ol
      - ["Dog", "Cat", "Cow"].each do |animal|
        li = animal
```

これをslimrbに食わせるとこんなHTMLになります。

```html:test3.html
<!DOCTYPE html>
<html>
  <head>
    <title>My first Slim</title>
  </head>
  <body>
    <ol>
      <li>
        Dog
      </li>
      <li>
        Cat
      </li>
      <li>
        Cow
      </li>
    </ol>
  </body>
</html>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79744/973f2399-3c43-d059-a0a8-8b1f688dc8b2.png)

リストとeachのからみは直感的なので、特に苦労することはないと思います。

# YAMLから論文リストを作る

## まずはナイーブに作る

ではいよいよYAMLで書かれた論文リストからHTMLにしましょう。とりあえず

* タイトル
* 著者
* ジャーナル情報
* (もしあれば)arXivへのリンク

を出力することにします。

RubyはYAMLを読み込めば、それがそのままハッシュとして使えるので、先程のeachの例を参考にすれば簡単に書けます。

```slim:test1.slim
doctype html
html
  - require 'yaml'
  head
    title Publication List
  body
    h1 Publication List
    ol
      - YAML.load_file("publication.yaml").each do |d|
        li :dl
          dt = d["title"]
          dd == "#{d["journal"]}, <strong>#{d["volume"]}</strong>, #{d["page"]} (#{d["year"]})"
          dd = d["author"]
          - if d.has_key? "arxiv"
            dd == "<a href=\"https://arxiv.org/abs/#{d["arxiv"]}\">arXiv:#{d["arxiv"]}</a>"
```

事前に`require 'yaml'`しておき、`YAML.load_file("publication.yaml")`でYAMLファイルをロードして、`each`でそれぞれのアイテムを表示します。`if`文も使えるので、特に難しいことはありませんが、テンプレートとしてはかなり読みづらいので、少し修正しましょう。

## ハッシュアクセスをプロパティっぽくする

いちいち`d["title"]`とか書くより、`d.title`と書きたいものです。`Hashie`を使えばできるっぽいのですが、なぜかローカルで動かなかったので、`Hash`クラスにメソッドを追加してしまいましょう。

```rb:myhash.rb
class Hash
  def method_missing(method, *args)
    key = method.to_s
    if self.has_key? key
      self[key]
    else
      false
    end
  end
def
```

存在しないメソッドを読んだら、そのメソッド名のキーがあればその値を、そうでなければ`false`を返す関数を作ってやります。これにより、slimファイルはこんな感じになります。`yaml`をrequireした後に自分で作った`myhash.rb`をrequireしています。

```slim:test2.slim
doctype html
html
  - require 'yaml'
  - require './myhash.rb'
  head
    title Publication List
  body
    h1 Publication List
    ol
      - YAML.load_file("publication.yaml").each do |d|
        li :dl
          dt = d.title
          dd == "#{d.journal}, <strong>#{d.volume}</strong>, #{d.page} (#{d.year})"
          dd = d.author
          - if d.arxiv
            dd == "<a href=\"https://arxiv.org/abs/#{d.arxiv}\">arXiv:#{d.arxiv}</a>"
```

生のハッシュっぽさが消えて、少し読みやすくなりました。

そうそう、Slimでは普通にHTMLタグを使うとエスケープされてしまいます。それを防ぐためには`=`ではなく`==`を使います。

## もう少しすっきりさせる

少し読みやすくなったものの、まだ`"#{d.journal}, <strong>#{d.volume}</strong>, #{d.page} (#{d.year})"`みたいなのがあって嫌です。これも`myhash.rb`に逃がしてしまいましょう。

```rb:myhash.rb
class Hash
  def journal_ref
    "#{journal}, <strong>#{volume}</strong>, #{page} (#{year})"
  end

  def arxiv_ref
    "<a href=\"https://arxiv.org/abs/#{arxiv}\">arXiv:#{arxiv}</a>"
  end
def
```

これで、slimファイルはこんな感じになります。

```slim:test3.slim
doctype html
html
  - require 'yaml'
  - require './myhash.rb'
  head
    title Publication List
  body
    h1 Publication List
    ol
      - YAML.load_file("publication.yaml").each do |d|
        li :dl
          dt = d.title
          dd == d.journal_ref
          dd = d.author
          - if d.arxiv
            dd == d.arxiv_ref
```

だいぶすっきりしましたね。

# まとめ

軽量テンプレート言語Slimを使って、ローカルでYAMLファイルから論文リストを作ってみました。知っている人には簡単なのでしょうが、そのものずばりのサンプルがなくてちょっと苦労したのでここに公開しておきます。

ずいぶん昔、文献リストをXMLで管理していたことがありました。その時に「RubyとYAMLでやれば楽じゃない？」と言われたのですが、当時はPerlを使っていてRubyを使えなかったのと、将来XSLTを使う予定があったので、その時はXMLを選びました。でもXSLTは(僕には)難易度が高く、そのうち第一言語がRubyになったので、結局Ruby+YAMLでなんかすることが多くなりました([YAMLで履歴書](https://qiita.com/kaityo256/items/e3884d0109223c324baf)とか)。

Slimは簡単で、かつRubyが埋め込めるので、HTMLを手書きに近い管理をしていて、かつRubyistな人(つまり私のような人)にはお勧めです。