Fork me on GitHub
#emacs
<
2019-07-12
>
Daouda01:07:15

hey Folks 🙂 I want to have a test file out of my clojure project, a file that i will use to try everything. But i want to use my project repl to run snippets code from that file. Is it possible? If yes, how can I do that please?

hkjels05:07:01

You can send individual defns or even arbitrary selections to a repl with cider

ag05:07:56

@UEA9PJ9FE you can try M-x cider-connect to the session

practicalli-johnny07:07:20

@UEA9PJ9FE why not just put your ‘test’ file in the project and require the namespaces of the functions you want to test. Then with the REPL running you can evaluate individual expressions in your ‘test’ file that call functions from the rest of your project. You could even use clojure.test If that doesn’t fit what you are trying to do, then please share more details of what you are trying to do,

Daouda02:07:36

Sorry guys for taking so long to answer you. Actually all your suggestions helped me a lot. Each of them helped me to achieve what I needed 😊

timvisher14:07:06

Is there any function in any of the emacs packages (cider, clojure-mode, clj-refactor, etc.) that will modify the textual form to add defs for all the locals? i.e. if I'm here

(let [a b c d]
  <point>
  …)
I'd get:
(let [a b c d]
  (def a a)
  (def b b)
  …)
or similarly in a defn form
(defn [a b c]
  <point>
  …)
I'd get:
(defn [a b c]
  (def a a)
  (def b b)
  (def c c)
  …)

practicalli-johnny15:07:41

@timvisher You should not use a def expression inside another expression. def is used to define a share name throughout the namespace

practicalli-johnny15:07:47

The let function creates local names, so already does what you want, you just need to use destructuring. Destructuring also works for function arguments

👍 4
yuhan15:07:41

I imagine this is just for temporary debugging purposes, not actual production code

practicalli-johnny16:07:39

Using def in the wrong scope can also give you incorrect results, throwing off your debugging.

yuhan15:07:08

ie. evaluating subexpressions in a let block

yuhan15:07:10

cider has a eval-up-to-point command that's useful for lots of those cases

yuhan15:07:51

otherwise I tend to use the scope-capture library and stick a (sc.api/spy) around the expressions I want to debug

kliph15:07:11

I've had some success using https://cider.readthedocs.io/en/latest/debugging/ lately, but I'm unaware of anything that would transform params into defs

timvisher15:07:55

Right. Was looking for something that wouldn't require an extra dep.

timvisher15:07:16

Makes it easier to transparently apply in prod or across whatever projects.

timvisher15:07:14

Although I'm reminded of Hoyte's reasoning behind not using emacs in LOL which was that emacs is a time-suck that encourages you to think about how to use it to write code for you rather than using [Clojure] to write code for you. 😛

dpsutton15:07:09

(def tapped (atom ()))

(defn tapper [x]
  (swap! tapped #(take 10 (cons x %))))

(defn add-value-tap []
  (add-tap tapper))

(defn remove-value-tap []
  (remove-tap tapper))
i just keep a little rolling buffer of things

practicalli-johnny16:07:39

Using def in the wrong scope can also give you incorrect results, throwing off your debugging.

practicalli-johnny16:07:31

cider-eval-defun-at-point is incredibly easy to use and requires no additional libraries or dependencies. You don't need to use the #dbg in your code if you just call that Emacs command on the function you want to debug. Evaluating the function again will switch of the debugging.

dpsutton16:07:06

@timvisher do/can you use the emacs debugger for these? I've got a handy macro for you if so

dpsutton16:07:52

while running the debugger you can invoke this function:

(defun cider-debug-create-local-let (start end)
  "During debugging, grab the locally bound vars and create a let
  binding. Place this let binding in the kill ring for future use."
  (interactive "r")
  (if cider--debug-mode-response
      (nrepl-dbind-response cider--debug-mode-response (locals)
        (let* ((code (buffer-substring-no-properties start end))
               (bindings (apply #'append locals))
               (formatted-bindings (mapconcat 'identity bindings " ")))
          (kill-new (format "(let [%s]\n %s)" formatted-bindings code))
          (message "copied let form to kill ring")))
    (message "No debugging information found.")))
and it captures the locals from the debugger and emits a let binding with the region you've selected

❤️ 4
dpsutton16:07:49

step through the debugger, highlight some code and then calling the above does "(let [%s]\n %s)" formatted-bindings code which makes a let form with the locals and the highlighted code into your kill ring

practicalli-johnny16:07:40

@dpsutton interesting idea, I will have to give that a try. Thanks.

timvisher16:07:09

@dpsutton Haven't ever gotten into the debugger although I've long wanted to. That's another nice thing about the textual change is that it doesn't lean on any of the middleware (not that that's a huge win. I use the middleware pretty freely anyway in prod).

timvisher16:07:14

I occasionally use the tapping technique when I can't control the callers or if I'm just interested in the values over time although I usually can use tools.trace for that and/or prepl.

timvisher16:07:36

(prepl being a theoretical thing. I haven't actually needed it yet.)

timvisher16:07:03

This is just an old-school LISP workflow which allows you to evaluate forms that refer to locals without editing them. Everything everyone's said so far makes sense it's just not the workflow I'm trying to support. 🙂

yuhan03:07:45

Lispy has this concept of "shadow locals" which I think is similar to what you're describing here - evaluate the let binding vector and it automatically injects them as locals in subsequent evals

theeternalpulse16:07:52

Does using println in a tap fn more efficient than running it in the main application thread?

andy.fingerhut17:07:37

Do you mean, is the tap fn executed on a different thread, and thus the main application thread can go back to doing what it did before calling the tap fn sooner than if the main application thread had called println directly?

andy.fingerhut17:07:26

Because if the question is: "Does calling println within a tap fn take less CPU resources than calling println from a main application thread?" I am pretty sure the answer is "no, it costs the same called in either place"

theeternalpulse17:07:20

The first one, sorry for my poor wording, though I think if I elaborated I would have answered my own question lol

andy.fingerhut17:07:17

The functions tap> and add-tap are documented to behave in a way where tap> does not block, implying it is merely placed on a queue. If there are too many functions processing those objects in the queue, or they are too slow, tap> can drop objects, not placing them in the queue at all.

yuhan03:07:45

Lispy has this concept of "shadow locals" which I think is similar to what you're describing here - evaluate the let binding vector and it automatically injects them as locals in subsequent evals