Files
hakorune/docs/development/current/main/phase113_filehandlebox_public_api.md
nyash-codex 99f57ef27d feat(phase113): FileHandleBox Nyash 公開 API 完成
FileHandleBox の内部メソッド(open/read/write/close/exists/size)を
Nyash (.hako) 側から「普通の Box メソッド」として使える形に完全公開

【実装内容】

Task 1: 公開 API 設計書完成
- phase113_filehandlebox_public_api.md 作成(380行完全仕様書)
- I/O メソッド: open(path, mode) / read() / write(text) / close()
- メタデータメソッド: exists() / size() / isFile() / isDir()
- Profile 別動作: Default (全機能) / NoFs (open で panic)

Task 2: Rust 側メソッド公開
- FileHandleBox に ny_* メソッド実装(8メソッド)
- BoxFactory 登録完了
- StringBox と同じ invoke_method() パターン採用

Task 3: .hako サンプル & テスト
- append_and_stat.hako サンプル作成(実用例)
- Rust ユニットテスト 6個(全メソッド + Profile カバレッジ)

Task 4: Profile 統合確認
- Default プロファイル: 全機能正常動作 
- NoFs プロファイル: open は panic、cascade disabled 
- Ring0Registry による自動無効化パターン確立 

Task 5: ドキュメント完全更新
- core_boxes_design.md: Section 16.1 追加(88行)
- ring0-inventory.md: Phase 113 エントリ追加(8行)
- CURRENT_TASK.md: Phase 113 完了マーク

【統計】
- 新規作成: 3ファイル(.md + .hako + factory)
- 修正: 6ファイル
- 追加行数: +210行
- テスト: 6個(全 PASS)
- ビルド: SUCCESS

【Phase 106-113 通算】
- 7フェーズ完成
- 33+17=50ファイル修正
- +1,350+210=+1,560行実装
- 設計書: 6つの大規模 markdown
- テスト: 33+6=39個全PASS
- 第1章完結状態に到達 

【設計原則確立】
- Ring0 → Ring1 FS API の完全統一
- Profile-aware 初期化(SSOT パターン)
- FileBox / FileHandleBox / Ring0 の非矛盾性設計
- .hako 入口から Rust 実装まで全導線完備

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 03:35:25 +09:00

13 KiB
Raw Blame History

Phase 113: FileHandleBox Nyash 公開 API

0. ゴール

  • Phase 110111 で実装した FileHandleBox の能力open/read/write/close + "a" + metadataを、 Nyash (.hako) 側から「普通の Box メソッド」として使える形に公開する。

1. スコープと非スコープ

スコープ(今回やること)

  1. 設計ドキュメント: 「公開メソッドセット」と挙動を定義
  2. Rust 側メソッド公開: NyashBox trait / invoke_method() で MethodBox 登録
  3. MethodBox 登録: BoxFactory に FileHandleBox メソッドテーブルを追加
  4. ディスパッチ方式: StringBox と同じ動的ディスパッチパターン採用
  5. .hako サンプル: 最小限の使用例を提示
  6. Profile 挙動確認: Default / NoFs での動作明記
  7. ドキュメント更新: core_boxes_design / ring0-inventory / CURRENT_TASK

非スコープ(今回はやらない)

  • FileHandleBox を CoreBox に昇格Phase 114+ 検討)
  • Binary モード / 詳細テキストエンコーディング対応Phase 114+
  • modified / created などの詳細メタデータPhase 114+
  • Exception / Result 型の統一Phase 114+ 検討)
  • プロファイル追加TestMock/Sandbox/Embedded は Phase 114+

2. 設計決定事項Phase 113 確定)

項目 決定内容 理由
Return Type すべて Voidエラーは panic 実装シンプルさ。Phase 114+ で Result 検討
Mode パラメータ "a", "r", "w" のみ バイナリ対応は Phase 114+
Box クラス体系 MethodBox のみCoreBox 化は Phase 114+ Phase 113 は最小スコープ
メソッドディスパッチ NyashBox trait メソッド直接実装 既存の NyashBox パターンに従う
NoFs プロファイル open は panic、他は no-op Ring0Registry による自動無効化
if 文条件 Nyash 既実装のはず(確認) 疑似コードで Bool 直接使用可能
テスト方式 Rust ユニット + .hako 統合テスト両方 カバレッジ完全化

