Rruuubbyyyy作った

ennnndをFeature Requestしたら思いの外反響が大きいというか、特に外国人にはクソミソに言われまくりで、その中の一人は Rruuubbyyyy とか言ってた。で、意味はわかんないけどたぶん作って欲しいんだなと思ったので、とりあえずその Rruuubbyyyy を作ってみた。

サンプルコード

moooodddulee Foo
  cclllasss Bar
    dddeeefff xyzzy
      iiffff tttrrueee ttheeen
        p :hheeellooo
      endd
    eeend
  ennndd
eeendd

Foo::Bar.new.xyzzy

mooooddduleeとかcclllasssとかがmoduleとかclassになる。要するにキーワード内で連続する文字が無視される。ennnndと書いてもend1つ分にしか見なされないことに注意。

実行結果

$ ./ruby rrruby.rb
:hheeellooo

ん、動いた。

実装
つまり、前回学んだことをさっそく使ってみたと。

--- ../ruby-1.9.2-p290/parse.y  2011-07-03 21:24:13.000000000 +0900
+++ parse.y     2011-07-23 23:46:52.000000000 +0900
@@ -7755,6 +7755,50 @@
 
                /* See if it is a reserved word.  */
                kw = rb_reserved_word(tok(), toklen());
+               if (!kw) {
+                    int i;
+                    char *tmpbuf = ALLOC_N(char, toklen());
+                    int tmplen;
+                    char prev = tokenbuf[0];
+
+                    tmpbuf[0] = prev;
+                    tmplen = 1;
+                    for (i = 1; i < toklen(); i++) {
+                        char cur = tokenbuf[i];
+                        if (prev != cur) {
+                            tmpbuf[tmplen++] = cur;
+                        }
+                        prev = cur;
+                    }
+                    if (tmplen < toklen()) {
+                        tmpbuf[tmplen] = '\0';
+                       kw = rb_reserved_word(tmpbuf, tmplen);
+                        if (kw) {
+                            tokidx = tmplen;
+                            for (i = 0; i < tokidx; i++) {
+                                tokenbuf[i] = tmpbuf[i];
+                            }
+                            tokfix();
+                        }
+                        else if (tmplen == 4 && strncmp(tmpbuf, "clas", 4) == 0) {
+                            strcpy(tokenbuf, "class");
+                            tokidx = 5;
+                           kw = rb_reserved_word(tok(), toklen());
+                        }
+                        else if (tmplen == 4 && strncmp(tmpbuf, "unles", 5) == 0) {
+                            strcpy(tokenbuf, "unless");
+                            tokidx = 6;
+                           kw = rb_reserved_word(tok(), toklen());
+                        }
+                        else if (tmplen == 3 && strncmp(tmpbuf, "end", 3) == 0) {
+                            xfree(tmpbuf);
+                            lex_state = EXPR_END;
+                            return keyword_end;
+                        }
+                    }
+                    xfree(tmpbuf);
+               }
+
                if (kw) {
                    enum lex_state_e state = lex_state;
                    lex_state = kw->state;


また一歩、野望に近づいた。

なかだ師匠(左)と遠藤師匠(右)に感謝。

・・・

おまけ

class Object
    def method_missing(name, *args, &block)
        new_name = name.gsub /(.)\1+/, '\1'
        raise NoMethodErrror.new(name) if name == new_name
        send new_name, *args, &block
    end
end

こういうのをprelude.rbに追加しておけばメソッド名も同じように引き伸ばせるはず。試してないけど。