Gå til innhold

SymbolicWeb: en slags work(b?)log!


Anbefalte innlegg

Hei,

Jeg jobber med et prosjekt kallt SymbolicWeb ( http://symbolicweb.org/ ). Tanken er å bruke språket Common Lisp til utvikling av web-applikasjoner. Så dette er ment å bli et alternativ til ting som f.eks. PHP.

 

En liten manual er under utvikling, den finnes på hjemmesiden. Noen kjappe eksempler:

 

* Her kjører et `sesjons-program': http://symbolicweb.org/sw/session-app (kildekode: http://nostdal.org/~lars/programming/lisp/...s/session.lisp)

(edit: fjernet noen gammle eksempler her - se i stedet poster nedover i denne tråden for flere/bedre eksempler!)

 

Det jobbes også med AJAX-muligheter: http://symbolicweb.org/sw/swajax (kildekode). Dette er på et rimelig tidlig stadie, men det foregår generellt sett slik at man har følgende HTML:

 

<h1 id="heading">Beta-versjon av SymbolicWeb</h1>

 

..og at man videre på serveren sier:

 

(setElement "heading" "Ferdig versjon av SymbolicWeb")

 

..for å endre HTML-elementet med id "heading" til å inneholde en ny tekst. Bruk av div/span elementer er interesannt her.

 

Kunne trengt noen betatestere! Er det noen som har noen innspill eller forslag med tanke på idéer, bugs, manual/tutorial-prosjekt e.l.? Vet at alt dette er på et veldig tidlig stadie, men det hadde vært artig å høre om noen hadde noen idéer allerede nå. :)

 

Lurer på om jeg skal gå over til å bruke html-template hele veien i alle eksemplene, som i `login-program'-eksempelet.

 

edit:

tror det er et par problemer med diverse browsere .. jeg har kun testet dette under Firefox, og må nok fikse visse ting slik at de fungerer knirkefritt under Opera og IE også

Endret av dayslepr
Lenke til kommentar
Videoannonse
Annonse

kom over en liten bug i mod_lisp2.c, her er en patch:

 

Index: mod_lisp2.c
===================================================================
--- mod_lisp2.c (revision 117)
+++ mod_lisp2.c (working copy)
@@ -417,7 +417,6 @@
#else
      RELAY_ERROR (apr_send (socket, p, &n2));
#endif
-      RELAY_ERROR (apr_socket_send (socket, p, (&n2)));
      if (n2 == n1)
       return (APR_SUCCESS);
      p += n2;

 

den er sendt inn til vedlikeholderen av mod_lisp ... :)

 

edit:

..og er nå en del av den "offesielle" versjonen av filen (litt off-beat kommentar i Changeloggen ..heh)

 

Når det gjelder SymbolicWeb så har jeg fikset et par feil i dokumentasjonen, og tukkler med noen idéer i koden.

Endret av dayslepr
Lenke til kommentar
  • 2 uker senere...

Ny måte å håndtere sesjoner på

Det er nå kommet en ny måte å håndtere sesjoner eller sesjonsdata i SymbolicWeb. Tidligere måtte man lese av data ved å kalle (getSessionVar "min-variabel"), nå er det kommet en enklere og mer «objekt orientert» måte og gjøre det på.

 

Tenk deg at du i et program skal huske et brukernavn ettersom du blar fra side til side. Dette kan nå gjøres slik:

 

(defclass MyApp (SessionApp)
 ((username :accessor username-of :initform nil)))

(defmethod defaultContent ((app MyApp))
  (princ (mkstr
           "You are currently logged in as: '" (username-of app) "'."))))

 

Om brukeren på et eller annet tidspunkt endrer verdien av en slik medlems-variabel, vil endringen kun være gjeldende for den respektive brukeren/sesjonen.

 

Vil man ha en "global" variabel for applikasjonen, løser man dette naturlig ved å bruke statiske medlemmer:

 

(defclass MyApp (SessionApp)
 ((username :accessor username-of :initform nil)
  (global-hits :accessor global-hits-of :initform 0
               :allocation :class)))

 

