This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-06-17
Channels
- # announcements (2)
- # aws (4)
- # babashka (20)
- # beginners (256)
- # calva (15)
- # chlorine-clover (1)
- # cider (12)
- # clj-kondo (25)
- # cljsrn (16)
- # clojure (115)
- # clojure-europe (7)
- # clojure-finland (5)
- # clojure-italy (10)
- # clojure-nl (35)
- # clojure-spec (13)
- # clojure-uk (83)
- # clojurescript (42)
- # code-reviews (81)
- # conjure (8)
- # cursive (6)
- # data-science (1)
- # datomic (3)
- # duct (18)
- # emacs (2)
- # figwheel-main (40)
- # fulcro (21)
- # helix (1)
- # jackdaw (7)
- # java (2)
- # lein-figwheel (5)
- # luminus (1)
- # observability (12)
- # off-topic (32)
- # parinfer (5)
- # pedestal (19)
- # re-frame (5)
- # reagent (8)
- # reitit (17)
- # rewrite-clj (47)
- # rum (19)
- # shadow-cljs (48)
- # spacemacs (4)
- # sql (40)
- # tools-deps (22)
- # vrac (1)
- # xtdb (25)
I have following code-snippet:
(def ^:dynamic *env*
(into {} #?(:clj (System/getenv)
:cljs (js->clj (.-env js/process)))))
When I run my tests for nodejs target I get following errors:
Exception: clojure.lang.ExceptionInfo: ClojureScript Exception
{:via [{:type clojure.lang.ExceptionInfo, :message "Execution error (Error) at (<cljs repl>:1).\n[object Object] is not ISeqable\n", :data {:type :js-eval-exception, :error {:status :exception, :value "Execution error (Error) at (<cljs repl>:1).\n[object Object] is not ISeqable\n"}, :repl-env #cljs.repl.node.NodeEnv{:host "localhost", :port 54832, :path nil, :socket #object[clojure.lang.Atom 0x37abe814 {:status :ready, :val {:socket #object[java.net.Socket 0xfadd58 "Socket[addr=localhost/127.0.0.1,port=54832,localport=61160]"], :in #object[java.io.BufferedReader 0x6ba88a47 "java.io.BufferedReader@6ba88a47"], :out #object[java.io.BufferedWriter 0x35f18100 "java.io.BufferedWriter@35f18100"]}}], :proc #object[clojure.lang.Atom 0x335be91 {:status :ready, :val #object[java.lang.ProcessImpl 0x51386308 "Process[pid=45561, exitValue=137]"]}], :state #object[clojure.lang.Atom 0x18f98236 {:status :ready, :val {:listeners 0}}], :debug-port nil}, :form (require (quote com.vadelabs.grid.env-test)), :js "goog.require('com.vadelabs.grid.env_test');\n'nil';\n"}, :at [cljs.repl$evaluate_form invokeStatic "repl.cljc" 578]}], :trace [[cljs.repl$evaluate_form invokeStatic "repl.cljc" 578] [cljs.repl$evaluate_form invoke "repl.cljc" 499] [cljs.repl$eval_cljs invokeStatic "repl.cljc" 693] [cljs.repl$eval_cljs invoke "repl.cljc" 686] [kaocha.cljs.queue_eval_loop$start_BANG_$fn__3689$fn__3694 invoke "queue_eval_loop.clj" 78] [kaocha.cljs.queue_eval_loop$start_BANG_$fn__3689 invoke "queue_eval_loop.clj" 69] [cljs.compiler$with_core_cljs invokeStatic "compiler.cljc" 1435] [cljs.compiler$with_core_cljs invoke "compiler.cljc" 1424] [kaocha.cljs.queue_eval_loop$start_BANG_ invokeStatic "queue_eval_loop.clj" 55] [kaocha.cljs.queue_eval_loop$start_BANG_ doInvoke "queue_eval_loop.clj" 40] [clojure.lang.RestFn invoke "RestFn.java" 470] [kaocha.cljs.prepl$prepl$fn__3710$fn__3711 invoke "prepl.clj" 14] [kaocha.cljs.prepl$prepl$fn__3710 invoke "prepl.clj" 13] [clojure.core$binding_conveyor_fn$fn__5754 invoke "core.clj" 2030] [clojure.lang.AFn call "AFn.java" 18] [java.util.concurrent.FutureTask run "FutureTask.java" 264] [java.util.concurrent.ThreadPoolExecutor runWorker "ThreadPoolExecutor.java" 1128] [java.util.concurrent.ThreadPoolExecutor$Worker run "ThreadPoolExecutor.java" 628] [java.lang.Thread run "Thread.java" 830]], :cause "Execution error (Error) at (<cljs repl>:1).\n[object Object] is not ISeqable\n", :data {:type :js-eval-exception, :error {:status :exception, :value "Execution error (Error) at (<cljs repl>:1).\n[object Object] is not ISeqable\n"}, :repl-env #cljs.repl.node.NodeEnv{:host "localhost", :port 54832, :path nil, :socket #object[clojure.lang.Atom 0x37abe814 {:status :ready, :val {:socket #object[java.net.Socket 0xfadd58 "Socket[addr=localhost/127.0.0.1,port=54832,localport=61160]"], :in #object[java.io.BufferedReader 0x6ba88a47 "java.io.BufferedReader@6ba88a47"], :out #object[java.io.BufferedWriter 0x35f18100 "java.io.BufferedWriter@35f18100"]}}], :proc #object[clojure.lang.Atom 0x335be91 {:status :ready, :val #object[java.lang.ProcessImpl 0x51386308 "Process[pid=45561, exitValue=137]"]}], :state #object[clojure.lang.Atom 0x18f98236 {:status :ready, :val {:listeners 0}}], :debug-port nil}, :form (require (quote com.vadelabs.grid.env-test)), :js "goog.require('com.vadelabs.grid.env_test');\n'nil';\n"}}
I can’t seem to understand what it means, and how can I resolve it?what does (js->clj (.-env js/process))
show in the repl?
as well as #?(:clj "this is clj" :cljs "this is cljs")
there’s a lot on going in the one statement you posted. the best way to debug is break it down and reduce the surface of area of where the bug could be hiding
"not iseqable" means "you can't implicitly use this thing as a collection"
you can't just hand the output of
(js->clj (.-env js/process)))
to into like that, because clojure doesn't know what to do with itI think you want to move the into call into System/getenv
ClojureScript 1.10.764
cljs.user=>
cljs.user=>
(js->clj (.-env js/process))
#object[Object [object Object]]
cljs.user=>
I wish to read environment variable in cljs environment. If I remove :cljs
block it works fine…but! System/getenv already returns a Map, so you don't need the into
unless you plan to conj to it
right - you need some method on what .-env returns, js->clj isn't magic and isn't doing anything useful there
there are many values in js that should just be data but sadly are not
so you need to find the voodoo that turns it into data
Interesting… that explains the issue… thanks @U051SS2EU It really helps.. will try few changes and see if I get it working… Let me try to figure out that “voodoo” 😄 😄
I looked it up in the mdn docs, it's just a vanilla js obj, I bet there's something in goog that turns it into a hash
you could do it with this, but you would think somebody made something that would just give you a hash map by now https://google.github.io/closure-library/api/goog.object.html#getKeys
I thought that’s what js->clj
did , http://cljs.github.io/api/cljs.core/js-GTclj
clearly something else is going on then, based on the error
perhaps the thing js->clj returns as a map isn't seqable? that seems super wierd though
If I remove into
function… then it works… but need to dig deeper to understand what’s going on…
oh, then it's just that js->cljs is weird (the cljs authors warn against using it)
makes sense
(persistent!
(reduce (fn [r k] (assoc! r (keyfn k) (thisfn (gobject/get x k))))
(transient {}) (js-keys x)))
if you are OK with a weird almost map that isn't seqable, use js->clj, otherwise you can use goog.object - yeah like that @U7RJTCH6J
this is taken from js->clj
and seems like it would work
but I’m guessing js->clj
doesn’t work because it can’t tell if it should convert the type that is (.-env js/process)
the above snippet lets you parameterize the key type, but it’s probably just better to use the given key:
(persistent!
(reduce (fn [r k] (assoc! r k (gobject/get x k)))
(transient {}) (js-keys x)))
also, since this is #beginners we can lose a few ms of perf and use
(into {} (map (fn [k] [k (gobject/get x k)]))
(js-keys x))
(if it's easier to read / understand)
Thanks guys…
(defn- nodejs->clj
[x]
(persistent!
(reduce (fn [r k] (assoc! r k (gobject/get x k)))
(transient {}) (js-keys x))))
(def ^:dynamic *env*
(into {} #?(:clj (System/getenv)
:cljs (nodejs->clj (.-env js/process)))))
This snippet works as expected…if all you are doing is lookups, you might be able to skip both into
and nodejs->clj
(using the raw map from System/getenv
, and the raw map from js-clj
)
also, a common thing is to end up merging the result of getenv and getProperties (useful because it's easier to set / impose properties with java tooling)
Cool.. thanks… I did end up removing into
from the implementation…
Just an FYI, whenever I was running the above snippet in repl it was freezing my repl and editor… I realized that the js/process
has some cyclic key references… It works well with following:
(def ^:dynamic *env*
#?(:clj (System/getenv)
:cljs (->> (.-env js/process)
(.stringify js/JSON)
(.parse js/JSON)
(js->clj))))
I am just stringifying and parsing js object back again…interesting. I assumed that all the keys and values for the node process.env
would be strings.
Yes… even I hoped so… but it’s JS… lots of weird things keep happening under the hood 😄
My 2018 Macbook Pro battery swelled up and the Apple store isn't open anytime soon, so I've decided to take a look at Clojure coming from a Swift background as I'm now on Windows for the foreseeable future
I'm interested in learning a lisp as well as functional programming
So far, I've installed Cursive in IntelliJ and I've been playing around with the REPL
FYI there is a #cursive channel here, too, which might be the best place to ask questions that are specific to Cursive. Granted, it might not be obvious at first which of your questions might be Cursive-specific.
My first task will likely be creating a deck of cards
doing that as symbols is a fun one-liner - iirc it's one of the puzzles on http://4clojure.com
and the core function shuffle
does exactly what one wants in this domain haha
I'm not used to lisp, I feel like it's going to take a few days to get the hang of the syntax
the thing to really get the hang of is we have nearly no syntax!
we have a far fewer "special cases" than most languages do
everything that can act like a function or a collection does, as a good first rule of thumb :D
also immutability, which I used a bit in Swift since structs and let is a thing
in terms of the functional side
and then laziness - that's another gotcha
but these are not syntax, they are semantics
(which can be harder, it's just a different kind of problem)
syntax: how do I write the behavior I understand in my new language semantics: how do I construct the result I want from the behaviors my language offers
When I was first learning Clojure it seemed like a very steep uphill, and it can be; the good part is that the steep uphill is SHORT; you learn the few main concepts that are hard initially and then you’re like “That’s it?“…. and yes, that’s pretty much it 🙂
@contact921 Since you're on Windows, you might find #clj-on-windows of interest. Do you use Scoop to install things on Powershell?
I haven't tried yet, but I'm running Cursive inside of IntelliJ
Was that your preferred editor before this?
Prior to this I had been using XCode with Swift
@contact921 do you have the REPL running from within Cursive? If yes, you’re on a good track
@U050KSS8M nREPL server started on port 59471 on host 127.0.0.1 - <nrepl://127.0.0.1:59471> Clojure 1.10.0
I noticed that sometimes with parentheses you can delete them, is there a reason for this?
Sometimes I want to insert code, or move them
Ah, fair enough. I use both macOS and Windows, but I don't like IDEs so I find IntelliJ way too heavy.
@U04V70XH6 are you on emacs?
Ah, ok
I switched off Emacs about four years ago (after using it on and off for 20-some years).
@U04V70XH6 what do you use?
I went from Emacs to Atom, with Chlorine now, and Cognitect's REBL data browser.
@contact921 in any case, let me know if you have any specific questions about Cursive or in general Clojure, happy to help;
Thanks! I see now that the parentheses are highlighted in yellow to show the scope
Makes keeping track a lot easier
I thought Cursive had parinfer which managed parens automatically?
So you never have to “manually” delete them except in very rare cases, in those it’s usually just easier to retype the expression
Probably the biggest adjustment when learning a Lisp is getting used to either parinfer or paredit and letting the editor manage parens for us, and then the next level is "structural editing".
@U04V70XH6 yea it does, but you can manually select over some (()) and you can still delete non-matching (); again that’s almost never needed
@contact921 in terms of structural editing: I assume on Windows it’s also under Edit -> Structural Editing in IntelliJ
I’d point you to Slurp/Barf combinations; for me those are essential for structural editing
I probably use no more than 4-6 of the Structural Edition actions… you don’t really need all of them to be productive but I encourage you to try them all out
Thanks! I'm off to bed for now but will be back tomorrow
I installed things a few hours ago, and now have a base project in leiningen setup which I'm using to test syntax
i think the biggest barrier is parentheses and the lack of code you actually need to write
Once you get to a certain point, it's very much "what parentheses?" 🙂
There's also an element of http://www.loper-os.org/wp-content/parphobia.png
commented lisp code is almost python
Parinfer uses indentation to organize parens so it is very nearly Python.
Prefer swap!
so that you are applying a (pure) function to an atom's value rather than just resetting it to a new value.
(reset! a (inc @a))
has a race condition that (swap! a inc)
does not.
If you are resetting an atom to a specific constant and no race condition is possible.
I see the docs say 'without regard to previous state' but the implications of that aren't clear to me.
Do you understand why the expression above is a race condition @phil634?
Right, two threads, both executing (reset! a (inc @a))
could end up adding 1 or 2.
But two threads executing (swap! a inc)
are guaranteed to add 2.
So in a case where I know nothing else is going on, I can see that I might be safe with reset! but it seems odd that it's there if there's no case where there's a reason to prefer it.
If you want to set an atom to a constant, regardless of what else might be trying to update it, reset!
is appropriate.
Yes, that's one way of looking at it.
Gotcha, I think that makes sense in terms of the code I'm trying to understand. Thanks 🙂
But bear in mind the expression above -- which depends on the current value of the atom -- and therefore causes a race condition.
(reset! a v)
is a shorthand for (swap! a (constantly v))
(the implementation is different -- it uses primitives in clojure.lang.RT
-- but the effect is basically the same)
@phil634 in practice, reset! is very rarely needed; a situation I can recall using reset! is during development in the REPL; otherwise, not much
The case I came across was in the context of a simple Reagent markdown editor. {:on-change #(reset! markdown (-> % .-target .-value)) :value @markdown}]
I see; yea that’s a case where you’re simply grabbing the whole value from onChange and setting it to be the value of the atom named ‘markdown’; that’s an acceptable usage for simple cases like that;
also in ClojureScript as long as everything is on the same thread (which it usually is), the discussion about race conditions doesn’t really apply; that being said, swap! still has value, even on a single thread in many cases; makes it easier to reason about the current state of the data in your program;
Hi everyone! I learned that I can create self-referencing datastructures (e.g. a ring buffer) in Clojure using atoms. https://stackoverflow.com/questions/3696214/is-it-possible-to-create-circular-references-in-clojure Sadly, I also learned that this breaks the REPL, because of a stackoverflow. I wonde if there is a workaround for this.
naive solution could be to wrap reset! in function which supress printing out recursive result. Example:
(defn reset-silent! [atom] (reset! (first atom) atom) "Done")
But I was striked by something else... When dereferencing the atom... I got this runtime error:
Execution error (ClassCastException) at user/eval143 (REPL:0).
class clojure.lang.PersistentVector cannot be cast to class java.util.concurrent.Future (clojure.lang.PersistentVector is in unnamed module of loader 'app'; java.util.concurrent.Future is in module java.base of loader 'bootstrap')
I'm on OpenJDK 11.0.7
Confirmed: it's really caused by the previous exception 😅https://clojuredocs.org/clojure.core/*print-level* by default print-level is nil that cause your data to be printed recursively. Try give it some number )
trivial example:
nil
user> (set! *print-level* 3)
3
user> (def a [(atom nil)])
#'user/a
user> (reset! (first a) a)
[#<Atom@5671b54e: [#]>]
@U04V4KLKC that’s great stuff about print-level, didn’t know about it!
@UJRDALZA5 I think it doesn't matter, I would suggest controlled access (indirection) because you can somewhat easily do circular things with non-circular data and it's probably a bit more seizable.
I was thinking you'd want the buffer elements next to each other in memory, as in a Java array of primitives. Purely from performance point of view. If I have to do it, I would probably pick a good ring buffer implementation from Java.
That's a great tip, thanks a lot!
Ok, moving a more specific question from main clojure here. I have namespace:
(ns config)
(defn load-x [] (System/getProperty "X"))
(def X (load-x))
(ns app)
(System/setProperty "X" "some-val")
(use 'config :reload-all)
config/X
Problem is, it does not reload def X
It's just a representation of the folder, I know this code is not "repl" consider files config.clj and app.clj exist in filesystembut X is a string in your example, why you need to call it? and it is reloading after removing ()
around config/X
fixed the code, it was typed snippet... problem is that it is not reloading... I will try and run isolated example in new project
Hello Can anyone help me
How to break the loop in Clojure
Anyone let me know
You usually dont explicitly break loops, just put the recur in one branch of an if condition and the return value in the other
Ok thanks
I have a defrecord example like this: (defrecord SomeName [^String field1 ^boolean field2])
I'm having difficulty creating an instance of the above record. I figured I could do something like this: (def f (SomeName "hi" false)) but I get this error: Execution error at nrepl.middleware.interruptible-eval/evaluate (interruptible_eval.clj:79). Expecting var, but SomeName is mapped to class <project_name>.core.SomeName
(def f (SomeName. "hi" false))
I added a dot after record name.
record defines a class so to create an instance you have to use constructor.
That worked! Thank you! 🙂
It’s preferred to use the constructor functions instead of Java interop
(->SomeName “hi” false)
(map-SomeName {:field1 “hi” :field2 false})
These functions are created automatically when you use defrecord
Just tried the arrow style and that worked.
Tried (map-SomeName...) and got this error: Unable to resolve symbol: map-SomeName in this context
sorry map->SomeName
how might i easily determine if some object is capable of having metadata attached to it?
In the following function definition: (defn f [name1->name2]...) What does the name1->name2 syntax mean?
there's nothing special about that syntax. name1->name2 is a valid symbol, just like foo
Oh okay. Got it
so hard to say what it means w/o context
That's fine. Clojure allows variable names unlike anything I've ever seen before. In C++, for example, name1->name2 means access method name2 in instance name1. But -> is also the threading macro. But if it's just a plain old name I can accept that.
How to do (use 'some-namespace :reload-all)
inside deftest macro? Or achieve a similar effect. I noticed this is my main issue with regards to previous case of reloading def
if the variables are already refered, you just need require - I often use this at my repl:
(doto 'some.project.some-test (require :reload) (in-ns) (clojure.test/run-tests))
@U051SS2EU problem is im having trouble with this from within deftest macro,
(deftest configuration-test
(testing "sometest"
(use 'app.conf :reload-all :verbose)
(prn app.conf/some-val)))
problem is... that it says its reloading
(clojure.core/load "/app/conf")
(clojure.core/in-ns 'user)
(clojure.core/refer 'app.conf)
but app.conf
name space has (prn "refreshing") in the global scope to show me if its refreshed -> and its not getting calledand also the value remains unchanged, it seems the its already interanlly binded and wont budge
don't use use
for loading, use require
also reloading should be a dev operation, reflecting the fact you edited a file, it shouldn't be part of test logic
@U051SS2EU hm, the problem is that config is loading data from env/config file, i memoize the loading so that its pure with cached values... for runtime i do not need dynamic reloading - but for test and validating some scenarios i need to switch the config file
for the config namespace i very much desire it behaves as just some static values... but for testing I try to just call side-effecty (internal)mock library, that just switches out some of the stuff
I try to avoid reference passing as much as possible, with dynamic reloading config becomes a stateful dependency - which generally I try to remove from codebase 🙂
then check things like whether the file you edited is the same as the one the repl is using - if require didn't work we would have noticed
but in a bigger picture, requiring reload of a namespace to test your code is a code smell in clojure, and is a sign you are making things hard for yourself by fighting the language
we usually reference pass
I'm not saying what you are doing is objectively wrong, or impossible. just that it is going to be a fight
there are libraries that do config, (env, doesn't do reloading, aero, does do reloading), you might look at what they do
so I am actually refactoring large codebase, and trying to tackle some of the implicitly stateful things that were clumsy -> ref passing is not nice, because now I can access settings in straightforward way (since they are considered consts to life cycle of the app) I can just config/some-val... which is big improvement over @config/some-val
sure, env and aero both offer that as well
you can avoid redefs and still be testable without namespace reloading in test code, by having a mechanism of rebinding the definitions without reloading the namespace - eg. alter-var-root
or intern
can be used to change the value inside a var or create one from scratch
that said, reloading should work, and the failure to reload is probably a dev or tooling error
@U051SS2EU thanks for help, i managed to establish the problem was :aot flag
I feel like I should have noticed that
wouldn’t that normally mean change something to another thing in the context of clojure? like clj->js
hello! I'm someone who comes strictly from a clojure/java background wanting to do some front end work. I don't really understand how reagent/clojure input forms work. If I want to take a value from a text field and set an atom's value to it, where would I learn to do that? For reference, I don't really understand what's going on in this piece of code:
:on-change #(reset! time-color (-> % .-target .-value))
which parts?
(-> % .-target .-value)
specifically. I understand the thread macro and the %, but I don't understand what's happening with .-target and .-value.-
is just like .
except it only works on properties and not methods
it's needed in cljs because a cljs object can have a property and method with the same name, so it disambiguates
it's valid in clj, but never needed as having the same name for a method and a property is impossible in the jvm
it indicates object lookup interop https://clojure.org/reference/java_interop
it's used for accessing methods on objects, which are superficially like functions but unlike functions are not first class entities
or properties, which are like keys on a map
In Clojure, we define a variable with def and a function with defn? And defn is just a shorter version of (def name (fn [params* ] exprs*))?
that's mostly true, yes
both def and defn create var objects which are attached to the current namespace
inside a function, you should use let
to create local bindings, because def
can only create namespace level globally visible bindings, and isn't appropriate for local values
Perfect, this answered a question I had regarding let
How do you write an if-else statement?
I see examples of using if and got that to work, but not else
(defn login-system
[]
(println "Enter password: ")
(let [password (read-line)
password-attempt (read-string password)]
(if (= password "clojure")
(println "Logged in!"))))
else is just the third (optional) form in an if
also, if always returns a value (which is much more civilized if you think about it, and very useful)
So this code is working, except I noticed something odd
(defn login-system
[]
(println "Enter password: ")
(let [password (read-line)
password-attempt (read-string password)]
(if true (= :password-attempt "clojure")
(println "Logged in!")))
(if false (= :password-attempt "clojure")
(println "Bad password!")))
Entering 5t as a password attempt throws the following error:
Execution error (NumberFormatException) at cjlr.core/login-system (core.clj:28).Execution error (NumberFormatException) at cjlr.core/login-system (core.clj:28).
Invalid number: 5t
But then other entries like r4 work?read-string
should be unnecessary there, as read-line
should return a string.
read-string
means "use the Clojure data/code reader given this string, and try to convert the first Clojure data/code expression into a data structure in memory"
I find that code very weird - the two ifs will respectively only call their first or second branch
The error is because 5t
is not a legal Clojure data/code thing. It starts out looking like a number, but has the t
tacked on
I was getting stuck with :a .b trying to compare a variable to a string
:a is not a variable!
(if true :password : "clojure")
that's another problem, :password is a keyword, it's a data object that stands for itself
and if true
is never useful, it's only used in the example to show how branching works
see my example at the top level - one call to println, with a branch to return the apropriate string
Thanks
if you just do the "elementary" problems on http://www.4clojure.com/problems they are a good step by step intro to clojure basics btw, (using an old version, but that shouldn't matter for the really basic stuff)
also this guide is great, if you haven't looked at it yet https://clojure.org/guides/learn/syntax
Perfect, I'm going to check these out!
I'd expect (println (if (= password-attempt "clojure") "Logged in!" "Bad password!"))
that looks like (sort-by (juxt :b :a) maps)
to me
yeah, it's more than two groups, but group-by would help
but i read it there's only two groups: :b
is bananas, or its not bananas. put the bananas group first and then the rest
I saw them as both segregated and sorted
(ins)user=> (pprint (sort-by (comp not #{"bananas"} :b) maps))
({:a 1, :b "bananas"}
{:a 1, :b "bananas"}
{:a 1, :b "apples"}
{:a 4, :b "apples"}
{:a 1, :b "apples"}
{:a 5, :b "oranges"}
{:a 7, :b "apples"})
nil
Perhaps even (sort-by :b maps)
if you truly do not care about the relative order of maps with the same value for the :b
key
Oops, misunderstood question. Never mind.
Things are a lot easier now that I have slurp and barf figured out
I want to remap M-e to eval last sexp. how to do it? please help.
I tried this `(define-key cider-repl-mode-map (kbd "M-e") #'cider-eval-last-sexp )` but it did not work (edited)
This is the error Symbol's value as variable is void: cider-repl-mode-map
Do I need to reload the repl each time I make a change to my code in a project file?
I'm using leiningen and nREPL inside intelliJ
there's some clumsy workarounds, but the normal thing is to restart your repl if you change your project.clj
or if by "project file" you mean some file in your project, there are a few ways to keep your repl up to date without restarting
For example, I have a core.clj file which I'm writing test functions in and then running in the repl
cursive should provide some shortcut or option for reloading / auto-reloading
the generic answer is (require 'my.ns :reload)
- that works everywhere
a common thing for me to use while developing: (doto 'my.ns-test (require 'my.ns :reload) in-ns clojure.test/run-tests)
- this gives me a single thing to search for in repl history and run again
but once again, cursive likely have a shorthand that's more convenient, every environment offers something different
And if you remember to eval every top-level form as you write or change code, your REPL should stay up-to-date without needing any of those reload options. That's what I recommend everyone aims for.
is defmulti
pretty much the go-to for running a different method/function body depending on a specific property of a map?
This has been super helpful: https://github.com/mhuebert/maria