# 機能設計書 31-capitalize_words

## 概要

本ドキュメントは、Hack Standard Library (HSL) の `Str\capitalize_words` 関数の機能設計について記載する。この関数は文字列内の各単語の最初の文字を大文字に変換する機能を提供する。

### 本機能の処理概要

`Str\capitalize_words` 関数は、指定された文字列内の各単語の最初の文字を大文字に変換するための関数である。単語の区切り文字（デリミタ）はデフォルトで空白文字（スペース、タブ、改行、キャリッジリターン、フォームフィード、垂直タブ）が使用されるが、カスタムデリミタを指定することも可能である。

**業務上の目的・背景**：テキスト処理において、タイトルケース（各単語の先頭を大文字にする形式）は頻繁に必要とされる。例えば、人名、書籍タイトル、見出しなどの表示フォーマットにおいて、各単語の先頭を大文字にする処理は一般的な要件である。この関数により、開発者は手動で文字列を分割・変換・結合する必要がなく、簡潔なコードでタイトルケース変換を実現できる。

**機能の利用シーン**：
- ユーザー名や氏名の正規化（"john doe" -> "John Doe"）
- 記事タイトルや見出しのフォーマット
- メニュー項目やラベルの表示整形
- データインポート時のテキスト正規化

**主要な処理内容**：
1. 入力文字列が空文字列の場合、そのまま空文字列を返す
2. デリミタが指定されていない場合、ロケール依存の単語境界でタイトルケース変換を実行
3. カスタムデリミタが指定された場合、デリミタで文字列を分割し各単語の先頭を大文字に変換
4. 変換後の単語をデリミタで再結合して返す

**関連システム・外部連携**：本関数は内部で `_Str\titlecase_l` 組み込み関数を使用し、ロケール対応のタイトルケース変換を実行する。また、カスタムデリミタ使用時は `Str\capitalize` 関数を内部的に呼び出す。

**権限による制御**：本機能は純粋関数であり、権限による制御は不要である。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 画面なし | - | 本プロジェクトはUIを持たないライブラリのため該当なし |

## 機能種別

計算処理 / 文字列変換

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| $string | string | Yes | 変換対象の文字列 | なし |
| $delimiters | ?string | No | 単語区切り文字（カスタムデリミタ） | null許容 |

### 入力データソース

関数呼び出し時の引数として直接指定される。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | string | 各単語の先頭が大文字に変換された文字列 |

### 出力先

関数の戻り値として呼び出し元に返却される。

## 処理フロー

### 処理シーケンス

