1. rosylilly

    Posted

    rosylilly
Changes in title
+power_assert.cr 作った
Changes in tags
+crystal
0.7.4
Changes in body
Source | HTML | Preview
@@ -0,0 +1,74 @@
+# 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 よろしく
+
+```rb
+assert { a == b }
+```
+
+という具合にとろうとしていたのだが、これだと macro 側で受ける時、
+
+```
+macro assert(&block)
+```
+
+と書くことになるのだが、この `block` にわたってくるのは [Macros::Block](http://crystal-lang.org/api/Macros/Block.html) になっているのだが、 `Macros::Block` からソースコードはとれても、その中身まで言及することが出来ない。ちなみに評価結果だけなら `{{ block }}` って書いときゃもらえる。
+
+で、とにかくそのままな AST をゲットするためにはどうすれバインダーとバインバインしていたら、素直に
+
+```
+macro assert(expression)
+```
+
+と書いておけば、 `Macros::Call` なりが吹っ飛んでくることが判明。この時点でほぼ勝ち申した。
+
+## Macros::Call
+
+[Macros::Call](http://crystal-lang.org/api/Macros/Call.html) には `receiver` と `args` と `name` があるので、 power assert で出力を行う際に必要なものはほぼすべて手に入る。あとはこれをごちゃごちゃいじり回すだけなのだが、あんまりドキュメントが優しくないので少しむずかしい。気をつけよう。
+
+## `a == b && c == d` に対応できない問題
+
+既知の問題として `assert a == b && c == d` を上手く取り扱うことが出来ない。ちなみにこれ、どういう AST が飛んでくるかというと `Macros::If` が飛んでくる。なんでや!?と思ったら AST になる所で変形していて
+
+```crystal
+if temp = (a == b)
+ c == d
+end
+```
+
+という形で送っていますとのことでした。マジかよー。
+
+うれしくないなぁと思いつつも、 assert に複雑な文を渡してる奴が悪いなこれは、ということであまり構わないことにしてリリースすることになりました。
+
+## 今後の展望
+
+Crystal の息が続く限り保守していくと思います。コンゴトモヨロシク。