macroexpand-1
をREPLで作業していないときにClojureマクロをテストする適切な方法は何ですか?REPLの代わりにソースファイルからmacroexpand-1を使用するには
答えて
我々は任意の値に3を追加するマクロテストしたいとします
(defmacro iiinc [x]
`(+ 3 ~x))
よりもむしろREPLでの作業を、私は通常のコードを開発するために私の好きなテキストエディタ/ IDEを使用することを好む、とthe lein test-refresh
pluginを使用私のユニットテストを継続的に実行するしかし、新しいマクロを繰り返し開発するためにmacroexpand-1
を使用しようとすると、これは機能しません。
問題はmacroexpand-1
とdeftest
マクロの間に多少の矛盾があるようです。だから、解決策は(deftest ...)
フォームの中にmacroexpand-1
を使用しないことです。しかし、ユニットテストのソースファイルにまだ残っていても、deftest
の外ではうまく動作します。ここでは例です:
; source file tst.clj.core
(newline)
(println "This works when not in (deftest ...)")
(println "(macroexpand-1 '(iiinc 2)) =>" (macroexpand-1 '(iiinc 2)))
(deftest t-stuff
(newline)
(println "But it is broken inside (deftest ...)")
(println "(macroexpand-1 '(iiinc 2)) =>" (macroexpand-1 '(iiinc 2)))
(newline)
(println "However, we can use the macro itself fine in our tests")
(println " (iiinc 2) =>" (iiinc 2))
(is (= 5 (iiinc 2)))) ; unit test works fine
上記の結果は次のとおりです。
This works when not in (deftest ...)
(macroexpand-1 '(iiinc 2)) => (clojure.core/+ 3 2)
Testing tst.clj.core
But it is broken inside (deftest ...)
(macroexpand-1 '(iiinc 2)) => (iiinc 2)
However, we can use the macro itself fine in our tests
(iiinc 2) => 5
Ran 1 tests containing 1 assertions.
0 failures, 0 errors.
問題が*ns*
がバインドされている間deftest
の外あなたの表現は、コンパイル時に実行されていることである、との内deftest
これらは実行時に後で実行されますが、*ns*
がバインドされていません。
なぜこの点が重要ですか? macroexpand
は、現在の名前空間のシンボルiiinc
を解決して、マクロであるかどうかを判断し、それがマクロである場合にその定義を見つけて呼び出す必要があるためです。コンパイル時にmacroexpand
が動作しているが、実行時には動作していないことがわかります。
解決策は何ですか。確かにコンパイル時にテストを実行しないでください!代わりに、フォームの名前空間を適切に修飾して、*ns*
のコンパイル時の利便性に依存しないようにする必要があります。使用する:あなたは、しかし、適切なソリューションは、後の評価のために意図されているフォームを引用するときに常にはちょうどあなたがマクロを書くときのように、何をすべきかを行うことです
(deftest t-stuff
(println "(macroexpand-1 '(my.ns/iiinc 2)) =>" (macroexpand-1 '(my.ns/iiinc 2)))))
を書き込むことによって、手動でこれを行うことができます構文引用符ではなく、通常の引用符ではありません。コンパイラがコンパイル時に意図した名前空間を見つけ出し、実行時にまだそれが存在するようにフォームに挿入します:
(deftest t-stuff
(println "(macroexpand-1 `(iiinc 2)) =>" (macroexpand-1 `(iiinc 2)))))
- 1. ソースファイルの代わりにiPhoneプロジェクトでコンパイルされたリソースを使用
- 2. divの代わりにdivの代わりにJSのプリペンドを使用する
- 3. トーストを使用する代わりに
- 4. 代わりにパーシャルビューコントローラを使用する
- 5. pxにマイナスを使用する代わりに使用する
- 6. 代わりに使用するフォント
- 7. //使用する代わりに、プロトコル://
- 8. urllib.request.urlretrieveの代わりに使用するコマンドは何ですか?
- 9. RxSwiftのVariableの代わりにBehaviorRelayを使用するには?
- 10. Railsの代わりにsend_fileの代替ファイルを使用する
- 11. scalaのアンモナイトは、utiliteのデフォルトとしてammonite.utilの代わりにscala.utilを使用するにはどうしたらいいですか? 「公式」ScalaのREPLで
- 12. カンマの代わりにJOINを使用するには?
- 13. dbの代わりにfileを使用するには?
- 14. Geb:Selenium Webdriverの代わりにMarionetteを使用するには?
- 15. Laravel - move()の代わりにcopy()を使用するには
- 16. Jade in Expressの代わりにアンダースコアテンプレートを使用するには?
- 17. httpsの代わりにhttpを使用するには
- 18. atdの代わりにcrondを使用するには?
- 19. file_get_contentsの代わりにCURLを使用するには?
- 20. アクティビティの代わりにActivityCompatを使用するには
- 21. loginPopupの代わりにloginRedirectを使用するには?
- 22. jqueryで$の代わりにキーワードを使用するには?
- 23. Apache Httpclientの代わりにSpring RestTemplateを使用するには?
- 24. HttpSecurityの代わりにanotationを使用するには?
- 25. ApplyToStateMachineの代わりにSemanticallyAdvisedMethodKindsを使用するには?
- 26. put putをput intの代わりに使用するには
- 27. クラスの代わりにコレクションを使用
- 28. Submitの代わりにButtonを使用
- 29. expand.gridの代わりにouterを使用
- 30. VARCHAR2の代わりにCLOBを使用
良い答えですが、この内容の一部はあなた自身が質問していることは、あなたがしようとしていることが機能していないことを説明しているからです。この答えのコンテキストがなければ、誰もあなたの非常に省略された質問に答えることができませんでした。 – amalloy