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

  • 12
    Like
  • 0
    Comment
More than 1 year has passed since last update.

Slim は Ruby 製テンプレートシステム。インデント記法で HTML や XML を簡潔に記述できる。

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

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

無駄な do

修正前
- 3.times do
  p わん

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

修正後
- 3.times
  p わん

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

修正前
td colspan="2" foo

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

修正後
td colspan=2 foo

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

id 属性はナンバー記号で

修正前
p id="signature" Eugene

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

修正後
p#singnature Eugene

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

p id="foo:bar" Hoge

などと書くしかない。

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

p#foo_bar-baz Hoge

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

修正前
p class="foo bar" hoge

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

修正後
p.foo.bar hoge

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

p#foo.bar.baz hoge

クラス属性のピリオド記法と普通の記法は混在できる。

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

これは,

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

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

クラス属性の二つの書き方は混在できるので,

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

でいい。

拙文「Slim の属性値指定のちょっといい話」にもう少し詳しいことを書いた。

#{ } を使おう

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

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

修正後
p 氏名:#{name}

次の形も OK。

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

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

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

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

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

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

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

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

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

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

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

修正前
header
  h1 タイトル

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

修正前
header: h1 タイトル

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

参考:inline tags

論理属性はどう書けば

修正前
input type="text" name="keyword" autofocus="autofocus"

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

修正後
input type="text" name="keyword" autofocus=""
修正後
input type="text" name="keyword" autofocus=true
修正後
input[type="text" name="keyword" autofocus]

詳しくは拙文「Slim で autofocus のような論理属性を書く」をどうぞ。

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

修正前
div#wrapper

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

修正後
#wrapper

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

修正前
div.signature
修正後
.signature

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

.nav
.footer

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

nav
footer

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

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

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

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

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

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

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

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

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

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

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

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

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

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

適当なヘルパーメソッドを作れば,以下のように < などの実体参照化を書かなくて済むようになる。

修正後
== pre
  |
    <div>
      foo
    </div>

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

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

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

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

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

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