メモ: coffeescriptつこうてみた
今作ってるモノで試しにCoffeeScript使ってみたら存外に書きやすく、かつ楽しかったのでメモ。
本家
CoffeeScriptはRuby,Python,Haskellから影響を受けたプログラミング言語です。
CoffeeScriptの文法にしたがって書いたものをcoffeeコマンドでコンパイルするとJavaScriptになります。
要するに、JavaScriptのシンタックスが嫌いとか、JavaScriptゴチャゴチャしがちでなんとかしたいとか、Webブラウザで実行するスクリプトもRubyとかPythonとかHaskellとかみたいに書きたいよーとか思ってる人にはおすすめです。
長所と短所
まだ使い始めて1週間くらいなのですが、現時点で感じることは
長所
- 同じ事をするにもJavaScriptよりコード量が少なくてすむ(Wikipediaによると1/3)
- 吐き出すのがJavaScriptなので、うまく動かない際にも、何が起こってるのか理解しやすい
- 書いてて気持ちいい
- 読みやすい
短所
- ブラウザのエラー出力は、コンパイル結果のJavaScript上の位置を示すので、そこからCoffeeScript上の間違いを自分で探す必要あり
- 一部、IenternetExplorer8では実行できないJavaScriptを吐き出す
インストール
インストールにはNode.jsが必要です。Ubuntuなら
$ sudo apt-get install nodejs
です。Macとかでも、多分homebrewとかportsとかにあると思います。たぶん。
Node.jsが入ったら、あとはnpmコマンドでインストールですが、システム全体で共用するなら
$ sudo npm install -g coffee-script
あるいは、なにかしらのプロジェクトを作ってそのプロジェクトディレクトリ内にインストールしたいなら
$ mkdir hoge_project $ cd hoge_project $ npm install coffee-script
てやります。
Hello World
とりあえず、最初のCoffeeScriptを作ってみます。
emacsなど好みのエディタで"helloworld.coffee"というファイルを新規作成し、以下のようにかきます。
alert "hello world"
コンパイルしてみます。
$ coffee -c helloworld.coffee
helloworld.jsというファイルができたと思います。中身を見てみます。
// Generated by CoffeeScript 1.4.0 (function() { alert("hello world"); }).call(this);
このJavaScriptをブラウザから呼ぶためにHTMLファイルを用意します。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>はじめてのCoffeeScript</title> <script src="helloworld.js"></script> </head> <body> </body> </html>
Ajaxとかするわけじゃないので、このままHTMLファイルダブルクリックで開けば実行できます。
ある程度大きなプロジェクトではまとまった機能毎にクラスにまとめるとかするといいと思います。
class ClassSample # インスタンス変数 name: null # 他の関数の呼び出しは "@間数名()" で start_sample: () -> @hello() @name = "shin" @my_name() @map_sample() # Rubyみたいに、引数にデフォルト値を指定できます # Rubyみたいに、文字列に#{}で値を埋め込めます hello: (str = "world")-> alert "hello #{str}" # インスタンス変数の参照は "@変数名" で my_name: () -> alert "myname is #{@name}" # 配列内の各要素に処理を施した新たな配列をかえします # 無名関数は "(引数) -> 処理" です map_sample: () -> array = [1,2,3,4,5,6] new_array = array.map (e) -> e * e console.log new_array
Rubyユーザが気をつけるべきことは、CoffeeScriptではブロックの終わりのendがいらないってことです。
この辺はPythonの影響があるらしく、インデントでブロックレベルを表現します。
たとえば条件分岐などは
a = 10 if a > 11 alert "10より大きい" else alert "10以下"
てな具合です。classや関数、ループなども同様となります。
コンパイルするとこうなります
$ coffee -c class_sample.coffee
// Generated by CoffeeScript 1.4.0 (function() { var ClassSample; ClassSample = (function() { function ClassSample() {} ClassSample.prototype.name = null; ClassSample.prototype.start_sample = function() { this.hello(); this.name = "shin"; this.my_name(); return this.map_sample(); }; ClassSample.prototype.hello = function(str) { if (str == null) { str = "world"; } return alert("hello " + str); }; ClassSample.prototype.my_name = function() { return alert("myname is " + this.name); }; ClassSample.prototype.map_sample = function() { var array, new_array; array = [1, 2, 3, 4, 5, 6]; new_array = array.map(function(e) { return e * e; }); return console.log(new_array); }; return ClassSample; })(); }).call(this);
ただ、これだと外部から呼び出せません。
外部から呼び出せるようにするには、コンパイルオプションに-b(--bare)を付加します。
$ coffee -bc class_sample.coffee
できあがったものはこうなります。
// Generated by CoffeeScript 1.4.0 var ClassSample; ClassSample = (function() { function ClassSample() {} ClassSample.prototype.name = null; ClassSample.prototype.start_sample = function() { this.hello(); this.name = "shin"; this.my_name(); return this.map_sample(); }; ClassSample.prototype.hello = function(str) { if (str == null) { str = "world"; } return alert("hello " + str); }; ClassSample.prototype.my_name = function() { return alert("myname is " + this.name); }; ClassSample.prototype.map_sample = function() { var array, new_array; array = [1, 2, 3, 4, 5, 6]; new_array = array.map(function(e) { return e * e; }); return console.log(new_array); }; return ClassSample; })();
これをよびだすHTMLファイルを用意します。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>はじめてのCoffeeScript</title> <script src="class_sample.js"></script> <script> var sample = new ClassSample(); sample.start_sample(); </script> </head> <body> </body> </html>
自動コンパイルとか
ここで、ファイルを編集する度にコンパイルするの面倒くさいですよね?
coffeeコマンドにはファイルを監視してて、変更されたらそのファイルを自動的にコンパイルしてくれるオプションがあります。
"-w"をつければ自動コンパイルです。
$ coffee -wc class_sample.coffee
さっきの-bと合わせると
$ coffee -wbc class_sample.coffee
また、ソースファイルの場所とJavaScriptの吐き出し先を指定するとこんな感じです。
$ coffee -wbc -o js/build src/coffee/*.coffee
CoffeeScriptにはcakeというコマンドがあってCakefileを作っておくとタスクが自動化できます。
sys = require "sys" fs = require "fs" exec = require("child_process").exec util = require "util" COFFEE = "coffee" OPTION = "-cb" WATCH_OPTION = "-wbc" SRCDIR = "./" OUTDIR = "js/build" # # @desc 与えられたオプションでコンパイルします # compile = (option) -> util.log "compiling coffee..." command = "#{COFFEE} #{option} -o #{OUTDIR} #{SRCDIR}/*.coffee" exec command, (error, stdout, stderror) -> util.log error if error util.log stdout if stdout util.log stderror if stderror if error util.log "failure" else util.log("ok") task "build", "compile coffee to java script", -> compile(OPTION) task "watch", "compile coffee to java script", -> compile(WATCH_OPTION)
上記だと、"cake build"とかやるとコンパイルできます。
ただ、これ、コンパイルエラーが出力されないんですよね... たぶん僕が何か間違ってるんでしょうが。。
まあこれくらいの内容なら普通にMakefileでも書けます。
COFFEE=coffee src_dir=. out_dir=js/build all: coffee coffee: @$(COFFEE) -bc -o ${out_dir} ${src_dir}/*.coffee coffee-auto: @$(COFFEE) -wbc -o ${out_dir} ${src_dir}/*.coffee clean: rm js/build/*.js
ビルドするコマンドが make coffee なんてちょっとオシャレですね(ぉ
今回はここまで。