ESM アジャイル事業部 開発者ブログ

永和システムマネジメント アジャイル事業部の開発者ブログです。

RubyKaigi 2024 に Night Cruise Sponsor として協賛します🛳️🌌

ふーが ( @fugakkbn ) です。

今年もこういったお知らせができることをうれしく思います。
私たち永和システムマネジメントは、RubyKaigi 2024 に Night Cruise Sponsor として協賛します。

rubykaigi.org

Night Cruise Sponsor

RubyKaigi 2024 は沖縄県那覇市で開催されます。沖縄といえば海!海といえばクルーズ!ということで、RubyKaigi 2019 以来の Night Cruise を会期前日である 5/14(火) の夜に開催します。沖縄の "ちゅら海" をクルーズ船でゆったり周遊しながら、Rubyist 同士の交流はもちろん、RubyKaigi 2024 に向けて気持ちを高めていく場を提供できればと思います。
会場ではタコライスや沖縄そば、オリオンビールに泡盛といった沖縄グルメを始めとしたお料理を食べ・飲み放題で提供予定です。

詳細やお申し込みについては追ってご案内しますので、永和システムマネジメントの X(旧 Twitter) をフォローして続報をお待ちください。

https://twitter.com/rubyagile

なお、今回は "First-Timer 枠" として RubyKaigi に初参加の方がお申し込みいただける枠を用意する予定です。初めての参加で不安な方や交流をしたいけれどどう動けばいいのかわからない方向けの参加枠です。初参加の方にも楽しんでいただけるイベントになればうれしいです!

RubyKaigi 2024 に向けて

いよいよ会期 1 ヶ月前ということで、どのセッションを聴講しようか、あるいはどんなセッションなのだろうかといった予習をされている方も多いことと思います。弊社でも、先日の エンジニアお茶会 でタイムテーブルを眺めながら当日に想いを馳せるなどしていました。毎年たくさんの気づきと刺激を受けられる RubyKaigi が今から本当に楽しみです。

そんな RubyKaigi 2024 に、今年もスポンサーとして関われることを嬉しく思います。Night Cruise で気持ちを高めて翌日からの Kaigi をより一層楽しみましょう!クルーズ会場、そして Kaigi 会場で皆さんとお会いできるのを楽しみにしています。

今年は弊社から @koic と @junk0612 の2名が登壇します

弊社からは @koic, @junk0612 の 2 名がスピーカーとして登壇します。こちらもぜひお楽しみに!

blog.agile.esm.co.jp


永和システムマネジメントでは、Ruby コミュニティと共生しながら成長したいエンジニアを絶賛募集しています。

agile.esm.co.jp

はじめてのRISC-Vベアメタルプログラミング(ヨロシク編)

こんにちは、永和システムマネジメントの内角低め担当、はたけやま( @htkymtks )です。

みなさん、RISC-Vをご存知ですか?RISC-VはCPUの命令セットアーキテクチャ(ISA)のひとつで、使用料のかからないオープンソースライセンスで提供されていることや、命令セットの美しさから注目を集めています。私も以前にRubyでRISC-Vシミュレータを作ったりしてました。

今回はRISC-Vを用いて、OSもライブラリも使用しないベアメタル環境で動作するプログラムを作成してみようと思います。

インストール

まずはRISC-Vのクロスコンパイラとエミュレータをインストールします。クロスコンパイラのビルドには約1時間ほどかかるので、時間の余裕がある時に行ってください。

$ brew tap riscv-software-src/riscv
$ brew install riscv-tools qemu

以下のコマンドを実行し、それぞれのバージョンが正しく表示されれば、インストールは成功です。

 $ riscv64-unknown-elf-gcc --version
 $ qemu-system-riscv64 --version

クロスコンパイラとは、あるアーキテクチャ(ターゲットシステム)向けの実行可能コードを、異なるアーキテクチャ(ホストシステム)上でコンパイルするためのツールです。今回はターゲットシステムがRISC-V、ホストシステムがARM64(Apple M1)に設定されたGCCを利用します。

