Attempting to call unbound fn: #'datoteka.core/to-file - clojure

I am very new to clojure and I get the following error:
Caused by: java.lang.IllegalStateException: Attempting to call unbound fn: #'datoteka.core/to-file
at clojure.lang.Var$Unbound.throwArity(Var.java:45)
at clojure.lang.AFn.invoke(AFn.java:32)
at package.auth_monitor$start_monitor_thread.invokeStatic(auth_monitor.clj:43)
at package.auth_monitor$start_monitor_thread.invoke(auth_monitor.clj:38)
at package.auth_monitor$start_monitor.invokeStatic(auth_monitor.clj:62)
at package.auth_monitor$start_monitor.invoke(auth_monitor.clj:49)
at package.auth_monitor$fn__11768.invokeStatic(auth_monitor.clj:71)
at package.auth_monitor$fn__11768.invoke(auth_monitor.clj:70)
the code is:
42. (let [^TailerListener listener (make-listener)
43. ^File file (fs/to-file path)
44. ^Tailer tailer (Tailer. file listener 1000 true)]
45. (doto (Thread. tailer)
46. (.setDaemon false)
47. (.start)))

I presume you are using the Datoteka library. Try using the file function to get a File object based on the path (to-file seems to be a wrong name):
(let [^TailerListener listener (make-listener)
^File file (fs/file path)
^Tailer tailer (Tailer. file listener 1000 true)]
(doto (Thread. tailer)
(.setDaemon false)
(.start)))

Related

custom accept function in start-server clojure

I'm trying to run clojure.core.server/start-server but instead of using the repl I want a custom function as accept option. I'm following this post where a repl server is executed as
clojure -X clojure.core.server/start-server :name '"server"' :port 5555 :accept clojure.core.server/repl :server-daemon false
What requirements do I need to pass a function to accept opt? What if I only want to print the request from any connection? Using something like clojure.core/println didn't work
clojure -X clojure.core.server/start-server :name '"server"' :port 5555 :accept clojure.core/println :server-daemon false
btw, I can't even run start-server on the repl itself, I've got the error everytime a made a request. Is it possible to run it from the repl?
(clojure.core.server/start-server {:name "server" :port 9000 :accept clojure.core.server/repl :server-daemon false})
#object[java.net.ServerSocket 0x25b865b5 "ServerSocket[addr=localhost/127.0.0.1,localport=9000]"]
user=> Exception in thread "Clojure Connection server 1" java.lang.ClassCastException: class clojure.core.server$repl cannot be cast to class clojure.lang.Named (clojure.core.server$repl and clojure.lang.Named are in unnamed module of loader 'app')
at clojure.core$namespace.invokeStatic(core.clj:1612)
at clojure.core.server$accept_connection.invokeStatic(server.clj:73)
at clojure.core.server$start_server$fn__8998$fn__8999$fn__9001.invoke(server.clj:117)
at clojure.lang.AFn.run(AFn.java:22)
at java.base/java.lang.Thread.run(Thread.java:833)
The start-server function states, that :accept must be a namespaced
symbol (so this is the reason, why you see the error in your REPL
(you are passing a variable; use 'clojure.core/println instead --
note the leading ').
As for passing your own function, it helps to take a look at the
function clojure.core.server/accept-connection, what is actually going
on. So basically your :accept function gets called with *in*,
*out*, *err* redirected (and also a binding of *session* with some
book-keeping) and the :args. So you want to read/write on
stdin/stdout in your function and parameterize with the given arguments.
E.g. create a file src/so.clj with the following content:
(ns so)
(defn accept
[prefix]
(loop []
(println prefix (read-line))
(recur)))
Then start the server from the same root:
clojure -X clojure.core.server/start-server :name '"server"' :port 5555 \
:accept so/accept \
:args '[">>>"]' \
:server-daemon false
Note the :accept symbol (it's coming from the shell, so Clojure reads
that as a symbol) points to the namespace and the function within. Make
sure, things match up with the class-path (src is a default source
path for the Clojure CLI).
Also note the passing of the :args represented as an EDN array.
Inside accept-connection the call to your function is then (apply accept args), so you can assume regular arguments in your accept-fn.
Then test your server with e.g. telnet:
% telnet localhost 5555
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hello
>>> hello
world
>>> world

Creating a new text file in a diretory using org-capture

Following this response: Org-Mode - How do I create a new file with org-capture?
I am trying to make this piece of code work, but I get the error: invalid file location: nil.
(defun capture-report-data-file (path)
(let ((name (read-string "Name: ")))
(expand-file-name (format "%s-%s.txt"
(format-time-string "%Y-%m-%d")
name) path)))
'(("t"
"todo"
entry
(file (capture-report-date-file "~/path/path/name"))
"* TODO")))
Actually, it works like this:
Replace
(file (capture-report-date-file "~/path/path/name"))
with
(file (lambda () (capture-report-date-file "~/path/path/name")))

How to show error on missing parameters for options?

