# 機能設計書 43-Class/Module拡張

## 概要

本ドキュメントは、mruby-class-ext gemが提供するClassクラスおよびModuleクラスへの拡張メソッド群の機能設計を記述する。モジュール階層比較演算子、名前取得、シングルトンクラス判定、サブクラス列挙、attached_object取得、class_exec/module_execを追加する。

### 本機能の処理概要

mruby-class-ext gemは、ClassクラスとModuleクラスにメタプログラミングおよびリフレクション用のメソッドを追加する。全てC言語(src/class.c)で実装されており、ROMテーブルを用いて効率的にメソッド登録を行う。

**業務上の目的・背景**：Rubyのクラス・モジュールシステムはオブジェクト指向プログラミングの核であり、継承関係の比較（<, <=, >, >=, <=>）、クラス名の取得(name)、動的なメソッド定義(class_exec/module_exec)はフレームワーク構築やメタプログラミングに不可欠である。mrubyコアには含まれないこれらの機能を拡張gemとして提供する。

**機能の利用シーン**：クラス継承関係の確認（A < B）、モジュールの名前取得、クラスのサブクラス列挙、動的メソッド定義（DSL構築時等）、シングルトンクラスの判定に使用される。

**主要な処理内容**：
1. Module#< / Module#<= / Module#> / Module#>= / Module#<=> - 継承階層の比較
2. Module#name - モジュール/クラスの完全修飾名を取得
3. Module#singleton_class? - シングルトンクラスかどうかを判定
4. Module#class_exec / Module#module_exec - モジュール/クラスのコンテキストでブロックを実行
5. Class#subclasses - 直接のサブクラス一覧を取得
6. Class#attached_object - シングルトンクラスの元オブジェクトを取得

**関連システム・外部連携**：なし。mrubyコアのクラスシステム・オブジェクト空間に依存する。

**権限による制御**：なし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はライブラリ機能であり、画面との関連はない |

## 機能種別

ライブラリ拡張（クラス・モジュールのリフレクション・メタプログラミング機能の追加）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| other (比較演算子) | Module/Class | Yes | 比較対象のモジュール/クラス | 非クラス/モジュールはTypeError |
| args (class_exec) | Any | No | ブロックに渡す引数 | 任意 |
| block (class_exec) | Block | Yes | 実行するブロック | ブロック必須 |

### 入力データソース

メソッド呼び出し時の引数およびブロック

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 比較演算子戻り値 | true/false/nil | 継承関係に基づく比較結果 |
| <=>戻り値 | -1/0/+1/nil | 継承関係の比較結果 |
| name戻り値 | String/nil | 完全修飾名（匿名クラスはnil） |
| singleton_class?戻り値 | Boolean | シングルトンクラスかどうか |
| class_exec戻り値 | Object | ブロックの戻り値 |
| subclasses戻り値 | Array | 直接のサブクラスの配列 |
| attached_object戻り値 | Object | シングルトンクラスの元オブジェクト |

### 出力先

メソッドの戻り値として呼び出し元に返却

## 処理フロー

### 処理シーケンス

```
1. 継承階層比較 (Module#< 等)
   ├─ 同一オブジェクトの場合: <,>はfalse、<=,>=はtrue、<=>は0
   ├─ is_ancestor(self, other)でself側の継承チェーンを走査
   ├─ is_ancestor(other, self)でother側の継承チェーンを走査
   └─ 継承関係なし: nil

2. Class#subclasses
   ├─ MRB_FL_CLASS_IS_INHERITEDフラグで継承有無を確認
   ├─ mrb_objspace_each_objectsで全オブジェクトを走査
   └─ 直接のスーパークラスが一致するクラスを配列に収集

3. Class#attached_object
   ├─ MRB_TT_SCLASSかどうかチェック
   ├─ 非シングルトンクラスの場合: TypeError
   └─ __attached__インスタンス変数から元オブジェクトを取得
```

### フローチャート

