While playing around with a little test website I came across what, I
believe to be a bug in the CLJS compiler. It seems like the generation of
symbols for use in macros (e.g. var#) is broken when compiled into certain
JavaScript forms.
This is a bit of a contrived example but it illustrates the point.
This is my-website.macros file:
(ns my-website.macros)
(defmacro defalert [name n]
`(let [i# ~n]
(defn ~name []
(js/alert i#))))
This is my-website.test file:
(ns my-website.test
(:require [jayq.core :as jq])
(:use-macros [my-website.macros :only [defalert]])
)
(defalert alert5 5)
(defalert alert9 9)
(alert5)
(alert9)
And this is (a portion of) the generated .js file:
var i__6378__auto__ = 5;
my_website.test.alert5 = function alert5() {
return alert(i__6378__auto__)
};
var i__6378__auto__ = 9;
my_website.test.alert9 = function alert9() {
return alert(i__6378__auto__)
};
my_website.test.alert5.call(null);
my_website.test.alert9.call(null);
When this is loaded into a webpage two alerts happen (as expected);
however, both of the alerts are "9". I believe the intention of the code
is to alert 5 and then alert 9. Inspecting the .js generated code it is
pretty clear what is going on. The compiler is generating the same symbol
for i# in both expansions of defalert and that symbol is being overwritten
in the global scope.
This seems like a bug to me, but I wanted to get other's opinions.
*Additional information*
My project.clj looks like:
(defproject my-website "0.1.0-SNAPSHOT"
:description "Scaffold clojure website"
:dependencies [[org.clojure/clojure "1.4.0"]
[jayq "0.1.0-alpha4"]
[noir "1.3.0-beta3"]]
:plugins [[lein-cljsbuild "0.2.9"]] ; cljsbuild plugin
:cljsbuild
{
:builds [{
;; The path to the top-level ClojureScript source directory:
:source-path "src-cljs"
;; The standard ClojureScript compiler options:
;; (See the ClojureScript compiler documentation for details.)
:compiler {
:output-to "resources/public/js/main.js"
:optimizations :whitespace
:pretty-print true}}]}
:main my-website.server)
This example is not as academic as it might first seem. I came across this
exact problem while using defpartial from the crate lib by Chris Granger.
Here is the code that tripped me up:
(defpartial button1 []
[:a.button1 {:href "#"} "Button 1"])
(defpartial button2 []
[:a.button2 {:href "#"} "Button 2"])
(jq/on ($ :body) :click button1
nil
(fn [e]
(.preventDefault e)
(alert "button 1"))
(jq/on ($ :body) :click button2
nil
(fn [e]
(.preventDefault e)
(alert "button 2"))
My intention was to alert with "Button 1" when any button1 was clicked and
to alert with "Button 2" when any button2 was clicked. In this case
clicking on any button2 does indeed alert with "Button 2", but clicking on
any button1 will also alert with "Button 2". The fundamental problem is
due the behavior that I describe in my contrived example.
By the way, the workaround here is very easy. Simply replace the button1 and
button2 functions in the on calls with the class names assigned to those
elements (:.button1 and :.button2 respectively).
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en