# 機能設計書 55-Structクラス

## 概要

本ドキュメントは、mrubyにおけるStructクラスの設計を記述する。Structクラスは名前付きフィールドを持つデータ構造体クラスを動的に生成する機能を提供し、簡易的なデータ保持オブジェクトの定義を可能にする。

### 本機能の処理概要

Struct.newで名前付きフィールドを指定して新しいクラスを動的に生成し、各フィールドへのアクセサメソッド（getter/setter）を自動定義する。生成されたクラスのインスタンスは配列ベース（MRB_TT_STRUCT）で値を保持する。

**業務上の目的・背景**：複数の関連するデータを1つのオブジェクトにまとめたい場合に、クラス定義を明示的に書くことなく簡易的にデータ構造を定義できる。設定値の集合、APIレスポンスの構造化、座標データなど、軽量なデータ保持が必要な場面で使用される。

**機能の利用シーン**：設定データの構造化、複数の戻り値の構造化、軽量なデータオブジェクトの定義、CSVデータの行表現など。

**主要な処理内容**：
1. Struct.new(name, :field1, :field2, ...)で新しいStructサブクラスを生成
2. 各フィールドに対応するgetter/setterメソッドを自動定義
3. membersメソッドでフィールド名一覧を取得
4. each/each_pair/selectでイテレーション
5. to_s/inspectで文字列表現を取得
6. []/ []=で添え字またはシンボルでフィールドにアクセス

**関連システム・外部連携**：Arrayクラス（内部実装がMRB_TT_STRUCT = 配列ベース）、Enumerableモジュール（includeされている）。

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

## 関連画面

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

## 機能種別

データ構造体生成

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | String | No | クラス名（省略可） | 定数名として有効な文字列 |
| members | Symbol可変長 | Yes | フィールド名のリスト | シンボルまたはシンボルに変換可能なオブジェクト |
| block | Block | No | クラス定義ブロック | - |

### 入力データソース

Rubyプログラムからの直接呼び出し。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 生成されたクラス | Class | Structのサブクラス |
| インスタンス | Struct | 生成されたクラスのインスタンス |

### 出力先

呼び出し元のRubyプログラムへの戻り値。

## 処理フロー

### 処理シーケンス

```
1. Struct.new(:field1, :field2, ...) の呼び出し
   └─ 引数をシンボルに変換し、重複チェック
2. 新しいクラスを生成
   └─ mrb_class_newでStructのサブクラスを作成
   └─ MRB_TT_STRUCTをインスタンスタイプに設定
3. アクセサメソッドの自動定義
   └─ 各フィールドに対してgetter（mrb_struct_ref）とsetter（mrb_struct_set_m）を定義
4. __members__インスタンス変数にメンバー一覧を保存
5. ブロックが渡された場合、ブロック内でクラス定義を追加
```

### フローチャート

