Skip to content

Commit

Permalink
[Enhancement] Append Data to PathBuf-like Instances (#111)
Browse files Browse the repository at this point in the history
* Added ::= PathBufLikeAppendix

* Added ::= PathBufLikeAppendix::append_silently

* Added ::= PathBufLikaAppendix::append_loudly

* Changed ::= MSRV:  1.76.0

* Added ::= tests for PathBufLikeAppendix

* Create summary of recent changes

* Skip ::= fix typo

---------

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
kevinmatthes and github-actions[bot] committed Feb 11, 2024
1 parent da4b1ad commit 9b794a3
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
(
references: {},
changes: {
"Added": [
"PathBufLikeAppendix::append_loudly",
"PathBufLikeAppendix",
"PathBufLikeAppendix::append_silently",
"tests for PathBufLikeAppendix",
],
"Changed": [
"MSRV: 1.76.0",
],
},
)
4 changes: 3 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,9 @@ mod writing;
pub use reading::{
BufReadReader, OptionReader, PathBufLikeReader, VectorReader,
};
pub use writing::{OptionTruncation, PathBufLikeTruncation, Writer};
pub use writing::{
OptionTruncation, PathBufLikeAppendix, PathBufLikeTruncation, Writer,
};

/// This crate's name.
pub const NAME: &str = "aeruginous-io";
Expand Down
101 changes: 101 additions & 0 deletions src/writing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,107 @@
use std::{io::Write, path::PathBuf};
use sysexits::Result;

/// Append to the files given as instances convertible to a
/// [`std::path::PathBuf`].
pub trait PathBufLikeAppendix<T>
where
PathBuf: From<T>,
{
/// Append the data this method is called on to the given destination.
///
/// This method behaves just like
/// [`crate::PathBufLikeAppendix::append_silently`] despite also printing
/// error messages to [`std::io::Stderr`].
///
/// # Errors
///
/// See [`sysexits::ExitCode`].
fn append_loudly(self, destination: T) -> Result<()>;

/// Append the data this method is called on to the given destination.
///
/// The data this method is called on will be converted to a [`String`] and
/// appended to the given file. The data therefore needs to implement
/// [`ToString`]. The file needs to be convertible to a
/// [`std::path::PathBuf`]. The data will be appended at the end of the
/// file, already existing data will not be changed. In case that the file
/// should not already exist, it will be created before writing to it.
///
/// The return value is either the unit type, in case of success, or a
/// [`sysexits::ExitCode`] to describe the error cause, otherwise.
///
/// Error messages are not written to [`std::io::Stderr`].
///
/// # Errors
///
/// See [`sysexits::ExitCode`].
fn append_silently(self, destination: T) -> Result<()>;
}

impl<P, T: ToString> PathBufLikeAppendix<P> for T
where
PathBuf: From<P>,
{
fn append_loudly(self, destination: P) -> Result<()> {
match std::fs::File::options()
.append(true)
.create(true)
.truncate(false)
.open(PathBuf::from(destination))
{
Err(e) => {
eprintln!("{e}");
Err(e.into())
}
Ok(mut file) => {
let bytes = self.to_string().as_bytes().to_vec();

match file.write(&bytes) {
Err(e) => {
eprintln!("{e}");
Err(e.into())
}
Ok(n) => {
if n == bytes.len() {
Ok(())
} else {
eprintln!(
"Creating an exact copy was not possible."
);
Err(sysexits::ExitCode::IoErr)
}
}
}
}
}
}

fn append_silently(self, destination: P) -> Result<()> {
match std::fs::File::options()
.append(true)
.create(true)
.truncate(false)
.open(PathBuf::from(destination))
{
Err(e) => Err(e.into()),
Ok(mut file) => {
let bytes = self.to_string().as_bytes().to_vec();

match file.write(&bytes) {
Err(e) => Err(e.into()),
Ok(n) => {
if n == bytes.len() {
Ok(())
} else {
Err(sysexits::ExitCode::IoErr)
}
}
}
}
}
}
}

/// Truncate files given as instances convertible to a [`std::path::PathBuf`].
pub trait PathBufLikeTruncation<T>
where
Expand Down
82 changes: 41 additions & 41 deletions tests/reading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,41 +53,40 @@ mod buf_read_reader {
}
}

