### 問題: 手続きを定義しなさい。引数には `method`と`path`を受け取る。 `method` は `GET`, `POST`, `HEAD`, `PUT`などの文字列である。 path は `/` から始まる任意の文字列である。 (`"/"` だけの場合もありうる) 返り値は `[status, contents]` からなるリスト/配列とする。 `status`は`"200 OK"`, `"404 NotFound"`などの文字列である。 `contents`は、method, path の関係ごとに紐付けられた文字列である 以下の要件を満たすように実装せよ。 ``` GET "/hello" → ("200 OK", "こんにちは") GET "/bye" → ("200 OK", "さよなら") POST "/bye" → ("200 OK", "ばいばい") DELETE "/bye" → ("200 ok" "きえました") 該当なし → ("404 NotFound", "ないです") ``` 処理とデータは可能な限り分離せよ。 `if (path == "/hello") 〜 elseif (path == "/bye")`のように、条件文にマジックナンバーが含まれるコードは望ましくない。 ### 回答 ```lisp= (defvar getdata '(("hello" . "こんにちは") ("bye" . "さよなら"))) (defvar postdata '(("bye" . (lambda (_elm) (list 200 "OK" "ばいばい"))))) (defvar data '("/hello" . (("GET" . "こんにちは"))) ("/bye" . (("POST"))) 404 NotFound 405 Method Not allowed (defun fn (method path) (unless (string-prefix-p "/" path) (error "not path start with /")) (let (status contents code str) (setq contents (cond ((string= "GET" method) (cond ;; (string= "/hello" path) ;; (setq code 200 ;; str "OK" ;; contents "こんにちは") (setq contents (alist-get method getdata)) (unless contents (setq code 404 contents "Not found")))) ((string= "POST" method) (t (let ((fn (alist-get method postdata))) (setq data (if fn (funcall fn method))) (setq code (nth 0 data)) (setq str (nth 1 data)) (setq contents (nth 2 data)))) (setq status (format "%s %s" code str)) (list status contents))) ```