Whilst experimenting with clj-webdriver
and writing social-phobia
I have created an interesting macro and would like to share it with you and get some feedback.
Awesome. But I would like to receive more useful messages if GitHub changes URL or IDs of HTML elements.
Let’s make our code “safer”:
12345678910111213
(defn error"Returns \"\"#uername\" not found\" for e.g."[selector]{:error(str (first (vals selector))" not found")})(defn safe-find-element"Find the element, if the element is found, call the f, if not return a map with an error."[selectorf](let [el(find-elementselector)](if (:webelementel)(fel)(errorselector))))
It means if we find an element we call function with that element,
if not we return error which looks like {error: "#signin-email not found"}.
Nice, but not so useful so far.
Let’s wrap click and input-text functions in this wrapper.
=>(do-unless:error(safe-input-text{:css"#login_field"}(auth:login))(safe-input-text{:css"#passwor"}(auth:pass))(safe-click{:xpath"//input[@type='submit']"})){:error"#passwor not found"}
Much nicer. But how is it supposed to work? Tada!
12345678910111213141516171819202122
(defmacro do-unless" Evaluates the expr if the condition which was called with result of previous expression returned false. Examples: ========= (do-unless nil? (println 1) (println 2)) 1 nil (do-unless nil? (do (println 1) 1) (println 2)) 1 2 nil"([conditionexpr&exprs]`(let [r#~expr](if (~conditionr#)r#(do-unless~condition~@exprs))))([conditionexpr]expr))
Basically this macro recursively produces, a set of nested let and if expressions.
Cache result of expression
Check is’t map with :error message or not
If yes, returns that map
If not start this cycle for next expression
Nice, also it should be faster than catch exceptions and also
we don’t produce any extra function calls like we do with monads.
I think this macro is pretty much fun for this kind of code with a purely
imperative nature.