# 機能設計書 37-Hash拡張

## 概要

本ドキュメントは、mrubyのHashクラスにvalues_at, slice, slice!, except, key, merge!, Hash[], invert, flatten, transform_keys, transform_values, fetch, delete_if, keep_if, dig, fetch_values, compact, to_proc等の拡張メソッドを追加するgem（mruby-hash-ext）の機能設計を記述する。

### 本機能の処理概要

**業務上の目的・背景**：CRuby互換のHash操作メソッドを提供し、ハッシュテーブル操作の表現力を向上させる。キー/値の抽出・変換（slice, except, transform_keys, transform_values）、複数ハッシュのマージ（merge!）、比較演算（<, <=, >, >=）等を利用可能にする。

**機能の利用シーン**：APIレスポンスからの特定キー抽出（slice, except）、ハッシュの結合（merge!）、キー/値の一括変換（transform_keys/transform_values）、デフォルト値付き取得（fetch）、nil値除去（compact）、ネスト値取得（dig）等。

**主要な処理内容**：
1. 抽出系: values_at, slice, except, fetch, fetch_values
2. 変換系: invert, transform_keys/transform_keys!, transform_values/transform_values!, flatten, to_proc
3. 結合系: merge!/update, Hash[]（クラスメソッド）
4. 検索系: key（値からキーを逆引き）, dig（ネストアクセス）
5. フィルタ系: delete_if, keep_if, select!/filter!, compact/compact!
6. 変更系: slice!（指定キー以外を削除）
7. 比較系: <, <=, >, >=（部分集合判定）
8. その他: each_pair（eachのエイリアス）, to_h

**関連システム・外部連携**：なし。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面なし |

## 機能種別

コレクション操作 / データ変換処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| keys | Object | Yes(slice等) | 対象キー（可変長） | - |
| other_hash | Hash | Yes(merge!) | マージ元ハッシュ（複数指定可） | Hashであること |
| value | Object | Yes(key) | 検索対象値 | - |
| key | Object | Yes(fetch) | 取得対象キー | - |
| default | Object | No(fetch) | デフォルト値 | - |
| block | Block | No | キー/値変換用ブロック | - |

### 入力データソース

メソッド呼び出し時の引数。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Hash | Hash | slice, except, invert, transform_*等の結果 |
| Array | Array | values_at, fetch_values, flattenの結果 |
| Object | Object | fetch, key, digの結果 |
| Boolean | true/false | <, <=, >, >=の比較結果 |
| Proc | Proc | to_procの結果 |

### 出力先

メソッドの戻り値。

## 処理フロー

### 処理シーケンス

```
1. slice: 指定キーのみを含む新Hashを構築
2. except: 指定キーを除外した新Hashを構築
3. merge!: 複数Hashを順にマージ。ブロック指定時はキー競合をブロックで解決
4. key: mrb_hash_foreachでイテレーションし、値がマッチするキーを返す
5. Hash[]: キーペア配列/Hash/交互引数から新Hashを構築
```

### フローチャート

