Skip to content
This repository was archived by the owner on Jun 24, 2020. It is now read-only.
This repository was archived by the owner on Jun 24, 2020. It is now read-only.

Macro expansion in Clojure step defs #3

@mpkorstanje

Description

@mpkorstanje

From: cucumber/cucumber-jvm#631

I am trying to use a macro in a step definition, and instead of having access to the value passed in to my step definition I get a symbol.

This is perhaps nothing more than me being relatively new to Clojure but it's certainly unexpected.

Given the the following scenario:

Scenario: Using macros inside step defintions
  Given my words are replaced:
  """
  My word is %{word}
  """

When I run my cukes with a step defintion like:

;; Step definition
(defmacro fmt [^String string]
  (let [-re #"%\{(.*?)\}"
        fstr (clojure.string/replace string -re "%s")
        fargs (map #(read-string (second %)) (re-seq -re string))]
    `(format ~fstr ~@fargs)))

(Given #"my words are replaced:" [string]
  (let [word "interpolated"]
    (assert (= (fmt string) "My word is interpolated")))

Then I get an error of:

Caused by: java.lang.ClassCastException: clojure.lang.Symbol cannot be cast to java.lang.CharSequence
    at clojure.core$re_matcher.invoke(core.clj:4386)
    at clojure.core$re_seq.invoke(core.clj:4411)
    at cucumber.runtime.clj$fmt.invoke(api_steps.clj:18)
    at clojure.lang.Var.invoke(Var.java:423)
    at clojure.lang.AFn.applyToHelper(AFn.java:167)
    at clojure.lang.Var.applyTo(Var.java:532)
    at clojure.lang.Compiler.macroexpand1(Compiler.java:6468)
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:6546)

I've gisted the full backtrace if that's of use, and I'm running cukes via lein-cucumber.

[lein-cucumber "1.0.2"]
  [info.cukes/cucumber-clojure "1.1.1"]
    [info.cukes/cucumber-core "1.1.1"]

If this is just me struggling at 11pm I apologise.

As a workaround I'm using a function instead of a macro, and passing the interpolations in:

(defn- fmt [^String string interpolations]
  (let [pattern #"%\{(.*?)\}"
        f (fn [[_ k]] (get interpolations k :missing))]
    (clojure.string/replace string pattern f)))

Without the macro all is well.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions