You can always create a single test resource with input and expected output per task, then run a test for each task. Something like (typos are expected, I did this on my phone):
deftest test-tasks
(doseq [[task {:keys [input expected]}] my-test-resource]
(testing task
(is (= expected (run-task task input))))))
@artem00298 ^ that would be my recommendation too: put all the data together and have a single test that runs each set of data through the (is (= ...))
test.
Not sure why but this piece of code is failing by not printing anything to the console
(defn parse-item [data]
(let [
title (get-in data [:attributes :title])
]
(println (format "Titulo: %s" title))
)
)
(defn success [response]
"Performs the items parsing if the request was successfully"
(let [items (get-items response)]
(map parse-item items))
)
where items
used in (map parse-item items)
is an structure like this (but bigger)
`
[{:id 'Some id', :attributes {:title 'Some title', :tags [] } }
{:id 'Some id 2', :attributes {:title 'Some title', :tags [] } }
]```Because map
is lazy and you're not realizing the sequence I suspect @matiasfh
Rule of thumb: do not use map
for anything with side-effects (like println
).
(run! parse-item items)
would be eager and run parse-items
for each item, so it would print lines. But that won't help you when you change parse-item
to actually produce transformed data.
make sense.. I'm printing there to a way of "debugging" not try to see what is happening.. what could be a clojure way of doing this (very bad) debugging?
Separate the transform from the print.
the idea is to just return the (format)
form
if success
really is just map
over items
, then (run! println (success ...))
would be the way to print results.
(def items my-items) (parse-item (first items))
should be enough
just call your function on one of the items. when it works, it should work on all of the items
Yeah, if you're working tightly in the REPL, you would test parse-item
by calling it on a single item.
(defn success [response]
(map #(format "Titulo: %s" %) (get-items response)))
would probably be simpler/more idiomatic.If you want a sequence of strings?
make sense.. now since you are online xD..
I just tried another thing (connected with this) .
This code is for a discord bot, so the bot connect to discord and receive a command. in this case the command triggers a http request using clj-http
and cheshire
.
Then parse the response with that function that we were talking.
but this error is fired up
SEVERE: Exception in dispatch-http
java.lang.Exception: Don't know how to write JSON of class org.apache.http.impl.nio.client.FutureWrapper
at clojure.data.json$write_generic.invokeStatic(json.clj:389)
at clojure.data.json$write_generic.invoke(json.clj:386)
at clojure.data.json$eval9381$fn__9382$G__9372__9389.invoke(json.clj:290)
at clojure.data.json$write_object.invokeStatic(json.clj:339)
at clojure.data.json$write_object.invoke(json.clj:323)
at clojure.data.json$eval9381$fn__9382$G__9372__9389.invoke(json.clj:290)
at clojure.data.json$write.invokeStatic(json.clj:479)
at clojure.data.json$write.doInvoke(json.clj:428)
at clojure.lang.RestFn.invoke(RestFn.java:425)
at clojure.lang.AFn.applyToHelper(AFn.java:156)
at clojure.lang.RestFn.applyTo(RestFn.java:132)
at clojure.core$apply.invokeStatic(core.clj:669)
at clojure.core$apply.invoke(core.clj:660)
at clojure.data.json$write_str.invokeStatic(json.clj:486)
at clojure.data.json$write_str.doInvoke(json.clj:481)
at clojure.lang.RestFn.invoke(RestFn.java:410)
at discljord.messaging.impl$eval11931$fn__11933.invoke(impl.clj:132)
at clojure.lang.MultiFn.invoke(MultiFn.java:239)
at discljord.messaging.impl$make_request_BANG_$make_request__13636.invoke(impl.clj:788)
at discljord.messaging.impl$make_request_BANG_.invokeStatic(impl.clj:793)
at discljord.messaging.impl$make_request_BANG_.invoke(impl.clj:767)
at discljord.messaging.impl$step_agent$fn__13660.invoke(impl.clj:838)
at clojure.core$binding_conveyor_fn$fn__5754.invoke(core.clj:2033)
at clojure.lang.AFn.applyToHelper(AFn.java:154)
at clojure.lang.RestFn.applyTo(RestFn.java:132)
at clojure.lang.Agent$Action.doRun(Agent.java:114)
at clojure.lang.Agent$Action.run(Agent.java:163)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
at java.base/java.lang.Thread.run(Thread.java:832)
based on my basic knowledge of Java this is clearly a problem with the async function`
(defn get-on-brd-message [query]
(let [url (get-url query)]
(client/get url {:accept :json :async? true }
(fn [response] (success response))
;; raise callback
(fn [exception] (println (.getMessage exception)))
)))
this is an error in writing json, not reading json
but you're trying to serialize some asynchronous value which can't work
Just by asking I figured that should try with a sync version of the request
😄
Thanks folks!
Hello all, I am now in the Clojure world, and I am really enjoying learning it. I have a very dumb question but I am not able to find it by my self. Why in the sample code I cannot have two (assoc-in…) ? I am trying to print both values but nothing happens. Thank you very much in advance.
;; interceptor for authorization
(def auth
{:name :auth
:enter
(fn [context]
(let [token (-> context :request :headers (get "token"))]
(if-let [uid (and (not (nil? token)) (get-uid token))]
(assoc-in context [:request :tx-data :user] uid)
(assoc-in context [:request :my-key :my-value] "Hello Again")
(chain/terminate
(assoc context
:response {:status 401 :body "Auth token not found"})))))
:error
(fn [context ex-info]
(assoc context
:response {:status 500 :body (.getMessage ex-info)}))
})
@ricardozcabral Welcome! Clojure is an expression-based language with immutable data. In the code above you seem to have three expressions inside your if
which I don't think should even compile. Each expression needs to have a single return value.
(def auth
{:name :auth
:enter
(fn [context]
(let [token (-> context :request :headers (get "token"))]
(if-let [uid (and (not (nil? token)) (get-uid token))]
(->
(assoc-in context [:request :tx-data :user] uid)
(assoc-in [:request :my-key :my-value] "Hello Again"))
(chain/terminate
(assoc context
:response {:status 401 :body "Auth token not found"})))))
:error
(fn [context ex-info]
(assoc context
:response {:status 500 :body (.getMessage ex-info)}))
})
This might help..Can you explain what you are trying to do in that if
?
@prayaganeethu Could you indent that code to show the grouping better?
I was just trying to understand how assoc-in works, if I could include more than one value on it. I have also tried to put that before the if and it did not work. But I believe you are correct @seancorfield I missed the if part. Thank you very much. and thank @prayaganeethu to show me how to fix it
Perhaps:
(def auth
{:name :auth
:enter
(fn [context]
(let [token (-> context :request :headers (get "token"))]
(if-let [uid (and (not (nil? token)) (get-uid token))]
(-> context
(assoc-in [:request :tx-data :user] uid)
(assoc-in [:request :my-key :my-value] "Hello Again"))
(chain/terminate
(assoc context
:response {:status 401 :body "Auth token not found"})))))
:error
(fn [context ex-info]
(assoc context
:response {:status 500 :body (.getMessage ex-info)}))
})
(thanks for the edit to show the grouping)
It definitely takes a bit of getting used to if your background is in statement-based languages that rely on mutation 😐
My background is 99% Java, so I am struggling a bit with it 😄
Hey, at least you're used to the JVM and stacktraces! 🙂
This is one of the reasons I am trying to learn Clojure, it helps a lot to be used to the JVM. Just so you know the sample above still doesn’t work I am getting clojure.lang.ArityException in Interceptor :auth - Wrong number of args (4) passed to: clojure.core/assoc-in%
(->
context
(assoc-in [:request :tx-data :user] uid)
(assoc-in [:request :my-key :my-value] "Hello Again"))
Please do recheck the arguments in both the assoc-in
- might have left context
in there still as an arg, henceYou are a life saver. Not it woks Thank you very much again 🙂
I have a certain reduction function which I need to write. I don't know what to call it or whether something similar exists. Does this sound like any kind of standard algorithm or standard iteration function? The function takes an object representing an expression, such as a mathematical expression, or boolean expression etc. And the function takes a set of reduction operations. Each reduction operation is a function which is given the opportunity to simplify the expression, thus each option takes the expression as argument and either returns the same expression or a simplified form. The algorithm keeps calling reduction functions in-turn until one successfully reduces it, i.e. until one fails to return the same object it received.
it's sort of a cousin of fixed-point
so basically (->> your-vector-of-operations (cons identity) (map #(% your-expression)) distinct second)
?
sorry, I don't understand that logic. Does that expression halt the computation as soon as one operation returns something different than it is given?
Here's what I have, untested:
(defn find-simplifier [obj simplifiers] ;; BAD name, need better name
(if (empty? simplifiers)
obj
(loop [[f & fs] simplifiers]
(let [new-obj (f obj)]
(cond
(not= new-obj obj)
new-obj
(empty? fs)
obj
:else
(recur fs))))))
my map
is subject to chunking, though; but perhaps it's fixable
Is there any video/tutorial about how to use doom emacs with clojure, kind of a workflow how to?. I'm completely ignorant about how to work with the code and the repl in a "dynamic" way
what is chunking?
http://www.tianxiangxiong.com/2016/11/05/chunking-and-laziness-in-clojure.html
This is not related to refactoring your code, however since I'm assuming you want to test for an empty rest of your simplifiers collection where you call (empty fs)
, what you are looking for in that case, just an FYI, is the predicate empty?
which would read (empty? fs)
instead
oh you mean it might calculate too many elements only to throw away unused ones?
yes.
Thanks, yes you're right. As I said I haven't tested it yet.
actually, a bit of clarification there (seq fs)
would be more idiomatic
Yes, I think that discussion has been had many times. I organised my code to avoid calling (not (empty? ...))
to avoid the dispute yet again.
I think you need a termination check on f first (and then you can remove the fs check), but seems like the right path to me
Yes, that's something I want to avoid. as any of the function might have high complexity. I'd like to avoid calling a tree reduction if a previous simplification gave me a good result.
(some #(let [expr' (% expr)] (and (not= expr' expr) expr')) your-funcs)
should do, if neither expr nor expr' can legally be falsey
argh, I was about to post it 😄
(defn simplify [x fs]
(or (some #(let [x' (% x)] (when-not (= x' x) x')) fs)
x))
@vlaaad, does that work if one of the functions reduces the expression to nil
or false
?
it is very likely, and desired sometimes that an expression simply to nil
I fixed the code. BTW.
@alexmiller don't I have to assure that the sequence is non-empty before restructuring it into [f & fs]
?
it does not 🙂
I dont have exactly what you ask, but this book may help https://practicalli.github.io/spacemacs/clojure-projects/ There may be differences in keybindings (I found doom a bit lacking in that area) The workflow I take is essentially this: • create a project on the command line (or eshell) • Open the project in emacs • cider-jack-in-clj to start a repl for the project • edit and evaluate code in the src buffers (I rarely use the REPL buffer directly) • cider-undef and cider-ns-refresh or just stop start the repl if I have stale vars (usually renaming functions or deftest functions without undef'ing the old name • Put experimental code in rich code blocks http://practicalli.github.io/clojure/repl-driven-devlopment.html#rich-comment-blocks---living-documentation • write test to start solidifying the design and run all tests with the cider runner https://practicalli.github.io/spacemacs/testing/unit-testing/running-tests.html • run a command line test runner, eg. kaocha, before committing to run the tests from scratch
Also take a look at http://www.parens-of-the-dead.com/ Its not a tutorial, but you can see repl driven development in action
There is a general #emacs channel here. Doom has a discord community, you may find some help there also.
you can augment the code to return (reduced x')
instead of x'
and then check if result of (some ...)
is reduced and then deref it if it is reduced and return x if it is nil
I did a thing: https://github.com/matiasfha/JenkinsBot A discord bot written in Clojure (first app) If you can take a look it will be very helpful
at this point just using reduce
instead would be simpler (i think)
no
you'll just nil for both if it's nil
more complex, actually, because you will be dealing with 2 moving parts instead of 1 (item and accumulator instead of item)
well, the first part is not actually moving all that much 🙂
but probably easier since it unpacks reduced
for you
yeah, that was the idea
I’m curious about why there is no def-
? Is using metadata dictionary the only way to declare private vars? :thinking_face:
but you won't be able to distinguish that from a real sequence [nil]
, ok in this case that can't happen as I have a sequence of unary functions, which I suppose nil is not.
yes
in short, defn-
was a mistake, metadata on a name is preferred
ouch, that's another difference apparently between function application and restructuring ((fn [a & as] 12))
throws an error but (let [[a & as] nil] ...)
binds a to nil
.
Because this is true about functions, I supposed it would be true about functions. 😞
but why defn-
was a mistake? it is pretty useful IMHO
If defn-
leads to requests for def-
, defmacro-
, ..., then it is a mistake. Adding metadata :private
to any/all of them works, including on defn
, and leads to fewer overall names needing defining
I have a threading macro: (-> a b c d)
I want to make c
conditional, so only if something-happened
is truthy the pipeline will go through c
. What is the best way to achieve this?
(-> a b (cond-> something-happened c) d)
oh this works
Consider why you wish to make things private. As Clojure uses immutable data, there is less reason to hide data. So the private concept is not as relevant in Clojure. It is mostly used as documentation rather than a constraint on accessing certain parts of code (which can still be accessed when private) Metadata forms part of the function documentation, so is more useful that creating a macro (e.g. defn- macro) to wrap each of the many ways to create a var. Hope that helps.
I tend to just define helper functions that contain code that would otherwise be shared by several functions. This is the main reason I would consider using private. If there are several helper functions, these can then be moved into a separate namespace. I test shared functions through the functions that use them, minimising the number of tests whilst still getting effective test coverage.
if i have a string ":name"
, what's the best way to turn it into the keyword :name
?
clojure.edn/read-string
or clojure.core/read-string (but the former is better from a security perspective)
Since clojure is lazy, you can map over all the simplifiers then pick out the first result not=
using some
(so you stop at the first):
(let [x '(+ 2 2)
simplifiers [identity reverse identity]]
(some #(when (not= % x) %)
(map (fn [s]
(s x)) simplifiers)))
…or roll it all up into one:
(let [x '(+ 2 2)
simplifiers [identity reverse identity]]
(some #(let [y (% x)]
(when (not= y x) y)) simplifiers))
Me, I would have simplifiers return nil if they choose not to transform, but it’s your app! 🙂ah of course, thank you
Say I have a script xx.clj which contains a main function. How can I run that main function with clj ?
clj -M xx.clj runs the whole script. I need run the main function.
clj -M -m xx
(but the script will need to be on the classpath)
although that will also load the clj file (which is the same as "running the script")
are you trying to avoid doing something else in the file?
yes. only run the main function.
I am thinking is there something similar to python’s: if name_ == ‘ main _’ : main()
do you have top level forms that "do" work? ie (println "HI")
and you are trying not to run those?
Take the case of clj -M xx.clj. I don’t want to write a (main) in the top level, which will run when the namespace is first loaded.
i'm not sure i follow. presumably a (defn -main [...] ...)
function won't be run when loaded, but the definition will be created
main is not run unless you invoke it (or use clj -M -m foo)
Yes. That’s is why I have to explicitly write a (main) in the toplevel. Mind the parens.
can I add the foo.clj to the classpath with the command line ?
you can clj -Sdeps '{:paths ["path/to/foos/dir"]}' ...
that's the directory containing foo.clj, not the path to foo.clj
Oh about this, why does cli require -M
when running main? Can't it "figure it out" automatically when doing -m?
(It's just a curiosity, not really a request or something else)
-M (now) means "run clojure.main" and we are moving towards a point where that will be the only way to run clojure.main (and -m may at some future point have some other meaning)
So can I just do cli -M foo
?
that will run foo as a script
Got it, so -M
is to tell the CLI to run the clojure.main, while -m is to tell it to run the main function in the namespace I'm indicating
yes
Ok so question — what happens when I just do cli -m namespace
? Why does it work anyway? Does it do something differently?
it does the same thing (for now), but will warn you to use -M - we just deprecated that behavior so this is a transitionary period
eventually clj -m namespace will not work
but it may be months before we make that next step
Ok fantastic, that explains everything. Thanks @alexmiller
np
i'm experimenting with using edn
instead of json
for sending data in a map from my server to the client. some of the values in my map are functions, and the edn reader in the client is throwing this error {:message "Invalid symbol: game.cards.basic/fn--16461/fn--16462.", :data {:type :reader-exception, :ex-kind :reader-error}}
. This was handled when I used json by just turning that into a string: "game.cards.basic/fn--16461/fn--16462"
which is harmless
i'm using the sente library, if that helps at all
i tried putting a {:default (fn [tag value] (str value))}
option in the edn/read-string
call, but that's not helped
there is no edn syntax for function instances
so you either need to pass a form and eval on the far side (danger will robinson) or use a symbol that can be resolved to code that's available on the far side
or there are some libs that handle function serialization
no way to just ignore it? i don't need the function on the other side, but writing a parser to selectively remove the function values feels like a lot of work
either way, thanks so much
well it's just data, you can dissoc whatever you want out of the map :)
I mean you can clean the whole tree with a clojure.walk/postwalk using a function like #(if (ifn? %) nil %)
holy crap, okay, that's pretty easy. i'll give that a whirl, thank you
beware: (ifn? :bob)
is true
right, fn? might actually be better here but use whatever discriminator is appropriate
Clojure noob here 👋
What should the contents of my project.clj
look like if I want a project structure that looks like this
my-project-dir/
project.clj
main.clj (I only want to work with this one Clojure file)
... (Other non-Clojure files)
(I'm using Leiningen)
by default lein uses a classpath root of src
. so if you require a namespace called main, it will look for src/main.clj
. that being said, its usually preferable to have some kind of disambiguating namespace. often this is your org, github username, or perhaps even some domain notion if its truly one-off code. perhaps a namespace like task.main
and have it at src/task/main.clj
So how do I change the default root?
I couldn't seem to find a project.clj reference online
https://github.com/technomancy/leiningen/blob/master/sample.project.clj#L309 by setting :source-paths
for this setup, I probably wouldn't recommend leiningen which is focused on projects. you might find https://clojure.org/guides/deps_and_cli easier
otherwise, I would really recommend adopting the standard project layout
if you're just writing scripts, try https://github.com/borkdude/babashka
Shouldn't (:import java.time.format DateTimeFormatter)
successfully pull DateTimeFormatter into the current namespace? I've seen people do (:import [java.util ArrayList HashMap])
so what am I doing wrong here? I get a ClassNotFoundException
This is inside the ns macro
(ns foo (:import [java.time.format DateTimeFormatter]))
Oh :woman-facepalming:
Syntax error (ClassNotFoundException) compiling at (main.clj:12:50).
DateTimeFormatter.RFC_1123_DATE_TIME
This is my main.clj@tahaahmedrasheedpk Try:
(.format DateTimeFormatter/RFC_1123_DATE_TIME limit)
ah
From the http://Clojure.org spec guide:
(ns my.domain (:require [clojure.spec.alpha :as s]))
(def email-regex #"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,63}$")
(s/def ::email-type (s/and string? #(re-matches email-regex %)))
(s/def ::acctid int?)
(s/def ::first-name string?)
(s/def ::last-name string?)
(s/def ::email ::email-type)
(s/def ::person (s/keys :req [::first-name ::last-name ::email]
:opt [::phone]))
Do I have to define map keys as specs to use them in s/keys
? Isn't there something like (s/keys :req [:first-name string? :last-name string? :email ::email-type])
?you have to define them as specs
Why is that :thinking_face:
one of the main philosophical ideas in spec is that attributes, not maps (concretions of attributes) should be the primary unit of specification
https://clojure.org/about/spec is probably the best written page about this and other ideas, but it's discussed in several of Rich's talks as well