Skip to content

feat: implement case...when...else...end conversion between Ruby and blocks #123

@takaokouji

Description

@takaokouji

Goal

Ruby の case...when...else...end 構文を、命令ブロック(control_if / control_if_else)と相互変換できるようにする。変換時は @ruby:syntax:case:<subject>:<index> コメントアノテーションで case 文を識別し、複数の case 文を区別するためにインデックスを付与する。

case は内部的にネストされた if...else...end ブロックとして表現され、elsif と同様のパターンで実装する。

変換パターン

pattern1: case...when...end

Ruby tab:

@a = 1
case @a
when 1
  say "1"
end

Code tab (Ruby pseudo-representation of command blocks):

@a = 1
if @a == 1 # @ruby:syntax:case:@a:1 (control_if), @ruby:syntax:case:@a:1 (operator_equals)
  say "1"
end

pattern2: case...when...else...end

Ruby tab:

@a = 1
case @a
when 1
  say "1"
else
  say "other"
end

Code tab:

@a = 1
if @a == 1 # @ruby:syntax:case:@a:1 (control_if_else), @ruby:syntax:case:@a:1 (operator_equals)
  say "1"
else
  say "other"
end

pattern3: case...when...when...else...end

Ruby tab:

@a = 1
case @a
when 1
  say "1"
when 2
  say "2"
else
  say "other"
end

Code tab:

@a = 1
if @a == 1 # @ruby:syntax:case:@a:1 (control_if_else), @ruby:syntax:case:@a:1 (operator_equals)
  say "1"
else
  if @a == 2 # @ruby:syntax:case:@a:1 (control_if_else), @ruby:syntax:case:@a:1 (operator_equals)
    say "2"
  else
    say "other"
  end
end

Affected Files

  • packages/scratch-gui/src/lib/ruby-to-blocks-converter/ast-handlers/control-flow.js_onCase ハンドラを追加
  • packages/scratch-gui/src/lib/ruby-to-blocks-converter/context-utils.jscaseCounter: 0 をコンテキストに追加
  • packages/scratch-gui/src/lib/ruby-generator/control.js@ruby:syntax:case:<subject>:<index> コメント検出と case...when...end 生成ロジックを追加
  • packages/scratch-gui/test/unit/lib/ruby-to-blocks-converter/control.test.js — Ruby→Blocks 変換のユニットテストを追加
  • packages/scratch-gui/test/unit/lib/ruby-generator/control.test.js — Blocks→Ruby 生成のユニットテストを追加
  • packages/scratch-gui/test/integration/ruby-tab/control.test.js — ラウンドトリップ統合テストを追加

Implementation Steps(TDD + Commit Strategy)

Phase 1: Ruby→Blocks 変換(_onCase ハンドラ)

Ruby AST の case ノードの各 when 節をネストされた control_if / control_if_else ブロックに変換する。全ての関連ブロックに @ruby:syntax:case:<subject>:<index> コメントを付与する。

  1. [RED] ユニットテスト追加(失敗確認)
    • pattern1: case...when...end
    • pattern2: case...when...else...end
    • pattern3: case...when...when...else...end
    • 複数 case 文(caseCounter が正しくインクリメントされること)
  2. [GREEN] 実装
    • context-utils.js: caseCounter: 0 を追加
    • control-flow.js: _onCase(node) メソッドを追加
      • case の subject(例: @a)を取得
      • when 節の条件と本体を処理し、control_if / control_if_else ブロックを生成
      • caseCounter++ して全関連ブロックに @ruby:syntax:case:<subject>:<index> コメントを付与
  3. [PASS] lint + ユニットテスト確認
  4. [COMMIT & PUSH] feat: implement case...when Ruby-to-blocks conversion
  5. [MAKE PR] PR 作成

Phase 2: Blocks→Ruby 生成(@ruby:syntax:case 検出)

control_if / control_if_else ブロックのコメントに @ruby:syntax:case:<subject>:<index> が含まれている場合、case...when...end を生成する。

  1. [RED] ユニットテスト追加(失敗確認)
    • pattern1〜3 のブロック→Ruby 変換テスト
  2. [GREEN] 実装
    • ruby-generator/control.js に case コメント検出ロジックを追加
    • トップレベル(最初の when)は case <subject>\nwhen <rhs> を生成
    • 同じインデックスを持つ後続ブロックは when <rhs> を生成
    • else 節は else として生成
    • 全体を end で閉じる
  3. [PASS] lint + ユニットテスト確認
  4. [COMMIT & PUSH] feat: implement case...when blocks-to-ruby generation

Phase Final: 統合テスト(実装後)

  • ラウンドトリップテスト(Ruby → Blocks → Ruby)を追加
  • lint + 全テスト(ユニット + 統合)パス確認
  • [COMMIT & PUSH] test: add integration tests for case...when conversion

Test Plan

Type Timing Target
Unit tests (TDD) Before implementation (RED → GREEN) _onCase ハンドラ、control_if / control_if_else ジェネレータ
Integration tests After implementation round-trip Ruby → Blocks → Ruby

Risks & Open Questions

  • Opal AST の case ノード構造: when 節の子ノード数や else の扱いを実装前に確認する必要がある
  • スコープ外: when 1, 2 のような複数条件の when は別 Issue で対応

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions