RubyのEnumeratorをJavascriptに実装してみた

Rubyはデフォルトでメソッドがいっぱいあってズルい!

JSでも同じように書きたい!

そんな想いから作りました。

ruby-enumerator.js

https://github.com/ksss/ruby-enumerator.js

RubyのEnumeratorとEnumerableのメソッドを、JSで同じように書くことができます。

NodeとHTMLで使用可能です。

Rubyの場合

e = Enumerator.new([1,3,4,6])
e.chunk { |i|
  i.even?
}.each { |res, i|
  p [res,i]
  #=> [false, [1, 3]]
  #=> [true, [4, 6]]
}

ruby-enumerator.jsを使った場合

var e = new Enumerator([1,3,4,6]);
e.chunk(function(i){
  return i % 2 === 0;
}).each(function(res, i){
  console.log([res, i]);
  //=> [false, [1, 3]]
  //=> [true, [4, 6]]
});

無限リストもRuby(v1.9.3)と同様に扱えます。 Rubyの場合

fib = Enumerator.new { |y|
  a = b = 1
  loop {
    y << a
    a, b = b, a + b
  }
}
p fib.take(10) #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

ruby-enumerator.jsを使った場合

var fib = new Enumerator(function(y){
  var a = 1;
  var b = 1;
  var tmp;
  for (;;) {
    y(a);
    tmp = b;
    b = a + b;
    a = tmp;
  }
});
console.log(fib.take(10).to_a()); //=> [1,1,2,3,5,8,13,21,34,55]

インストール方法は、nodeの場合npmで、htmlの場合コードを読み込めばEnumeratorオブジェクトが使用できるようになります。

nodeの場合

npm install ruby-enumerator
var Enumerator = require('ruby-enumerator').Enumerator;

htmlの場合

<script src="https://raw.github.com/ksss/ruby-enumerator.js/master/enumerator.js"></script>
<script src="./your.js"></script>

他のオブジェクトにruby-enumerator.jsの機能を追加することもできます。

Enumerator.extend(jQuery);
$('.foo').chunk(function(i){
  // ...
}).each(function(res,i){
  // ...
});

細かいところまでできるだけRubyに似せるように書いたのですが、同じ点と違う点があります。

同じ点

  • コールバック関数で宣言する引数の数によって変数に渡される値を変えます
var e = Enumerator({'a':1});
e.each(function(i){
  console.log(i); //=>['a',1]
});
e.each(function(key,value){
  console.log([key,value]); //=> ['a',1]
});
  • EnumeratorはEnumerableを継承しています
  • Enumerableに属するメソッドは全てeachメソッドを使用して実装されています。eachメソッドを上書きした場合ほぼ全てのメソッドに影響があります。

違う点

  • オブジェクト作成時のnewは省略できます。
  • functionでオブジェクトを作るとき、Rubyのyield(<<)メソッドではなく簡単化のため引数を単に関数として使います。
  • Rubyで配列を返す場合、ruby-enumerator.jsではメソッドチェインが可能なようにEnumeratorオブジェクトを返します。
  • イテレーター内から途中でbreakできませんが、throwで強制的に抜けることができます。
  • Staticなメソッドを幾つか追加しています。

Rubyの要素をJavascriptに入れると何が起きるか、これからが楽しみです。