Finally (FINALLY!) finished the Token integration
This commit is contained in:
parent
ee56d7c081
commit
632850c58c
6 changed files with 230 additions and 200 deletions
|
@ -21,6 +21,6 @@ mod token;
|
|||
mod usage;
|
||||
mod vars;
|
||||
|
||||
pub use matches::Matches;
|
||||
pub use vars::Vars;
|
||||
pub use matches::{Matches, matches};
|
||||
pub use vars::{Vars, vars};
|
||||
pub use usage::usage;
|
||||
|
|
|
@ -17,20 +17,17 @@
|
|||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Keys;
|
||||
use std::env;
|
||||
|
||||
use errors::{Error, ErrorKind};
|
||||
use vars::Vars;
|
||||
|
||||
pub struct Matches {
|
||||
matches: HashMap<String, String>,
|
||||
program_name: String
|
||||
matches: HashMap<String, String>
|
||||
}
|
||||
|
||||
impl Matches {
|
||||
pub fn new(opts: &mut Vars) -> Result<Matches, Error> {
|
||||
let mut args = env::args();
|
||||
pub fn matches(vars: &mut Vars, env_args: &[String]) -> Result<Matches, Error> {
|
||||
let mut matches: HashMap<String, String> = HashMap::new();
|
||||
let mut args = env_args.iter();
|
||||
|
||||
args.next(); // Remove the program name
|
||||
|
||||
|
@ -44,7 +41,7 @@ impl Matches {
|
|||
if ¤t_arg[..2] == "--" { // Long form opt
|
||||
arg_vec.push(String::from(¤t_arg[2..]));
|
||||
} else { // Short form opt
|
||||
// Assuming it's a group of short-form opts; e.g. tar -xzf
|
||||
// Assuming it's a group of short-form vars; e.g. tar -xzf
|
||||
for c in current_arg[1..].chars() {
|
||||
let mut s = String::new();
|
||||
s.push(c);
|
||||
|
@ -53,48 +50,69 @@ impl Matches {
|
|||
}
|
||||
|
||||
for arg in arg_vec.iter() {
|
||||
if opts.contains_opt(&arg) {
|
||||
let has_arg: bool = *opts.get_opt(&arg).unwrap();
|
||||
if vars.contains_opt(arg) {
|
||||
let token = vars.get_opt(arg).unwrap();
|
||||
|
||||
if has_arg {
|
||||
if token.has_arg {
|
||||
// NOTE: The corresponding arg MUST be immediately following
|
||||
current_arg = match args.next() {
|
||||
None => return Err(Error::new(ErrorKind::MissingArgument, (*arg).clone())),
|
||||
None => return Err(Error::new(ErrorKind::MissingArgument, arg.clone())),
|
||||
Some(a) => a
|
||||
};
|
||||
|
||||
matches.insert(arg.clone(), current_arg);
|
||||
matches.insert(token.name(), current_arg.clone());
|
||||
} else {
|
||||
matches.insert(arg.clone(), String::new());
|
||||
matches.insert(token.name(), String::new());
|
||||
}
|
||||
} else {
|
||||
return Err(Error::new(ErrorKind::InvalidArgument, arg.clone()));
|
||||
}
|
||||
}
|
||||
} else { // Probably a required arg
|
||||
let arg_name: String = opts.get_arg().unwrap().clone();
|
||||
matches.insert(arg_name, current_arg);
|
||||
let arg = vars.get_arg().unwrap();
|
||||
matches.insert(arg.name(), current_arg.clone());
|
||||
}
|
||||
|
||||
next_arg = args.next();
|
||||
}
|
||||
|
||||
match opts.arg_len() {
|
||||
0 => Ok(Matches { matches: matches, program_name: program_name }),
|
||||
_ => Err(Error::new(ErrorKind::MissingArgument, opts.get_arg().unwrap())),
|
||||
}
|
||||
match vars.arg_len() {
|
||||
0 => Ok(Matches { matches: matches }),
|
||||
_ => Err(Error::new(ErrorKind::MissingArgument, vars.get_arg().unwrap().name())),
|
||||
}
|
||||
}
|
||||
|
||||
impl Matches {
|
||||
pub fn get(&self, arg: &str) -> Option<&String> {
|
||||
self.matches.get(arg)
|
||||
}
|
||||
|
||||
pub fn has_arg(&self, arg: &str) -> bool {
|
||||
pub fn has_match(&self, arg: &str) -> bool {
|
||||
let arg = String::from(arg);
|
||||
self.matches.contains_key(&arg)
|
||||
}
|
||||
|
||||
pub fn args(&self) -> Keys<String, String> {
|
||||
pub fn matches(&self) -> Keys<String, String> {
|
||||
self.matches.keys()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Matches;
|
||||
use super::super::errors::{Error, ErrorKind};
|
||||
use super::super::vars::Vars;
|
||||
|
||||
#[test]
|
||||
fn test_matches() {
|
||||
let opts = vec!["o/opt(An option)", "a(Argument):"];
|
||||
let env_args = vec![String::from("test"), String::from("-a"), String::from("Test")];
|
||||
let mut vars = Vars::new("Test", &opts).unwrap();
|
||||
let matches = match Matches::new(&mut vars, &env_args) {
|
||||
Ok(m) => m,
|
||||
Err(why) => panic!("An error occurred: {}", why)
|
||||
};
|
||||
|
||||
assert_eq!(matches.get("opt").unwrap(), &String::from("opt"));
|
||||
}
|
||||
}
|
||||
|
|
36
src/token.rs
36
src/token.rs
|
@ -15,24 +15,22 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::ascii::AsciiExt;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use errors::{Error, ErrorKind};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Token {
|
||||
short_name: String,
|
||||
long_name: String,
|
||||
description: String,
|
||||
pub short_name: String,
|
||||
pub long_name: String,
|
||||
pub description: String,
|
||||
pub is_arg: bool,
|
||||
pub has_arg: bool,
|
||||
pub is_group: bool,
|
||||
padding: usize
|
||||
pub padding: usize
|
||||
}
|
||||
|
||||
impl Token {
|
||||
pub fn new(input: &str) -> Result<Token, Error> {
|
||||
pub fn token(input: &str) -> Result<Token, Error> {
|
||||
let mut short_name = String::new();
|
||||
let mut long_name = String::new();
|
||||
let mut description = String::new();
|
||||
|
@ -49,7 +47,7 @@ impl Token {
|
|||
};
|
||||
|
||||
if is_arg && has_arg {
|
||||
return Err(Error::new(ErrorKind::OptionFormat, String::from(input)));
|
||||
return Err(Error::new(ErrorKind::TokenFormat, String::from(input)));
|
||||
}
|
||||
|
||||
let option = if is_arg {
|
||||
|
@ -91,9 +89,9 @@ impl Token {
|
|||
description: description,
|
||||
padding: 0
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Token {
|
||||
pub fn adjust_padding(&mut self, padding: usize) {
|
||||
self.padding = padding;
|
||||
}
|
||||
|
@ -115,13 +113,13 @@ impl Token {
|
|||
repr.len()
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
pub fn name(&self) -> String {
|
||||
if !self.long_name.is_empty() {
|
||||
&self.long_name
|
||||
self.long_name.clone()
|
||||
} else if !self.short_name.is_empty() {
|
||||
&self.short_name
|
||||
self.short_name.clone()
|
||||
} else {
|
||||
""
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,7 +142,6 @@ impl Token {
|
|||
|
||||
if self.has_arg {
|
||||
let name = String::from(self.name());
|
||||
name.to_ascii_uppercase();
|
||||
repr.push(' ');
|
||||
repr.push_str(&name);
|
||||
}
|
||||
|
@ -152,7 +149,6 @@ impl Token {
|
|||
repr.push(']');
|
||||
} else {
|
||||
let name = String::from(self.name());
|
||||
name.to_ascii_uppercase();
|
||||
repr.push_str(&name);
|
||||
}
|
||||
|
||||
|
@ -207,7 +203,6 @@ mod tests {
|
|||
padding: 0
|
||||
};
|
||||
|
||||
println!("{}", token);
|
||||
assert_eq!(token, control_token);
|
||||
}
|
||||
|
||||
|
@ -228,7 +223,6 @@ mod tests {
|
|||
padding: 0
|
||||
};
|
||||
|
||||
println!("{}", token);
|
||||
assert_eq!(token, control_token);
|
||||
}
|
||||
|
||||
|
@ -249,7 +243,6 @@ mod tests {
|
|||
padding: 0
|
||||
};
|
||||
|
||||
println!("{}", token);
|
||||
assert_eq!(token, control_token);
|
||||
}
|
||||
|
||||
|
@ -270,7 +263,6 @@ mod tests {
|
|||
padding: 0
|
||||
};
|
||||
|
||||
println!("{}", token);
|
||||
assert_eq!(token, control_token);
|
||||
}
|
||||
|
||||
|
@ -286,8 +278,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_name() {
|
||||
let short_name = "o/out";
|
||||
let long_name = "/out";
|
||||
let short_name = "o";
|
||||
let long_name = "o/out";
|
||||
let group = "(Output)";
|
||||
|
||||
let short_token = Token::new(short_name).unwrap();
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
use vars::Vars;
|
||||
|
||||
pub fn usage(vars: &Vars) {
|
||||
for token in vars.tokens.iter() {
|
||||
for token in vars.tokens() {
|
||||
println!("{}", token);
|
||||
}
|
||||
}
|
56
src/vars.rs
56
src/vars.rs
|
@ -15,37 +15,42 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::VecDeque;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::slice::Iter;
|
||||
|
||||
use errors::Error;
|
||||
use token::Token;
|
||||
use token::{Token, token};
|
||||
|
||||
pub struct Vars {
|
||||
pub opts: HashMap<String, bool>,
|
||||
pub args: VecDeque<String>,
|
||||
opts: HashMap<String, Token>,
|
||||
args: VecDeque<Token>,
|
||||
pub tokens: Vec<Token>,
|
||||
pub program_name: String
|
||||
}
|
||||
|
||||
impl Vars {
|
||||
pub fn new(program_name: &str, options: &[&str]) -> Result<Vars, Error> {
|
||||
let mut opts: HashMap<String, bool> = HashMap::new();
|
||||
let mut args: VecDeque<String> = VecDeque::new();
|
||||
pub fn vars(program_name: &str, options: &[&str]) -> Result<Vars, Error> {
|
||||
let mut opts: HashMap<String, Token> = HashMap::new();
|
||||
let mut args: VecDeque<Token> = VecDeque::new();
|
||||
let mut tokens: Vec<Token> = Vec::new();
|
||||
let mut longest_token_len: usize = 0;
|
||||
|
||||
for opt in options.iter() {
|
||||
let token = match Token::new(opt) {
|
||||
let token = match token(opt) {
|
||||
Ok(t) => t,
|
||||
Err(why) => return Err(why)
|
||||
};
|
||||
|
||||
if !token.is_group {
|
||||
if token.is_arg {
|
||||
args.push_back(String::from(token.name()));
|
||||
args.push_back(token.clone());
|
||||
} else {
|
||||
opts.insert(String::from(token.name()), token.has_arg);
|
||||
if !token.short_name.is_empty() {
|
||||
opts.insert(token.short_name.clone(), token.clone());
|
||||
}
|
||||
|
||||
if !token.long_name.is_empty() {
|
||||
opts.insert(token.long_name.clone(), token.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let token_len = token.len();
|
||||
|
@ -62,18 +67,29 @@ impl Vars {
|
|||
tokens.push(token);
|
||||
}
|
||||
|
||||
opts.insert(String::from("-h"), false);
|
||||
opts.insert(String::from("--help"), false);
|
||||
let help_token = Token {
|
||||
short_name: String::from("h"),
|
||||
long_name: String::from("help"),
|
||||
description: String::from("Display usage information"),
|
||||
is_arg: false,
|
||||
has_arg: false,
|
||||
is_group: false,
|
||||
padding: 0
|
||||
};
|
||||
|
||||
opts.insert(String::from("-h"), help_token.clone());
|
||||
opts.insert(String::from("--help"), help_token.clone());
|
||||
|
||||
Ok(Vars {
|
||||
opts: opts,
|
||||
args: args,
|
||||
tokens: tokens,
|
||||
program_name: program_name
|
||||
program_name: String::from(program_name)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_opt(&self, opt_name: &String) -> Option<&bool> {
|
||||
impl Vars {
|
||||
pub fn get_opt(&self, opt_name: &String) -> Option<&Token> {
|
||||
self.opts.get(opt_name)
|
||||
}
|
||||
|
||||
|
@ -81,11 +97,15 @@ impl Vars {
|
|||
self.opts.contains_key(opt)
|
||||
}
|
||||
|
||||
pub fn get_arg(&mut self) -> Option<String> {
|
||||
pub fn get_arg(&mut self) -> Option<Token> {
|
||||
self.args.pop_front()
|
||||
}
|
||||
|
||||
pub fn arg_len(&self) -> usize {
|
||||
self.args.len()
|
||||
}
|
||||
|
||||
pub fn tokens(&self) -> Iter<Token>{
|
||||
self.tokens.iter()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
extern crate pirate;
|
||||
|
||||
use pirate::{Matches, usage, Vars};
|
||||
use std::env;
|
||||
|
||||
use pirate::{matches, vars};
|
||||
|
||||
fn main() {
|
||||
let opts = vec!["n:", "b/boop", ":input"];
|
||||
let mut vars = match Vars::new(&opts) {
|
||||
Ok(v) => v,
|
||||
Err(why) => {
|
||||
println!("{}", why);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let matches = match Matches::new(&mut vars) {
|
||||
let env_args: Vec<String> = env::args().collect();
|
||||
let opts = vec!["o/opt(An option)", "a(Argument):"];
|
||||
let mut vars = vars("A Test Program", &opts).unwrap();
|
||||
|
||||
let matches = match matches(&mut vars, &env_args) {
|
||||
Ok(m) => m,
|
||||
Err(why) => {
|
||||
println!("{}", why);
|
||||
return;
|
||||
}
|
||||
Err(why) => panic!("An error occurred: {}", why)
|
||||
};
|
||||
|
||||
if matches.has_arg("-h") || matches.has_arg("--help") {
|
||||
usage(&vars);
|
||||
return;
|
||||
if matches.has_match("a") {
|
||||
let m = matches.get("a").unwrap();
|
||||
println!("{}", m);
|
||||
}
|
||||
|
||||
match matches.get("opt") {
|
||||
Some(_) => println!("Opt was passed to the program"),
|
||||
None => println!("Opt was not passed to the program")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue