Lisp tutorial for Pythonista.Day #3 : Lisp meets web.                                                          Ransui Iso ...
宿題やった?
今日は Web アプリだよ!   超基本部分しかやらないけどモチベーション維持のためにもネタは重要
Allegro Serve ってのがある  有名な商用処理系の Allegro Common Lisp についてくる Web サーバとちょっとしたフレームワーク
Portable Allegroserve      ってのを使います Allegro serve を他の処理系でも使えるように移植したやつがあるので、有り難く使わさせて頂く
インストールは簡単   最初の日にインストールした QuickLisp を使うですCL­USER> (ql:system­apropos "aserve")#<SYSTEM aserve / portableaserve­20101006­cv...
QuickLisp の更新方法 リポジトリとかたまに更新されるのでチェックしとけ!CL­USER> (ql:update­client)Installed version 2010121400 is as new as upstream ver...
REPL 環境下でテストしてみる●   とりあえずお約束の Hello World からCL­USER> (require :aserve)NILCL­USER> (use­package :net.aserve)TCL­USER> (use­...
UTF8 なんだし日本語出るだろ jk●   .sbclrc に設定もしてるし大丈夫じゃね?CL­USER> (defun hello­world (request entity)           (with­http­response (...
UTF8 なんだし日本語出るだろ jk●   .sbclrc に設定もしてるし大丈夫じゃね?CL­USER> (defun hello­world (request entity)           (with­http­response (...
unicode/byte 文字列変換●   最終的に byte 列として解釈できりゃ OK らしい(defun bin­to­str (data)  (let* ((size (length data))         (octets (ma...
また色々新しいの出た! 例によってザックリと解説
let と let* の違い●   let は変数束縛が同時に起こる感じ       ●(let ((x 10)      (y 20)       ●      (z (+ x y))       ●      ●  ... body ......
配列の作成●   make-array で作成する(make­array  次元指定 or 最大サイズ              :element­type  データ型              :initial­contents  初期値  ...
配列の参照と書き換え●   単純に参照する場合は aref か elt を使う(setf arr (make­array 3 :element­type integer))(setf (aref arr 0) 0)(setf (elt arr ...
dotimes フォーム●   単純なカウンタ付きループ(dotimes (var max­value result­value) body)      ●   変数 var は 0 からスタートして (­ max­value 1) まで回る ...
他のパッケージ内のシンボルの参照●   2 つの参照方法がある     ●   package­name:symbol­name          –   公開 (export されている ) シンボルを参照する     ●   package...
さっきまでのプログラムをファイルに書く●   pastebin 見てね     ●   http://pastebin.com/7AfPE0GG     ●   helloworld.lisp  とか名前をつけて保存●   実行と終了     ...
パッケージに関する操作●   (require :module­name)      ●   標準パッケージはこれでロードできる。●   (asdf:oos asdf:load­op :module­name)      ●   インストールさ...
HTML で出力してみる●   html マクロを使う(defun hello­html­world (request entity)  (with­http­response (request entity)    (with­http­bo...
HTML マクロの基礎●   (:tag­name body)      ●   タグ名はキーワードで指定する      ●   タグに囲まれる値部分はリストの要素として書く●   ((:tag­name :attr­name value) b...
フォームの取り扱い●   入力欄は普通に書けばイイ(defun hello (request entity)  (with­http­response (request entity)    (with­http­body (request e...
フォーム値の取り出し方法●       request 引数に入ってるので引っ張り出す(defun get­field­value (request field­name)  (cdr (assoc field­name (request­qu...
テンプレへの値の埋め込み●   :princ­safe キーワードを使おう      ●   < > & をエスケープしてくれるので安全(defun greeting (request entity)  (let ((name (get­fie...
お待ちかねの課題です
こんなの作ってね!            超シンプル掲示板!
書きこまれたデータの保持●   SQL 系は次回やる予定なので、今回はオンメモリ(defvar *bbs­datas* nil)(defun add­new­article (subject body)  (push (cons subject...
テンプレートの構成            書き込みエリア                      ページ全体            表示エリア
ページ全体テンプレート●   こんな感じかな?(defun page­template ()  (html    (:html      (:head (:title "Tiny BBS"))      (:body       (write­...
表示部分のテンプレ●   こんな感じ(defun view­template (article)  (html    ((:div :style "border: 1px solid black; padding: 2px;")     ((:...
で、あと書かなきゃいけないのは   書き込み部分のテンプレ   コントローラ関数 :bbs
コントローラ関数 bbs の作り方のヒント●   request からフォーム値を取り出す     ●   書き込みボタンが押されてたら         –   add-new-article を呼ぶ     ●   ページ全体テンプレを呼ぶ ...
いやー。ヒント出しすぎ もう、余裕で作れるでしょ?
Upcoming SlideShare
Loading in...5
×

Lisp Tutorial for Pythonista : Day 3

3,518

Published on

Lisp meets Web : A tutorial of Portable AllegroServe and build a tiny BBS application.

Published in: Technology
2 Comments
1 Like
Statistics
Notes
No Downloads
Views
Total Views
3,518
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
0
Comments
2
Likes
1
Embeds 0
No embeds

No notes for slide

Lisp Tutorial for Pythonista : Day 3

  1. 1. Lisp tutorial for Pythonista.Day #3 : Lisp meets web. Ransui Iso Strategic Technology Group, X-Listing Co, Ltd.
  2. 2. 宿題やった?
  3. 3. 今日は Web アプリだよ! 超基本部分しかやらないけどモチベーション維持のためにもネタは重要
  4. 4. Allegro Serve ってのがある 有名な商用処理系の Allegro Common Lisp についてくる Web サーバとちょっとしたフレームワーク
  5. 5. Portable Allegroserve ってのを使います Allegro serve を他の処理系でも使えるように移植したやつがあるので、有り難く使わさせて頂く
  6. 6. インストールは簡単 最初の日にインストールした QuickLisp を使うですCL­USER> (ql:system­apropos "aserve")#<SYSTEM aserve / portableaserve­20101006­cvs / quicklisp 2010­12­07>NILCL­USER> (ql:quickload "aserve")        ****  なんかいろいろでる ****("aserve")CL­USER> 
  7. 7. QuickLisp の更新方法 リポジトリとかたまに更新されるのでチェックしとけ!CL­USER> (ql:update­client)Installed version 2010121400 is as new as upstream version 2010121400. No update.TCL­USER> (ql:update­all­dists)No update available for "quicklisp 2010­12­07".NIL
  8. 8. REPL 環境下でテストしてみる● とりあえずお約束の Hello World からCL­USER> (require :aserve)NILCL­USER> (use­package :net.aserve)TCL­USER> (use­package :net.html.generator)TCL­USER> (start :port 4040)#<WSERVER port 4040 {1002D47421}>CL­USER> (defun hello­world (request entity)           (with­http­response (request entity)             (with­http­body (request entity)               (princ "Hello World" *html­stream*))))HELLO­WORLDCL­USER> (publish :path "/hello­world"                  :content­type "text/plain; charset=utf8"                  :function #hello­world) で、ブラウザで http://localhost:4040/hello­world にアクセス
  9. 9. UTF8 なんだし日本語出るだろ jk● .sbclrc に設定もしてるし大丈夫じゃね?CL­USER> (defun hello­world (request entity)           (with­http­response (request entity)             (with­http­body (request entity)               (princ " 波浪ワールド " *html­stream*))))
  10. 10. UTF8 なんだし日本語出るだろ jk● .sbclrc に設定もしてるし大丈夫じゃね?CL­USER> (defun hello­world (request entity)           (with­http­response (request entity)             (with­http­body (request entity)               (princ " 波浪ワールド " *html­stream*))))2­aserve­worker: 01/04/11 ­ 17:56:08 ­ while processing command "GET /hello­world HTTP/1.1"got error The value 27874 is not of type (UNSIGNED­BYTE 8). 多バイト文字文化圏の悲哀!
  11. 11. unicode/byte 文字列変換● 最終的に byte 列として解釈できりゃ OK らしい(defun bin­to­str (data)  (let* ((size (length data))         (octets (make­array size                              :element­type (unsigned­byte 8)                             :fill­pointer 0)))    (dotimes (i size)      (vector­push (char­code (elt data i)) octets))    (sb­ext:octets­to­string octets :external­format :utf­8)))● ついでなので逆変換もいっとけ(defun str­to­bin (str)  (let* ((octets (sb­ext:string­to­octets str       :external­format :utf­8                         :null­terminate nil))         (size (length octets))         (result (make­array size                              :element­type character                             :fill­pointer 0)))    (dotimes (i size)      (vector­push (code­char (elt octets i)) result))    result))
  12. 12. また色々新しいの出た! 例によってザックリと解説
  13. 13. let と let* の違い● let は変数束縛が同時に起こる感じ ●(let ((x 10)      (y 20) ●      (z (+ x y)) ● ●  ... body ... ) ● ● z の初期化には x と y が必要だけど、初期化は * 同時 * なので x,y ともにまだ存在しない!なので未定義変数参照エラー。● let* は変数束縛が逐次的に起こる感じ(let* ((x 10)   (y 20)   (z (+ x y))  ... body ... ) ● こっちは問題ない。この差は多分にコンパイラの都合。
  14. 14. 配列の作成● make-array で作成する(make­array  次元指定 or 最大サイズ :element­type  データ型 :initial­contents  初期値 :fill­pointer  要素の追加位置ポインタを使うか? :adjustable  サイズを可変にするか? 他にもオプションあるけど、普通使うのはこんくらい(setf arr (make­array 3 :element­type simple­string :initial­contents ("ham" "spam" "egg"))(serf arr (make­array (2 2) :element­type integer :initial­contents ((1 0) (0 1)))(setf arr (make­array 0 :fill­pointer t :adjustable t))
  15. 15. 配列の参照と書き換え● 単純に参照する場合は aref か elt を使う(setf arr (make­array 3 :element­type integer))(setf (aref arr 0) 0)(setf (elt arr 1) 5)(setf (aref arr 5) 10) ← 当然のことながらエラー   aref は配列専用で elt はシーケンス汎用。 aref のほうが効率はいいはず。● fill-pointer を使うと色々便利(setf arr (make­array 3 :element­type integer :fill­pointer t))(fill­pointer arr)(setf (fill­pointer arr) 0)arr(vector­push 1 arr)(vector­push 2 arr)(vector­push 3 arr)(vector­push 4 arr) ← 配列の長さを超えたので値は追加できない   :adjustable を t に指定して vector­push­extend を使えば可変長配列として 要素ををどんどん追加できる。
  16. 16. dotimes フォーム● 単純なカウンタ付きループ(dotimes (var max­value result­value) body) ● 変数 var は 0 からスタートして (­ max­value 1) まで回る ● result­value でループが終了したときの dotimes フォームの戻 り値を指定できる。省略時は nil 。 ● body は普通に色々書けばいい。 – ループを脱出したい場合は return を使う。この場合 result­value は使われ ない。 – return と書くのが気持ち悪い人は (defmacro break­loop (&body body) `(return ,@body)) とか定義しておくとちょびっと幸せかも。 – ちなみに break って名前はすでに cl:break として使われてて、デバッガへ 行くとかいう機能になってるですと!こんなイイ名前をもったいない!
  17. 17. 他のパッケージ内のシンボルの参照● 2 つの参照方法がある ● package­name:symbol­name – 公開 (export されている ) シンボルを参照する ● package­name::symbol­name – 非公開 (export されていない ) シンボルを強制的に参照するsb-ext パッケージ SBCL の拡張機能sb-impl パッケージ SBCL の内部実装へのインタフェース
  18. 18. さっきまでのプログラムをファイルに書く● pastebin 見てね ● http://pastebin.com/7AfPE0GG ● helloworld.lisp  とか名前をつけて保存● 実行と終了 ● sbcl ­­load helloworld.lisp ● REPL が生きてるので (quit) で終了できる● リロード ● REPL で (load "helloworld.lisp") ● (publish­pages)
  19. 19. パッケージに関する操作● (require :module­name) ● 標準パッケージはこれでロードできる。● (asdf:oos asdf:load­op :module­name) ● インストールされているモジュールをロードする ● QuickLisp でインストールしたモジュールも内部では ASDF の管 理下にある● (use­package :package­name) ● Python で言うところの from package­name import * に似 ているけど、名前空間の操作しかしない点が異なる。
  20. 20. HTML で出力してみる● html マクロを使う(defun hello­html­world (request entity)  (with­http­response (request entity)    (with­http­body (request entity)      (html (:html              (:head (:title (u " 波浪ワールド ")))              (:body                (:h1 (u " 波浪ワールド "))               ((:p :style "color: red;") (u " 赤い文字ですよ "))               ((:p :style (format nil "color: ~a;"                                    (nth (random 5)                                         ("red" "blue"    "green" "purple" "black"))))                (u " ここはランダムで色が変わるのです ")) ))) ))) Lisp の中にテンプレートが完全に組み込まれてますよ! テンプレの中に処理もそのまま書ける!
  21. 21. HTML マクロの基礎● (:tag­name body) ● タグ名はキーワードで指定する ● タグに囲まれる値部分はリストの要素として書く● ((:tag­name :attr­name value) body) ● タグに属性をつけたい場合はタグ全体をリスト化して属性名をキー にしたキーワード引数風味に書く ● 値部分は普通の書き方と同じ● テンプレ的機能 ● body とか value 部分には「バイナリ文字列」を返す S 式が書ける – 便宜的にバイナリ文字列って言ってるよ – いまんとこはマルチバイト文字想定される時は u マクロで囲んどけ。
  22. 22. フォームの取り扱い● 入力欄は普通に書けばイイ(defun hello (request entity)  (with­http­response (request entity)    (with­http­body (request entity)      (html (:html              (:head (:title (u " あいさつ ")))              (:body               (:h1 (u " あいさつ "))               ((:form :method "POST" :action "greeting")                ((:input :type "text" :name "name" :value ""))                ((:input :type "submit" :name "greeting­button"  :value "Hi!")) ) )) ))))
  23. 23. フォーム値の取り出し方法● request 引数に入ってるので引っ張り出す(defun get­field­value (request field­name)  (cdr (assoc field­name (request­query request) :test #equal))) – assoc 関数:連想リストを検索する ● 連想リストとは ((key1 value1) (key2 value2) ...) 形式のリスト。すごく単純な Key Value データの表現。 ● 線形検索なので当然のことながら効率は良くない。 ● が、 hash­table に比べればずっとお手軽。 – request­query 関数は ((name1 . value1) (name2 . value2) ...) 形式の dot pair のリストでフォーム値を返す ● dot pair については先週のスライド見てね
  24. 24. テンプレへの値の埋め込み● :princ­safe キーワードを使おう ● < > & をエスケープしてくれるので安全(defun greeting (request entity)  (let ((name (get­field­value request "name")))    (if (null name)        (setf name " 名無しさん ")        (setf name (bin­to­str name)))    (with­http­response (request entity)      (with­http­body (request entity)        (html (:html                (:head (:title (u " あいさつ ")))                (:body                 (:h1 (u " あいさつ "))                 (:p (:princ­safe (u (format nil "Hello ~a" name)))) )))))))(format t ... ) : 標準出力ストリームへ書き出す(format nil ... ) : ストリームへの書き出し無し
  25. 25. お待ちかねの課題です
  26. 26. こんなの作ってね! 超シンプル掲示板!
  27. 27. 書きこまれたデータの保持● SQL 系は次回やる予定なので、今回はオンメモリ(defvar *bbs­datas* nil)(defun add­new­article (subject body)  (push (cons subject body) *bbs­datas*))
  28. 28. テンプレートの構成 書き込みエリア ページ全体 表示エリア
  29. 29. ページ全体テンプレート● こんな感じかな?(defun page­template ()  (html    (:html      (:head (:title "Tiny BBS"))      (:body       (write­section­template)       (dolist (article *bbs­datas*)         (view­template article))))))
  30. 30. 表示部分のテンプレ● こんな感じ(defun view­template (article)  (html    ((:div :style "border: 1px solid black; padding: 2px;")     ((:div :style "background­color: lightgray; color: black;")       (:princ­safe (u (car article))))     (:pre (:princ­safe (u (cdr article))))) ))
  31. 31. で、あと書かなきゃいけないのは 書き込み部分のテンプレ コントローラ関数 :bbs
  32. 32. コントローラ関数 bbs の作り方のヒント● request からフォーム値を取り出す ● 書き込みボタンが押されてたら – add-new-article を呼ぶ ● ページ全体テンプレを呼ぶ ● おしまい!
  33. 33. いやー。ヒント出しすぎ もう、余裕で作れるでしょ?

×