I'm an absolute Clojure beginner and I'm trying to build a CLI app using the clojure.tools.cli library.
My problem is that I can't show any error when an option is not provided with required parameter.
What I want:
$ java -jar test.jar -m SAMPLE
Given file: SAMPLE
$ java -jar test.jar -m
ERROR: Please provide a file
What happens:
$ java -jar test.jar -m SAMPLE
Given file: SAMPLE
$ java -jar test.jar -m
$
It doesn't show anything.
Here is my code:
(ns obmed-clj.core
(:require [clojure.tools.cli :refer [parse-opts]])
(:gen-class))
(def cli-options
[["-m" "--menu FILE" "Provide menu file path"
:parse-fn #(if (nil? %)
(println "ERROR: Please provide a file")
%)
:validate-fn #(println "Given file:" %)]])
(defn -main [& args]
(parse-opts args cli-options))
You are abusing the -fn arguments here a little. Their use is to convert the "string" (in your case, since you have "--menu FILE") and then do additional validation on that (but rather use :validate [fn msg] instead). So e.g.:
user=> (def cli-opts [["-m" "--menu FILE" "menu file"
:parse-fn #(java.io.File. %)
:validate [#(.exists %) "file must exist"]]])
#'user/cli-opts
Missing argument:
user=> (parse-opts ["-m"] cli-opts)
{:arguments [],
:errors ["Missing required argument for \"-m FILE\""],
:options {},
:summary " -m, --menu FILE menu file"}
File not existing:
user=> (parse-opts ["-m" "XXX"] cli-opts)
{:arguments [],
:errors ["Failed to validate \"-m XXX\": file must exist"],
:options {},
:summary " -m, --menu FILE menu file"}
All is well:
user=> (parse-opts ["-m" "/etc/hosts"] cli-opts)
{:arguments [],
:errors nil,
:options {:menu #<java.io.File#34d63c80 /etc/hosts>},
:summary " -m, --menu FILE menu file"}

writing a test to check the file returned by a ring response

I have a compojure route which returns a file. I want to test -
1) If a file is returned.
2) The specific file that was returned.
When I run (app (ring.mock/request :get "/myroute")) I get
{:body #<File resources/public/templates/index.html>, :headers {"Content-Length" "2349", "Last-Modified" "Sat, 16 Mar 2013 11:01:03 GMT"}, :status 200}
How do I check that the returned value in the body is of a type file ? And getting more ambitious can I check it is the file located at 'resources/public/templates/index.html' ?
Ring requests are just maps, so you can extract the body with the :body keyword and then check it's type with type
(type (:body (app (ring.mock/request :get "/myroute"))))
(perhaps I'm not understanding the question though?)

Clojure throws ClassCastException on java.util.Collection

I'm trying to use an MPD library in Java in Clojure. Everything has gone well, but these methods that return a java.util.Collection get bad reception in REPL. Let's define
(def mpd (org.bff.javampd.MPD. "localhost" ))
(def pl (.getMPDPlaylist mpd))
(def db (.getMPDDatabase mpd))
And now some methods play ok:
(.getSongList pl) ; returns List<MPDSong>
works well. But for instance every db (MPDDatabase) method return Collection<MPDSong> (according to their API):
(.findAlbum db "Crises") ; returns Collection<MPDSong>
java.lang.ClassCastException (NO_SOURCE_FILE:0)
Doesn't work that well. Why is that, how to fix it?
Stack trace follows:
hello.hello=> (.findAlbum db "Crises")
java.lang.ClassCastException (NO_SOURCE_FILE:0)
hello.hello=> (.printStackTrace *e)
java.lang.ClassCastException (NO_SOURCE_FILE:0)
at clojure.lang.Compiler.eval(Compiler.java:5440)
at clojure.lang.Compiler.eval(Compiler.java:5391)
at clojure.core$eval.invoke(core.clj:2382)
at clojure.main$repl$read_eval_print__5624.invoke(main.clj:183)
at clojure.main$repl$fn__5629.invoke(main.clj:204)
at clojure.main$repl.doInvoke(main.clj:204)
at clojure.lang.RestFn.invoke(RestFn.java:422)
at user$eval13$acc__808__auto____14$fn__16.invoke(NO_SOURCE_FILE:1)
at clojure.lang.AFn.run(AFn.java:24)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.ClassCastException
at java.lang.Class.cast(Class.java:2990)
at clojure.lang.Reflector.boxArg(Reflector.java:364)
at clojure.lang.Reflector.boxArgs(Reflector.java:397)
at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:55)
at clojure.lang.Reflector.invokeInstanceMethod(Reflector.java:28)
at hello.hello$eval44.invoke(NO_SOURCE_FILE:8)
at clojure.lang.Compiler.eval(Compiler.java:5424)
... 9 more
nil
Looks like the API Documentation is invalid (checking using clojure.contrib.repl-utils):
user> (show MPDDatabase "findAlbum$")
=== public org.bff.javampd.MPDDatabase ===
[ 1] findAlbum : Collection (MPDAlbum)
and you need to a intermediate MPDAlbum object:
user> (.findAlbum db (MPDAlbum. "Crisis"))
#<ArrayList []>