2 Dec 2011

移行しました

ブログは以下に移行しました

 

http://liquidz.github.com/

16 Oct 2011

#clojure でspymemcachedの薄すぎるラッパー書いた

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)))

キーにキーワードを使えるようにしたくらいで本当ペラッペラ。 まあ自分用ということで。

15 Oct 2011

自分用に heroku #clojure mongodb のテンプレートプロジェクト作った

※追記: このテンプレートは以下を参考にしています。

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 はインストールしておく

使い方(nsがmytestの場合)

$ 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

あとは煮るなり焼くなり好きにする感じで

10 Apr 2011

Plojuctor: Clojure REPL上で動作するプレゼンツールを作ってみた(半分ネタ) #clojure

thumbnail

元ネタは以下です。

Here Comes Clojure: A Clojure Talk in Clojure http://bit.ly/hU4qDx

中身が全部素のテキストだったので、こういうツールがあっても良いんじゃないかなぁ という軽い気持ちでツールにしてみました。

Plojuctor

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) でページ番号指定の移動も可です。

VimClojure

元ネタ同様に単純なClojure REPL上では色付けされません。 VimClojure上のREPLで動作させるとカラースキームによって色付けされます。

プレゼンの書き方

詳細は plojuctor.core, plojuctor.sentence を参照してください。 気が向いたらドキュメント書きます。 以下は単純な例です。

(defslide
  (title "スライドタイトル")
  (item "itemは箇条書き"
        (code (println "コードはこんな感じ"))
        "スライドは定義した順に表示"))

(defslide
  (middle-page
    (center-page
      "上下左右中央")))

最後に

基本的なセンテンスは実装したつもりなので、あとは関数なりマクロなりで 自分の使いやすいようにカスタマイズすれば良いかなぁという感じです。 ただ実際のプロジェクタで表示した時に見やすいかは全く保証できませんが、、、

というClojureネタでした。

25 Feb 2011

DotCloudでCompojureしてみた(Hello World, MySQL) #clojure

約2ヶ月の時間を経てDotCloudのinvitationがようやくきたからいじってみました。

@makingさんの以下の記事と同じことをClojureでやってみただけなので 真新しいことは何一つやってませんのでご承知置きください。

新しいPaaS?のDotCloudを試す

なお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

project.clj

こちらも@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/ といった “/"直下でサービスで動きます。

core.clj

単純なhello worldです。

(ns liquidz.core
  (:use [compojure core route]))

(defroutes app
  (GET "/" _ "hello clojure world")
  (not-found "page not found"))

動作確認&war化

ローカルでring起動

$ lein ring server

war化

$ mkdir service
$ lein ring uberwar

war化する際に存在しないディレクトリ配下にwarを吐こうとするとエラーになるので 事前にディレクトリは作成しておきます。

DotCloudへのプッシュ

プッシュも公式ドキュメントに書いてある通り行います。 なお以下コマンドはカレントディレクトリがleiningenで作成したプロジェクト直下である想定です。

$ dotcloud push liquidz.www ./service

上記コマンドで service 配下にある全てのファイルがDotCloud上にrsyncされます。 warファイルの吐き出し先を service にしたのは、ソースファイルなどまで rsync されるのが気持ち悪かったためです。

プッシュが完了すると以下のURLから動作が確認できます。

http://www.liquidz.dotcloud.com/

ね?簡単でしょ?

MySQLも試す

元記事と同様に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"))

MySQLのJDBCドライバを準備

以下から拾ってきて leiningen で作成したプロジェクトの lib にコピーしておきます。 http://java.keicode.com/lib/mysql-driver.php

これがないと “java.sql.SQLException: No suitable driver” のようなエラーが出るはずです。

動作確認&war化&プッシュ

前回同様です。

ローカルで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と比べると

  • SQLが使える
  • スピンアップタイムがない

という2点だけでも大きな利点になるではないかなぁと思いました。

そんな感じで開発はものすごくしやすい環境ではあるので、 まだベータに申し込んでない人は申し込んでみるのをオススメします。

http://www.dotcloud.com/

14 Feb 2011

「Java使いをScalaに引き込むサンプル集」をclojureで書いてみた #clojure

元ネタは以下なので、先に参照しておくとわかりやすいと思います。

Java使いをScalaに引き込むサンプル集 http://www.mwsoft.jp/programming/scala/java_to_scala.html

同じJVM上で動く言語としてClojureだってあるんだよというのを 知らしめたくて書いてみました。 なおここで示すClojureコードの例はあくまで個人的な書き方なので必ずしも正しい、効率的ではないのでおかしな点があればコメントください。 使ってるバージョンは Clojure 1.2.0 です。


ClojureだってだいたいJavaと同じよu…ゴメンなさい嘘です

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は元記事のとおり。

Java

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new File("foo.xml"));

Scala

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にはありません。(ドキュメントを見る限り)


Listや配列の初期化はClojureでは問題なし

リストの扱い易さはLisp方言であるClojureの強み。 Common Lisp, Scheme同様に以下で出来ます。

(def ls '("abc" "def" "ghi"))

またClojureにはリストの他にベクターもあります。

(def v ["abc" "def" "ghi"])

ベクターはベクター用の操作関数を利用することで、リストよりも効率よく操作できたりします。


デフォルト引数、あるよ

元記事にある foo を参考にします。

Scala

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)))

throws はClojureだって省略できるよ

こんな感じで書いても大丈夫です。Clojureも例外処理は書かなくて良いようにできています。

(defn get-connection []
  (DriverManager/getConnection "jdbc:sqlite:hoge.sqlite3"))

文字列の比較は罠になりません

元記事にあった以下の比較

Java

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))

Clojureもいろいろ省略できます

元記事のJavaは以下。

Java

public int sum(int i1, int i2)  {
    return i1 + i2;
}

素直に書いても型、returnが省略されます。

(defn sum [i1 i2] (+ i1 i2))

無名関数を使うと引き数名も省略できます。

(def sum #(+ % %2))

try-catchの共通化だって

マクロ使えばできます。 ちなみにここでいうマクロは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 するという処理を共通化したマクロです。


ループの入れ子も楽々

元記事の以下のループ

Java

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並に短く書けることはわかってもらえたと思います。 見た目のわかりやすさといった点では括弧が大きな壁にはなると思いますが、 まぁこんな言語もあるんだよというのが伝われば幸いかなぁと思います。

11 Jan 2011

パスワードチェックライブラリ作ったった #clojure

自分で使うためのものだけど、パスワードの入力制限を簡単に実装できるライブラリ作ったった。

使い方は、一般的に使われるであろうチェック用関数は用意してあるので、 その中で自サービスで使いたいものを選ぶだけな感じ。

; アルファベット、数字、記号を含んでいて、文字数が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)を参照のこと。 そんな感じで。

7 Jan 2011

Gravatarのライブラリ作ったった #clojure

需要は全然ないと思うけど自分でちょっと使いそうだったから作ったった。 でも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って必要なさそうだな。。まぁいいや。

22 Dec 2010

Compojure 0.5.3 on GAE/Jの問題点?自分だけ? #clojure

ローカルで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

という自分のためのメモ

16 Dec 2010

Javaのstaticメソッドをclojureのfnに変換してみた #clojure

引数が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できるのが ちょっとだけ嬉しいかも? でもあまり使い道多くないかも