エミュレータにはQEMUを使用します。QEMUは様々なCPUアーキテクチャをサポートするエミュレータで、32ビット及び64ビットのRISC-Vが対応しています。

サンプルプログラム

レジスタs0に値(0x4649 = ヨロシク)をセットして無限ループするサンプルプログラムを用意します。

  .text
  .globl _start
  .type _start, @function

_start:
  # レジスタ s0 へ即値 0x4649 をロード
  li s0, 0x4649
loop:
  # 無限ループ
  j loop

リンカスクリプト

QEMU(正確にはVirtio)では、アドレス0x80000000番地からプログラムの実行が開始されます。そのため、以下のようなリンカスクリプトを用意し、プログラムの開始位置のアドレスが0x80000000番地になるようにします。

MEMORY {
   RAM (RWX) : ORIGIN = 0x80000000, LENGTH = 0x40000000
}
SECTIONS {
    .text : {
        *(.text)
        _end = .; /* 後日 malloc で使う予定 */
    }
}

ビルド

それではサンプルプログラムをビルドしましょう。アセンブラを使用してアセンブリコード sample1.S からオブジェクトファイル sample1.o を生成し、オブジェクトファイルから実行ファイル sample1.elf を生成します。

$ riscv64-unknown-elf-as sample1.S -o sample1.o
$ riscv64-unknown-elf-ld -Tmy_baremetal.ld --no-relax sample1.o -o sample1.elf

生成された sample1.elf を逆アセンブルしてみましょう。プログラムが0x80000000番地からスタートすることが確認できます。

$ riscv64-unknown-elf-objdump -S sample1.elf
 
sample1.elf:     file format elf64-littleriscv
 
 
Disassembly of section .text:
 
0000000080000000 <_start>:
    80000000:   00004437           lui s0,0x4
    80000004:   6494041b            addiw   s0,s0,1609 # 4649 <_start-0x7fffb9b7>
 
0000000080000008 <loop>:
    80000008:   0000006f            j   80000008 <loop>

実行

先ほど作成したELFファイルを指定してQEMUを実行します。

qemu-system-riscv64 -M virt -monitor stdio -bios sample1.elf

引数の意味は以下のとおり。

  • -bios sample1.elf
    • 実行ファイルを指定します
  • -M virt
    • ターゲットとなるボードを指定します。今回は「RISC-V VirtIO board = virt」を使用します
  • -monitor stdio
    • QEMUモニタをターミナルに表示するために指定します

実行結果を確認

QEMUを起動してプログラムを実行すると、QEMUモニタも一緒に立ち上がります。「info registers」コマンドでレジスタの中身を確認すると、レジスタ「x8/s0」に「4649」がセットされていることがが確認できます。また、プログラムカウンタ(PC)の値が「80000008」であることから、無限ループしていることが分かります。

動作確認を終えたら、QEMUモニタで「quit」と入力してQEMUを終了させます。

終わりに

以上、QEMU上のRISC-Vでベアメタルプログラミングを行う方法を紹介しました。次回はこの上で何か面白いアプリケーションを動かしてみようと思います。

RubyKaigi 2024 に永和システムマネジメントから @koic @junk0612 の2人が登壇します

2024年5月15日(水) から17日(金) の3日間にわたって開催される RubyKaigi 2024 に永和システムマネジメントから @koic (Day 2) 、 @junk0612 (Day 3) の2人が登壇します。

rubykaigi.org

ここでは、それぞれの登壇者から講演内容について軽く紹介をします。

5月16日(木) 14:50-15:20 @koic 『RuboCop: LSP and Prism』

