Hatena::ブログ(Diary)

you know something? | Use it for myself. このページをアンテナに追加 RSSフィード

2014-09-26 (Fri)

ブログを移動いたしました

08:57 | ブログを移動いたしましたを含むブックマーク ブログを移動いたしましたのブックマークコメント

今後は下記サイト更新して参ります。引き続きのご愛読をよろしくお願いいたします m(_ _)m

http://toomore-such.hatenablog.jp/

トラックバック - http://d.hatena.ne.jp/ayu_standalone/20140926

2011-06-17 (Fri)

TextMate で Clojure のソースを快適にインデント!

| 11:26 |  TextMate で Clojure のソースを快適にインデント!を含むブックマーク  TextMate で Clojure のソースを快適にインデント!のブックマークコメント

Clojure のソースを TextMate で書き綴って、REPL で実行するプロセスはとても快適ではありますが、一点ほど難点があります。それはインデントです。

python でも同様の症状が発生しますが、ruby のようにブロックの終端を表わすブレースなどが行頭に戻って来ないソース形式の場合、TextMate ではインデントが正常に動作しません。

仕方ありませんので、python では、Python Package Index : PythonTidy 1.20 を呼び出して代用しておりましたが、どうも Clojure でも同様の処置を施さねばならないようです。


Google 先生によると、こちらを

(参考) はてなブックマーク - TextMateでのClojureのインデント解決編 - マンジラボ

参考にせよ、との思し召しなのですが、残念ながら、当該サイトは閉鎖、ないしはメンテナンスされていない状態のようです。

ブクマに残されたコメントから推察するに、Emacs の clojure-mode を呼び出してコード整形を果たしている様子。その辺から Google 先生にお問い合わせすると....

(参考) All sizes | Tidy up clojure code in TextMate | Flickr - Photo Sharing!

有りましたぁ!なんと、コードの断片を画像で発見してしまいましたよw


この画像を写経することでキレイなインデントを獲得することができました。以下が Command(s) に埋め込むコードです。

#!/usr/bin/env ruby

filename = "/tmp/tmptx_tidyup_code.clj";

File.open(filename, "w") {|f|
  STDIN.each do |line|
    f.print line
  end
}

# path は clojure-mode.el を保存したパスに変更してください
# lisp-indent-offset は好みのインデント幅に変更してください

result = `/usr/bin/emacs -batch \
--eval '(load "/path/clojure-mode.el")' \
#{filename} \
--eval '(setq indent-tabs-mode nil)' \
--eval '(setq lisp-indent-offset 4)' \
--eval '(indent-region (point-min) (point-max) nil)' \
-f save-buffer &> /dev/null`

puts `cat #{filename}`

いやいや。これで閉じ括弧を先頭に持って来るような、無様なことをせずに済みます。

トラックバック - http://d.hatena.ne.jp/ayu_standalone/20110617

2011-06-16 (Thu)

「Clojure と slim3」の夏がやってくる (其の四)

| 12:08 | 「Clojure と slim3」の夏がやってくる (其の四)を含むブックマーク 「Clojure と slim3」の夏がやってくる (其の四)のブックマークコメント

忠実に Junit4 を再現しようとして、いささか躓いてしまいましたが、ヒントは Scala の Slim3 対応にありました。


(参考) Slim3をScalaで動かすためのいろいろ - ゆろよろ日記

package slim3scala.controller.Foo

import org.specs.Specification
import org.specs.runner._
import org.slim3.tester.ControllerTester

object IndexControllerSpec extends org.specs.Specification {

