Clojure docstring for libraries/namespaces - clojure

How to add docstrings and/or comments to Clojure libaries/namespaces as a whole, i.e. not just to specific functions within the namespace?
I've noticed that the clojure source uses (comment ...) in some places to do this (example), is that recommended?

You can add a docstring to any namespace in the ns form.
(ns my.name.space
"Very cool namespace doing this and that."
(:require other.cool.stuff))

You can add it to the ns declaration:
(ns ^{:author "mikera"
:doc "My awesome library"}
foo.bar.core)
The example you link to does that too - so not sure if this is what you mean? But I think it's the most "standard" - it will get picked up by documentation systems such as Codox and Autodoc.

Related

Where should I save simple configuration settings?

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))

Multilingual doc support for Clojure

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.

What are the namespace gotchas for clojurescript when coming from clojure?

I'm trying to understand the namespacing model in clojurescript. I understand that javascript doesn't come built in with namespace support, so its been an add on via the google closure library. However, I don't understand how clojurescript deals with these differences. Can someone please explain?
Lets say for example I want to use the google charts api and whenever possible would like to use advanced compilation. What do I use in the closure/build call, how would the ns form look like and what's the best way to refer to the api from the code? I've looked at https://github.com/sritchie/contour but that example doesn't use advanced compilation, and I don't see the options referring to the google api in the project.clj file.
The namespace declaration is the same regardless of whether you are using simple or advanced mode compilation. The difference is that libraries that don't participate in google dependency management via goog.require('') and goog.provide('') need to be explictly referenced via an externs.js file. This file, which you pass to the cljs compiler, provides stubs of all the vars and associated methods. A typical externs.js would look something like:
// contents of externs.js
var externalLibrary = {}
var externalLibrary.method = function() {}
So to reference a google closure aware library your namespace declaration looks like this:
(ns my.namespace
(:require [goog.events.KeyCodes :as key-codes])
And that emits the following javascript:
goog.provide("my.namespace");
goog.require("goog.events.keycodes");
Note that if you want to call your closurescript from another javascript file then you need to tag the method as exported so that the optimizing compiler knows to preserve the name. (e.g. you might have a script tag on a page from where you want to call a javascript function that has been generated from clojurescript)
That looks like this:
(defn ^:export externallyCalled [])
The other thing to be aware of is that you have to treat macros differently in clojurescript, this is because the ability to process them 'on the fly' in the reader is not present in the same way as it is in clojure.
you do that as follows (note that you are obliged to bind the macros with :as in this case)
(ns my.namespace
(:require-macros [my.macros :as my]))
If you are calling code that didn't participate in google's dependency management you access it via the js namespace and the javascript interop...
(. js/nonGoogle (method args)) ; a method access
(. js/nonGoogle -p) ; a property access
all the usual . variants work too..

Clojure namespaces

I want to split a big clojure-script into smaller ones. And it looks like this.
One:
(ns one
(:use [two :only (show)]))
(def status "WORKING")
Two:
(ns two
(:use [one :only (status)]))
(defn show [] (println status))
Result: Exception.
PS I understand that some some kind of recursive namespace constructing happens. I know only a sloppy half-solution, like defining without body before referncing to namespaces? Any suggestions?
+1 for the answer of ponzao. To elaborate a bit more: Cyclic dependencies of namespaces are often a sign, that you didn't get your abstractions and/or APIs right. Either you "mix" layers or things should just be in one namespace, because the really belong together.
If you want to just split one namespace into several files, this is also possible.
name/space.clj:
(ns name.space)
(declare status)
(load "space_one")
(load "space_two")
name/space_one.clj:
(in-ns 'name.space)
(defn show [] (println status))
name/space_two.clj:
(in-ns 'name.space)
(def status "WORKING")
You are constructing a cyclic dependency between two components, are you sure this is what you want? Why not have a third namespace containing their common functions?

Can't import clojure records

I have created a record like this:
(defrecord User [user-id email])
:but when I try to access it from another name-space I get the error:
(User. "name" "email")
java.lang.IllegalArgumentException: Unable to resolve classname: User
It works when I do:
(oe.model.modelcore.User. "name" "email")
: I know I will need to import the Java class, but is there any way for clojure to do this automatically when I do:
(use 'oe.model.modelcore :reload)
Technically you must require it (don't necessarily need to use it) so that the file containing the record definition is compiled and the class is created. Then you must import it so that it is available to construct as a Java class. If you create a constructor function in the first ns like
(defn new-user [id email]
(User. id email))
then you will not need to import it in the calling ns.
I wrote this up a while back here:
http://tech.puredanger.com/2010/06/30/using-records-from-a-different-namespace-in-clojure/
It could be really tricky if you have - (dash) in your name space.
As it turns out there were two errors:
– Importing defrecord from another namespace is not just :use. I had to first :require the namespace, then import the defrecord. This was a trivial problem to solve and I figured it out quickly. Only this did not work in my case
– Dashes “-” and Underscores “_” are a nuisance since we are mixing Lisp with Java. While the file system uses underscores Clojure converts things to dashes. Brilliant.
So to fix the second error I use the follow in the ns block
(ns adder.core
(:require building-blocks.activity)
(:import [building_blocks.activity Activity]))
https://cyrax.wordpress.com/2013/07/22/clojure-importrequireuse-defrecord-from-another-namespace/
In your question you are creating a record, then invoking the constructor for the class generated as a side effect. To do so you need to import that class as mentioned in another answer.
However, imho the preferred path (since Clojure 1.4) is to use the constructor functions generated by defrecord (here they'll be named ->User and map->User). These functions allow you to avoid the interop forms and just refer in the constructor functions like any other function. By avoiding interop, this is a more portable less-hosty solution:
(ns some-ns
(:require [oe.model.modelcore :refer (->User)]))
(def user (->User "name" "email"))
You have to import the record like this:
(ns some-ns
(:import [oe.model.modelcore User]))