@koic です。今年は『RuboCop: LSP and Prism』というタイトルで話します。タイトルにあるように RuboCop をとおした LSP と Prism の話です。当初 LSP を主体にして、タイトルには Prism と出していなかったのですが、Rails/OSS パッチ会で RubyKaigi オーガナイザーでもある松田さんから「Lrama の講演が3つあるので、Prism もタイムテーブルに入れたい」といった雰囲気の話を受けてタイトルを更新したものになります。結果として思ったよりも Prism に関するボリュームは膨らむかもしれません。

LSP は Language Server Protocol の略称で、よく聞くところでは Ruby LSP などがあります。git hooks で rubocop コマンドを実行するようなエディタ連携の上位互換になる側面もあるので、LSP 未使用の方はぜひ使ってみると良いと思います。LSP の基本的な事柄について詳しくは RubyKaigi 2017 で @mtsmfm が話されている『Ruby Language Server』を予習しておくと事前知識に便利だと思います。

rubykaigi.org

もうひとつの大きなトピックは Prism です。RuboCop が Ruby のソースコードをパースするにあたって @whitequark プロダクトである Parser gem を使っていますが、RuboCop 1.62 で Prism のサポートを実験的に導入しました。そのあたりの裏側と今後の話を展開する予定です。Prism そのものについては、RubyKaigi 2023 で Kevin Newton が話されていた『Yet Another Ruby Parser』あたりは予習になると思います。

rubykaigi.org

そんな感じで LSP と Prism の話です。LSP は去年の RubyKaigi 2023 で Standard gem の作者である Justin Searls と話して RuboCop に組み込んだ機能です。LSP を入れたら Error Tolerance なパーサーのことを検討するわけで、そこで Parsing Ruby is Suddunly Managable の Prism に着目したというのは必然的な流れでした。加えて、昨年 RubyConf Taiwan 2023 で The Bison Slayer の金子さんと4日4晩パーサーそのものやその周辺ツールについて話す機会があって、その影響もそれなりに出ている活動の話になります。

このように RuboCop について、LSP と Prism といったテクノロジーを使ってどのような課題解決を目指しているのか、これからの Linter や Formatter について RubyKaigi する予定です。お楽しみに。

rubykaigi.org

5月17日(金) 14:10-14:40 @junk0612 『From LALR to IELR: A Lrama's next step』

@junk0612 です。RubyKaigi には初めての登壇です。『From LALR to IELR: A Lrama's next step』というタイトルのとおり、Lrama の話をします。Lrama について詳しくは昨年の @yui-knk さんの発表をどうぞ。

rubykaigi.org

言語処理系の分野では、Lexer と Parser は分離可能であると (基本的には) されています。しかし、例えば CRuby では < は比較演算子の役割に加えて、<< として Array の要素追加や、<<- として Heredoc の開始に使われるなどの用途があり、Lexer は状態を持ったうえで必要に応じて自身の状態を変えねばならず、特にこれまで読んできた内容、すなわち Parser の状態の影響を受けてしまうのが現実です。

CRuby ではその「Lexer の状態」を管理するための lex_state という変数があります。しかし現状では、さまざまな場所で状態が変更され見通しが悪くなっているうえ、人手によって管理されているためにある変更が他にどのような影響を与えるか機械的に知る術がなく、とても扱いづらいものになってしまっています。

そこで、パーサージェネレーター方面から「より良い LR アルゴリズムを用いたパーサー」の提供をすることで、lex_state にまつわる問題を解消しようという試みを行っています。具体的には PSLR というアルゴリズムを採用した Scannerless parser の提供です。ところが PSLR は、現在 Lrama に実装されている一般的な LR アルゴリズムである LALR からではなく、それを改良した IELR という別のアルゴリズムに立脚しています。そこで "Lrama's next step" として、IELR パーサーを Lrama が生成できるようにしよう、というのが講演の主軸となる内容です。Scannerless parser とは何なのか、IELR とLALR の違い、実装でつらかった点などについては当日の発表をお楽しみに。

rubykaigi.org

