I've done some coding in clojure inside core.clj which have a -main method that can take 0 or more arguments:
(defn -main
"dequeue function"
[& args]
I'm loading this clj file with:
(load-file "src/exercise/core.clj")
And then i'm trying to learn how to call this within repl in order to develop core_test.clj (if there is any tips about how to develop this auto tests, please give me some hints as well). What I'm trying to do now is:
(-main "resources\\sample-input.json" "a")
But this is printing "Arguments 0" which is a message that I told the code to print just to see how many arguments are being passed with
(println "Arguments" (count *command-line-args*))
How am I suposed to do this?
Thanks!
i'm trying to learn how to call this within repl in order to develop core_test.clj
Usually you'd write other functions that are called from -main and test those rather than the app's entry point -main.
But you should be able to call -main like any other function. I have a src/sandbox/main.clj file:
(ns sandbox.main)
(defn -main [& args]
(prn args))
Starting a REPL in the project folder, I can call -main like this:
(use 'sandbox.main) ;; (load-file "src/sandbox/main.clj") also works
=> nil
(in-ns 'sandbox.main)
=> #object[clojure.lang.Namespace 0x67ccce04 "sandbox.main"]
(-main "some" "args")
;; ("some" "args")
=> nil
There's a key difference in my example though: it's printing -main's args binding; *command-line-args* is nil because you're not running the code from the command line with args, you're running it from a REPL.
Regardless, it's probably a better idea to use an existing library to work with CLI args rather than *command-line-args* directly.
Related
I would like to format my logs differently depending on whether my code is being run from a REPL or if I'm running the compiled jar.
Is there any simple way to do this? I was thinking maybe Leiningen leaves a trace somewhere when running the REPL.
(defn current-stack-trace []
(.getStackTrace (Thread/currentThread)))
(defn is-repl-stack-element [stack-element]
(and (= "clojure.main$repl" (.getClassName stack-element))
(= "doInvoke" (.getMethodName stack-element))))
(defn is-in-repl []
(some is-repl-stack-element (current-stack-trace)))
(defn my-log [msg]
(if (is-in-repl)
(prn (str "RUNNING IN REPL : " msg))
(prn msg)))
Is this an expected behaviour, or it's a problem with my Clojure installations (I'm checking it on Windows and Linux)?
I have a simple project, created with lein new app testfor. Here's the code of src/testfor/core.clj:
(ns testfor.core
(:gen-class))
(defn -main [& args]
(println "hello")
(for [x [1 2 3]]
(println x)))
When I run lein repl and invoke (-main) from the REPL, the output is this:
testfor.core=> (-main)
hello
1
2
3
But then I run the application with lein run, or lein uberjar and run the generated JAR file, the output is this:
$ lein run
hello
So, it somehow doesn't run the for loop.
Am I doing something wrong here?
I believe this is because for returns a lazy-sequence of elements - https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/for
In the example when you call the -main function from the repl, in this case the last expression in the function is returned from the function call (just like any other function call). The REPL sees the lazy-seq and attempts to print it, which requires realising the seq, which will evaluate the println statements.
In the example when you Leiningen calls the main method, it is like calling a main method on a Java class which has a void return type public static void main. Clojure will see it as lazy and nothing tries to realise the seq so the println expressions are never evaluated.
for is not a for loop like in Java. It creates a lazy sequence that depends on the different options you specify. See for documentation.
The important point in your case is the lazy word.
The repl will actually force the realisation of the lazy sequence, but when running with lein, this is not the case. In order to do what you want you need to force with either dorun or doall :
(defn -main [& args]
(println "hello")
(dorun (for [x [1 2 3]]
(println x))))
cuvier:tgo$ lein run
hello
1
2
3
I just started on my first clojure project using lein, the code here:
(ns fileops.core
(:use
[clojure.core :only (slurp)]
[clojure-csv.core :only (parse-csv)]
[fileops.core]))
(defn -main
"I don't do a whole lot ... yet."
[& args]
(read-file "sample.csv"))
(defn read-file
"open and read the csv file"
[fname]
(with-open [file (clojure.java.io/reader fname)]
(parse-csv (slurp fname))))
I tried to run this using "lein run" but I keep getting this error:
Caused by: java.lang.RuntimeException: Unable to resolve symbol: read-file in this context
at clojure.lang.Util.runtimeException(Util.java:219)
at clojure.lang.Compiler.resolveIn(Compiler.java:6874)
at clojure.lang.Compiler.resolve(Compiler.java:6818)
at clojure.lang.Compiler.analyzeSymbol(Compiler.java:6779)
at clojure.lang.Compiler.analyze(Compiler.java:6343)
... 52 more
What am I doing wrong?
You have used only slurp from clojure core, meaning that every other core function is now unavailable to you :) Try changing your ns to use :require instead of :use, as this is more idiomatic.
One thing to note is that order does matter in clojure, so if you don't declare a function at the top of your file, as in C and some other languages, the earlier functions will not be able to make reference to them. This is what was causing your error before and is why I like to define my -main function at the bottom. It's a matter of style.
Another thing is that your -main function is taking variable args right now and not using them. In Clojure it is idiomatic to use _ to refer to a parameter that doesn't get used. You could use & _ to avoid error messages, for when the user passes in unnecessary args, but I would just have the -main function parameterless from the start. This is because nothing needs to be provided to main when you run the program, and errors do make debugging easier. It is good to know what is getting used and where. The sample.csv file is already provided and is having read-file called on it, so the program should run if your read-file function is correct and the sample.csv file is in the proper location.
Regarding your -main function, it would be nice to put a little test in there to see if it executes properly when you run it, so I changed it to print out the contents of the csv file onto your console. This way of printing from a file is efficient and worth studying in its own right.
Finally, Make sure you include clojure-csv.core in your project.clj file.
core.clj:
(ns fileops.core
(:require
[clojure-csv.core :refer [parse-csv]]))
(defn read-file
"open and read the csv file"
[fname]
(with-open [file (clojure.java.io/reader fname)]
(parse-csv (slurp fname))))
(defn -main []
(println (clojure.string/join "\n" (read-file "resources/test.csv"))))
project.clj:
...
:dependencies [[org.clojure/clojure "1.5.1"]
[clojure-csv/clojure-csv "2.0.1"]
...]
:main fileops.core
You need to declare fileops.core as :main, as shown above. This tells Leiningen what function to execute when you enter lein run. Very important and tricky stuff.
So now make sure you are in the root of your project directory and at the terminal, run the following:
lein clean
lein deps
lein run
Good luck!
Further reading:
8th light blog on name-spaces
flying machine studios explanation of lein run
read-file should be before main in your source OR you should put before -main a declare cause like that:
(declare read-file)
I'm learning about Hystrix and Clojure and don't understand how to (properly) set a timeout on a Hystrix command in Clojure.
I searched StackOverflow and the web more generally. I looked at Hystrix's Clojure wrapper source code (https://github.com/Netflix/Hystrix/blob/master/hystrix-contrib/hystrix-clj/src/main/clojure/com/netflix/hystrix/core.clj). There is a init-fn function parameter that looked promising, but the comments seem to suggest that this won't be a sustainable solution. But would this be a simple start?
I have a ridiculously simple Hystrix command running in Clojure and would appreciate help in extending this to set, say, a 200ms timeout:
(ns hystrix-timeout.core
(:require [clojure.string :as str])
(:require [com.netflix.hystrix.core :as hystrix])
(:gen-class))
(defn my-primary [a]
(if (= a true) (throw (Exception. "Primary failed")) (str "primary: " a)))
(defn my-fallback [a]
(str "fallback: " a))
(hystrix/defcommand my-command
{:hystrix/fallback-fn my-fallback}
[a]
(my-primary a))
(defn -main
"Executes a simple Hystrix command. Will use a timeout when I know how to do this in Clojure."
[& args]
(println (my-command false))
(println (my-command true))
(System/exit 0) ; Exit explicitly as Hystrix threads are still running.
)
I've put my lein project up at https://github.com/oliverbaier/learning/tree/master/hystrix-timeout in case this makes answering easier.
Thanks a lot,
Oliver
The simplest route is to just use System properties. You can set either a global default:
(System/setProperty "hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds" "200")
or a command specific value:
(System/setProperty "hystrix.command.my-command.execution.isolation.thread.timeoutInMilliseconds" "200")
You can perform this in your -main method. If you are running a real web-app sans -main, you can add a ring init in project.clj :ring {:handler your-handler :init your-config-method} your-config-method will be invoked on startup.
I've got the following in a clojure file:
(ns helloworld
(:gen-class
:main -main))
(defn hello-world-fn []
(println "Hello World"))
(defn -main [& args]
(eval (read-string "(hello-world-fn)")))
and I'm running it with
lein run helloworld
and I'm getting the following error:
Exception in thread "main" java.lang.RuntimeException: Unable to resolve symbol:
helloworld in this context, compiling:(helloworld.clj:12)
I have a feeling I need to do something with ns-resolve or resolve but I haven't had any success. I've tried the following in the main function:
(let [call-string (read-string "(hello-world-fn)")
func (resolve (symbol (first call-string)))
args (rest call-string)]
(apply func args))
Without success.
Can someone (a) point me in the right direction; and (b) explain precisely what is going on in the Clojure reader when this occurs?
Try to see what the actual namespace is inside your -main.
(defn -main [& args]
(prn *ns*)
(eval (read-string "(hello-world-fn)")))
It outputs #<Namespace user> before bombing out with the exception. This hints that execution of programs with lein run starts out in the user namespace, which obviously does not contain the mapping for your hello-world-fn symbol. You'll need to explicitly qualify it.
(defn -main [& args]
(eval (read-string "(helloworld/hello-world-fn)")))
You can solve your challenge, in a very elegant way, using macros. In fact, you can write a macro that mimics eval.
(defmacro my-eval [s] `~(read-string s))
(my-eval "(hello-world-fn)")); "Hello World"
It works better that eval because the symbol resolution of s occurs in the context that calls my-eval. Thanks to #Matthias Benkard for the clarifications.
You can read about macros and their syntax in http://clojure.org/reader