# 機能設計書 41-Object拡張

## 概要

本ドキュメントは、mruby-object-ext gemが提供するObjectクラスおよび関連クラスへの拡張メソッド群の機能設計を記述する。NilClassへの型変換メソッド、Kernelモジュールへのユーティリティメソッド、BasicObjectへのinstance_execメソッドを追加する。

### 本機能の処理概要

mruby-object-ext gemは、Ruby標準のObjectクラスに存在する便利なメソッドのうち、mrubyコアには含まれていないものを拡張gemとして提供する。C言語(src/object.c)とRuby(mrblib/object.rb)の両方で実装されている。

**業務上の目的・背景**：mrubyはコンパクトな組み込み向けRuby実装であり、コアには最小限のメソッドのみを含む。しかし、tap, then, yield_self, itself, instance_execなどのメソッドはRubyプログラミングにおいて頻繁に使用されるため、拡張gemとして提供する必要がある。また、NilClassへの型変換メソッド(to_a, to_f, to_h, to_i)は、nilを安全にデフォルト値に変換するパターンで広く使われる。

**機能の利用シーン**：メソッドチェーンの途中でデバッグ出力を挿入する場合(tap)、値の変換パイプラインを構築する場合(then/yield_self)、nilの安全な型変換(nil.to_a => [])、レシーバのコンテキストでブロックを実行する場合(instance_exec)に使用される。

**主要な処理内容**：
1. NilClass#to_a - nilを空配列[]に変換
2. NilClass#to_f - nilを0.0に変換（MRB_NO_FLOATが未定義の場合）
3. NilClass#to_h - nilを空ハッシュ{}に変換
4. NilClass#to_i - nilを0に変換
5. Kernel#itself - レシーバ自身を返す
6. Kernel#tap - selfをブロックに渡し、selfを返す
7. Kernel#yield_self / Kernel#then - selfをブロックに渡し、ブロックの戻り値を返す
8. BasicObject#instance_exec - レシーバのコンテキストでブロックを実行

**関連システム・外部連携**：なし。mrubyコアの組み込み型システムに依存する。

**権限による制御**：なし。全オブジェクトで利用可能。

## 関連画面

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

## 機能種別

ライブラリ拡張（ユーティリティメソッド群の追加）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| block (tap) | Block | Yes | selfを受け取るブロック | ブロックが必須（yield self） |
| block (yield_self) | Block | No | selfを受け取るブロック | ブロックなしの場合はEnumeratorを返す |
| args (instance_exec) | Any | No | ブロックに渡す引数 | 任意の数の引数 |
| block (instance_exec) | Block | Yes | レシーバのコンテキストで実行するブロック | ブロックが必須 |

### 入力データソース

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

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| nil.to_a戻り値 | Array | 空配列 [] |
| nil.to_f戻り値 | Float | 0.0 |
| nil.to_h戻り値 | Hash | 空ハッシュ {} |
| nil.to_i戻り値 | Integer | 0 |
| itself戻り値 | Object | レシーバ自身 |
| tap戻り値 | Object | レシーバ自身 |
| yield_self戻り値 | Object | ブロックの戻り値 |
| instance_exec戻り値 | Object | ブロックの戻り値 |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. gem初期化 (mrb_mruby_object_ext_gem_init)
   └─ NilClassにto_a, to_h, to_i, to_fをROMテーブルで登録
   └─ KernelモジュールにitselfメソッドをC関数で登録
   └─ BasicObjectにinstance_execをROMテーブルで登録

2. tap呼び出し (Ruby実装)
   └─ yield self でブロックにselfを渡す
   └─ selfを返す

3. yield_self/then呼び出し (Ruby実装)
   └─ ブロックなしの場合: to_enum(:yield_self)でEnumeratorを返す
   └─ ブロックありの場合: block.call(self)でブロックの戻り値を返す

4. instance_exec呼び出し (C実装)
   └─ mrb_singleton_class_ptrでシングルトンクラスを取得
   └─ mrb_object_execでレシーバのコンテキストでブロックを実行
