初心者が「Clojure で Web 開発をはじめてみよう」をやってみて、ひっかかったところ。と、ライブラリのメモ。
- 「プログラミングClojure 第2版」を一通り読んで
- 公式サイトのチュートリアルをやって
- 4Clojure(現在は閉鎖中)を「easy」まで解答
ぐらいの初心者です。
理解を深める為に、ひっかかったろころ、チュートリアルで使用されているライブラリをまとめてみました。
ひっかかったところ、すぐに飲み込めなかったところ
Varオブジェクト
シンボルを直接渡してしまうと
handler
を束縛していたオブジェクト(関数)が直接run-server
に渡ってしまい、それを後から変更することは出来なくなるのですが、Var
オブジェクトを渡しておけばhandler
を束縛するオブジェクトが変わってもrun-server
関数はVar
に格納されたオブジェクトをその都度参照出来るようになるので、サーバーを再起動せずにhandler
関数の再評価だけで出力結果を変更することができるようになります。
とりあえずは、「値渡しを参照渡しに変更」と読み替えて進めたけど、もう少し深いみたいなので、改めて調べます。
シンボル
Symbol は、それ自体が指し示す値を保持しているわけではない。
user=> (def x 1)
#'user/x
user=> 'x
x
user=> (type 'x)
clojure.lang.Symbol
user=> x
1
user=> (type x)
java.lang.Long
user=> (namespace 'user/x)
user
user=> (name 'user/x)
x
user=> (namespace 'x)
nil
user=> (name 'x)
x
メタ情報
http://ayato-p.github.io/clojure-beginner/intro_web_development/part3_what_is_compojure.html#id17
今まで使っていた
html
の定義はそのままに持ってきていますが、ring.util.response/response
もこのネームスペースに再定義します。再定義する際にring.util.response/response
のVar
をtodo-clj.util.response/response
に渡しているわけですが、このときにメタ情報が失われます(つまり引数の数などといった情報)。なので、alter-meta!
でメタ情報を更新しています。
clojure.org のリファレンスによると
型に関する情報をコンパイラーに伝達するために使用されますが、データソース、ポリシーなどに注釈を付けるなど、さまざまな目的でアプリケーション開発者が使用することもできます。
メタデータは同等性(またはハッシュコード)に影響を与えません。メタデータのみが異なる2つのオブジェクトは同じです。 (Google 翻訳)
https://clojure.org/reference/metadata
(def ^{:version 1} document "This is text")
;;=> #'user/document
(meta #'document)
;;=> {:version 1}
(alter-meta! #'document #(update-in % [:version] inc)) ;increase version
;;=> {:version 2}
コンディションマップ
http://ayato-p.github.io/clojure-beginner/intro_web_development/part3_5_middleware_for_dev.html#id1
(defn wrap-dev [handler]
{:pre [(or (fn? handler) (and (var? handler) (fn? (deref handler))))]}
(let [wrap-exceptions (try-resolve 'prone.middleware/wrap-exceptions)
:pre / post とかあるのは、契約プログラミングにおける 事前条件 / 事後条件を示しています。これは関数を実行する際に、それぞれの条件を満たしているかを毎回チェックする、というものです。 特に安全にコードを実行したい際に利用することができます。
(defn constrained-sqr [x]
{:pre [(pos? x)]
:post [(> % 16), (< % 225)]}
(* x x))
いずれかの条件がfalseと評価され、* assert *がtrueの場合、java.lang.AssertionError例外がスローされます。
~@(スプライシングアンクオート)
http://ayato-p.github.io/clojure-beginner/intro_web_development/part3_what_is_compojure.html#id1
replで実行すると、いろいろ名前空間名がついてややこしくなるけど、それを省略すると以下のようになる、はず。
`(1 2 3) ;リストをクオート
=> (1 2 3)
`(1 2 3 (for [i (range 5)] i)) ;
=> (1 2 3 (for [i (range 5)] i))
`(1 2 3 ~(for [i (range 5)] i)) ;forをアンクォート
=> (1 2 3 (0 1 2 3 4))
`(1 2 3 ~@(for [i (range 5)] i)) ;forをスプライシングアンクオート
=> (1 2 3 0 1 2 3 4)
マクロ
ソースを見て、やっている内容はわかるけど、実際に自分で作るときにマクロの使い所が難しそうです。
いろいろ記事が書かれているようなので、要調査。
使われているライブラリの概要
ring
Webのリクエスト→処理→レスポンスを抽象化して扱う枠組み。
Compojure
ルーティング+α。DSLを使うタイプ。
compojure.core/GET
(GET "/" request home)
第一引数はパスで、第二引数はバインディング、第三引数以降ではバインディングを利用して返却するレスポンスを作る部分。
compojure.core/context
パスの共通部分をまとめるものです
(defroutes todo-routes
(context "/todo" req
(GET "/" req todo-index)
(GET "/new" req todo-new)
compojure.core/routes
それぞれのルート定義(ハンドラー)をひとつの Ring ハンドラーへとする
compojure.core/defroutes
↑のマクロ定義
compojure.routes/not-found
prone
親切なエラー画面を出す。
environ
環境変数や Java のシステムプロパティを同じようにアクセス出来るようになる。
alenbic
replを再起動しなくてもライブラリを依存関係に追加。
Hiccup
タグベクターを HTML へ変換。
hiccup.core/html
bouncer
バリデーション
(require '[bouncer.core :as b]
'[bouncer.validators :as v])
;; => nil
user> (b/validate {:title ""}
:title v/required)
ring-http-response
ring.util.response
ネームスペースを置き換える便利な HTTP レスポンスに関するライブラリ
slingshot
Clojure の try
と throw
のそれぞれと互換がある try+
, throw+
というマクロを提供するライブラリ
potemkin
便利な関数いろいろ
ディスカッション
コメント一覧
まだ、コメントがありません