ブログ移行します
GitHub-pages+jekyll+Octopressによるmarkdownなブログシステムがステキすぎるので移行します。

GitHub-pages+jekyll+Octopressによるmarkdownなブログシステムがステキすぎるので移行します。
小ネタです。とあるnodeモジュールのgithub見てて「なるほど」と思ったのでポスト。V8、つまりnode環境であれば以下方法でヒアドキュメントみたいなことが可能なんですね。
console.log(function(){/*
aaa
bbb
ccc
*/}.toString().split(/\n/).slice(1, -1).join("\n"));
元ネタはこんな感じでUsageの出力に利用してますた。ECMAの仕様的にはFunction.prototype.toStringは定義されてないので出力結果はエンジンの実装依存ってことになりますがV8はOKと。まぁ僕の場合、nodeプログラムはほとんどCoffeeScriptで書いちゃうわけですけどね(ヒアドキュメントで変数埋め込みが使えるから)。
各所で良書だと評判の「テスト駆動JavaScript」を途中まで読みまして、自分もこれは良書だと思ったので書評的にブログエントリーを書いてみます。
ターゲットとなる人は各章ごとに分かれると思いました。
「導入」です。読みべき人は以下。
持論としてTDDは「テスト手法」ではなく「設計と開発のためのプラクティス」と考えています。第1部ではそれに対する理解の足がかりが得られ、TDDの利点やJSでのTDDを始めるにあたっての必要な情報が解説されています。この第1部を読んで琴線に触れない人はそのままこの本を閉じて本棚にしまってください。
言語的な観点でJSと他言語の異なる点について解説しています。この章はTDD関係ありません。JSについて深い知識を有している人は読み飛ばしてOK。以下に当てはまる人は読んでおくといいと思います。
様々なモジュールの実装についてTDDでどのように行うかを解説していきます。ここからがこの本のメインコンテンツです。
第1部を読んでTDDに興味が出た、詳細が知りたい、という人が理解を深めるためにこの章を熟読するべきです。AjaxやDOMといったクロスブラウザな部分をTDDで開発しながらうまく抽象化する手法、また通常のブラウザ上ではないサーバーサイド環境でNode.jsを取り上げておりTDDでのモジュール開発など、幅広く取り扱っているのがTDDプラクティスに留まらず大変参考になります。
よりよいTDDを行うためのプラクティスについて言及しています。
「TDD実践をもう始めた、そこからさらによいTDDを書きたい」という人が読むべき章です。ぶっちゃけ僕はまだちゃんとここまで読めてません。
各章の最後にある「まとめ」がよくまとまっているので、まずは各章の導入部分とまとめだけを読めば良いです。この方法であれば30分ぐらいでざっくり全容が把握できます。その後、第3部以降はまとめを読んで気になる章から読んでいけばよいかと思います。
またTDDに興味沸かないという人でもJSの知識として第2部は読んでおくとよいです。
TDDは「テスト手法」ではなく「設計と開発のためのプラクティス」という認識が深まりました。うまく書かれたユニットテストはJSで直面する問題(AjaxやDOMといったクロスブラウザな部分の設計)に対してのよい設計を導いてくれると感じました(まだ実践できてないが)。
また外部から見たオブジェクトの仕様(IN/OUT、状態遷移、振る舞い)を表現する手法としてユニットテストは有効である。本書でも一貫してテストコードファーストでの解説がなされておりそれが実感できます。
ぶっちゃけ「JSのTDDはこうすればよい!」という銀の弾丸的なTDD方法論が分かったわけではありません。それはおそらく書くプロダクトコードでケースバイケース。ただイベントドリブンなJSにおいてどういった設計をしながらTDDで開発するのが良いか、という指針は確実に本書を読む前より理解出来たと思います。
構成のまとまり具合と網羅しているJS情報が秀逸。良書認定! JSでTDDをしたい人は必読 。そうじゃなくても JSデベロッパーは第2部必読 です。
CoffeeScriptではJavaScript1.7の機能がいくつか実装されてます。その中でのmyブームが分割代入(destructuring assignment)で、すごく便利なので本エントリーで紹介してみます。
MDNのドキュメントを見てもらうのがいいです。以上。
基本は「配列形式の分割代入」と「オブジェクト形式の分割代入」があります。それらを組み合わせた複雑な分割代入も可能です。まずは単純な配列形式の分割代入から。
ary = [1, 2, 3] [a, b, c] = ary console.log a # 1 console.log b # 2 console.log c # 3
続いてオブジェクト形式の分割代入。
obj = {x: 10, y: 20}
{x:objX, y:objY} = obj
console.log objX # 10
console.log objY # 20
変数名がプロパティ名と同じでよければもっと簡潔な書き方が可能です。
{x, y} = obj
console.log x # 10
console.log y # 20
が可能です(Scalaみたいな高度なものじゃない)。これはCoffeeScriptだけの実装なのかな?例えば最初の要素と2番目以降の要素を分割する場合。
[a, b...] = [1..5] console.log a # 1 console.log b # [2, 3, 4, 5]
最初と最後、それ以外を分割する場合。
[a, b..., c] = [1..5] console.log a # 1 console.log b # [2, 3, 4] console.log c # 5
想像つくかもだけど、以下あいまいなパターンはもちろんコンパイルエラーです。
[a, b..., c, d..., e] = [1..10] # コンパイルエラー ⇒ multiple splats are disallowed in an assignment: d...
MDNのドキュメントにも書いてありますが「一つの文によって全体の構造を読み込むことができるという点」というのが大きいと思います。これは言い換えると「1行でそのロジックで処理するデータのデータ構造を表現できる」ということ。JSONのレスポンスデータを処理するコードっていうのはよくあるシチュエーションだと思いますが、ちょっと昔のコード見て「これってどういったデータ構造を処理するロジックなんだっけ?」って感じることが自分の書いたコードですらよくあります。ロジックの意図をより短いコードで表現できるこういった機能は利用するほかないです。
前置きが長くなりましたが、実際にコードを書いてみます。例えばTwitterSearchAPIをJSONPで取得してレスポンスで何か処理するコードを書くとすると、
$.ajax
url: "http://search.twitter.com/search.json"
data:
q: "バルス"
dataType: "jsonp"
success: (data) ->
{page, results} = data
# pageとresultsを処理するロジックが続く...
みたいな。TwitterAPIのレスポンスが以外とシンプルだったのであんまり伝わらないかもですが、レスポンスが複雑なデータ構造の場合はこの恩恵が受けれるはずです、きっと。
CoffeeScriptでの分割代入(destructuring assiginment)について簡単ですがまとめてみました。利用することでロジックの記述が簡潔になるシチュエーションもいくつかありそうです。CoffeeScriptでのプログラミングテクニックとしてぜひ押さえておきたい機能かと!
最近お仕事で既存のJavaScriptプロダクトコードをCoffeeScriptで書き換えてるんですけど、まぁコードが簡潔になるわなるわで徐々にJavaScriptを受け付けない体になってる僕ですどうもこんにちは。
そんなわけで小難しい話なしで簡単に伝わりそうなCoffeeScript押しな理由を箇条書きで6つほどメモ。一人でもCoffeeScriptに興味持ってくれればコレ幸い。
新しい言語を学ぶには学習コストが発生するわけなので、以下なケースのJavaScriptコードっていう文脈を背景に話します。
こういった場合、少しでもロジックを簡潔に書けることがコードの可読性とメンテナンス性に大きく寄与していくので、これから説明するとこだけでの導入でも学習コストを上回る恩恵が受けれるんじゃないかなーと僕は思うのですよ。
JavaScriptで関数リテラルを書くとこうなります。
function cube(num) {
return Math.pow(num, 3);
}
これをCoffeeScriptで書くとこうなります。
cube = (num) ->
Math.pow num, 3
functionキーワードが必要なく「->」が関数リテラルを表現します。引数リストが必要なければ引数リストすら省略可能です。またreturnキーワードも必要なく、関数の最後に評価された式が戻り値となります。あとスコープを表すブレース(波括弧)は必要なく、スコープはインデントで表現されます(pythonライク)。また関数呼び出しの括弧も引数を与える場合は省略可能です。
ワンライナーで書けるのであればワンライナーにしてしまうのがCoffeeScriptっぽいと思うので、上記の関数の最終形はこうですね。
cube = (num) -> Math.pow num, 3
ブラウザJSで誰しもが以下なコードを書いたことがあると思います。
var self = this;
document.getElementById("hoge").onclick = function (e) {
self.clickHandler(e);
}
onclickを設定するスコープのthis参照のインスタンスメソッドをonclick関数内でコールしたいってやつですね。このselfって部分はthatやらいろんな流派をみたことがある。。これがCoffeeScriptだとシンタックスシュガーが用意されています。
document.getElementById("hoge").onclick = (e) => @clickHandler e
@はthisのシンタックスシュガーで「@clickHandler」は「this.clickHandler」と同じです。で上記例では関数リテラルを「->」ではなく「=>」と書いています。こうすると外側のthis参照と同じものが内側の@(this)でも参照できるというわけです。selfやらthatといったthis参照をローカル変数に格納する手間が削減され、これまで人それぞれな書き方だった部分も言語仕様として解決されるわけです。
Rubyライクな変数展開が文字列リテラルで可能です。
sayName = (name) -> "my name is #{name}!"
sayName "kozy" # "my name is kozy!"
そしてヒアドキュメントで複数行の文字列リテラルが書けるのです。
htmlString = """
<a href="#{href}">
<img src="#{src}" />
</a>
"""
ヒアドキュメントの場合はダブルクォーテーションのエスケープも気にする必要なし。簡単なHTMLのテンプレート処理であればCoffeeScriptだけで可能ですね。何かしらのテンプレートエンジンを利用するにしても元ネタとなるテンプレート文字列をプログラム内にplainなテキストとしてどうやって保持するかはJavaScriptの永遠の課題だと思ってました(文字列リテラルで保持?外部ファイルでAjax?textareaのinnerHTMをretrieve?)。それが解決できるだけでもCoffeeScriptは導入したほうがいいと思うよマジで。
オブジェクトのプロパティと値、および配列(Arrayライクなオブジェクト)のイテレーションがCoffeeScriptだと簡単に書けます。
console "#{key}: #{value}" for key, value of obj
console "#{key}: #{value}" for own key, value of obj
console "#{item}" for item in ary
オプジェクトプロパティのイテレーションは「of」を利用。プロトタイプチェーンを辿らずにイテレーションしたければ「for own」のほうを利用するとhasOwnPropertyが利用される形となります。
配列のイテレーションは「in」を利用します。配列のほうはコンパイルされた結果lengthプロパティをチェックする「for(var i=0, l=ary.length; i < l; i++)〜」なイテレーションに変換されるので、Arrayのメソッドは利用できないけどlengthは持っているArrayライクなargumentsやDOMNodes(getElementsByTagNameで取得できるやつ)なんかも上記の書き方で気にせずイテレーションできちゃいます。
またイテレーションの条件もwhenキーワードでワンライナーで書けたりするのも素敵です。たとえばnull以外の要素のみをイテレーションする場合。
console.log item for item in ary when item isnt null
JavaScript1.7の機能がCoffeeScriptでは実現されており、イテレーションからの値の生成が簡単にできます。forイテレーションの結果はそのループの最後に評価された値の配列が返ります。論よりコード。
sqrt = (i*i for i in [1..5]) console.log sqrt # [1, 4, 9, 16, 25]
ECMAScript5で実装されたmap関数と同じようなことが出来ますね。僕はデータからHTML文字列の変換なんかでよくこんな書き方をしちゃいます。
ary = [
{href: "a.html", text: "ページa"}
{href: "b.html", text: "ページb"}
{href: "c.html", text: "ページc"}
]
a_html = ("<a href="#{data.href}">#{data.text}</a>" for data in ary).join "¥n"
console.log a_html
###
<a href="a.html">ページa</a>
<a href="b.html">ページb</a>
<a href="c.html">ページc</a>
###
jsonpなんかやってると複雑なデータ構造に対するプロパティの存在チェックしながらで以下なコードとかみたことある。
var status = json && json.data && json.data.status;
ショートサーキット評価って呼ばれるやつですね。CoffeeScriptとはこれをスマートに解決してくれます。
status = json?.data?.status
Rubyライクに「?」を付けることで存在するかどうかのチェックコードが入ります。途中のプロパティが存在していなければundefinedが返ります。また関数呼び出しに対して「?」をつけると内部的にはfunction型かどうかのチェックがしっかり入ります。
result = obj.callback?()
どーでしょう?ちょっとしたことが多かったりしますが、こういったシンタックスシュガーにより手続き的でおまじない的なコードが減るので、本来やろうとしている処理だけが残りコードの可読性に寄与すると思います。みんなCoffeeScriptに興味持ってくれて、特にうちの会社からJavaScriptが無くならないかなーと日々夢みてますホント。
本当はパターンマッチと分割代入(destructuring assignment)なんかも入れたかったんだけど、それだけでエントリ1本書けそうな気がしたのでまた後で書く。。。
実は関数リテラルのくだりはテストコード書く場合に一番恩恵を受けると思う。Jasmineなんかは無名関数のスコープで1スペック表現する仕様なんで、無名関数のネスト祭りなわけなんですよ。このページの「Nested Describes」の項に書いてあるサンプルコードがCoffeeScriptで書き換えるのをパっと想像しただけでどれだけ簡潔になるかって話ですよね。
(c) 2011 kozy.heteml.jp