Skip to content

Commit 84eb9fb

Browse files
committed
feat(str): Edit-distance predicate
This will be more helpful when assert-rs#7 is implemented. Fixes assert-rs#9
1 parent d65bf5b commit 84eb9fb

File tree

5 files changed

+164
-1
lines changed

5 files changed

+164
-1
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ travis-ci = { repository = "assert-rs/predicates-rs" }
1818
appveyor = { repository = "assert-rs/predicates-rs" }
1919

2020
[dependencies]
21+
difference = { version = "2.0", optional = true }
2122

2223
[features]
23-
default = []
24+
default = ["difference"]
2425
unstable = []

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@
8585
8686
#![deny(missing_docs, missing_debug_implementations)]
8787

88+
#[cfg(feature = "difference")]
89+
extern crate difference;
90+
8891
// core `Predicate` trait
8992
pub mod predicate;
9093
pub use self::predicate::{BoxPredicate, Predicate};

src/predicate/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ pub use self::ord::{eq, ge, gt, le, lt, ne, EqPredicate, OrdPredicate};
2222
pub use self::set::{contains, contains_hashable, contains_ord, ContainsPredicate,
2323
HashableContainsPredicate, OrdContainsPredicate};
2424

25+
// specialized primitive `Predicate` types
26+
pub mod str;
27+
2528
// combinators
2629
mod boolean;
2730
mod boxed;

src/predicate/str/difference.rs

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// Copyright (c) 2018 The predicates-rs Project Developers.
2+
//
3+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6+
// option. This file may not be copied, modified, or distributed
7+
// except according to those terms.
8+
9+
use std::borrow;
10+
11+
use difference;
12+
13+
use Predicate;
14+
15+
#[derive(Clone, Copy, Debug)]
16+
enum DistanceOp {
17+
Similar,
18+
Different,
19+
}
20+
21+
impl DistanceOp {
22+
fn eval(self, limit: i32, distance: i32) -> bool {
23+
match self {
24+
DistanceOp::Similar => distance <= limit,
25+
DistanceOp::Different => limit < distance,
26+
}
27+
}
28+
}
29+
30+
/// Predicate that diffs two strings.
31+
///
32+
/// This is created by the `predicate::str::similar`.
33+
#[derive(Clone, Debug)]
34+
pub struct DifferencePredicate {
35+
orig: borrow::Cow<'static, str>,
36+
split: borrow::Cow<'static, str>,
37+
distance: i32,
38+
op: DistanceOp,
39+
}
40+
41+
impl DifferencePredicate {
42+
/// The split used when identifying changes.
43+
///
44+
/// Common splits include:
45+
/// - `""` for char-level.
46+
/// - `" "` for word-level.
47+
/// - `"\n" for line-level.
48+
///
49+
/// Default: `"\n"`
50+
///
51+
/// # Examples
52+
///
53+
/// ```
54+
/// use predicates::predicate::*;
55+
///
56+
/// let predicate_fn = str::similar("Hello World").split(" ");
57+
/// assert_eq!(true, predicate_fn.eval("Hello World"));
58+
/// ```
59+
pub fn split<S>(mut self, split: S) -> Self
60+
where
61+
S: Into<borrow::Cow<'static, str>>,
62+
{
63+
self.split = split.into();
64+
self
65+
}
66+
67+
/// The maximum allowed edit distance.
68+
///
69+
/// Default: `0`
70+
///
71+
/// # Examples
72+
///
73+
/// ```
74+
/// use predicates::predicate::*;
75+
///
76+
/// let predicate_fn = str::similar("Hello World!").split("").distance(1);
77+
/// assert_eq!(true, predicate_fn.eval("Hello World!"));
78+
/// assert_eq!(true, predicate_fn.eval("Hello World"));
79+
/// assert_eq!(false, predicate_fn.eval("Hello World?"));
80+
/// ```
81+
pub fn distance(mut self, distance: i32) -> Self {
82+
self.distance = distance;
83+
self
84+
}
85+
}
86+
87+
impl Predicate for DifferencePredicate {
88+
type Item = str;
89+
90+
fn eval(&self, edit: &str) -> bool {
91+
let change = difference::Changeset::new(&self.orig, edit, &self.split);
92+
self.op.eval(self.distance, change.distance)
93+
}
94+
}
95+
96+
/// Creates a new `Predicate` that diffs two strings.
97+
///
98+
/// # Examples
99+
///
100+
/// ```
101+
/// use predicates::predicate::*;
102+
///
103+
/// let predicate_fn = str::diff("Hello World");
104+
/// assert_eq!(false, predicate_fn.eval("Hello World"));
105+
/// assert_eq!(true, predicate_fn.eval("Goodbye World"));
106+
/// ```
107+
pub fn diff<S>(orig: S) -> DifferencePredicate
108+
where
109+
S: Into<borrow::Cow<'static, str>>,
110+
{
111+
DifferencePredicate {
112+
orig: orig.into(),
113+
split: "\n".into(),
114+
distance: 0,
115+
op: DistanceOp::Different,
116+
}
117+
}
118+
119+
/// Creates a new `Predicate` that checks strings for how similar they are.
120+
///
121+
/// # Examples
122+
///
123+
/// ```
124+
/// use predicates::predicate::*;
125+
///
126+
/// let predicate_fn = str::similar("Hello World");
127+
/// assert_eq!(true, predicate_fn.eval("Hello World"));
128+
/// assert_eq!(false, predicate_fn.eval("Goodbye World"));
129+
/// ```
130+
pub fn similar<S>(orig: S) -> DifferencePredicate
131+
where
132+
S: Into<borrow::Cow<'static, str>>,
133+
{
134+
DifferencePredicate {
135+
orig: orig.into(),
136+
split: "\n".into(),
137+
distance: 0,
138+
op: DistanceOp::Similar,
139+
}
140+
}

src/predicate/str/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright (c) 2018 The predicates-rs Project Developers.
2+
//
3+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6+
// option. This file may not be copied, modified, or distributed
7+
// except according to those terms.
8+
9+
//! String Predicates
10+
//!
11+
//! This module contains predicates specifiuc to string handling.
12+
13+
#[cfg(feature = "difference")]
14+
mod difference;
15+
#[cfg(feature = "difference")]
16+
pub use self::difference::{diff, similar, DifferencePredicate};

0 commit comments

Comments
 (0)