-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Add str::contains_all function #147
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -288,3 +288,81 @@ where | |
pattern: pattern.into(), | ||
} | ||
} | ||
|
||
/// Predicate that checks for all patterns. | ||
/// | ||
/// This is created by `predicates::str:contains_all`. | ||
#[derive(Debug, Clone, PartialEq, Eq)] | ||
pub struct ContainsAllPredicate { | ||
patterns: Vec<String>, | ||
} | ||
|
||
impl Predicate<str> for ContainsAllPredicate { | ||
fn eval(&self, variable: &str) -> bool { | ||
for pattern in &self.patterns { | ||
if !variable.contains(pattern) { | ||
return false; | ||
} | ||
} | ||
|
||
true | ||
} | ||
|
||
fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option<reflection::Case<'a>> { | ||
let mut missing = None; | ||
|
||
for pattern in &self.patterns { | ||
if !variable.contains(pattern) && !expected { | ||
missing = Some(pattern) | ||
} | ||
} | ||
|
||
match missing { | ||
Some(m) => Some( | ||
reflection::Case::new(Some(self), false) | ||
.add_product(reflection::Product::new("missing", m.to_owned())), | ||
), | ||
None => None, | ||
} | ||
} | ||
} | ||
|
||
impl reflection::PredicateReflection for ContainsAllPredicate {} | ||
|
||
impl fmt::Display for ContainsAllPredicate { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
let palette = crate::Palette::new(f.alternate()); | ||
write!( | ||
f, | ||
"{}.{}({})", | ||
palette.var("var"), | ||
palette.description("contains_all"), | ||
palette.expected(format!("{:?}", &self.patterns)), | ||
) | ||
} | ||
} | ||
|
||
/// Creates a new `Predicate` that ensures a str contains `pattern` | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// use predicates::prelude::*; | ||
/// | ||
/// let predicate_fn = predicate::str::contains_all(vec!["One", "Two", "Three"]); | ||
/// assert_eq!(true, predicate_fn.eval("One Two Three")); | ||
/// assert_eq!(false, predicate_fn.eval("One Two Four")); | ||
/// assert_eq!(false, predicate_fn.eval("Four Five Six")); | ||
/// ``` | ||
Comment on lines
+352
to
+356
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whats the use case for this vs just doing multiple There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using multiple There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In a way, this is a special casing of other predicates (anding a bunch of contains) and I'm trying to understand when we are justified in baking that in vs having people build it up from other parts. Speaking of, I wonder if we should implement There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, that could work. However, this again breaks when the user reaches N, with N being the maximum number of items in a tuple we implemented There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tuples can be composed of tuples. And for a case like this, the types will all be the same, so we could also support arrays |
||
pub fn contains_all<P, T>(patterns: P) -> ContainsAllPredicate | ||
where | ||
P: IntoIterator<Item = T>, | ||
T: AsRef<str>, | ||
{ | ||
let patterns: Vec<_> = patterns | ||
.into_iter() | ||
.map(|p| p.as_ref().to_string()) | ||
.collect(); | ||
|
||
ContainsAllPredicate { patterns } | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we do this, we should probably have a
find_case
implementation to either report which items matched so people don't have to manually scan the string for themThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I will look into this!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a basic
find_case
impl. I'm unsure if the current impl does what this function expects. This is because I'm not quite sure how it integrates into thepredicates-rs
ecosystem.But, the implementation can be improved by implementing
reflection::PredicateReflection
andfmt::Display
forContainsAllPredicate
.