2010年1月10日日曜日

Share and Share Alike

私たちのアプリは新たな問題に出くわします:別々のブラウザウィンドウそれぞれに独自のブログが保持されたままです。これだと、殆どの人の為のブログの利点、つまり他人との共有が出来ません!新規投稿を挿入すると、新しいブログ値を生成するより、既存のブログを構造的に変更したほうが良いに決まっています。(HTDP41章)。そこで、構成に変更機能を追加しましょう。

ちょっとした詳細に目を向けましょう:web-server言語では、デフォルトではストラクチャは変更不可なのです。このデフォルトを無効にして、ストラクチャ変更子へのアクセスが欲しいのです。そうするにはストラクチャ定義に#:mutableを付け加えます。

初めに、blogpostのリストだ、としましたが、ブログの変更を許可し、ブログを変更可能なストラクチャとする為、定義に戻りたいと思います。


(define-struct blog (posts) #:mutable)



(struct blog (posts))
posts : (listof post?)


変更可能なストラクチャはストラクチャのフィールドを変更する為の機能を提供します;この場合、set-blog-posts!と呼ばれるストラクチャ変更子を手にします。


set-blog-posts! : (blog? (listof post?) . -> . void)


これでブログの投稿が変更可能になります。

Exercise.blog-insert-post!機能を書いてみましょう。


blog-insert-post! : (blog? post? . -> . void)


この機能の意図的な副作用はブログの投稿を拡張します。


ブログのデータ表現を変更したので、それを用いてwebアプリを改良します。また、注意しなければならない事は、webアプリ内部では同じブログ値を共有しているので、もはやハンドラを用いてそれをたらい回しにする必要がなくなりました:現時点のブログはBLOG変数を通して与えられます。

insert-blog-post!を加えた調整と変数の整理を経過して、私たちのwebアプリは今はこのようになります:


#lang web-server/insta

; ブログは a (make-blog posts)
; 投稿リストは (listof post)
(define-struct blog (posts) #:mutable)

; 投稿は (make-post title body)
; タイトルは文字列、本体も文字列
(define-struct post (title body))

; BLOG: blog
; 初期状態のブログ
(define BLOG
(make-blog
(list (make-post "First Post" "This is my first post")
(make-post "Second Post" "This is another post"))))

; blog-insert-post!: blog post -> void
; ブログと投稿を受け取り、ブログの頭に投稿を加える
(define (blog-insert-post! a-blog a-post)
(set-blog-posts! a-blog
(cons a-post (blog-posts a-blog))))

; start: request -> html-response
; リクエストを受け取り、webコンテンツ全てを
; 表示するページを生成する
(define (start request)
(render-blog-page request))

; parse-post: bindings -> post
; 束縛から投稿を抽出する
(define (parse-post bindings)
(make-post (extract-binding/single 'title bindings)
(extract-binding/single 'body bindings)))

; render-blog-page: request -> html-response
; BLOGの中身のhtml-responseページを生成する
(define (render-blog-page request)
(local [(define (response-generator make-url)
`(html (head (title "My Blog"))
(body
(h1 "My Blog")
,(render-posts)
(form ((action
,(make-url insert-post-handler)))
(input ((name "title")))
(input ((name "body")))
(input ((type "submit")))))))

(define (insert-post-handler request)
(blog-insert-post!
BLOG (parse-post (request-bindings request)))
(render-blog-page request))]

(send/suspend/dispatch response-generator)))

; render-post: post -> html-response
; 投稿を受け取り、投稿のhtml-response要素を生成する
(define (render-post a-post)
`(div ((class "post"))
,(post-title a-post)
(p ,(post-body a-post))))

; render-posts: -> html-response
; ブログを受け取り、全投稿のhtml-response
; 要素を生成する
(define (render-posts)
`(div ((class "posts"))
,@(map render-post (blog-posts BLOG))))

webアプリを訪ねた二つのウィンドウを開いて、両方のウィンドウから投稿してみてください。両方のブラウザが同じブログを共有していることが分かるでしょう。

0 件のコメント:

コメントを投稿