Repository: BurntSushi/ripgrep
File: src/args.rs (Rust)

Code before:
            try!(ovr.add(&glob));
        }
        ovr.build().map_err(From::from)
    }

    /// Builds a file type matcher from the command line flags.
    fn types(&self) -> Result<Types> {
        let mut btypes = TypesBuilder::new();
        btypes.add_defaults();
        for ty in self.values_of_lossy_vec("type-clear") {
            btypes.clear(&ty);
        }
        for def in self.values_of_lossy_vec("type-add") {
            try!(btypes.add_def(&def));
        }
        for ty in self.values_of_lossy_vec("type") {
            btypes.select(&ty);
        }
        for ty in self.values_of_lossy_vec("type-not") {
            btypes.negate(&ty);
        }
        btypes.build().map_err(From::from)
    }

    /// Parses the max-filesize argument option into a byte count.
    fn max_filesize(&self) -> Result<Option<u64>> {
        use regex::Regex;

        let max_filesize = match self.value_of_lossy("max-filesize") {
            Some(x) => x,
            None => return Ok(None)
        };

        let re = Regex::new(r#"^(\d+)([KMG])?$"#).unwrap();
        let caps = try!(re.captures(&max_filesize)
                          .ok_or("invalid format for max-filesize argument"));

        let value = match caps.get(1) {
            Some(value) => Some(try!(value.as_str().parse::<u64>())),
            None => None
        };
        let suffix = caps.get(2).map(|x| x.as_str());
        match suffix {
            None      => Ok(value),
            Some("K") => Ok(value.map(|x| x * 1024)),
            Some("M") => Ok(value.map(|x| x * 1024 * 1024)),
            Some("G") => Ok(value.map(|x| x * 1024 * 1024 * 1024)),
            _ => Err(From::from("invalid suffix for max-filesize argument"))
        }
    }


Review comment (suggestion):
This duplication isn't acceptable, sorry.

Please just get rid of the clap validator. The error can be reported from here. That will also get rid of the build dep on regex.

Code after:
            try!(ovr.add(&glob));
        }
        ovr.build().map_err(From::from)
    }

    /// Builds a file type matcher from the command line flags.
    fn types(&self) -> Result<Types> {
        let mut btypes = TypesBuilder::new();
        btypes.add_defaults();
        for ty in self.values_of_lossy_vec("type-clear") {
            btypes.clear(&ty);
        }
        for def in self.values_of_lossy_vec("type-add") {
            try!(btypes.add_def(&def));
        }
        for ty in self.values_of_lossy_vec("type") {
            btypes.select(&ty);
        }
        for ty in self.values_of_lossy_vec("type-not") {
            btypes.negate(&ty);
        }
        btypes.build().map_err(From::from)
    }

    /// Parses the max-filesize argument option into a byte count.
    fn max_filesize(&self) -> Result<Option<u64>> {
        use regex::Regex;

        let max_filesize = match self.value_of_lossy("max-filesize") {
            Some(x) => x,
            None => return Ok(None)
        };

        let re = Regex::new("^([0-9]+)([KMG])?$").unwrap();
        let caps = try!(re.captures(&max_filesize)
                          .ok_or("invalid format for max-filesize argument"));

        let value = try!(caps[1].parse::<u64>().map_err(|err| err.to_string()));
        let suffix = caps.get(2).map(|x| x.as_str());

        match suffix {
            None      => Ok(Some(value)),
            Some("K") => Ok(Some(value * 1024)),
            Some("M") => Ok(Some(value * 1024 * 1024)),
            Some("G") => Ok(Some(value * 1024 * 1024 * 1024)),
            _ => Err(From::from("invalid suffix for max-filesize argument"))
        }
    }

    /// Returns true if ignore files should be ignored.
    fn no_ignore(&self) -> bool {