Archive for September 2008
ucw; jump into other component’s default state
By simple links:
(defcomponent A1-component (template-component)
()
(:entry-point "^(|app1.ucw)$"
(:application *my-ucw-app*
:class regexp-dispatcher))
(:default-initargs :template-name "A1.tal"))
tal
<html xmlns:tal="http://common-lisp.net/project/bese/tal/core"
xmlns:ucw="http://common-lisp.net/project/ucw/core"
tal:in-package=":ucw-apps">
<body>
<a href="app2.ucw">goto A2</a>
</body>
</html>
In case you don’t need entry points into both components, having one entry-point-like component:
(defcomponent A1-component (template-component)
()
(:entry-point "^(|app.ucw)$"
(:application *my-ucw-app*
:class regexp-dispatcher))
(:default-initargs :template-name "A1.tal"))
(defcomponent A2-component (template-component)
()
(:default-initargs :template-name "A2.tal"))
tal
<html xmlns:tal="http://common-lisp.net/project/bese/tal/core"
xmlns:ucw="http://common-lisp.net/project/ucw/core"
tal:in-package=":ucw-apps">
<body>
<a ucw:action="(jump 'A2-component)">goto A2</a>
</body>
</html>
ucw state-machine; initial attempt
With state machines you can specify certain aspects of your app. It seems reasonable to implement them in ucw. The code is similar to previous constant case, update/insert parts below. The app prints out your state, possible transitions as links and in case of a click, you can go to that other state. As an example I’ve chosen tcp state machine. Using tal:dolist (sort of loop driven from the template file) is a bit strange, I tried to abstract this away with make-transition and make-node funs.
lisp file
(defun make-transition (at-pair)
(let ((action (car at-pair))
(target (cadr at-pair)))
`(((action . ,action) (target . ,target)))))
(defun make-node (def)
(list (car def) (mapcar #'make-transition (cdr def))))
; http://www.virtualventures.ca/~cat/tcp-states.gif
(defparameter =state-machine=
(mapcar
#'make-node
`(("CLOSED"
("Passive open" "LISTEN")
("Active open/SYN" "SYN_SENT"))
("LISTEN"
("Close" "CLOSED")
("Send/SYN" "SYN_SENT")
("SYN/SYN+ACK" "SYN_RCVD"))
("SYN_RCVD"
("Close/FIN" "FIN_WAIT_1")
("ACK" "ESTABLISHED"))
("SYN_SENT"
("Close" "CLOSED")
("SYN+ACK/ACK" "ESTABLISHED")
("SYN/SYN+ACK" "SYN_RCVD"))
("ESTABLISHED"
("Close/FIN" "FIN_WAIT_1")
("FIN/ACK" "CLOSE_WAIT"))
("FIN_WAIT_1"
("FIN/ACK" "CLOSING")
("ACK" "FIN_WAIT_2"))
("CLOSE_WAIT"
("Close/FIN" "LAST_ACK"))
("FIN_WAIT_2"
("FIN/ACK" "TIME_WAIT"))
("CLOSING"
("ACK" "TIME_WAIT"))
("LAST_ACK"
("ACK" "CLOSED"))
("TIME_WAIT"
("timeout" "CLOSED")))))
(defcomponent tal-component (template-component)
((state :accessor state
:initform (car =state-machine=)))
(:entry-point "^(|app.ucw)$"
(:application *my-ucw-app*
:class regexp-dispatcher))
(:default-initargs :template-name "buzz.tal"))
(defaction move-to-state ((component tal-component) new-state)
(setf (state component)
(assoc new-state =state-machine= :test #'string-equal)))
tal file:
<html xmlns:tal="http://common-lisp.net/project/bese/tal/core"
xmlns:ucw="http://common-lisp.net/project/ucw/core"
tal:in-package=":ucw-apps">
<body>
<p>Ur st8 iz: <b tal:content="(car $state)" /></p>
<p>Transitions:</p>
<ul>
<li tal:dolist="(cadr $state)">
<a href=""
ucw:action="(move-to-state $component $target)"
tal:content="$action">action</a>
</li>
</ul>
</body>
</html>
constant ucw page; improvements & thoughts
With UCW TAL templates, you can write xml documents which are similar to html, and handled by UCW in such a way that data is injected into it from the lisp side. From this perspective I think we can talk about View’s from a MVC or MVP pattern. The model should be the data content of components. MVC is in use when TAL templates are using only pure slots. When they use other methods to obtain values, you can talk about presenters distributed into these methods.
I created a sample app just to start with by copying parts from the examples section of the UCW box set. I’ve gotten issues (also with the counter example), the page saying “attempt to call `IT.BESE.UCW::MAKE-STANDARD-ENVIRONMENT’ which is an undefined function”. After a short google session and a grep withing the yaclml package, I realized, there’s no such a function. I downloaded a new version of this yaclml and I found a defun for this thingy in it. Things started to work.
And now the content of my app’s files:
(defpackage :ucw-apps
(:use :common-lisp
:it.bese.ucw
:it.bese.arnesi
:it.bese.yaclml))
(in-package :ucw-apps)
(defvar *my-ucw-app*
(make-instance
'cookie-session-application
:tal-generator (make-instance
'yaclml:file-system-generator
:cachep t
:root-directories (list *ucw-tal-root*))
:www-roots (list (merge-pathnames "./" *ucw-tal-root*))
:url-prefix "/my/"))
(register-application *default-server* *my-ucw-app*)
(defcomponent tal-component (template-component)
((page-name :initarg :page-name :accessor page-name))
(:entry-point "^(|app.ucw)$"
(:application *my-ucw-app*
:class regexp-dispatcher))
(:default-initargs :template-name
"buzz.tal" :page-name "FooBar"))
buzz.tal:
<html xmlns:tal="http://common-lisp.net/project/bese/tal/core"
xmlns:ucw="http://common-lisp.net/project/ucw/core"
tal:in-package=":ucw-apps">
<head>
<title tal:content="$page-name">page name goes here</title>
</head>
<body>
<h1 tal:content="(page-name $component)" tal:escape-html="nil">page name
goes here</h1>
</body>
</html>
This all only gives you a page with FooBar as h1 & title.
ucw constant-page application
I’ve already experimented with UCW. What about to continue? Why not? : )
Actually I’m sitting in front of a Windows machine. My favourite movie about UCW uses slime to dynamically interact with the running server. This means thread support from the CL perspective (as far as I understand right now). SBCL doesn’t have it in regards the w32 port (by the way last time I’ve started the server with SBCL here and I waited several minutes to get repl prompt till I realized that I’ll never get one), clisp 2.45 isn’t compatible with current slime in current UCW boxset. I’ve ended up using Allegro, free, express, whatever version. It’s lucky that UCW doesn’t use too much heap (there’s a limitation for this in the Allegro release I’ve downloaded). Finally XEmacs-Slime-UCW combo works now.
Please find a static page implementation in UCW below.
(in-package :it.bese.ucw-user)
; The component, which contains all the necessary
; information for a page, now, contains nothing.
; It's kinda constant page, so there's no need to store
; or give (by parameters) it information.
(defcomponent my-page (simple-window-component) ())
; This gives the projection of my component into the space
; of html documents.
(defmethod render ((page my-page))
(<:p "my page..."))
;; Some red tape.
; An application server needs an application, which
; can be started by entering the right entrypoint as
; an address into the addressbar of a browser.
; An app, resides within http://running-server/my-page/*
(defvar *my-app*
(make-instance 'cookie-session-application
:url-prefix "/my-page/"))
; Obviously you have to tell the server about your app.
(register-application *default-server* *my-app*)
; Loading of "http://127.0.0.1:8080/my-page/index.ucw" (with
; default config of ucw) calls this. Call nearly means render.
(defentry-point "index.ucw" (:application *my-app*)
()
(call 'my-page))
To be continued… : )
conditioning your Lisp
I’ve been always interested in Lisp’s condition system, but somehow I’ve never had time. As an aspect of it, you can provide condition handling strategies within your low level code and, without unwinding the stack, the high level layers can decide how to continue. You can signal that a given condition is true or it is happening right now. It also can be a tool for passing parameters from high level code to low level without pushing it over the stack. This aspect of the PCL book wasn’t as clear as I needed, hence this entry covering my curiosity.
(define-condition zero ()
())
(defun f (i)
(if (not (= i 0))
i
(restart-case (signal 'zero)
(as-it-is () i)
(skip () 1)
(use-other-value (v) v))))
(defun g (is result)
(if (null is)
result
(g (cdr is)
(* result
(f (car is))))))
(defun h (list)
(handler-bind ((zero
#'(lambda (c)
(invoke-restart 'use-other-value 1e-10))))
(g list 1)))
goto sponsored by Lisp
(defun f ()
(tagbody
(setq x 0)
my-label
(princ (format nil "~a" x))
(if (< x 9)
(progn
(incf x)
(go my-label)))))
For further details, see: GO spec and the like…
I stopped doin’ it
Dunno why..
ooo basic
sub ExportHtmlPdfDoc dim args(1) as new com.sun.star.beans.PropertyValue args(0).Name = "InteractionHandler" args(0).Value = "" args(1).Name = "FilterName" args(1).Value = "writer_pdf_Export" ThisComponent.storeToURL(ThisComponent.getURL()+".pdf",args()) args(1).Value = "MS Word 97" ThisComponent.storeToURL(ThisComponent.getURL()+".doc",args()) args(1).Value = "HTML (StarWriter)" ThisComponent.storeToURL(ThisComponent.getURL()+".htm",args()) end sub