coffeescript触ってみた

文法ぱっと見ファーストインプレッション

https://sites.google.com/site/sappariwiki/coffeescript/coffeescript-langref
ここを読んでみて、coffeescriptの文法はぱっと見た感じかなり好みだなと思った。かなり良いとこどりの言語。ちなみにぼくはjavascriptもあんまりたくさん書いたことはありません。

関数

関数定義はHaskellに似ているけど、若干違和感がある。Haskellと=の位置が違うからかもしれない。
デフォルト引数は良いね。可変長引数は良いけど、おれの短いjs歴のなかではまだ使いたかったことがない。

内包表記

内包表記はmapでいいじゃんと思いつつも、あるとつい使っちゃう。何がそうさせるのかわからないけど、もしかしたらそれっぽく見えるからってだけかもしれない。ていうかjsってmapもなかったっけ?

範囲演算子

範囲演算子はとても良い。大好き。phppythonにもあるといいのに。

インデント

pythonhaskellと似たようなインデントでブロックを表す言語らしい。個人的にはあまり好きではない。自由に改行できないし、emacsで括弧単位の操作ができないし。

すべては式(できるだけ)

これは良い。もう全部式でいいよ。文とかいらね。ifもforも値を返す。そうでなくっちゃね。

存在演算子

これも良いね。jsのめんどいところをかっこ良くカバーしてる感じがする。

その他

後置のifとかperl出身の僕にはうれしい。なければないでかまわないけど。比較連結式もあればうれしいレベル。なくてもかまわない。

ちょっと書いてみてセカンドインプレッション

ということで最近書いてたjsをcoffeescriptに置き換えてみた。それで思ったこと。

コールバックで渡す無名関数のところがちょっとわかりにくい

関数定義は

hoge = (x, y) ->
    fuga x
    baba y

みたいな感じなわけだけど、無名関数はどうかくんだろうと思って適当に書いてみたら、それであってたみたい。

(x, y) ->
    fuga x
    baba y

でだ、jsってコールバックでがんがん無名関数渡すじゃない?そのときにこの関数定義とインデントでブロックを表すってルールでこんな感じになると思うんだ。

insertRecord = (item_id, value) ->
    db.transaction (tx) ->
        tx.executeSql select_count_traininngs, [],
                      (tx, res) ->
                          dt = new Date()
                          now = dt.toISOString()
                          tx.executeSql insert_traininng,
                                        [res.rows.item(0).cnt + 1, 1, localStorage['user'], item_id, value, now],
                                        (tx, res) -> console.log(res); update(),
                                        (tx, error) -> reportError 'sql', error.message

元のjsはこう

function insertRecord(item_id, value) {
    db.transaction(function(tx) {
        tx.executeSql(select_count_traininngs, [],
                      function(tx, res) {
                          var lastId = res.rows.item(0).cnt;
                          var dt = new Date();
                          var now = dt.toISOString();
                          tx.executeSql(insert_traininng,
                                        [lastId + 1, 1, user, item_id, value, now],
                                        function(tx, res) { console.log(res); update(); },
                                        function(tx, error) { reportError('sql', error.message); });
        });
    });
}

見た目は近いけど、コールバックで無名関数を渡していることが僕にはわかりにくい。2個目以降の'->'のある部分が全部コールバックで無名関数を渡しているんだけど、たとえば db.transaction (tx) -> の部分とか(tx)以降がdb.transactionの引数だってぱっとわかる?慣れの問題かもしれないけど、ちょっと止まっちゃう。(S式みたいに外側に括弧があればわかりやすいのに!)

javascritpのコードが生成されるのでそれを見ながら直せる

なんかあってるか自信の無いところとかは生成されたjsのコードを見ながら確認したり修正したりできる。

TRY COFFEESCRIPTが便利

http://jashkenas.github.com/coffee-script/のTRY COFFEESCRIPTにペーストしながら書いた。emacsのcoffee-modeをいれたんだけどまだあまり使いこなせてない。きっとこいつでもリアルタイムのjs変換したりできるに違いない。

まとめ

今後もjsをしばらくやってくと思うので、coffeescriptを使ってってみようと思う。

tea-time.elでポモドーロ(ついでにgrowlで通知するようにした)

ポモドーロをやりたいが、あたらしい職場でまだキッチンタイマーの音を鳴らす勇気がないので、emacsのタイマーを探してみた。
そしたらtea-time.el*1というのがあって、見てみるとこれがちょうど良さそうなので使ってみる。

インストール

M-x auto-install-from-url
https://raw.github.com/krick/tea-time/master/tea-time.el

