I'm currently learning clojure, but I was wondering how to get and store user input in a clojure program. I was looking at the clojure api and I found a function called read-line, however I'm not sure how to use it if it's the right function to use...
Anyhow, how do you get user input in clojure ?
read-line is the correct function..
(println (read-line))
..would basically echo the users input:
Clojure 1.0.0-
user=> (println (read-line))
this is my input
this is my input
To use it in an if statement, you'd probably use let:
(let [yayinput (read-line)]
(if (= yayinput "1234")
(println "Correct")
(println "Wrong")))
Hope that's enough to get you started, because that's about the limit of my Clojure knowledge!
Remember also that you have access to all of Java ...
OK so perhaps I should present some examples ... my clojure skills are not good so these examples may need a bit of tweaking.
The System.console() way:
(let [console (. System console)
pwd (.readPassword console "tell me your password: ")]
(println "your password is " pwd))
The BufferedReader way:
(print "give me a line: ")
(let [reader (java.io.BufferedReader. *in*)
ln (.readLine reader)]
(println "your line is " ln))
My point is that one can leverage knowledge of Java, and Java itself, in Clojure. It's one of its principal, advertised strengths.
Wonder what would my score have been if the question were about user input from a GUI!
By the way, you could use JOptionPane to put up a little GUI to get user input ...
read-line is used to get user input and use let to bind it to some variable.
For example : if you want to read user ID and password from user and display it, you could use the following piece of code
(defn print-message [pid pw]
(println "PID : " pid)
(println "PW : " pw))
(defn inp[]
(println "Enter your PID and password")
(let[pid (read-line) pw (read-line)]
(print-message pid pw) ))
Related
I know that one can simulate a user's input by wrapping the (read-line) function in with-in-str and then passing your input programmatically like this:
(with-in-str "punit naik" (println (read-line)))
This will of course print punit naik to the console.
But the problem is, I have a function which runs recursively and continuously asks for user input in it's iterations.
And I want to write a test case for that function. How do I achieve this?
read-line reads one line at a time. You can prepare a string that contains all of the lines that need to be read separated with new line:
(with-in-str
"a\nb\nc"
(loop []
(if-let [line (read-line)]
(do
(println "Line was" line)
(println "Recurring")
(recur))
(println "No more lines"))))
This prints:
Line was a
Recurring
Line was b
Recurring
Line was c
Recurring
No more lines
I've been experimenting with creating monads in clojure so I can separate my pure code from my impure code more thouroghly, and I've stumbled upon something strage with ordering.
When using the following code for a minimum use-case, the desired output is for it to print "Please enter your name: " to the screen and then take a single line of input, which is then printed back out to the screen. The code below is what should be able to acccomplish this:
;; IO Monad definitions
(defn io-bind
[mv mf]
(fn []
(let [val (mv)
f (mf val)]
(f))))
;; Monadic functions
(defn io-print
[msg]
(fn []
(print msg)))
(defn io-read-line
[_]
(fn []
(read-line)))
;; Entry point
(defn -main
"I don't do a whole lot ... yet."
[& args]
((-> (io-print "Please enter your name: ")
(io-bind io-read-line)
(io-bind io-print))))
I've experienced a hitch with this however, in that it will first poll for input from the user using (read-line) and only afterwards will it then print "Please enter your name: ".
In larger examples, it will still perform all of the visible IO actions in the proper order, for example in this case it does print out "Please enter your name: " before it prints out what you inputted, yet it still requests that input first.
The strangest part however is that the instant I replace print with println in io-print it does all of the ordering as intented, regardless of circumstance.
Why might this be occuring? Is there some way that print is lazy that println is not, for example?
You need to add the following after the print:
(flush)
println will implicitly flush the output to the screen, so that is why you are seeing different behavior than with print.
Please see https://clojuredocs.org/clojure.core/flush for more info, as also the source code for all the details.
I am trying to create a custom message in the body section of email using riemann.
I couldn't append the field dynamically.
Riemann config:
(let [email (mailer
{:host "XXXXX" :port XX :user "XXX" :pass "XXX" :auth "true"
:subject (fn [events] "Team")
:body (fn [events]
(apply str "Hello Team, now the time is" (:timestamp event) "Thank You!"))
:from "xxx#gmail.com"})]
My output:
Hello Team, now the time is Thank You!
My expected output:
Hello Team, now the time is 12:13:45 Thank You!.
My timestamp not getting appended in the :body.
from the docs:
These formatting functions take a sequence of
events and return a string.
so the question is which event in the sequence would you like to get the timestamp from? If you lookup a keyword in a sequence, as opposed to one of the members of that sequence, you will get back nil as a default:
core> (:asdf '(1 2 3))
nil
and if you apply str that into a couple other strings it will have no effect because str will ignore it. Which is where your output is coming from. Here is an analogous example function:
core> (let [body-fn (fn [events]
(apply str "Hello Team, now the time is"
(:timestamp events)
"Thank You!"))]
(body-fn [{:timestamp 42} {:timestamp 43}]))
"Hello Team, now the time isThank You!"
if we choose the timestamp from the first event:
core> (let [body-fn (fn [events]
(apply str "Hello Team, now the time is"
(:timestamp (first events))
"Thank You!"))]
(body-fn [{:timestamp 42} {:timestamp 43}]))
"Hello Team, now the time is42Thank You!"
When alerting through riemann my personal opinion is to wrap the things being alerted into fixed time windows and use the timestamp from the start of that window, though this is primarily because of personal preference.
In Clojure I want to create a function that would continually ask the user for an option, execute some code depending on the option, and then quit when the user’s option is “q”.
I am comfortable will all of the various Clojure forms that work with sequences, and I could certainly finagle a Java-like solution to the above, but I cannot figure out how to do this in a “clojuresque” manner.
Thanks,
Jeffrey S
Something like this should do the job:
(defn main-loop []
(case (read-line)
"q" nil
"a" (do (println "got a command!") (recur))
"b" (do (println "got b command!") (recur))
(do (println "got invalid command!") (recur))))
I have just started playing with Clojure and the first thing I thought I'd try is storing and retrieving a list of structs, like in Suart Halloway's example here.
My spit/slurp of a hash of structs works fine with, if I use struct instances without spaces in the attribute strings like the following:
(struct customer "Apple" "InfiniteLoop")
But if I use this:
(struct customer "Apple" "Infinite Loop 1")
I get an error:
Exception in thread "main" clojure.lang.LispReader$ReaderException: java.lang.ArrayIndexOutOfBoundsException: 7 (test-storing.clj:19)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:2719)
at clojure.lang.Compiler$DefExpr.eval(Compiler.java:298)
at clojure.lang.Compiler.eval(Compiler.java:4537)
at clojure.lang.Compiler.load(Compiler.java:4857)
at clojure.lang.Compiler.loadFile(Compiler.java:4824)
at clojure.main$load_script__5833.invoke(main.clj:206)
at clojure.main$init_opt__5836.invoke(main.clj:211)
at clojure.main$initialize__5846.invoke(main.clj:239)
at clojure.main$null_opt__5868.invoke(main.clj:264)
at clojure.main$legacy_script__5883.invoke(main.clj:295)
at clojure.lang.Var.invoke(Var.java:346)
at clojure.main.legacy_script(main.java:34)
at clojure.lang.Script.main(Script.java:20)
Caused by: clojure.lang.LispReader$ReaderException: java.lang.ArrayIndexOutOfBoundsException: 7
at clojure.lang.LispReader.read(LispReader.java:180)
at clojure.core$read__4168.invoke(core.clj:2083)
at clojure.core$read__4168.invoke(core.clj:2081)
at clojure.core$read__4168.invoke(core.clj:2079)
at clojure.core$read__4168.invoke(core.clj:2077)
at chap_03$load_db__54.invoke(chap_03.clj:71)
at clojure.lang.AFn.applyToHelper(AFn.java:173)
at clojure.lang.AFn.applyTo(AFn.java:164)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:2714)
... 12 more
Caused by: java.lang.ArrayIndexOutOfBoundsException: 7
at clojure.lang.PersistentArrayMap$Seq.first(PersistentArrayMap.java:216)
at clojure.lang.APersistentMap.hashCode(APersistentMap.java:101)
at clojure.lang.Util.hash(Util.java:55)
at clojure.lang.PersistentHashMap.entryAt(PersistentHashMap.java:134)
at clojure.lang.PersistentHashMap.containsKey(PersistentHashMap.java:130)
at clojure.lang.APersistentSet.contains(APersistentSet.java:33)
at clojure.lang.PersistentHashSet.cons(PersistentHashSet.java:59)
at clojure.lang.PersistentHashSet.create(PersistentHashSet.java:34)
at clojure.lang.LispReader$SetReader.invoke(LispReader.java:974)
at clojure.lang.LispReader$DispatchReader.invoke(LispReader.java:540)
at clojure.lang.LispReader.read(LispReader.java:145)
... 20 more
Depending on the amount of the fields in the struct, I might also just get a part of the string as an attribute name instead of the error. For example :Loop 1
I use a store-function like this:
(defn store-customer-db [customer-db filename]
(spit filename (with-out-str (print customer-db))))
And a read-function like this:
(defn load-db [filename]
(with-in-str (slurp filename)(read)))
From the output file of spit I can see that the print doesn't give double quotes to the strings which seems to be a problem for slurp. What would be the correct solution for this?
My Clojure version is 1.0, and the contrib is a few weeks old snapshot.
print and println are meant for human-readable output. If you want to print something that's meant to be read in again later, use pr or prn.
user> (read-string (with-out-str (prn {"Apple" "Infinite Loop"})))
{"Apple" "Infinite Loop"}
Whereas:
user> (read-string (with-out-str (print {"Apple" "Infinite Loop"})))
java.lang.ArrayIndexOutOfBoundsException: 3 (NO_SOURCE_FILE:0)
It's trying to run this code:
(read-string "{Apple Infinite Loop}")
which has an odd number of keys/values. Note the lack of quotation marks around the individual hash keys/values. Even if this read works (i.e. if you coincidentally supply an even number of parameters), what it reads won't be a hash-map full of Strings, but rather Symbols. So you'll be getting back something other than what you output.
user> (map class (keys (read-string (with-out-str (print {"foo bar" "baz quux"})))))
(clojure.lang.Symbol clojure.lang.Symbol)
For, say:
(def hashed-hobbits {:bilbo "Takes after his Mother's family" :frodo "ring bearer"})
You only need:
(spit "hobbitses.txt" hashed-hobbits)
and to read it back:
(def there-and-back-again (read-string (slurp "hobbitses.txt")))
spit/slurp wraps it all in a string but using read-string on the slurp interprets the string back to clojure code/data. Works on trollish data structures too!