# 機能設計書 20-文字列変換

## 概要

本ドキュメントは、Nushellにおける文字列変換機能の設計について記述する。str upcase、str downcase、str capitalizeコマンドを通じて、文字列の大文字・小文字変換機能を提供する。

### 本機能の処理概要

文字列変換機能は、文字列の大文字・小文字変換を行う。str upcaseは全て大文字に、str downcaseは全て小文字に、str capitalizeは先頭文字のみ大文字に変換する。

**業務上の目的・背景**：データ処理において文字列の正規化は基本的な操作である。大文字小文字を統一することで、比較や検索の精度向上、表示フォーマットの統一、データクレンジングなど多様なユースケースに対応する。

**機能の利用シーン**：
- `'hello' | str upcase` で"HELLO"に変換
- `'WORLD' | str downcase` で"world"に変換
- `'nushell' | str capitalize` で"Nushell"に変換
- `$table | str downcase name` でテーブルのnameカラムを小文字化

**主要な処理内容**：
1. 入力値の型判定
2. 文字列変換関数の適用
3. CellPath指定時は該当パスの値を更新

**関連システム・外部連携**：Rust標準ライブラリの文字列操作関数（to_uppercase, to_lowercase）と連携。

**権限による制御**：特になし。純粋なデータ操作機能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | メインREPL | 主画面 | 文字列変換コマンドの入力と結果表示 |

## 機能種別

データ操作（文字列変換）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| rest | CellPath[] | No | データ構造内の変換対象パス | 有効なCellPath |

### 入力データソース

- パイプライン入力: String、List<String>、Table、Record
- CellPath指定時はネストした構造内の文字列も変換可能

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| converted_string | String | 変換後の文字列 |
| converted_list | List | 変換後の文字列リスト |
| converted_table | Table | 指定カラム変換後のテーブル |
| converted_record | Record | 指定フィールド変換後のレコード |

### 出力先

- パイプライン出力: `PipelineData`として後続コマンドへ渡す

## 処理フロー

### 処理シーケンス