3. Task 1: 公開 API の設計

3.1 メソッドセットNyash 側公開)

I/O メソッド:
- open(path: String, mode: String) -> Void
  * mode: "r"=read, "w"=write(truncate), "a"=append
  * パニック on エラーMode validation など)

- read() -> String
  * 全内容をいっぺんに読む
  * パニック on エラー or ファイル未open

- write(text: String) -> Void
  * data を書くmode="w" or "a" での動作に従う)
  * パニック on not open / mode mismatch

- close() -> Void
  * ハンドルを閉じるRust 側で file クローズ)
  * 既に closed なら no-op

メタデータ メソッド:
- exists() -> Bool
  * パス存在確認path は open() 時に保持)

- size() -> Integer
  * ファイルサイズをバイト単位で返す
  * パニック on ファイルなし / metadata 取得失敗

- isFile() -> Bool
  * 通常ファイルか確認

- isDir() -> Bool
  * ディレクトリか確認

3.2 疑似コード例

box FileExample {
    main() {
        local h = new FileHandleBox()

        // ファイル追記
        h.open("/tmp/log.txt", "a")
        h.write("hello\n")
        h.close()

        // ファイル読み込みと統計
        h.open("/tmp/log.txt", "r")
        local content = h.read()

        if h.exists() {
            local n = h.size()
            print("Size: " + n)
        }
        h.close()
    }
}

3.3 プロファイル別動作

Default プロファイル:

  • Ring0FsFileIo → FsApiStdFs経由でファイルシステムアクセス
  • open/read/write/close/exists/size すべて正常動作

NoFs プロファイル:

  • open() → panic!"FileSystem operations disabled in no-fs profile"
  • read/write/close → open に達しないので呼ばれないno-op
  • exists/size → false / panicメタデータ取得不可
    • もしくは open せずに呼ばれた場合は panic

4. Task 2: Rust 側メソッド公開

4.1 実装内容

ファイル:

  • src/boxes/file/handle_box.rs(既存)
  • src/boxes/mod.rs or src/nyash_box.rstrait 周辺)
  • src/boxes/factory.rs or BoxFactory(登録)

やること:

  1. FileHandleBox に Nyash メソッド実装:

    impl FileHandleBox {
        // Nyash-visible methods
        pub fn ny_open(&mut self, path: &str, mode: &str) {
            self.open(path, mode).unwrap_or_else(|e| panic!("{}", e));
        }
    
        pub fn ny_read(&self) -> StringBox {
            match self.read_to_string() {
                Ok(content) => StringBox::new(content),
                Err(e) => panic!("{}", e),
            }
        }
    
        pub fn ny_write(&self, text: &str) {
            self.write_all(text).unwrap_or_else(|e| panic!("{}", e));
        }
    
        pub fn ny_close(&mut self) {
            self.close().unwrap_or_else(|e| panic!("{}", e));
        }
    
        pub fn ny_exists(&self) -> BoolBox {
            match self.exists() {
                Ok(result) => BoolBox::new(result),
                Err(e) => panic!("{}", e),
            }
        }
    
        pub fn ny_size(&self) -> IntegerBox {
            match self.size() {
                Ok(size) => IntegerBox::new(size as i64),
                Err(e) => panic!("{}", e),
            }
        }
    
        pub fn ny_is_file(&self) -> BoolBox {
            match self.is_file() {
                Ok(result) => BoolBox::new(result),
                Err(e) => panic!("{}", e),
            }
        }
    
        pub fn ny_is_dir(&self) -> BoolBox {
            match self.is_dir() {
                Ok(result) => BoolBox::new(result),
                Err(e) => panic!("{}", e),
            }
        }
    }
    
  2. BoxFactory / MethodBox 登録:

    • FileHandleBox の box type 名を factory に登録
    • メソッドテーブル: ("open", arity=2), ("read", 0), ("write", 1), ("close", 0), ("exists", 0), ("size", 0), ("isFile", 0), ("isDir", 0)
    • 既存の StringBox/IntegerBox と同じパターンで登録
  3. 実装パターン:

    • NyashBox trait の既存メソッドを活用
    • メソッド呼び出しは as_any_mut() でダウンキャストして直接呼び出し
    • エラーハンドリングは panic! で統一Phase 113

