I have a simple function hello in my source.
(defn hello [n] (str "Hello" n))
In the test case I am calling the hello function. But seems like it is returning nil. Test case:
(deftest test (testing "string"
;(is (= "Hello x" (ql/hello "x")))))
(is (= (ql/hello "x") "Hello x"))))
I am getting the following error.
expected: (= (ql/hello "x") "Hello x")
actual: (not (= nil "Hello x"))
Why is it returning nil? If I call the hello function from repl I get "Hello x" followed by nil, but I think it is due to repl right? When I call hello from another function, shouldn't it return the string? I am running the test case from repl directly and not using lein.
From your description it seems that your actual hello function was defined as:
(defn hello [n]
(println "Hello" n))
When you run (hello "x") it prints Hello x to the console and returns nil (that's the behaviour of println).
To get your test passing you need to redefine your function in the REPL so it matches your version with str instead of println.
boot.user=> (require '[clojure.test :refer :all])
nil
boot.user=> (defn hello [n]
#_=> (println "Hello" n))
#'boot.user/hello
boot.user=> (is (= "Hello x" (hello "x")))
Hello x
FAIL in () (boot.user5664236129068656247.clj:1)
expected: (= "Hello x" (hello "x"))
actual: (not (= "Hello x" nil))
false
boot.user=> (defn hello [n]
#_=> (str "Hello " n))
#'boot.user/hello
boot.user=> (is (= "Hello x" (hello "x")))
true
boot.user=>
Related
(defn get-coll-id [^String coll_id]
(log/info "coll_id: " coll_id)
(if (string/blank? coll_id)
(let [collVal (get-coll-val)]
(log/info "collVal: " collSeqVal)
(format "C%011.0f" collVal))
coll_id))
The log shows "coll_id: null". However, string/blank did not detect the null, and thus log of collVal is skipped. What is the method to check null string?
Something (perhaps a DB?) is giving you the string "null" for coll_id, or perhaps (log/info ...) converts a Clojure nil into the string "null".
Consider this code:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require
[clojure.string :as str]
))
(defn get-coll-id [^String coll_id]
(println "coll_id: " coll_id)
(if (str/blank? coll_id)
(println :blank)
coll_id))
(dotest
(newline)
(println :v1)
(spyx (get-coll-id nil))
(newline)
(println :v2)
(spyx (get-coll-id (pr-str nil)))
)
with output:
:v1
coll_id: nil
:blank
(get-coll-id nil) => nil
:v2
coll_id: nil
(get-coll-id (pr-str nil)) => "nil"
No matter what you do, you get either the value nil or the string "nil" printed.
Since I haven't used Java for a while, I tried to force it to generate the string "null", but calling o.toString() for a null value creates a
NullPointerException, so that is not the answer.
Update
As amalloy points out, String.valueOf() will convert a Java null into the string "null":
package demo;
public class Demo {
public static String go() {
Object o = null;
return String.valueOf( o );
}
}
when run:
(newline)
(spyx :v3 (demo.Demo/go))
with result
:v3 (demo.Demo/go) => "null"
As to your original question, the nil? function could be used:
(defn blank-or-nil?
[s]
(or (nil? s)
(str/blank? s)))
(defn get-coll-id [^String coll_id]
(println "coll_id: " coll_id)
(if (blank-or-nil? coll_id)
(println "found blank-or-nil coll_id")
coll_id))
which then prints found blank-or-nil coll_id when passed a nil value. However, this could confuse things if your are passed the string "null" or the string "nil".
You need to clarify which value is the input, then track down the source.
The above code is based on my favorite template project.
I am newbie in Clojure. I have following Expressions:
(= (__ "Dave") "Hello, Dave!")
(= (__ "Jenn") "Hello, Jenn!")
(= (__ "Rhea") "Hello, Rhea!")
In place of __, in all 3 places must be inserted same expression so that the equality check in all 3 cases are true. At this point i have come up with str "Hello, ". As i understand this should produce "Hello, Dave" "Hello, Jenn" "Hello, Rhea" How do i put "!" mark at the and of each string? (I can only "write" expression in place of __)
Thank you
You want to drop a function into the place of __.
This function shall take a string s and shall return a string that is based on s so as to satisfy the three test cases.
A possible function is
(fn [s] (str "Hello, " s "!"))
which can written using Clojure syntactic sugar
#(str "Hello, " % "!"))
Thus
(= (#(str "Hello, " % "!") "Dave") "Hello, Dave!")
Bonus: Using testing framework
Clojure comes with a nice testing library, clojure.test (I don't know why it is called an API, which would mean there is a component on the other side of the callable functions; it's just a library)
We can use the testing library for good effect:
(require '[clojure.test :as t]) ; make library visible
(def myfun (fn [s] (str "Hello, " s "!"))) ; our function as symbol myfun
(t/deftest test-stringmanip
(t/is (= (myfun "Dave") "Hello, Dave!"))
(t/is (= (myfun "Jenn") "Hello, Jenn!"))
(t/is (= (myfun "Rhea") "Hello, Rhea!")))
(t/run-tests) ; do it!
I wrote a short function for debugging:
(defn printvar
"Print information about given variables in `name : value` pairs"
[& vars]
(dorun (map #(println (name %) ":" (eval %)) vars)))
Then I tried to test it:
(defn -main [arg1 arg2]
(def moustache true) (def answer 42) (def ocelots-are "awesome!")
(printvar 'moustache 'answer 'ocelots-are)
(printvar 'arg1 'arg2))
But ran into some really confusing behaviour:
$ lein repl
> (-main "one" "two")
# moustache : true
# answer : 42
# ocelots-are : awesome!
# CompilerException java.lang.RuntimeException: Unable to resolve symbol: arg1 in this context, compiling:(/tmp/form-init4449285856851838419.clj:1:1)
$ lein run "one" "two"
# Exception in thread "main" java.lang.RuntimeException: Unable to resolve symbol: moustache in this context, compiling:(/tmp/form-init4557344131005109247.clj:1:113)
Experimenting a bit more, I discovered this:
(defn -main [arg1 arg2]
(meta #'arg1))
# Exception in thread "main" java.lang.RuntimeException: Unable to resolve var: arg1 in this context, compiling:(dict_compress/core.clj:9:11)
(defn -main [arg1 arg2]
(def arg1 arg1)
(meta #'arg1))
# {:ns #<Namespace dict-compress.core>, :name arg1, :file dict_compress/core.clj, :column 2, :line 10}
Now I'm totally confused.
What exactly are you passing when you do (f 'var) and (f var)?
Why are there different behaviours when run from the REPL versus directly?
What's the difference between a received argument versus a defined variable?
How can I fix my code?
Am I going about debugging the wrong way?
Inside printvar the def'ed vars moustache answer and ocelots-are are correctly printed because def defines them as "globals".
Meaning there is a moustache var that the printvar function can "see".
Think about it this way, this works:
(def moustache 43)
(defn printvar []
(println moustache)
(defn main [arg1]
(printvar))
This doesn't work:
(defn printvar []
(println arg1))
(defn main [arg1]
(printvar))
Which is exactly what you're doing, passing the parameter name to eval does nothing for the parameter scope (printvar won't be able to see it).
A couple of issues with your code:
You shouldn't be defing inside a function, local bindings are defined with let
If you want to eval you need to consider scope of what you're evaling.
Just to elaborate on #Guillermo's comment, here is a macro that does the printing of any variable, locally or globally bound.
(defmacro printvar
([])
([v & more]
`(let [v# ~v]
(println '~v "=" v#)
(when (seq '~more)
(printvar ~#more)))))
With this you can try the sequence :
user> (def glob-var "foo")
#'user/glob-var
user> (defn -main [loc1 loc2]
(printvar glob-var loc1 loc2))
#'user/-main
user> (-main "bar" 42)
glob-var = foo
loc1 = bar
loc2 = 42
nil
user>
Input: "Michael" "Julia" "Joe" "Sam"
Output: Hi, Michael, Julia, Joe, and Sam. (pay attention to the commas and the word "and")
Input: nil
Output: Hi, world.
Here is my first attempt:
(defn say-hi [& name]
(print "Hi," name))
user> (say-hi "Michael")
Hi, (Michael)
nil
user> (say-hi "Michael" "Julia")
Hi, (Michael Julia)
nil
Question:
How to implement default: (no input, say "Hi World!")
How to get rid of the parents around names in output?
How to implement the commas separation and add the conjunction word "and"?
First off, Clojure supports multi-arity functions, so you could do something like this to achieve default behaviour:
(defn say-hi
([] (say-hi "World"))
([& names] ...))
Then, what you want is to take a seq and join all the strings it contains together, using ", " in between. The clojure.string namespaces contains lots of string manipulation functions, one of them being clojure.string/join:
(require '[clojure.string :as string])
(string/join ", " ["Michael", "Julia"])
;; => "Michael, Julia"
But the last element of the seq should be concatenated using " and " as a separator, so you'll end up with something like this:
(require '[clojure.string :as string])
(defn say-hi
([] (say-hi "World"))
([& names]
(if (next names)
(format "Hi, %s, and %s!"
(string/join ", " (butlast names))
(last names))
(format "Hi, %s!" (first names)))))
Note that you have to differentiate between the single- and multi-name cases and (next names) basically checks whether the seq contains more than one element. (You could achieve the same by adding another arity to the function.)
(say-hi)
;; => "Hi, World!"
(say-hi "Michael")
;; => "Hi, Michael!"
(say-hi "Michael" "Julia" "Joe" "Sam")
;; => "Hi, Michael, Julia, Joe, and Sam!"
You can use clojure.string/join:
(use '[clojure.string :only [join]])
(defn sentencify [& elems]
(->>
[(join ", " (butlast elems)) (last elems)]
(remove empty?)
(join " and ")))
(defn say-hi [& name]
(print "Hi," (if name
(sentencify name)
"World!")))
A concise solution:
(defn say-hi [& names]
(let [names (case (count names)
0 ["world"]
1 names
(concat (butlast names) (list (str "and " (last names)))))]
(->> names, (cons "Hi"), (interpose ", "), (apply str))))
(say-hi)
;"Hi, world"
(say-hi "Michael")
;"Hi, Michael"
(say-hi "Michael" "Julia" "Joe" "Sam")
;"Hi, Michael, Julia, Joe, and Sam"
For long lists of names, you would want to eschew count, last, and butlast, maybe by pouring names into a vector first.
To print (as the question does) rather than return the formatted string, append print to the final form:
(->> names, (cons "Hi"), (interpose ", "), (apply str), print)
How do you make a callable type or object in Clojure?
For example, how could I define a record Foo taking a single value :bar which could be called to print that value?
user=> (def foo (Foo. "Hello world"))
user=> (foo)
Hello World
user=> (:bar foo)
"Hello World"
(defrecord Foo [bar]
clojure.lang.IFn
(invoke [_] (println bar)))
((Foo. "Hello, world!"))
;; => Hello, world!
(:bar (Foo. "Hello, world!"))
;; => "Hello, world!"
...Whether doing this is a good idea is another question.
Records implementing IFn
(defrecord Foo [bar]
clojure.lang.IFn
(invoke [_] (println bar))
(applyTo [this args] (clojure.lang.AFn/applyToHelper this args)))