(defun display-message ()
(cl-who:with-html-output-to-string (*+html-stream+*)
(:html
(:head (:title "Show a single message"))
(:body
(:div
(let ((msgid (hunchentoot:get-parameter "message")))
(cl-who:fmt "Slot value of 'subject: ~A" (slot-value (car (select
(where :message-id msgid))) 'subject))))))))
If I replace the last msgid with a number, it works fine. I know it's
something I'm missing with macros, but I can't figure it out on my -
any pointers?
I know little about the context of this, but I would first check that
msgid inside that let is what you want it to be, eg insert
(format t "msgid: ~a~%")
etc.
Tamas
(defun display-message ()
(cl-who:with-html-output-to-string (*+html-stream+*)
(:html
(:head (:title "Show a single message"))
(:body
(:div
(let ((msgid (hunchentoot:get-parameter "message")))
(cl-who:fmt "Message requested: ~A" msgid)))))))
;; (cl-who:fmt "Slot value of 'subject: ~A" (slot-value (car (select
(where :message-id msgid))) 'subject))))))))
If you'd check TREE-TO-COMMANDS in who.lisp, it writes that:
;; (FMT form*) --> (FORMAT STREAM
form*)
(list* 'format stream (rest x)))))
Namely, there is nothing magical about FMT directive of CL-WHO. For
debugging, you can try partially expanding CL-WHO macros step by step.
(For this purpose, C-c C-m and C-c M-m keys can help you in SLIME.)
Regards.
> If I replace msgid inside the 'where' call with a number (not a
> variable), the output is correct.If I do the following, the output is
> correct:
>
> (defun display-message ()
> (cl-who:with-html-output-to-string (*+html-stream+*)
> (:html
> (:head (:title "Show a single message"))
> (:body
> (:div
> (let ((msgid (hunchentoot:get-parameter "message")))
> (cl-who:fmt "Message requested: ~A" msgid)))))))
> ;; (cl-who:fmt "Slot value of 'subject: ~A" (slot-value (car (select (where :message-id msgid))) 'subject))))))))
Therefore problem is not with cl-who but with the (select (where ...))
form. I don't know what they are. Are you sure you can give a variable
to WHERE? What do you get if you type at the REPL something like:
(let ((msgid "some-id"))
(select (where :message-id msgid)))
?
--
__Pascal Bourguignon__
Are you sure that get-parameter returns a number?
> (cl-who:fmt "Message requested: ~A" msgid)))))))
Try "~S" instead of "~A" in the format.
> ;; (cl-who:fmt "Slot value of 'subject: ~A" (slot-value (car (select
> (where :message-id msgid))) 'subject))))))))
Also start backing up to the next level. Print out the result of
(where :message-id msgid)
instead of just msgid itself.
-- Don
_______________________________________________________________________________
Don Geddis http://don.geddis.org/ d...@geddis.org
All brontosauruses are thin at one end, much MUCH thicker in the middle,
and then thin again at the far end.
-- New dinosaur theory by "Miss Anne Elk" (Monty Python)
OP: Apparently uou know more than Tamas.
>
> I know little about the context of this, but I would first check that
> msgid inside that let is what you want it to be, eg insert
>
> (format t "msgid: ~a~%")
TP: For the love of god, man, can you read?* He substituted the literal
value and got what he wanted and cleverly grokked it was a macrology issue.
From PCL: the definition of where:
(defmacro where (&rest clauses)
`#'(lambda (cd) (and ,@(make-comparisons-list clauses))))
OP: I want you to eat for the rest of your life, so please hack up where
and make-comparison-lists to print out the value of their inputs, and
then /compile/ (not run) display-message.
You can also just:(macroexpand '(where :msgid hi-mom)) I changed to
'hi-mom to reduce distractions.
Now meditate on your navel.
The issue is, with any given macro, when are the input forms evaluated?
If an input form is not evaluated at run-time (ie, if the form itself
gets processed at compile-time) you are doomed trying to use anything
other than a literal value (whose form, ny def, evaluates to itself).
"doomed", btw, means you are looking for some other tool that /does/
evaluate its input, possibly called select-query (I made that up). Then
you would do:
(select-query '(where :msgid 42)
...which is silly because 42 already works with select, or:
(select-query `(where :msgid ,hi-mom))
Left as an exercise: where-query, so you can (let's abrreviate, k?):
(select (whereq :msgid hi-mom))
hth, kzo
> Tamas K Papp wrote:
>> I know little about the context of this, but I would first check that
>> msgid inside that let is what you want it to be, eg insert
>>
>> (format t "msgid: ~a~%")
>
> TP: For the love of god, man, can you read?* He substituted the literal
> value and got what he wanted and cleverly grokked it was a macrology
> issue.
The OP didn't post the macro, and it is surely not standard. A macro
can behave differently depending on whether it is passed literal
values or symbols (though that is not something I would usually design
when writing simple macros, but I don't know the example in question).
Generally people can get better help if they post all relevant code.
You did look it up instead of the OP, which is nice of you, but can't
be generally expected.
Tamas
Oops, here and in the next bit (now deleted) I forgot that the issue
turned out to be with "where", not select, select being a normal
function. ie, Yeah, I am just typing over the keyboard.
Rather than try to salvage this mess, let's just leave it at your goal
being (and let's drive home the point):
(select (where-query :msg-id
(hunchentoot:get-parameter "message")))
..and then something like:
(let ((id (hunchentoot:get-parameter "message")))
(select (whereq :msgid id)))
...where the /function/ where-query is a modification of PCL's 'where'
macro and 'whereq let's you buy back the syntactic brevity. That sould
get interesting if one wants to limit evaluation to the value form and
not the key, by which I mean this would /not/ work:
(let ((key :msgid)
(id (hunchentoot:get-parameter "message")))
(select (whereq key id))
still just typing at keyboard,k
(defun where (&key topic subject message-id parentid)
#'(lambda (msg)
(and
(if topic (equal (slot-value msg 'topic) topic ) t)
(if subject (equal (slot-value msg 'subject) subject) t)
(if message-id (equal (slot-value msg 'message-id) message-id)
t)
(if parentid (equal (slot-value msg 'parent-message-id)
parentid) t))))
(defun select (selector-fn)
(remove-if-not selector-fn *message-list*))
F*ck, now I owe Tamas an apology! 2009 is off to a great start.
> I'm thinking that it has something to do with
> the cl-who:w-h-o-t-s macro, and the way it's interacting with the two
> defun's and lambda:
>
>
> (defun where (&key topic subject message-id parentid)
> #'(lambda (msg)
> (and
> (if topic (equal (slot-value msg 'topic) topic ) t)
> (if subject (equal (slot-value msg 'subject) subject) t)
> (if message-id (equal (slot-value msg 'message-id) message-id)
> t)
> (if parentid (equal (slot-value msg 'parent-message-id)
> parentid) t))))
>
> (defun select (selector-fn)
> (remove-if-not selector-fn *message-list*))
>
>
> (defun display-message ()
> (cl-who:with-html-output-to-string (*+html-stream+*)
> (:html
> (:head (:title "Show a single message")) (:body
> (:div
> (let ((msgid (hunchentoot:get-parameter "message")))
Right here ^^^ might be your problem. cl-who does its own form of macro
expansion and IIUC has no case to handle "Let". ie, it has things like
:head and :div and even fmt, so you have to lead with those. But once it
gets to (fmt this that the other thing) it just bungs in everything
after the fmt into a format statement, so you can do your let statement
just in time (and be grateful Lisp subsumes the functionale).
See below for a quickly edited untested possibility.
> (cl-who:fmt "Slot value of 'subject: ~A" (slot-value (car
> (select
> (where :message-id msgid))) 'subject))))))))
(defun display-message ()
(cl-who:with-html-output-to-string (*+html-stream+*)
(:html
(:head (:title "Show a single message"))
(:body
(:div
(cl-who:fmt "Slot value of 'subject: ~A"
(let ((msgid (hunchentoot:get-parameter "message")))
(slot-value (car
(select
(where :message-id msgid))) 'subject))))))))
hth,kt
You've probably solved this now, but for later you might try setting
TBNL:*CATCH-ERRORS-P* to NIL so you can debug the problem using the Lisp
debugger with a proper backtrace etc. instead of just getting a "HTTP
500 error" message in the browser.
http://www.weitz.de/hunchentoot/#debug
(ERROR "~@<There is no applicable method for the generic function
~2I~_~S~\n ~I~_when called with arguments ~2I~_~S.~:>")
[:EXTERNAL]
Now I just have to figure out WHY I'm getting the error...
Hmm, that's a pretty obscure error message. Something tells me you
haven't pasted the actual message itself here. You are looking at the
code or function call (some point in the stack/back-trace) which
_generates_ the error message.
The message itself should be at the top (in Slime), then the back-trace
should follow below.
Lars gave the thread that eventually unraveled the the issue,
Hunchentoot was returning:
"There is no standard applicable message for the generic function"
then it went on to tell me that msgid was nil.
What took so long to penetrate was WHY msgid was nil. After staring
at the Hunchentoot documentation, staring at my code, surfing the web,
banging my head bloody, I eventually realized that get-parameter
returns a string, and select using msgid needed an integer... add
(parse-integer (get-parameter "message")) and all my troubles went
away!
D'OH!