# 機能設計書 64-Method/UnboundMethodクラス

## 概要

本ドキュメントは、mrubyにおけるMethodおよびUnboundMethodクラスの設計を記述する。mruby-method gemとして実装され、メソッドオブジェクトの取得・呼び出し・リフレクションを提供する。

### 本機能の処理概要

Method/UnboundMethodクラスは、Rubyのメソッドをファーストクラスオブジェクトとして扱う機能を提供する。obj.method(:name)でMethodオブジェクトを取得し、call/[]で呼び出したり、unbindでUnboundMethodに変換したりできる。メソッドのarity、source_location、parameters等のリフレクション情報も取得可能。

**業務上の目的・背景**：メソッドをオブジェクトとして扱えることで、コールバック、デコレータパターン、メソッドの動的ディスパッチ等の高度なプログラミングパターンが実現できる。

**機能の利用シーン**：コールバック関数としてのメソッド渡し、メソッドの引数情報の動的取得、スーパークラスのメソッドへの直接アクセス（super_method）、メソッドのバインド先変更等で使用される。

**主要な処理内容**：
1. Methodオブジェクト生成（Kernel#method、Kernel#singleton_method）
2. UnboundMethodオブジェクト生成（Module#instance_method）
3. メソッド呼び出し（Method#call / Method#[]）
4. バインド解除と再バインド（Method#unbind、UnboundMethod#bind）
5. バインド付き呼び出し（UnboundMethod#bind_call）
6. メソッド情報取得（arity、source_location、parameters、owner、receiver、name）
7. スーパーメソッドの取得（super_method）
8. メソッドの等価比較（==、eql?）

**関連システム・外部連携**：mruby-proc-ext（parameters/source_location）に依存。

**権限による制御**：singleton_methodはシングルトンメソッドのみに限定。bind時にクラス互換性チェック。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | CLIベースのため画面なし |

## 機能種別

リフレクション / メタプログラミング

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | Symbol | Yes | メソッド名 | 存在するメソッドであること |
| obj | Object | Yes (bind時) | バインド先オブジェクト | 元のクラスと互換性があること |
| args | Any | No | メソッド呼び出し時の引数 | メソッドのarityに従う |

### 入力データソース

mrubyスクリプトからの直接呼び出し

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Method | Method | バインド済みメソッドオブジェクト |
| UnboundMethod | UnboundMethod | 非バインドメソッドオブジェクト |
| 呼び出し結果 | Object | call/[]の戻り値 |
| arity | Integer | 引数情報（固定数 or -n-1） |

### 出力先

mruby値スタック上に結果を返却

## 処理フロー

### 処理シーケンス

```
1. メソッドオブジェクト生成
   └─ method_alloc()でRObjectを割り当て、_owner/_recv/_name/_proc/_klassをインスタンス変数として設定
2. メソッド探索
   └─ method_search_vm()でメソッドテーブルを走査し、RProc*を取得
3. メソッド呼び出し（Method#call）
   └─ mcall()でreceiver/proc/midを設定し、mrb_exec_irep()を呼び出し
4. バインド操作
   └─ bind_check()でクラス互換性を検証後、新しいMethodオブジェクトを生成
```

### フローチャート

```mermaid
flowchart TD
    A[obj.method(:name)] --> B[method_alloc]
    B --> C[search_method_owner]
    C --> D{メソッド見つかった?}
    D -->|Yes| E[Method/UnboundMethodオブジェクト生成]
    D -->|No| F{respond_to_missing?}
    F -->|Yes| E
    F -->|No| G[NameError]
    E --> H[インスタンス変数設定]
    H --> I[_owner, _recv, _name, _proc, _klass]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-64-01 | バインドチェック | UnboundMethod#bindは、元のクラスと互換性のあるオブジェクトにのみバインド可能 | bind/bind_call時 |
| BR-64-02 | シングルトンメソッド制約 | singleton_methodはシングルトンクラスのメソッドのみ取得可能 | singleton_method呼び出し時 |
| BR-64-03 | method_missing対応 | メソッドが見つからない場合、respond_to_missing?で確認 | method()呼び出し時 |
| BR-64-04 | new/allocate不可 | Method/UnboundMethodクラスのnew/allocateは使用不可 | クラスメソッド呼び出し時 |

### 計算ロジック

メソッドオブジェクトは5つのインスタンス変数（_owner, _recv, _name, _proc, _klass）で状態を管理する。

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | NameError | 未定義のメソッド名 | メソッド名を確認 |
| - | TypeError | bind時のクラス不一致 | 互換性のあるオブジェクトを使用 |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

ROMテーブルベースのメソッド登録で初期化コスト削減。

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

Method#callは元のメソッドの可視性を無視して呼び出しを行う。

## 備考

mruby-proc-extに依存（arity、source_location、parameters）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | method.c | `mrbgems/mruby-method/src/method.c` | Methodオブジェクトの5インスタンス変数による状態管理 |

**読解のコツ**:
- Methodオブジェクトは通常のRObject（MRB_TT_OBJECT）として割り当てられ、_owner/_recv/_name/_proc/_klassの5つのインスタンス変数で管理される
- **102-106行目**: method_object_alloc() - MRB_OBJ_ALLOCでRObjectを割り当て
- **108-119行目**: method_extract_proc() - _procインスタンス変数からRProcを取得

#### Step 2: メソッド探索を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | method.c | `mrbgems/mruby-method/src/method.c` | search_method_owner()とmethod_alloc() |

**主要処理フロー**:
- **628-647行目**: search_method_owner() - メソッドテーブル走査、respond_to_missing?対応
- **656-683行目**: method_alloc() - Method/UnboundMethodオブジェクトの生成とインスタンス変数設定

#### Step 3: メソッド呼び出しを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | method.c | `mrbgems/mruby-method/src/method.c` | mcall()によるメソッド実行 |

**主要処理フロー**:
- **273-294行目**: mcall() - procとmidの設定、mrb_exec_irep()による実行
- **309-313行目**: method_call() - Method#callのエントリーポイント
- **338-344行目**: method_bcall() - UnboundMethod#bind_call

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

```
Kernel#method(sym) / Module#instance_method(sym)
    |
    +-- method_alloc()
    |       +-- search_method_owner()
    |       |       +-- method_search_vm()
    |       |       +-- respond_to_missing? [fallback]
    |       +-- method_object_alloc()
    |       +-- mrb_obj_iv_set() x5  ... インスタンス変数設定
    |
Method#call / Method#[]
    |
    +-- mcall()
            +-- method_extract_proc/mid/owner/receiver()
            +-- mrb_exec_irep()  ... VM実行
```

### データフロー図

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

obj + :method_name  ──▶ method_alloc()          ──▶ Method/UnboundMethod
                          |
Method + args       ──▶ mcall()                 ──▶ メソッド戻り値
                          +-- mrb_exec_irep()

UnboundMethod + obj ──▶ unbound_method_bind()   ──▶ Method
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| method.c | `mrbgems/mruby-method/src/method.c` | ソース | Method/UnboundMethodクラス全実装（891行） |
| method.rb | `mrbgems/mruby-method/mrblib/method.rb` | Ruby実装 | Ruby側のヘルパーメソッド |
| mrbgem.rake | `mrbgems/mruby-method/mrbgem.rake` | 設定 | gem仕様定義 |
| method.rb | `mrbgems/mruby-method/test/method.rb` | テスト | テストケース |
