# 機能設計書 33-Enumerable拡張

## 概要

本ドキュメントは、mrubyのEnumerableモジュールにtally, filter_map, drop, take, each_cons, each_slice, group_by, sort_by, flat_map, max_by, min_by, minmax, minmax_by, none?, one?, all?, any?, each_with_object, reverse_each, cycle, find_index, zip, to_h, uniq, count, first, sum, grep_v, filter, each_entry等の拡張メソッドを追加するgem（mruby-enum-ext）の機能設計を記述する。

### 本機能の処理概要

**業務上の目的・背景**：CRuby互換のEnumerableメソッド群を提供し、コレクション操作の表現力を大幅に向上させる。ISO標準では定義されていない高度なイテレーション・集約・変換操作を利用可能にする。

**機能の利用シーン**：データの集約・分類（tally, group_by）、フィルタリング（filter_map, grep_v）、スライシング（each_cons, each_slice, take, drop）、検索（find_index, first）、ソート（sort_by, max_by, min_by）、変換（flat_map, to_h, zip）等。

**主要な処理内容**：
1. 集約系: tally（頻度カウント）, sum（合計）, count（カウント）, minmax（最小最大）
2. フィルタ系: filter_map（変換+フィルタ）, none?/one?/all?/any?（条件判定）, grep_v（逆grep）, uniq（重複除去）
3. スライス系: drop/drop_while, take/take_while, each_cons, each_slice, first
4. ソート系: sort_by, max_by, min_by, minmax_by
5. 変換系: flat_map/collect_concat, to_h, zip, group_by
6. イテレーション系: each_with_object, reverse_each, cycle, find_index, each_entry

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

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

## 関連画面

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

## 機能種別

コレクション操作 / イテレーション処理

## 入力仕様

### 入力パラメータ

各メソッドの引数はCRuby互換。主要なパターン:

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| n | Integer | Yes(一部) | 要素数（take, drop, each_cons, each_slice等） | 正の整数 |
| block | Block | No | 各要素に適用するブロック | ブロック未指定時はEnumerator返却 |
| pat | Object | No | パターン（all?, any?, none?, one?） | ===演算子対応 |
| init | Numeric | No | 初期値（sum） | デフォルト0 |

### 入力データソース

メソッド呼び出し時の引数およびself（Enumerableをincludeするオブジェクト）。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Array | Array | 変換・フィルタ結果（多くのメソッド） |
| Hash | Hash | group_by, tally, to_hの結果 |
| Object | Object | max_by, min_by, firstの結果 |
| Boolean | true/false | none?, one?, all?, any?の結果 |
| Integer | Integer | count, find_index, sumの結果 |
| Array | [min, max] | minmax, minmax_byの結果 |

### 出力先

メソッドの戻り値。

## 処理フロー

### 処理シーケンス

```
各メソッドはself.eachを呼び出してイテレーションし、
ブロックの戻り値に基づいて結果を構築する共通パターンを持つ。

1. ブロック有無の判定
   └─ ブロックなしの場合、to_enum(:メソッド名, 引数)でEnumeratorを返す
2. self.eachによるイテレーション
   └─ 各要素に対してブロックを適用
3. 結果の構築と返却
```

### フローチャート

```mermaid
flowchart TD
    A[メソッド呼び出し] --> B{ブロックあり?}
    B -->|No| C[to_enum返却]
    B -->|Yes| D[self.each開始]
    D --> E[各要素にブロック適用]
    E --> F[結果蓄積]
    F --> G{全要素処理済み?}
    G -->|No| E
    G -->|Yes| H[結果返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | ブロック未指定時Enumerator | ブロックが指定されない場合はEnumeratorを返す | ほぼ全メソッド |
| BR-02 | 負数サイズ禁止 | take/dropにおいて負の引数はArgumentError | take, drop呼び出し時 |
| BR-03 | パターンマッチング | pat引数が指定された場合は`===`演算子で判定 | all?, any?, none?, one? |
| BR-04 | __svalue変換 | 複数値yieldの場合は__svalueで単一値に変換 | each内部での要素取得時 |

### 計算ロジック

- **tally**: `hash[x] = (hash[x]||0)+1` で頻度カウント
- **sum**: `result += block.call(*e)` または `result += e.__svalue` で累積加算
- **count**: 条件に合致する要素数を加算

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ArgumentError | take/dropに負数指定 | "attempt to take/drop negative size" |
| - | ArgumentError | each_cons/each_sliceに0以下指定 | "invalid size" / "invalid slice size" |
| - | ArgumentError | firstに負数指定 | "attempt to take negative size" |
| - | TypeError | zipの引数がto_a不可 | "wrong argument type X (must respond to :to_a)" |
| - | TypeError | to_hの要素がArrayでない | "wrong element type X (expected Array)" |
| - | ArgumentError | to_hの要素が2要素でない | "element has wrong array length" |

### リトライ仕様

なし。

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

なし。

## パフォーマンス要件

各メソッドはO(n)（nはコレクション要素数）。sort_byはO(n log n)。

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

なし。

## 備考

- 全メソッドが純Rubyで実装されている
- Array#sort_byはeach_with_indexを使った最適化実装を持つ（enum.rb 921-937行目）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | enum.rb | `mrbgems/mruby-enum-ext/mrblib/enum.rb` | Enumerableモジュールの構造全体 |

**読解のコツ**: `__svalue`はmruby内部メソッドで、`yield *val`で複数値が渡された場合の値を単一値に変換する。`NONE`は引数未指定の検出用センチネル。

#### Step 2: 主要メソッド群を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | enum.rb | `mrbgems/mruby-enum-ext/mrblib/enum.rb` | 各メソッドの実装パターン |

**主要処理フロー**:
- **15-22行目**: drop - n個スキップして残りを返す
- **38-47行目**: drop_while - 条件falseまでスキップ
- **58-70行目**: take - 先頭n個を取得
- **114-127行目**: each_cons - n個の連続スライスでイテレーション
- **142-158行目**: each_slice - n個ずつスライスでイテレーション
- **171-181行目**: group_by - ブロック結果でグルーピング
- **192-195行目**: sort_by - ブロック結果でソート
- **270-283行目**: flat_map - マッピング+フラット化
- **298-318行目**: max_by - ブロック結果が最大の要素
- **455-470行目**: none? - パターン/ブロック/値での判定
- **819-828行目**: filter_map - フィルタ+マップ一体化
- **852-859行目**: tally - 頻度カウント
- **871-883行目**: sum - 合計計算

#### Step 3: Array最適化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | enum.rb | `mrbgems/mruby-enum-ext/mrblib/enum.rb` | 921-938行目 Array#sort_by最適化 |

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

```
Enumerable#メソッド
    |
    +-- self.each {|*val| ... }
    |       +-- val.__svalue  (複数値->単一値変換)
    |       +-- block.call(*val)  (ユーザブロック呼び出し)
    |
    +-- to_enum(:メソッド名, 引数)  (ブロック未指定時)
```

### データフロー図

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

Enumerableオブジェクト ──▶ self.each ──▶ ブロック適用 ──▶ Array/Hash/Object
(self)                       イテレーション    結果蓄積         結果返却
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| enum.rb | `mrbgems/mruby-enum-ext/mrblib/enum.rb` | ソース(Ruby) | 全拡張メソッドの実装 |
| mrbgem.rake | `mrbgems/mruby-enum-ext/mrbgem.rake` | 設定 | gem定義 |
| enum.rb | `mrbgems/mruby-enum-ext/test/enum.rb` | テスト | テストケース |
