Помощь в разработке небольшого макроса модульного теста в Clojure - PullRequest
6 голосов
/ 08 августа 2009

у меня есть небольшой макрос для модульного теста

  (defmacro is [expr value]
        `(if (= ~expr ~value)
             'yes
             (println "Expected " ~value "In" ~expr "But Evaluated to" ~expr)))

Как правильно написать сообщение об ошибке? Прямо сейчас это дает

Clojure 1.0.0-
1:1 user=> (is (+ 2 2) 4)
user/yes
1:2 user=> (is (+ 2 2) 5)
Expected  5 In 4 But Evaluated to 4

Я хочу оценить выражение и сказать «да», если оцененное значение соответствует ожидаемому, иначе выведите ошибку с выражением вместо значения после «In».

Ответы [ 2 ]

11 голосов
/ 08 августа 2009

Оригинальный ответ

Я думаю, это то, что вы ищете:

(defmacro is [expr value]
    `(if (= ~expr ~value)
         true
         (println "Expected " ~value "In" (str (quote ~expr)) 
                  "But Evaluated to" ~expr)))

то, что делает (quote ~expr), - это перенос s-выражения, представленного expr, в ваш «шаблон», но предотвращает его оценку, а затем применение str к неоцененному s-выражению превращает его в строку для объединения с другими строками сообщения об ошибке. Итак:

user=> (is (+ 2 2) 5)
Expected  5 In (+ 2 2) But Evaluated to 4

производит желаемое поведение.

Вместо того, чтобы использовать 'yes для сообщения об успехе, вы можете просто использовать true в качестве отчета об успешном прохождении теста, давая:

user=> (is (+ 2 2) 4)
true

и избежание проблемы возврата 'yes в качестве квалифицированного символа. Если по какой-то причине вам нужен символ, вы можете сделать ключевое слово:

(defmacro is [expr value]
    `(if (= ~expr ~value)
         :yes
         (println "Expected " ~value "In" (str (quote ~expr)) 
                  "But Evaluated to" ~expr)))


user=> (is (+ 2 2) 4)
:yes



Ответ на вопрос, заданный в комментариях

Вы спрашивали в комментариях:

Извините, я должен был быть более ясным в своем вопросе. Какая разница между символом и ключевым словом в этом случае?

Рассмотрим исходное определение (с исправлением, чтобы ошибка возвращалась так, как вы хотели):

(defmacro is [expr value]
`(if (= ~expr ~value)
     'yes
     (println "Expected " ~value "In" (str (quote ~expr)) 
              "But Evaluated to" ~expr)))

Я полагаю, что вы хотите, чтобы 'yes думал, что вы можете использовать его для тестирования против 'yes в других контекстах (такие тесты часто встречаются во вводных текстах для lisp). Но 'yes используется в вашем определении макроса, он возвращает квалифицированный символ при прохождении теста:

user=> (is (+ 2 2) 4)
user/yes

Так вот, это не то, что вы хотели бы. Представь, что ты сказал это:

user=> (= 'yes (is (+ 2 2) 4))
false

Чтобы получить true ответ, вы должны будете сказать это (используя синтаксическую кавычку):

user=> (= `yes (is (+ 2 2) 4))
true

Если вы определили свой макрос для возврата :yes, то вы получите возврат, который можно проверить, без необходимости синтаксического цитирования объекта, который вы используете для проверки:

user=> (= :yes (is (+ 2 2) 4))
true

Но это все излишне, потому что вас действительно интересует, вернет ли (+ 2 2) 4, т. Е. Является ли ваше утверждение true или false, а не равно, равно ли 'yes `` yes or 'yes ; you can just have it return true` и избегайте этого шага проверки (в реальном мире).

В любом случае, чтобы понять, что такое квалифицированные символы, вам нужно прочитать документы на считывателе clojure и этот ответ SO, объясняющий входы и выходы символов в clojure .

0 голосов
/ 09 августа 2009

Если у вас есть макропечать «Есть», у вас возникает проблема с перерезанием. Пусть макрос 'Is' возвращает список, который содержит что-то вроде этого: Возможно, у вас есть макрос DefTest для агрегирования ваших утверждений. Вот где вы должны написать свой ответ.

...