Is there any kind of multilingual documentation support for functions? I am from Turkey. I want people to write in Clojure and I dream a line like
(doc hello-world "Turkish")
As of today there's no such feature built into the language. You can attach arbitrary metadata to vars, though:
(defn ^{:docs {:en "Prints and returns its argument"
:es "Imprime y devuelve su argumento"}}
debug [x]
(println x)
x)
Recall that Clojure's documentation system uses the :doc metadata keyword name. So you'd have to pick another name (e.g. :docs).
Then you could redefine functions such as clojure.repl/doc so they take into account your metadata.
Related
In my clojure Luminus/Compojure app I have this in routes.clj:
(def page-size 12)
(def images-path "/public/images/.....")
I need to move them to a config of some sort. Where is the best place? I'd like something simple and not to use any additional library on top on the ones that I'm already using which come with Luminus.
Luminus uses it's config library for configuration. You can put your configuration variables into appropriate config.edn files (per environment). Config values are available as a map stored in config.core/env. You can see an example in your <app>.core namespace:
(defn http-port [port]
;;default production port is set in
;;env/prod/resources/config.edn
(parse-port (or port (env :port))))
Ask yourself this question:
Would I ever want multiple deployments of my application where this setting differs?
If the answer to that question is "yes" then the configuration should be dictated by the environment running you application either by an edn file, Environ or other means.
If not... then you are talking about something I would categorize as an application constant, which helps avoiding magic numbers. In some situations it can improve readability by placing these in specific namespaces like so.
Constants namespace:
(ns my.app.constants)
(def page-size 12)
(def images-path "/public/images/.....")
Application:
(ns my.app.core
(:require [my.app.constants :as const)
;; now access the application constant like this
;; const/page-size
(defn image-url [image-name]
(str const/images-path "/" image-name))
In the clojurescript re-frame todomvc application we find the following snippet in the todomvc.views namespace.
(defn todo-list
[visible-todos]
[:ul.todo-list
(for [todo #visible-todos]
^{:key (:id todo)} [todo-item todo])])
Although I have read the Clojure chapter on metadata I don't quite understand the purpose of:
^{:key
in the snippet above. Please explain.
The :key is what React needs when you have many items, so that they can be unique within the group. But the latest version of React does not need these keys. So if you use the latest versions of reframe / Reagent, just try without the :key metadata.
This metadata is equivalent to placing :key within the component. So for example what you have is equivalent to:
[todo-item {:key (:id todo)} todo]
Using the metadata approach is a convenience, which must in some cases be easier than the 'first key in props passed to the component' approach.
Here's more explanation.
^{:key (:id todo)} [todo-item todo] would be equivalent to (with-meta [todo-item todo] {:key (:id todo)}), see https://clojuredocs.org/clojure.core/with-meta
Reagent uses this to generate the corresponding react component with a key. Keys help React identify which items have changed, are added, or are removed. here is the explanation: https://reactjs.org/docs/lists-and-keys.html
I am generating Codox documentation for a Clojurescript webapp. Here's an example function that I'll use to demonstrate my issue:
(defn breadcrumbs
"Render Breadcrumbs"
[app owner]
(om/component
(let [crumbs (:breadcrumbs app)]
(dom/div #js {:id "breadcrumbs"}
(when (> (count crumbs) 0)
(apply dom/ol #js {:className "breadcrumb os-border-default"}
(om/build-all breadcrumb crumbs)))))))
The problem is that using om/component causes Codox to generate documentation for four additional "hidden" functions (presumably these are the IRender, IDidUpdate, etc functions that can be defined for a component...but I'm not sure). In the documentation these functions look like this:
->t6127
(->t6127 crumb breadcrumb meta6128)
->t6130
(->t6130 crumb breadcrumb meta6131)
->t6133
(->t6133 owner app breadcrumbs meta6134)
->t6136
(->t6136 owner app breadcrumbs meta6137)
This unneeded documentation is greatly cluttering up the final product. I know individual functions can be skipped via "^:no-doc" but there doesn't seem to be a way to use that here.
Has anyone else experienced this and know how to get rid of the clutter?
Codox currently has problems with reify in ClojureScript, which is used internally by om/component.
David Nolen suggested that the information to distinguish these temporary values should be available in current versions of ClojureScript via the analyzer, but I haven't been able to find it, and no-one's been able to point me to it. See issue #72 on the Codox project page for more information.
om/component is a very simple macro that generates only render for IRender. It looks like Codox is giving you two functions for breadcumb (first two) and two for breadcumbs. One is probably the one you want and the other one is from render. You could either write your components like this:
(defn breadcrumbs
"Render Breadcrumbs"
[app owner]
(reify
om/IRender
(render ^:no-doc [_]
(let [crumbs (:breadcrumbs app)]
(dom/div #js {:id "breadcrumbs"}
(when (> (count crumbs) 0)
(apply dom/ol #js {:className "breadcrumb os-border- default"}
(om/build-all breadcrumb crumbs)))))))
or write your own no-doc-component macro:
(defmacro no-doc-component
[& body]
`(reify
om.core/IRender
(~(vary-meta 'render assoc :no-doc true) [this#]
~#body)))
Disclaimer: although I've tried the macro, I haven't tried it with Codox.
weevejester fixed this issue in version 0.8.11.
He also configured the ClojureScript analyzer to not analyze dependencies which allows me to generate docs for my Om projects. It should also reduce the number of namespaces in the :exclude configuration. Mine has been reduced to 0.
Being new to clojure, I would like some advice on implementing the repository pattern*.
In an OO language, I would create a repository interface, a test and at least one db impl. I would instantiate them during bootstrap, pass the objects around using DI or get them through a service locator. I'm guessing it's done completely different in clojure?
1) What is a good way of grouping the functions in the repo? Protocol, "free" functions in a namespace?
2) Where do I instantiate the repository back-end, i.e. allocate resources like db-connections etc.? Do I instantiate an implementation of the repository protocol and assign it to an atom, or in the case of free functions, redefine them?
*) A repository is a back-end abstraction for persistence and typically supports a CRUD style range of operations.
EDIT: Here is the approach I'm currently using. A protocol to group functions. A test and a "real" record implementing it. Then an atom to register the repo with.
(defprotocol GardenRepo
"Repository of Gardens. Supports CRUD style operations."
(list-gardens [repo] "Get a seq of all gardens in the repo.")
(get-garden [repo id] "Get a specific garden by it's id.")
...)
(let [repo (atom nil)]
(defn get-garden-repo [] #locator)
(defn set-garden-repo [new-repo] (reset! repo new-repo)))
1) Group functions by shared subproblems. In our ORM we have a namespace for db interaction, a separate namespace for each target db, a namespace for model construction and query operations, a namespace for field definition, a separate namespace describing each implementation of the field protocol (ie. int, string, text, slug, collection).
2) Use a function that returns all the functions used, each implicitly using resources defined by the passed in config, ie.:
(defn make-repository
[config]
(let [db (initialize-db config)
cleanup #(do-cleanup db)
store (fn [key val] (store-data key val db))
retrieve (fn [key] (retrieve-data key db))]
{:db db ;; this is optional, can be very useful during initial development
:cleanup cleanup
:store store
:retrieve retrieve}))
This could of course create an instance of a record if access of the functions is a performance bottleneck, and the record could implement a protocol if you want to define multiple implementations of the same functionality (different db drivers that may need different setup etc.). The user of the library decides how and where to bind these functions you return, as appropriate for their own design.
An example of how a client could use this repository:
(def repo (make-repository config))
(def cleanup-repo (:cleanup repo))
(def store-to-repo (:store repo))
(def retrieve-from-repo (:retrieve repo))
(defn store-item
[data]
(let [processed (process data)
key (generate-key data)]
(try (store-to-repo key data)
(catch Exception e
(cleanup-repo)))))
I tried to follow the documentation for clojure.instant/read-instant-timestamp, which reads:
clojure.instant/read-instant-timestamp
To read an instant as a java.sql.Timestamp, bind *data-readers* to a
map with this var as the value for the 'inst key. Timestamp preserves
fractional seconds with nanosecond precision. The timezone offset will
be used to convert into UTC.`
The following result was unexpected:
(do
(require '[clojure.edn :as edn])
(require '[clojure.instant :refer [read-instant-timestamp]])
(let [instant "#inst \"1970-01-01T00:00:09.999-00:00\""
reader-map {'inst #'read-instant-timestamp}]
;; This binding is not appearing to do anything.
(binding [*data-readers* reader-map]
;; prints java.util.Date -- unexpected
(->> instant edn/read-string class println)
;; prints java.sql.Timestamp -- as desired
(->> instant (edn/read-string {:readers reader-map}) class println))))
How can I use the *data-readers* binding? Clojure version 1.5.1.
clojure.edn functions by default only use data readers stored in clojure.core/default-data-readers which, as of Clojure 1.5.1, provides readers for instant and UUID literals. If you want to use custom readers, you can do that by passing in a :readers option; in particular, you can pass in *data-readers*. This is documented in the docstring for clojure.edn/read (the docstring for clojure.edn/read-string refers to that for read).
Here are some examples:
(require '[clojure.edn :as edn])
;; instant literals work out of the box:
(edn/read-string "#inst \"2013-06-08T01:00:00Z\"")
;= #inst "2013-06-08T01:00:00.000-00:00"
;; custom literals can be passed in in the opts map:
(edn/read-string {:readers {'foo identity}} "#foo :asdf")
;= :asdf
;; use current binding of *data-readers*
(edn/read-string {:readers *data-readers*} "...")
(The following section added in response to comments made by Richard Möhn in this GitHub issue's comment thread. The immediate question there is whether it is appropriate for a reader function to call eval on the data passed in. I am not affiliated with the project in question; please see the ticket for details, as well as Richard's comments on the present answer.)
It is worth adding that *data-readers* is implicitly populated from any data_readers.{clj,cljc} files that Clojure finds at the root of the classpath at startup time. This can be convenient (it allows one to use custom tagged literals in Clojure source code and at the REPL), but it does mean that new data readers may appear in there with a change to a single dependency. Using an explicitly constructed reader map with clojure.edn is a simple way to avoid surprises (which could be particularly nasty when dealing with untrusted input).
(Note that the implicit loading process does not result in any code being loaded immediately, or even when a tag mentioned in *data-readers* is first encountered; the process which populates *data-readers* creates empty namespaces with unbound Vars as placeholders, and to actually use those readers one still has to require the relevant namespaces in user code.)
The *data-readers* dynamic var seems to apply to the read-string and read functions from clojure.core only.
(require '[clojure.instant :refer [read-instant-timestamp]])
(let [instant "#inst \"1970-01-01T00:00:09.999-00:00\""
reader-map {'inst #'read-instant-timestamp}]
;; This will read a java.util.Date
(->> instant read-string class println)
;; This will read a java.sql.Timestamp
(binding [*data-readers* reader-map]
(->> instant read-string class println)))
Browsing through the source code for clojure.edn reader here, I couldn't find anything that would indicate that the same *data-readers* var is used at all there.
clojure.core's functions read and read-string use LispReader (which uses the value from *data-readers*), while the functions from clojure.edn use the EdnReader.
This edn library is relatively new in Clojure so that might be the reason why the documentation string is not specific enough regarding edn vs. core reader, which can cause this kind of confusion.
Hope it helps.