How can I detect the Clojure runtime environment? - clojure

I've written a very simple date library in Clojure and I'd like to be able to use it both when my code runs in a JVM and when it is compiled to Javascript with ClojureScript. The fly in the ointment is how to detect which runtime environment the code is in so that a macro might use the platform's own date string parsing mechanism. Each platform's date objects
How should one write a library that may be reused across different deployment platforms like the JVM, JS, CLR etc.? I know that one might cheat and parse date strings with a regex but that will not easily cover the case of parsing month names from the large variety of human languages which the built-in date parsing libraries solve quite nicely.

Use resolve to find out which vars defined:
user=> (resolve '*clojurescript-version*)
nil
user=> (resolve '*clojure-version*)
#'clojure.core/*clojure-version*
user=> *clojure-version*
{:major 1, :minor 5, :incremental 1, :qualifier nil}

You can use these misc vars:
http://clojuredocs.org/clojure_core/clojure.core/clojure-version
Returns clojure version as a printable string.
http://clojuredocs.org/clojure_core/clojure.core/clojure-version
The version info for Clojure core, as a map containing :major :minor
:incremental and :qualifier keys. Feature releases may increment
:minor and/or :major, bugfix releases will increment :incremental.
Possible values of :qualifier include "GA", "SNAPSHOT", "RC-x" "BETA-x"

Clojure has special Conditional reader rule to switch b/w runtimes.
In your example, it would something like:
(def ^:dynamic *runtime*
#?(:clj :clojure)
#?(:cljs :clojurescript))
(print *runtime*) ;; :clojure

Related

Why BENCODE has been used for transporting clojure code to nrepl in CIDER?

Why can't we simply convert Clojure code to string and send it over TCP and evaluate on the other side(nrepl)?
For example : This is a hashmap {"foo" "bar", 1 "spam"} whose BENCODE encoding is d3:foo3:bari1e4:spame.
If we convert it to string -> {\"foo\" \"bar\", 1 \"spam\"}
and evaluate on the other side instead of using BENCODE as shown below.
(eval (read-string "{\"foo\" \"bar\", 1 \"spam\"}"))
; ⇒ {"foo" "bar", 1 "spam"}
I am new to the Clojure world. This might be a stupid question but anyway.
nREPL's maintainer here. There are several reasons why nREPL uses bencode by default:
We needed a data format that supports data streaming easily (you won't find many streaming JSON parsers)
We needed a data format that could easily be supported by many clients (support for formats like JSON and EDN is tricky in editors like Emacs and vim). I can tell you CIDER would not have existed if 8 years ago we had to deal with JSON there. :-)
Bencode is so simple that usually you don't even need to rely on a third-party library for it (many clients/servers have their own implementation of the encoding/decoding in less than 100 lines of code) - this means means that clients/servers have one less 3rd party library. Tools like nREPL can't really have runtime deps, as they conflict with the user application deps.
EDN didn't exist back when nREPL was created
Btw, these days nREPL supports EDN and JSON (via the fastlane library) as well, but I think that bencode is still the best transport in most cases.
For people looking for the answer, read the # Motivation section in https://github.com/clojure/tools.nrepl/blob/master/src/main/clojure/clojure/tools/nrepl/bencode.clj
This is very well written.

Clojure - require several versions of a library in a project

Everything is in the title, but here is an example use case :
a function had a first parameter like the following :
(my-fn "a.b.c" ...)
Which now in a newer version became :
(my-fn ... ["a", "b", "c"])
Is it possible to :require a specific version of a library ?
For instance :
:require my.util.lib :as newlib ;; new version
:require my.util.lib#v0.0.1 :as lib ;; old library
It would then allow to migrate this library usage file per file.
As mentioned in the comments, I think Osgi is the only true way to accomplish this, and probably not worth the effort in complexity to set it up.
What are the versions of the library you are using? If it is following semantic versioning practices, and it still on a version with breaking changes, you have to be prepared for this sort of thing and will probably just have to update your code.

Clojure file-system portability

I want to write a simple program for playing sound clips. I want to deploy it on Windows, Linux and MacOSX. The thing that still puzzles me is location of configuration file and folder with sound clips on different operating systems. I am a Clojure noob. I am aware that Common Lisp has special file-system portability library called CL-FAD. How it is being done in Closure? How can I write portable Clojure program with different file system conventions on different systems?
You can use clojure.java.io/file to build paths in a (mostly) platform-neutral way, similarly to how you would with os.path.join in Python or File.join in Ruby.
(require '[clojure.java.io :as io])
;; On Linux
(def home "/home/jbm")
(io/file home "media" "music") ;=> #<File /home/jbm/media/music>
;; On Windows
(def home "c:\\home\\jbm")
(io/file home "media" "music") ;=> #<File c:\home\jbm\media\music>
clojure.java.io/file returns a java.io.File. If you need to get back to a string you can always use .getPath:
(-> home
(io/file "media" "music")
(.getPath))
;=> /home/jbm/media/music"
Is that the sort of thing you had in mind?
In addition to clojure.java.io (and, of course, the methods on java.io.File), raynes.fs is a popular file system utility library.
Note that Windows perfectly supports the forward slash as a path separator (which is awesome because that way you don't have to escape backslashes all the time).
The only significant difficulty you'll run into is that the "standard" locations (home folder, etc.) are different on Windows and UNIX systems. So you need to get those from the system properties (see the getProperty method in http://docs.oracle.com/javase/7/docs/api/java/lang/System.html).
For a platform-independent approach, you can find the canonical path from a path relative to the project and then join it with the filename.
(:require [clojure.java.io :as io :refer [file]]))
(defn file-dir
"Returns canonical path of a given path"
[path]
(.getCanonicalPath (io/file path)))
(-> "./resources" ;; relative
(file-dir)
(io/file "filename.txt")) ;;=> /path/to/project/resources/filename.txt

Equivalent to clojure.contrib's show?

There used to be this useful utility called show in clojure.contrib. Now, that it's deprecated, is there an equivalent to it?
Thanks!
De-constructing show to be more "simple", making available distinct pieces of re-usable functionality, was discussed by Stuart Halloway in a talk he give on clojure simplicity.
The resulting code makes use of clojure.reflect/reflect and clojure.pprint/print-table
and standard clojure filter:
(require 'clojure.reflect)
(require 'clojure.pprint)
(->> (clojure.reflect/reflect java.lang.String)
:members
(filter #(.startsWith (str (:name %)) "last"))
(clojure.pprint/print-table))
I refer you to the Where Did Clojure.Contrib Go document, which says about clojure.contrib.repl-utils:
Migrated to clojure.repl and clojure.java.javadoc. show functionality similar to clojure.reflect/reflect.
The clojure.reflect API documentation is here, and the clojuredocs.org examples are here.

Code sharing between server and client in Clojurescript/Clojure

Say I wanted to factor out some common code between my client-side *.cljs and my server-side *.clj, e.g. various data structures and common operations, can I do that ? Does it make sense to do it ?
I wrote the cljx Leiningen plugin specifically to handle Clojure/ClojureScript code sharing for a Clojure data visualization library.
95% of non-host-interop code looks the same, and cljx lets you automatically rewrite that last 5% by specifying rewrite rules using core.logic.
Most of the time, though, it's simple symbol substitutions; clojure.lang.IFn in Clojure is just IFn in ClojureScript, for instance.
You can also use metadata to annotate forms to be included or excluded when code is generated for a specific platform.
Update: as of clojure 1.7, check out Clojure reader conditionals or cljc. I've used cljc with great success to share a lot of code between server and browser very easily.
Great question! I've been thinking a lot about this as well lately and have written a few apps to experiment.
Here's my list of what types things you might want to share and pros/cons of each:
Most of my client cljs files contains code that manipulates the dom. So, it wouldn't make sense to share any of that with server
Most of the server side stuff deals with filesystem and database calls. I suppose you might want to call the database from the client (especially if you're using one of the no-sql db's that support javascript calls). But, even then, I feel like you should choose to either call db from client or call db from server and, therefore, it doesn't make much sense to share the db code either.
One area where sharing is definitely valuable is being able to share and pass clojure data structures (nested combinations of lists, vectors, sets, etc) between client and server. No need to convert to json (or xml) and back. For example, being able to pass hiccup-style representations of the dom back and forth is very convenient. In gwt, I've used gilead to share models between client and server. But, in clojure, you can simply pass data structures around, so there's really no need to share class definitions like in gwt.
One area that I feel I need to experiment more is sharing state between client and server. In my mind there are a few strategies: store state on client (single page ajax type applications) or store state on server (like legacy jsp apps) or a combo of both. Perhaps the code responsible for updating state (the atoms, refs, agents or whatever) could be shared and then state could be passed back and forth over request and response to keep the two tiers in synch? So far, simply writing server using REST best practices and then having state stored on client seems to work pretty well. But I could see how there might be benefits to sharing state between client and server.
I haven't needed to share Constants and/or Properties yet, but this might be something that would be good to reuse. If you put all your app's global constants in a clj file and then wrote a script to copy it over to cljs whenever you compiled the clojurescript, that should work fine, and might save a bit of duplication of code.
Hope these thoughts are useful, I'm very interested in what others have found so far!
The new lein-cljsbuild plugin for Leiningen has built-in support for sharing pure Clojure code.
Wrote a quick bit of code to copy a subset of my server clojure code over to my clojurescript code, renaming as .cljs before building:
(ns clj-cljs.build
(use
[clojure.java.io]
)
(require
[cljs.closure :as cljsc]
)
)
(defn list-files [path]
(.listFiles (as-file path))
)
(defn copy-file* [from to]
;(println " coping " from " to " to)
(make-parents to)
(copy from to)
)
(defn rename [to-path common-path f]
(str to-path common-path (.replaceAll (.getName f) ".clj" ".cljs"))
)
(defn clj-cljs* [files common-path to-path]
(doseq [i (filter #(.endsWith (.getName %) ".clj") files)]
(copy-file* i (file (rename to-path common-path i)))
)
(doseq [i (filter #(.isDirectory %) files)]
(clj-cljs* (list-files i) (str common-path (.getName i) "/") to-path)
)
)
(defn build [{:keys [common-path clj-path cljs-path js-path module-name]}]
(clj-cljs* (list-files (str clj-path common-path)) common-path cljs-path)
(cljsc/build
cljs-path
{
:output-dir js-path
:output-to (str js-path module-name ".js")
}
)
)
(defn build-default []
(build
{
:clj-path "/home/user/projects/example/code/src/main/clojure/"
:cljs-path "/home/user/projects/example/code/src/main/cljs/"
:js-path "/home/user/projects/example/code/public/js/cljs/"
:common-path "example/common/" ; the root of your common server-client code
:module-name "example"
}
)
)
This question predates cljc, but since I stumbled upon it, I thought I would mention Clojure reader conditionals.