Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 93 additions & 1 deletion matcher_rs/src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::collections::HashMap;

use crate::{MatchTable, Matcher, ProcessType, SimpleMatcher};
use crate::{MatchTable, MatchTableType, Matcher, ProcessType, SimpleMatcher};

/// A builder for constructing a `SimpleMatcher`.
///
Expand Down Expand Up @@ -52,6 +52,98 @@ impl<'a> SimpleMatcherBuilder<'a> {
}
}

/// A builder for constructing a single [`MatchTable`].
///
/// This builder provides a fluent, ergonomic API for building a [`MatchTable`]
/// without having to construct the struct literal directly. The two required
/// fields — `table_id` and `match_table_type` — are supplied upfront in
/// [`MatchTableBuilder::new`]; everything else is optional and can be added
/// incrementally before calling [`build`](MatchTableBuilder::build).
///
/// # Example
///
/// ```rust
/// use matcher_rs::{MatchTableBuilder, MatchTableType, ProcessType, MatcherBuilder};
///
/// let table = MatchTableBuilder::new(1, MatchTableType::Simple { process_type: ProcessType::None })
/// .add_word("hello")
/// .add_word("world")
/// .add_exemption_word("goodbye")
/// .build();
///
/// let matcher = MatcherBuilder::new()
/// .add_table(1, table)
/// .build();
/// ```
pub struct MatchTableBuilder<'a> {
table_id: u32,
match_table_type: MatchTableType,
word_list: Vec<&'a str>,
exemption_process_type: ProcessType,
exemption_word_list: Vec<&'a str>,
}

impl<'a> MatchTableBuilder<'a> {
/// Creates a new `MatchTableBuilder` with the two required fields.
///
/// # Arguments
///
/// * `table_id` - The unique identifier for the table.
/// * `match_table_type` - The matching strategy (Simple, Regex, or Similar).
pub fn new(table_id: u32, match_table_type: MatchTableType) -> Self {
Self {
table_id,
match_table_type,
word_list: Vec::new(),
exemption_process_type: ProcessType::None,
exemption_word_list: Vec::new(),
}
}

/// Appends a single word to the match word list.
pub fn add_word(mut self, word: &'a str) -> Self {
self.word_list.push(word);
self
}

/// Appends multiple words to the match word list.
pub fn add_words(mut self, words: impl IntoIterator<Item = &'a str>) -> Self {
self.word_list.extend(words);
self
}

/// Sets the [`ProcessType`] applied to exemption words.
///
/// Defaults to [`ProcessType::None`] if not called.
pub fn exemption_process_type(mut self, process_type: ProcessType) -> Self {
self.exemption_process_type = process_type;
self
}

/// Appends a single word to the exemption word list.
pub fn add_exemption_word(mut self, word: &'a str) -> Self {
self.exemption_word_list.push(word);
self
}

/// Appends multiple words to the exemption word list.
pub fn add_exemption_words(mut self, words: impl IntoIterator<Item = &'a str>) -> Self {
self.exemption_word_list.extend(words);
self
}

/// Consumes the builder and returns the configured [`MatchTable`].
pub fn build(self) -> MatchTable<'a> {
MatchTable {
table_id: self.table_id,
match_table_type: self.match_table_type,
word_list: self.word_list,
exemption_process_type: self.exemption_process_type,
exemption_word_list: self.exemption_word_list,
}
}
}

/// A builder for constructing a `Matcher`.
///
/// This builder provides a convenient way to construct a `Matcher` interpolator
Expand Down
2 changes: 1 addition & 1 deletion matcher_rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ mod util;
pub use util::word::SimpleWord;

mod builder;
pub use builder::{MatcherBuilder, SimpleMatcherBuilder};
pub use builder::{MatchTableBuilder, MatcherBuilder, SimpleMatcherBuilder};

mod process;
pub use process::process_matcher::{
Expand Down
115 changes: 114 additions & 1 deletion matcher_rs/tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ mod test_matcher {
use std::collections::HashMap;

use matcher_rs::{
MatchTable, MatchTableType, Matcher, MatcherBuilder, ProcessType, TextMatcherTrait,
MatchTable, MatchTableBuilder, MatchTableType, Matcher, MatcherBuilder, ProcessType,
TextMatcherTrait,
};

#[test]
Expand Down Expand Up @@ -249,6 +250,118 @@ mod test_matcher {
assert!(matcher.is_match("hello"));
assert!(!matcher.is_match("hello,world"))
}

#[test]
fn match_table_builder_simple() {
let table = MatchTableBuilder::new(
1,
MatchTableType::Simple {
process_type: ProcessType::None,
},
)
.add_word("hello")
.add_word("world")
.build();

let matcher = MatcherBuilder::new().add_table(1, table).build();
assert!(matcher.is_match("hello"));
assert!(matcher.is_match("world"));
assert!(!matcher.is_match("goodbye"));
}

#[test]
fn match_table_builder_add_words_bulk() {
let table = MatchTableBuilder::new(
2,
MatchTableType::Simple {
process_type: ProcessType::None,
},
)
.add_words(["foo", "bar", "baz"])
.build();

let matcher = MatcherBuilder::new().add_table(1, table).build();
assert!(matcher.is_match("foo"));
assert!(matcher.is_match("bar"));
assert!(matcher.is_match("baz"));
assert!(!matcher.is_match("qux"));
}

#[test]
fn match_table_builder_exemption() {
let table = MatchTableBuilder::new(
3,
MatchTableType::Simple {
process_type: ProcessType::None,
},
)
.add_word("hello")
.add_exemption_word("world")
.build();

let matcher = MatcherBuilder::new().add_table(1, table).build();
assert!(matcher.is_match("hello"));
assert!(!matcher.is_match("hello world"));
}

#[test]
fn match_table_builder_add_exemption_words_bulk() {
let table = MatchTableBuilder::new(
4,
MatchTableType::Simple {
process_type: ProcessType::None,
},
)
.add_word("hello")
.add_exemption_words(["world", "earth"])
.build();

let matcher = MatcherBuilder::new().add_table(1, table).build();
assert!(matcher.is_match("hello"));
assert!(!matcher.is_match("hello world"));
assert!(!matcher.is_match("hello earth"));
}

#[test]
fn match_table_builder_regex() {
use matcher_rs::RegexMatchType;

let table = MatchTableBuilder::new(
5,
MatchTableType::Regex {
process_type: ProcessType::None,
regex_match_type: RegexMatchType::Regex,
},
)
.add_word("h[aeiou]llo")
.add_word("w[aeiou]rld")
.build();

let matcher = MatcherBuilder::new().add_table(1, table).build();
assert!(matcher.is_match("hallo"));
assert!(matcher.is_match("world"));
assert!(!matcher.is_match("hxllo"));
}

#[test]
fn match_table_builder_similar() {
use matcher_rs::SimMatchType;

let table = MatchTableBuilder::new(
6,
MatchTableType::Similar {
process_type: ProcessType::None,
sim_match_type: SimMatchType::Levenshtein,
threshold: 0.8,
},
)
.add_word("helloworld")
.build();

let matcher = MatcherBuilder::new().add_table(1, table).build();
assert!(matcher.is_match("helloworl")); // one char off
assert!(!matcher.is_match("completely different"));
}
}

mod test_process {
Expand Down