ハトネコエ Web がくしゅうちょう

プログラミングやサーバー・Web制作、チームマネジメントなど得た技術のまとめ

haml2slim を改善して haml から slim への移行をしやすくしました

動機

haml から slim へ移行しようとして haml2slim を使おうとしたものの、
上手く変換されず自力で直さないといけないところが多い状態でした。

最初は「リファクタリングする箇所も多いから、一行ずつ注視して自力で変更していけばいいか」と思っていたんですが、
同じところを何度も直していると、ミスも起こるし時間もかかるしで、
haml2slim 自体を直すのが効率良いなと気付きまして、以下のリポジトリを作りました。

気が向いたら本家にプルリクエストを送る可能性もありますが、
2014年のプルリクエストが2022年の今なお放置されている状態で、
希望が薄いので作成する可能性は低いです……。

フォーク元のベースとして、そのプルリクエストである https://github.com/a2ikm/haml2slim/tree/ruby19-hash を使わせていただきました。
ありがとうございます。

本家の haml2slim から変更したこと

https://github.com/nekonenene/haml2slim/compare/9d79c40...4ce0c64

1. .gitignore を調整

Gemfile.lock.bundle が gitignore の対象になっていたので削除しました。
逆に vendor/bundle が gitignore の対象になっていなかったので追加しています。

関連する差分: https://github.com/nekonenene/haml2slim/compare/6490994...bef06a9

2. minitest を Gemfile に追加

minitest をテストで使っているのに Gemfile に指定がされていなかったので追加しています。
また、 minitest の現在のバージョンでは deprecated になっている記法を修正しました。

関連する差分: https://github.com/nekonenene/haml2slim/commit/dfc0d919433ee93af21853e8623409a14e11d755

3. Ruby 1.9 以降での Hash Syntax に対応

私がベースに使ったリポジトリの作者さんのプルリクエスト ( https://github.com/slim-template/haml2slim/pull/23 ) で
Ruby 1.9 以降での Hash Syntax に対応しているのですが、使ってみて、
これにはまだ不足があることに気付きました。

%button{data: { confirm: "OK?" }}

のような data 属性の変換に対応していないことです。

また、Hash Syntax に関わらず、
キーや値が single quotations ( ' )で囲まれている場合や、
値が Symbol である場合や、値にスペースが含まれる場合に、
正常に変換されていなかったので修正しました。

関連する差分:

4. 文字列内の変数展開の修正

%span
  #{1 + 1}

span
  #{1 + 1}

と変換されるようになっていましたが、これでは2行目でエラーを吐いてしまうので、

span
  | #{1 + 1}

と変換されるように修正しました。

また、

%span 次は#{1 + 2}回目です

がパースの関係で

span 次は# 1 + 2 回目です

のように変換されてしまう問題も修正しました。

関連する差分: https://github.com/nekonenene/haml2slim/compare/77a5072...17acd8d

5. ( , [ , { は HTML エスケープするように

%span (#{aaa})

haml では問題なく、文字列としてカッコがレンダリングされるのですが、

span (#{aaa})

と slim でなっている場合、カッコは Attributes Wrapper と思われてしまい
パースしようとするのですが、上手くいかずにパースエラーが起こってしまいます。

思わぬエラーの要因になるので、
HTMLタグのすぐ後ろに ( , [ , { がある場合には HTML エスケープをおこなうようにしました。
不格好ではありますが、エラーが起こるよりは断然マシです。

関連する差分: https://github.com/nekonenene/haml2slim/commit/4ce0c640b2d0e580e9c3a5274d5be535ce8117d0

6. Vue の変数展開に対応

Rails と Vue.js を組み合わせて使っている場合のみに関係する話ですが、

%span {{ 1 + 1 }}

のように Vue の変数展開を書いているものを、

span {{ 1 + 1 }}

のように slim 向けに直しても上手くいってくれません。
(参考: https://qiita.com/Take-st/items/4bb3ebd25f361276c4c4#comment-ae32b23dae3266a24e54

span
  | {{ 1 + 1 }}

と変換されるようにしてみました。

関連する差分: https://github.com/nekonenene/haml2slim/commit/f23bdc1ee282919a57ad5f65cb4f448ea53c35c4

7. HTMLタグの後ろにスペースを付ける

haml では

%span= Time.now

のように、HTMLタグのすぐ後ろに = を付けるのが一般的ですが、
slim では

span = Time.now

のようにHTMLタグの後ろにスペースを付けるのが一般的です。
( http://slim-lang.com )
そのように変換されるように調整しました。

関連する差分: https://github.com/nekonenene/haml2slim/compare/17acd8d...18b334e

解決していない問題

これで多くの問題が片付きましたが、これでもまだ全てではありません。
私の気付いているものですと、

= render partial: "dummy",
  collection: @some_variable,
  as: :some_variable

のように複数行に渡るものが

= render partial: "dummy",
  | collection: @some_variable,
  | as: :some_variable

と変換されてしまい、パースエラーになってしまう問題を残しています。
あまりあるケースではないのと、対応が面倒そうに感じるので放置しています。

おわりに

これで haml から slim への移行作業が大幅に効率化されました。

やはり、自力で繰り返しおこなう作業は、コンピューターに任せるのがなによりですね。

github.com