Как извлечь метаданные из var, когда функция возвращает свой символ? - PullRequest
0 голосов
/ 06 мая 2018

Я использую re-frame с spec для проверки app-db, очень как в примере todomvc .

Когда пользователь вводит недопустимую запись, я использую s/explain-data (в перехватчике перекадровых данных), чтобы вернуть карту problems с наименованием :pred, что вызвало ошибку проверки. Этот предикат является символом типа project.db/validation-function.

Моя функция проверки имеет метаданные, которые доступны из отчета с помощью:

(meta #'project.db/validation-function)

Определение функции (в пространстве имен project.db) выглядит следующим образом:

(defn validation-function
  "docstring..."
  {:error-message "error message"}
  [param]
  (function-body...)

Проблема в том, что я не могу понять, как получить метаданные динамически (работая в project.events пространстве имен), например:

(let [explain-data (s/explain-data spec db)
      pred (->> (:cljs.spec.alpha/problems explain-data) first :pred)
      msg (what-goes-here? pred)]
  msg)

Я пробовал следующие вещи вместо what-goes-here?:

  • symbol? т true
  • str т "project.db/validation-function"
  • meta т nil
  • var выдает ошибку времени компиляции "Невозможно разрешить var: p1__46744 # в этом контексте"

Я думаю, что проблема в том, что я получаю символ, но мне нужна переменная, на которую он ссылается, - это место, где живут метаданные.

Я пытался использовать макрос, но на самом деле не знаю, что я делаю. * * * * * * * * * * * * * * * * * * * * * * * * * - самое близкое обсуждение, которое я мог найти, но я не мог решить это.

Помощь!

Ответы [ 2 ]

0 голосов
/ 07 мая 2018

В общем, вы не можете сделать это, потому что переменные не реализованы в ClojureScript.

С https://clojurescript.org/about/differences#_special_forms:

  • вар ноты
    • Вары не реализуются во время выполнения. Когда компилятор встречает специальную форму var, он генерирует экземпляр Var, отражающий время компиляции метаданные. (Это удовлетворяет многим распространенным статическим случаям использования.)

На REPL, когда вы оцениваете

(meta #'project.db/validation-function)

это то же самое, что и

(meta (var project.db/validation-function))

и при компиляции (var project.db/validation-function) генерируется код JavaScript для создания экземпляра cljs.core/Var, который содержит, помимо прочего, данные, которые вы можете получить с помощью meta. Если вам интересно, соответствующий анализатор и компилятор код поучителен.

Таким образом, если (var project.db/validation-function) (или эквивалент читателя #'project.db/validation-function) не существует нигде в вашем исходном коде (или косвенно с помощью чего-то вроде ns-publics), эти данные не будут доступны во время выполнения.

Пропуск var reification - хорошая вещь при оптимизации размера кода. Если вы включите опцию : repl-verbose REPL, вы увидите, что выражение (var project.db/validation-function) испускает значительное количество кода JavaScript.

При работе с def s в REPL, компилятор переносит достаточное количество метаданных анализа, и все делается - например, когда оценки def форм возвращают var, а не значение - во имя создания иллюзии, которая вы работаете с воплощенными переменами Clojure. Но эта иллюзия преднамеренно испаряется при создании кода для производственной доставки, сохраняя только существенное поведение во время выполнения.

0 голосов
/ 06 мая 2018

edit: извините, я не увидел, что var не работает для вас. Все еще работаем над этим ...

Вам необходимо окружить символ project.db/validation-function var . Это позволит преобразовать символ в переменную.

Так что what-goes-here? должно быть

(defn what-goes-here? [pred]
  (var pred))
...