///|
/// A step pattern: a Cucumber Expression or a regular expression.
pub(all) enum StepExpression {
Cucumber(Expression)
Regular(RegularExpression)
}
///|
/// The source of the expression.
pub fn StepExpression::source(self : StepExpression) -> String {
match self {
Cucumber(e) => e.source()
Regular(e) => e.source()
}
}
///|
/// Match the expression against a text.
pub fn StepExpression::match_(
self : StepExpression,
text : String,
) -> Match? raise {
match self {
Cucumber(e) => e.match_(text)
Regular(e) => e.match_(text)
}
}
///|
/// Makes a Cucumber Expression or a regular expression from a string, with
/// the same rules as the reference Java implementation:
///
/// - A string that starts with `^` or ends with `$` is a regular expression.
/// - A string that starts and ends with `/` is a regular expression without
/// the slashes.
/// - All other strings are Cucumber Expressions.
pub(all) struct ExpressionFactory {
priv registry : ParamTypeRegistry
}
///|
pub fn ExpressionFactory::new(
registry : ParamTypeRegistry,
) -> ExpressionFactory {
{ registry, }
}
///|
/// Make an expression from a string.
pub fn ExpressionFactory::create_expression(
self : ExpressionFactory,
expression : String,
) -> StepExpression raise ExpressionError {
let length = expression.length()
if length == 0 {
return Cucumber(Expression::parse_with_registry(expression, self.registry))
}
if expression.has_prefix("^") || expression.has_suffix("$") {
let regex = RegularExpression::new(expression, registry=self.registry) catch {
ValidationError(..) if has_parameter(expression) =>
raise ExpressionError::ValidationError(
position=0,
message="You cannot use anchors (^ or $) in Cucumber Expressions. Please remove them from \{expression}",
)
e => raise e
}
return Regular(regex)
}
if length >= 2 && expression.has_prefix("/") && expression.has_suffix("/") {
let inner = expression
.view(start_offset=1, end_offset=length - 1)
.to_owned()
return Regular(RegularExpression::new(inner, registry=self.registry))
}
Cucumber(Expression::parse_with_registry(expression, self.registry))
}
///|
/// True when the text has something that looks like a parameter, for
/// example `{int}`.
fn has_parameter(text : String) -> Bool {
guard text.find("{") is Some(start) else { return false }
text.view(start_offset=start).contains("}")
}