Cookpad Daily Ruby Puzzles Extraを解いた
RubyKaigi 2019 Cookpad Daily Ruby Puzzles の正解と解説 - クックパッド開発者ブログ
読んで面白かったので久しぶりにrubyを触ってExtraのパズル解いた。
Extra 1
Hello = "Hello" # Hint: Stop the recursion. def Hello Hello%() + " world" end puts Hello()
3-3と同様に()
を%()
にして%
記法にする。
!の部分には改行を含めた任意の非英数字を使うことができます (%w、%W、%i、%I は区切りに空白、改行を用いるため、!の部分には使うことができません)。 始まりの区切り文字が括弧(
(',
[',{',
<')である時には、終りの区切り文字は 対応する括弧になります。括弧を区切り文字にした場合、対応が取れていれば 区切り文字と同じ括弧を要素に含めることができます。
Hello
が1行目の宣言の変数に、%()
が空文字列になるのはわかるけど、rubyはString並べると結合されんの……? 謎。
Extra 2
s = "Dž" # Hint: https://techlife.cookpad.com/entry/2018/12/25/110240 s == s.upcase or s == s.downcase or puts "Hello world"
タイトルケース、そういうのがあるのか。勉強になります。upcaseでもdowncaseでもない第三のcase。
完全に余談ですが、Unicode の大文字・小文字の話題になると、「Dz」という字の話をするのがお作法です。これは D と z の 2 文字ではなく、D と z が合体した 1 つの文字です。こういう文字を、digraph、二重音字と言います。この文字には、大文字・小文字に加え、タイトルケース(先頭の文字だけが大文字)の 3 種類があります。
Extra 3
def say s %= 'Small' t = 'world' puts "#{s} #{t}" end TracePoint.new(:line){|tp| tp.binding.local_variable_set(:s, 'Hello') tp.binding.local_variable_set(:t, 'Ruby') tp.disable }.enable(target: method(:say)) say
結構時間かかった。s = 'Small'
の前にTrasePointがs
に'Hello'
をsetするので、s = 'Small'
で上書きされそうになるのを、s %= 'Small'
にしてやることで、Stringの%を使う自己代入にしてあげる。Stringの%はprintfと同じ規則でのフォーマットで、'Hello'
にはフォーマット指定子が含まれないのでフォーマット後文字列は'Hello'
のままとなる。合ってる?
もう一個の1文字回答なんなんだろう……。
感想
楽しかった。%が酷使されている気がする。
2019/4/26追記
Extra 3の別解分からないのでカンニングした。
def say\ s = 'Small' t = 'world' puts "#{s} #{t}" end TracePoint.new(:line){|tp| tp.binding.local_variable_set(:s, 'Hello') tp.binding.local_variable_set(:t, 'Ruby') tp.disable }.enable(target: method(:say)) say
\
で行を繋げることで、def say s = 'Small'
扱いにし、引数s(デフォルト値'Small')にしてあげることで、t = 'world'
の行の評価前にsに'Hello'、tに'Ruby'がsetされて、評価後はs = 'Hello'、 t = 'world'になる。
バックスラッシュの行継続、メソッド定義での引数宣言の()が省略できる、引数のデフォルト値が代入と同じ形で表現できるためsay
での呼び出しで引数0でもエラーにならない、の三点。綺麗ですね。
プログラムは式を並べたものです。式と式の間はセミコロ ン(;)または改行で区切ります。ただし、バックスラッシュに続く改行は文 の区切りにならず、次の行へ継続します。