  val tester = new ControllerTester( classOf[IndexController] )

(以下略)

要は、ControllerTester や AppEngineTester さえ生成できれば、Clojure 由来のテスト環境でまったく問題無い、ということになります。

切っ掛けとなった id:yuroyoro さんには本当に感謝です。


そこで、まずは、コントローラーのテストです。

IndexControllerTest.clj

(ns com.example.controller.IndexControllerTest
    (:import
        com.example.controller.IndexController,
        javax.servlet.http.HttpServletResponse,
        org.slim3.tester.ControllerTester)
    (:use clojure.contrib.test-is))


(defn setup-fixtures
    "Docstring for setup-fixtures."
    [test-func]

    (def tester (ControllerTester. (.. (IndexController.) getClass)))
    (.setUp tester)
    (.start tester "/")
    (test-func)
    (.tearDown tester))
(use-fixtures :each setup-fixtures)


(deftest test-sample
    "Docstring for -run."

    (is (= (.. HttpServletResponse SC_OK) (.getStatus (.. tester response)))))

次に、サービスのテストです。

Slim3ServiceTest.clj

(ns com.example.service.Slim3ServiceTest
    (:import
        com.example.service.Slim3Service,
        org.slim3.tester.AppEngineTester)
    (:use clojure.contrib.test-is))


(defn setup-fixtures
    "Docstring for setup-fixtures."
    [test-func]

    (def tester (AppEngineTester.))
    (.setUp tester)
    (test-func)
    (.tearDown tester))
(use-fixtures :each setup-fixtures)


(deftest test-sample
    "Docstring for -run."

    (Slim3Service/newAndPut "abc")
    (is (= 1 (.. (Slim3Service/queryAll) size))))

これを

$ mvn test

で実行してあげると....

(前略)
-------------------------------------------------------
 T E S T S
-------------------------------------------------------
There are no tests to run.

Results :

Tests run: 0, Failures: 0, Errors: 0, Skipped: 0
# ↑ こちらは Java のテスト結果

[INFO] [clojure:test {execution: test-clojure}]

(中略)

Ran 2 tests containing 2 assertions.
0 failures, 0 errors.
# ↑ こちらが Clojure のテスト結果

(以下略)

はい。無事成功となりました。

余談ではありますが、Clojure のテストは俗に言う setUp や tearDown にクロージャーを上手く取り入れていて、大変分かりやすいですね。

さぁ、これで一通り、準備は完了です。

さぁて、Clojure と Slim3 で、この夏、何を作ろうかな?

トラックバック - http://d.hatena.ne.jp/ayu_standalone/20110616

2011-06-14 (Tue)

「Clojure と slim3」の夏がやってくる (其の弐)

| 15:08 | 「Clojure と slim3」の夏がやってくる (其の弐)を含むブックマーク 「Clojure と slim3」の夏がやってくる (其の弐)のブックマークコメント

(其の壱) で

これで、コントローラーの Clojure 化を無事果たすことができました。

次は、サービスの Clojure 化に挑戦してみたいと思います。

と申し上げたのですが、maven が生成する初期プロジェクトのコントローラーとサービスの Clojure 化を目指すことに変更しました。

取りあえず、出来上がった IndexController.clj は下記の通りです。

IndexController.clj

(ns com.example.controller.IndexController
    (:gen-class
        :extends org.slim3.controller.Controller
        :exposes {response {:get getResponce, :set setResponce}}
        :exposes-methods {forward forwardS, requestScope requestScopeS})
    (:import
        com.example.meta.Slim3ModelMeta,
        com.example.model.Slim3Model,
        java.util.Date,
        org.slim3.datastore.Datastore))


(defn -run
    "Docstring for -run."
    [this]

    (let [res (.. this getResponce)]
        (.println (.. res getWriter) "Hello, World!")

        (let [model (Slim3Model.)]
            (.setProp1 model (.. (Date.) toString))
            (Datastore/put model))

        (doseq [x (.. (Datastore/query (Slim3ModelMeta/get)) asList)]
            (.println (.. res getWriter) (.. x getProp1)))

        (.flushBuffer res)))

Java の IndexController 同様、"Hello World!" を出力した後、put した Slim3Model の query 結果から順次 prop1 の内容を出力します。

さて、次は、今度こそ、サービスの Clojure 化に挑戦してみたいと思います。


追伸: しかし、本当に Clojure のソースは美しいですね。もう 、ちょっと Java には戻れませんって。

「Clojure と slim3」の夏がやってくる (其の参)

| 18:47 | 「Clojure と slim3」の夏がやってくる (其の参)を含むブックマーク 「Clojure と slim3」の夏がやってくる (其の参)のブックマークコメント

さて、サービスの Clojure 化です。

本当は Pure Clojure で行きたかったところですが、そうすると、せっかくの Hot Reloading を無効にせねばなりません。

そうでなくとも、ゆとり Eclipse 世代w としては手動ビルドさえ面倒な状況ですから、ビルドのたびに開発サーバ再起動なんてやってられません。

なので、止むを得ず Java クラスとして扱うこととしました。

まずは、サービスのコードです。

Slim3Service.clj

(ns com.example.service.Slim3Service
    (:gen-class
        :methods [
                     #^{:static true} [newAndPut [String] void],
                     #^{:static true} [queryAll [] java.util.List]])
    (:import
        com.example.meta.Slim3ModelMeta,
        com.example.model.Slim3Model,
        com.google.appengine.api.datastore.Key,
        java.util.List,
        org.slim3.datastore.Datastore))


(defn -newAndPut
    "Docstring for new-and-put [prop1]."
    [prop1]

    (let [model (Slim3Model.)]
        (.setProp1 model prop1)
        (let [key (Datastore/put model)]
            (.setKey model key))))

(defn -queryAll
    "Docstring for queryAll."
    []

    (.. (Datastore/query (Slim3ModelMeta/get)) asList))

次に、作成したサービスを使用するよう、コントローラーを変更します。

IndexController.clj

(ns com.example.controller.IndexController
    (:gen-class
        :extends org.slim3.controller.Controller
        :exposes {response {:get getResponce, :set setResponce}}
        :exposes-methods {forward forwardS, requestScope requestScopeS})
    (:import
        com.example.meta.Slim3ModelMeta,
        com.example.model.Slim3Model,
        com.example.service.Slim3Service,
        java.util.Date,
        org.slim3.datastore.Datastore))


(defn -run
    "Docstring for -run."
    [this]

    (let [res (.. this getResponce)]
        (.println (.. res getWriter) "Hello, World!")

        (Slim3Service/newAndPut (.. (Date.) toString))

        (doseq [x (Slim3Service/queryAll)]
            (.println (.. res getWriter) (.. x getProp1)))

        (.flushBuffer res)))

Java クラスの扱いの勘所が分かってくると、スイスイ記述できますね。本当に素晴らしいです。

さて、次は、本来であれば先に行なうべきなのですが、TestCase を記述してみたいと思います。

トラックバック - http://d.hatena.ne.jp/ayu_standalone/20110614

2011-06-12 (Sun)

「Clojure と slim3」の夏がやってくる (其の壱)

| 08:18 |  「Clojure と slim3」の夏がやってくる (其の壱)を含むブックマーク  「Clojure と slim3」の夏がやってくる (其の壱)のブックマークコメント

最近、ようやく AppEngine にというか、KVS の扱いに慣れてきたように思います。

RailsDjango では常に DRY であること要求されますが、その無言の圧力に従っていれば、自然アプリ全体が見通しの良い構造になっていきます。

ある意味、考え無しでも、そこそこのモノができてしまいますので、実力が上がったように思いがちですが、実際はフレームワークの力によるもの、ということが往々にしてあります。

反面、GAE では製作者の技量が試されるような気がします。

ここは、規定時間内に処理が終了さえすれば、何も問われない世界です。だからと言って、何も考えずにアプローチしていては、この GAE というコースは攻略できません。

DRY ばかりを推し進めてもウマく行きません。さりとて、正規化を外しまくると管理が大変になってしまいます。とにかくバランスがとても大切で、この感覚を定着させるまでが一苦労でした。

「各種 API へのアクセスを可能な限り減らして、インスタンス内で高速にデータ処理する」というサイクルを、製作するアプリの性質ごとに最適化していくプロセスは、ちょっとしたパズルのようで、個人的には一番楽しい時間でもあります (ちなみに、一番キライなのはページ作りw)

ただ、先日発表になった新料金プランによって敷居が更に上がったような気がします。これからは、もっと妥協無く上記サイクルを徹底しないと利用料金を低く抑えられません (面倒になってしまって、手綱を緩めてしまうこと多々<涙>)

Rails のような FW とは異なり、AppEngine では、データとコードが相当なレベルで分離されていません。KVS からリスト構造を取得して、そのリストがコードに変化してユーザに届くような感じで、この感覚は正に Lisp であります。

そういう意味で、リストが扱いづらい Java への不満が募り始めたところでありました (ちなみに、Java の方がテスト環境の構築が容易であることを考慮すると、pytyon という選択肢は残念ながら有り得ません)

そこで、JVM 上の Lisp と言えば Clojure。Slim3 を Clojure から操れないか、試してみました。


まずは、プロジェクトの作成から。Jenkins から扱いやすいよう maven で生成します。

$ mvn archetype:generate -DarchetypeCatalog=http://slim3.googlecode.com/svn/trunk/repository

(中略)
Define value for property 'groupId': : com.example
Define value for property 'artifactId': : CljTest
(以下略)

次に、pom.xml を修正して Clojure 関連ツールの導入準備をします。

(参考) Clojureでの開発環境 - in a Stream


次に、プロジェクトを maven で Eclipse 化して Eclipse へインポートします。

$ mvn eclipse:eclipse

これで、Eclipse で編集できるようになりました。試してみたところ、Hot Reloading は有効のようです。

ただ、Eclipse の自動ビルドではコンパイルしてくれないので、手動でコンパイルする必要があります。

$ mvn compile (含む Java ファイル)
    or
$ mvn clojure:compile (Clojure ファイルのみ)

また、せっかくコンパイルした Clojure 由来のクラスファイルを消されてしまいますので、Eclipse の「Project メニュ → Build Automatically」のチェックを外しておきます。


さぁ、これで準備完了です。

手始めに maven が生成した IndexController を置き換えてみたいと思います。

まずは、src/main/java/com/example/controller/IndexController.java を削除します。

次に、src/main/clojure/com/example/controller/IndexController.clj と war/index.jsp を作成します。


IndexController.clj

(ns com.example.controller.IndexController
    (:gen-class :extends org.slim3.controller.Controller
    :exposes-methods {forward forwardSuper, requestScope requestScopeSuper}))


(defn -run
    "Docstring for -run."
    [this]

    (. this requestScopeSuper "msg", "OK?")
    (. this forwardSuper "index.jsp"))

;; 余談ではありますが、Java のソースと比べると圧到的に美しいですねぇ (主観 100%)

index.jsp

<!DOCTYPE HTML>
<html>
<body>
  <h1>Hello, World!! ${msg}</h1>
</body>
</html>

最後に、Eclipse の「Run メニュ → Run AsWeb Application」を実行した後、

$ mvn clojure:compile

を実行して http://localhost:8888/ にアクセスしてみましょう。

Hello, World!! OK?

と表示されれば、成功です。


これで、コントローラーの Clojure 化を無事果たすことができました。

次は、サービスの Clojure 化に挑戦してみたいと思います。

トラックバック - http://d.hatena.ne.jp/ayu_standalone/20110612