3

I'm new to clojure, and I'm trying to use clojure.contrib.strint to build a URL. for example I might use this for a google search:

(def search_base_url "http://www.google.com/search?hl=en&q=~{query}")

(defn search_url [search_term]
  (let [query (.replaceAll search_term "\\s+" "+")]
    (<< search_base_url)))

But this gives me the compiler error:
error: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.IllegalArgumentException: No matching method found: indexOf for class clojure.lang.Symbol.
I think strint uses indexOf a few times, so somehow I'm not giving the << function what it wants, it seems.

I've also tried (def search_base_url '(<< "http://myurl.com?~{params}")), but then I can't figure out how to evaluate that form in the context of my let. I could just put the string in the search_url function, but that feels inferior to me and I'm hoping the answer to this will help me understand clojure a bit better.

Thanks

Johnny Brown
  • 1,000
  • 11
  • 18

2 Answers2

1

The problem is, that the "<<" macro expects a string, not something which evaluates to string. That is, it tries to call .indexOf on the symbol named "search_base_url", instead of on its value.

So one way to fix this is:

(defn search-url [search-term]
  (let [query (.replaceAll search-term "\\s+" "+")]
    (<< "http://www.google.com/search?hl=en&q=~{query}")))
ivant
  • 3,909
  • 1
  • 25
  • 39
0

I had a look at the source code for << on github ... and I could not get it to work the way you want either.

BUT

If you re-write the macro like this:

(defmacro <<<
    [string]
      `(apply str (map #(eval %) (interpolate ~string))))

Then

(def query "queryitem")
(def basesearch "http://www.google.com/search?hl=en&q=~{query}")

(<<< basesearch)

Will return

"http://www.google.com/search?hl=en&q=queryitem"

Which is what you want. Reason is:

 (interpolate basesearch)

returns a lazy-seq that does not perform evaluation of the sequence:

 ("http://www.google.com/search?hl=en&q=" query "")

The query symbol is never evaluated in the << macro and is returned as is.

Since silent-read and interpolate are private you would have todo some copy paste but the final usage is quite cool.

Nicolas Modrzyk
  • 13,961
  • 2
  • 36
  • 40
  • 3
    This breaks down when `query` is eg. a let local. `<<` was explicitly designed to expand at compile time. Not runtime. Use `format` if you need that. Or construct the query string from pieces: `(<< "~{baseurl}?hl=~{language}&=~{queryitem}")`. – kotarak Aug 12 '11 at 08:19