`global-hits' kan her være en «hit-counter» som teller antall forespørsler globalt uavhengig av hvilken bruker som gjør forespørslen.

 

Se session.lisp og tilhørende template session.html for et mer komplett eksempel (bruk View Source i nettleseren din for å se innholdet av HTML-templaten). Tingen kjører her: http://nostdal.org/sw/session-app

 

Videre er nå dokumentasjon flyttet til filer blant kildekoden for å gjøre vedlikeholdet av dette enklere (README, INSTALL, TUTORIAL ...).

 

Det jeg tenkte å implementere fremover er en direkte «kobling» mellom forespørsler (forms f.eks.) fra klient og funksjoner/metoder på server. Dette for å ungå en stygg "switch" for å avgjøre hva som skal skje. Tanken er også å få den til å sende POST/GET data som argumenter til funksjonen om parameter-navnene til funksjonen matcher name/id-attributtene til form-dataene. Det kan jo bli litt spennende .. kanskje .. :)

 

http://symbolicweb.org/

Endret av dayslepr
Lenke til kommentar

Direkte kobling mellom forespørsler og funksjoner/metoder

Okei, jeg skal forsøke å forklare dette kjappt - da jeg begynner å bli sliten i øveretasjen. :) (edit: kjappt vil som regel si liten tid til å korte ned på posten) Nå, hvor var jeg? Hvordan skal jeg forklare det her? .. Jeg kan forsøke med et eksempel.

 

Ta situasjonen man står ovenfor når man har en «loginside», og man har en web-applikasjon fyllt med ting som kan skje ettersom hva brukeren velger å gjøre. Det er jo ikke sikkert h*n ønsker å logge inn hver gang, og da må det være en ting i koden som "ruter" forespørselen til riktig «håndterer» alt ettersom type forespørsel.

 

Måten man ofte gjør dette på er å lage en slags «switch» som sjekker en POST/GET-variabel av noe slag og ruter forespørselen videre. Dette fungerer forsåvidt greit, men er kanskje ikke så pent? I tillegg må man passe på å lese av data som de forskjellige «håndtererene» trenger.

 

Idéen er å automatisere begge disse delene; det å finne en «håndterer» og sende den riktige data. Om man bytter ut ordet «håndterer» med funksjon eller metode, og ordet «data» med argumenter - så får du det jeg har her.

 

Her kjører en applikasjon som tar i bruk dette: http://nostdal.org/sw/handler-app (kildekoden: http://nostdal.org/~lars/programming/lisp/...s/handler.lisp)

 

Om du titter på HTML-formen, så ser du at text-elementene har samme name-attributter som parameter-navnene til funksjonen `login', og det er derfor `login' mottar disse som argumenter. Er det ikke fint? :) `SWHandler' er den som avgjør hvilken funksjon/håndterer det er snakk om. Merk at man kan definerer flere kall samtidig, da `callHandler' tar et argument for hvilket form-element den skal se etter for aktuellt funksjons-navn.

 

Man kan i tillegg kalle login som en vanlig funksjon/metode fra REPLen:

 

SWTests> (login "my-username" "my-password")
"User tried to login with username 'my-username' and password 'my-password'."

 

...dette er veldig greit når man skal debugge ting. :)

 

Puh, nå er det kvelden her .. Anyways; noen som har noen idéer til ting jeg kan implemnetere til neste gang? Jeg har gått tom akkurat nå :p (men kommer sikkert på noe senere)

Endret av dayslepr
Lenke til kommentar

Hei igjen,

