adblock-list-compiler 0.0.8

CLI tool to compile multiple adblock list sources into a single file
Documentation
use lazy_static::lazy_static;
use regex::Regex;

use super::Domain;

#[derive(Debug, PartialEq, Eq)]
pub struct Host {
    ip: String,
    domain: Domain,
}

pub fn parse_host(value: &str) -> Option<Host> {
    lazy_static! {
        static ref RE: Regex = Regex::new(
            r"(?P<ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+(?P<domain>.{2,200}\.[a-z]{2,6})"
        )
        .unwrap();
    }

    let captures = match RE.captures(value) {
        Some(c) => c,
        None => return None,
    };

    match (captures.name("ip"), captures.name("domain")) {
        (Some(ip), Some(domain)) => {
            let ip = ip.as_str().trim().to_string();
            let domain = domain.as_str().trim().to_string();

            let domain = match Domain::parse(&domain) {
                Some(domain) => domain,
                None => return None,
            };

            Some(Host { ip, domain })
        }
        _ => None,
    }
}

impl Host {
    pub fn parse(value: &str) -> Option<Self> {
        parse_host(value)
    }

    pub fn into_domain(self) -> Domain {
        self.domain
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    fn test_parse_host_some(input: &str, expected_ip: &str, expected_domain: &str) {
        let expected = Some(Host {
            ip: expected_ip.to_string(),
            domain: Domain(expected_domain.to_string()),
        });
        let output = parse_host(input);
        assert_eq!(output, expected);
    }

    #[test]
    fn it_extract_domain() {
        test_parse_host_some("127.0.0.1 abc.example.com", "127.0.0.1", "abc.example.com");
        test_parse_host_some("0.0.0.0 abc.example.com", "0.0.0.0", "abc.example.com");
        test_parse_host_some(
            "127.0.0.1 Bücher.example.com",
            "127.0.0.1",
            "xn--bcher-kva.example.com",
        );
    }
}