```mermaid
flowchart TD
    A[Struct.new 呼び出し] --> B{名前付き?}
    B -->|Yes| C[定数名でクラス定義]
    B -->|No| D[無名クラスとして生成]
    C --> E[mrb_class_new]
    D --> E
    E --> F[MRB_SET_INSTANCE_TT MRB_TT_STRUCT]
    F --> G[make_struct_define_accessors]
    G --> H[各フィールドにgetter/setter定義]
    H --> I[__members__にメンバー一覧保存]
    I --> J{ブロックあり?}
    J -->|Yes| K[ブロック実行でクラス定義追加]
    J -->|No| L[クラスを返却]
    K --> L
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-55-01 | メンバー重複禁止 | 同じ名前のフィールドを重複定義できない | Struct.new呼び出し時 |
| BR-55-02 | 定数名チェック | 名前付きStructの場合、名前は定数として有効でなければならない | 名前付き定義時 |
| BR-55-03 | Enumerable包含 | 生成されたStructクラスはEnumerableをincludeする | 常時 |
| BR-55-04 | アクセサ自動定義 | 各フィールドに対しgetterとsetter（field=）が自動定義される | Struct生成時 |

### 計算ロジック

特になし。

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | TypeError | 構造体が破損している場合 | 正常なStructオブジェクトを使用 |
| - | NameError | 定数名として不正な名前を指定 | 有効な定数名を使用 |
| - | ArgumentError | メンバーが重複している | 一意なメンバー名を使用 |
| - | ArgumentError | 引数の数がメンバー数と不一致 | 正しい数の引数を提供 |

### リトライ仕様

リトライ不要。

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

該当なし。

## パフォーマンス要件

- アクセサメソッドはmrb_proc_new_cfunc_with_envで生成され、通常のCメソッドと同等の速度
- フィールドアクセスは配列インデックスアクセス（O(1)）

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

特になし。

## 備考

- Struct内部はMRB_TT_STRUCT型で、RSTRUCTマクロ（実質RARRAY）でアクセスする
- mrblibのstruct.rbでeach, each_pair, select, dig等のRubyメソッドが定義されている
- ISO 15.2.18準拠の実装

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | struct.c | `mrbgems/mruby-struct/src/struct.c` | RSTRUCT_LEN/RSTRUCT_PTRマクロ（RARRAY_LEN/PTRのエイリアス）（19-20行目） |
| 1-2 | struct.c | `mrbgems/mruby-struct/src/struct.c` | struct_s_members(): __members__インスタンス変数からメンバー一覧取得（37-55行目） |

**読解のコツ**: StructのインスタンスはMRB_TT_STRUCT型だが、内部的にはRArray構造体と同じレイアウトを使用する。RSTRUCT_PTR(st)で配列の先頭ポインタを、RSTRUCT_LEN(st)で要素数を取得できる。

#### Step 2: クラス生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | struct.c | `mrbgems/mruby-struct/src/struct.c` | make_struct(): 新しいStructサブクラスの生成（184-200行目） |
| 2-2 | struct.c | `mrbgems/mruby-struct/src/struct.c` | make_struct_define_accessors(): getter/setter自動定義（163-182行目） |

**主要処理フロー**:
- **174行目**: mrb_proc_new_cfunc_with_envでgetter（mrb_struct_ref）を生成
- **175行目**: mrb_proc_new_cfunc_with_envでsetter（mrb_struct_set_m）を生成
- **177-179行目**: getter/setterをメソッドとして登録

#### Step 3: フィールドアクセスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | struct.c | `mrbgems/mruby-struct/src/struct.c` | mrb_struct_ref(): フィールド読み取り（111-124行目） |
| 3-2 | struct.c | `mrbgems/mruby-struct/src/struct.c` | mrb_struct_set_m(): フィールド書き込み（153-161行目） |

#### Step 4: Rubyレベルのメソッドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | struct.rb | `mrbgems/mruby-struct/mrblib/struct.rb` | each/each_pair/selectメソッドの定義（13-46行目） |
| 4-2 | struct.rb | `mrbgems/mruby-struct/mrblib/struct.rb` | digメソッドの定義（61-68行目） |

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

```
Struct.new(:field1, :field2, ...)
    |
    +-- make_struct()
    |    +-- mrb_class_new() [サブクラス生成]
    |    +-- MRB_SET_INSTANCE_TT(MRB_TT_STRUCT)
    |    +-- make_struct_define_accessors()
    |    |    +-- mrb_struct_ref [getter]
    |    |    +-- mrb_struct_set_m [setter]
    |    +-- mrb_id_attrset() [setter名(field=)生成]
    |
    +-- StructClass.new(val1, val2, ...)
         +-- mrb_ary_resize() [配列サイズ確保]
         +-- mrb_ary_set() [値設定]
```

### データフロー図

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

:field1, :field2, ...  ──> Struct.new()  ──────────────> Class (Structサブクラス)
                            |                              |
                            +-- アクセサ自動定義           +-- getter/setter
                            +-- __members__設定            +-- members配列

val1, val2, ...  ──────> StructClass.new() ────────────> Struct instance
                            |                              |
                            +-- 配列に値格納              +-- [val1, val2, ...]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| struct.c | `mrbgems/mruby-struct/src/struct.c` | ソース | Structクラスの主要C実装 |
| struct.rb | `mrbgems/mruby-struct/mrblib/struct.rb` | ソース | each/each_pair/select/digのRuby実装 |
| struct.rb | `mrbgems/mruby-struct/test/struct.rb` | テスト | Structクラスの動作テスト |
| mrbgem.rake | `mrbgems/mruby-struct/mrbgem.rake` | 設定 | gemメタデータ定義 |