ところで @koic の文章にもあったとおり、今年は Lrama にまつわるトークが3本あります。どれか1つでいいか……と思っている皆さんにぜひお伝えしたいのが、内容的に被る部分はおそらくほぼないので、3本それぞれに聞く価値があるという点です。全部聞けばあなたも Lrama マスターになれること間違いなし。3日間に分散していて1日1本ペースなので、体力的にもやさしめです。ぜひお越しください。

rubykaigi.org rubykaigi.org


それでは本編をお楽しみに。沖縄の会場でお会いしましょう。

RubyKaigi 2024 に スポンサーとしても参加している永和システムマネジメントでは、Ruby とアジャイルソフトウェア開発や構文解析器の研究を通じてコミュニティと成長したいエンジニアを絶賛募集しています。

agile.esm.co.jp

Rails / OSS パッチ会オンライン 2024年4月のお知らせ

2024年4月の Rails / OSS パッチ会を 4月10日(水)に Discord でオンライン開催します。

この会をひとことでいうと、日頃のお仕事で使っている Rails をはじめとする OSS について、upstream にパッチを送る会です。

会には Ruby と Rails のコミッターである顧問の a_matsuda もいますので、例えば Rails に送るパッチのネタがあるけれど、パッチを送るに適しているかの判断やパッチを送る流れが悩ましいときなど a_matsuda に相談して足がかりにするなどできます。

開催時間は 17:00-19:00 となりますがご都合のあう方はぜひご参加下さい。

Discord の Rails/OSS パッチ会サーバーへの招待 URL は以下です。

discord.gg

来月開催される RubyKaigi 2024 に向けた話題などがあると思います。

rubykaigi.org

これからパッチ会に参加してみたいという方、OSS 開発者間の会話に興味があるので聞いてみたいという方もお気軽にどうぞ。


永和システムマネジメントでは、Ruby とアジャイルソフトウェア開発を通じてコミュニティと成長したいエンジニアを絶賛募集しています。

agile.esm.co.jp

RuboCop の設定ファイルで、無効な cop を明示する書き方から有効な cop を明示する書き方に直してみた

はじめに

こんにちは、@wai-doi です。

本記事では RuboCop の設定ファイルの .rubocop.ymlで、特定の cop の無効化を明示している書き方から、逆に、有効になっている cop の有効化を明示する書き方に直す方法を考えました。

やりたかったこと

まず以下のような .rubocop.yml がありました。

AllCops:
  DisabledByDefault: true

Layout:
  Enabled: true

Layout/ArgumentAlignment:
  Enabled: false

Layout/ArrayAlignment:
  Enabled: false

# 省略

Layout/SpaceInsideHashLiteralBraces:
  Enabled: false

上から順に見ていくと、まず AllCops: DisabledByDefault: true で全ての cop を無効化しています。そして、Layout: Enabled: true で Layout の cop を有効化にしています。最後に Layout の中で特定の cop を Layout/ArgumentAlignment: Enabled: false のように無効化にしています。

この状態から、逆に、どの cop が有効になっているかがわかりやすいよう、有効化している cop だけを明示した書き方に直したいということがありました。

期待する書き方は以下です。

AllCops:
  DisabledByDefault: true

Layout/AccessModifierIndentation:
  Enabled: true

# Layout/ArgumentAlignment Layout/ArrayAlignment は書かれていない

Layout/BeginEndAlignment:
  Enabled: true

# 省略

Layout/TrailingWhitespace:
  Enabled: true

つまり以下のように書き換えたかったです。

  • Layout: Enabled: true を削除する
  • Layout cops でデフォルトに有効になっている cop を明示的に Enabled: true で書く
  • ただし今 Enabled: false を書いている cop については何も書かない

解決したスクリプト

明示的に Enabled: true を書くために、RuboCop のドキュメントにあるたくさん Layout cops を書き写すのは面倒なので、以下の Ruby スクリプトを書いてみました。

rubocop v1.60.2 を用いました。

require 'rubocop'

