I'm writing a small application that includes a password change function with validators for password quality. Currently the validators are specified in a map like so:
(def validations
{:min-length 6
:max-length 32})
The validations map is defined in the validations namespace, but I plan to move it to a configuration namespace later on. My decision to use a map in this way was to make configuration straight-forward for non-programmers.
There are a number of validation functions in the validations namespace that usually take the form:
(defn min-length [n s]
{:req (str "be at least " n " characters long")
:pass? (>= (.length (or s "")) n)})
So with the function above (min-length 3 "clojure") would return {:req "be at least 3 characters long", :pass? true}.
I can validate a password with this function in the validation namespace with this function:
(defn validate-new-password [password]
(into {} (for [[k v] validations]
[k (eval (list (-> k name symbol) v password))])))
The result being something like:
>(validate-new-password "clojure")
{:min-length {:req "be at least 6 characters long", :pass? true},
:max-length {:req "be no longer than 32 characters long", :pass? true},
:min-digits {:req "have at least 1 digit", :pass? false},
:allow-whitespace {:req "not contain spaces or tabs", :pass? true},
:allow-dict-words {:req "not be a dictionary word", :pass? false}}
What is the most practical way to resolve the validation functions when the validate-new-password function is called from outside the validation namespace?
I've tried a number of approaches over the past weeks but I've never been happy with the resulting form (and none of them have worked!).
Generally I guess the question is "how are symbols in a :require'd namespace resolved when called by functions within that namespace?"
I'm also interested on any general comments about my implementation.
There is no need for eval, as in 98% of the cases.
(defn validate-new-password
[password]
(into {} (for [[k v] validations]
[k ((->> k name (symbol "your.name.space") resolve) v password)])))
To answer the general question (from the penultimate paragraph of the question), symbols are normally resolved at compile time -- you have to go out of your way (that is, use resolve1) to postpone resolution to runtime.
That said, you probably don't need to postpone resolution in this case, you simply need to :require the configuration namespace in the validations namespace and refer to config/validations in the relevant spot.
A minor complication would arise if you wanted your config namespace to depend on the validations namespace (i.e. :require or :use it itself, or else another namespace which depends on it). In that case you could provide a handful of configuration setters in the validations namespace and use those from config. E.g.:
(def validations (atom default-validations))
(defn set-validations! [vs] (reset! validations vs))
(defn add-validation! [k v] (swap! validations assoc k v))
Then put #validations in place of validations in validate-new-password.
Alternatively, you could put your default validations in a Var and provide functions to rebind the Var (presumably this will only need to happen once, or else very rarely, so using a Var shouldn't be a problem):
(def validations default-validations)
(defn set-validations! [vs] (.bindRoot validations vs))
(defn add-validation! [k v] (alter-var-root validations assoc k v))
Now if you actually cannot predict, at the time of writing the code, which namespace you'll need to resolve your symbol in, then kotarak's answer (with its use of resolve) is the way to go.
1 You could say eval also allows you to do it, although technically it performs compilation at runtime, so symbol resultion in eval'd forms still occurs at compilation time. The more important thing to remember about it is that it's hardly ever needed.
Related
I am trying to print the documentation for all functions in a given namespace by invoking the following expression in a REPL:
(doseq
[f (dir-fn 'clojure.repl)]
(doc f))
However the invocation of this expression returns nil without printing the documentation to the REPL. I know this might have to do with doc being a macro, but I'm a Clojure novice and am not entirely sure how to understand the problem.
Why does this expression return nil without printing the documentation?
How can this expression be modified so that it prints the documentation for each function in a given namespace?
Thanks!
Update: Combined both provided answers:
(defn ns-docs [ns']
(doseq [[symbol var] (ns-interns ns')]
(newline)
(println symbol)
(print " ")
(println (:doc (meta var)))))
(ns-docs 'clojure.repl)
I would, instead, start here:
The Clojure CheatSheet
ClojureDocs.org
Clojure-Doc.org (similar name, but different)
The API & Reference sections at Clojure.org
Note that doc is in the namespace clojure.repl, which reflects its intended usage (by a human in a repl). Here is some code that will also iterate on a namespace & print doc strings (using a different technique):
(doseq [[fn-symbol fn-var] (ns-interns 'demo.core)]
(newline)
(println fn-symbol)
(println (:doc (meta fn-var))))
where demo.core is the namespace of interest.
Note that ns-interns gives you both a symbol and var like:
fn-symbol => <#clojure.lang.Symbol -main>
fn-var => <#clojure.lang.Var #'demo.core/-main>
The meta function has lots of other info you may want to use someday:
(meta fn-var) =>
<#clojure.lang.PersistentArrayMap
{ :arglists ([& args]),
:doc "The Main Man!",
:line 9, :column 1,
:file "demo/core.clj",
:name -main,
:ns #object[clojure.lang.Namespace 0x14c35a06 "demo.core"]}>
While this probably won't help you with answering your question, the problem of evaluating macro's comes up a lot when you are learning Clojure.
Macros are responsible for the evaluation of their arguments. In this case clojure.repl/doc will ignore the current lexical context and assume that the symbol f that you're giving it is the name of a function you want to see the documentation for. It does this because it's intended to be used at the REPL, and is assuming you wouldn't want to type quotes all the time.
As f doesn't exist, it prints nothing. Then doseq returns nil, since it exists to do something for side effects only - hence starting in do. In order to pass an argument to a macro that refuses to respect the lexical context like this, you need to write the code for each element in the list.
You can do this by hand, or by constructing the code as data, and passing it to eval to execute. You can do this in an imperative style, using doseq:
(doseq [f (ns-interns 'clojure.repl)]
(eval `(doc ~(symbol "clojure.repl" (str (first f))))))
or in a slightly more Clojurey way (which will allow you to see the code that it would execute by removing eval from the end and running it at the REPL):
(->> (ns-interns 'clojure.repl)
(map #(list 'clojure.repl/doc (symbol "clojure.repl" (str (first %)))))
(cons `do)
eval)
In both of these we use quote and syntax-quote to construct some code from the list of symbols reflected from the namespace, and pass it to eval to actually execute it. This page on Clojure's weird characters should point you in the right direction for understanding what's going on here.
This an example of why you shouldn't write macro's, unless you've got no other options. Macro's do not compose, and are often difficult to work with. For a more in depth discussion, Fogus's talk and Christophe Grand's talk are both good talks.
Why does this expression return nil without printing the documentation?
Because the doc macro is receiving the symbol f from your loop, instead of a function symbol directly.
How can this expression be modified so that it prints the documentation for each function in a given namespace?
(defn ns-docs [ns']
(let [metas (->> (ns-interns ns') (vals) (map meta) (sort-by :name))]
(for [m metas :when (:doc m)] ;; you could filter here if you want fns only
(select-keys m [:name :doc]))))
(ns-docs 'clojure.repl)
=>
({:name apropos,
:doc "Given a regular expression or stringable thing, return a seq of all
public definitions in all currently-loaded namespaces that match the
str-or-pattern."}
...
)
Then you can print those maps/strings if you want.
As part of improving Cider's debugger, I need to implement special handling for all possible special-forms. In order words, I need to know all symbols which satisfy special-symbol?.
The doc page on Special Forms, while helpful, doesn't offer all of them.
For instance, after some experimentation, I've learned that
Most of the forms listed there have a * counterpart (let* and loop*, for instance).
There is a clojure.core/import* special-symbol (which I wouldn't have found if not for sheer luck).
Is there a complete list of all special symbols?
Alternatively, is there a way to list all interned symbols? If so, then I could filter over special-symbol?.
Looking at the definition of special-symbol? provides a big clue:
(defn special-symbol?
"Returns true if s names a special form"
{:added "1.0"
:static true}
[s]
(contains? (. clojure.lang.Compiler specials) s))
Thus:
user=> (pprint (keys (. clojure.lang.Compiler specials)))
(&
monitor-exit
case*
try
reify*
finally
loop*
do
letfn*
if
clojure.core/import*
new
deftype*
let*
fn*
recur
set!
.
var
quote
catch
throw
monitor-enter
def)
I have compojure based app where I need to parse a request and retrieve parameters that can be numbers. I want to be able to verify that the parameters exist and that they are numbers before actually processing the request. This is what I have so far:
(defn get-int [str]
"Returns nil if str is not a number"
(try (Integer/parseInt str)
(catch NumberFormatException _)))
(defn some-request [request]
(let [some-number (get-int (get-in request [:route-params :some-number])
other-number (get-int (get-in request [:route-params :other-number])]
(if (every? identity [some-number other-number])
(process-the-request)
(bad-request "The request was malformed")))
Is there a better way to do string -> number conversion?
Is there a better way to do request validation?
This question contains good examples for parsing numbers in Clojure. If you are not sure that the string contains a valid number, your approach looks good.
If you can pass the parameters as part of the query string, you could use a route with regex to retrieve the value, e.g.
(GET ["/user/:id", :id #"[0-9]+"] [id]
(let [num (read-string id)]
(str "The number is: " num)))
The route would only match if the regex conditions are met, therefore you could skip the Integer/parseInt check.
Use Long/parseLong instead of Integer/parseInteger. The latter supports only 32 bits, which is often insufficient; for instance, Datomic entity IDs don't fit into Integer.
Never use read-string for user input. In addition, you must sanitize user input, removing injected scripts and such. https://github.com/alxlit/autoclave is a good start, although the defaults are arguably too aggressive.
I have an incoming lazy stream lines from a file I'm reading with tail-seq (to contrib - now!) and I want to process those lines one after one with several "listener-functions" that takes action depending on re-seq-hits (or other things) in the lines.
I tried the following:
(defn info-listener [logstr]
(if (re-seq #"INFO" logstr) (println "Got an INFO-statement")))
(defn debug-listener [logstr]
(if (re-seq #"DEBUG" logstr) (println "Got a DEBUG-statement")))
(doseq [line (tail-seq "/var/log/any/java.log")]
(do (info-listener logstr)
(debug-listener logstr)))
and it works as expected. However, there is a LOT of code-duplication and other sins in the code, and it's boring to update the code.
One important step seems to be to apply many functions to one argument, ie
(listen-line line '(info-listener debug-listener))
and use that instead of the boring and error prone do-statement.
I've tried the following seemingly clever approach:
(defn listen-line [logstr listener-collection]
(map #(% logstr) listener-collection))
but this only renders
(nil) (nil)
there is lazyiness or first class functions biting me for sure, but where do I put the apply?
I'm also open to a radically different approach to the problem, but this seems to be a quite sane way to start with. Macros/multi methods seems to be overkill/wrong for now.
Making a single function out of a group of functions to be called with the same argument can be done with the core function juxt:
=>(def juxted-fn (juxt identity str (partial / 100)))
=>(juxted-fn 50)
[50 "50" 2]
Combining juxt with partial can be very useful:
(defn listener [re message logstr]
(if (re-seq re logstr) (println message)))
(def juxted-listener
(apply juxt (map (fn [[re message]] (partial listner re message))
[[#"INFO","Got INFO"],
[#"DEBUG", "Got DEBUG"]]))
(doseq [logstr ["INFO statement", "OTHER statement", "DEBUG statement"]]
(juxted-listener logstr))
You need to change
(listen-line line '(info-listener debug-listener))
to
(listen-line line [info-listener debug-listener])
In the first version, listen-line ends up using the symbols info-listener and debug-listener themselves as functions because of the quoting. Symbols implement clojure.lang.IFn (the interface behind Clojure function invocation) like keywords do, i.e. they look themselves up in a map-like argument (actually a clojure.lang.ILookup) and return nil if applied to something which is not a map.
Also note that you need to wrap the body of listen-line in dorun to ensure it actually gets executed (as map returns a lazy sequence). Better yet, switch to doseq:
(defn listen-line [logstr listener-collection]
(doseq [listener listener-collection]
(listener logstr)))
Given a list of names for variables, I want to set those variables to an expression.
I tried this:
(doall (for [x ["a" "b" "c"]] (def (symbol x) 666)))
...but this yields the error
java.lang.Exception: First argument to def must be a Symbol
Can anyone show me the right way to accomplish this, please?
Clojure's "intern" function is for this purpose:
(doseq [x ["a" "b" "c"]]
(intern *ns* (symbol x) 666))
(doall (for [x ["a" "b" "c"]] (eval `(def ~(symbol x) 666))))
In response to your comment:
There are no macros involved here. eval is a function that takes a list and returns the result of executing that list as code. ` and ~ are shortcuts to create a partially-quoted list.
` means the contents of the following lists shall be quoted unless preceded by a ~
~ the following list is a function call that shall be executed, not quoted.
So ``(def ~(symbol x) 666)is the list containing the symboldef, followed by the result of executingsymbol xfollowed by the number of the beast. I could as well have written(eval (list 'def (symbol x) 666))` to achieve the same effect.
Updated to take Stuart Sierra's comment (mentioning clojure.core/intern) into account.
Using eval here is fine, but it may be interesting to know that it is not necessary, regardless of whether the Vars are known to exist already. In fact, if they are known to exist, then I think the alter-var-root solution below is cleaner; if they might not exist, then I wouldn't insist on my alternative proposition being much cleaner, but it seems to make for the shortest code (if we disregard the overhead of three lines for a function definition), so I'll just post it for your consideration.
If the Var is known to exist:
(alter-var-root (resolve (symbol "foo")) (constantly new-value))
So you could do
(dorun
(map #(-> %1 symbol resolve (alter-var-root %2))
["x" "y" "z"]
[value-for-x value-for-y value-for z]))
(If the same value was to be used for all Vars, you could use (repeat value) for the final argument to map or just put it in the anonymous function.)
If the Vars might need to be created, then you can actually write a function to do this (once again, I wouldn't necessarily claim this to be cleaner than eval, but anyway -- just for the interest of it):
(defn create-var
;; I used clojure.lang.Var/intern in the original answer,
;; but as Stuart Sierra has pointed out in a comment,
;; a Clojure built-in is available to accomplish the same
;; thing
([sym] (intern *ns* sym))
([sym val] (intern *ns* sym val)))
Note that if a Var turns out to have already been interned with the given name in the given namespace, then this changes nothing in the single argument case or just resets the Var to the given new value in the two argument case. With this, you can solve the original problem like so:
(dorun (map #(create-var (symbol %) 666) ["x" "y" "z"]))
Some additional examples:
user> (create-var 'bar (fn [_] :bar))
#'user/bar
user> (bar :foo)
:bar
user> (create-var 'baz)
#'user/baz
user> baz
; Evaluation aborted. ; java.lang.IllegalStateException:
; Var user/baz is unbound.
; It does exist, though!
;; if you really wanted to do things like this, you'd
;; actually use the clojure.contrib.with-ns/with-ns macro
user> (binding [*ns* (the-ns 'quux)]
(create-var 'foobar 5))
#'quux/foobar
user> quux/foobar
5
Evaluation rules for normal function calls are to evaluate all the items of the list, and call the first item in the list as a function with the rest of the items in the list as parameters.
But you can't make any assumptions about the evaluation rules for special forms or macros. A special form or the code produced by a macro call could evaluate all the arguments, or never evaluate them, or evaluate them multiple times, or evaluate some arguments and not others. def is a special form, and it doesn't evaluate its first argument. If it did, it couldn't work. Evaluating the foo in (def foo 123) would result in a "no such var 'foo'" error most of the time (if foo was already defined, you probably wouldn't be defining it yourself).
I'm not sure what you're using this for, but it doesn't seem very idiomatic. Using def anywhere but at the toplevel of your program usually means you're doing something wrong.
(Note: doall + for = doseq.)