Clojureでコマンドライン引数パースめも
tools.cliを用いれば簡単にできる。
導入
- project.clj の :dependencies に以下を追記
[org.clojure/tools.cli "0.2.2"]
利用例
- use に以下を追加
[clojure.tools.cli :only (cli)]
- main関数の実装例
(defn -main [& args] (let [[options extra-args banner] (cli args ["-p" "--port" "Listen on this port" :default 9999 :parse-fn #(Integer. %)] ["-h" "--host" "The hostname" :default "localhost"] ["-v" "--[no-]verbose" "Verbose" :default true] ["-h" "--help" "Show Help" :flag true])] (if (:help options) (println banner) ; ヘルプオプションが指定された場合はbannerを表示して終了 (my-function (:port options) ; そうでない場合は、各オプションとオプション以外の引数を渡して主処理実行 (:host options) (:verbose options) extra-args))))
- 実行例
lein run -- --help ;=> ;Usage: ; ; Switches Default Desc ; -------- ------- ---- ; -p, --port 9999 Listen on this port ; -h, --host localhost The hostname ; -v, --no-verbose, --verbose true Verbose ; -h, --no-help, --help false Show Help lein uberjar java -jar target/該当のjar --help ;=> (同上) lein repl (use :reload 'myapp.core) (-main "--help") ;=> (同上)
補足
- cli 関数の戻り値は options extra-args banner からなるベクタ
- options コマンドオプション部分をパースしてマップにしたもの
- extra-args コマンドオプション以外の引数のベクタ
- banner ヘルプ表示用の整形された文字列
ClojureコードのAPIドキュメント生成メモ
Codoxを使って簡単に生成できる。
Compojure、Hiccup、RingもCodoxを使ってAPIドキュメント生成しているよう。
導入
- project.clj の :plugins に以下を追記
[codox "0.6.4"]
実行
下記コマンドを実行すると、docフォルダ内にAPIドキュメントが生成される。
lein doc
なお、ドキュメント化されるVarは以下を満たすもののみである。
- パブリックである
- doc-stringが指定されている
- メタデータ「:no-doc true」が指定されていない
実行オプション
project.cljに追記する形で以下のオプション指定可能。
対象の指定
- 対象ソースディレクトリの指定(デフォルトはsrc)
:codox {:sources ["path/to/source"]}
- 対象から除外する名前空間の指定
:codox {:exclude [my.private.ns another.private.ns]}
- 対象とする名前空間を明示的に指定
:codox {:include [library.core library.io]}
出力内容の指定
- 異なる出力関数を用いるように指定
:codox {:writer codox.writer.html/write-docs}
:codox {:src-dir-uri "http://github.com/clojure/clojure/blob/master"}
-
- 関数のリンクについて、その関数の定義行のアンカーにダイレクトにリンクさせる
:codox {:src-dir-uri "http://github.com/clojure/clojure/blob/master" :src-linenum-anchor-prefix "L"}
Emacsの操作メモ
今更ながら、Emacsの操作メモ
ヘルプ
私はC-hをBSに当てて、ヘルプはC-?に当てている。
そのためC-h C-hは打てないので、ヘルプのヘルプは「M-x help-for-help」で参照する。
ヘルプサブコマンド
- a コマンド名検索(apropos)
- b 現在のキーバインド一覧(bindings)
- k 指定したキーにバインドされているコマンドの表示(key)
- w 指定したコマンドにバインドされているキーの表示(where)
- f 指定した関数の説明を表示(function)
- v 指定した変数の説明を表示(val)
シェル
検索(isearch)(C-s)中のコマンド
- C-w 現在のカーソル位置の内容に沿って、検索文字を広げる
- M-y 検索窓へのyank
- C-h b キーバインド一覧(C-hを殺してると使えない。。)
- C-h m ヘルプ(C-hを殺してると使えない。。)
(個人的)Clojureのコーディングルールめも
Clojureの個人的なコーディングルールを整理しておく。
シンボルの命名
全般
- 「-」区切りの単語列
関数
- 状態を変化させる関数には末尾に「!」を付与
- 述語には末尾に「?」を付与
関数以外のvar
- グローバルを意識したvarのシンボルには、接頭と末尾に「*」を付与
束縛
- 値を気にしない束縛には「_」を使う
名前空間
- プロジェクト内のライブラリは use で読み込む
- 外部ライブラリは基本的に require :as で読み込む
- 頻用する関数等、名前空間に直接読み込んだ方が明らかに可読性が上がる場合は use :only で読み込む
(参考)OSSプロジェクトでの例
- プロジェクト内ライブラリの読み込み
- require :as で読み込んでいる:Ring, Korma, ...
- use で読み込んでいる:Compojure, Hiccup, ...
メタデータ
- doc-stringは必ず記述する(nsおよび各種def)
- :author を記述する?(←ソースに著者情報とか入れるべきか迷い中。clojure.coreのnsには記述されているが・・・。RingみたいにCONTRIBUTORS.mdとか作って関係者列挙とかの手もある)
- :added で追加されたバージョンを明記する?(←同じく迷い中。バージョン管理システム側に任せて良い気もする)
スコープ
- 純粋関数は基本的にグローバルで定義(defn)すること?(←迷い中。再利用奨励したいのが意図だが)
- グローバルで定義した関数の外部仕様は無断変更禁止
- 嫌なら defn- で定義すること
Clojureの基礎〜中身確認系、クオート、その他記号系〜
「Clojureの基礎〜Clojureの特徴〜 - oknknicの日記」に引き続きClojureの基礎メモ。
中身確認系
- #' varスペシャルフォーム(シンボルをvarに解決し、Varオブジェクトそのものを返す)に展開されるリーダーマクロ
#'str ; #'clojure.core/str (meta #'str) ;メタデータの取得 ; {:arglists ([] [x] [x & ys]), :ns #<Namespace clojure.core>, :name str, :column 1, :added "1.0", :static true, :doc "With no args, returns the empty string. With one arg x, returns\n x.toString(). (str nil) returns the empty string. With more than\n one arg, returns the concatenation of the str values of the args.", :line 504, :file "clojure/core.clj", :tag java.lang.String}
- @ deref関数(参照先の値を返す)に展開されるリーダーマクロ
(def hoge (ref "hogehoge")) @hoge ; "hogehoge" (def toge "togetoge") @#'toge ; "togetoge"
クオート
その他、記号系
- ^ メタデータのリーダーマクロ
(def ^{:info "info-val"} metatest) (meta #'metatest) ; {:info "info-val", :ns #<Namespace xml.core>, :name metatest, :column 1, :line 1, :file "NO_SOURCE_PATH"} ; なお、関数定義の場合は下記のようにメタデータを記載できる (defn meta-test-fn "ドキュメント" {:metadata "メタデータ"} [] 1) (meta #'meta-test-fn) ; {:arglists ([]), :metadata "メタデータ", :ns #<Namespace xml.core>, :name meta-test-fn, :column 1, :doc "ドキュメント", :line 1, :file "NO_SOURCE_PATH"} ; :tagメタデータ(戻り値および引数の期待する型)は下記のように略記可能 (defn ^String upper [^String s] (.toUpperCase s))
- -> 第1引数を引数として第2引数の関数を実行し、その結果を引数として第3引数の関数を実行、・・・この繰り返し
(defn square [x] (* x x)) (-> 2 square square) ; 16
参考
- 作者: Stuart Halloway and Aaron Bedra,川合史朗
- 出版社/メーカー: オーム社
- 発売日: 2013/04/26
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (11件) を見る
Clojureの基礎〜Clojureの特徴〜
「Clojureの基礎〜名前空間〜 - oknknicの日記」に引き続き基礎メモ。
基本に立ち返って、Clojureの特徴を整理。
Lispである
構文をほとんどもたず、同図像性がある
関数型言語(ただし非純粋)
- 関数が第一級のオブジェクト
- 実行時に関数を生成できる
- 関数を引数にした関数を定義できる(高階関数)
- 関数を返す関数を定義できる
- 純粋関数は副作用をもたない
- データは不変になるため、必然的にスレッドセーフ
- 複数の関数を組み合わせても、想定外の相互作用が発生し辛い
- 純粋関数は参照透過性をもつ
- 遅延評価できる
- メモ化できる
- 並列化できる
- 関数実行に必要な情報は引数のみである
- 引数のみ準備すればよいため、テストし易い
非純粋関数型言語としての特徴
- 副作用のサポート
- 参照、エージェント、アトム、そしてソフトウェアトランザクショナルメモリ
- 動的束縛
JVM上で動く
JVM以外でも動く
- ClojureScript
- ClojureCLR
参考文献
- 作者: Stuart Halloway and Aaron Bedra,川合史朗
- 出版社/メーカー: オーム社
- 発売日: 2013/04/26
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (11件) を見る
nrepl.el(nREPLのEmacsクライアント)の使い方メモ
「EmacsでClojure開発環境構築メモ - oknknicの日記」でも少し言及したnrepl.el。
今回は実用メモ。
REPL操作
REPLの起動
- C-c M-j nREPL-Server と Client を起動し、Client から Server へ接続
- leiningenで生成したプロジェクトのcljファイルを開いた状態で実行すると、そのプロジェクトのREPLが起動
- C-u を前段で実行すると、プロジェクトをエコーエリアで選択可能
- C-c C-z REPLバッファにカーソルを移動
REPL操作
- TAB シンボルのコンプリート
- C-j 改行+インデント
- C-RET 必要な括弧を全て閉じた上で評価
- C-c M-o REPLバッファのクリア
エディタ操作
なお、以下の操作は C-右クリック で選択して実行も可能。
REPLへ影響を与える操作
編集補助
- M-TAB(ESC TAB) シンボルのコンプリート
カーソル移動
- M-. シンボルの定義へ移動
- M-, 移動前へ戻る
情報表示
- C-c C-d カーソル位置のシンボルのドキュメントを表示
- C-c C-s カーソル位置のシンボルのソースを表示
- C-c C-j カーソル位置のシンボルのJavaDocを標準ブラウザで表示
マクロエキスパンド
- C-c C-m カーソル位置のシンボルをmacroexpand-1し、別バッファへ表示
- C-c M-m カーソル位置のシンボルをclojure.walk/macroexpand-allし、別バッファへ表示
参考:キーボードショートカットリスト
参考:nREPLサーバをClojureアプリケーションに組み込む
project.cljに追記
[org.clojure/tools.nrepl "0.2.3"]
アプリケーションに追記
(use '[clojure.tools.nrepl.server :only (start-server stop-server)]) (defonce server (start-server :port 7888))