everyone
I'm try to write a function to wrap CsvReadOptions.Builder.html in clojure .
The function will take a map like this : {:header true :locale "US"}, the function will configure the builder according to the map.
(defn reader-options [ opts ]
(let [ b (CsvReadOptions$Builder.)]
(cond-> b
(contains? opts :locale ) (.locale (:locale opts))
(contains? opts :header ) (.header (:header opts))
true (.build ))
)
)
Sorry if it is too much to ask, is there a better way in clojure to accomplish this ? because the key works duplicates in single line.
(contains? opts :locale ) (.locale (:locale opts))
Thank you again for any suggestions.
In theory, you can write a macro that expands into the code you need:
(defmacro defbuilder [fn-name builder-class fields]
(let [opts (gensym)]
`(defn ~fn-name [~opts]
(cond-> (new ~builder-class)
~@(mapcat
(fn [field-sym]
(let [field-kw (keyword (name field-sym))]
`((contains? ~opts ~field-kw)
(. ~field-sym (get ~opts ~field-kw)))))
fields)
true (.build)))))
Now,
(defbuilder options-from-map CsvReadOptions$Builder
[header locale...])
will generate:
(clojure.core/defn options-from-map [G__12809]
(clojure.core/cond-> (new CsvReadOptions$Builder)
(clojure.core/contains? G__12809 :header)
(. header (clojure.core/get G__12809 :header))
(clojure.core/contains? G__12809 :locale)
(. locale (clojure.core/get G__12809 :locale))
...
true (.build)))
In practice, however, this code is:
Locale
object).Thus, you are much better off writing a wrapper by hand - or, if you need to use a Builder just once in your code, omit the wrapper altogether and use interop.