苦労じゃー(2)

秋は文化祭の季節である。近頃の若者はどんな生態か(ああ、すっかり爺の物言だな)観察の 目的で出かけてみた。

各クラスやクラブ毎にテーマを決めて、展示やら出し物をやっていた。季節外れの暑い日だった ので、アイスクリームがよく売れていた。中華饅を売ろうとした君達。来年は、ウェザーレポートの 会社の人に助言を求めて、よくリサーチしてね。あるいは、コンビニのおじちゃんに良く相談 するとか。余った中華饅は、後で死ぬ気になって食べたんでしょうかね。ああ、これも青春の よき思い出、なんちゃってね。

出し物とかで気合が入っているのは、1年生達。3年生は、もうどうでもいいよって投げ槍の風。 文化祭より、受験とかの準備で大変なんすかね?

でも、体育館でやってたロックのコンサート。3年生が高校生活を惜しんで、乗りのりな演奏を してたぞ。まあ、ロックだから、しんみりやれって言ったって無理だけどね。

かぶり物をかぶって、階段をそろりそろりと歩いていた連中(キャッキャと黄色い声を出してたんで、 女子高生か)がいたけど、どこから仕入れてきたんだろう? ああいう物のレンタルって有るのかな?

実習農場の脇で、女子高生が野菜や果物を売っていた。裏の畑で男子高生が収穫。それをトラクター やら猫車で一生懸命に売り場まで運んでいたよ。彼らもあと数年したら、明るい農村を担う一翼 になるんだろうな。今のうちから、婿、嫁の当たりを付けとけよ。文化祭は絶好の機会だから。

地域の奥様がニコニコしながら買っていた。ネギが 一束400円、本当に抱える程大きな束だ。これが売れていたね。おいらは、小松菜を買いました。 こちらは一袋100円。でもすごい量だ。

りんごは、まだ樹になっているんだけど時期尚早なので販売無し。きっとたわわに実って 収穫出来たら、地域の爺婆ホームに土産を持って、慰問に行くのかな。きっとそうだろう。そんな 事をふっと考えてしまいましたよ。

で、りんごのかわりに、ラ・フランスって言う 洋ナシを売っていた。大きなのが4個で300円。熟すまで、冷蔵庫で10日ぐらい保存しておいて 下さいって女子高生が言っていた。青い堅いのを食べたい時は、今すぐでも良いんですかって 聞こうと思ったけど、セクハラになりそうなので、おじさんは我慢しましたよ。

cake

clojureの開発環境を漁っていたら、cakeなんてのが 引っかかってきた。makeが元祖でrakeが生まれ、今度はcakeですかい。cake PHP とかと 若干かぶっている気がするけど大丈夫?

他に有名な環境として、エクリプスとかネットビーンズとか有るのは知ってますが、起動するのが 遅くて、尻軽ユーザーは絶対に使いません。(きっぱり)

このケーキは甘いルビーで出来ているようだ。FAQを読むと

Q: Why does Cake use Ruby?
A: Because we needed to write the client script is some widely available 
   scripting language, and bash got way too hairy way too fast. 
   Besides, Ruby is arguably more platform-independent than bash. 
   Also, we only use Ruby libraries that are included in the core distribution
   so Cake can work as many places as possible.

Rubyは、何処でも動くと認定して下さったようで、matzに成り代わってお礼申し上げます。 但し、Jrubyは、forkが標準じゃサポートしてないんでお勧めしませんとも書いてるな。

Javaは箱庭、やがてガラスの天井にぶち当たるって、shiroさんが言ってたと思うんだけど、 本当だな。まあ、それを承知してるんならいいけど。

で、使ってみようかなと思うんだけど、Cake on Windows の項を見ると、ruby 1.8.7限定っぽい。1.9系だとセグフォ になるとな。報告されてから随分と時間が経っているので、直ってるかも知れないけど、今回は 使うのを諦めよう。

かくして、放浪の旅へ。

clooj

次に見つけたのが、 cloojと言うやつ。javaで書かれたGUI式の 開発環境だ。インストールが楽そうなので触ってみるよ。

