This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-08-30
Channels
- # adventofcode (4)
- # aleph (1)
- # announcements (6)
- # babashka (11)
- # beginners (63)
- # calva (73)
- # clj-kondo (9)
- # clj-on-windows (20)
- # cljdoc (8)
- # cljsrn (4)
- # clojure (48)
- # clojure-europe (20)
- # clojure-italy (1)
- # clojure-nl (11)
- # clojure-spec (11)
- # clojure-uk (3)
- # clojurescript (32)
- # cloverage (1)
- # conjure (1)
- # cryogen (5)
- # datomic (83)
- # fulcro (28)
- # graphql (23)
- # gratitude (4)
- # helix (15)
- # honeysql (4)
- # improve-getting-started (14)
- # introduce-yourself (3)
- # jackdaw (5)
- # kaocha (11)
- # leiningen (1)
- # malli (1)
- # meander (5)
- # off-topic (18)
- # pathom (17)
- # pedestal (6)
- # polylith (15)
- # practicalli (1)
- # quil (2)
- # reitit (4)
- # releases (6)
- # shadow-cljs (38)
- # sql (20)
- # testing (6)
- # timbre (5)
- # tools-deps (11)
- # vim (2)
Hello, I am trying to pass data that is of a list (or a seq?) format kinda.
(let [info (if is-correct?
{:Name "Wags", :age 55, :working true}
{:Name names, :age ages :working (case ages -1 true -2 false)})]
(println "info" info))
The values of names
and ages
is (Mafee)
and (-1)
respectivelyWhat's going on?
Your case statement has no matching clause. You have a clause for -1 and for -2. It got some lazy sequence as a value not those two numbers you handle
How to use lazy seq then?
with case
Then, if we are using lazy seq then what's the alternative to using case?
(-1 -2)
or reverse
but many of them but again only -1 and -2
Have to convert it to vector?
no conversion is needed:
user=> (let [v (list 1 2 3)] (case v [1 2 3] :OK))
:OK
i don't know how to help with your particular problem needs here. But i'm just helping you understand the illegal argument exception. It said there was no matching clause. you provided two clauses, one for -1 and one for -2. Giving it a sequence of values cannot work
this vec
call isn't needed, case
already considers (list 1 2)
and [1 2]
to be a match
Maybe you just need to grab the first item in the list, i.e.
(let [info (if false
{:Name "Wags", :age 55, :working true}
{:Name (first names), :age (first ages) :working (case (first ages) -1 true -2 false)})]
(println "info" info))
;=> info {:Name Mafee, :age -1, :working true}
Hi, I'm trying pedestal and I wonder if there is a way to reload routes (for example after changing an interceptors) without restarting the server every time?
Hi all, I'm trying doall
and don't know why the true condition, in this case, isn't working at all.
(doall (map (fn [age working exit]
(let [info (if present
{:name "Wags", :age 50, :working true, :exit nil}
(if-not (nil? working)
{:Name "Mafee", :is-left (cond (= exit -1) true (= exit -2) false)
:working working, :age age}
{:name "Wags", :age 50, :working true, :exit nil}))]
(println "info" info)
)) age working exit))
(def present false)
(doall (map (fn [[age working exit]]
(let [info (if present
"present"
(if-not (nil? working)
"not present working nil"
"present and working"))]
(println "info" info)))
[[10 nil -1]]))
(def present true)
(doall (map (fn [age working exit]
(let [info (if present
"present"
(if-not (nil? working)
"not present working nil"
"present and working"))]
(println "info" info)))
[10 21] [nil nil] [-1 -2]))
your function fn [age working exit]
expects to get 3 collection passed(defn process-f [age working exit]
(let [info (if present
{:name "Wags", :age 50, :working true, :exit nil}
(if-not (nil? working)
{:Name "Mafee", :is-left (cond (= exit -1) true (= exit -2) false)
:working working, :age age}
{:name "Wags", :age 50, :working true, :exit nil}))]
(println "info" info)))
(doall (map process-f age working exit))
I rewrite slightly the code snippet to highlight that it is not the function expecting three collection to be passed but map
function. process-f
is still expects three arguments (not collections!)Only the when present
is false
it returns as per the false condition but when the present
is true
, it doesn't return anything
Hello! I'm working with a small cli tool and attempting to support sub-subcommands in the form of:
rbt cluster query -q "/_cat/indices" -n mycluster
So far this is what I've come up with "borrowing" from various sources:
(ns rbt.main
(:gen-class)
(:require
[clojure.tools.cli :refer [parse-opts]]
[rbt.cmd.cluster :as cluster]))
(def cli-opts [["-h", "--help", "Display help"]])
(defn -main
[& args]
(let [opts (parse-opts args cli-opts :in-order true)
config (:config (:options opts))
subcmd (first (:arguments opts))
subcmd-args (rest (:arguments opts))]
(cond
(:help (:options opts)) (prn "You do need help.")
(= "cluster" subcmd) (cluster/parse subcmd-args)
(= "help" subcmd) (prn "You need some help?")
:else (prn "No idea.")))
(shutdown-agents))
(ns rbt.cmd.cluster
(:require
[clojure.tools.cli :refer [parse-opts]]
[rbt.cluster.query :as query]))
(def cli-opts
[["-q", "--query ENDPOINT", "Endpoint to query"]
["-n", "--name CLUSTER", "Name of cluster to query"]
["-h", "--help", "Display help"]])
(def usage
"Use -q query and -n name to define the query and name parameters
Usage: rbt cluster query -q \"/_cat/indices\" -n k8s-prod-zone-1")
(defn parse
"Access cluster subcommand"
[& args]
(let [opts (parse-opts args cli-opts :in-order true)
config (:config (:options opts))
subcmd (first (:arguments opts))
subcmd-args (rest (:arguments opts))]
(cond
(:help (:options opts)) (println usage)
(= "help" subcmd) (println usage)
(= "query" subcmd) (query/parse subcmd-args)
:else (println usage))))
The error I am attempting to resolve is:
Exception in thread "main" java.lang.ClassCastException: class clojure.lang.PersistentVector$ChunkedSeq cannot be cast to class java.lang.CharSequence (clojure.lang.PersistentVector$ChunkedSeq is in unnamed module of loader 'app'; java.lang.CharSequence is in module java.base of loader 'bootstrap')
at clojure.core$re_matcher.invokeStatic(core.clj:4838)
at clojure.core$re_seq.invokeStatic(core.clj:4863)
at clojure.core$re_seq.invoke(core.clj:4863)
at clojure.tools.cli$tokenize_args.invokeStatic(cli.cljc:34)
at clojure.tools.cli$tokenize_args.doInvoke(cli.cljc:15)
at clojure.lang.RestFn.invoke(RestFn.java:464)
at clojure.tools.cli$parse_opts.invokeStatic(cli.cljc:755)
at clojure.tools.cli$parse_opts.doInvoke(cli.cljc:564)
at clojure.lang.RestFn.invoke(RestFn.java:464)
at rbt.cmd.cluster$parse.invokeStatic(cluster.clj:17)
at rbt.cmd.cluster$parse.doInvoke(cluster.clj:14)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at rbt.main$_main.invokeStatic(main.clj:17)
at rbt.main$_main.doInvoke(main.clj:9)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at rbt.main.main(Unknown Source)
This is using borkdude/sci so that I can compile it down to a single executable/startup time speed. From what I can tell in the exception is possibly the second invocation of parse-opts is failing to find any arguments?what does (rest (:arguments opts))
look like in your rbt.main/-main
function? i.e., the value of subcmd-args
java -jar rbt.jar cluster query -q "/_cat/indices" -n k8s-prod-zone-1
("query" "-q" "/_cat/indices" "-n" "k8s-prod-zone-1")
cool; when you pass that collection to your parse
function, the [& args]
signature of that function means that it expects a variable number of arguments, and so args
is itself a collection, so you're passing [["query" "-q" ,,,]]
to the underlying parse-opts
function
ah I see
So apply will take it out of that collection then and I can still use [& args]
is that typically more flexible?
if you control all the functions, I find using varargs as little as possible to be the least surprising, since it's collections in, collections out, without any auto-wrapping like you have with varargs
Afternoon all. As I started writing Clojure for the first time yesterday I think I qualify as a beginner and this is very much a beginner task. Using Emacs, Cider, and Leiningen on Windows 10, I'm extracting text for processing from a one-page purchase order in PDF format. I can achieve this with pdfboxing
by putting this in the ns form of my core.clj, like so:
(:require [pdfboxing.text :as text])
I can also put that require statement in the body of core.clj rather than in the ns form, but I'm still fuzzy on the difference between the two. Then I can use it like this:
(def jtext (text/extract "./test.pdf"))
...which just works, and leaves me with a string representing all the text on the page, with "\r\n" delimiting the various fields. These fields do not always appear in the same order, but because it is mostly boilerplate I can use a regex.
If I want to extract the purchasing manager's name (which could be one of several different people), I know that this comes after the name of the company issuing the order and before a brief description of the order, and this description itself comes before the name of the company receiving the order. Something like this:
BigCompany Inc.\r\nJane Smith\r\nStainless steel materials\r\nSmallCompany Ltd.
So I have a field with a known structure, two fields of variable text (the manager's name and the order description), followed by another field with known structure. Though I'm still not familiar with Clojure/Java's flavour of regex it appears that I can apply a regex with groups like this:
(def manager-text (re-find #"BigCompany Inc.\r\n(.+)\r\n(.+)\r\nSmallCompany Ltd" jtext))
...and I can then take the element of the vector containing the name:
(def manager (manager-text 1))
This seems to work, but feels a bit clunky and fragile. Is there a more idiomatic way to approach this in Clojure (destructuring...?), or is this just one of those times where something crude is good enough and I should just move on?
Dan
I feel like I would reach for either instaparse or clojure.spec for this sort of thing. I'm afraid I'm on my phone and away from a REPL at the moment. But have a look at both of those libraries and see if you think they'll help.
@U02CVCL55N0 I've actually raised a PR https://github.com/dotemacs/pdfboxing/pull/62 that allows you to selectively extract parts of the page by specifying sets of coordinates. It hasn't been merged yet but you might want to give it a try. I've been using it for quite some time in another project of mine. No problems so far π
The style guide recommends vertically aligning function arguments with the second argument whenever there is one on the same line as the function:
https://guide.clojure.style/#one-space-indent
I find this recommendation a little awkward for functions that have a "generic" first argument like app
or this
.
Recommended:
(comp/transact! this
[(save-thing {:foo :bar})])
My preferred:
(comp/transact! this
[(save-thing {:foo :bar})])
A third alternative:
(comp/transact!
this
[(save-thing {:foo :bar})])
How important is it to stick to the recommended style?heh, maybe I'm a bit shook over style violations after reading some comments on the orange website about how Clojure newbies often produce the ugliest codebases.
If you use cider, then the "correct" way to do this is to tag your comp/transact! with a {:style/indent 1}
metadata, which will produce indentation like this:
(comp/transact! this
[(save-thing {:foo :bar}])
make ugly code. as you code more you will develop your own sense of style and how important it is. feel free to evolve and make your own style choices as you go
^ this The only caveat I have to this is that I usually try to not fight my auto indenter, which is cider, so I've learned cider's indent metadata syntax and include it even in libraries I release so that my indentation can be consistent across not just my code, but anyone who uses cider, and it'll be better than the default for my usecases.
As an example, I wrote a macro restart-case
which indents like this:
(restart-case
(some code)
(::a-restart [some args]
(some code)))
If I used "default" indentation, then it would have indented like this:
(restart-case
(some code)
(::a-restart [some args]
(some code)))
I think this is much less readable, which is why I put the effort into making this better.I haven't looked at adding manual configs for Cider at all. Good tips, I'll explore the options there.
With code organization and defining namespaces, is it acceptable to have a file and directory named the same but can still pull out the functionality from each? For example, I wanted to break down my subcommands under rbt.cmd.cluster.query
which would be src/cmd/cluster/query.clj
but I also wanted to have some syntatic sugar in rbt.cmd.cluster
which would be src/cmd/cluster.clj
. If I organize code like this is that acceptable?
Yes @adam.stokes not uncommon
Great! Thank you, will keep the cyclic deps in mind, I've hit that a few times with similar naming schemes in python as well
@adam.stokes another thing to keep in mind is that there's no hierarchical relationship between nested directories / namespace fragments, beyond what gets imposed by convention / idiom. there's no reason that foo.bar.baz can't require foo.bar for example (ie. putting protocol / multimethod definitions in foo.bar and putting an implementation in foo.bar.baz...)
Gotcha, that makes a lot of sense. I think that is also the difference with how Python does it, there seems to be a direct relation with the directory itself for resolving the namespaces for module imports