From: keiju / rational.com (石塚圭樹 ) Subject: [ruby-list:6479] Re: call for scripts Date: Tue, 17 Feb 1998 23:02:54 +0900 Message-ID: <199802171318.WAA02938.keiju / bc.mbn.or.jp> keiju> あと, keiju> keiju> 3. パズル関係のプログラム keiju> 4. パズル的なプログラム keiju> 5. メソッドの連鎖がナガーク続くプログラム keiju> keiju> なども, 採用される確立が高いと思います(ただし, 本文というかコラム扱い keiju> になると思いますが(^^;;;). この分野にお強い方も多いみたいですので, 興 keiju> 味ある方は挑戦してみて下さいませ(__;;; 千田@リコーと申します。 サイン本ほしさにちょっと作ってみました。 いわゆる自己再生プログラムというやつです。 プログラムの実行結果が自分のソースコードとなるようなプログラムのことで % ruby xxx.rb | diff -c - xxx.rb が何も出力を返さないようなプログラムxxx.rbのことをいいます。 C言語では main(a){printf(a,34,a="main(a){printf(a,34,a=%c%s%c,34);}",34);} がよく知られています。 これをまねしてrubyで書くと (1)--------- #!/usr/local/bin/ruby a='#!/usr/local/bin/ruby a=%c%s%c;printf(a,39,a,39); ';printf(a,39,a,39); ------------ というぐあいになります。 # 最初Cと同じ構造にしようとしたらrubyでは引数の評価 -> 関数引数のbindの # 関係がCと違うことに気づいてしまった。printf(a,...)のaのところで # undefined local variable or method `a' # となってしまう。 これじゃああんまりおもしろくないので (1) printfを使わないで (2) ruby特有の機能を使って (3) 文字コードを仮定しないで(上の39は"を意味している) 出きるようなものを書いてみました。 (2)--------- #!/usr/local/bin/ruby def once;yield"end;once{|x,y|print y;print x.inspect,',';p y;print x+'\n';}","#!/usr/local/bin/ruby\ndef once;yield" end;once{|x,y|print y;print x.inspect,',';p y;print x+' ';} ------------ (注:2行目は長いのでmailでは折り返されてしまうかも知れない) これでは何のことかわからないので解説しましょう。:-) うえの(2)の中の自己言及している文字列を短く置き換えると (2')--------- #!/usr/local/bin/ruby def once;yield"xxx","yyy" end;once{|x,y|print y;print x.inspect,',';p y;print x+' ';} ------------ となり(これならよめるでしょう)、実行結果は yyy"xxx","yyy" xxx となります。iteratorの定義で文字列を定義し、実行部分でもとのソースコードと 相似な形に出力するように出力部を調整しているだけです。文字列に対する inspectが""をつけて返してくれるおかげでこの部分はきれいに書けます。 上の2つは"まじめ"な方法で実現したものですが、実は"ふざけた"方法で自己再生 プログラムを作ることができます。 それは、、、
(3)--------- #!/usr/local/bin/ruby a=open($0,"r") while a.gets print $_ end ------------ # 飛び道具攻撃 !! 説明は不要でしょう。 :-) では。 --- +--------------------------------------------------------------------+ | (株)リコー SS事業本部 周辺機器開発部 開発2グループ | | 千田滋也 (senda / ic.rdc.ricoh.co.jp) | +--------------------------------------------------------------------+