Ошибка оценки символа Clojure

Итак, у меня сейчас есть этот код:

(ns contact-form.core
  (:gen-class))

(def foo "Hello World!")

(defn some-func [a-symbol]
  (println (str a-symbol "'s value is: " (eval a-symbol))))

(defn -main [& args]
  (some-func 'foo))

После выполнения C-c C-k в Emacs я получаю следующий вывод:

contact-form.core> (-main)
foo's value is: Hello World!
nil

Но когда я делаю lein uberjar и запускаю полученный файл jar, я получаю сообщение об ошибке:

Exception in thread "main" java.lang.RuntimeException: Unable to resolve symbol: foo in this context, compiling:(NO_SOURCE_PATH:0)
    at clojure.lang.Compiler.analyze(Compiler.java:6235)
    at clojure.lang.Compiler.analyze(Compiler.java:6177)
    at clojure.lang.Compiler.eval(Compiler.java:6469)
    at clojure.lang.Compiler.eval(Compiler.java:6431)
    at clojure.core$eval.invoke(core.clj:2795)
    at contact_form.core$some_func.invoke(core.clj:7)
    at contact_form.core$_main.doInvoke(core.clj:10)
    at clojure.lang.RestFn.invoke(RestFn.java:397)
    at clojure.lang.AFn.applyToHelper(AFn.java:159)
    at clojure.lang.RestFn.applyTo(RestFn.java:132)
    at contact_form.core.main(Unknown Source)
Caused by: java.lang.RuntimeException: Unable to resolve symbol: foo in this context
    at clojure.lang.Util.runtimeException(Util.java:156)
    at clojure.lang.Compiler.resolveIn(Compiler.java:6720)
    at clojure.lang.Compiler.resolve(Compiler.java:6664)
    at clojure.lang.Compiler.analyzeSymbol(Compiler.java:6625)
    at clojure.lang.Compiler.analyze(Compiler.java:6198)
    ... 10 more

Итак, у меня есть два вопроса:

  1. Почему uberjar не работает точно так же, как REPL?
  2. Что я могу сделать, чтобы решить эту проблему?

person wrongusername    schedule 15.01.2012    source источник


Ответы (1)


<сильный>1. Почему uberjar работает не так, как REPL?

Причиной ошибки «NO_SOURCE_PATH» является то, что вы в настоящее время не находитесь в пространстве имен, которое определило «foo.

Для иллюстрации: если я оцениваю ваш код в своем REPL и выполняю его, он помещает меня в пространство имен contact-form.core, как и следовало ожидать, потому что (ns contact-form.core) оценивается REPL, но если я переключаюсь на пространство имен user и вызываю -main, я могу создать то же самое. ошибка:

contact-form.core=> (-main)
foo's value is: Hello World!
nil
contact-form.core=> (ns user)
nil
user=> (contact-form.core/-main)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: foo in this context, compiling:(NO_SOURCE_PATH:120) 
user=> 

Таким образом, указание вашей точки входа main для автономного выполнения uberjar (вне REPL) эквивалентно вызову (contact-form.core/-main) из пространства имен по умолчанию в вашей банке, которое равно clojure.core, потому что (ns contact-form.core) не оценивалось. Результат: main можно выполнить с полным путем (в пространстве имен) к функции, но ни один из символов из contact-form.core недоступен в текущем пространстве имен по умолчанию.

<сильный>2. Исправление

Решение состояло бы в том, чтобы сначала явно переключиться на ваше пространство имен.:

(defn -main [& args]
  (use 'contact-form.core)
  (some-func 'foo))
person Scott    schedule 15.01.2012
comment
use делает гораздо больше, чем просто переключает пространства имен. Я бы порекомендовал (binding [*ns* (the-ns 'contact-form.core)] (some-func 'foo)) - person Chouser; 26.03.2013
comment
@chouser Отлично! Считайте меня назидательным, сэр! :-) - person Scott; 27.03.2013