herokuでmemcached使うのにちょうど良いライブラリが見当たらなかったので、 spymemcached の set/get のみをラップしたclojureライブラリ書きました。薄い!
https://github.com/liquidz/clj-spymemcached
https://clojars.org/clj-spymemcached
; 接続 (memcached! :host "localhost" :port 11211) ; 文字列 (cache-set :hello "world") ; default expiration = 3600 (cache-get :hello :default "default value") ; リスト (cache-set :ls '(1 2 3 4) :expiration 3600) (= 1 (first (cache-get :ls))) ; マップ (cache-set :map {:a 1 :b 2}) (= 2 (:b (cache-get :map)))
キーにキーワードを使えるようにしたくらいで本当ペラッペラ。 まあ自分用ということで。
※追記: このテンプレートは以下を参考にしています。
Clojure on Heroku with Noir and Mongo in 10 minutes http://thecomputersarewinning.com/post/clojure-heroku-noir-mongo
heroku + clojure + mongo の環境作りに ちょっと時間を使ってしまったのでテンプレートプロジェクトとしてまとめてみました。自分用に。
https://github.com/liquidz/heroku-template
leiningen, git, heroku はインストールしておく
$ git clone git://github.com/liquidz/heroku-template.git mytest $ cd mytest $ ./setup.sh mytest $ heroku create --stack cedar $ heroku addons:add mongohq:free $ git push heroku master
setup.sh は各ファイルの ns を変換するスクリプト
なおローカルで実行する場合には以下で実行すると、reload, stacktrace が有効になります
$ lein run -m mytest.dev
あとは煮るなり焼くなり好きにする感じで

元ネタは以下です。
Here Comes Clojure: A Clojure Talk in Clojure http://bit.ly/hU4qDx
中身が全部素のテキストだったので、こういうツールがあっても良いんじゃないかなぁ という軽い気持ちでツールにしてみました。
https://github.com/liquidz/plojuctor
テストコードもドキュメントも書いてないαバージョンです。 動作がおかしいところもあると思いますがご了承ください。
$ git clone git://github.com/liquidz/plojuctor.git $ cd plojuctor $ lein deps $ lein repl user=> (use 'plojuctor.core :reload) user=> (next-page!)
スライドの移動は (next-page!) , (prev-page!) で行います。 (move-page! N) でページ番号指定の移動も可です。
元ネタ同様に単純なClojure REPL上では色付けされません。 VimClojure上のREPLで動作させるとカラースキームによって色付けされます。
詳細は plojuctor.core, plojuctor.sentence を参照してください。 気が向いたらドキュメント書きます。 以下は単純な例です。
(defslide (title "スライドタイトル") (item "itemは箇条書き" (code (println "コードはこんな感じ")) "スライドは定義した順に表示")) (defslide (middle-page (center-page "上下左右中央")))
基本的なセンテンスは実装したつもりなので、あとは関数なりマクロなりで 自分の使いやすいようにカスタマイズすれば良いかなぁという感じです。 ただ実際のプロジェクタで表示した時に見やすいかは全く保証できませんが、、、
というClojureネタでした。
約2ヶ月の時間を経てDotCloudのinvitationがようやくきたからいじってみました。
@makingさんの以下の記事と同じことをClojureでやってみただけなので 真新しいことは何一つやってませんのでご承知置きください。
なおeasy_install, leiningenはインストール済みという前提で進めます。
以下の公式ドキュメントに沿って進めます。
http://docs.dotcloud.com/static/tutorials/firststeps/
dotcloudのインストール
$ sudo easy_install dotcloud
アプリケーションの作成
$ dotcloue create liquidz
サービスをデプロイ
$ dotcloud deply -t java liquidz.www
今回はClojureを使うのでサービスのタイプはJavaを選びました。 またサービス名を liquidz.www としてので、このサービスには http://www.liquidz.dotcloud.com/ というURLが割り当てられることになります。
Compojureを使ってサクッと作ります。
$ lein new liquidz $ cd liquidz
こちらも@makingさんの以下の記事をベースにwarファイルを作成できるようにしています。 @makingさん様々です。 http://blog.ik.am/entry/view/id/58/title/Clojure%E3%81%A7%E4%BD%9C%E6%88%90%E...
(defproject liquidz "1.0.0-SNAPSHOT" :description "FIXME: write" :dependencies [[org.clojure/clojure "1.2.0"] [org.clojure/clojure-contrib "1.2.0"] [compojure "0.5.3"] ] :dev-dependencies [[lein-ring "0.2.4"]] :uberjar-name "service/root.war" :ring {:handler liquidz.core/app} )
uberjar-nameがなぜ “service” 配下なのかは後ほど説明します。 また war のファイル名は root.war にすると http://www.hogehoge.dotcloud.com/ といった “/"直下でサービスで動きます。
単純なhello worldです。
(ns liquidz.core (:use [compojure core route])) (defroutes app (GET "/" _ "hello clojure world") (not-found "page not found"))
ローカルでring起動
$ lein ring server
war化
$ mkdir service $ lein ring uberwar
war化する際に存在しないディレクトリ配下にwarを吐こうとするとエラーになるので 事前にディレクトリは作成しておきます。
プッシュも公式ドキュメントに書いてある通り行います。 なお以下コマンドはカレントディレクトリがleiningenで作成したプロジェクト直下である想定です。
$ dotcloud push liquidz.www ./service
上記コマンドで service 配下にある全てのファイルがDotCloud上にrsyncされます。 warファイルの吐き出し先を service にしたのは、ソースファイルなどまで rsync されるのが気持ち悪かったためです。
プッシュが完了すると以下のURLから動作が確認できます。
http://www.liquidz.dotcloud.com/
ね?簡単でしょ?
元記事と同様にMySQLも試します。MySQLサービスの作成手順はまったく同じです。
$ dotcloud deploy -t mysql liquidz.db $ dotcloud info liquidz.db
上記infoで作成したMySQLのrootのパスワード、ホスト名などなどがわかります。
MySQLへアクセスするようちょっと修正します。 今回はMySQLアクセス用に /sql というルートを追加しました。
(ns liquidz.core (:use [compojure core route] [clojure.contrib.sql])) (def db {:classname "com.mysql.jdbc.Driver" :subprotocol "mysql" :subname "//db.liquidz.dotcloud.com:1455" :user "root" :password "パスワード" }) (defroutes app (GET "/" _ "hello clojure world") (GET "/sql" _ (with-connection db (with-query-results rs ["select 40+2"] (-> rs first str)))) (not-found "page not found"))
以下から拾ってきて leiningen で作成したプロジェクトの lib にコピーしておきます。 http://java.keicode.com/lib/mysql-driver.php
これがないと “java.sql.SQLException: No suitable driver” のようなエラーが出るはずです。
前回同様です。
ローカルでring起動
$ lein ring server
war化
$ lein ring uberwar
push
$ dotcloud push liquidz.www ./service
プッシュが完了したら本番環境でも確認してみましょう。
http://www.liquidz.dotcloud.com/sql
“{:40+2 42}” こんな結果が返ってくるはずです。 ちゃんとMySQL上で足し算ができ、結果も受け取れてますね。
想像以上に簡単に動いたのでビックリしました。 言語もPHP, Python, Ruby, Javaと使えるので、何か作って公開したいという時にはかなり有力候補になるんじゃないかなぁと。
ただ、まだじっくり触れてない何とも言えないですが、現状はデプロイ、プッシュが簡単に出来るコマンド類と実際にアプリが動く環境が提供されているだけなので、テストする際には自前でいろいろ準備しないといけないはず。 その辺りは優秀なテスティングフレームワークがデフォルトで提供されているappengineに軍配が上がる感じです。
でもappengineと比べると
という2点だけでも大きな利点になるではないかなぁと思いました。
そんな感じで開発はものすごくしやすい環境ではあるので、 まだベータに申し込んでない人は申し込んでみるのをオススメします。
元ネタは以下なので、先に参照しておくとわかりやすいと思います。
Java使いをScalaに引き込むサンプル集 http://www.mwsoft.jp/programming/scala/java_to_scala.html
同じJVM上で動く言語としてClojureだってあるんだよというのを 知らしめたくて書いてみました。 なおここで示すClojureコードの例はあくまで個人的な書き方なので必ずしも正しい、効率的ではないのでおかしな点があればコメントください。 使ってるバージョンは Clojure 1.2.0 です。
ClojureもJavaの機能をそのまま使うことができます。 以下はFileReaderを使った例。
(import '[java.io File FileReader BufferedReader]) (let [reader (BufferedReader. (FileReader. (File. "temp.txt")))] (try (doseq [line (take-while (comp not nil?) (repeatedly #(.readLine reader)))] (println line)) (finally (.close reader))))
Scalaと違ってJava使いに馴染みやすい記述とは言えないものになっています。 ちなみに with-open マクロを使うと close が不要になります。
(with-open [reader (BufferedReader. (FileReader. (File. "temp.txt")))] (doseq [line (take-while (comp not nil?) (repeatedly #(.readLine reader)))] (println line)))
あとちょっと脱線しますが、 clojure.contrib.io/read-lines を使うともっと楽です。
(use '[clojure.contrib.io :only [read-lines]]) (doseq [line (read-lines "temp.txt")] (println line))
Java, Scalaは元記事のとおり。
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(new File("foo.xml"));
val factory = DocumentBuilderFactory.newInstance();
val builder = factory.newDocumentBuilder();
val doc = builder.parse(new File("foo.xml"));Clojureだと以下です。この状況でdefを使うのは変なのでlet使ってます。
(let [factory (DocumentBuilderFactory/newInstance) builder (.newDocumentBuilder factory) doc (.parse builder (File. "foo.xml"))] ;do something )
factory, builder を束縛する必要がないなら “..” を使って以下のようにも書けます。
(let [doc (.. (DocumentBuilderFactory/newInstance) (newDocumentBuilder) (parse (File. "foo.xml")))] ;do something )
言語の説明記事じゃないので"..“の詳細は省きますが、Clojureなら1つ1つ束縛しなくても書けます。 なお Scala にある "別名import” はClojureにはありません。(ドキュメントを見る限り)
リストの扱い易さはLisp方言であるClojureの強み。 Common Lisp, Scheme同様に以下で出来ます。
(def ls '("abc" "def" "ghi"))
またClojureにはリストの他にベクターもあります。
(def v ["abc" "def" "ghi"])
ベクターはベクター用の操作関数を利用することで、リストよりも効率よく操作できたりします。
元記事にある foo を参考にします。
def foo(c1 : Char = 'A', c2 : Char = 'B', c3 : Char = 'C') {
println(c1.toString + c2.toString + c3.toString)
}Clojureのcoreだけ使うと以下のようになります。
(defn foo [& {:keys [c1 c2 c3] :or {c1 "A", c2 "B", c3 "C"}}] (println (str c1 c2 c3))) (foo) ; => ABC (foo :c1 "D") ; => DBC (foo :c2 "E" :c3 "F") ; => AEF
1つの引数の場合でも名前を指定しないといけないところがScalaとの違いです。 また keys や or でゴチャゴチャしてます。 ここは clojure.contrib.def/defnk を使うと見やすくなります。
(use '[clojure.contrib.def :only [defnk]]) (defnk foo2 [:c1 "A" :c2 "B" :c3 "C"] (println (str c1 c2 c3)))
こんな感じで書いても大丈夫です。Clojureも例外処理は書かなくて良いようにできています。
(defn get-connection [] (DriverManager/getConnection "jdbc:sqlite:hoge.sqlite3"))
元記事にあった以下の比較
String str1 = "テスト"; String str2 = "テスト"; String str3 = new String("テスト"); System.out.println(str1 + " == " + str2 + " = " + (str1 == str2)); //=> テスト == テスト = true System.out.println(str1 + " == " + str3 + " = " + (str1 == str3)); //=> テスト == テスト = false
ClojureでもScala同様に値で比較を行います。
(let [str1 "test" str2 "test" str3 (String. "test")] (println str1 "=" str2 "=" (= str1 str2)) ; => true (println str1 "=" str3 "=" (= str1 str3))) ; => true
オブジェクトの比較を行う場合は identical? が使えます。
(println str1 "identical?" str2 "=" (identical? str1 str2)) (println str1 "identical?" str3 "=" (identical? str1 str3))
元記事のJavaは以下。
public int sum(int i1, int i2) { return i1 + i2; }
素直に書いても型、returnが省略されます。
(defn sum [i1 i2] (+ i1 i2))
無名関数を使うと引き数名も省略できます。
(def sum #(+ % %2))
マクロ使えばできます。 ちなみにここでいうマクロはC言語にあるようなマクロやエクセルマクロとはまったくの別物です。
(defmacro trycatch [& body] `(try ~@body (catch Exception e# nil))) (println (trycatch (/ 10 3))) ; => 10/3 Clojureでは分数になります (println (trycatch (/ 10 0))) ; => nil
最初の例で使った with-open も同様に close するという処理を共通化したマクロです。
元記事の以下のループ
for (int i = 1; i < 10; i++) for (int j = 1; j < 10; j++) System.out.println(i * j);
Scalaのforみたく、Clojureのforでもできます。
(some println (for [i (range 1 10), j (range 1 10)] (* i j)))
ただClojureのforは他言語のforと違ってリストを返す関数なので (some println ls) で出力してあげてます。 またScala同様に入れ子はいくつでも可能です。
(some println (for [i (range 1 4), j (range 1 4), k (range 1 4), l (range 1 4)] (* i j k l)))
またfor内での条件も同様
(some println (for [i (range 1 10), j (range 1 10) :when (or (even? i) (even? j))] (* i j)))
リストへの変換はもともとリストを返してるのでもちろんできます。
ClojureはLisp方言の1つなのでリスト操作はもちろん得意
(let [ls '(1 2 3 5 3 5 7 8)] ; ユニーク (println (distinct ls)) ; 偶数奇数でのグループ分け (println (group-by odd? ls)) ; 和 (println (apply + ls)) ; 積 (println (apply * ls)) ; それぞれ2倍したリスト (println (map #(* % 2) ls)))
2つのリストの差分は core で上手い方法が見つからなかった。。 とりあえずセットを使うと以下のように書けます。
(use '[clojure.set :only [difference]]) (println (difference (hash-set 1 2 3 4 5) (hash-set 1 4 5)))
またClojureでもScala同様にArrayListなどは扱うことができます。
(import '[java.util ArrayList]) (let [ls (ArrayList.)] (doto ls (.add 1) (.add 2) (.add 3)) (println (apply + ls)) (println (map #(str "x=" %) ls)))
ぜんぜんたいしたコードではないですが、ClojureでもScala並に短く書けることはわかってもらえたと思います。 見た目のわかりやすさといった点では括弧が大きな壁にはなると思いますが、 まぁこんな言語もあるんだよというのが伝われば幸いかなぁと思います。
自分で使うためのものだけど、パスワードの入力制限を簡単に実装できるライブラリ作ったった。
使い方は、一般的に使われるであろうチェック用関数は用意してあるので、 その中で自サービスで使いたいものを選ぶだけな感じ。
; アルファベット、数字、記号を含んでいて、文字数が6~10文字 (def mychecker (combine-checkers contains-alphabet? contains-number? contains-symbol? (length-range 6 10)))
combine-checkersでは各チェック関数をANDで結合する関数。 結合した関数は左から順に評価。 ORで結合したい場合には combine-checkers-or を使えばおk。
で、作ったチェック関数はチェック結果を真偽値で返すだけだけど、 どのチェックで失敗したかを判別したい場合には @last-checker に 最後にチェックした関数の関数名がシンボル型で入ってるのでそれが使える。
; 文字数3~5かつ、全て同じ文字でないチェック関数 (let [checker (combine-checkers (length-range 3 5) not-same-characters?)] (checker "aa") ; false (println @last-checker) ; length-range ; -- (checker "aaa") ; false (println @last-checker) ; not-same-characters? ; -- (checker "aaaaaa") ; false (println @last-checker) ; length-range ; -- (checker "abc") ; true )
デフォルトで用意してあるチェック用関数は上記のソース(github)を参照のこと。 そんな感じで。
需要は全然ないと思うけど自分でちょっと使いそうだったから作ったった。 でもGravatarのAPIをそのままラッピングだけの簡単なものデス。
以下、使用例
; アバター画像URL取得 (gravatar-image "your@mail.address") ; サイズ指定 (gravatar-image "your@mail.address" :size 24) ; デフォルト画像指定 (gravatar-image "your@mail.address" :default "ttp://hoge.com/fuga.png") ; HTTPS利用 (gravatar-image "your@mail.address" :secure? true) ; ------ ; プロフィール取得 (gravatar-profile "your@mail.address") ; HTTPS利用 (gravatar-profile "your@mail.address" :secure? true)
デフォルト画像指定はURLちゃんと書いたらimgタグに展開されちゃったからわざとh抜いて書いてます。 あれ、でもプロフィール取得のHTTPSって必要なさそうだな。。まぁいいや。
ローカルでdevサーバを起動してアクセスすると 以下の例外が起きるのはうちだけの問題??
java.lang.NoClassDefFoundError: compojure/response/Renderable
ググっても特にそれらしい情報がなかった。 Renderableだから0.5系全般でそうだったのかな?
で、例外からして単純に defprotocol で生成されるはずの クラスファイルが参照できてないだけっぽいから、 compojure の project.clj に以下を追加してみて問題なくなったことを確認。
:aot [compojure.response]ちなみに上記を追加して lein compile とかすると classes に Renderable.class が生成されてることがわかるはず。
毎回修正しなくても良いように :aot を追加修正しただけのを clojarsにプッシュして作業終了。
http://clojars.org/org.clojars.liquidz/compojure
という自分のためのメモ
引数が1つだけであれば
#(Hogehoge/fuga %)
みたいにするだけだけど、オーバーロードされてるメソッドは 引数の個数分別々に定義しないといけなくて面倒だったから そこらへんも考慮してclojureのfnに変換するコードを書いてみた
以下、簡単な例
(ns test (:use jstatic)) (def encode (static-method->fn java.net.URLEncoder/encode)) (println (encode "ほげ")) ; => %E3%81%BB%E3%81%92 (println (encode "ほげ" "EUC-JP")) ; => %A4%DB%A4%B2 (println (apply encode (list "ほげ" "Shift_JIS"))) ; => %82%D9%82%B0
オーバーロードされたメソッドに対してapplyできるのが ちょっとだけ嬉しいかも? でもあまり使い道多くないかも