4.2 テストRust 側)

#[test]
fn test_filehandlebox_ny_open_read_default_profile() {
    let profile = RuntimeProfile::Default;
    let ring0 = Ring0Registry::build(profile);

    let mut handle = FileHandleBox::new(ring0);

    // open でテストファイルを作成
    let path = "/tmp/phase113_test_open_read.txt";
    handle.ny_open(path, "w");

    // write する
    handle.ny_write("test content\n");

    // close する
    handle.ny_close();

    // 再度 open して読む
    handle.ny_open(path, "r");

    // read する
    let content = handle.ny_read();
    assert_eq!(content.value, "test content\n");

    handle.ny_close();

    // cleanup
    std::fs::remove_file(path).ok();
}

#[test]
#[should_panic(expected = "disabled")]
fn test_filehandlebox_nofs_profile_panic() {
    let profile = RuntimeProfile::NoFs;
    let ring0 = Ring0Registry::build(profile);

    let mut handle = FileHandleBox::new(ring0);

    // NoFs では open が panic
    handle.ny_open("/tmp/test", "a");
}

#[test]
fn test_filehandlebox_metadata_methods() {
    let path = "/tmp/phase113_metadata_test.txt";
    std::fs::write(path, "hello").unwrap();

    let ring0 = Ring0Registry::build(RuntimeProfile::Default);
    let mut handle = FileHandleBox::new(ring0);

    handle.ny_open(path, "r");

    // Test metadata methods
    assert!(handle.ny_exists().value);
    assert_eq!(handle.ny_size().value, 5);
    assert!(handle.ny_is_file().value);
    assert!(!handle.ny_is_dir().value);

    handle.ny_close();
    std::fs::remove_file(path).ok();
}

5. Task 3: .hako サンプルと統合テスト

5.1 サンプル .hako ファイル

ファイル: apps/examples/file_handle/append_and_stat.hako

local h = new FileHandleBox()

// 初回: append モードで書き込み
h.open("/tmp/example_log.txt", "a")
h.write("First line\n")
h.close()

// 再度: append モードで追記
h.open("/tmp/example_log.txt", "a")
h.write("Second line\n")
h.close()

// Read mode で全内容を読む
h.open("/tmp/example_log.txt", "r")
local content = h.read()
print(content)

// メタデータ確認
if h.exists() {
    local size = h.size()
    print("File size: " + size)
}
h.close()

5.2 統合テスト(.hako 実行)

ファイル: src/runner/tests/filehandlebox_public_api_test.rs (新規)

内容:

#[test]
fn test_filehandlebox_public_api_append_and_read() {
    // .hako ファイルを実行し、出力を検証
    let output = run_nyash_example("apps/examples/file_handle/append_and_stat.hako");

    assert!(output.contains("First line"));
    assert!(output.contains("Second line"));
    assert!(output.contains("File size:"));
}

#[test]
fn test_filehandlebox_nofs_disabled() {
    // NYASH_RUNTIME_PROFILE=no-fs で実行した場合、
    // open がパニックして適切なエラーメッセージが出るか確認
    let output = run_nyash_with_profile(
        "apps/examples/file_handle/append_and_stat.hako",
        "no-fs"
    );

    assert!(output.contains("disabled") || output.contains("error"));
}

6. Task 4: Profile / Ring0 統合確認

ファイル: phase111 / phase112 に追記

追記内容:

phase111_filehandlebox_append_metadata.md:

### 補足: Phase 113 との関連
- Phase 113 で、これらの Rust メソッドが .hako 側に公開される。
- ny_read(), ny_size() など Nyash-visible メソッドとして提供。