```mermaid
flowchart TD
    A[merge! 呼び出し] --> B{ブロックあり?}
    B -->|No| C[C実装 __merge で高速マージ]
    B -->|Yes| D[Ruby側でeach_keyイテレーション]
    D --> E{self.has_key? k}
    E -->|Yes| F[block.call k, self-k, other-k]
    E -->|No| G[self-k = other-k]
    C --> H[結果返却]
    F --> H
    G --> H
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | fetchのKeyError | キーが存在せずデフォルト値もブロックもない場合KeyError | fetch呼び出し時 |
| BR-02 | Hash[]の奇数引数エラー | キーペア形式で奇数個の引数はArgumentError | Hash[]呼び出し時 |
| BR-03 | merge!のブロック分岐 | ブロックなしはC実装の高速パス、ありはRuby実装 | merge!呼び出し時 |
| BR-04 | 比較演算のTypeError | Hash以外との比較はTypeError | <, <=, >, >= |
| BR-05 | compact!のnil返却 | nil値がなかった場合はnilを返す | compact! |

### 計算ロジック

- **部分集合判定**: `size < hash.size && all? {|k,v| hash.key?(k) && hash[k] == v}`
- **to_proc**: `->x{self[x]}` でHashをProcに変換

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | KeyError | fetchでキー不存在かつデフォルトなし | "Key not found: X" |
| - | ArgumentError | Hash[]で奇数個引数 | "odd number of arguments for Hash" |
| - | ArgumentError | Hash[]で無効な要素形式 | "wrong element type X (expected array)" |
| - | TypeError | merge!の引数が非Hash | "Hash required (X given)" |
| - | TypeError | 比較演算で非Hash引数 | "can't convert X to Hash" |

### リトライ仕様

なし。

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

なし。

## パフォーマンス要件

- slice/except: O(引数数)
- merge!: O(マージ元Hashの要素数合計)
- key: O(Hash要素数)（全走査）
- 比較演算: O(小さい方のHash要素数)

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

なし。

## 備考

- CとRubyのハイブリッド実装
- merge!はブロックなし時にC実装の__mergeに委譲して高速化
- slice_bang_iはmrb_hash_foreachのイテレータコールバックとして実装

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | hash_ext.c | `mrbgems/mruby-hash-ext/src/hash_ext.c` | slice_bang_i_arg, key_search構造体 |

**読解のコツ**: `mrb_hash_foreach`は内部イテレータで、コールバック関数が各エントリに対して呼ばれる。戻り値1でイテレーション停止。

#### Step 2: C実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | hash_ext.c | `mrbgems/mruby-hash-ext/src/hash_ext.c` | 各メソッドのC実装 |

**主要処理フロー**:
- **25-41行目**: hash_values_at - 複数キーの値取得
- **53-72行目**: hash_slice - キー抽出
- **114-140行目**: hash_slice_bang - 指定キー以外を削除
- **152-164行目**: hash_except - キー除外
- **185-265行目**: hash_s_create - Hash[]コンストラクタ
- **291-330行目**: hash_key - 値からキー逆引き
- **345-368行目**: hash_merge - C実装マージ（__merge）

#### Step 3: Ruby実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | hash.rb | `mrbgems/mruby-hash-ext/mrblib/hash.rb` | Ruby実装メソッド群 |

**主要処理フロー**:
- **28-40行目**: merge! - ブロック付きマージ
- **55-57行目**: compact! - nil値除去
- **103-115行目**: fetch - デフォルト値/ブロック付き取得
- **131-138行目**: delete_if - 条件削除
- **171-175行目**: invert - キーと値の反転
- **224-229行目**: < - 部分集合判定
- **299-306行目**: dig - ネストアクセス
- **318-326行目**: transform_keys - キー変換
- **354-361行目**: transform_values - 値変換
- **381-383行目**: to_proc - Proc変換

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

```
Hash#merge!
    |
    +-- [ブロックなし] __merge (C実装)
    |       +-- mrb_hash_merge (内部C関数)
    |
    +-- [ブロックあり] Ruby実装
            +-- other.each_key
            +-- block.call(k, self[k], other[k])

Hash[]
    +-- hash_s_create (C実装)
            +-- [Hash引数] mrb_hash_merge
            +-- [Array引数] mrb_ary_ref -> mrb_hash_set
            +-- [キーペア] mrb_hash_set

Hash#key
    +-- hash_key (C実装)
            +-- mrb_hash_foreach -> hash_key_i
```

### データフロー図

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

Hash (self)    ──────▶ C/Ruby処理関数 ──────▶ Hash / Array / Object
keys/other_hash         抽出/変換/マージ        結果
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| hash_ext.c | `mrbgems/mruby-hash-ext/src/hash_ext.c` | ソース(C) | C実装メソッド群 |
| hash.rb | `mrbgems/mruby-hash-ext/mrblib/hash.rb` | ソース(Ruby) | Ruby実装メソッド群 |
| mrbgem.rake | `mrbgems/mruby-hash-ext/mrbgem.rake` | 設定 | gem定義 |
| hash.rb | `mrbgems/mruby-hash-ext/test/hash.rb` | テスト | テストケース |