# Layout cops を取得します
layout_cops = RuboCop::Cop::Registry.new(RuboCop::Cop::Registry.all).with_department(:Layout)

# デフォルトで有効になる Layout cops だけを取得する
default_enabled_layout_cops = layout_cops.enabled(RuboCop::ConfigLoader.default_configuration)

# .rubocop.yml から Enabled: false を書いている cop名 を取り出す
disabled_layout_cop_names = RuboCop::ConfigLoader
  .load_file('.rubocop.yml')
  .to_h
  .select {|cop_name, cop_config| cop_name.start_with?('Layout/') && cop_config['Enabled'] == false }
  .keys

# デフォルトで有効になる cop から Enabled: false を書いている cop を除く
enabled_layout_cop_names = default_enabled_layout_cops.map(&:cop_name) - disabled_layout_cop_names

# .rubocop.yml に Enabled: true をコピペできる形式にして出力する
puts enabled_layout_cop_names.map {|cop_name|
  <<~YAML
    #{cop_name}:
      Enabled: true
  YAML
}.join("\n")

1行目と2行目の RuboCop::Cop::RegistryRuboCop::ConfigLoader の使ったコードは @koic さんに教えていただきました。 RuboCop::Cop::Registry は RubCop が内部で持っている cop の一覧情報が取得できるクラスで、RuboCop::ConfigLoader は RuboCop の設定ファイルを処理するクラスです。

工夫した点

工夫したところは3行目の disabled_layout_cop_names を取得するところです。 以下のように RuboCop::Cop::Registry#disabled を使って .rubocop.yml で無効になっている cop を取得しようとしましたが、これではうまくできませんでした。

disabled_layout_cop_names = layout_cops.disabled(RuboCop::ConfigLoader.load_file('.rubocop.yml'))

#disabled実装を見ると、.rubocop.yml に Enabled:true と書かれている cop を除くという処理であることがわかりました。.rubocop.ymlには Enabled: true は書いていないためなにも除かれなかったため、これはうまくできませんでした。

別の方法で取れないかいろいろ探すと、RuboCop::ConfigLoader.load_file('.rubocop.yml') の結果を to_h でハッシュに変換できるようだったため、正規表現などを使って Enabled: false の cop を取得する方法で実現できました。

後からわかったことですが、ここで .rubocop.yml をハッシュへの変換しているのは単純にYAMLをパースしているだけなので、 YAML.load_file('.rubocop.yml') でも同じでした。

RuboCop にあるメソッドで Enabled: false と書いている cop をもっとスマートに取得できる方法もあるかもしれないですが、わかりませんでした。

おわりに

今回やってみて、RuboCop::Cop::RegistryRuboCop::ConfigLoader など RuboCop を普段使うだけでは知らなかったクラスなどを知ることができてよかったです。


永和システムマネジメントでは、Ruby とアジャイルソフトウェア開発を通じてコミュニティと成長したいエンジニアを絶賛募集しています。

agile.esm.co.jp

Rails / OSS パッチ会オンライン 2024年3月のお知らせ

2024年3月の Rails / OSS パッチ会を 3月13日(水)に Discord でオンライン開催します。

この会をひとことでいうと、日頃のお仕事で使っている Rails をはじめとする OSS について、upstream にパッチを送る会です。

会には Ruby と Rails のコミッターである顧問の a_matsuda もいますので、例えば Rails に送るパッチのネタがあるけれど、パッチを送るに適しているかの判断やパッチを送る流れが悩ましいときなど a_matsuda に相談して足がかりにするなどできます。

開催時間は 17:00-19:00 となりますがご都合のあう方はぜひご参加下さい。

Discord の Rails/OSS パッチ会サーバーへの招待 URL は以下です👇

discord.gg

5月に開催される RubyKaigi 2024 に向けた話題などがあるかもしれません。