clooj-downloadsから、独立型の やつを取ってくるだけ。他には何も要らない。(まあ、JREが必要だけど、普通入ってるよね)

Windowsの場合は、取ってきたjarファイルをダブルクリックするだけで動き出す。jarファイルが 目障りなら、適当な所に隠しておいて、ショットカットを出しておけばそれでOK。

unixとかだと、.bashrcにでも、エイリアスを登録しておけばOK。shの一行野郎なんて無駄ですから、 bashをこき使いましょう。それにしてもLinux界隈では、shと言いつつbashだし、viと言いつつvim だったりして、何だかなあと思うよ。少なくても、viは純正のviかnviぐらいのシンプルな奴がいいね。

そうそう、vimがLoveな人は苦労じゃのプラグインがあるみたいだよ。vimからswank-clojureする 方法を誰か公開してましたよ。お好きな人は探してみてね。

alias clooj='java -jar ~/.java/clooj-0.2.4-standalone.jar'

おいらは、jarファイルの隠し場所として、~/.java を選んだ。このdirは、一度cloojを起動すると 自動的に作成され、その中にcloojの隠しdirが作られているんだ。(各種の設定情報が入ってるよ)

cloojの使い方

起動すると、3列に分かれた窓が出てくる。一番左側はプロジェクト関係のファイル配置図。複数の プロジェクトを登録しておいて、混乱の極みを味わうも良し、各作成者の個性を観賞するも良しです。

真ん中は、編集画面。シンタックスによって色が着かないのがちょっと残念と言えば残念ですだ。 ただ、しっかりと、括弧やダブルクォーテーションのバランスをチェックしてくれるのがLispの 編集系の面目を保ってる。

一番右側は上下2段に別れている。下側はREPLの入力欄。上側はREPLからの表示欄になっている。 プロジェクトを何か登録しておかないと、repl入力系が動かないので注意の事。最初、そんな事情が 分からんで、なんだ動かないじゃんと落胆しましたよ。こういうのって、何処かにちらっと書いて おいて欲しいぞ。

プロジェクトに新規ファイルを追加するときに、ちょっと注意が必要だ。例えば、myprojにhoge.clj を追加したい場合、myproj.hoge を指定しる。ファイル区切りに / を混ぜたり、エクステンションを 付けたりすると、希望のものが登録されない。慣れれば、どうって事無いけど、最初は面喰らうよ。 面倒なら、直接OS側から登録しちゃった方が早いかも。こういう暗黙の了承ってGUIでは普通の事 なんですかね?

そうそう、ファイルに変更を加えると、左側窓内のファイル名に変更の印 * が付くよ。(メニューから saveしてやれば消える)saveしないまま、cloojを終了しても、再起動すると復帰してくれるんで 実害は無いんだけど、ちょっと自分的には心穏やかじゃ無いな。

使ってみる

cloojからプロジェクト(myproj)を作って実験。

C:\homes\myzit\myproj\src\myproj>cat core.clj
(ns myproj.core
  (:use [myproj.hoge :only (hoge fuga)]))

(defn -main [& args]
  (hoge)
  (fuga)
  (println "Hello cljooj")
  (fuga))

core.cljってのは、デフォで作成されるファイル。普通はこのファイルに、メインエントリーの (-main)を置くらしい。そうすると、他にもファイルが必要になるんだな。よそのファイルで 定義した関数を楽に参照する為に、:use するとな。で、もう一方の下らないやつは

C:\homes\myzit\myproj\src\myproj>cat hoge.clj
(ns myproj.hoge)

(defn hoge []
  (println "HOGEHOGE"))

(defn fuga []
  "FUGSFUA")

一応これで動いたっぽいので、後は業界標準のleinでコンパイルしようとしたら、

C:\homes\myzit\myproj>lein compile
No namespaces to :aot compile listed in project.clj.

見事にエラーですよ。仰せに従って、