```mermaid
flowchart TD
    A[Module#<] --> B{self == other?}
    B -->|Yes| C[false]
    B -->|No| D[mod_compare_hierarchy]
    D --> E{is_ancestor self, other?}
    E -->|Yes| F[true - selfはotherの子孫]
    E -->|No| G{is_ancestor other, self?}
    G -->|Yes| H[false - otherはselfの子孫]
    G -->|No| I[nil - 関係なし]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-43-01 | 継承階層比較 | is_ancestor関数でICLASS(include module)も含めて比較する | 比較演算子使用時 |
| BR-43-02 | name凍結 | name戻り値の文字列はfrozenとなる | Module#name呼び出し時 |
| BR-43-03 | subclasses走査 | MRB_FL_CLASS_IS_INHERITEDフラグがない場合は空配列を即返す | Class#subclasses呼び出し時 |
| BR-43-04 | attached_object制限 | シングルトンクラス以外ではTypeErrorが発生する | Class#attached_object呼び出し時 |

### 計算ロジック

is_ancestor関数: 継承チェーンを辿り、MRB_TT_ICLASSの場合はc->cで比較、通常クラスはポインタ比較

## データベース操作仕様

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | TypeError | 比較演算子に非モジュール/クラスを渡した場合 | モジュールまたはクラスを渡す |
| - | TypeError | attached_objectを非シングルトンクラスに呼んだ場合 | シングルトンクラスに対して呼ぶ |

### リトライ仕様

リトライは不要

## トランザクション仕様

該当なし

## パフォーマンス要件

比較演算子はO(d)（d=継承チェーンの深さ）。subclassesはO(n)（n=オブジェクト空間のオブジェクト数）で、全オブジェクトを走査するためコストが高い。

## セキュリティ考慮事項

class_exec/module_execはクラス/モジュールのコンテキストでコードを実行するため、信頼されないコードでの使用に注意。

## 備考

- class_execとmodule_execは同一の実装(mod_module_exec)
- subclassesはmrb_objspace_each_objectsを使用するため、全オブジェクトを走査する
- nameの戻り値はfrozen文字列

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | class.c | `mrbgems/mruby-class-ext/src/class.c` | subclass_args構造体（77-80行目） |

**読解のコツ**: `struct RClass`はmrubyのクラス/モジュールを表す構造体。`super`フィールドがスーパークラスへのポインタ、`tt`フィールドが型（MRB_TT_CLASS, MRB_TT_SCLASS等）を表す。`MRB_TT_ICLASS`はincludeされたモジュールの内部表現。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | class.c | `mrbgems/mruby-class-ext/src/class.c` | gem初期化（364-372行目） |

**主要処理フロー**:
1. **364-372行目**: `mrb_mruby_class_ext_gem_init` - ModuleとClassにROMテーブル登録
2. **338-348行目**: `mod_ext_rom_entries` - Moduleのメソッド定義（比較演算子、name、singleton_class?等）
3. **350-353行目**: `cls_ext_rom_entries` - Classのメソッド定義（attached_object, subclasses）

#### Step 3: 継承階層比較を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | class.c | `mrbgems/mruby-class-ext/src/class.c` | is_ancestor関数と比較演算子 |

**主要処理フロー**:
- **179-193行目**: `is_ancestor` - 継承チェーンを辿る核心ロジック
- **214-232行目**: `mod_compare_hierarchy` - is_ancestorを使った比較判定
- **241-247行目**: `mrb_mod_le` (<=) - 直接compare_hierarchy呼び出し
- **256-265行目**: `mrb_mod_lt` (<) - 同一なら false、それ以外はcompare_hierarchy
- **311-335行目**: `mrb_mod_cmp` (<=>) - 同一なら0、比較結果を-1/0/+1/nilに変換

#### Step 4: サブクラス列挙を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | class.c | `mrbgems/mruby-class-ext/src/class.c` | subclassesとadd_subclasses |

**主要処理フロー**:
- **96-107行目**: `add_subclasses` - コールバック関数。MRB_TT_CLASSで直接スーパークラスが一致するものを収集
- **126-137行目**: `class_subclasses` - MRB_FL_CLASS_IS_INHERITEDフラグ確認後、全オブジェクト走査

#### Step 5: その他メソッドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | class.c | `mrbgems/mruby-class-ext/src/class.c` | name, singleton_class?, attached_object, class_exec |

**主要処理フロー**:
- **24-32行目**: `mod_name` - mrb_class_pathで名前取得、frozen設定
- **45-49行目**: `mod_singleton_class_p` - mrb_sclass_pで判定
- **70-74行目**: `mod_module_exec` - mrb_object_execでコンテキスト実行
- **154-162行目**: `class_attached_object` - MRB_TT_SCLASSチェック後、__attached__インスタンス変数取得

### プログラム呼び出し階層図

```
mrb_mruby_class_ext_gem_init
    |
    +-- MRB_MT_INIT_ROM(Module)
    |       +-- mrb_mod_lt (<)
    |       |       +-- mod_compare_hierarchy
    |       |               +-- is_ancestor
    |       +-- mrb_mod_le (<=)
    |       +-- mrb_mod_gt (>)
    |       +-- mrb_mod_ge (>=)
    |       +-- mrb_mod_cmp (<=>)
    |       +-- mod_name
    |       |       +-- mrb_class_path
    |       +-- mod_singleton_class_p
    |       |       +-- mrb_sclass_p
    |       +-- mod_module_exec
    |               +-- mrb_object_exec
    |
    +-- MRB_MT_INIT_ROM(Class)
            +-- class_attached_object
            |       +-- mrb_obj_iv_get(__attached__)
            +-- class_subclasses
                    +-- mrb_objspace_each_objects
                            +-- add_subclasses (callback)
```

### データフロー図

```
[入力]                  [処理]                            [出力]

ClassA, ClassB   --> mod_compare_hierarchy()        --> true/false/nil
Module           --> mod_name()                     --> "Module::Name" (frozen)
Class            --> mod_singleton_class_p()        --> true/false
Class + block    --> mod_module_exec()              --> ブロック戻り値
Class            --> class_subclasses()             --> [SubClassA, SubClassB, ...]
SingletonClass   --> class_attached_object()        --> original_object
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| class.c | `mrbgems/mruby-class-ext/src/class.c` | ソース | 全メソッドのC実装 |
| mrbgem.rake | `mrbgems/mruby-class-ext/mrbgem.rake` | 設定 | gem定義ファイル |
| class.rb | `mrbgems/mruby-class-ext/test/class.rb` | テスト | Classメソッドのテスト |
| module.rb | `mrbgems/mruby-class-ext/test/module.rb` | テスト | Moduleメソッドのテスト |