```
1. 入力文字列のチェック
   └─ 空文字列の場合、空文字列を返して終了
2. デリミタの確認
   └─ nullの場合: ロケール依存のタイトルケース変換を実行
   └─ 指定ありの場合: カスタムデリミタ処理に進む
3. カスタムデリミタ処理
   └─ strcspnでデリミタ位置を検出しながら単語を分割
   └─ 各単語に対してStr\capitalize()を適用
   └─ 単語とデリミタを結合して結果文字列を構築
4. 結果を返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{入力が空文字列?}
    B -->|Yes| C[空文字列を返す]
    B -->|No| D{デリミタ指定?}
    D -->|null| E[titlecase_l関数で変換]
    D -->|指定あり| F[デリミタで単語分割]
    F --> G[各単語にcapitalizeを適用]
    G --> H[単語とデリミタを結合]
    E --> I[結果を返す]
    H --> I
    C --> J[終了]
    I --> J
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 空文字列処理 | 入力が空文字列の場合は空文字列を返す | $string === '' |
| BR-02 | デフォルトデリミタ | デリミタ未指定時はロケール定義のデリミタを使用 | $delimiters === null |
| BR-03 | 先頭文字のみ変換 | 各単語の最初の文字のみ大文字に変換 | 全ての単語に対して |
| BR-04 | 連続デリミタ対応 | 連続するデリミタ間の空単語も処理される | カスタムデリミタ使用時 |

### 計算ロジック

カスタムデリミタ指定時のアルゴリズム：
1. `strcspn` 関数でデリミタまでの文字数を計算
2. 取得した部分文字列を単語として、その後のデリミタ文字と共にタプルとして保存
3. 各単語に `Str\capitalize` を適用
4. 単語とデリミタを連結して最終結果を構築

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

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | - | 本関数は例外をスローしない | - |

### リトライ仕様

リトライ処理は不要（純粋関数のため）。

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

トランザクション管理は不要（データベース操作なし）。

## パフォーマンス要件

- 計算量: O(n) - nは入力文字列の長さ
- カスタムデリミタ使用時は単語数に応じたオーバーヘッドが発生
- 純粋関数属性 `[]:` により副作用なしが保証され、最適化の対象となる

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

- 入力文字列はそのまま処理されるため、エスケープ処理は呼び出し元の責任
- 純粋関数のため、副作用やセキュリティリスクはない

## 備考

- ロケール対応版として `Str\capitalize_words_l` 関数も提供されている
- 最初の文字のみを大文字にする場合は `Str\capitalize` を使用
- 全文字を大文字にする場合は `Str\uppercase` を使用

---

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

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

### 推奨読解順序

#### Step 1: メイン実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | transform.php | `src/str/transform.php` | capitalize_words関数のメイン実装 |

**主要処理フロー**:
- **44-47行目**: 関数シグネチャの定義（string型の入力、?string型のオプショナルデリミタ）
- **48-50行目**: 空文字列チェック
- **51-54行目**: デリミタがnullの場合、_Str\titlecase_l関数を呼び出し
- **56-72行目**: カスタムデリミタ処理のロジック

**読解のコツ**: `[]:` アノテーションは純粋関数を示し、副作用がないことを保証する。`namespace\capitalize` は同一名前空間内の `capitalize` 関数を参照する。

#### Step 2: 依存関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | transform.php | `src/str/transform.php` | capitalize関数の実装（26-31行目） |

**主要処理フロー**:
- **26-31行目**: 最初の1文字を大文字に変換するロジック

#### Step 3: ロケール対応版を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | transform_l.php | `src/str/transform_l.php` | capitalize_words_l関数のロケール対応版実装 |

**主要処理フロー**:
- **52-57行目**: Localeオブジェクトを受け取り、ロケール対応のタイトルケース変換を実行

#### Step 4: テストコードで動作を確認する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | StrTransformTest.php | `tests/str/StrTransformTest.php` | capitalize_wordsのテストケース |
| 4-2 | StrLocaleTest.php | `tests/str/StrLocaleTest.php` | ロケール対応版のテストケース |

**主要処理フロー**:
- **35-53行目**: デフォルトデリミタでのテストケース
- **56-103行目**: カスタムデリミタでのテストケース

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

```
Str\capitalize_words($string, $delimiters)
    │
    ├─ ($delimiters === null の場合)
    │      └─ _Str\titlecase_l($string, null)
    │              └─ HHVM組み込み関数
    │
    └─ (カスタムデリミタの場合)
           ├─ \strlen() - 文字列長取得
           ├─ \strcspn() - デリミタまでの文字数計算
           ├─ \substr() - 部分文字列取得
           └─ Str\capitalize($word) - 各単語の先頭大文字化
                  └─ _Str\uppercase_l() + Str\slice()
```

### データフロー図

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

$string ─────────────┬──▶ 空文字チェック
                     │
$delimiters ─────────┼──▶ デリミタ判定
                     │
                     ├──▶ (null) titlecase_l() ────────▶ 変換済み文字列
                     │
                     └──▶ (指定あり)
                            ├─▶ 単語分割
                            ├─▶ 各単語capitalize()
                            └─▶ 結合 ─────────────────▶ 変換済み文字列
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| transform.php | `src/str/transform.php` | ソース | capitalize_words関数のメイン実装 |
| transform_l.php | `src/str/transform_l.php` | ソース | ロケール対応版capitalize_words_l関数の実装 |
| StrTransformTest.php | `tests/str/StrTransformTest.php` | テスト | capitalize_wordsのユニットテスト |
| StrLocaleTest.php | `tests/str/StrLocaleTest.php` | テスト | ロケール対応版のユニットテスト |