C:\homes\myzit\myproj>cat project.clj
(defproject myproj "1.0.0-SNAPSHOT"
  :aot [myproj.core myproj.hoge]  ;; <====== add
  :description "FIXME: write"
  :dependencies [[org.clojure/clojure "1.3.0"]])

:aot ってのを追加しました。(最初から追加しておいて欲しいぞ)

C:\homes\myzit\myproj>lein compile
Copying 1 file to C:\homes\myzit\myproj\lib
Warning: *classpath* not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise. Please either indicate ^:dynamic *classpath*
or change the name.
Compiling myproj.core
Compiling myproj.hoge
Compilation succeeded.

警告されつつコンパイル成功。詳しき事はこちらの サンプル参照ってか。思いの他不親切だな。

c:\homes\myzit\myproj>java -jar myproj-1.0.0-SNAPSHOT-standalone.jar
Failed to load Main-Class manifest attribute from
myproj-1.0.0-SNAPSHOT-standalone.jar

で、実行ファイルを作ってみたけど、エラーになる。何で? よう分からん。

ちょいとイジケて、cloojのソースをgit便で御取り寄せ。コンパイルして実行ファイルを作って みたら、ちゃんと動いてくれた。ついでに、何行あるか数えてみたら2500行を肥えてました。

おいらの実験コードはせいぜい数行。それなのに、5行のコードにもBugが有るって! このフレーズ、おいらが今発明 しましたからね。(それって、昔から言う、5分の虫にも魂有り、だから殺生はいかんよってのの 、単なるパクリじゃん)

で、じっと見てたら、:main が抜けてた。自動で入れておいて欲しいぞ。:gen-class も抜けてた。 (:gen-classって関数でも無いのに括弧で囲まなきゃならんて、ややこしいな)それに気づいて、emacsで修正しようとしたら、cloojがファイル属性をread-onlyに変更しちゃって るの。無理して開けば、文字コードはCP932って言ってくるし。。。

どうも、おいらの感性には合わないなあ。ストレスの元になりそうなので、使うのは止めて、部品取り の目的(作者の方へ、決してジャンクって事ではありませんので)で、置いておこう。

部品としてのclooj

部品として見た場合、目利きが必要だな。ざっとファイル名からどんなカテゴリーの部品が有るか 当たりを付ける。お宝鑑定団じゃないけど、余り価値のなさそうなやつに入れ込んでも仕方が無い からな。

ユーティリティにこんなのが有った。

;; identify OS

(defn get-os []
  (.. System (getProperty "os.name") toLowerCase))

