power_assert.cr 作った

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

TL;DR

https://github.com/rosylilly/power_assert.cr

F

Failures:

  1) MyLib .major_version should be equal 1
     Failure/Error: assert MyLib.major_version == 1

         MyLib.major_version == 1
         |                   |  |
         |                   |  1
         |                   false
         2

     # ./spec/my_lib_spec.cr:6

やったぜ

power assert とは

ぐぐってくれ。

実装方法

Crystal には macro があって、大変めちゃカッコイイのだが、これをとにかく乱用して作り上げている。文字列生成周りがすごいハードコード感にあふれていて厳しいのでなんとかしたいのだが、うまくいく気がしない。

ちなみに、最初は Ruby の power-assert よろしく

assert { a == b }

という具合にとろうとしていたのだが、これだと macro 側で受ける時、

macro assert(&block)

と書くことになる。この block にわたってくるのは Macros::Block なんだけど、 Macros::Block からソースコードはとれても、その中身まで言及することが出来ない。ちなみに評価結果だけなら {{ block }} って書いときゃもらえる。

で、とにかくそのままな AST をゲットするためにはどうすれバインダーとバインバインしていたら、素直に

macro assert(expression)

と書いておけば、 Macros::Call なりが吹っ飛んでくることが判明。この時点でほぼ勝ち申した。

Macros::Call

Macros::Call には receiverargsname があるので、 power assert で出力を行う際に必要なものはほぼすべて手に入る。あとはこれをごちゃごちゃいじり回すだけなのだが、あんまりドキュメントが優しくないので少しむずかしい。気をつけよう。

a == b && c == d に対応できない問題

既知の問題として assert a == b && c == d を上手く取り扱うことが出来ない。ちなみにこれ、どういう AST が飛んでくるかというと Macros::If が飛んでくる。なんでや!?と思ったら AST になる所で変形していて

if temp = (a == b)
  c == d
end

という形で送っていますとのことでした。マジかよー。

うれしくないなぁと思いつつも、 assert に複雑な文を渡してる奴が悪いなこれは、ということであまり構わないことにしてリリースすることになりました。

今後の展望

Crystal の息が続く限り保守していくと思います。コンゴトモヨロシク。