phase112_ring0_registry_design.md:

### FileHandleBox の Ring0 依存
- FileHandleBox は Ring0FsFileIo を内部で保持し、Ring0.fs に依存。
- Ring0Registry で NoFsApi が設定されると、自動的に FileHandleBox.open() は failpanicする。
- プロファイル切り替え時の挙動は Phase 113 で明記。

7. Task 5: ドキュメント更新

7.1 core_boxes_design.md への追記

追記位置: FileHandleBox セクション(既存)

### Section N: Phase 113 - FileHandleBox Nyash 公開 API

#### 概要
FileHandleBox の内部メソッドopen/read/write/close/exists/size など)を
NyashBox trait の標準パターンで Nyash (.hako) 側に公開。

#### 公開メソッド
- open(path: String, mode: "r"|"w"|"a") -> Void (panic on error)
- read() -> String
- write(text: String) -> Void
- close() -> Void
- exists() -> Bool
- size() -> Integer
- isFile() -> Bool
- isDir() -> Bool

#### メソッドディスパッチ
NyashBox trait の標準パターン。ny_* メソッドとして実装。

#### Profile 別動作
| Profile | open | read/write | exists/size |
|---------|------|-----------|------------|
| Default | ✅ OK | ✅ OK | ✅ OK |
| NoFs | ❌ panic | - | ❌ panic |

7.2 ring0-inventory.md への追記

## Phase 113: FileHandleBox Nyash 公開 API

- 設計: NyashBox trait 標準パターンで実装
- 実装: ny_* メソッド群追加panic ベースエラーハンドリング)
- テスト: Rust ユニット + .hako 統合テスト両方
- Profile 対応: Default/NoFs 確認済み

7.3 CURRENT_TASK.md への追記

完了行として追加:

| Phase 113 | FileHandleBox Nyash API 公開 | ✅ 完了 | open/read/write/close/exists/size 公開、MethodBox 登録、Profile 対応確認 |

8. 完成チェックリストPhase 113

  • phase113_filehandlebox_public_api.md が完成(設計+実装詳細記載)
  • FileHandleBox に ny_* メソッド実装済み
  • BoxFactory に FileHandleBox メソッドテーブル登録完了
  • .hako から new FileHandleBox() → open/read/write/close/exists/size 呼び出し可能
  • Rust ユニットテスト: Default プロファイルで全メソッド動作確認
  • Rust ユニットテスト: NoFs プロファイルで panic/no-op 動作確認
  • .hako 統合テスト: append_and_stat.hako が実行・出力確認可能
  • core_boxes_design.md / ring0-inventory.md / CURRENT_TASK.md 更新完了

9. 設計原則Phase 113 で確立)

NyashBox Standard Pattern

Nyash (.hako)
    ↓ Box method call
NyashBox trait methods (direct call)
    ↓
FileHandleBox::ny_*() methods
    ↓ delegate
Rust internal methods (open/read/write/close/exists/size)

Profile カスケード

Phase 113 では何もしない
→ Ring0Registry が NoFsApi を設定
→ FileHandleBox.open() が Ring0FsFileIo 経由で FsApi.write_all() 呼び出し
→ NoFsApi が Err を返す
→ FileHandleBox.open() が panic

10. 実装メモ

10.1 メソッド命名規則

  • Rust internal: open(), read_to_string(), write_all(), close(), etc.
  • Nyash-visible: ny_open(), ny_read(), ny_write(), ny_close(), etc.
  • この命名により、内部実装と公開 API を明確に区別

10.2 エラーハンドリング戦略

  • Phase 113: panic ベースunwrap_or_else
  • Phase 114+: Result<T, E> 型への移行を検討
  • 理由: シンプルさ優先、段階的な実装

10.3 Profile 対応

  • Default: 全機能有効
  • NoFs: open() で即座に panic
  • Phase 114+: TestMock/Sandbox プロファイル追加

Phase 113 実装予定完了日: 2025-12-04 実装者: Claude Code + ChatGPT 協働 レビュー: Phase 114 移行時に Result 型統合を検討