(def is-win
  (memoize #(not (neg? (.indexOf (get-os) "win")))))

(def is-mac
  (memoize #(not (neg? (.indexOf (get-os) "mac")))))

(def is-unix
  (memoize #(not (and (neg? (.indexOf (get-os) "nix"))
                      (neg? (.indexOf (get-os) "nux"))))))

ちょいと走らせてみる。丁度今、このファイルを開いているんで、C-c C-k で、コンパイルした 後

user> (use 'clooj.utils)
nil
user> (get-os)

"freebsd"
user> (is-unix?)
; Evaluation aborted.
user> (is-unix)
false

Yes/Noで答えられる疑問文には、普通 ? を付けると思うんだけど、作者様は、しっかりJavaに 汚染されてました。それから、*bsd は、unix族では無い(と言うより、そんなのあるの知らない)と 思っておられるようです。これは頂けませんな。早速、抗議行動、もとえPatchでも送りましょうかね。

それ以前に、 .. って何よ。黒猫本で読んだはずだけど、忘れちゃった(それは、きっと歳のせい)

user> (doc ..)
-------------------------
clojure.core/..
([x form] [x form & more])
Macro
  form => fieldName-symbol or (instanceMethodName-symbol args*)

  Expands into a member access (.) of the first member on the first
  argument, followed by the next member on the result, etc. For
  instance:

  (.. System (getProperties) (get "os.name"))

  expands to:

  (. (. System (getProperties)) (get "os.name"))

  but is easier to write, read, and understand.

正に、どんぴしゃの説明が出てきたよ。Haskell屋さんが使う $ と一緒っぽいな。

後はJavaのドキュメントかな。まだ昔の名前(Sun)で 出ているけど、いつまでこのサイトは現役でいられるのだろう。きっとボラクルも心の中では、 Sunは永久に不滅ですって思ってるのかな。そう言えば、Cの父 dmr も、freeされて、天国に 回収されちゃいましたね。合掌。

ついでに、ドットも見とくかな

user> (doc .)
-------------------------
.
  (.instanceMember instance args*)
  (.instanceMember Classname args*)
  (Classname/staticMethod args*)
  Classname/staticField
Special Form
  The instance member form works for both fields and methods.
  They all expand into calls to the dot operator at macroexpansion time.

  Please see http://clojure.org/java_interop#dot

こうして見てくると、Javaの世界じゃん、唯一Lispっぽいのはmemoizeだな。おいらは、こやつが マクロと思うんだけど。本当はどうよ?、

user> (source memoize)
(defn memoize
  "Returns a memoized version of a referentially transparent function. The
  memoized version of the function keeps a cache of the mapping from arguments
  to results and, when calls with the same arguments are repeated often, has
  higher performance at the expense of higher memory use."
  {:added "1.0"}
  [f]
  (let [mem (atom {})]
    (fn [& args]
      (if-let [e (find @mem args)]
        (val e)
        (let [ret (apply f args)]
          (swap! mem assoc args ret)
          ret)))))

それにしてもClojureと言えども、Javaにおんぶに抱っこしてもらってコードを書くんだな。 ならば、今後お世話になるであろう、ファイルとのやりとりを探してみる。

(defn write-value-to-prefs
  "Writes a pure clojure data structure to Preferences object."
  [prefs key value]
  (let [chunks (partition-str pref-max-bytes (with-out-str (pr value)))
        node (. prefs node key)]
    (.clear node)
    (doseq [i (range (count chunks))]
      (. node put (str i) (nth chunks i)))))

この中に出てくる、with-out-strとかprがちょいと気になるんで、、、

user> (doc with-out-str)
-------------------------
clojure.core/with-out-str
([& body])
Macro
  Evaluates exprs in a context in which *out* is bound to a fresh
  StringWriter.  Returns the string created by any nested printing
  calls.
nil
user> (doc pr)

-------------------------
clojure.core/pr
([] [x] [x & more])
  Prints the object(s) to the output stream that is the current value
  of *out*.  Prints the object(s), separated by spaces if there is
  more than one.  By default, pr and prn print in a way that objects
  can be read by the reader
user> *out*
#<PrintWriter java.io.PrintWriter@1f4ea9d>

結局、*out* を、あちこちに接続すればいいのかな?schemeで言うportだな。 でも、ちょいと変な感じ。こういう時は 大海に向かって問うてみれば良い。

そしたら、Writing Files in Clojure なんてのが引っかかってきた。ちゃんとそれなりの便利屋さんが居るのね。知らんかったよ。

cloojのメニューに、フォント変更なんて言う素敵なのを見つけた時はちと嬉しかったよ。で、 早速呼び出してみたはいいけど、決定のボタンが無かった。変な作りだなあ。そのまま閉じれば 、その時のフォントを記憶しておいてくれるみたい。

フォントやサイズを変えると、即座に編集窓に反映されるんで、実際のソースでどう見えるか 納得づくなのが良い。んでもって、早速丸漢のOSAKAフォントにしたんだ。

でも、今月のCQ誌に、フォントのBug情報が載ってたよ。印刷するとカーニングだかがおかしく なるんですって。それも現象が出たり出なかったりの神出鬼没なやつらしい。

Jobsの御大が、お怒りなんですかね? アップル圏の意匠をゲイツ帝国で使うのは まかりならんってね。成仏出来ないで、こんな所でいじわるしてんのね。

由緒正しいフォントを使いましょう。それはIPAフォント。 使用許諾書に同意して、このページの中ほどに表示されている「TTFファイル/TTF file」の中の「IPAゴシック(Ver.003.03)/IPA Gothic(Sans serif)(Ver.003.03) を使えばいいです。