して、.emacs等に

 (require 'tea-time)
 (setq tea-time-sound "path-to-sound-file")
 (setq tea-time-sound-command "afplay %s")

を貼付ける。
以上。

使い方

M-x tea-time

すると「How long? (min)」って聞かれるので、セットしたい時間を入力する。
あとは時間が来るとミニバッファに通知してくれる。

growlで

でも、ミニバッファの通知は控えめすぎてこれじゃ気づけないかもしれない、、ということでgrowlで通知するようにしてみた。
growlやgrowlnotifyがもしインストールされていなければ、ここ*2からインストールしておく。

で、適当にgrowl通知用の関数をでっち上げる。一応priorityとstickyにも対応しておいた。

(defun my-growl-notification (title message &optional priority sticky)
 ""
 (shell-command
    (format
     (concat "growlnotify -t \"%s\" -m \"%s\""
			 (if priority (concat " -p " (number-to-string priority)) "")
			 (if sticky " -s "))
			 title
			 message)))

次に、ちょっと手抜きしてtea-time.elのtea-timer関数を書き換える。

(defun tea-timer (sec)
  "Ding and show notification when tea is ready.
Store current timer in a global variable."
  (interactive)
  (run-at-time sec nil (lambda (seconds)
			 (tea-time-play-sound)
;; 			 (tea-time-show-notification (format "Time is up! %d minutes" (/ seconds 60)))
			 (my-growl-notification "tea-time.el" (format "Time is up! %d minutes" (/ seconds 60))) ; 上の行をコメントアウトして、この行を追加した
			 ) sec))

これでgrowlで通知されるようになった。

*1:https://github.com/krick/tea-time

*2:http://growl.info/

関数定義してghciでloadしてささっと試す

最近Haskell勉強中なんだけど、ghciで普通に関数定義できないみたい*1なんで、ちょっと不便してた。でもコンパイルするのはメンドイ。
そしたら今日ghciでその関数定義したファイル(というかモジュール?)をloadしてghci内で使えることを知った。
hoge.hsというファイル内に関数定義を書いて

import Chara

lstrip :: String -> String
lstrip = dropWhile isSpace

ghciで:loadするとすると、ghci内でその関数が使えるようになる。

*Main> :load hoge
[1 of 1] Compiling Main             ( hoge.hs, interpreted )
Ok, modules loaded: Main.
*Main> 

これでインタラクティブシェル的な感じで関数定義できて便利。

*Main> :t lstrip 
lstrip :: String -> String
*Main> lstrip "   jkjkj   "
Loading package filepath-1.1.0.4 ... linking ... done.
Loading package old-locale-1.0.0.2 ... linking ... done.
Loading package old-time-1.0.0.5 ... linking ... done.
Loading package unix-2.4.0.2 ... linking ... done.
Loading package directory-1.0.1.1 ... linking ... done.
Loading package process-1.0.1.3 ... linking ... done.
Loading package array-0.3.0.1 ... linking ... done.
Loading package time-1.1.4 ... linking ... done.
Loading package random-1.0.0.2 ... linking ... done.
Loading package haskell98 ... linking ... done.
"jkjkj   "
*Main> lstrip "   \tmuu"
"muu"
*Main> 

なんか初回実行時だけloadとかlinkとか入るのかな?良くわからないけど。

*1:let使えばできるっぽい

Pythonで辞書から存在しないキーで参照したときにもエラーにならないようにしたい

pythonで辞書からhoge['fuga']という書き方で存在しない無いキーで引くとKeyErrorになった。
無いときはNoneを入れたいなと思っていたので、どうしたら良いかと思っていたら@takezo70がgetというメソッドを教えてくれた。

辞書.get(キー, 無かったときの値)

kay-frameworkを触ってみるつもりが、python2.5用のsslモジュールをインストールするのに苦労した話

kayを試してみようと思ってDLしてきてチュートリアル*1にある通りにプロジェクト作成して、アプリ作成して、のところでつまずく。

[07-17 22:21:35 suzuki@suzuki-shinichirou-no-MacBook-Air /Users/suzuki/tmp/kaytest/myproject]
python manage.py startapp myapp
Running on Kay-1.1.1
/Users/suzuki/tmp/kaytest/myproject/kay/ext/media_compressor/media_compiler.py:14: DeprecationWarning: the md5 module is deprecated; use hashlib instead
  import md5
[07-17 22:22:16 suzuki@suzuki-shinichirou-no-MacBook-Air /Users/suzuki/tmp/kaytest/myproject]

おっと、hashlibが入ってない。もう入ってると思って手順飛ばしてた。
いや、py25-hashlibは入ってた。python2.5を指定して実行するとできた。しかしpy25-socket-sslがない。pilもない。これらを入れるか。どうやっていれれば良いのかな?良くわからないのでmacportsで入れる。

しかしエラーで入らない。どうやら僕のmacのpython2.5はmacportsで入れたものじゃないらしく(元々入っていた?)ゆえにmacportsでpy25-socket-sslなどが入れられないっぽい。かといって今更python2.5をmacportsで入れ直すのも面倒だし、、
(ちなみにssl以外のpilやipythonは

sudo easy_install-2.5 pil
sudo easy_install-2.5 ipython

でインストールできた)
ぐぐってやり方が書いてあるページを見つけた*2けど、その先のインストーラがおいてあるっていうリンクが切れていたり、、
そんなことをグニャグニャやっていたのだけど、http://pypi.python.org/pypi/ssl#downloadsからDLしてsetup.py installでさくっとインストールできた。

[07-18 02:00:18 suzuki@suzuki-shinichirou-no-MacBook-Air /Users/suzuki/Downloads/ssl-1.15]
sudo python2.5 setup.py install
Password:
looking for /usr/include/openssl/ssl.h
looking for /usr/include/krb5.h
running install
running build
running build_py
running build_ext
running install_lib
running install_data
copying test/test_ssl.py -> /System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/test
copying test/keycert.pem -> /System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/test
copying test/badcert.pem -> /System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/test
copying test/badkey.pem -> /System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/test
copying test/nullcert.pem -> /System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/test
running install_egg_info
Writing /Library/Python/2.5/site-packages/ssl-1.15-py2.5.egg-info
[07-18 02:00:25 suzuki@suzuki-shinichirou-no-MacBook-Air /Users/suzuki/Downloads/ssl-1.15]

またいつかのためのメモ

*1:http://kay-docs-jp.shehas.net/tutorial.html

*2:http://d.hatena.ne.jp/niiyan/20100318/1268926738