Skip to content

Commit

Permalink
Merge pull request #79 from timburks/result
Browse files Browse the repository at this point in the history
Modify run_with_result() to return Result<(), Box<dyn std::error::Error>>
  • Loading branch information
ksk001100 authored Dec 4, 2023
2 parents 36c5f28 + 4f4db04 commit 34c897a
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 44 deletions.
21 changes: 14 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ $ cli calc -op sub 10 6 3 2
### Top level error handling

```rust
use seahorse::{ActionError, App, Context, Flag, FlagType};
use seahorse::{App, Context, Flag, FlagType};
use std::env;

fn main() {
Expand All @@ -251,9 +251,7 @@ fn main() {
.version(env!("CARGO_PKG_VERSION"))
.action_with_result(|c: &Context| {
if c.bool_flag("error") {
Err(ActionError {
message: "ERROR...".to_string(),
})
Err(Box::new(Error))
} else {
Ok(())
}
Expand All @@ -266,11 +264,20 @@ fn main() {

match app.run_with_result(args) {
Ok(_) => println!("OK"),
Err(e) => match e {
ActionError { message } => println!("{}", message),
},
Err(e) => println!("{}", e),
};
}

#[derive(Debug, Clone)]
struct Error;

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ERROR...")
}
}

impl std::error::Error for Error {}
```

```bash
Expand Down
22 changes: 15 additions & 7 deletions examples/top_level_error_handling.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use seahorse::{ActionError, App, Context, Flag, FlagType};
use seahorse::{App, Context, Flag, FlagType};
use std::env;
use std::fmt;

fn main() {
let args: Vec<String> = env::args().collect();
Expand All @@ -10,9 +11,7 @@ fn main() {
.version(env!("CARGO_PKG_VERSION"))
.action_with_result(|c: &Context| {
if c.bool_flag("error") {
Err(ActionError {
message: "ERROR...".to_string(),
})
Err(Box::new(Error))
} else {
Ok(())
}
Expand All @@ -25,8 +24,17 @@ fn main() {

match app.run_with_result(args) {
Ok(_) => println!("OK"),
Err(e) => match e {
ActionError { message } => println!("{}", message),
},
Err(e) => println!("{}", e),
};
}

#[derive(Debug, Clone)]
struct Error;

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "test error")
}
}

impl std::error::Error for Error {}
11 changes: 3 additions & 8 deletions src/action.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::Context;
use std::error::Error;
use std::result::Result;

/// Command and application action type
///
Expand All @@ -13,11 +15,4 @@ use crate::Context;
/// ```
pub type Action = fn(&Context);

pub type ActionWithResult = fn(&Context) -> ActionResult;

pub type ActionResult = Result<(), ActionError>;

#[derive(Debug)]
pub struct ActionError {
pub message: String,
}
pub type ActionWithResult = fn(&Context) -> Result<(), Box<dyn Error>>;
44 changes: 25 additions & 19 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::{
Action, ActionError, ActionResult, ActionWithResult, Command, Context, Flag, FlagType, Help,
error::ActionError, error::ActionErrorKind, Action, ActionWithResult, Command, Context, Flag,
FlagType, Help,
};
use std::error::Error;

