逆リファクタリング問題
tbpgr さんの逆リファクタリング問題
https://codeiq.jp/magazine/2015/02/21347/
に挑戦した。
優秀解答として紹介していただいたので、解説する。
ソース
まずはソース。
#coding:utf-8 def static(*);yield if block_given?;:!end alias void static alias Main void class System;def self.in; self;end;def self.eof; STDIN.eof?;end def self.out;Kernel;end;def self.read; STDIN.getc;end;end def If(x);yield if ($g=x);end def Else;yield unless $g;end def While(x);yield while x.(); end class BasicObject;def method_missing(method, *args); args[0].upcase if args.size==1 && args[0].is_a?( "".class );end;end alias lambda ! 謎言語風です。 ! 入出力がSystem.inだったりSystem.outだったりする辺りはJava風。 ! メインがMainなのはC#風。 ! コメントは苦し紛れに FORTRAN 風。 ! もっとWhileを見慣れた感じにしたかったんだけど、これ以上アイディアがなく。 public static void Main(){ string s=null; While {! System.in.eof()} { If ( s==null ){ s=""; } Else{ s=" "+upcase(s); } s=System.in.read()+s; } System.out.print(s); }
全体的な話
実は、『Cプログラミング診断室』( http://www.amazon.co.jp/dp/4774117870 )の「第8章 Pascalが好き」へのオマージュのつもりで書き始めた。
ダメなソースコードの例が解説付きで載っている名著なので、未読の方は是非。
それはさておき。
当初は Java 風にしようとしていたんだけど、どうもうまく出来なくて。
特に while ループを
While(条件){ループ内}
のようにする方法がわからず、仕方なく謎言語風という形に逃げた。
順に解説
謎言語部に登場する部品を、概ね登場順に解説する。
FORTRAN風のコメント
FORTRAN 風のコメントは、普通に 否定演算子 + ruby のメソッド呼び出しに なっている。
つまり「謎言語風です。」などはメソッド呼び出し。そんなメソッドはないんだけど、method_missing でエラーにならなくなる。
「! メインがMainなのはC#風。」の部分は、# 以下がrubyのコメントになっている。
ちなみに、
「! Mainメソッドが云々」
のようなコメントを書くと、大文字始まりなのでメソッドではなく定数になり、実行時エラーになる。
以下、method_missing に到達する処理を「無駄メソッド」と記述する。
public static void Main
public は ruby の予約語……ではなく、Module クラスの private メソッド。static以下の実行結果を public にする。
static も void も Main もメソッドで、
static( void( Main(){略} ) )
ということになっている。
public に何かを渡さなくてはいけないので、static は「:!」を返している。
Main の引数のブロックを実行しなくてはいけないので、Main はブロックを受け取ったらそれを実行するようになっている。
string s=null;
型を指定して変数を宣言しているようにみえる
string s=null;
は、
string( s=null() )
という意味である。
string も null も無駄メソッドだけど、s は本当にローカル変数。
無駄メソッドは、引数がないと nil を返すようになっているので、これで
無駄メソッド( s=nil )
となり、無事、本当に s が nil になる。
While
難儀した割に無様な While なんだけど、
alias 全角空白 lambda
によって、While の部分は
While( lambda{条件} ){ ループ内 }
System クラス
System.in.eof()
は、比較的普通な感じ。System クラスには以下の様な4つの特異メソッドがある。
メソッド | 意味 |
---|---|
in | System クラスを返す |
out | Kernel クラスを返す |
eof | STDIN.eof? |
read | STDIN.getc |
で。System.in.eof() は、System.eof() で、つまり STDIN.eof? になる。
最後の方にある System.in.read() は、System.read() なので、STDIN.getc になる。
一番最後の System.out.print(s) は、System.print(s) なので、Kernel.print(s)、つまり、print(s) になる。
まとめ
こうして書いてみると、工夫が足らんなあという気分になる。
もうちょっと馬鹿げた意味のわからないことを書きたかったなぁ。