弊社の構文解析器研究部に関心がある方や、これからパッチ会に参加してみたいという方、OSS 開発者間の会話に興味があるので聞いてみたいという方もお気軽にどうぞ。


永和システムマネジメントでは、Ruby とアジャイルソフトウェア開発を通じてコミュニティと成長したいエンジニアを絶賛募集しています。

agile.esm.co.jp

パターンマッチで NODE_ONCE に対応するようにした

こんにちは、構文解析研究部員の S.H. です。

社内でやっているエンジニアお茶会で (@koic) さんから以下のIssueの件で「Rubyのパーサー周りの問題ではないか」と相談を受けました。

github.com

そこで調査したところ比較的簡単に修正できそうなことが分かり、以下のPull Requestを作成して無事マージされました。

github.com

これは、その時の調査した内容などをまとめた記事になります。

もともとの挙動

RuboCop と RuboCop Performance を使っている際に以下のようなコードを自動修正すると、コンパイルエラーになるコードへと変換されてしまうようです。

自動修正前のコード:

v = "117"

case "117"
in /#{v}/
  p "Passed"
end
# => Passed

自動修正後のコード:

v = "117"

case "117"
in /#{v}/o # オプションとして `o` が末尾についている
  p "Passed"
end
# => NODE_IN: unknown node (NODE_ONCE)

自動修正前のコードとの差分はオプションとして o が末尾についているかどうかだけのようです。またエラーメッセージにある NODE_INNODE_ONCE はRuby内部で利用しているASTノードのことなのでRuby本体側の問題らしいことが分かりますね。

調査

まずはエラーメッセージを元に CRuby のソースコードを grep してみました。

NODE関連のエラーメッセージなので該当しそうな個所としては parse.y、node.c、node_dump.c、compile.c、 ruby_parser.c あたりが怪しそうでした。ただ parse.y、node.c、node_dump.c、ruby_parser.c に関してはおそらく無関係かもしれないな思っていました。

これは以下のように考えたためです。

  • parse.y、node.c、node_dump.c については、Universal Parser の C API依存削減対応や新しい NODE 追加などを直近で調べていたなので、該当しそうな箇所を見た覚えがないので無関係かもしれない
  • またIssueのコードからパターンマッチ関係で発生しているエラーらしく、以前からあるソースコードが怪しいため比較的最近追加された ruby_parser.c ではなさそう

そこで compile.c のソースコードを grep すると該当しそうなところがありました。

github.com

iseq_compile_pattern_each という関数の中でエラーメッセージを出力して、パターンマッチで受け取ったパターンのASTノードに合わせて ISeq に変換しているようです。またエラーメッセージと合わせて考えると、 NODE_ONCE というASTノードにマッチした時の処理がないためエラーになっていそうですね。

次に再現コードを作成し、最新のRuby(ruby 3.4.0dev (2024-02-01T12:17:37Z master 8531ac3115) [x86_64-linux])で実行してみました。

v = "117"

case "117"
in /#{v}/o
  p "Passed"
end

無事、コンパイルエラーになり再現できました。

test.rb:4: NODE_IN: unknown node (NODE_ONCE)
test.rb: compile error (SyntaxError)

その後、再現コードがどういったASTノードを生成しているのか dump してみました。

$ ruby --dump parsetree test.rb

以下が dump した結果になります。

###########################################################
## Do NOT use this node dump for any purpose other than  ##
## debug and research.  Compatibility is not guaranteed. ##
###########################################################

