I have defined a -main function in a :gen-class :main true namespace in Clojure. I am trying to test it from the REPL.
My main function looks like this:
(defn -main [& args]
; ...
)
and I am trying to call it with (ns/-main "-x" "foo"), (ns/-main "-x foo"), (ns/-main ["-x" "foo"]), (ns/-main (into-array String ["-x" "foo"]), etc., and all give me various errors.
How do I call this function from the REPL and pass in some command line arguments to test it?
Thanks.
I tried to reproduce it:
(defn -main [& args]
(apply str args)
)
Then called like:
(-main "a" "b" "c")
And it evaluated to:
"abc"
As it should..
Be sure to check are you using the right namespace identifier, also see if anything weird is happening inside your -main function, like using a string as a number..
Also, it wouldn't hurt to see your error message on this..
Related
I just started learning Clojure and I have my own Clojure script but it's not returning the output that I am hoping for (Hello World). Here is my code:
(ns com.playground.core
(:gen-class))
(defn -main
[]
((defn CHEESE
[]
(str "Hello World"))
(CHEESE)))
This is the output that I get in the REPL:
clj꞉com.playground.core꞉>
#'com.playground.core/-main
I want to see Hello World in the output.
You have a double parentheses there. Try this:
(defn -main
[]
(defn CHEESE
[]
(str "Hello World"))
(CHEESE))
Of course your MUST call -main, otherwise you'll see nothing:
(defn -main
[]
(defn CHEESE
[]
(str "Hello World"))
(CHEESE))
=> #'com.playground.core/-main
(-main)
=> "Hello World"
I see your define a function inside another function. You should use let or letfn for this purpose.
Starting a REPL for the project does not run -main. Running your program produces the following:
Execution error (ArityException) at com.playground.core/-main (core.clj:6).
Wrong number of args (1) passed to: com.playground.core/-main/CHEESE--177
What is happening?
The defn form creates and registers a function under the name
CHEESE in the com.playground.core namespace.
The defn form returns the created var, which evaluates to the
function.
The containing ((defn ...) (CHEESE)) form applies the CHEESE function to
(CHEESE), the result of evaluating the CHEESE function without
arguments,
... which is the string "Hello World".
It doesn't matter what the argument is, because CHEESE has no arity 1 invocation: you can't apply it to any argument.
You can get the same (bad) effect more simply by pulling the defn for CHEESE out of -main. While we're at it, let's drop the str, which has no effect:
(defn CHEESE []
"Hello World")
(defn -main []
(CHEESE (CHEESE)))
Execution error (ArityException) at com.playground.core/-main (core.clj:8).
Wrong number of args (1) passed to: com.playground.core/CHEESE
To put it right, we simply drop the (CHEESE)argument:
(defn -main []
(CHEESE))
producing ...
Process finished with exit code 0
No returned value, but at least it ran. But if we evaluate (-main) in a REPL, ...
(-main)
=> "Hello World"
There.
Actually, It's not exactly wrong.
This return is the "return of declaration".
For example, you defined a -main in the com.playground.core namespace.
The return is the symbol of this declaration #'com.playground.core/-main
To print the Hello world message you need to call the function CHEESE after the declaration.
So... about double parenthesis, it's not good, but not impact hehe.
Another point is the function name, it's not good too. Consider using kebab-case.
You also consider keeping the function declaration more explicitly. Something like that;
(ns com.playground.core
(:gen-class))
(defn CHEESE [] (str "Hello World"))
(defn -main []
(CHEESE))
But also did it you're not printing the Hello world. Your only declaring a function (CHEESE) that returns a String type.
To print, you need to call a print function.
(ns com.playground.core
(:gen-class))
(defn hello [] (str "Hello World"))
(defn -main []
(print (hello)))
I did the evolution of declarations to explain better
So, you can improve the code using the let alternative and the threading macros
Consider use the https://kimh.github.io/clojure-by-example/ and https://tryclojure.org/ to understand these options better :)
I am a newbie to Clojure and currently trying to invoke a simple macro using defmacro and macroexpand.
(ns tutorial.core
(:gen-class)) ; namespace
(defn -main [& args]
(defmacro Simple [] (println "Hello"))
(macroexpand '(Simple))
)
Is there something I have missed? it seems the program runs without any problems but the results are not coming out as expected.
I expect the results to print out as Hello, but no outputs result from this script.
Preface:
Please see this past question for an overview of the best way to write a macro (IMHO).
Answer:
You shouldn't define the macro in the main function. Try this:
(ns demo.core)
(defmacro happy
[]
`(println "I'm happy!")) ; *** notice the backtick! ***
(defn -main [& args]
(println :expanded (macroexpand '(happy)))
(happy)
)
start up a repl:
~/expr/demo > lein repl
demo.core=> (macroexpand '(happy))
;=> (clojure.core/println "I'm happy!")
and we see that it works. Try running from the command line:
~/expr/demo > lein run
:expanded (happy) ; <= ***** OOOPS! *****
I'm happy!
Try changing the single-quote into a syntax-quote (aka backtick), then run:
(defn -main [& args]
(println :expanded (macroexpand `(happy)))
(happy))
~/expr/demo > lein run
:expanded (clojure.core/println I'm happy!)
I'm happy!
The explanation is that the syntax-quote will fully-qualify the Var happy => demo.core/happy (you can see the same effect on the println Var inside of the happy macro itself because of that syntax-quote). This allows the macroexpand to work properly. Compare with a single-quote:
(defn -main [& args]
(println :expanded (macroexpand '(demo.core/happy)))
(happy))
~/expr/demo > lein run
:expanded (clojure.core/println I'm happy!)
I'm happy!
The cause of this behavior is that, in the REPL, we see from the prompt that we are in the demo.core namespace, so happy is resolved as demo.core/happy. When we use lein run, however, observe:
(defn -main [& args]
(println *ns*)
(println (ns-name *ns*)))
with result:
~/expr/demo > lein run
*ns* => #object[clojure.lang.Namespace 0xb625b00 "user"]
(ns-name *ns*) => user
and we see that the *ns* is set to the user namespace and happy cannot be resolved to the Var demo.core/happy unless we fully qualify it either manually or using syntax-quote in the code.
You can find a list of documentation here. Be sure especially to study the Clojure CheatSheet.
For macros, the book Mastering Clojure Macros is also good.
Your macro function doesn't return code, but does the printing immediately. This is very bad style as it has unforeseen consequences.
If you were to use this is a function:
(defn hello [] (Simple))
It prints "Hello" when the function is created. The code being inserted in the function is the result fo println which is nil, thus you have created this:
(defn hello [] nil)
Then if you call hello 3 times none of the calls will no any printing since your macro doesn't produce anything else than nil. If you change your macro to return structure:
;; The quote that makes all the difference
(defmacro Simple [] '(println "Hello"))
Then if will not print anything during the createion of hello, but the expansion would be (println "Hello") and the same fucntion hello would become:
(defn hello [] (println "Hello"))
I am a newbie to Clojure and I am trying to read a file which should be specified at the command line.
When I try the following, giving the file name at REPL, it is working
(ns testpj.core
(:require [clojure.java.io :as io]))
(defn readfile [filename]
(println (System/getProperty "user.dir"))
(println "Arguments: " filename)
(slurp filename))
And then I run this at REPL and I get the contents of the file
(require '[testpj.core :as h])
(h/readfile file1.txt)
But when I change the above code to main and I try to give the file name at the
command line
lein run file1.txt
(defn -main [& args]
(println (System/getProperty "user.dir"))
(println "Arguments: " args)
(slurp args))
, I am getting the following error:
"java.lang.IllegalArgumentException: Cannot open <("file1.txt")> as an InputStream."
Can anyone help? Thanks
The argument vector for -main is [& args], which means that -main accepts any number of arguments. Inside the function, the var args will be bound to a list of the arguments passed to it, or nil if no arguments are given to the function. So, to slurp the first argument passed to a function which takes multiple arguments:
(slurp (first args))
I wonder, how can I replace this without "->"?
(defn -main [& args]
(->
"http://www.fsdfdsfds.com" URL. html-resource
print))
I tried this and it didn't print anything:
(defn -main [& args]
(print(URL. html-resource "http://www.fsdfdsfds.com"))
You can replace it like so:
(print (html-resource (URL. "http://www.fsdfdsfds.com")))
The way you have it, you are passing 2 args to URL. The thread-first macro passes your url string to URL., then html-resource, then to print.
I would like to print each of my leiningen test methods as they are running. I have a lein tests file that is relatively simple:
(defn myfixture [b]
(do
(println "start")
(b)
(println "end")
)
)
(deftest test1 [] .....
I want to see "test1" print out at the repl when I run the tests. Is there a simple way to print the method name (either by calling a method of b in myfixture, or, in the invocation of "lein test")?
You can get the name of a function like this:
(defn function-name [f]
(:name (meta f)))
(defn my-func []
(println "Hello, world!"))
(let [f my-func]
(function-name f))
;=> my-func
I don't know if the facility that you are looking for exists in the regular clojure.test but midje has some pretty extensive fixture facilities, this link is maybe worth checking out.