Skip to content

feat: support Ruby symbol literals (:symbol) with $_symbols_ global list #313

@takaokouji

Description

@takaokouji

Goal

Ruby のシンボルリテラル :symbol を Smalruby で扱えるようにする。シンボルはグローバルリスト $_symbols_ で管理し、data_itemnumoflist ブロックでインデックスを参照することで高速な比較を実現する。教育的観点から、.to_s なしでは文字列として使えないことを明示する(say/puts/p/print は例外として暗黙変換)。

アーキテクチャ概要

Ruby ソースコード                       Scratch ブロック
─────────────────                     ──────────────────
(パーザーが自動管理)                   グローバルリスト $_symbols_ = [":foo", ":bar", ":baz"]
                                      (プロジェクトファイルに永続化)

:foo (値として参照)                ←→  data_itemnumoflist(LIST=$_symbols_, ITEM=":foo")
                                      + comment: @ruby:symbol:foo

:foo.to_s                          ←→  operator_join(STRING1="foo", STRING2="")
                                      + comment: @ruby:symbol:foo

say(:foo)                          ←→  looks_say(MESSAGE="foo")
                                      + comment: @ruby:symbol:foo

x = :foo                           ←→  data_setvariableto(x, data_itemnumoflist(...))
                                      variable dataType: 'symbol'

:foo == :bar                       ←→  operator_equals(
                                        data_itemnumoflist(":foo"),
                                        data_itemnumoflist(":bar"))
                                      → 整数比較(高速)

設計判断(確定事項)

項目 決定
ブロックエディタでの直接操作 考慮外(Rubyタブ編集が前提)
$_symbols_ の永続化 Scratch VM のリスト変数としてプロジェクトファイルに格納(初期化ブロック不要)
シンボルの順序 ソースコード上の出現順
複数ターゲット間の共有 グローバルリストに統合

動作一覧

コード ブロック表現 備考
:foo (値として) data_itemnumoflist(LIST=$_symbols_, ITEM=":foo") + @ruby:symbol:foo インデックス参照
:foo.to_s operator_join("foo", "") + @ruby:symbol:foo 文字列変換
say(:foo) looks_say(MESSAGE="foo") + @ruby:symbol:foo 暗黙変換
puts(:foo) / p(:foo) / print(:foo) 同上パターン 暗黙変換
x = :foo data_setvariableto(x, itemnumoflist) dataType='symbol'
:foo == :bar operator_equals(index, index) 整数比較(高速)
move(:foo) エラー: 「.to_s を付けてください」
self.when(:flag_clicked) 既存動作 変更なし
ふりがな: :foo シンボル「foo」
ルビースクリプト保存 $_symbols_ = [:foo, :bar, :baz] を出力

Affected Files

Ruby → Blocks(コンバーター)

  • packages/scratch-gui/src/lib/ruby-to-blocks-converter/index.js — シンボル収集、$_symbols_ リスト作成、エラーメッセージ
  • packages/scratch-gui/src/lib/ruby-to-blocks-converter/ast-handlers/expressions.jsvisitSymbolNode 拡張
  • packages/scratch-gui/src/lib/ruby-to-blocks-converter/operators.js.to_s にシンボルレシーバ追加
  • packages/scratch-gui/src/lib/ruby-to-blocks-converter/looks.jssay でシンボル引数の暗黙変換
  • packages/scratch-gui/src/lib/ruby-to-blocks-converter/variables.js — 変数代入時の symbol dataType
  • packages/scratch-gui/src/lib/ruby-to-blocks-converter/node-utils.js — シンボル関連ユーティリティ拡張
  • packages/scratch-gui/src/lib/ruby-to-blocks-converter/variable-utils.js$_symbols_ リスト管理

Blocks → Ruby(ジェネレーター)

  • packages/scratch-gui/src/lib/ruby-generator/data.jsdata_itemnumoflist + @ruby:symbol:foo 出力
  • packages/scratch-gui/src/lib/ruby-generator/looks.jssay + @ruby:symbolsay(:foo) 出力
  • packages/scratch-gui/src/lib/ruby-generator/code-finisher.js$_symbols_ = [...] 出力

ロケール

  • packages/scratch-gui/src/locales/ja.js — エラーメッセージ
  • packages/scratch-gui/src/locales/ja-Hira.js — エラーメッセージ(ひらがな)

ふりがな

  • packages/scratch-gui/src/lib/furigana-node-handlers.js_handleSymbolNode 追加

Implementation Steps

  • Phase 1: $_symbols_ リスト管理基盤 — パーザー内でシンボル収集、Stage 上にグローバルリスト作成
  • Phase 2: シンボル参照 → data_itemnumoflist ブロック — visitSymbolNode 拡張、@ruby:symbol:foo コメント付与
  • Phase 3: :symbol.to_s サポート — operators.js'symbol' レシーバ追加
  • Phase 4: say/puts/p/print でシンボル暗黙変換 — 各ハンドラでシンボル引数の暗黙文字列変換
  • Phase 5: シンボル非対応メソッドのエラーメッセージ — symbolNeedsToS エラー追加、ロケール追加
  • Phase 6: Blocks → Ruby ジェネレーター — @ruby:symbol コメント検出、シンボルリテラル・$_symbols_ 出力
  • Phase 7: ふりがな対応 — _handleSymbolNodeシンボル「foo」 表示
  • Phase 8: Integration Tests — round-trip、$_symbols_ 管理、エラーケース

Definition of Done

  • ユニットテスト pass
  • Integration テスト pass
  • lint pass
  • CI green
  • ブラウザ確認(Playwright MCP):
    • :foo.to_s を Ruby タブで入力 → エラーなしで変換、ブロック表示される
    • say(:foo, 2) → 正常にブロック変換、スプライトが「foo」と表示
    • x = :foodata_itemnumoflist ブロックで変数にインデックス格納
    • :foo == :baroperator_equals で比較ブロック生成
    • move(:foo) → 「.to_s を付けてください」エラーメッセージ表示
    • :foo 単独 → エラーメッセージ表示
    • self.when(:flag_clicked) → 既存動作が壊れていない
    • ブロック → Ruby 変換で :foo リテラルが正しく出力される
    • 「ルビースクリプトを保存」で $_symbols_ = [:foo, :bar, :baz] が出力される
    • :foo にふりがな シンボル「foo」 が表示される

Test Plan

Type Timing Target
Unit tests (TDD) 各Phase で RED → GREEN シンボル収集、ブロック変換、エラー、ジェネレーター、ふりがな
Integration tests Phase 8 round-trip、$_symbols_ 管理
Browser verification CI green 後 Playwright MCP で DoD 確認

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions