Slim コードのリファクタリング

[Slim](http://slim-lang.com/) は Ruby 製テンプレートシステム。インデント記法で HTML や XML を簡潔に記述できる。

この記事は，「Slim をなんとなく使っている」という人向けに，既存の Slim コードを見直してみようと呼びかけるもの。

Slim だってリファクタリング（結果を変えずに記述を合理化）すれば可読性や保守性が向上するはず。

# 無駄な do

```slim:修正前
- 3.times do
  p わん
```

ブロックパラメーターが無いなら  `do` は省略できる。

```slim:修正後
- 3.times
  p わん
```

# 属性値は文字列化してくれる

```slim:修正前
td colspan="2" foo
```

これは単に次のように書ける。

```slim:修正後
td colspan=2 foo
```

`colspan=` の右には Ruby の式を書くことができて，式の評価結果は `to_s` メソッドで文字列化されるため。

# id 属性はナンバー記号で

```slim:修正前
p id="signature" Eugene
```

`id` 属性は便利な `#` 記法がある。

```slim:修正後
p#singnature Eugene
```

ただし，id が「`:`」などを含んでいる場合はこの記法は使えないので

```slim
p id="foo:bar" Hoge
```

などと書くしかない。

一方，アンダースコアやハイフンは使っても大丈夫。

```slim
p#foo_bar-baz Hoge
```

## 追記：2020-05-23

2020 年 5 月 8 日にリリースされた slim 4.1.0 で，ナンバー記号表記の id に `:` などが使えるようになった。つまり，このバージョン以降なら

```slim
p#foo:bar Hoge
```

で期待どおり

```html
<p id="foo:bar">Hoge</p>
```

が得られる。
id だけでなくクラスも同様。

詳細は以下参照：
[Add support for slashes w/ digits and colons in class / id names by thewatts · Pull Request #841 · slim-template/slim](https://github.com/slim-template/slim/pull/841)

# class 属性はピリオド記法でいくつでも

```slim:修正前
p class="foo bar" hoge
```

`class` 属性もピリオド記法で書ける。クラス名が複数ある場合はピリオド記法を重ねればよい。

```slim:修正後
p.foo.bar hoge
```

ナンバー記号との併用もできる。

```slim
p#foo.bar.baz hoge
```

# クラス属性のピリオド記法と普通の記法は混在可能

```slim:修正前
p class=(counter.zero? ? "foo noitem" : "foo")
```

これは，

- `foo` クラスは必ずつける。
- `counter` がゼロのときのみ `noitem` クラスをつける。

という意図だが，こんな分かりづらい書き方をすることはない。

クラス属性の二つの書き方は混在させられるので，

```slim:修正後
p.foo class=("noitem" if counter.zero?)
```

でいい。

拙文「[Slim の属性値指定のちょっといい話 - Qiita](http://qiita.com/scivola/items/a182fc613bc9703d8ec8)」にもう少し詳しいことを書いた。


# `#{ }` を使おう

```slim:修正前
p = "氏名：#{name}"
```

式展開を書くためにわざわざ文字列オブジェクトにして `=` で入れなくても，そのまま書けるって。

```slim:修正後
p 氏名：#{name}
```

次の形も OK。

```slim:修正後
p
  | 氏名：#{name}
```

ただ，ちょっと注意して欲しい。Slim の `#{ }` は，Ruby の式展開とは違って，中身の評価結果を文字列化して埋め込むときに**エスケープ**する。

だからこの例で，修正前と修正後は等価ではない。

もっとも，この例ではエスケープするべきだろうから，修正後のほうが望ましいだろうけど。

もし，エスケープして欲しくない式を埋め込みたいなら `#{{ }}` を使おう。


# HTML タグを直に書いたほうが簡潔なことも

```slim:修正前
p
  | 畳み込みには
  code inject
  | メソッドを使う。
```

インライン要素は，HTML タグを直接記述したほうが簡潔なこともある。

```slim:修正後
p 畳み込みには<code>inject</code>メソッドを使う。
```

このあたりは臨機応変に。
タグの直接記述のほうが良さそうに感じたら躊躇しなくていい。


# 子要素が一つなら階層構造が 1 行で書ける

```slim:修正前
header
  h1 タイトル
```

`header` の子要素は `h1` ただ一つ。このような場合，コロン `:` を使って 1 行で階層構造を記述することができる。

```slim:修正前
header: h1 タイトル
```

何階層でもネストできる。
コロンのあとのスペースは省略できない。

参考：[inline tags](http://www.rubydoc.info/gems/slim/frames#Inline_tags) 


# 論理属性はどう書けば

```slim:修正前
input type="text" name="keyword" autofocus="autofocus"
```

短くするなら，以下のようないくつかの書き方ができる。

```slim:修正後
input type="text" name="keyword" autofocus=""
```

```slim:修正後
input type="text" name="keyword" autofocus=true
```

```slim:修正後
input[type="text" name="keyword" autofocus]
```

詳しくは拙文「[Slim で autofocus のような論理属性を書く - Qiita](http://qiita.com/scivola/items/8f6de92a03d7a8246cc0)」をどうぞ。


# id か class のある div は要素名省略

```slim:修正前
div#wrapper
```

`id` 属性を持つ `div` は，要素名を省略することができる。

```slim:修正後
#wrapper
```

`class` 属性を持つ `div` も要素名を省略することができる。

```slim:修正前
div.signature
```

```slim:修正後
.signature
```

ただ，こちらは好みが分かれるかも知れない。ピリオドはインパクトに欠けるので，

```slim
.nav
```

```slim
.footer
```

のように要素名と紛らわしいクラス名を付けた場合，

```slim
nav
```

```slim
footer
```

と読み誤るかも知れない。

# ある要素以下をコメントアウト

```slim:修正前
header
  /h1.image-title
  /  img src="title.png" alt="タイトル"
  h1 タイトル
```

このような場合，`img` は `h1.image-title` より字下げしてあるので，スラッシュを置かなくても期待どおり消えてくれる。

```slim:修正後
header
  /h1.image-title
    img src="title.png" alt="タイトル"
  h1 タイトル
```

詳しくは拙文「[Slim で一部をまるごとコメントアウトする方法 - Qiita](https://qiita.com/scivola/items/c9a79c13688a3444a3cc)」をどうぞ。


# 属性値がヘルパーメソッド呼び出しだけ

```slim:修正前
script src="#{url_to 'js/common.js'}"
```

この例では，`src` 属性の値として，`url_to` メソッドを呼び出している。（ちなみに Rails の例ではない）

しかし，わざわざ文字列リテラルの式展開の形にする必要は無い。Slim では属性値のところに Ruby の式が書けるので，以下でいい。

```slim:修正後
script src=url_to('js/common.js')
```

修正前では省略できていたメソッド引数の `( )` が省略できなくなったが，それでもこちらのほうが簡素でいいと思う。

# ヘルパーを使って無駄な手動エスケープをやめよう

```slim:修正前
pre
  |
    &lt;div&gt;
      foo
    &lt;/div&gt;
```

こんなコード誰も見たくないしメンテしたくないよね。

適当なヘルパーメソッドを作れば，以下のように `<` などを文字参照（`&lt;` など）の形で書かなくて済むようになる。

```slim:修正後
== pre
  |
    <div>
      foo
    </div>
```

ヘルパーメソッドのつくり方は，Rails なのか何なのかによってちょっと違うとしても，だいたいこんな感じ：

```rb
def pre
  %|<pre>#{Temple::Utils.escape_html(yield)}</pre>|
end
```

ここで，`Temple::Utils.escape_html` というのは，slim gem が依存している temple gem が持っている HTML エスケープのメソッドです。好きなメソッドに置き換えてください。

上記の例では，`pre` メソッドには

```rb
{"<div>\n  froo\n</div>"}
```

というブロックが与えられたのと同じになる。インデントも期待どおりになっている。