When using the repl, sometimes you want to destroy a variable because it somehow get in the way of your programming (most usually namespace collisions).
Is there a way to destroy a variable in clojure?
user>(def x 1)
#'user/x
user>(aggressive-destroy! x)
nil
user>x
Unable to resolve symbol: x in this context
ns-unmap
user=> (def my-var "this is my-var!")
#'user/my-var
user=> (println my-var)
this is my-var!
nil
user=> (ns-unmap 'user 'my-var)
nil
user=> (println my-var)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: my-var in this context, compiling:(NO_SOURCE_PATH:13)
user=>
Related
Given the following function
(defn func []
(break!))
I want the break! function to start a repl, and inside that repl I can print the callstacks that invokes func.
The feature is like ipdb in Python, which comes quite handy when we want to interactively investigate inside the runtime of some function.
A very basic version could just be:
(defn break! [] (clojure.main/repl))
That will start a new, nested REPL, and when you exit it (with ^D -- or ^Z on Windows), it will continue on.
You can't evaluate locals, but if you write break! as a macro, you can at least display the active locals before starting the REPL:
user=> (defmacro break! []
(let [locals (into {} (map (juxt keyword identity)) (keys &env))]
(prn locals)
(clojure.main/repl :prompt #(print "nested> "))))
#'user/break!
user=> (defn foo "Using the break! function." [a b] (break!))
#'user/foo
user=> (foo 13 42)
{:a 13, :b 42}
nested> (doc foo)
-------------------------
user/foo
([a b])
Using the break! function.
nil
nested> ^D
nil
user=>
If you want the stacktrace as data inside the nested REPL, you can evaluate (:trace (Throwable->map (Throwable.)))
In my app I'm providing some interface to users that they can provide code and app evaluates that code within sandbox(so eval fn not allowed).The thing is I need to catch if user overrides some built-in function such as =
Any ideas how to catch and prevent that thing?(The idea is they should not be able to do that)
Code:
(defn =
[]
//some code)
WARNING: = already refers to: #'clojure.core/= in namespace: user, being replaced by: #'user/=
One solution might be:
I was trying to get the warning message as String but with-out-str function did not work.
(with-out-str
(defn = []))
;=> ""
Also wrote that with-err-str(changed with-out-str little bit) did not work as well.
(defmacro with-err-str
[& body]
`(let [s# (new java.io.StringWriter)]
(binding [*err* s#]
~#body
(str s#))))
(with-err-str
(defn = []))
;=> ""
Need: "WARNING: = already refers to: #'clojure.core/= in namespace: user, being replaced by: #'user/="
It does work when you use eval:
user=> (with-err-str (eval '(defn - [] 11)))
"WARNING: - already refers to: #'clojure.core/- in namespace: user, being replaced by: #'user/-\n"
user=> (re-seq #"WARNING" (with-err-str (eval '(defn / [] 11))))
("WARNING")
Or you could redefine the defn macro in user's code, but nothing prevents them to use other clojure tools to redefine a var:
user=> (defmacro defn-safe
#_=> [nam & decls]
#_=> (if (resolve (symbol "clojure.core" (name nam)))
#_=> (print "Whoops")
#_=> (list* `defn (with-meta nam (assoc (meta nam) :private true)) decls)))
#'user/defn-safe
user=> (defn-safe foo [x] (+ x 2))
#'user/foo
user=> (foo 22)
24
user=> (defn-safe = [a b] (- a b))
Whoopsnil
user=>
Another option, and probably your best bet is using
https://github.com/clojure/tools.analyzer
clojail handles this (and many other things as well). If you're looking to sandbox Clojure, I'd recommend taking a look.
One solution might be like this:
(def before (set (vals (ns-map *ns*))))
(defn = [])
(def after (set (vals (ns-map *ns*))))
(clojure.set/difference before after)
;=> #{#'clojure.core/=}
I wanna get the string representation of a variable. For example,
(def my-var {})
How to get the string "my-var" from symbol my-var? And
(defn my-fun [] ...)
How to get the string "my-fun" from function my-fun?
user=> (def my-var {})
#'user/my-var
user=> (defn my-fun [] )
#'user/my-fun
user=> (name 'my-var)
"my-var"
user=> (name 'my-fun)
"my-fun"
user=> (doc name)
-------------------------
clojure.core/name
([x])
Returns the name String of a string, symbol or keyword.
nil
Every Var in Clojure has :name metadata attached.
user> (def my-var {})
#'user/my-var
user> (:name (meta #'my-var))
my-var
user> (let [a-var #'my-var]
(:name (meta a-var)))
my-var
However, usually if you already have the Var, then you already know the name anyway, and usually you don't use Vars in a program (i.e., you just pass my-var or my-fun rather than #'my-var and #'my-fun).
There's nothing to get the Var (or var-name) of a function or a value that happens to be the value of some Var. A Var knows its value, but not the other way round. That of course makes sense since, e.g., the very same function may be the value of zero (for local functions) or multiple vars.
How about this?
(defn symbol-as-string [sym] (str (second `(name ~sym)))
=> (def my-var {})
#'user/my-var
=> (symbol-as-string my-var)
"my-var"
=> (symbol-as-string 'howdy)
"howdy"
Doesn't work for function or macro names though, maybe someone can help me
=> (symbol-as-string map)
"clojure.core$map#152643"
=> (symbol-as-string defn)
java.lang.Exception: Can't take value of a macro: #'clojure.core/defn (NO_SOURCE_FILE:31)
I'm trying to call clojure.walk/stringify-keys on a map that might include record instances. Since stringify-keys is recursive, it attempts to convert the keys on my record, (since (map? record-var) is true) which causes an error. Is there any way to tell if a var is a record rather than just a Clojure map? I
d like to provide my own implementation of stringify-keys that is record-aware.
The current implementation of stringify-keys causes the following:
(use '[clojure.walk :only [stringify-keys]])
(defrecord Rec [x])
(let [record (Rec. "foo")
params {:x "x" :rec record}]
(stringify-keys params))
This causes the following exception: UnsupportedOperationException Can't create empty: user.Rec user.Rec (NO_SOURCE_FILE:1)
Records seem to implement the IRecord marker interface:
user=> (defrecord Rec [x])
user.Rec
user=> (require '[clojure.reflect :as r])
nil
user=> (:bases (r/reflect Rec))
#{java.io.Serializable clojure.lang.IKeywordLookup clojure.lang.IPersistentMap clojure.lang.IRecord java.lang.Object clojure.lang.IObj clojure.lang.ILookup java.util.Map}
user=> (instance? clojure.lang.IRecord (Rec. "hi"))
true
Update
1.6 now has the record? functions
you can check the type of each member and see if it is really a map or something else (where something else is presumed to be a record)
user> (type {:a 1 :b 2})
clojure.lang.PersistentArrayMap
Is there a way in clojure to get a function's code after the function has been loaded?
Ie. without doing something like [untested]
(defmacro blat [x] `(do (def code ~(quote (mexpand-all x)))
~x)))
(blat (defn func [abc] (...)))
You can get the source of a symbol using the clojure.repl/source function. However, this only works if the var for which the symbol resolves to is in a .clj file on the classpath. You can't, for example, do this:
user=> (defn foo [x] x)
#'user/foo
user=> (require 'clojure.repl)
nil
user=> (clojure.repl/source foo)
Source not found
nil