How is 'provided' implemented in a fact in Midje? - clojure

I was reading Clojure in Action chapter 8 about TDD and experimented with the stubbing macro. It uses the dynamic binding mechanism to stub functions. Alas, in Clojure 1.3 it is not possible to use the binding mechanism for non-dynamic vars, so the stubbing macro doesn't work in most cases, unless you explicitly declare the var which points to a function dynamic. Then I wondered how stubbing is done in Midje and tried to find the source for 'provided', but I couldn't find it. So here it goes:
How is 'provided' implemented in a fact in Midje? Can someone explain this in detail?

Clojure 1.3 provides a with-redefs macro that works even with vars that haven't been declared dynamic:
user=> (def this-is-not-dynamic)
user=> (with-redefs [this-is-not-dynamic 900] this-is-not-dynamic)
900
For backward compatibility, Midje uses its own version, whose guts look like this:
(defn alter-one-root [[variable new-value]]
(if (bound? variable)
(let [old-value (deref variable)]
(alter-var-root variable (fn [current-value] new-value))
[variable old-value])
(do
(.bindRoot variable new-value)
[variable unbound-marker])))

Related

Group multiple namespace definitions under one namespace

Suppose I have the namespaces foo.car.components.engine, foo.car.components.transmission, foo.car.components.brakes.
In foo.car.components.engine there is (defn engine [] ...), foo.car.components.transmission there is (defn transmission [] ...),
foo.car.components.brakes there is (defn brakes [] ...).
I'd like to make these available in foo.car.components such that other namespaces only need to require foo.car.components to use engine, transmission, and brakes.
The following works, but I'm wondering if there are cleaner ways to do this or if it's even good practice.
(ns foo.car.components
(:require
[foo.car.components.engine :as engine]
[foo.car.components.transmission :as transmission]
[foo.car.components.brakes :as brakes]))
(def engine engine/engine)
(def transmission transmission/transmission)
(def brakes brakes/brakes)
I don't offhand know of a better way, but this way does come with downsides, so take these into consideration when deciding if you want to use this:
It doesn't transfer Meta information to the "wrapper", so any docstrings/other information attached to the main function won't show up in IDEs when you use the wrapper.
Along the same vein, because the wrapper doesn't have an argument list, if you ctrl+q the wrapper functions, it also won't show the available argument lists of the main function.
Having said that, Seesaw, a major Clojure library that wraps Swing does use this "technique". If I ever forget the docs/arguments of a function that has a "convenience wrapper", I just have to hit ctrl+b twice (in IntelliJ), and it will take me to the original source where I can look it over. It's ironically inconvenient, but I guess that's the price for convenience elsewhere.
To get around these faults, you could write a function (or a macro that wraps def) that transfers Meta information. Considering argument list information is stored as Meta information, that might be enough to overcome the faults.
This answer doesn't really answer your question, so I hope someone else is able to give some insight here. I thought that this was relevant information though.
You can use:
import-vars
from https://github.com/ztellman/potemkin
It doesn't seem that this feature is provided by Clojure API. You can consider https://github.com/ptaoussanis/encore look for defalias.
On the other hand, if you have brakes, transmission and engine as public interfaces and you can use them separately why would you merge them? As opposite, you can provide all definitions in components or even car which will use in turn brakes, transmission and engine. In such way, it is not necessary to expose all components.
I think the way you're doing it is the best way, because it makes explicit the sources of the defs in each namespace. If you have large namespaces with a lot of functions, you could write a basic helper function to do this for you:
(ns foo.utils)
(defn export-refs
[target-ns source-namespaces]
(doseq [ns source-namespaces
[sym f] (ns-interns ns)
:let [existing (get (ns-interns target-ns) sym)]]
(when (and existing (not= (var-get existing) f))
(throw (Exception.
(format (str "Cannot refer to symbol %s in %s from %s, because that symbol "
"already exists in the target namespace")
sym (ns-name ns) (ns-name target-ns)))))
(intern target-ns sym f)))
(ns foo.car.components.engine)
(defn engine [] (println "engine"))
(ns foo.car.components.transmission)
(defn transmission [] (println "transmission"))
(ns foo.car.components.brakes)
(defn brakes [] (println "brakes"))
(ns foo.car.components
(:require [foo.utils :refer [export-refs]]))
(export-refs 'foo.car.components '[foo.car.components.engine
foo.car.components.transmission
foo.car.components.brakes])
(ns user
(:require [foo.car.components :refer [engine transmission brakes]]))
(engine) ;; Prints "engine"
(transmission) ;; Prints "transmission"
(brakes) ;; Prints "brakes"
Whether it's "good practice" or not is up to you. Obviously it has the advantage of splitting code into smaller files with specific functionality, while allowing the import of only a single namespace. The disadvantage is that there's a bit of indirection in where the functions come from, which will make finding the function sources more difficult, and there's more risk of name collisions.

why are compojure routes defined as macros?

