Jan Thomä
Jan Thomä

Reputation: 13604

How do i make macros available to load-file in Clojure?

Suppose you have the following code:

(ns foo)

(defmacro defproject [project-name version & args]
 ...
)

(defn read-project ([file]
    (load-file file)))

Update: The full code can be found at https://github.com/derkork/intellij-leiningen-plugin/blob/master/src/de/janthomae/leiningenplugin/leiningen/LeiningenProjectFile.clj

Now i call read-project on a file "project.clj" that has the following contents:

(defproject de.janthomae/leiningenplugin "1.0.0-SNAPSHOT"
  ...
)

And I get the following error message

java.lang.Exception: Unable to resolve symbol: defproject in this context (project.clj:1)
 at clojure.lang.Compiler.analyze(Compiler.java:4420)
 at clojure.lang.Compiler.analyze(Compiler.java:4366)
 at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:2828)
 at clojure.lang.Compiler.analyzeSeq(Compiler.java:4594)
 at clojure.lang.Compiler.analyze(Compiler.java:4405)
 at clojure.lang.Compiler.analyze(Compiler.java:4366)

That tells me it doesn't find my defproject macro. And I am totally clueless why it is that way, since the macro is defined just a few lines ahead. Do I need to export it somehow so it can be seen from files which are loaded using load-file?

Upvotes: 4

Views: 453

Answers (1)

koddo
koddo

Reputation: 3408

project.clj doesn't indeed know where to look for foo/defproject. So if you are on repl, you can do

user> (in-ns 'foo)
foo> (read-project "project.clj")

This will run code from project.clj inside foo namespace, where defproject is defined. Or you can place (in-ns 'foo) inside project.clj. Result will be the same.

But you can also write something like this in project.clj:

(foo/defproject ...)

This will call defproject inside your current namespace when you run (foo/read-project "project.clj").


update

from test_uberjar.clj:

(def project (binding [*ns* (the-ns 'leiningen.core)]
               (read-project "test_projects/sample_no_aot/project.clj")))

from test_deps.clj:

(:use [leiningen.core :only [read-project defproject]] ...)

So, defproject is always available when doing load-file.

Upvotes: 1

Related Questions