cucumber-expressions

    Cucumber Expressions parser and matcher for MoonBit

    cucumber
    expressions
    bdd
    testing
    gherkin
    Download zip
    Author
    Version
    0.3.2
    License
    Apache-2.0
    Last updated
    7 months ago
    Downloads
    1K

    #moonrockz/cucumber-expressions

    A Cucumber Expressions parser and matcher for MoonBit. The simpler alternative to regular expressions used in BDD step definitions.

    #Installation

    moon add moonrockz/cucumber-expressions

    #Quick Start

    let expr = @cucumber-expressions.Expression::parse!("I have {int} cucumber(s) in my {word}")
    let m = expr.match_("I have 42 cucumbers in my basket").unwrap()
    // m.params[0].value => IntVal(42), m.params[0].raw => "42"
    // m.params[1].value => WordVal("basket"), m.params[1].raw => "basket"

    #Built-in Parameter Types

    All 11 types from the Cucumber Expressions specification:

    ParameterDescriptionExample matchValue type
    {int}Integers, optionally negative42, -1IntVal(Int)
    {float}Decimal and scientific notation3.14, -1.5e10FloatVal(Double)
    {double}Same as float3.14, 1.5e10DoubleVal(Double)
    {long}64-bit integers9223372036854775807LongVal(Int64)
    {byte}Byte-range integers127, 255ByteVal(Byte)
    {short}Short integers8080ShortVal(Int)
    {bigdecimal}Arbitrary-precision decimals99.99BigDecimalVal(Decimal)
    {biginteger}Arbitrary-precision integers12345678901234567890BigIntegerVal(BigInt)
    {string}Single- or double-quoted strings"hello", 'hi'StringVal(String)
    {word}A single word (no whitespace)bananaWordVal(String)
    {}Anonymous — matches anythingwhatever you wantAnonymousVal(String)

    let expr = @cucumber-expressions.Expression::parse!("{word} costs {float} dollars")
    let m = expr.match_("coffee costs 4.50 dollars").unwrap()
    // m.params[0].value => WordVal("coffee"), m.params[0].raw => "coffee"
    // m.params[1].value => FloatVal(4.5), m.params[1].raw => "4.50"

    #Optional Text

    Parentheses mark text as optional. This is useful for plurals:

    let expr = @cucumber-expressions.Expression::parse!("I have {int} cucumber(s)")
    expr.match_("I have 1 cucumber") // matches
    expr.match_("I have 5 cucumbers") // matches

    #Alternation

    Use / to match one of several alternatives:

    let expr = @cucumber-expressions.Expression::parse!("I have a cat/dog")
    expr.match_("I have a cat") // matches
    expr.match_("I have a dog") // matches

    #Custom Parameter Types

    Register your own named parameter types with ParamTypeRegistry. An optional transformer converts matched text into a typed value:

    let registry = @cucumber-expressions.ParamTypeRegistry::default()
    registry.register(
    "color",
    @cucumber-expressions.ParamType::Custom("color"),
    [@cucumber-expressions.RegexPattern("red|green|blue")],
    transformer=@cucumber-expressions.Transformer::new(fn(groups) {
    @cucumber-expressions.ParamValue::CustomVal(@any.of(groups[0]))
    }),
    )
    let expr = @cucumber-expressions.Expression::parse_with_registry!(
    "the {color} ball",
    registry,
    )
    let m = expr.match_("the red ball").unwrap()
    // m.params[0].value => CustomVal(<Any>), m.params[0].raw => "red"

    #Match Result

    Expression::match_ returns a Match?. A successful match contains an array of Param values in order. Each Param has:

    • value — typed ParamValue (pattern-matchable enum)
    • type_ — which ParamType matched
    • raw — original matched text as String

    let expr = @cucumber-expressions.Expression::parse!("{word} is {int}")
    match expr.match_("MoonBit is 1") {
    Some(m) => {
    let name = m.params[0] // { value: WordVal("MoonBit"), type_: Word, raw: "MoonBit" }
    let num = m.params[1] // { value: IntVal(1), type_: Int, raw: "1" }
    }
    None => println("no match")
    }

    #Error Handling

    Expression::parse raises ExpressionError, a suberror with these variants:

    VariantCause
    UnmatchedBraceMissing closing }
    UnmatchedParenMissing closing )
    CannotEscapeInvalid escape sequence
    UnexpectedEscapeEndBackslash at end of expression
    ValidationErrorStructural errors (empty alternation, nested optionals, etc.)
    UnknownParameterTypeUnregistered {name} in expression

    try {
    let _ = @cucumber-expressions.Expression::parse!("{unknown}")
    } catch {
    @cucumber-expressions.ExpressionError::UnknownParameterType(name=name, ..) =>
    println("Unknown parameter: " + name)
    }

    #License

    Apache-2.0

    ExpressionError

    pub suberror ExpressionError {
    UnmatchedBrace(Int, String)
    UnmatchedParen(Int, String)
    CannotEscape(Int, Char, String)
    UnexpectedEscapeEnd(Int, String)
    ValidationError(Int, String)
    UnknownParameterType(String, String)
    }

    Errors that can occur during cucumber expression parsing.

    Expression

    pub(all) struct Expression {
    // private fields
    }

    A parsed and compiled cucumber expression, ready for matching.

    Expression::match_

    fn Expression::match_(self : Expression, text : String) -> Match?

    Match this expression against a text string. Returns Some(Match) with extracted parameters, or None if no match.

    Expression::parse

    fn Expression::parse(expression : String) -> Expression raise ExpressionError

    Parse a cucumber expression with the default parameter type registry.

    Expression::parse_with_registry

    fn Expression::parse_with_registry(expression : String, registry : ParamTypeRegistry) -> Expression raise ExpressionError

    Parse a cucumber expression with a custom parameter type registry.

    Expression::source

    fn Expression::source(self : Expression) -> String

    Get the original expression source string.

    Match

    pub(all) struct Match {
    params : Array[Param]
    }

    A successful match result with extracted parameters.
    impl Eq for Match
    impl Show for Match

    Node

    pub(all) enum Node {
    TextNode(String)
    ParameterNode(String)
    OptionalNode(Array[Node])
    AlternationNode(Array[Array[Node]])
    ExpressionNode(Array[Node])
    }

    A single node in a cucumber expression AST.
    impl Eq for Node
    impl Show for Node
    impl ToJson for Node

    Param

    pub(all) struct Param {
    value : ParamValue
    type_ : ParamType
    raw : String
    }

    An extracted parameter value.
    impl Eq for Param
    impl Show for Param

    ParamType

    pub(all) enum ParamType {
    Int
    Float
    String_
    Word
    Anonymous
    Double_
    Long
    Byte
    Short
    BigDecimal
    BigInteger
    Custom(String)
    }

    Parameter types supported by cucumber expressions.
    impl Eq for ParamType
    impl Show for ParamType
    impl ToJson for ParamType

    ParamTypeEntry

    pub(all) struct ParamTypeEntry {
    name : String
    type_ : ParamType
    patterns : Array[RegexPattern]
    transformer : Transformer
    }

    A registered parameter type entry with name, type, regex patterns, and transformer.

    ParamTypeRegistry

    pub(all) struct ParamTypeRegistry {
    // private fields
    }

    Registry mapping parameter type names to their regex patterns.

    ParamTypeRegistry::default

    Create a registry with the 11 built-in parameter types pre-registered.

    ParamTypeRegistry::entries_view

    Read-only view of all registered parameter type entries.

    ParamTypeRegistry::get

    fn ParamTypeRegistry::get(self : ParamTypeRegistry, name : String) -> ParamTypeEntry?

    ParamTypeRegistry::new

    ParamTypeRegistry::register

    fn ParamTypeRegistry::register(self : ParamTypeRegistry, name : String, type_ : ParamType, patterns : Array[RegexPattern], transformer? : Transformer) -> Unit

    ParamValue

    pub(all) enum ParamValue {
    IntVal(Int)
    FloatVal(Double)
    DoubleVal(Double)
    LongVal(Int64)
    ByteVal(Byte)
    ShortVal(Int)
    StringVal(String)
    WordVal(String)
    AnonymousVal(String)
    BigDecimalVal(
    Decimal
    )
    BigIntegerVal(
    BigInt
    )
    CustomVal(
    Any
    )
    }

    A typed value produced by a transformer function. Built-in types have concrete variants for compile-time pattern matching. Custom types use CustomVal(@any.Any) for type-erased transformer results.

    RegexPattern

    pub(all) struct RegexPattern {
    // private fields

    fn new(value : String) -> RegexPattern
    }

    A regex pattern used for matching parameter types in cucumber expressions.
    impl Eq for RegexPattern

    RegexPattern::to_string

    fn RegexPattern::to_string(self : RegexPattern) -> String

    Token

    pub(all) enum Token {
    Text(String)
    BeginParameter
    EndParameter
    BeginOptional
    EndOptional
    Alternation
    WhiteSpace(String)
    }

    Tokens produced by the cucumber expression tokenizer.
    impl Eq for Token
    impl Show for Token

    Transformer

    pub(all) struct Transformer {
    // private fields
    }

    A transformer function that converts captured regex group strings into a typed ParamValue. Receives an array of captured group strings (arity matches capture groups in the regex).

    Transformer::call

    fn Transformer::call(self : Transformer, groups : Array[String]) -> ParamValue raise

    Transformer::new

    fn Transformer::new(f : (Array[String]) -> ParamValue raise) -> Transformer

    compile

    fn compile(node : Node, registry : ParamTypeRegistry) -> String raise ExpressionError

    Compile a cucumber expression AST to a regex pattern string.

    compile_expression

    fn compile_expression(expression : String, registry? : ParamTypeRegistry) -> String raise ExpressionError

    Parse a cucumber expression and compile it to a regex pattern string.

    parse_expression

    fn parse_expression(expression : String) -> Node raise ExpressionError

    Parse a cucumber expression string into an AST.

    tokenize

    fn tokenize(expression : String) -> Array[Token] raise ExpressionError

    Tokenize a cucumber expression string into an array of tokens.

    Converts the raw expression into a flat token stream. Does not validate matching braces or parentheses — that is the parser's responsibility.

    validate

    fn validate(node : Node) -> Unit raise ExpressionError

    Validate a parsed cucumber expression AST. Raises ValidationError for invalid expression structures.

    version

    fn version() -> String

    Cucumber Expressions for MoonBit.

    A parser and matcher for Cucumber Expressions, the simpler alternative to regular expressions used in BDD step definitions.