faclair 0.1.0

HTTP Client for the learngaelic.scot Scottish Gaelic dictionary
Documentation
#![deny(warnings, missing_docs, missing_copy_implementations, missing_debug_implementations)]

//! This is a client that can be used to search the learngaelic.scot/dictionary Scottish Gaelic
//! Dictionary

/// Make a search using the default options
///
/// # Example
///
/// ```rust,no_run
/// # fn main() -> Result<(), faclair::Error> {
/// let search_result = faclair::search("saor")?;
/// assert_eq!(search_result[0].translation, "1 free, liberate! 2 absolve! 3 exempt!");
/// #   Ok(())
/// # }
/// ```
pub fn search(query: &str) -> Result<Vec<SearchResult>, Error> {
    search_with_options(query, Options::default())
}

/// Search for a gaelic word or phrase, providing additional options for the search
pub fn search_with_options(query: &str, options: Options) -> Result<Vec<SearchResult>, Error> {
    let language = options.language.to_string();
    Ok(ureq::post("https://learngaelic.scot/dictionary/search")
        .send_form(&[
            ("abairt", query),
            ("slang", &language[..]),
            ("wholeword", if options.whole_word { "true" } else { "false" }),
        ])?
        .into_json()?)
}

/// Possible values for the 'language' option
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Language {
    /// en
    English,
    /// gd
    Gaelic,
    /// both
    Both,
}
impl std::fmt::Display for Language {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        use Language::*;
        Ok(match self {
            English => f.write_fmt(format_args!("en"))?,
            Gaelic => f.write_fmt(format_args!("gd"))?,
            Both => f.write_fmt(format_args!("both"))?,
        })
    }
}

/// A single result of a search
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct SearchResult {
    /// Entry ID
    pub id: usize,
    /// Search result
    pub headword: String,
    /// *unknown*
    pub source: Option<String>,
    /// The translation of the search result
    pub translation: String,
    /// Grammar information
    pub grammar: String,
    /// IPA Pronunciation information
    pub ipa: String,
    /// *unknown*
    pub wordclass: String,
    #[serde(rename = "hasAudio")]
    /// Whether there is audio for the result or not
    pub has_audio: bool,
    #[serde(rename = "audioVersion")]
    /// Version of the audio
    pub audio_version: usize,
    #[serde(rename = "gdKeys")]
    /// *unknown*
    pub gd_keys: Option<String>,
    #[serde(rename = "enKeys")]
    /// *unknown*
    pub en_keys: Option<String>,
    #[serde(rename = "commitMessage")]
    /// *unknown*
    pub commit_message: Option<String>,
}


/// Additional search options
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Options {
    whole_word: bool,
    language: Language,
}
impl Options {
    /// Specify that we should search for the whole word only
    pub fn whole_word(&mut self) -> &mut Options {
        self.whole_word = true;
        self
    }
    /// Specify whether to search both english and gaelic
    pub fn language(&mut self, language: Language) -> &mut Options {
        self.language = language;
        self
    }
}
impl std::default::Default for Options {
    fn default() -> Options {
        Options {
            whole_word: false,
            language: Language::Gaelic,
        }
    }
}

/// Possible errors
#[derive(Debug, Display)]
pub enum Error {
    /// An error from the ureq http client library
    Ureq(ureq::Error),
    /// An error from the standard library's IO module
    Io(std::io::Error),
}
impl std::error::Error for Error {}
impl From<std::io::Error> for Error {
    fn from(e: std::io::Error) -> Error {
        Error::Io(e)
    }
}
impl From<ureq::Error> for Error {
    fn from(e: ureq::Error) -> Error {
        Error::Ureq(e)
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        let result = super::search("saor").expect("Problem when searching for 'saor'");
        assert_eq!(result[0].translation, "1 free, liberate! 2 absolve! 3 exempt!");
    }
}

use derive_more::Display;
use serde::{Deserialize, Serialize};