```
1. コマンド引数の解析
   └─ CellPathのリストを取得

2. 入力データの処理
   └─ input.map()でストリーミング処理

3. 各値に対して変換適用
   └─ CellPath空: 直接action()を適用
   └─ CellPath指定: update_cell_path()で該当パスを更新

4. action関数で変換実行
   └─ str upcase: to_uppercase()
   └─ str downcase: to_lowercase()
   └─ str capitalize: uppercase_helper()

5. 結果を返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[CellPath解析]
    B --> C[input.map開始]

    C --> D{CellPath空?}
    D -->|Yes| E[action直接適用]
    D -->|No| F[update_cell_path]

    F --> G{パス更新成功?}
    G -->|Yes| H[更新後の値を返却]
    G -->|No| I[Value::error返却]

    E --> J{入力型}
    J -->|String| K[変換関数適用]
    J -->|Error| L[そのまま返却]
    J -->|Other| M[OnlySupportsThisInputTypeエラー]

    K --> N{コマンド種別}
    N -->|upcase| O[to_uppercase]
    N -->|downcase| P[to_lowercase]
    N -->|capitalize| Q[uppercase_helper]

    O --> R[Value::string生成]
    P --> R
    Q --> R

    R --> S[終了]
    H --> S
    I --> S
    L --> S
    M --> S
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 文字列専用 | String型以外は型エラー | 常に適用 |
| BR-02 | エラー透過 | Value::Errorはそのまま返却 | 常に適用 |
| BR-03 | Unicode対応 | Unicodeの大文字小文字変換に対応 | 常に適用 |
| BR-04 | capitalize先頭のみ | capitalizeは最初の文字のみ大文字化 | capitalize時 |

### 計算ロジック

upcase変換:
```
s.to_uppercase()
```

downcase変換:
```
s.to_lowercase()
```

capitalize変換:
```
fn uppercase_helper(s: &str) -> String {
    let mut chars = s.chars();
    match chars.next() {
        None => String::new(),
        Some(f) => f.to_uppercase().collect::<String>() + chars.as_str()
    }
}
```

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

該当なし（インメモリ処理のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| OnlySupportsThisInputType | 型エラー | String以外の入力 | 文字列値を入力 |

### リトライ仕様

該当なし（同期処理のため）

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

該当なし（状態変更を伴わない）

## パフォーマンス要件

- ストリーミング処理: input.map()でメモリ効率良く処理
- is_const: trueで定数評価可能（コンパイル時最適化対象）
- run_const: StateWorkingSetを使用した定数実行をサポート

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

- 特になし。読み取り専用の文字列変換操作のみ。

## 備考

- 3コマンドとも同一のoperate関数パターンを共有
- CellPath指定で深いネスト構造の部分的な変換も可能
- Unicodeの大文字小文字変換はロケール依存の場合がある

---

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

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

### 推奨読解順序

#### Step 1: 共通パターンを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | upcase.rs | `crates/nu-command/src/strings/str_/case/upcase.rs` | operate関数(73-98行目)の共通処理パターン |

**読解のコツ**: 3つのコマンドはほぼ同一のパターン。`operate`関数がCellPath処理の共通ロジック、`action`関数が各コマンド固有の変換ロジック。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | upcase.rs | `crates/nu-command/src/strings/str_/case/upcase.rs` | run関数(43-52行目)でCellPath取得と処理委譲 |
| 2-2 | upcase.rs | `crates/nu-command/src/strings/str_/case/upcase.rs` | run_const関数(54-62行目)で定数評価サポート |

**主要処理フロー**:
1. **50行目**: `call.rest()`でCellPathリストを取得
2. **51行目**: `operate()`関数に処理委譲

#### Step 3: 変換ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | upcase.rs | `crates/nu-command/src/strings/str_/case/upcase.rs` | action関数(100-114行目)でupcase変換 |
| 3-2 | downcase.rs | `crates/nu-command/src/strings/str_/case/downcase.rs` | action関数(123-137行目)でdowncase変換 |
| 3-3 | capitalize.rs | `crates/nu-command/src/strings/str_/case/capitalize.rs` | action関数(115-129行目)とuppercase_helper(131-138行目) |

**主要処理フロー (upcase)**:
- **102行目**: `s.to_uppercase()`で大文字変換
- **103行目**: Value::Errorはそのまま返却
- **104-112行目**: 非String型はOnlySupportsThisInputTypeエラー

**主要処理フロー (capitalize)**:
- **117行目**: `uppercase_helper(val)`で先頭文字大文字化
- **133-136行目**: chars()で最初の文字を取得し、to_uppercase()適用

#### Step 4: CellPath処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | upcase.rs | `crates/nu-command/src/strings/str_/case/upcase.rs` | operate関数内のupdate_cell_path(86-92行目) |

**主要処理フロー**:
- **82-83行目**: CellPath空の場合は直接action適用
- **85-92行目**: CellPath指定時はforループで各パスを更新
- **87-88行目**: `update_cell_path()`でネスト値を更新

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

```
StrUpcase::run() / StrDowncase::run() / StrCapitalize::run()
    │
    ├─ call.rest() -> Vec<CellPath>
    │
    └─ operate()
           │
           └─ input.map(|v| {...})
                  │
                  ├─ column_paths.is_empty():
                  │      └─ action(&v, head)
                  │             │
                  │             ├─ (upcase) val.to_uppercase()
                  │             ├─ (downcase) val.to_lowercase()
                  │             └─ (capitalize) uppercase_helper(val)
                  │
                  └─ column_paths specified:
                         └─ for path in &column_paths:
                                └─ ret.update_cell_path(path, action)
```

### データフロー図

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

                       ┌─────────────────────────────────┐
String ───────────────▶│         直接変換                 │
     │                 │  action(input, head)            │
     │                 │    ├─ upcase: to_uppercase()   │
     │                 │    ├─ downcase: to_lowercase() │
     │                 │    └─ capitalize: uppercase_helper() │
     │                 └─────────────────────────────────┘
     │                                  │
     │                                  ▼
     │                            String (converted)
     │
     │                 ┌─────────────────────────────────┐
List/Table/Record ────▶│      input.map() 処理           │
     │                 │  for each value:               │
     │                 │    ├─ CellPath空: action(v)    │
     │                 │    └─ CellPath有: update_cell_path() │
     │                 └─────────────────────────────────┘
     │                                  │
     │                                  ▼
     │                 ┌─────────────────────────────────┐
     │                 │     update_cell_path()         │
     │                 │  ネスト構造内の値を更新         │
     │                 │  Box::new(|old| action(old))   │
     │                 └─────────────────────────────────┘
     │                                  │
     │                                  ▼
     └─────────────────────────────────▶ List/Table/Record (converted)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| upcase.rs | `crates/nu-command/src/strings/str_/case/upcase.rs` | ソース | str upcaseコマンド実装 |
| downcase.rs | `crates/nu-command/src/strings/str_/case/downcase.rs` | ソース | str downcaseコマンド実装 |
| capitalize.rs | `crates/nu-command/src/strings/str_/case/capitalize.rs` | ソース | str capitalizeコマンド実装 |
| mod.rs | `crates/nu-command/src/strings/str_/case/mod.rs` | ソース | caseモジュールエクスポート |
| mod.rs | `crates/nu-command/src/strings/str_/mod.rs` | ソース | str_モジュールエクスポート |
