forked from scratchfoundation/scratch-editor
-
Notifications
You must be signed in to change notification settings - Fork 1
Closed
Description
Goal
Ruby の module / include をサポートし、複数スプライトでメソッド定義を共有できるようにする。モジュール編集時に即座に全スプライトへ同期する、スモウルビーの目玉機能。Ruby version 2 専用。
動作イメージ
Ruby タブの表示(各スプライト共通)
Sprite1:
module Utils
def add(a, b)
a + b
end
end
class Sprite1
include Utils
when_flag_clicked do
move(add(1, 5))
end
endSprite2:
module Utils
def add(a, b)
a + b
end
end
class Sprite2
include Utils
when_clicked do
turn_right(add(1, 5))
end
endScratch ブロック表現(各スプライト)
各スプライトに同一の procedure blocks が複製される:
procedures_definition: add(a, b) ← comment: @ruby:module_source:Utils
[a + b を返すブロック群]
ファイルダウンロード(全ターゲット)
require "smalruby3"
module Utils
def add(a, b)
a + b
end
end
class Stage < ::Smalruby3::Stage
end
class Sprite1 < ::Smalruby3::Sprite
include Utils
when_flag_clicked do
move(add(1, 5))
end
end
class Sprite2 < ::Smalruby3::Sprite
include Utils
when_clicked do
turn_right(add(1, 5))
end
endコメント設計
procedures_definition ブロック
@ruby:module_source:Utils ← このメソッドは module Utils 由来
クラスコメント(include 順序保持)
@ruby:class:name,include=Utils,include=Helpers
include= の出現順が include 順序を表す。
モジュール同期メカニズム(即時同期)
トリガー: あるスプライトの Ruby コードが変換(Ruby → Blocks)されたとき
フロー:
- Sprite1 のコードを変換 →
module Utilsのメソッド定義を検出 - Sprite1 の procedure blocks に
@ruby:module_source:Utilsコメント付きで作成 - 同期処理:
Utilsを include している他の全スプライトを検出(procedure blocks のコメントから@ruby:module_source:Utilsを検索) - 各対象スプライトについて:
a. そのスプライトの Ruby コードを生成(Blocks → Ruby)
b. 生成コード内の古いmodule Utils ... endを新しい定義に置換
c. 置換後のコードを再変換(Ruby → Blocks)し、ブロックを適用
Scratch ブロックの仕組みにより、プロシージャの引数追加時に呼び出し側に "" がデフォルト引数として自動追加されるため、同期エラーは発生しない。
Ruby version 制限
- Ruby version 1:
moduleはエラー(「moduleは Ruby version 2 でのみ使用できます」) - v2 → v1 への切替防止: いずれかのターゲットに
@ruby:module_source:*コメント付きプロシージャまたは@ruby:classコメントが存在する場合、v1 切替ボタンをグレーアウトし、ツールチップで理由を表示
エラーハンドリング
| ケース | メッセージ |
|---|---|
v1 で module を使用 |
module は Ruby version 2 でのみ使用できます |
include で未定義モジュールを参照 |
モジュール Utils が定義されていません |
| module 内にネストした module | 現在のスモウルビーでは使うことができません |
module_function を使用 |
現在のスモウルビーでは使うことができません |
extend を使用 |
現在のスモウルビーでは使うことができません |
| module 内にメソッド定義以外 | 現在のスモウルビーではモジュール内にメソッド定義のみ記述できます |
Affected Files
Ruby → Blocks(コンバーター)
packages/scratch-gui/src/lib/ruby-to-blocks-converter/index.js—visitModuleNode追加、visitClassNodeにinclude処理追加、v1 エラー処理
Blocks → Ruby(ジェネレーター)
packages/scratch-gui/src/lib/ruby-generator/index.js—finish()で module 生成 +include挿入、finishTargets()で重複排除packages/scratch-gui/src/lib/ruby-generator/procedure.js—@ruby:module_source:*検出時にdef method(self.なし)生成
モジュール同期
packages/scratch-gui/src/containers/ruby-tab.jsx— コード変換後にモジュール同期処理を実行packages/scratch-gui/src/lib/module-sync.js(新規) — 同期ロジック
v1 切替防止
- Ruby version 切替 UI — v2 専用機能使用時の v1 切替無効化
テスト(新規)
packages/scratch-gui/test/unit/lib/ruby-to-blocks-converter/module.test.jspackages/scratch-gui/test/unit/lib/ruby-generator/module.test.jspackages/scratch-gui/test/unit/lib/module-sync.test.jspackages/scratch-gui/test/integration/module-include.test.js
Implementation Steps
-
Phase 1: visitModuleNode + include → Blocks
visitModuleNode実装(module body のメソッド AST を context に保存)visitClassNodeに include 処理追加(module メソッドを展開し@ruby:module_source:*コメント付与)- クラスコメントに
include=ModuleNameを追加 - v1 での module エラー処理
- TDD: ユニットテスト先行
feat: add module/include support to ruby-to-blocks converter
-
Phase 2: Blocks → Ruby(単一ターゲット)
procedure.js:@ruby:module_source:*検出時にdef method(self.なし)生成finish()/_wrapWithClass(): module メソッドを分離しmodule ... end+include生成- クラスコメントの
include=順序でinclude文を生成 - TDD: ユニットテスト先行
feat: generate module/include syntax from procedure comments
-
Phase 3: モジュール同期
module-sync.js新規作成ruby-tab.jsxに変換後の同期処理追加- 他ターゲットの検出 → Ruby 生成 → module 置換 → 再変換 → ブロック適用
- TDD: ユニットテスト先行
feat: add immediate module sync across sprites
-
Phase 4: ファイル出力の重複排除
finishTargets()で全ターゲットの module 定義を重複排除し先頭に1回出力- TDD: ユニットテスト先行
feat: deduplicate module definitions in multi-target output
-
Phase 5: エラーハンドリング + v1 切替防止
- ネスト module、module_function、extend の検出・エラー表示
- module 内の非メソッド文のエラー
- v2 専用機能使用時の v1 切替無効化 UI
feat: add module error handling and v1 switch prevention
-
Phase Final: Integration Tests
- ラウンドトリップ統合テスト(Ruby → Blocks → Ruby)
- モジュール同期統合テスト
- ファイル出力統合テスト
test: add integration tests for module/include feature
Test Plan
| Type | Timing | Target |
|---|---|---|
| Unit tests (TDD) | Before implementation (RED → GREEN) | visitModuleNode, include 展開, generator, module-sync |
| Integration tests | After implementation | ラウンドトリップ, 同期, ファイル出力 |
Risks & Open Questions
- 同期のパフォーマンス: スプライト数が多い場合、全ターゲットの Ruby 生成 → 再変換がボトルネックになる可能性。非同期処理で UI をブロックしない工夫が必要。
- ネスト module / module_function / extend: サポートしない。検出時にエラー表示。
- module 内の定数やクラス変数: サポートしない。メソッド定義のみ。
- ふりがな対応:
furigana-annotator.jsに module/include 関連のキーワードマッピング追加が必要(別 Issue で対応可)。
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels