Clojure file-system portability - clojure

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

Related

How do I require clojure.java.io with lein exec?

I am totally new to clojure. I would like to start writing simple scripts, and I came across lein-exec as a means of doing so even if a script contains dependencies. Although I can run an example I found online, I don't know how to require clojure.java.io.
(require 'leiningen.exec)
;places the dependency on the classpath
(leiningen.exec/deps '[[enlive/enlive "1.1.4"]])
(require '[net.cgrand.enlive-html :as html])
How would I require something like clojure.java.io using lein exec?
EDIT: adding more detail
(require 'leiningen.exec)
(leiningen.exec/deps '[[clojure.java.io]])
(require 'clojure.java.io)
(defn Example []
(.exists (clojure.java.io "Example.txt")))
(Example)
gives me
Caused by: java.lang.IllegalArgumentException: Provided artifact is missing a version: [clojure.java.io]
and this
(require 'leiningen.exec)
;(leiningen.exec/deps '[[clojure.java.io]])
(require 'clojure.java.io)
(defn Example []
(.exists (clojure.java.io "Example.txt")))
(Example)
gives me
Caused by: java.lang.ClassNotFoundException: clojure.java.io
Well, personally, I'd recommend using inlein instead of lein-exec for doing scripting with Clojure:
http://inlein.org/
https://github.com/hypirion/inlein
I find it nicer, and it uses standard lein dependency map for defining your dependencies.
Secondly, this: (require 'clojure.java.io) IS the right way to require clojure.java.io. That namespace is included with Clojure itself, so you don't need to declare an additional dependency on any other library to use it.
Your problem is that you are not using it correctly:
(.exists (clojure.java.io "Example.txt"))
In the above code, you are calling clojure.java.io as if it was a function, but it is not a function, it is a namespace. You need to choose a function inside of it to call, such as the file function. If this was java, you could kinda think of the namespace as the class, and the function as a method on the class. If you do:
(.exists (clojure.java.io/file "Example.txt"))
It should work now. Notice how in Clojure, the syntax is: namespace/function. This is different the some other languages like Java or Python, where you would have: some.location.class.method instead, basically the function is also separated by a .. This is not the case in Clojure, in Clojure, the function part is separated by a /.

Make clojure functions available in every namespace during development?

I have number of useful helper functions that I use at the REPL during Clojure development. This includes some built-in functions like doc and pprint, but also some custom ones of my own from my user.clj. The default clojure experience seems to be:
dev> (doc +)
;; works
dev> (in-ns 'project.core)
project.core> (doc +)
;; what is this "doc" thing you're talking about!?!?
which is pretty irritating (I'm aware that I can refer to clojure.repl/doc here). Is there an easy way to ensure that something is available during development regardless of which namespace I'm currently operating in?
One option is to add a :repl-options to your project map in project.clj:
(defproject myproj "1.0"
:dependencies [[org.clojure/clojure "1.9.0-alpha15"]]
:repl-options { :init-ns myproj.core
:init (require '[clojure.repl :refer :all]) })
...
$ lein repl
myproj.core=> (doc +) ; works
As Alex Gherega mentions, it's probably a bad idea to automatically and indiscriminately import stuff into every namespace. However, you could create a macro (or maybe a function would work?) to help import development-related namespaced when/if they are needed. Add it to your user.clj. Then if you are working in another namespace and decide it would be useful, you can just run (user/import-useful-dev-stuff) (or whatever you decide to call it).
For what it's worth, I pretty much do all my REPL sessions within the user namespace and require all the namespaces I need from there. I use Emacs, and if I need to change something in another namespace, I just change the source, then do C-c C-k (after initiating a cider session) to reload the file. If you don't use Emacs, it's only a little more work to reload from the REPL via require with the :reload option.
Unless you use boot or lein or some other form that would "magically" add this namespace to your REPL development session then I'm afraid you're just have to require it by hand every time.
The thing is namespaces have their well intended role of avoiding name conflicts. If you would have another way of telling a current namespace to use/require another namespace without doing it then you would have a whole lot of other problems.
If you're not using lein/boot you could just do as Alex Miller responded. For a more controlled way of what you need from the clojure.repl or some other ns API just have a require & use declaration in you namespace of interest e.g.:
(ns 'project.core
(:require [clojure.repl :refer [doc]]))
If you get yourself in this situation, do:
(clojure.core/refer-clojure)
to require and load everything from clojure.core.
Or an alternate approach, if project.core exists, is to instead:
(require 'project.core)
(in-ns 'project.core)
Loading the namespace via require will refer clojure.core.
Or if project.core does not exist, do:
(ns project.core)
The ns macro will do both refer-clojure and in-ns.

Import Record Type in Clojure/ClojureScript

Is there any way to import a record type, that works in Clojure as well as ClojureScript?
As far as I can tell it's (ns x (:import y [A B])) for Clojure, (ns x (:require y :refer [A B])) for ClojureScript, and each is invalid for the respective other.
Ignoring the specifics on the syntax of requiring records, there are two main ways to write ns declarations (or any platform specific code) for multiple Clojure variants while sharing the majority of your code.
CLJX is a Clojure preprocessor that runs before the Clojure compiler. You write platform specific code prefixed with #+clj or #+cljs in a .cljx file. It can run on pretty much any Clojure code, and will spit out multiple platform specific files which the respective Clojure Compilers can handle.
Reader Conditionals are a feature in Clojure 1.7 and are available in recent releases of ClojureScript. This is similar in spirit to cljx, but is integrated into the Clojure Compiler. You write code with reader conditionals like #?(:clj 1 :cljs 2) in files with a .cljc extension.
Now back to your specific question, you can achieve this with Reader Conditionals like so:
(ns myapp.music-store
(:require #?(:clj [myapp.cool-music]
:cljs [myapp.cool-music :refer [Vinyl]]))
#?(:clj
(:import [myapp.cool_music Vinyl])))
I wrote a longer blog post about this too: Requiring records in Clojure and ClojureScript

Can I conditionally compile clojure / clojurescript?

Is there a way to in clojure / clojurescript to conditionally compile something depending on whether you're compiling to JVM bytecode of Javascript?
I am writing a small game in ClojureScript but want to keep the majority of the code platform neutral so I can convert to Clojure at some point. I also find that compiling in Clojure is better for finding errors in my code.
I have this working fine by having a directory of clj files that cljsbuild converts to cljs using crossovers.
Where I've come unstuck is trying to use core.async in my clj files. This is needed for cljs:
(ns gaz.system
(:require-macros [cljs.core.async.macros :refer [go]])
(:require
[cljs.core.async]))
While this is needed for clj to work
(ns gaz.system
(:require
[core.async ]))
I'd love to have one file with some form conditional require depending on how it's being compiled. Is that possible at all?
Con
Have a look at cljx. It let's you prefix s-expressions with e.g. #+clj or #+cljs to create different code for Clojure and Clojurescript.
Also, though I have not tried it so far, there is lein-dalap which seems to rely on pure, compilable Clojure to generate Clojurescript.

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.