Clojure read file or spreadsheet - clojure

I need help on how to read .xlsx files in clojure. I found this library docjure and can't run their sample code as below.
(->> (load-workbook "sample.xlsx")
(select-sheet "Price List")
(select-columns {:A :name, :B :price}))
Running the above code throws a FileNotFoundException from the core.clj file even though i am sure the "sample.xlsx" exists in the same directory as core.clj.
I think the issue is reading the file and would appreciate help in doing so but i am open to suggestions too, thanks.

Related

Distributing a simple library via clojars

I have implemented a hyphenation algorithm (at namespace hyphenator-clj.core), defined it as org.clojars.nikonyrh.hyphenator-clj 0.1.0 at defproject and pushed it to Clojars. Uberjar seems to have files like core__init.class, core.clj and core.class.
However when I try to use it as a dependency on an other project I get this error:
$ lein uberjar
Retrieving org/clojars/nikonyrh/hyphenator-clj/org.clojars.nikonyrh.hyphenator-clj/0.1.0/org.clojars.nikonyrh.hyphenator-clj-0.1.0.pom from clojars
Retrieving org/clojars/nikonyrh/hyphenator-clj/org.clojars.nikonyrh.hyphenator-clj/0.1.0/org.clojars.nikonyrh.hyphenator-clj-0.1.0.jar from clojars
Compiling example.core
java.io.FileNotFoundException: Could not locate org/clojars/nikonyrh/hyphenator_clj__init.class or org/clojars/nikonyrh/hyphenator_clj.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name., compiling:(core.clj:1:1)
Exception in thread "main" java.io.FileNotFoundException: Could not locate org/clojars/nikonyrh/hyphenator_clj__init.class or org/clojars/nikonyrh/hyphenator_clj.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name., compiling:(core.clj:1:1)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3657)
at clojure.lang.Compiler.compile1(Compiler.java:7474)
at clojure.lang.Compiler.compile1(Compiler.java:7464)
at clojure.lang.Compiler.compile(Compiler.java:7541)
at clojure.lang.RT.compile(RT.java:406)
at clojure.lang.RT.load(RT.java:451)
at clojure.lang.RT.load(RT.java:419)
at clojure.core$load$fn__5677.invoke(core.clj:5893)
...
Must I change my project's folder structure so that it matches the expected org/clojars/nikonyrh/hyphenator_clj__init.class, or can I somehow override the current behavior? If there is a good tutorial about this out there I would be happy to read it.
Basically I would like to get this example project to work. project.clj:
(defproject example "0.0.1-SNAPSHOT"
:description ""
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojars.nikonyrh.hyphenator-clj "0.1.0"]]
:javac-options ["-target" "1.6" "-source" "1.6" "-Xlint:-options"]
:aot [example.core]
:main example.core)
src/example/core.clj:
(ns example.core
(:require [org.clojars.nikonyrh.hyphenator-clj :as h])
(:gen-class))
(defn -main [& argv] (doseq [arg argv] (println (h/hyphenate arg :hyphen \-))))
I'm suspecting I also have the english.txt in a wrong directory, as it isn't contained in the uberjar but resource files are an other topic.
You would probably be better off not using a hyphen in the namespace hyphenator-clj. Why not just use hyphenator? But if you do I suspect that the name of the directory should have an underscore in it rather than a hyphen, so be: hyphenator_clj.
If fixing that issue doesn't help then another thing to look out for, which I can't see from your question, is where exactly is core.clj in the directory structure, and does the project.clj reflect that? For instance is the path for the namespace hyphenator-clj.core in a src directory off the root of your project? The root of your project being defined as where the project.clj is located.
Something else that would be good to see in the question is whether you can get the program to work just locally, without having packed it up into an uberjar and shipped it to clojars. My guess would be that it does work locally, but it would help for that to be stated.
Okay taking a look at your links now. You might like to read a working project deployed to clojars, that has hypens in its name, for instance here. The first difference you might notice is the project name you use is rather long: org.clojars.nikonyrh.hyphenator-clj. It should just be hyphenator-clj. Also I would recommend having an identifier ending in "-SNAPSHOT" as that project does.
But taking a look at the bigger picture, a great idea you suggested in the comments is to test without Clojars being in the mix at all. To do this use lein install on the library you want to use from another lein project.
Ahaa at least I understand the process a bit better now, basically my require has to match the structure of the used JAR file, which may be very different from the project's name. For example cc.qbits/spandex is actually required as qbits.spandex.
The english.txt dependency was fixed by moving it to resources folder, deploying the new version to Clojars and importing the dependency as it exists in the JAR:
(ns example.core
(:require [hyphenator-clj.core :as h])
(:gen-class))
(defn -main [& argv] (doseq [arg argv] (println (h/hyphenate arg :hyphen \-))))

Could not locate file when importing it