/// Multiple action application entry point
#[derive(Default)]
Expand Down Expand Up @@ -252,7 +254,7 @@ impl App {
pub fn run(&self, args: Vec<String>) {
match self.run_with_result(args) {
Ok(_) => return,
Err(e) => panic!("{}", e.message),
Err(e) => panic!("{}", e),
}
}

Expand All @@ -268,7 +270,7 @@ impl App {
/// let app = App::new("cli");
/// let result = app.run_with_result(args);
/// ```
pub fn run_with_result(&self, args: Vec<String>) -> ActionResult {
pub fn run_with_result(&self, args: Vec<String>) -> Result<(), Box<dyn Error>> {
let args = Self::normalized_args(args);
let (cmd_v, args_v) = match args.len() {
1 => args.split_at(1),
Expand All @@ -279,9 +281,9 @@ impl App {
Some(c) => c,
None => {
self.help();
return Err(ActionError {
message: "unsupported command".to_string(),
});
return Err(Box::new(ActionError {
kind: ActionErrorKind::NotFound,
}));
}
};

Expand Down Expand Up @@ -493,7 +495,8 @@ impl Help for App {

#[cfg(test)]
mod tests {
use crate::{Action, ActionError, ActionWithResult, App, Command, Context, Flag, FlagType};
use crate::{Action, ActionWithResult, App, Command, Context, Flag, FlagType};
use std::fmt;

#[test]
fn app_new_only_test() {
Expand Down Expand Up @@ -727,9 +730,7 @@ mod tests {
#[should_panic]
fn app_with_error_result_test() {
let a: ActionWithResult = |_: &Context| {
return Err(ActionError {
message: "we expect this to fail".to_string(),
});
return Err(Box::new(Error));
};
let app = App::new("test").action_with_result(a);
app.run(vec!["test".to_string()]);
Expand All @@ -748,9 +749,7 @@ mod tests {
#[test]
fn app_with_error_result_value_test() {
let a: ActionWithResult = |_: &Context| {
return Err(ActionError {
message: "we expect this to fail".to_string(),
});
return Err(Box::new(Error));
};
let app = App::new("test").action_with_result(a);
let result = app.run_with_result(vec!["test".to_string()]);
Expand All @@ -771,9 +770,7 @@ mod tests {
#[should_panic]
fn command_with_error_result_test() {
let a: ActionWithResult = |_: &Context| {
return Err(ActionError {
message: "we expect this to fail".to_string(),
});
return Err(Box::new(Error));
};
let command = Command::new("hello").action_with_result(a);
let app = App::new("test").command(command);
Expand All @@ -794,13 +791,22 @@ mod tests {
#[test]
fn command_with_error_result_value_test() {
let a: ActionWithResult = |_: &Context| {
return Err(ActionError {
message: "we expect this to fail".to_string(),
});
return Err(Box::new(Error));
};
let command = Command::new("hello").action_with_result(a);
let app = App::new("test").command(command);
let result = app.run_with_result(vec!["test".to_string(), "hello".to_string()]);
assert!(result.is_err());
}

#[derive(Debug, Clone)]
struct Error;

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "test error")
}
}

impl std::error::Error for Error {}
}
5 changes: 3 additions & 2 deletions src/command.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{Action, ActionResult, ActionWithResult, Context, Flag, FlagType, Help};
use crate::{Action, ActionWithResult, Context, Flag, FlagType, Help};
use std::error::Error;

/// Application command type
#[derive(Default)]
Expand Down Expand Up @@ -256,7 +257,7 @@ impl Command {

/// Run command
/// Call this function only from `App`
pub fn run_with_result(&self, args: Vec<String>) -> ActionResult {
pub fn run_with_result(&self, args: Vec<String>) -> Result<(), Box<dyn Error>> {
let args = Self::normalized_args(args);

match args.split_first() {
Expand Down
26 changes: 26 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,32 @@
use std::error;
use std::fmt;

#[derive(Debug)]
pub struct ActionError {
pub kind: ActionErrorKind,
}

impl fmt::Display for ActionError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.kind)
}
}

impl std::error::Error for ActionError {}

#[derive(PartialEq, Clone, Debug)]
pub enum ActionErrorKind {
NotFound,
}

impl fmt::Display for ActionErrorKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ActionErrorKind::NotFound => f.write_str("NotFound"),
}
}
}

#[derive(PartialEq, Clone, Debug)]
pub enum FlagError {
NotFound,
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub mod error;
mod flag;
mod help;

pub use action::{Action, ActionError, ActionResult, ActionWithResult};
pub use action::{Action, ActionWithResult};
pub use app::App;
pub use command::Command;
pub use context::Context;
Expand Down

0 comments on commit 34c897a

Please sign in to comment.