What is a good way to pass around additional data with a class created by gen-class
, so that I can get hold of them easily given the class name? Currently I am adding an extra method to the class, _opts()
, that returns these extra data but it feels as a hack.
(PS: I tried to just store the additional data in an atom but that did not work, perhaps lein test
does some namespace cleanup or something between tests. defonce
might help but it feels hackish too.)
update Simplified, this is the core of my problem: 1. I am asked to gen-class class named eg math.Algebra and given a map of options. 2. I’m given the class name, “math.Algebra” and asked to return the opts map.
Why?
I am creating clj-concordion to enable using clojure & clojure.test with the Concordion Java test framework that requires me to pass it an object with custom methods. (Each “test” is defined in a Markdown file and I have to provide the underlying fixture object having the methods used in the file, as determined by the writer.) I also need to pass it extra options. The complication is that there are two distinct interactions, from me to the framework and the other way around:
- I
gen-class
and instantiate the fixture object, wrap it with the framework’sFixtureType
holding the additional options, and invoke the framework’s run method. - The framework tells me to test a particular .md file - which I map to the corresponding fixture class, use
(-> name Class/forName -> .newInstance)
to instantiate. Once here - what is the best way to get hold of the options??? (As mentioned above, I get them hackishly from the instance via(._opts obj)
Current implementation
This is how the user defines the fixture class and options:
(cc/deffixture
"math.algebra.AdditionFixture"
; Expose fns in this ns as a method on the object:
[add]
; Extra options and setup/teardown functions:
{:concordion/full-ognl false
:concordion/fail-fast true
:concordion/fail-fast-exceptions [IndexOutOfBoundsException]
::cc/before-suite #(println "AdditionFixture: I run before each Suite")
::cc/after-suite #(println "AdditionFixture: I run after each Suite")})
The deffixture macro then (see line 221 does gen-class
, deftest
, and defines a wrapper function for each of the methods, including the additional _opts
:
; ...
`(do
; Add wrapper fns for the methods (defined in let, not shown):
~@defns
(defn ~(symbol (str prefix "_opts")) [~'_] ~opts) ; HERE: For passing opts around w/ the class
; Make the class:
(gen-class
:name ~class-name
:methods ~(conj
methods*
'[_opts [] java.util.Map])
:prefix ~prefix)
; Define a test to run this:
(test/deftest ~(symbol (str prefix "test"))
(run-fixture (new-fixture ~(symbol class-name) ~opts) true)))
So, is there a better way? (The framework itself uses Java annotations and thus keeps the additional config and the class at one place.)
Thank you!