mod path_buf_like_reader {
use aeruginous_io::PathBufLikeReader;
mod option_reader {
use aeruginous_io::OptionReader;

#[test]
fn method_result_equality() {
fn method_result_equality_none() {
assert_eq!(
"tests/assets/GPL-3.0.rs".read_loudly().unwrap(),
"tests/assets/GPL-3.0.rs".read_silently().unwrap(),
None::<&str>.read_loudly(&b"test"[..]).unwrap(),
None::<&str>.read_silently(&b"test"[..]).unwrap()
);
}

#[test]
fn read_loudly_failure_attempt_to_read_directory() {
assert!(".github/".read_loudly().is_err());
}

#[test]
fn read_loudly_failure_file_does_not_exist() {
assert!("no_such_file.txt".read_loudly().is_err());
}

#[test]
fn read_silently_failure_attempt_to_read_directory() {
assert!(".github/".read_silently().is_err());
fn method_result_equality_some() {
assert_eq!(
Some("tests/assets/GPL-3.0.rs")
.read_loudly(&b""[..])
.unwrap(),
Some("tests/assets/GPL-3.0.rs")
.read_silently(&b""[..])
.unwrap(),
);
}

#[test]
fn read_silently_failure_file_does_not_exist() {
assert!("no_such_file.txt".read_silently().is_err());
fn read_silently_success_none() {
assert_eq!(None::<&str>.read_silently(&b"test"[..]).unwrap(), "test\n");
}

#[test]
fn read_silently_success() {
fn read_silently_success_some() {
assert_eq!(
"tests/assets/GPL-3.0.rs".read_silently().unwrap(),
Some("tests/assets/GPL-3.0.rs")
.read_silently(&b""[..])
.unwrap(),
"\
/// Copyright (C) 2024 Kevin Matthes
///
Expand All @@ -108,40 +107,41 @@ mod path_buf_like_reader {
}
}

mod option_reader {
use aeruginous_io::OptionReader;
mod path_buf_like_reader {
use aeruginous_io::PathBufLikeReader;

#[test]
fn method_result_equality_none() {
fn method_result_equality() {
assert_eq!(
None::<&str>.read_loudly(&b"test"[..]).unwrap(),
None::<&str>.read_silently(&b"test"[..]).unwrap()
"tests/assets/GPL-3.0.rs".read_loudly().unwrap(),
"tests/assets/GPL-3.0.rs".read_silently().unwrap(),
);
}

#[test]
fn method_result_equality_some() {
assert_eq!(
Some("tests/assets/GPL-3.0.rs")
.read_loudly(&b""[..])
.unwrap(),
Some("tests/assets/GPL-3.0.rs")
.read_silently(&b""[..])
.unwrap(),
);
fn read_loudly_failure_attempt_to_read_directory() {
assert!(".github/".read_loudly().is_err());
}

#[test]
fn read_silently_success_none() {
assert_eq!(None::<&str>.read_silently(&b"test"[..]).unwrap(), "test\n");
fn read_loudly_failure_file_does_not_exist() {
assert!("no_such_file.txt".read_loudly().is_err());
}

#[test]
fn read_silently_success_some() {
fn read_silently_failure_attempt_to_read_directory() {
assert!(".github/".read_silently().is_err());
}

#[test]
fn read_silently_failure_file_does_not_exist() {
assert!("no_such_file.txt".read_silently().is_err());
}

#[test]
fn read_silently_success() {
assert_eq!(
Some("tests/assets/GPL-3.0.rs")
.read_silently(&b""[..])
.unwrap(),
"tests/assets/GPL-3.0.rs".read_silently().unwrap(),
"\
/// Copyright (C) 2024 Kevin Matthes
///
Expand Down
38 changes: 38 additions & 0 deletions tests/writing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,44 @@
| |
\******************************************************************************/

mod path_buf_like_appendix {
use aeruginous_io::{PathBufLikeAppendix, PathBufLikeReader};

#[test]
fn append_loudly_failure() {
assert!(String::new().append_loudly("tests/").is_err());
}

#[test]
fn append_loudly_success() {
let f = "path_buf_like_appendix_append_loudly_success.txt";

assert!("test line 1\n".append_loudly(f).is_ok());
assert_eq!(f.read_silently().unwrap(), "test line 1\n");
assert!("test line 2\n".append_loudly(f).is_ok());
assert_eq!(f.read_silently().unwrap(), "test line 1\ntest line 2\n");

std::fs::remove_file(f).unwrap();
}

#[test]
fn append_silently_failure() {
assert!(String::new().append_silently("tests/").is_err());
}

#[test]
fn append_silently_success() {
let f = "path_buf_like_appendix_append_silently_success.txt";

assert!("test line 1\n".append_silently(f).is_ok());
assert_eq!(f.read_silently().unwrap(), "test line 1\n");
assert!("test line 2\n".append_silently(f).is_ok());
assert_eq!(f.read_silently().unwrap(), "test line 1\ntest line 2\n");

std::fs::remove_file(f).unwrap();
}
}

mod path_buf_like_io {
use aeruginous_io::{PathBufLikeReader, PathBufLikeTruncation};

Expand Down

0 comments on commit 9b794a3

Please sign in to comment.