Et par endringer i APIet (dette er pre-1.0, så det er vel ok?:)). `handler.lisp' kjører nå her: http://nostdal.org:6060/sw/handler/

 

Foreløpig på laptopen igjen dette - jobber med å få ferdig et par ting før jeg commiter en patch og oppdaterer på server. Før patchen sendes inn så skal jeg passe på at tutorial og dokumentasjon er oppdatert. :)

 

... i samme slengen kan jeg nevne at jeg jobber med en større tutorial som skal ta for seg utvikling av en webshop, den foreløpige adressen er her: http://nostdal.org:6060/~lars/programming/...l/tutorial.html (denne er veldig mye ikke-ferdig; spesiellt pga. det at APIet til SW er under endringer..)

 

Komplett program under:

 

;;;; http://SymbolicWeb.org/

(in-package :SWTests)


(defclass MyHandlerApp (SessionApp)
 ((template :allocation :class :accessor template-of
            :initform (relativePath "programming/lisp/symbolicweb/tests/templates/handler.xhtml"))
  (session-counter :initform 0 :accessor session-counter-of)
  (session-amount :initform 1 :accessor session-amount-of)
  (global-counter :initform 1 :accessor global-counter-of
                  :allocation :class)
  (global-amount :initform 1 :accessor global-amount-of)))


(defView default ((app MyHandlerApp))
 (printTemplate (template-of app)
                (list :global-counter (princ-to-string (global-counter-of app))
                      :global-amount (princ-to-string (global-amount-of app))
                      :session-counter (princ-to-string (session-counter-of app))
                      :session-amount (princ-to-string (session-amount-of app))
                      :session-id (session-id-of app))))


(defHandler increaseGlobal ((instance MyHandlerApp) global-amount)
 (let ((amount (read-from-string global-amount)))
   (setf (global-amount-of instance) amount)
   (incf (global-counter-of instance) amount)))


(defHandler decreaseGlobal ((instance MyHandlerApp) global-amount)
 (let ((amount (read-from-string global-amount)))
   (setf (global-amount-of instance) amount)
   (decf (global-counter-of instance) amount)))


(defHandler increaseSession ((instance MyHandlerApp) session-amount)
 (let ((amount (read-from-string session-amount)))
   (setf (session-amount-of instance) amount)
   (incf (session-counter-of instance) amount)))


(defHandler decreaseSession ((instance MyHandlerApp) session-amount)
 (let ((amount (read-from-string session-amount)))
   (setf (session-amount-of instance) amount)
   (decf (session-counter-of instance) amount)))


(defHandler restartSession ((instance MyHandlerApp))
 (setf (session-counter-of instance) 0)
 (endSession instance))

 

..templaten er her..

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html 
    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
 <title>SymbolicWeb: Example `handler.lisp'</title>
</head>

<body>
 <h1>SymbolicWeb: Example `handler.lisp'</h1>

 <h2>Global counter</h2>
 Value: <b><!-- TMPL_VAR global-counter --></b>
 <form method="post">
   Amount to change: <input type="text" name="global-amount" value="<!-- TMPL_VAR global-amount -->"/>
   <br/>
   <input type="radio" onclick="this.form.submit()" name="SWChannel" value="increaseGlobal"/> 
   Increase <br/>
   <input type="radio" onclick="this.form.submit()" name="SWChannel" value="decreaseGlobal"/> 
   Decrease <br/>
 </form>
 
 <h2>Session counter</h2>
 <em>(session-id: <!-- TMPL_VAR session-id -->)</em> <br/>
 Value: <b><!-- TMPL_VAR session-counter --></b>
 <form method="post">
   Amount to change: <input type="text" name="session-amount" value="<!-- TMPL_VAR session-amount -->"/>
   <br/>
   <input type="radio" onclick="this.form.submit()" name="SWChannel" value="increaseSession"/> 
   Increase <br/>
   <input type="radio" onclick="this.form.submit()" name="SWChannel" value="decreaseSession"/> 
   Decrease <br/>
 </form>
 
 <form method="post">
   <input type="hidden" name="SWChannel" value="restartSession"/>
   <input type="submit" value="Restart session"/>
 </form>
 
</body>
</html>

Endret av dayslepr
Lenke til kommentar
hehe; jeg måtte laste ned litt film i natt .. pluss at det konstant har vært mellom 20 og 40 stk. som spiller samtidig på ADSL-linja her! :D

5913298[/snapback]

 

Hehe, det forklarer saken. Syntes nemlig det var litt rart det gikk saa sakte med 5 spillere paa i dag morges/rundt 03:00 norsk tid....

Lenke til kommentar

Okei, nå kan man justere størrelsen på brettet m.m.:

http://nostdal.org:5050/sw/SWGo/SWGo/

 

Tror jeg tar en pause fra denne nå, bortsett fra retting av bugs og slikt da. Det er nemlig dukket opp en masse nye idéer som kan plasseres i SW mens jeg har jobbet med dette. :D

 

Jeg har forresten fundert litt; er det noen XHTML/CSS/GFX'ere som kunne tenke seg å "teame opp" rundt slike prosjekter? Jeg har en masse kule idéer for fremtiden. :)

 

Edit:

Jeg er såklart også interessert i og bli med på idéer andre måtte ha .. :)

Endret av dayslepr
Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...