# @ NODE_SCOPE (id: 15, line: 1, location: (1,0)-(6,3))
# +- nd_tbl: :v
# +- nd_args:
# |   (null node)
# +- nd_body:
#     @ NODE_BLOCK (id: 13, line: 1, location: (1,0)-(6,3))
#     +- nd_head (1):
#     |   @ NODE_LASGN (id: 0, line: 1, location: (1,0)-(1,9))*
#     |   +- nd_vid: :v
#     |   +- nd_value:
#     |       @ NODE_STR (id: 1, line: 1, location: (1,4)-(1,9))
#     |       +- nd_lit: "117"
#     +- nd_head (2):
#         @ NODE_CASE3 (id: 12, line: 3, location: (3,0)-(6,3))*
#         +- nd_head:
#         |   @ NODE_STR (id: 2, line: 3, location: (3,5)-(3,10))
#         |   +- nd_lit: "117"
#         +- nd_body:
#             @ NODE_IN (id: 11, line: 4, location: (4,0)-(5,12))
#             +- nd_head:
#             |   @ NODE_ONCE (id: 7, line: 4, location: (4,3)-(4,10))
#             |   +- nd_body:
#             |       @ NODE_DREGX (id: 6, line: 4, location: (4,3)-(4,10))
#             |       +- nd_lit: ""
#             |       +- nd_next->nd_head:
#             |       |   @ NODE_EVSTR (id: 4, line: 4, location: (4,4)-(4,8))
#             |       |   +- nd_body:
#             |       |       @ NODE_LVAR (id: 3, line: 4, location: (4,6)-(4,7))
#             |       |       +- nd_vid: :v
#             |       +- nd_next->nd_next:
#             |           (null node)
#             +- nd_body:
#             |   @ NODE_FCALL (id: 8, line: 5, location: (5,2)-(5,12))*
#             |   +- nd_mid: :p
#             |   +- nd_args:
#             |       @ NODE_LIST (id: 10, line: 5, location: (5,4)-(5,12))
#             |       +- as.nd_alen: 1
#             |       +- nd_head:
#             |       |   @ NODE_STR (id: 9, line: 5, location: (5,4)-(5,12))
#             |       |   +- nd_lit: "Passed"
#             |       +- nd_next:
#             |           (null node)
#             +- nd_next:
#                 (null node)

これを見ると NODE_ONCE は動的に生成された正規表現用の NODE_DREGEX をラップしていることがわかります。

NODE_ONCE は6年ほど前に導入されたもので、 /regexp/o の時にのみ扱うASTノード ということも以下の記事から分かりました。

ruby-trunk-changes.hatenablog.com

また NODE_DREGX は以下の部分でパターンマッチ用のISeqを生成しているようでした。NODE_LIT(リテラル用のNODE)やNODE_STR なども同じ部分で判定しているようです。

github.com

ここまでのことから以下のことが分かりました。

  • パターンマッチ用のISeq生成処理でNODE_ONCEのケースがないため、すり抜けてエラーになっている
  • NODE_ONCENODE_DREGX をラップしているだけの NODE なので他への影響範囲は小さそう
  • NODE_DREGXと同じ部分にはNODE_LITやNODE_STRなどもあることから、そこへNODE_ONCEを渡してやればよさそう

これらの調査結果をもとに対応に進めます。

対応

iseq_compile_pattern_eachNODE_ONCE のケースでもISeqを生成するように修正してみました。すると以下の再現コードを実行できるようになりました。

v = "117"

case "117"
in /#{v}/o
  p "Passed"
end
# => Passed

あとはテストケースも追加してPull Requestを作成しました。

github.com

先日無事マージされ、現在のRubyのmasterでは修正されています。

反省点

無事修正できましたが反省点もありました。

https://bugs.ruby-lang.org にチケットを作成していなかった点です。

チケットを作成しておくことで後からチケットを見た時にどういった経緯だったかが確認しやすくなりますし、bugs.ruby-lang.org にはバックポートが必要かどうかをチケットに記載できたりもします。 そのため後からバックポートが必要な修正だった場合に、コミッターの方々が対応しやすくなる可能性があります。

こういった点からチケットを起票していなかった点は、良くないですね。

今後はチケットを起票するべきかなども考慮しつつ、対応を進められればと思いますね。


永和システムマネジメントでは、Rubyへのコントリビューションを通じてコミュニティと成長したいエンジニアを絶賛募集しています。

agile.esm.co.jp