Я хотел бы написать макрос Clojure с тестовыми тегами
, который оборачивает кучу форм и добавляет некоторые метаданные к имени каждой сложной
формы - в частности, добавить некоторые вещи в ключ : теги
, чтобы я мог играть с помощью
Одна очевидная реализация для with-test- тэгов
состоит в рекурсивном обходе всего тела, модифицируя каждую дефестированную
форму, как я ее нахожу. Но я недавно прочитал Let Over Lambda , и он делает хороший пункт: вместо того, чтобы самостоятельно ходить по коду, просто оберните код в макролет
и дайте компилятору пройтись по нему за вас. Что-то вроде:
(defmacro with-test-tags [tags & body]
`(macrolet [(~'deftest [name# & more#]
`(~'~'deftest ~(vary-meta name# update-in [:tags] (fnil into []) ~tags)
~@more#))]
(do ~@body)))
(with-test-tags [:a :b]
(deftest x (...do tests...)))
Это имеет очевидную проблему, однако, что ловкий
макрос продолжает рекурсивно расширяться навсегда. Вместо этого я мог бы расширить его до clojure.test/deftest
, избегая, таким образом, дальнейших рекурсивных расширений, но тогда я не могу с пользой вложить экземпляры с test- тэгов
для маркировки подгрупп тестов.
На данный момент, особенно для такого простого, как ловкий
, похоже, что сама ходьба по коду будет проще. Но интересно, знает ли кто-нибудь технику написания макроса, которая «слегка модифицирует» определенные подэкспрессии, не рекурсивно вечно.
Для любопытства: я рассмотрел некоторые другие подходы, такие как наличие binding
-binding var, который я установил, как я иду вверх и вниз код, и использование этого var, когда я наконец вижу deftest
, но так как каждый макрос возвращает только одно расширение, его привязки не будут на месте для следующего вызова макроэкспанда.
Я сделал постшаговую реализацию только сейчас, и хотя она работает, она не уважает специальные формы, такие как цитата
- она расширяется и внутри них.
(defmacro with-test-tags [tags & body]
(cons `do
(postwalk (fn [form]
(if (and (seq? form)
(symbol? (first form))
(= "deftest" (name (first form))))
(seq (update-in (vec form) [1]
vary-meta update-in [:tags] (fnil into []) tags))
form))
body)))
(Кроме того, извините за возможный шум на теге common-lisp - я подумал, что вы можете помочь с более странными макро вещами даже с минимальным опытом Клоюре.)
-121--813123-Кто-нибудь знает, как добавить пользовательское имя к свойству в модели Django? Например, если у меня есть свойство
@property
def my_property(self):
return u'Returns some calculations'
и я показываю его в admin в виде столбца:
class MyAdmin(admin.ModelAdmin):
list_display=['my_property',]
Тогда я вижу столбец «My property» и то, что мне нужно, это столбец «Property X». Я пытался с my_property.short_description и my_property.verbose_name, ничего из этого не вышло.