Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable passed to macro gets resolved in wrong namespace?

The Noir macro defpage is giving me a little bit of trouble. I am trying to construct a call similar to this:

(defpage [:post "some/url"] [data]
  ;; some stuff...
  )

However, instead of using the keyword :post I would like to use a variable, like this:

(def my-method :post)
(defpage [my-method "some/url"] [data]
  ;; some stuff...
  )

The problem is that when the macro expands, it wants to resolve the variable my-method in the compojure.core namespace instead of my own, giving me the error:

No such var: compojure.core/MY-METHOD

How can I force my-method to resolve in the current context?

like image 883
benekastah Avatar asked Dec 03 '11 23:12

benekastah


People also ask

Is there any way to resolve macro variable in shell script?

IS there any way to resolve macro variable in shell script. I did my research but couldn't find anything. Show activity on this post. The shell is not going to be able to resolve a variable from an external macro system, such as &val1, like you suggest in your example. You can have the shell use values from the environment.

Why can’t I get the datastep value of a macro variable?

Since macro statements are resolved while the code is fetched for compilation and execution, they have no access to datastep variable values. Use the call symput () subroutine to save datastep values to macro variables. hmmm, so the issue is timing. Thank you, that helps.

What happens if there are more than one variable in a macro?

If you include only one variable name on the MACRO command, that variable contains all the parameters entered with the macro name. If there are more variable names than parameters, the unused variables are set to nulls. Multiple parameters are separated by a blank or comma, or a quoted string that is separated by a blank or comma.

Why do macro statements have to be done at run time?

It had to be done at run time because the length of each variable can be different, and therefore the @ cursor will be different for every line. .... Since macro statements are resolved while the code is fetched for compilation and execution, they have no access to datastep variable values.


3 Answers

I guess this is a similar problem to: How can I apply clojure's doc function to a sequence of functions A macro can do whatever it wants with its args, so passing a naked symbol in can result in unpredictable results.

A way to solve it, but it ain't pretty:

(eval (list 'defpage (vector my-method "some/url") '[data]
  ; some stuff
))

Notice that my-method is not a literal here, so it gets resolved and evaluated in our own namespace first, before going into eval.

like image 90
Michiel Borkent Avatar answered Nov 04 '22 05:11

Michiel Borkent


It seems, that noir is not meant to be used this way, because it takes the method argument and transforms it to the symbol in compojure.core (see https://github.com/ibdknox/noir/blob/master/src/noir/core.clj#L36). It means, that it doesn't expect a variable in this place, only literals. So I don't think you can do anything about that, except post an issue to noir...

like image 40
Vsevolod Dyomkin Avatar answered Nov 04 '22 06:11

Vsevolod Dyomkin


If we look through noir/core.clj file (source), find parse-route function and reason what it does with its method argument (it is called action there), we could find that method keyword is converted to string, uppercased and resolved in compojure.core namespace. All this is done during macro expansion time. So it is not possible to use variable instead of keyword without altering noir code.

like image 42
Vladimir Matveev Avatar answered Nov 04 '22 05:11

Vladimir Matveev