vim-users.jp

Hack #164: JavaScript開発環境 その2 CoffeeScriptを使う

Posted at 2010/07/29
このエントリーをはてなブックマークに追加

問題

JavScriptはその動的性と柔軟な構文により、ブラウザ上で動作するアプリケーションに限らず多くの場で活躍する便利なプログラミング言語です。しかしそれでもいくつか問題が残されています。

  1. セミコロン

    多くのVimユーザはコロンとセミコロンの配置を入れ替え、コロンの入力を容易にするよう調整しているといわれています。しかしながらJavaScriptでは文末にセミコロンの入力を必要とします。

    var a = 1;
    

    上記のような簡素な例だと単純にFPの消費量のみの問題なのですが、しかし以下のようにセミコロンが必要な場合と必要でない場合がすぐに判別しないときもあり、このとき若干の面倒さが残ります。

    function f1() {
      return 1;
    }
    
    var f2 = function() {
      return 1;
    };
    
  2. 括弧

    JavaScriptは関数と変数の名前空間が一致しているためか、関数適用の括弧を省略できない言語仕様となっています。

    f();
    
    f(x);
    

    引数がない場合は()の有無により関数自体か関数実行結果の値かを区別できるというので納得できるのですが、しかし引数がある場合には納得できません。

    f x;
    

    もしこのように書けば、これはf(x)以外に考えられないはずです。それなのに毎回f(x);と記述しなければならないのは冗長で、開発効率の大幅な低下を招きます。

解決法

~/.vim/ftplugin/javascript.vimなどで努力することで、容易に間違いなくセミコロンを入力するためのサポートを行なう、あるいは括弧を自動的に入力するなどやりかたはありますが、いずれもまじめに対処するとなかなか難しい問題です。

もっとも容易な解決策は、例えばJavaScriptを避けることです。

CoffeeScriptでプログラムを書き、JavaScriptにコンパイルする手法を紹介します。CoffeeScriptでは前述の2つの問題を解決し、ほかにもHack #160: JavaScript開発環境で挙げた長い予約語functionをいかにして入力するかという問題も解決します。

例を挙げます。0から2までの数字を出力するコードをCoffeeScriptで記述してみましょう。

f: ->
  memo: 0
  ->
    memo++

Number.prototype.times: (f) ->
  f i for i in [1..this]

g: f()

3.times (i) ->
  p g()

coffee -cpコマンドで、上記コードが以下のようなJavaScriptにコンパイルされます。

(function(){
  var f, g;
  f = function() {
    var memo;
    memo = 0;
    return function() {
      return memo++;
    };
  };
  Number.prototype.times = function(f) {
    var _a, _b, i;
    _a = []; (_b = (1));

    for (i = _b; i <= this; i += 1) {
      _a.push(f(i));
    }
    return _a;
  };
  g = f();
  (3).times(function(i) {
    return p(g());
  });
})();

前述の問題が全て解決したことが分かります。

CoffeeScriptを使うためにはNodeJsCoffeeScript処理系の二つが必要です。2010年7月現在、MacPortsでインストールできるNodeJsはバージョン0.1.92ですが、0.1.98以降で導入されたreadlineや、一部の正規表現エンジンの動作の違いから、0.1.92ではCoffeeScriptの一部の機能しか利用できません。折角ですのでNodeJsは最新版を導入しましょう。

また、CoffeeScriptをVimから快適に使うためのツールがいくつか存在します。以下で紹介する全てを導入することを強くお勧めします。

  1. vim-coffee-script

    http://github.com/kchmck/vim-coffee-script

    ftdetect, ftplugin, indent, syntax全てがそろっています。

    a

  2. quickrun

    http://github.com/thinca/vim-quickrun

    <Space>rなどで編集中ファイルを実行します。CoffeeScriptに対応しています。

    b

    また、明示的に:QuickRun 'coffee -cp'などとすることで、QuickRun出力バッファに, CoffeeScriptからコンパイルした結果のJavaScriptを表示し続けることができ、大変便利です。

新たな問題

JavaScriptでは変数名や関数名をcamelCaseでつけます。つまり、this_is_a_penよりもthisIsAPenが好まれます。JavaScriptを書き慣れている人ならば何の問題もなくcamelCaseで命名していくでしょうが、しかしCoffeeScriptはむしろPythonやRubyのように見えるため、混乱してアンダースコアで小文字の単語を繋げてしまう傾向にあります。

すぐに思い付く解決方法はCoffeeScriptのコンパイラ部分を書き換えて識別子名を自動で置換することでしょうが、しかしこの方法ですともとのCoffeeScriptのコードはcamelCaseでないままです。

解決法

挿入モードの_をシフトキーとして扱うようにし、this_is_a_penと打鍵するだけでthisIsAPenと打鍵したことになるようVim側の挙動を変更します。そのためにstickykey.vimを用います。

  1. http://www.vim.org/scripts/script.php?script_id=2990 からstickykeyをインストールする
  2. ~/.vim/ftplugin/coffee.vimに以下を記述する

    function! JavaScriptUnderScoreBecomesCamelCase()
      if matchstr(getline('.'), '.', col('.')-2) =~ '\w'
        return "\<Plug>(stickykey-shift)"
      else
        return '_'
      endif
    endfunction!
    
    imap <buffer><expr> _ JavaScriptUnderScoreBecomesCamelCase()
    

カーソル位置が[a-zA-Z0-9_]のときのみ_がシフトキーとして動作します。空白文字の上で_を打鍵したときなどは_のままになりますので、例えば_ではじまる関数名の関数を定義するときなどに気兼ねなく_を打鍵できます。

補足

本HackでCoffeeScriptを用いた効率的なJavaScriptの開発方法を紹介しましたが、しかしながら、CoffeeScriptも万能ではありません。無引数関数の値を取り出すための(), 関数リテラルの仮引数指定の(x), 条件演算子a ? b : cの違いなど。これらの問題を解決するためのパッチが勇士によって開発中とのことです。

また、coffee -iで起動するインタラクティブなcoffeeインタプリタをvimshellを用いたVim内で操作できるはずなのですが、現時点ではなぜかうまく動作しないという問題があります。

ujihisa

もどる
blog comments powered by Disqus