diff --git a/Makefile b/Makefile index 0e00fe8..b476e88 100644 --- a/Makefile +++ b/Makefile @@ -10,17 +10,17 @@ AGNOSTIC_TEST_IDS = `seq 1 3` docopt: $(objects) -docopt.so: docopt.rs docopt.rc - $(RUSTC) -L ./rust-pcre docopt.rc +docopt.so: docopt.rs + $(RUSTC) docopt.rs -test_docopt: docopt.rs docopt.rc - $(RUSTC) docopt.rc --test -o test_docopt -L ./ -L ./rust-pcre +test_docopt: docopt.rs + $(RUSTC) docopt.rs --test -o test_docopt run_tests: ./test_docopt agnostic_testee: agnostic_testee.rs - $(RUSTC) agnostic_testee.rs -L ./ -L ./rust-pcre + $(RUSTC) agnostic_testee.rs -L ./ run_agnostic_tests: python ./python_docopt/language_agnostic_test/language_agnostic_tester.py ./agnostic_testee $(AGNOSTIC_TEST_IDS) diff --git a/README.rst b/README.rst index abefedd..be5693c 100644 --- a/README.rst +++ b/README.rst @@ -9,7 +9,7 @@ This is a port of Python docopt library http://github.com/docopt/docopt Requirements ------------- -- Rust >= 0.4 // using bleeding-edge master branch of Rust +- Rust >= 0.8 // using bleeding-edge master branch of Rust - GNU Make == 3.81 // you can try other versions as well @@ -17,8 +17,7 @@ Building & tests ---------------- Run following commands to init and update git submodules:: - git submodule init - git submodule update + git submodule update --init To build and run language agnostic tests:: diff --git a/agnostic_testee.rs b/agnostic_testee.rs index 7b3eeb5..c9b7e2a 100644 --- a/agnostic_testee.rs +++ b/agnostic_testee.rs @@ -1,37 +1,38 @@ extern mod std; extern mod docopt; -use io::{ReaderUtil, WriterUtil}; -use send_map::linear::LinearMap; -use std::json::LinearMap; - +use std::rt::io; +use std::str; /// Reads whole stream and outputs it as string -fn read_whole_stream_to_str(input_stream: io::Reader) -> ~str { +fn read_whole_stream_to_str(input_stream: &mut io::Reader) -> ~str { let mut buf = ~[]; - loop { - let ch = input_stream.read_byte(); - if input_stream.eof() { break; } - buf.push(ch as u8); + do std::rt::io::io_error::cond.trap(|_| ()).inside { + loop { + match input_stream.read_byte() { + Some(c) => buf.push(c as char), + None => break, + } + } } - str::from_bytes(buf) + str::from_chars(buf) } fn main () { - let input_stream = io::stdin(); + let mut input_stream = io::stdin(); - let doc: ~str = read_whole_stream_to_str(input_stream); + let doc: ~str = read_whole_stream_to_str(&mut input_stream as &mut io::Reader); - let docopt_result = docopt::docopt(copy doc); + let docopt_result = docopt::docopt(doc.clone()); match docopt_result { - Ok(options) => io::println(options.to_json().to_str()), + Ok(options) => io::println(format!("{}", options.to_str())), Err(error_message) => io::println(error_message) } /* Testing various things */ - io::println(docopt::printable_usage(copy doc)); + io::println(docopt::printable_usage(doc.clone())); } diff --git a/docopt.rc b/docopt.rc deleted file mode 100644 index 697ad7b..0000000 --- a/docopt.rc +++ /dev/null @@ -1,6 +0,0 @@ -#[link(name = "docopt", - vers = "0.1", - author = "Kirill Panshin")]; -#[crate_type = "lib"]; - -extern mod std; diff --git a/docopt.rs b/docopt.rs index 85200ef..7ed367e 100644 --- a/docopt.rs +++ b/docopt.rs @@ -1,52 +1,57 @@ -use cmp::Eq; -use str::str; +#[link(name = "docopt", + vers = "0.1", + author = "Kirill Panshin")]; +#[crate_type = "lib"]; -use std::map::Map; -use send_map::linear::LinearMap; -use std::json; +extern mod std; +extern mod extra; +use std::cmp::Eq; +use std::hashmap::HashMap; +use std::str; +use extra::json; -use std::json::ToJson; +use extra::json::ToJson; //Toplevel public function for parsing. Args are taken from os::args() -pub fn docopt(doc: ~str) -> Result, ~str> { +pub fn docopt(doc: ~str) -> Result, ~str> { - let argv = os::args(); - docopt_ext(copy doc, copy argv) + let argv = std::os::args(); + docopt_ext(doc.clone(), argv.clone()) } /// Toplevel public function for parsing doc. Arguments passed explicitly -pub fn docopt_ext(doc: ~str, argv: ~[~str]) -> Result, ~str> { +pub fn docopt_ext(doc: ~str, argv: ~[~str]) -> Result, ~str> { - let mut options = LinearMap(); + let mut options = HashMap::new(); /* TODO: insert data to map here */ options.insert(~"Arguments", argv.to_json()); if doc == ~"trigger_error" { - Err(str::append(~"Error: ", doc)) + Err(format!("Error: {}", doc)) } else { - Ok(move options) + Ok(options) } } pub struct Option { - mut short: ~str, - mut long: ~str, - mut argcount: int, - mut value: ~str + short: ~str, + long: ~str, + argcount: int, + value: ~str } /// Parse token and return option object pub fn Option(short: ~str, long: ~str, argcount: int, value: ~str) -> Option { Option { - short: move short, - long: move long, - argcount: move argcount, - value: move value + short: short, + long: long, + argcount: argcount, + value: value } } @@ -64,26 +69,27 @@ pub fn get_option() -> Option { impl Option { /// Parse token and return option object - fn parse(option_description: &str) { - let splitted = str::split_str_nonempty( - option_description.trim(), ~" "); - let mut (options, description) = match splitted.len() { - 1 => (copy splitted[0], ~""), - 2 => (copy splitted[0], copy splitted[1]), - _ => {io::println("Error: double space must appear only once"); - fail}// Handle this situation more gracefully + fn parse(&mut self, option_description: &str) { + let splitted = option_description.trim().split_str_iter(" ").to_owned_vec(); + let (options, description) = match splitted.len() { + 1 => (splitted[0].to_owned(), ~""), + 2 => (splitted[0].to_owned(), splitted[1].to_owned()), + _ => {fail!("Error: double space must appear only once"); + }// Handle this situation more gracefully }; - let options = str::replace(options, ~",", ~" "); - let options = str::replace(options, ~"=", ~" "); - let splitted = str::split_char_nonempty(options, ' '); + let options = str::replace(options, ",", " "); + let options = str::replace(options, "=", " "); + let splitted = options.split_iter(' ').to_owned_vec(); - for splitted.each() |part| { - if str::starts_with(*part, ~"--") { - self.long = copy *part; + for part in splitted.iter() { + if *part == "" { + // pass + } else if part.starts_with("--") { + self.long = part.to_owned(); } - else if str::starts_with(*part, ~"-") { - self.short = copy *part; + else if part.starts_with("-") { + self.short = part.to_owned(); } else { self.argcount = 1; @@ -91,13 +97,13 @@ impl Option { } if self.argcount > 0 { - let splitted_desc = description.split_str(~"[default: "); + let splitted_desc = description.split_str_iter("[default: ").to_owned_vec(); self.value = match splitted_desc.len() { 1 => {~""}, - 2 => {splitted_desc[1].split_char(']')[0]}, - _ => {io::println("Error: [default: VALUE] must \ - appear only once"); - fail} // May be handle this more gracefully + 2 => {splitted_desc[1].split_iter(']').nth(0).unwrap().to_owned()}, + _ => {fail!("Error: [default: VALUE] must \ + appear only once"); + } // May be handle this more gracefully }; } // TODO: parse default value '\[default: (.*)\]' @@ -107,30 +113,30 @@ impl Option { } -impl Option: Eq { +impl Eq for Option { #[inline(always)] - pure fn eq(other: &Option) -> bool { + fn eq(&self, other: &Option) -> bool { ((self.short == other.short) && (self.long == other.long) && (self.argcount == other.argcount) && (self.value == other.value)) } #[inline(always)] - pure fn ne(other: &Option) -> bool { !self.eq(other) } + fn ne(&self, other: &Option) -> bool { !self.eq(other) } } /// Print usage pub fn printable_usage(doc: ~str) -> ~str { - let splitted = str::split_str_nonempty(doc, ~"Usage:"); + let splitted = doc.split_str_iter("Usage:").to_owned_vec(); let (word_usage, usage) =match splitted.len() { - 1 => (copy splitted[0], ~""), - 2 => (copy splitted[0], copy splitted[1]), - _ => {io::println("Error in description: ``Usage:`` \ - must appear only once"); - fail // Handle more gracefully + 1 => (splitted[0].to_owned(), ~""), + 2 => (splitted[0].to_owned(), splitted[1].to_owned()), + _ => {fail!("Error in description: ``Usage:`` \ + must appear only once"); + // Handle more gracefully } }; - fmt!("%s%s", word_usage, usage) + format!("{}{}", word_usage, usage) } @@ -138,11 +144,12 @@ pub fn printable_usage(doc: ~str) -> ~str { mod tests { fn check_option(token: ~str, option_args: (~str, ~str, int, ~str)) { - let option = get_option(); + let mut option = super::get_option(); option.parse(token); - let (short, long, argcount, value) = copy option_args; - assert option == Option(copy short, copy long, - copy argcount, copy value); + let (short, long, argcount, value) = option_args; + assert!(option == super::Option(short.clone(), long.clone(), + argcount.clone(), value.clone()), + "Parsing: {}", token); } #[test] @@ -176,13 +183,13 @@ mod tests { #[test] fn test_docopt_ext_ok() { - let result = docopt_ext(~"Usage: my_program", ~[]); - assert result.is_ok(); + let result = super::docopt_ext(~"Usage: my_program", ~[]); + assert!(result.is_ok()); } // #[test] // fn test_docopt_ext_err() { - // let result = docopt::docopt_ext(~"Usage: my_program", ~[~"-h"]); + // let result = super::docopt::docopt_ext(~"Usage: my_program", ~[~"-h"]); // assert result.is_err(); // }