-
Notifications
You must be signed in to change notification settings - Fork 73
Are “Cucumber Expressions” supported ? #124
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
Comments
I do not believe so. Might be something for someone to investigate. 😄 |
@ilslv what do you think? I think this can be fully done on proc macro layer by simply translating cucumber expresion into regex during macro expansion. We don't even need to touch type machinery here. |
That would be the sanest way to do it. |
The proposed syntax may be |
@tyranron sounds like the way to do it. I propose adding support for Parameter types and leaving custom parameters for already existing So Kotlin's example @ParameterType("red|blue|yellow") // regexp
fun color(color: String): Color { // name (from method), type
return Color(color) // transformer function
} will be implemented as follows: #[then(expr = "I have {string} eyes")]
fn eyes_color(w: &mut World, color: Color) {
// ...
}
enum Color {
// ...
}
impl FromStr for Color {
// ...
} |
Quoted from #157 (comment) For custom parameters I propose something like this enum Animal {
Cat,
Dog,
Ferris,
}
impl FromStr for Animal {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"cat" => Ok(Self::Cat),
"dog" => Ok(Self::Dog),
"🦀" => Ok(Self::Ferris),
_ => Err("expected 'cat', 'dog' or '🦀'"),
}
}
}
impl CustomParameter for Animal {
const NAME = "animal";
const REGEX = "cat|dog|🦀";
}
#[then(expr = "the {animal} is not hungry")]
async fn cat_is_fed(world: &mut AnimalWorld, animal: Animal) {
sleep(Duration::from_secs(2)).await;
match animal {
Animal::Cat => assert!(!world.cat.hungry),
Animal::Dog => assert!(!world.dog.hungry),
Animal::Ferris => assert!(!world.ferris.hungry),
};
} With that we can validate that parameter name is right with const assertion. And to validate regex we can even use clippy lint : Playground. UPD: Clippy lint will require our users to run it over tests codebase, which is rarely done. If we want to avoid this, we'll have to implement |
@ilslv well, in code it would be nice to have something like this: #[derive(cucumber::Parameter)]
#[param(regex = "cat|dog|🦀")] // `name = ` is optional,
enum Animal { // by default we may use `lowercased(ty.ident)`
Cat,
Dog,
Ferris,
}
impl FromStr for Animal {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"cat" => Ok(Self::Cat),
"dog" => Ok(Self::Dog),
"🦀" => Ok(Self::Ferris),
_ => Err("expected 'cat', 'dog' or '🦀'"),
}
}
} Regarding
So, when we expand This way we have compile-time guarantees and cheks, while preserving obvious and ergonomic API for users. Do I miss something? |
@tyranron pretty much yes, but I would change couple of things:
In addition to validating we should check that regex doesn't contain capture groups itself. Because in case it is, those capture groups will be mapped onto the next step function argument.
Or we can just create Also we should const assert that |
Seems reasonable. But we still should allow Another way is just silently transform
As a simplest way to do so - yes. But I proposed that way with a better errors redability in mind, if it applies though.
If we allow it to happen, it just won't work soundly. Having a |
With merging #168 now is fully implemented and will be released in 0.11. |
I couldn't find any references to them, in documentation, examples or even implementation code.
For the record, Cucumber Expressions are the usual way to write step definitions in most languages, it's slightly less powerful than Regex but much more readable.
For example consider:
vs
(Float regex matcher taken from Stackoverflow)
The text was updated successfully, but these errors were encountered: