Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ruby "enbugging" quiz の別解を求めて(@j5c8k6m8)

coincheck
June 05, 2024
87

Ruby "enbugging" quiz の別解を求めて(@j5c8k6m8)

Ruby Kaigi 2024 のリキャップイベントで使用したスライド

coincheck

June 05, 2024
Tweet

Transcript

  1. ©2024 Coincheck Inc. • アプリケーション基盤G に所属 ◦ Rails update ◦

    モジュラモノリス推進 ◦ 認可 / 認証 ◦ 開発規約の整備 自己紹介 • 元 SIer 出身 • たまに Qiita とか Zenn とか • kusaka と読み替えて下さい
  2. ©2024 Coincheck Inc. Ruby "enbugging" quiz https://ruby-quiz-2024.storesinc.tech/ RubyKaigi2024 の STORES

    さんの企画 Rubyコミッタである、遠藤(mame) さんが作成 mame さんの quiz は毎年の RubyKaigi の楽しみの一つ (画像はmame さんのセッションより引用) https://speakerdeck.com/mame/good-first-issues-of-typeprof?slide=3
  3. ©2024 Coincheck Inc. Ruby "enbugging" quiz • 全部で 12 Stage

    (3Stage/日. 全問解いた後の extra で追加 3stage) • クリア条件: Expected error に記載のエラーを発生させること • 手順: ◦ 最初から表示されている コードの一部を書き換える ▪ 書き換えた量 (diff) に応じて Score が変わる ◦ 実行ボタン   を押す ▪ Expected error のエラーが発生したらクリア n → nil クリア! (例年より簡単?..)
  4. ©2024 Coincheck Inc. Ruby "enbugging" quiz Day 1 できた! 3問で18

    なるほど。。 自力で解けると気持ちいいので、まずはチャレンジを ただ解くだけではなく、低スコアチャレンジもできるという2段構えの quiz (すべて、Score 1での解が用意されている?) 間違い探しのように、 答えを知っちゃうと、 探す楽しみがなくなるタイプ
  5. ©2024 Coincheck Inc. Ruby "enbugging" quiz 5/27 に STORES さんの

    テックブログから mame さんの公式解説記事 も出していただいてます! (予想通り、全ての問題が Score 1で解けます) https://product.st.inc/entry/2024/05/27/113038 (※ ネタバレ防止のため、マスク) 私はここでいう 別の回答 で解いたな、、 他にも解説記事で紹介されてない、 Score 1 の別解があるのでは? Solver プログラム を作って、別解を確認してみよう! 必読!
  6. ©2024 Coincheck Inc. Solver を作る https://github.com/cc-kusaka/rubykaigi2024_after_enbugging_quiz_solver 作成した Solver(リポジトリ) の URL

    と QRコード この後の話の ネタバレ含む Ruby "enbugging" quiz のエラー形式は、 markdown friendly に改善された 3.4.0 形式なことに注意 (引用) mame さんのセッション ("Good first issues of TypeProf") より https://speakerdeck.com/mame/good-first-issues-of-typeprof?slide=2 コードは ruby 3.4.0 の環境で 実行してください
  7. ©2024 Coincheck Inc. Solver を作る 用意したJSON読み込み 結果JSON出力 各文字位置 に対して、 文字削除

    or ASCII の各文字挿入 のケース で 解答となる source を作成 eval で実行 SyntaxError は StandardError ではない点に注意 正解かの判定
  8. ©2024 Coincheck Inc. Solver を作る 警告を抑止 (RUBYOPT=”W0”) し、 評価コード中の puts

    の標準出力を無視 ( 1> /dev/null) して、 実行! 想定外のエラーが発生!
  9. ©2024 Coincheck Inc. Solver を作る(instance_eval) 発生したエラーに特異クラスの module名が入ってしまい、 Expected error が一致しなくなってしまっていた。

    Actual error: private method 'main' called for an instance of #<Class:0x000000010091e9d8>::C (NoMethodError) Stage 7 のケース(Class名の問題) 以外にも、 グローバル変数やクラス変数がリセットされない問題もありそう。 問題中にclass 定義
  10. ©2024 Coincheck Inc. ※ esa_io さんのブログ (https://docs.esa.io/posts/509) で、 solver (https://github.com/fukayatsu/ruby-quiz-2024/blob/main/solve.rb)

    が紹介されていました。 こちらは、Thread を利用した多重処理で重さを回避しているようでした。 (エラー取得も Open3 モジュールを利用) 実行が終わらない (全体だと数時間かかる) Solver を作る(コマンド実行) Stage 1 に限定して 15分21秒 instance_eval 版は 0.3秒
  11. ©2024 Coincheck Inc. Solver を作る(fork) Stage7 を考慮し、Object の class_eval で実行。

    別プロセスで実行するので、 グローバル変数を含む各種変数が、 前の施行の影響を受けない。 fork でプロセスを複製し、結果を IO.pipe でやりとり (pipe 周りでコードがちょっと長くなる) 都度 wait をするので実質 1並行
  12. ©2024 Coincheck Inc. Solver を作る(fork) 実際にやってみても、 undefined local variable or

    method になり、クリアにならない ‘j’ を入れる誤解答が提示 ‘j’ を入れる誤解答が提示
  13. ©2024 Coincheck Inc. Solver を作る(fork) require ‘json’ で ‘j’ メソッドが生えていた!

    https://github.com/ruby/ruby/blob/d50404d6fe9dcd991dbad4f8757d23d38d1b5b80/ext/json/lib/json/common.rb#L658-L663
  14. ©2024 Coincheck Inc. Solver を作る(まとめ) • 隔離された Clean な実行環境を用意するのには、一定コストが必要 •

    現状では fork でプロセスコピーが、(性能を含めた)一定解か。(require 問題はあるが) # Solver の内容 実行時間 (Stage 1のみ) 出力結果 1 (グローバルスコープで) eval を利用 - • クロージャを参照して失敗 2 (スコープを意識して) instance_eval を利用 0.3秒 • 実行環境のモジュール名の差異が発生 • クラス変数やグローバル変数を実行都度リセットできない 3 (ファイル出力と) コマンド実行を利用 (single) 15分 21秒 • 基本的には問題なし • Error の一致判定は標準エラー出力の部分一致を利用 4 fork を利用 (single) 19.3秒 • 評価前の `require` などで 環境に差異が発生 5 fork を利用 (multi) 6.6秒 • 同上
  15. ©2024 Coincheck Inc. # Solver の内容 実行時間 (Stage 1のみ) 出力結果

    1 (グローバルスコープで) eval を利用 - • クロージャを参照して失敗 2 (スコープを意識して) instance_eval を利用 0.3秒 • 実行環境のモジュール名の差異が発生 • クラス変数やグローバル変数を実行都度リセットできない 3 (ファイル出力と) コマンド実行を利用 (single) 15分 21秒 • 基本的には問題なし • Error の一致判定は標準エラー出力の部分一致を利用 4 fork を利用 (single) 19.3秒 • 評価前の `require` などで 環境に差異が発生 5 fork を利用 (multi) 6.6秒 • 同上 Solver を作る(まとめ) • 隔離された Clean な実行環境を用意するのには、一定コストが必要 • 現状では fork でプロセスコピーが、(性能を含めた)一定解か。(require 問題はあるが) ◦ Ruby に Namespace が導入されるのに期待 ▪ 少なくとも、require ‘json’ 問題は解決可能なはず ▪ instance_eval のような方法でも実現可能になるかも
  16. ©2024 Coincheck Inc. 別解を見る # Expected error 解数(※1) 別解 Stage

    1 undefined method '+' for nil (NoMethodError) 11 有 Stage 2 undefined method 'downcase' for nil (NoMethodError) 16 無 Stage 3 wrong number of arguments (given 2, expected 3) (ArgumentError) 1 無 Stage 4 nil can't be coerced into Integer (TypeError) 9 有 Stage 5 index -4 too small for array; minimum: -3 (IndexError) 1 無 Stage 6 negative argument (ArgumentError) 7 有 Stage 7 private method 'main' called for an instance of C (NoMethodError) 5 無 Stage 8 cyclic include detected (ArgumentError) 7 有 Stage 9 wrong number of arguments (given 1, expected 0) (ArgumentError) 11 有 Stage A cannot clamp with an exclusive range (ArgumentError) 10 無 Stage B 0: 1 === 0 does not return true (NoMatchingPatternError) 1 無 Stage C invalid radix 52 (ArgumentError) 2 無 (※1) 空白文字の違いは1でカウント 面白いと思った 3つの別解を紹介します(ネタバレ含む)
  17. ©2024 Coincheck Inc. += を使うことでnil 初期化 .追加で、メソッドチェーンにして 右辺から評価させる (1_000.p は

    no method だけど) 1文字メソッドの p を追加 別解を見る (Stage 1) 削除, ‘#’, ‘@’, ‘$’ が公式解説でも言及されていた ‘+’, ‘.’, ‘p’ を追加する方法(上記以外の箇所も含めて) が別解
  18. ©2024 Coincheck Inc. 配列として代入できる記法 (知らなかった) 解説では、n = *10 が紹介。 別解を見る

    (Stage 6) 公式の解説もとにかく面白いので すが(コメントがひっかけ) そのコメントを利用する別解
  19. ©2024 Coincheck Inc. Score1 での解の数 紹介していない別解もあるので、興味ある人は 以下の回答(と公式の解説)を見てみてください。 https://github.com/cc-kusaka/rubykaigi2024_after_enbugging_quiz_solver/blob/main/answers3.json # Expected

    error 解数(※1) 別解 Stage 1 undefined method '+' for nil (NoMethodError) 11 有 Stage 2 undefined method 'downcase' for nil (NoMethodError) 16 無 Stage 3 wrong number of arguments (given 2, expected 3) (ArgumentError) 1 無 Stage 4 nil can't be coerced into Integer (TypeError) 9 有 Stage 5 index -4 too small for array; minimum: -3 (IndexError) 1 無 Stage 6 negative argument (ArgumentError) 7 有 Stage 7 private method 'main' called for an instance of C (NoMethodError) 5 無 Stage 8 cyclic include detected (ArgumentError) 7 有 Stage 9 wrong number of arguments (given 1, expected 0) (ArgumentError) 11 有 Stage A cannot clamp with an exclusive range (ArgumentError) 10 無 Stage B 0: 1 === 0 does not return true (NoMatchingPatternError) 1 無 Stage C invalid radix 52 (ArgumentError) 2 無 (※1) 空白文字の違いは1でカウント
  20. ©2024 Coincheck Inc. • まずは、何よりも、本 LT の前提となる 「Ruby "enbugging" quiz」を

    作成/提供していただいた、Stores さん、 mame さん、関係者の方々に感謝します。 • mame さんが提供している quiz は、ものすごく楽しいので、ぜひ参加してください。 • 変わったプログラムを書いたり読んだりすると、言語の背景が薄く見えるような感覚があっ て楽しいですね。 • 来年は TRICK2025 の開催も決定しているので、チャレンジしたいです(宣言) さいごに