I have the following piece of code in a ClojureScript project :
(ns project.lib
(:require [cljs.test :refer-macros [is]]))
(defn my-fn [p]
{:pre [(is (#{:allowed-key :another-allowed-key} p))]}
;;...
)
I would like to know if I can control the behaviour of the :pre and :post assertions, and generally what is the way to make sure that some code related to parameter checking is not included.
Note : I am aware of the :closure-define compiler option, but not sure how to apply it to this specific case.
You can set the compiler option :elide-asserts to true to eliminate all assertions, including :pre and :post assertions.
This flag is independent of :advanced and needs to be set even under that mode to eliminate the assertions from production code.
See https://github.com/clojure/clojurescript/wiki/Compiler-Options#elide-asserts
Also note that, generally, the cljs.test namespace would only be used in unit test namespaces, which would be placed in a separate directory (perhaps under "test" as opposed to to "src") and, if using lein, you would use :source-paths so as to not include the tests in your production builds.
Having said that, using :pre and :post is perfectly fine in production codeājust use "regular" predicates instead of the cljs.test is macro. For your specific example, is could be eliminated as the precondition simply needs to evaluate to something truthy.
Related
Using core.matrix in a ClojureScript project. For javascript interop I need aljabr as explained in https://github.com/mikera/core.matrix/wiki/Matrix-implementations
After I try to specify the implementation (as I do with other Clojure implementations)
(require '[clojure.core.matrix :as mat])
(require '[thinktopic.aljabr.core :as imp])
(mat/set-current-implementation :aljabr)
I get this error and I can't use the matrix implementation for Javascript
INFO: No dynamic loading of implementations in Clojurescript.
You must require an implementation explicitly in a namespace, for example thinktopic.aljabr.core
Looking on github I only find the implementation used as I mention above (e.g. https://github.com/mars0i/free/commit/71dbbe4d58645ad4e25f2ac2d4ccba6ccef93968), how can I make aljabr work in cljs?
You need to set the implementation statically, that means not at the beginning of the file like you did but when you actually declare your matrix
(mat/matrix :aljabr [[1.0 2.0 3.0][4.0 5.0 7.0]])
(I answered to myself just cause there is no result on the internet for that error and took me a while to understand the error message explanation, even with git blames)
I have a library of functions which I want to let users play with in the browser.
So I want to set up a situation like this :
I'm developing with figwheel and devcards.
In the main core.cljs I require various functions from my library, so they're all in scope.
Now I want to let the user enter some code which calls that library.
I see how I can run that code with eval, but I can't see how to make my library functions visible to the code being evaled.
And I'm confused by most of the documentation I'm seeing about this (eg. How can I make functions available to ClojureScript's eval?)
Is it possible? And if so, does anyone have a simple example of it being done?
cheers
Phil
Yes, it is possible to provide access to an ambient / pre-compiled library used by evaluated code.
First, you must ensure that the functions in your library are available in the JavaScript runtime. In other words, avoid :advanced optimization, as this will eliminate functions not called at compile time (DCE). Self-hosted ClojureScript is compatible with :simple.
Second, you need to make the analysis metadata available to the self-hosted compiler that will be running in the browser (either making use of cljs.js/load-analysis-cache! or an optional argument to cljs.js/empty-state).
A minimal project illustrating how to do this is below (and also at https://github.com/mfikes/ambient):
Project Code
src/main/core.cljs:
(ns main.core
(:require-macros [main.core :refer [analyzer-state]])
(:require [cljs.js]
[library.core]))
(def state (cljs.js/empty-state))
(defn evaluate [source cb]
(cljs.js/eval-str state source nil {:eval cljs.js/js-eval :context :expr} cb))
(defn load-library-analysis-cache! []
(cljs.js/load-analysis-cache! state 'library.core (analyzer-state 'library.core))
nil)
src/main.core.clj:
(ns main.core
(:require [cljs.env :as env]))
(defmacro analyzer-state [[_ ns-sym]]
`'~(get-in #env/*compiler* [:cljs.analyzer/namespaces ns-sym]))
src/library/core.cljs:
(ns library.core)
(defn my-inc [x]
(inc x))
Usage
We have a main.core namespace which provides an evaluate function, and this example will show how to call functions in an ambient / pre-compiled library.core namespace.
First, start up a browser REPL via
clj -m cljs.main
At the REPL, load our main namespace by evaluating
(require 'main.core)
Test that we can evaluate some code:
(main.core/evaluate "(+ 2 3)" prn)
This should print
{:ns cljs.user, :value 5}
Now, since main.core required library.core, we can call functions in that namespace. Evaluating this at the REPL will yield 11:
(library.core/my-inc 10)
Now, let's try to use this "ambient" function from self-hosted ClojureScript:
(main.core/evaluate "(library.core/my-inc 10)" prn)
You will see the following
WARNING: No such namespace: library.core, could not locate library/core.cljs, library/core.cljc, or JavaScript source providing "library.core" at line 1
WARNING: Use of undeclared Var library.core/my-inc at line 1
{:ns cljs.user, :value 11}
In short, what is going on is that even though library.core.my_inc is available in the JavaScript environment, and can indeed be called, producing the correct answer, you get warnings from the self-hosted compiler that it knows nothing about this namespace.
This is because the compiler analysis metadata is not in the main.core/state atom. (The self-hosted compiler has its own analysis state, held in that atom in the JavaScript environment, which is separate from the JVM compiler analysis state, held via Clojure in the Java environment.)
Note: If we instead had the source for library.core compiled by the self-hosted compiler (by perhaps by using main.core/evaluate to eval "(require 'library.core)", along with properly defining a cljs.js/*load-fn* that could retrieve this source, things would be good, and the compiler analysis metadata would be in main.core/state. But this example is about calling ambient / pre-compiled functions in library.core.
We can fix this by making use of cljs.js/load-analysis-cache! to load the analysis cache associated with the library.core namespace.
This example code embeds this analysis cache directly in the code by employing a macro that snatches the analysis cache from the JVM-based compiler. You can transport this analysis cache to the browser by any mechanism you desire; this just illustrates one way of simply embedding it directly in the shipping code (it's just data).
Go ahead and evaluate the following, just to see what the analysis cache for that namespace looks like:
(main.core/analyzer-state 'library.core)
If you call
(main.core/load-library-analysis-cache!)
this analysis cache will be loaded for use by the self-hosted compiler.
Now if you evaluate
(main.core/evaluate "(library.core/my-inc 10)" prn)
you won't see any warnings and this will be printed:
{:ns cljs.user, :value 11}
Furthermore, since the self-hosted compiler now has the analysis metadata for libraray.core, it can properly warn on arity errors, for example
(main.core/evaluate "(library.core/my-inc 10 12)" prn)
will cause this to be printed:
WARNING: Wrong number of args (2) passed to library.core/my-inc at line 1
The above illustrates what happens when you don't have the analyzer cache present for a namespace and how to fix it using cljs.js/load-analysis-cache!. If you know that you will always want to load the cache upon startup, you can simply things, making use of an optional argument to cljs.js/empty-state to load this cache at initialization time:
(defn init-state [state]
(assoc-in state [:cljs.analyzer/namespaces 'library.core]
(analyzer-state 'library.core)))
(def state (cljs.js/empty-state init-state))
Other Projects
A few (more elaborate) projects that make library functions available to self-hosted ClojureScript in the browser:
Klangmeister
power-turtle
life-demo
I have a Clojurescript program running in the browser.
It imports a number of libraries, and then I want to allow the user to enter some small clojurescript "glue-code" that calls those libraries.
I can see (from https://cljs.github.io/api/cljs.js/eval) that you call eval with four arguments, the first being the state of the environment, which is an atom. But can I actually turn my current environment with all the functions I've required from elsewhere, into an appropriate argument to eval?
Update :
I thought that maybe I could set the namesspace for the eval using the :ns option of the third, opts-map, argument. I set it to the namespace of my application :
:ns "fig-pat.core"
But no difference.
Looking at the console, it's definitely the case that it's trying to do the evaluation, but it's complaining that names referenced in the eval-ed code are NOT recognised :
WARNING: Use of undeclared Var /square
for example. (square is a function I'm requiring. It's visible in the application itself ie. the fig-pat.core namespace)
I then get :
SyntaxError: expected expression, got '.'[Learn More]
Which I'm assuming this the failure of eval-ed expression as a whole.
Update 2 :
I'm guessing this problem might actually be related to : How can I get the Clojurescript namespace I am in from within a clojurescript program?
(println *ns*)
is just printing nil. So maybe Clojurescript can't see its own namespace.
And therefore the :ns in eval doesn't work?
Calling eval inside a clojurescript program is part of what is called "self-hosted clojurescript".
In self-hosted clojurescript, namespaces are not available unless you implement a resolve policy. It means that have to let the browser know how to resolve the namespace e.g. loads a cljs file from a cdn.
It's not so trivial to implement namespace resolving properly.
This is explained in a cryptic way in the docstring of load-fn from cljs.js namespace.
Several tools support namespaces resolving in self-host cljs running in the browser e.g Klipse and crepl
What is an idiomatic way to handle application configuration in clojure?
So far I use this environment:
;; config.clj
{:k1 "v1"
:k2 2}
;; core.clj
(defn config []
(let [content (slurp "config.clj")]
(binding [*read-eval* false]
(read-string content))))
(defn -main []
(let [config (config)]
...))
Which has many downside:
The path to config.clj might not always be resolved correctly
No clear way to structure config sections for used libraries/frameworks
Not globally accessible (#app/config) (which of course, can be seen as a good functional style way, but makes access to config across source file tedious.
Bigger open-source projects like storm seem to use YAML instead of Clojure and make the config accessible globally via a bit ugly hack: (eval ``(def ~(symbol new-name) (. Config ~(symbol name)))).
First use clojure.edn and in particular clojure.edn/read. E. g.
(use '(clojure.java [io :as io]))
(defn from-edn
[fname]
(with-open [rdr (-> (io/resource fname)
io/reader
java.io.PushbackReader.)]
(clojure.edn/read rdr)))
Regarding the path of config.edn using io/resource is only one way to deal with this. Since you probably want to save an altered config.edn during runtime, you may want to rely on the fact that the path for file readers and writers constructed with an unqualified filename like
(io/reader "where-am-i.edn")
defaults to
(System/getProperty "user.dir")
Considering the fact that you may want to change the config during runtime you could implement a pattern like this
(rough sketch)
;; myapp.userconfig
(def default-config {:k1 "v1"
:k2 2})
(def save-config (partial spit "config.edn"))
(def load-config #(from-edn "config.edn")) ;; see from-edn above
(let [cfg-state (atom (load-config))]
(add-watch cfg-state :cfg-state-watch
(fn [_ _ _ new-state]
(save-config new-state)))
(def get-userconfig #(deref cfg-state))
(def alter-userconfig! (partial swap! cfg-state))
(def reset-userconfig! #(reset! cfg-state default-config)))
Basically this code wraps an atom that is not global and provides set and get access to it. You can read its current state and alter it like atoms with sth. like (alter-userconfig! assoc :k2 3). For global testing, you can reset! the userconfig and also inject various userconfigs into your application (alter-userconfig! (constantly {:k1 300, :k2 212})).
Functions that need userconfig can be written like
(defn do-sth [cfg arg1 arg2 arg3]
...)
And be tested with various configs like default-userconfig, testconfig1,2,3...
Functions that manipulate the userconfig like in a user-panel would use the get/alter..! functions.
Also the above let wraps a watch on the userconfig that automatically updates the .edn file every time userconfig is changed. If you don't want to do this, you could add a save-userconfig! function that spits the atoms content into config.edn. However, you may want to create a way to add more watches to the atom (like re-rendering the GUI after a custom font-size has been changed) which in my opinion would break the mold of the above pattern.
Instead, if you were dealing with a larger application, a better approach would be to define a protocol (with similar functions like in the let block) for userconfig and implement it with various constructors for a file, a database, atom (or whatever you need for testing/different use-scenarios) utilizing reify or defrecord. An instance of this could be passed around in the application and every state-manipulating/io function should use it instead of anything global.
I wouldn't bother even keeping the configuration maps as resources in a separate file (for each environment). Confijulate (https://github.com/bbbates/confijulate , yes - this is a personal project) lets you define all your configuration for each environment within a single namespace, and switch between them via system properties. But if you need to change values on the fly without rebuilding, Confijulate will allow you do that, too.
I've done a fair bit of this over the past month for work. For the cases where passing a config around is not acceptable, then we've used a global config map in an atom. Early on in the application start up, the config var is swap!ed with the loaded config and after that it is left alone. This works in practice because it is effectively immutable for the life of the application. This approach may not work well for libraries, though.
I'm not sure what you mean by "No clear way to structure config sections for used libraries/frameworks". Do you want libraries to have access to the config? Regardless, I created a pipeline of config loaders that is given to the function that setups the config at start up. This allows me to separate config based on library and source.
Let's say I want to build a large clojure library with several components. As a developer, I would like to keep many of the components in separate namespaces since many helper functions can have similar names. I don't necessarily want to make things private since they may have utility outside in extreme cases and the work-arounds behind private is not good. (In other words, I would like to suggest code usage, not completely prevent usage.)
However, I would like the users of the library to operate in a namespace with a union of a subset of many of the functions in each sub library. What is the idiomatic or best way to do this? One solution that comes to my mind is to write a macro that generates :requires and creates a new var mapping by def'ing a given list of var names (see first code example). Are there tradeoffs with this method such as what happens to extending types? Is there a better way (or builtin)?
Macro example (src/mylib/public.clj):
(ns mylib.public
(:require [mylib.a :as a])
(:require [mylib.b :as b]))
(transfer-to-ns [+ a/+
- b/-
cat b/cat
mapper a/mapper])
Again, to clarify, the end goal would be to have some file in other projects created by users of mylib to be able to make something like (src/someproject/core.clj):
(ns someproject.core
(:require [mylib.public :as mylib]))
(mylib/mapper 'foo 'bar)
#Jeremy Wall, note that your proposed solution does not fullfill my needs. Lets assume the following code exists.
mylib/a.clj:
(ns mylib.a)
(defn fa [] :a)
mylib/b.clj:
(ns mylib.b)
(defn fb [] :b)
mylib/public.clj:
(ns mylib.public
(:use [mylib.a :only [fa]])
(:use [mylib.b :only [fb]]))
somerandomproject/core.clj: (Assume classpaths are set correctly)
(ns somerandomproject.core
(:require [mylib.public :as p])
;; somerandomproject.core=> (p/fa)
;; CompilerException java.lang.RuntimeException: No such var: p/fa, compiling: (NO_SOURCE_PATH:3)
;; somerandomproject.core=> (mylib.a/fa)
;; :a
If you notice, "using" functions in mylib/public.clj DOES NOT allow public.clj to PROVIDE these vars to the user file somerandomproject/core.clj.
You might find it interesting to look at how a library like Compojure or Lamina organizes its "public" api.
Lamina has "public" namespaces like lamina.api that serve to alias (using Zach's import-fn from his potemkin library) functions from the "internal" namespaces like lamina.core.pipeline. With a bit of docs, this serves to clearly delineate the public-facing ns's from the likely-to-change internals. I've found the major drawback to this strategy is that the import-fn makes it much more difficult to walk (in emacs) from the use of a function into it's implementation. Or to know which function to use clojure.repl/source on for example.
A library like Compojure uses private vars to separate public/private parts of the functions (see compojure.core for example). The major drawback with "private" functions is that you may later find you want to expose them or that it makes testing more complicated. If you control the code base, I don't find the private aspects to be a big deal. The testing issue is easily worked around by using #'foo.core/my-function to refer to the private function.
Generally I tend to use something more like Compojure's style than Lamina's but it sounds like you'd prefer something more like Lamina.
I'm not exactly sure what your asking here. I think maybe you want to know what the best practice for importing publics from a namespace for shared utility functions? In that case the refer function is what you are looking for I think: http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/refer
(refer mylib.a :only [+])
(refer mylib.b :only [-])
It imports the public items in a namespace into the current namespace. However the preferred method would be to do this in your namespace declaration with a :use directive
(ns (:use (mylib.a :only [+])
(mylib.b :only [-])))