def'ine a value with a dynamic name - function

So I want to pass a function to the "name" portion of def.
The problem is:
"First argument to def must be a Symbol"
I'm trying to for instance do:
(def serverNumber 5)
(def (str "server" serverNumber) {:id serverNumber :value 4939})
But I can't find annnnnnny way to do this. Any help would be beyond appreciated :)

First, I have to note that this seems like a bad idea. Why are you trying to generate defs with dynamically-generated names? (As #pst already pointed out, maps are the usual solution for creating bindings with dynamically-generated identifiers.)
Assuming you have a legit reason for doing this (maybe it's part of some library functionality where you're generating defs for the user), you can accomplish this with a macro:
(defmacro def' [sym-exp & other-args]
`(def ~(-> sym-exp eval symbol) ~#other-args))
(def serverNumber 5)
(def' (str "server" serverNumber) {:id serverNumber :value 4939})
Note that this only works at the top level (since macros are run at compile time). If you want to do this in a function or something then you just need to use eval:
(defn def'' [sym-exp & other-args]
(eval `(def ~(-> sym-exp eval symbol) ~#other-args)))
If you just want to create a bunch of agents, maybe something like this will work:
(def servers
(vec (for [i (range 5)]
{:id i :value 4939})))
Then you can just access them by index:
(servers 0)
; => {:id 0, :value 4939}

The run-time equivalent of def is intern:
(intern *ns*
(symbol (str "server" server-number))
{:id server-number :value 4939})

Related

Cljs re-frame is not showing element as expected

I'm experimenting with Cljs re-frame, in which I'm trying to show a cell in UI with the below function,
(defn cell
[{:keys [id value on-change]}]
[(r/adapt-react-class Box) {:key id
:type :number
:ml 2
:content-editable (nil? value)
:on-change on-change
:border "2px solid #10AF34"
:width "30px"
:height "30px"
:align "center"}
value])
When I try to call the method directly from a method that is being invoked for rendering, it works,
(defn app
[]
(cell {:id "1-1"
:value nil
:on-change #(js/alert "in cell 1 1")}))
Whereas, when I try to wrap it in another method and call, it is not working
(defn grid
[data]
(cell {:id "1-1"
:value 1
:on-change #(js/alert "in cell 1 1")}))
(defn app
[]
(grid (generate-data)))
If someone wants to try it out, the grid/cell is available here and the app/rendering function is available here.
Your issue might stem from using [(r/adapt-react-class Box) …] - I‘m not sure it’s problematic, but I‘d either def the result of adapt-react-class and reuse it, or use the [:> Box …] syntax.

How to implement *load-fn* for :requires in bootstrapped clojurescript

(ns scratch
(:require [cljs.js :as cjs]))
;Let's setup a simple clojurescript string eval that supports namespaces:
(def current-ns 'cljs.user)
(def compiler-state (cjs/empty-state))
(defn eval-text [text]
(println string)
(cjs/eval-str compiler-state text current-ns
{:eval cjs/js-eval
:ns current-ns
:context :expr
:def-emits-var true}
(fn [result]
(set! current-ns (:ns result))
(println result))))
(eval-text "(ns a.a)")
(eval-text "(defn add [a b] (+ a b))")
(eval-text "(add 4 4)")
;I can refer to the function from another namespace explicitly with no problem
(eval-text "(ns x.x)")
(eval-text "(a.a/add 6 6)")
;However when I do
(eval-text "(ns b.b (:require [a.a :refer [add]]))")
On the last line I get:
{:error #error {:message Could not require a.a, :data {:tag :cljs/analysis-error}, :cause #object[Error Error: No *load-fn* set]}}
So I have to create my own https://cljs.github.io/api/cljs.js/#STARload-fnSTAR
and pass it into the :load compiler option to handle this :require even though the compiler state already knows about my namespace as I can call the fully qualified function from another namespace.. Correct?
What is the best way to do that?
Should I create maps that store namespace->source-code from previously evaled code and get namespace->analysis-cache from the compiler state and pass these into the :source and :cache callbacks of my custom load function?
Is there a better / more efficient way to do this?
I believe I found the answer:
The :load option of eval-str can be set to the following function:
(defn load-dep [opts cb]
(cb {:lang :js :source ""})
And it will quite happily resolve. This isn't really apparent from the documentation that the callback can return this value when the namespace/var is already in the compiler state so I'll leave the question here.

Which reagent Form 2 component function arguments are in use?

Which form is better?
(defn my-func [arg arg2]
(fn [] [:div (str arg arg2)]))
Or this one?
(defn my-func []
(fn [arg arg2] [:div (str arg arg2)]))
I'm writting from my phone so forgive me indentation...
There's other difference between these functions aside from arity.
The first function will close over arg, and arg2 on first render, and use these arguments for each subsequent rerender. E.g.
(def a 1)
(def b 2)
[my-func a b]
will always result in [:div '12'] whether or not a or b were changed
The second function will take arg, and arg2 on each render and will update the result when arguments change.
Look for Rookie mistake in reagent docs
I believe your question should be which one is correct(The first one is correct). The second one has got an arity exception. Based on your use case, I would prefer to define and call the anonymous function so as to get the results. Consider this number one edit:
(defn my-func [arg arg2]
((fn [] [:div (str arg arg2)])))

How to 'turn on' cljs.spec

How do I make sure that clojure/cljs.spec is verifying function call arguments and return values?
Say I have this function:
(defn my-inc [x]
(inc x))
After which I have this:
(s/fdef my-inc
:args (s/cat :x number?)
:ret number?)
This code compiles because [cljs.spec.alpha :as s] has been required.
Now I call the function so as to hopefully generate an error:
(my-inc "Not a number")
I would like to see the fdef being used, and see the error message stating that my-inc cannot be called with a string. How do I make this happen in a very general way, for instance with a setting in project.clj or user.cljs?
With this code in user.cljs:
(:require
[cljs.spec.alpha :as s]
[cljs.spec.test.alpha :as ts])
(defn my-inc [x]
(inc x))
(s/fdef my-inc
:args (s/cat :x number?)
:ret number?)
(ts/instrument)
(defn x-1 []
(my-inc "Hi"))
I can call x-1 from the cljs/figwheel REPL, and get this failure message:
#error {:message "Call to #'cljs.user/my-inc did not conform to spec:\nIn: [0] val: \"Hi\" fails at: [:args :x] predicate: number?\n:cljs.spec.alpha/spec #object[cljs.spec.alpha.t_cljs$spec$alpha50572]\n:cljs.spec.alpha/value (\"Hi\")\n:cljs.spec.alpha/args (\"Hi\")\n:cljs.spec.alpha/failure :instrument\n", :data #:cljs.spec.alpha{:problems [{:path [:args :x], :pred cljs.core/number?, :val "Hi", :via [], :in [0]}], :spec #object[cljs.spec.alpha.t_cljs$spec$alpha50572], :value ("Hi"), :args ("Hi"), :failure :instrument}}
I can also get conformance errors when working with a real project running code in a browser. The errors show up in the developer's console on the browser.
Put (ts/instrument) at the bottom of user.cljs to turn instrumentation on for all namespaces for development.
Edit
Just in case you are hit by this problem: https://dev.clojure.org/jira/browse/CLJS-1792
- the fix is to include [org.clojure/test.check "0.10.0-alpha2"] (probably with a more recent version) in your project.clj dependencies.
You can use instrument to check args conformance for certain symbols or all vars.
When called without arguments, instrument wraps all instrumentable vars into a function that checks the args before delegating to the original function.

Clojure: creating new instance from String class name

In Clojure, given a class name as a string, I need to create a new instance of the class. In other words, how would I implement new-instance-from-class-name in
(def my-class-name "org.myorg.pkg.Foo")
; calls constructor of org.myorg.pkg.Foo with arguments 1, 2 and 3
(new-instance-from-class-name my-class-name 1 2 3)
I am looking for a solution more elegant than
calling the Java newInstance method on a constructor from the class
using eval, load-string, ...
In practice, I will be using it on classes created using defrecord. So if there is any special syntax for that scenario, I would be quite interested.
There are two good ways to do this. Which is best depends on the specific circumstance.
The first is reflection:
(clojure.lang.Reflector/invokeConstructor
(resolve (symbol "Integer"))
(to-array ["16"]))
That's like calling (new Integer "16") ...include any other ctor arguments you need in the to-array vector. This is easy, but slower at runtime than using new with sufficient type hints.
The second option is as fast as possible, but a bit more complicated, and uses eval:
(defn make-factory [classname & types]
(let [args (map #(with-meta (symbol (str "x" %2)) {:tag %1}) types (range))]
(eval `(fn [~#args] (new ~(symbol classname) ~#args)))))
(def int-factory (make-factory "Integer" 'String))
(int-factory "42")
The key point is to eval code that defines an anonymous function, as make-factory does. This is slow -- slower than the reflection example above, so only do it as infrequently as possible such as once per class. But having done that you have a regular Clojure function that you can store somewhere, in a var like int-factory in this example, or in a hash-map or vector depending on how you'll be using it. Regardless, this factory function will run at full compiled speed, can be inlined by HotSpot, etc. and will always run much faster than the reflection example.
When you're specifically dealing with classes generated by deftype or defrecord, you can skip the type list since those classes always have exactly two ctors each with different arities. This allows something like:
(defn record-factory [recordname]
(let [recordclass ^Class (resolve (symbol recordname))
max-arg-count (apply max (map #(count (.getParameterTypes %))
(.getConstructors recordclass)))
args (map #(symbol (str "x" %)) (range (- max-arg-count 2)))]
(eval `(fn [~#args] (new ~(symbol recordname) ~#args)))))
(defrecord ExampleRecord [a b c])
(def example-record-factory (record-factory "ExampleRecord"))
(example-record-factory "F." "Scott" 'Fitzgerald)
Since 'new' is a special form, I'm not sure there you can do this without a macro. Here is a way to do it using a macro:
user=> (defmacro str-new [s & args] `(new ~(symbol s) ~#args))
#'user/str-new
user=> (str-new "String" "LOL")
"LOL"
Check out Michal's comment on the limitations of this macro.
Here is a technique for extending defrecord to automatically create well-named constructor functions to construct record instances (either new or based on an existing record).
http://david-mcneil.com/post/765563763/enhanced-clojure-records
In Clojure 1.3, defrecord will automatically defn a factory function using the record name with "->" prepended. Similarly, a variant that takes a map will be the record name prepended with "map->".
user=> (defrecord MyRec [a b])
user.MyRec
user=> (->MyRec 1 "one")
#user.MyRec{:a 1, :b "one"}
user=> (map->MyRec {:a 2})
#user.MyRec{:a 2, :b nil}
A macro like this should work to create an instance from the string name of the record type:
(defmacro newbie [recname & args] `(~(symbol (str "->" recname)) ~#args))