解答、ヒント、解説などは充分な余白を開けた上で表示するので、安心して読んでください。
問題
このRubyプログラムに1文字追加して、"Hello world\n"を出力するプログラムにしなさい。 なお、例外などで異常終了するものは正答とはみなしません。
RubyKaigi 2019のCookpadのパズルリスペクトです。
なお、hanachinさんが色々な人が出している問題をまとめてくれているので、もっと問題を解きたい方はそちらをご覧ください。
Okinawa.rb Ruby Puzzles 2019/5/15 - #rubykaigi のRubyPuzzleが面白かったので真似しました。Ruby 2.7でしか動きません。 · GitHub
ヒント
以下にヒントを少しずつ書いていきます。適当にスクロールしてください。 ヒント3まであり、少しずつ核心に近づいていきます。
ヒント その1
Lexerの気持ちになりましょう。
ヒント その2
Rubyのparser_yylex
関数を読んでみましょう。parse.y
にあります。
ヒント その3
ほぼ答えです。
答え
想定解は、6パターンあります(多分)。3種類の文字を、プログラム中のある2箇所に入れることで"Hello world\n"を出力するプログラムとなります。
ここではその答えを1つ示します。
ですが、答えのプログラムを直接書くのはすこし難しいので、答えのプログラムを出力するRubyのプログラムを書きます。
# ans.rb puts <<~"RUBY" puts("Hello world")\x04 if false \ && false && false RUBY
このプログラムの出力をRubyプログラムとして実行すると、"Hello world\n"が出力されます。
$ ruby ans.rb | ruby Hello world
解説
ヒント その3にあるとおり、Rubyのプログラムの終わりにはいくつかの方法があります。
ファイルの終り(文字列をevalしている場合は文字列の終り)
これは普通の方法ですね。
ENDのみの行(前後に空白があると認識されません)
__END__
とだけ書かれた行があると、その行以降はRubyのプログラムとしては扱われず、DATA
という定数から参照できます。
これが今回の答えです。
ソースコード中に直接このコントロール文字を埋め込むと、そこでRubyプログラムが終了します。
今回はif false && false && false
の部分がなかったことになればHello world
が出力されるので、if
の直前にこのコントロール文字を入れてやることで、if
を無視することができます。
便利ですね。