I just started playing with clojure, and I have a question.
I create a folder called testingclojure in ~/ and it contains a file called core.clj which has a simple function like this:
(ns testingclojure.core)
(defn greetings
[{:keys [name age]}]
(format "Hello my name is %s and I'm %s years old" name age))
So the filepath is: ~/testingclojure/core.clj
Meanwhile I'm in ~/, and I want to use it in repl, so I type:
(use '[testingclojure [core :as c]])
Unfortunately, I got an error, something like "Could not locate testingclojure/core.clj". How to solve this problem?
How do you invoke the repl?
Are you using leiningen or just the clojure jar?
You need to include the current folder
if you are using the clojure jar
java -cp [path to clojure jar];.; clojure.main
if you are using leiningen place your code in the src folder or use the src directive in your project.clj to point it to the right source folder.

Why don't absolute classpaths work when starting clojure repl?

A problem has traped me for quite a while when I'm exploring Clojure. I try to generate a class by invoking the compile function in REPL on a Clojure script as below:
(ns mylib.DirLister (:gen-class))
(defn -listDir [this path]
(->> path java.io.File. .listFiles (map #(.getName %))))
I saved this script to e:/temp/clj/src/mylib/DirLister.clj. The following session goes well when I specify the relative paths for the -cp option, i.e., classes are successfully generated in the classes path:
e:\temp\clj>java -cp .\src;.\classes;d:/tools/clojure-1.4.0/clojure-1.4.0.jar clojure.main
Clojure 1.4.0
user=> (compile 'mylib.DirLister)
mylib.DirLister
user=>
But when I use absolute paths, there prompt a "No such file or directory" error:
e:\>java -cp e:/temp/clj/src;e:/temp/clj/classes;d:/tools/clojure-1.4.0/clojure-1.4.0.jar clojure.main
Clojure 1.4.0
user=> (compile 'mylib.DirLister)
CompilerException java.io.IOException: No such file or directory, compiling:(mylib/DirLister.clj:1)
user=>
How come ? I mean why the absolute paths don't work but the relative paths do.
I know I could go with leiningen. but since I'm studying Clojure, I want to understand the stuff underneath before adopting this full-featured tool.
Looks to me like you have a mixture of forward-slash and backward-slashes on the command line. I'm not sure exactly what shell you are using and whether that could make a difference. But, a path with e: in it would normally require a back-slash '\'. Maybe this will help, or at least remove one potential source of problems?
Could you try to change the 2nd example to use
e:\temp\clj\src;e:\temp\clj\classes;d:\tools\clojure-1.4.0\clojure-1.4.0.jar
to see if that helps?
Finally I got the answer:
the compile function will always use the value of the built-in variable *compile-path* as the path of the output classes, which defaulted to "classes" under the current directory if you didn't set it otherwise. So the problem I came across is not really about relative or absolute path, it is about the current directory and the value of *compile-path* .
Refer to ClojureDoc .

clojure how to know the path of a folder / file / directory in one project?

Assume there is two files inside my clojure project, one clj and the other is txt.
Is there a way to know the path (as a string) of the txt file from the clj file?
There is:
(System/getProperty "user.dir")
or
(-> (java.io.File. ".") .getAbsolutePath)
But this gives where the current directory. The one that includes the clj file, the one the code is written in.
But how to know the path of the txt file?
The purpose is to write into this txt file from the clj file.
Thank you.
In Java and therefore Clojure you can find files on the CLASSPATH. For example, in Java it is common to put things like log4j.properties at the top of your CLASSPATH (e.g., in the classes directory) and then you can reference the file in your Clojure (or Java) code with:
(java.io.File. "log4j.properties")
Are you using and running your app with Leiningen? If so, you can create a directory at the top level and put files there. For example, if you have a config file you can have a "conf" dir with a properties files:
my-lein-proj$ ls
conf doc project.clj README.md src target test
Suppose you put a myproj.conf file in the conf directory and you want to read from it in your Clojure code. Then you can just do:
(slurp "conf/myproj.conf")
The Clojure library local-file allows you to get your current project's directory with local-file/project-dir. As long as you know where in your project the file you want to access is, you should be able to find it this way.
This gives where the current clj file, the one that this code is
written in.
No, it doesn't.
It gives the current directory.
Did you take into account that one can run clojure scripts that are not in the current directory?
if your file structure is something similar to this:
config | src | target | test
you have a config inside config directory, in our case let's assume its java.config and you are trying to read this file inside core.clj in src directory you can also use clojure.java.io/reader method
for example:
(clojure.java.io/reader "config/java.config")
you can run below commands in the repl to see the contents of the file
(slurp (clojure.java.io/reader "config/java.config")
if you are interested in reading the contents of the file line by line you combine above function with with-open method and read line by line:
(with-open [word (clojure.java.io/reader "config/java.config")]
(loop [c (.read word)]
(if (not= c -1)
(do
(print (char c))
(recur (.read word))))))

Determine file-script directory at runtime from clojure

I am creating a third-party library for Clojure. In the core of this library I need to run script from the operation system. In this case I cannot use absolute path to this file like this /Users/me/src/clojure-pymorphy/src/pymorphy/pymorphy.py.
But if I use relative path script/script.py - than sometimes location of the script could be determined as wrong. It depends on the directory from which I run/use this clojure library. Because this library will be distributed as the third-party I need the way to determine the path of script.py from Clojure source code.
Project folders looks like this:
clojure-pymorphy/
src/
pymorphy/
pymorphy.py
pymorphy.clj
Script pymorphy.py is invoked from pymorphy.clj. File pymorphy.clj begins from this lines:
(ns pymorphy
(:import (java.util ArrayList)
(jep Jep)))
I've tried to find out is there a way to determine directory to pymorphy namespace at runtime and just simply add "pymorphy/pymorphy.py" to it. But after many hours of googling I come to conclusion that it's not possible.
So is there any other ways to dynamically determine path to clojure namespace at runtime?
Many thanks.
While looking at the similar questions at stackoverflow I find the solution:
(.getFile (clojure.java.io/resource "pymorphy/pymorphy.py"))
If you to run this script, so this will be something like - this will copy script to temp file, and run it. You need to create file, because if you'll pack everything into jar, then interpreter won't be able to read file..
(let [tmp (File/createTempFile "tmp" "py")
script (clojure.java.io/resource "pymorphy/pymorphy.py")]
(try
(when (and script (.exists tmp))
(with-open [os (.openStream script)]
(clojure.java.io/copy os tmp))
(run-script....))
(finally
(when (.exists tmp)
(.delete tmp)))))