# 機能設計書 67-Proc#binding

## 概要

本ドキュメントは、mrubyにおけるProc#bindingメソッドの設計を記述する。mruby-proc-binding gemとして実装され、Procオブジェクトが定義されたコンテキストのBindingオブジェクトを取得する機能を提供する。

### 本機能の処理概要

Proc#bindingは、Procオブジェクト（ブロック、ラムダ）が定義された時点の実行コンテキスト（ローカル変数、self等）をBindingオブジェクトとして返すメソッドである。返されたBindingオブジェクトを使用して、Procが定義されたスコープのローカル変数を操作したり、eval()でそのコンテキストでコードを評価したりできる。

**業務上の目的・背景**：Procオブジェクトが保持するクロージャ環境を明示的にBindingとして取得することで、テンプレートエンジンやDSL実装において、特定のコンテキストでの式評価が可能になる。

**機能の利用シーン**：テンプレートエンジンでProcの定義元スコープの変数にアクセスする場合、デバッガでProcのクロージャ環境を調査する場合、DSL実装でProcの定義元コンテキストを操作する場合等で使用される。

**主要な処理内容**：
1. Procオブジェクトからupper proc（定義元のproc）を取得
2. Procオブジェクトの環境（REnv）を取得
3. mrb_binding_new()でBindingオブジェクトを生成
4. source_locationをProcのソース位置情報からコピー

**関連システム・外部連携**：mruby-binding（Bindingオブジェクトの生成）、mruby-proc-ext（source_location取得）に依存。

**権限による制御**：特になし。Proc#bindingは公開メソッド。

## 関連画面

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

## 機能種別

リフレクション / コンテキスト管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| （なし） | - | - | 引数なし（MRB_ARGS_NONE） | - |

### 入力データソース

mrubyスクリプトからの直接呼び出し（Procオブジェクトのメソッド）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Binding | Binding | Procが定義されたコンテキストのBindingオブジェクト |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. Procオブジェクトからproc構造体を取得
   └─ mrb_proc_ptr(procval)
2. procの有効性チェック
   └─ C関数procまたはupper無しの場合はNULL
3. 有効な場合：環境とレシーバの取得
   a. env = MRB_PROC_ENV(proc)
   b. proc = proc->upper（定義元のprocに移動）
   c. receiver = env->stack[0]
4. mrb_binding_new()でBindingオブジェクト生成
5. source_locationをProcから取得してBindingに設定
6. Bindingオブジェクトを返却
```

### フローチャート

```mermaid
flowchart TD
    A[Proc#binding] --> B{C関数proc?}
    B -->|Yes| C[proc=NULL, env=NULL]
    B -->|No| D{upper存在?}
    D -->|No| C
    D -->|Yes| E[env = MRB_PROC_ENV]
    E --> F[proc = proc->upper]
    F --> G[receiver = env->stack 0]
    C --> H[mrb_binding_new]
    G --> H
    H --> I[source_location設定]
    I --> J[Binding返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-67-01 | C関数procの処理 | C関数のProcからはproc=NULL、env=NULL、receiver=nilのBindingを返す | MRB_PROC_CFUNC_Pがtrue |
| BR-67-02 | upper proc参照 | BindingのprocはProcのupperを参照する（Proc自体のスコープではなく定義元スコープ） | Ruby関数proc時 |
| BR-67-03 | レシーバ取得 | レシーバはenvのstack[0]から取得（envにスタックがある場合） | env有効時 |
| BR-67-04 | source_location | Procのsource_locationをBindingにコピー | 常時 |

### 計算ロジック

Procの環境チェーンを1段遡ってupper procを取得することで、Procが定義されたスコープのローカル変数空間を正しく参照する。

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | （エラーなし） | C関数procの場合はNULLのBindingを返すが例外は発生しない | - |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

77行の小規模実装であり、処理は軽量。mrb_binding_new()の内部でlvspace生成が行われるが、個別のProc#binding呼び出しのコストは低い。

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

Proc#bindingはProcが定義されたスコープの全ローカル変数へのアクセスを提供するため、信頼できないコードにProcオブジェクトを渡す場合は注意が必要。

## 備考

- mruby-bindingとmruby-proc-extの両方に依存する
- gem初期化でProc.class（mrb->proc_class）にbindingメソッドを追加

---

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

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

### 推奨読解順序

#### Step 1: 外部依存関係を確認する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | proc_binding.c | `mrbgems/mruby-proc-binding/src/proc_binding.c` | 外部関数の宣言 |

**読解のコツ**:
- **7行目**: mrb_proc_source_location() - mruby-proc-extが提供するソース位置取得関数
- **10行目**: mrb_binding_new() - mruby-bindingが提供するBinding生成関数
- これらの外部関数の存在を前提として本機能が構築されている

#### Step 2: メイン処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | proc_binding.c | `mrbgems/mruby-proc-binding/src/proc_binding.c` | mrb_proc_binding()の処理フロー |

**主要処理フロー**:
- **35-57行目**: mrb_proc_binding() - Proc#bindingのC実装
- **38行目**: mrb_proc_ptr(procval) - Procオブジェクトからstruct RProc*を取得
- **42-46行目**: C関数procまたはupper無しの場合のフォールバック（proc=NULL、env=NULL）
- **48-52行目**: 有効なprocの場合のenv/proc/receiver取得
- **54行目**: mrb_binding_new()でBindingオブジェクト生成
- **55行目**: source_locationをProcから取得してBindingのインスタンス変数に設定

#### Step 3: gem初期化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | proc_binding.c | `mrbgems/mruby-proc-binding/src/proc_binding.c` | gem初期化関数 |

**主要処理フロー**:
- **67-71行目**: mrb_mruby_proc_binding_gem_init() - Procクラスにbindingメソッドを追加
- **70行目**: mrb_define_method_id()でProc#bindingを登録（MRB_ARGS_NONE）

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

```
Proc#binding
    |
    +-- mrb_proc_binding()
            +-- mrb_proc_ptr()            ... Procからstruct RProc*取得
            +-- MRB_PROC_CFUNC_P()        ... C関数判定
            +-- MRB_PROC_ENV()            ... 環境(REnv)取得
            +-- mrb_binding_new()         ... Binding生成（mruby-binding提供）
            |       +-- binding_wrap_lvspace()
            |       +-- mrb_obj_iv_set() x3
            +-- mrb_proc_source_location() ... ソース位置取得（mruby-proc-ext提供）
            +-- mrb_iv_set()              ... source_locationをBindingに設定
```

### データフロー図

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

Proc (RProc)         ──▶ mrb_proc_binding()          ──▶ Binding (proc/recv/env)
                            |
                            +-- proc->upper取得
                            +-- MRB_PROC_ENV取得
                            +-- env->stack[0]→receiver
                            |
                            +-- mrb_binding_new()
                            +-- source_location設定
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| proc_binding.c | `mrbgems/mruby-proc-binding/src/proc_binding.c` | ソース | Proc#binding全実装（77行） |
| mrbgem.rake | `mrbgems/mruby-proc-binding/mrbgem.rake` | 設定 | gem仕様定義 |
| binding.c | `mrbgems/mruby-binding/src/binding.c` | 依存ソース | mrb_binding_new()提供 |