```

### フローチャート

```mermaid
flowchart TD
    A[gem初期化] --> B[NilClass拡張メソッド登録]
    A --> C[Kernel#itself登録]
    A --> D[BasicObject#instance_exec登録]

    E[tap呼び出し] --> F[yield self]
    F --> G[selfを返す]

    H[yield_self呼び出し] --> I{ブロックあり?}
    I -->|Yes| J[block.call self]
    I -->|No| K[to_enum :yield_self]

    L[instance_exec呼び出し] --> M[シングルトンクラス取得]
    M --> N[mrb_object_exec実行]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-41-01 | tap不変則 | tapはブロックの戻り値を無視し、常にselfを返す | tap呼び出し時 |
| BR-41-02 | yield_self遅延 | ブロックなしの場合はEnumeratorを返す | yield_selfがブロックなしで呼び出された場合 |
| BR-41-03 | nil安全変換 | nilの型変換はデフォルト値（空値または0）を返す | NilClassの型変換メソッド呼び出し時 |
| BR-41-04 | instance_execコンテキスト | ブロック内のselfはレシーバに変更される | instance_exec呼び出し時 |

### 計算ロジック

特になし

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

### 操作別データベース影響一覧

該当なし（データベース操作は行わない）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | LocalJumpError | tapでブロックが渡されない場合 | ブロックを必ず渡す |
| - | TypeError | instance_execでブロックが渡されない場合 | ブロックを必ず渡す |

### リトライ仕様

リトライは不要

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

該当なし

## パフォーマンス要件

各メソッドはO(1)の時間計算量で動作する。tap, yield_selfはブロック呼び出しのオーバーヘッドのみ。

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

instance_execはレシーバのプライベートメソッドやインスタンス変数にアクセス可能なため、信頼されないコードでの使用に注意が必要。

## 備考

- MRB_NO_FLOATマクロが定義されている場合、nil.to_fは利用不可
- thenはyield_selfのエイリアス
- itselfメソッドはC実装(mrb_obj_itself)だが、コア側で定義されており、このgemでは登録のみ行う

---

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

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

### 推奨読解順序

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

mruby-object-ext gemは独自のデータ構造を持たない。mrubyコアのmrb_value、struct RClassなどの既存データ構造を使用する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | mrbgem.rake | `mrbgems/mruby-object-ext/mrbgem.rake` | gem定義。依存関係なし |

**読解のコツ**: MRB_MT_ENTRYマクロはROMテーブル（読み取り専用メソッドテーブル）にメソッドを登録するためのマクロ。MRB_MT_INIT_ROMでクラスに一括登録する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | object.c | `mrbgems/mruby-object-ext/src/object.c` | gem初期化関数とC実装メソッド |

**主要処理フロー**:
1. **113-123行目**: `mrb_mruby_object_ext_gem_init` - gem初期化。NilClass・Kernel・BasicObjectへのメソッド登録
2. **100-107行目**: `nil_ext_rom_entries` - NilClassのROMテーブルエントリ定義
3. **109-111行目**: `bob_ext_rom_entries` - BasicObjectのROMテーブルエントリ定義

#### Step 3: NilClass拡張メソッドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | object.c | `mrbgems/mruby-object-ext/src/object.c` | NilClassへの型変換メソッド群 |

**主要処理フロー**:
- **16-20行目**: `nil_to_a` - mrb_ary_new()で空配列を返す
- **30-34行目**: `nil_to_f` - mrb_float_value(mrb, 0.0)で0.0を返す
- **44-48行目**: `nil_to_h` - mrb_hash_new()で空ハッシュを返す
- **57-61行目**: `nil_to_i` - mrb_fixnum_value(0)で0を返す

#### Step 4: Kernel/BasicObject拡張メソッドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | object.c | `mrbgems/mruby-object-ext/src/object.c` | instance_execのC実装 |
| 4-2 | object.rb | `mrbgems/mruby-object-ext/mrblib/object.rb` | tap, yield_self/thenのRuby実装 |

**主要処理フロー**:
- **94-98行目**: `obj_instance_exec` - シングルトンクラスを取得してmrb_object_execを呼び出す
- **120行目**: `mrb_obj_itself`をKernel#itselfとして登録
- **mrblib/object.rb 10-13行目**: `yield_self` - ブロックなしならto_enum、ありならblock.call(self)
- **mrblib/object.rb 29-32行目**: `tap` - yield selfしてselfを返す

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

```
mrb_mruby_object_ext_gem_init
    |
    +-- MRB_MT_INIT_ROM(NilClass)
    |       +-- nil_to_a -> mrb_ary_new
    |       +-- nil_to_h -> mrb_hash_new
    |       +-- nil_to_i -> mrb_fixnum_value
    |       +-- nil_to_f -> mrb_float_value
    |
    +-- mrb_define_method_id(Kernel, itself)
    |       +-- mrb_obj_itself（コア定義）
    |
    +-- MRB_MT_INIT_ROM(BasicObject)
            +-- obj_instance_exec
                    +-- mrb_singleton_class_ptr
                    +-- mrb_object_exec
```

### データフロー図

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

nil              --> nil_to_a()              --> []
nil              --> nil_to_f()              --> 0.0
nil              --> nil_to_h()              --> {}
nil              --> nil_to_i()              --> 0
obj              --> itself()                --> obj
obj + block      --> tap { block }           --> obj
obj + block      --> yield_self { block }    --> block.call(obj)
obj + args + blk --> instance_exec(args,blk) --> blk結果
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| object.c | `mrbgems/mruby-object-ext/src/object.c` | ソース | NilClass拡張、instance_exec、itselfのC実装 |
| object.rb | `mrbgems/mruby-object-ext/mrblib/object.rb` | ソース | tap、yield_self/thenのRuby実装 |
| mrbgem.rake | `mrbgems/mruby-object-ext/mrbgem.rake` | 設定 | gem定義ファイル |
| object.rb | `mrbgems/mruby-object-ext/test/object.rb` | テスト | instance_exec、tapのテスト |
| nil.rb | `mrbgems/mruby-object-ext/test/nil.rb` | テスト | NilClass拡張メソッドのテスト |
| object_ext.c | `mrbgems/mruby-object-ext/test/object_ext.c` | テスト | C APIテスト用ヘルパー |