for example the Luminus website states that
Compojure route definitions are just functions that accept request
maps and return response maps...
(GET "/" [] "Show something")
...
But compojure routes are not functions
(defmacro GET "Generate a `GET` route."
[path args & body]
(compile-route :get path args body))
One can use the function make-route that returns a functions, but does not allow for destructuring. So as a function you can not use compojure's special syntax for destructing (i.e the vector) but does this stop any form of destructuring? Does the macro from given them a performance increase?
(make-route :get "/some_path" some_handler)
Couldn't the destructing syntax be passed to the function using a macro wrapper?
One reason macros are used is so the user can write function and symbol names without having to quote everything. Take this example from the Clojure Cookbook:
; Routing
(defroutes main-routes
(GET "/" [] (index))
(GET "/en/" [] (index))
(GET "/fr/" [] (index-fr))
(GET "/:greeting/" [greeting] (view greeting)))
All of the index* symbols, plus view and greeting would have to be quoted if GET were a function:
; Routing
(defroutes main-routes
(GET "/" [] '(index))
(GET "/en/" [] '(index))
(GET "/fr/" [] '(index-fr))
(GET "/:greeting/" '[greeting] '(view greeting)))
Since function arguments are evaluated before the function is invoked, (index) et al would be evaluated as soon as the form was read. Also, the greeting arg will be changing on each HTTP request, so it obviously is not known ahead of time.
The macro also takes care of all the destructuring magic which is not (normally) possible with a regular function.
The thing which is often confusing (and is not well explained to beginners) is that a line like:
(GET "/:greeting/" [greeting] (view greeting))
is not normal "Clojure code". Instead, it is a type of shorthand (Domain-Specific Language or DSL to be precise) that the GET macro will ingest and use as instructions on how to generate "legal" Clojure code. The DSL is normally much shorter, simpler, & more convenient for a human than the final generated code, just as Clojure is much shorter, simpler, & more convenient than the Java Bytecode produced by the Clojure compiler, or the machine assembly language code eventually produced by the JVM.
In short, each macro is a "pre-compiler" that turns the DSL into plain Clojure, which is then ingested by the Clojure compiler to generate Java bytecode.
Having said that, it could be re-arranged to put all of the macro magic into the defroutes macro so that the GET symbol was neither a function nor a macro, but just a type of marker like the :get keyword in the implementation. As a user, these kinds of implementation details normally don't matter much.
Update
It is best to use macros only when a function won't work or is very awkward. The deciding factor is usually if one wants to use bare (unquoted) symbols, but not evaluate them in advance. Core Clojure itself uses macros for many constructs that are "built-ins" in other languages, including defn, for, and, or, when, and others.
Also note that a macro cannot do some things a function can, such as being a parameter to a higher-order function like filter.
In summary, a function defines a behavior. A macro defines a language extension.

Practical Clojure: macros and Java interop

In Practical Clojure's chapter on Java interop, the authors note the following about the Java interop "syntactic sugar" (e.g. (.method object arguments) instead of (. object method arguments)):
Since these “syntactic sugar” expansions happen in the same compilation phase as macro-expansion, macros that do complex code-generation may need to avoid them and use the new and . (dot) special forms directly.
I don't understand why "syntactic sugar" expansion happening in the same phase as macro expansion is a problem. Is it because there may be issues with the order of expansions?
Macros concerned with generating interop calls typically should use the desugared special form, but that's not because of when desugaring happens, nor is it a problem. And they don't have to: more times than I care to count, I've seen someone write:
(defmacro call [obj method & args]
`(~(symbol (str "." (name method))) ~obj ~#args))
which is just a total mess, compared to how it would look with the appropriate tool:
(defmacro call [obj method & args]
`(. ~obj ~method ~#args))

What is the difference between (defn function-name) and (defn- function-name in clojure?

Can someone explain this to me? I think I understand that (defn -main) is declaring a main method that would be recognised by Java and that if you use this in conjunction with a namespace with (:gen-class) that you can fool Java into thinking clojure is object oriented, however I can't work out what the purpose is if you just create a function like
(def- add2
(partial + 2)
)
or (defn- my-function...)
Can anyone explain this simply or correct me if the above assumptions are wrong?
**Edit - I understand what a partial function does :) I'm just wondering if there's a difference between above and (def add2 (partial + 2))
Functions defined with defn- aren't accessible outside of the namespace they were defined in. In other words, they are private.
Take a look at the source of defn-. This macro evaluates to a call to defn with {:private true} merged into the metadata hash.

Get available clojure namespaces

Is there an idiomatic way to get available namespaces that can be used?
(all-ns) returns only already used namespaces. (Package/getPackages) returns all Java packages available for import, but only those Clojure namespaces that are already used.
Then I stumbled upon this post, but it uses some classpath magic.
So I want to get something like ('clojure.core 'clojure.set ... 'clojure.contrib.accumulators 'clojure.contrib.condition ...) if I have the clojure.jar and contrib.jar on my classpath, but I haven't used anything yet.
You will need to do "classpath magic". Since there is no kind of registry, you have to walk the classpath and look in every clojure source file to determine what namespaces are available. (In case the files are not AOT compiled. Otherwise you'll need a different heuristic.)
I think the function used in the linked post is the best way to go: clojure.contrib.find-namespaces/find-namespaces-on-classpath.
Deprecated since Clojure 1.3.0; use now clojure.tools.namespace.find/find-namespaces and clojure.java.classpath/classpath from http://github.com/clojure/java.classpath
I have found bultitude to be a great tool for doing this.
Example:
user=> (require '[bultitude.core :as b])
nil
user=> (take 10 (b/namespaces-on-classpath))
(bultitude.core-test bultitude.core clojure.data clojure.string clojure.test clojure.xml clojure.inspector clojure.repl clojure.set clojure.test.junit)
user=> (b/namespaces-on-classpath :prefix "bultitude")
(bultitude.core-test bultitude.core)