タスクを出力する関数を記述する

完了

定義する必要がある 3 つ目かつ最後のアクションは list_tasks 関数です。 必要な処理は、ジャーナル ファイルを読み取り、タスクのリストがある場合はそれを出力することのみです。

pub fn list_tasks(journal_path: PathBuf) -> Result<()> {
    // Open the file.
    let file = OpenOptions::new().read(true).open(journal_path)?;
    // Parse the file and collect the tasks.
    let tasks = collect_tasks(&file)?;

    // Enumerate and display tasks, if any.
    if tasks.is_empty() {
        println!("Task list is empty!");
    } else {
        let mut order: u32 = 1;
        for task in tasks {
            println!("{}: {}", order, task);
            order += 1;
        }
    }

    Ok(())
}

この関数は他の関数よりも少し複雑さが減っています。ファイルに書き込む必要がないためです。 collect_tasks ヘルパー関数を再利用します。これで、リファクタリングが役に立つことがわかります。 次に、内容を一覧表示する前に、タスク ベクトルが空かどうかを確認します。

リストを出力するときは、1 で始まる単純なカウンターを使用してタスクを列挙します。 この数値は、ユーザーが complete_task アクションに渡すものと同じです。

Task 構造体にはまだ Display の特性が実装されていないため、このコードはコンパイルされないことに注意してください。 他のモジュールで見たように、Display の特性は、エンド ユーザーに構造体の表現を表示するために使用されます。これが、まさにここで行っている処理です。

型に Display の特性を実装するのは簡単です。 次のように、fmt 関数を実装するだけです。

use std::fmt;

impl fmt::Display for Task {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let created_at = self.created_at.with_timezone(&Local).format("%F %H:%M");
        write!(f, "{:<50} [{}]", self.text, created_at)
    }
}

Display::fmt 関数では、DateTime<Utc> タイムスタンプを DateTime<Local> 構造体に変換し、タスクが作成された日時をユーザーがローカル時刻で確認できるようにします。

最初から DateTime<Local> 型を使用して created_at フィールドを定義しなかったのはなぜか疑問に思われるかもしれません。 そうしなかったのは、DateTime 構造体が Utc 型に特殊化されていることが chrono::serde::ts_seconds モジュールで想定されているためです。

次に、write! マクロを使用して、Task の表現を Formatterf に書き込みます。 Task 型を次のように表します。

  • {:<50}: 50 個のスペースが埋め込まれた左揃えの文字列。
  • それに続く [{}]: タスクが作成された日時 (かっこ内)。

まとめ

tasks.rs モジュール ファイルの探索は以上です。 タスク モジュールの完全なコードを確認するには、「Rust プレイグラウンド」をご覧ください。 実行する必要がある最後の手順は、cli::CommandLineArgs によってキャプチャされたユーザー入力を、このモジュールで定義した 3 つの関数にバインドすることです。

次のセクションでは、その結果を main.rs ファイルで接続し、アプリケーションを完成させます。