This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-03-19
Channels
- # bangalore-clj (2)
- # beginners (217)
- # boot (3)
- # cider (130)
- # cljs-dev (117)
- # cljsrn (11)
- # clojure (99)
- # clojure-china (1)
- # clojure-denver (1)
- # clojure-dev (22)
- # clojure-italy (30)
- # clojure-norway (5)
- # clojure-russia (13)
- # clojure-sanfrancisco (3)
- # clojure-spec (74)
- # clojure-uk (107)
- # clojurescript (40)
- # clr (6)
- # core-async (25)
- # core-logic (4)
- # cursive (1)
- # data-science (1)
- # datomic (62)
- # duct (11)
- # editors (14)
- # figwheel (3)
- # fulcro (12)
- # funcool (1)
- # garden (12)
- # graphql (19)
- # jobs (4)
- # jobs-rus (1)
- # lein-figwheel (1)
- # leiningen (12)
- # luminus (5)
- # off-topic (45)
- # onyx (12)
- # other-languages (1)
- # parinfer (5)
- # programming-beginners (3)
- # re-frame (113)
- # reagent (63)
- # remote-jobs (10)
- # ring-swagger (1)
- # shadow-cljs (31)
- # slack-help (3)
- # spacemacs (27)
- # specter (1)
- # unrepl (44)
- # yada (16)
has anyone tried to stand up the re-frame/example/simple
application?
I seem to be running into "Figwheel Server: Resource not found". Whereas the todomvc
example works fine
nevermind... I had to go to a specific HTML file to load the app. tl;dr: RTFM
What is the correct way to pull in a new dependency using only the REPL instead of adding it to my project.clj and restarting lein repl
?
https://github.com/cemerick/pomegranate This might help?
Thanks
@mfiano You might consider switching to Boot since it supports that out of the box.
You can just say (merge-env! :dependencies '[[my-new/library "RELEASE"]])
and it will find and load the latest version of that library into your running REPL.
Interesting. I tried boot but I didn't really understand how to use it
To be honest, I'm using Emacs/CIDER integration
Happy to help you with that -- we switched from Leiningen to Boot at work two years ago and we've been really happy. You can use Emacs/CIDER with Boot just fine.
What changes do I have to make? I actually have boot
in my $PATH already
It'll depend on what's in your project.clj
file but you basically just convert it to build.boot
and that's it.
How does CIDER know to use lein or boot when I type ,'
to start a REPL?
(set-env! :dependencies '[[...]])
is probably all you'll need if you're working with a simple project.clj
. CIDER looks for both project.clj
and build.boot
So if it sees project.clj
, it'll use lein
. If it doesn't, but it sees build.boot
, it'll use boot
.
Ok so lein has precedence.
Yeah, I believe so. I haven't used CIDER for years tho'.
In Atom/ProtoREPL, you can configure which has precedence. You probably can in CIDER too.
I just read "brave and true" and "joy of" this week, and this is actually the very first bit of programming I'm doing, so I really don't know what is preferred to use. The lein vs boot thing was very confusing to me about which to use, but I'd like to get a nice setup going if boot is what is preferred
very first bit of Clojure programming that is...I am an old Common Lisp user 🙂
Leiningen has been around longer but I think Boot is a better build tool these days.
One thing I didn't like about lein was the chore it is to make a custom template.
I wrote a bunch of blog posts about our move from lein to boot in 2016 http://seancorfield.github.io/blog/archives/
Boot relies on the same template machinery so you won't find it any easier, sorry. Boot new can run all of the Leiningen templates, as well as any new Boot templates, but the machinery is pretty much the same.
I read some of your blog posts before it seems. How do I go about getting rid of (-main)
as you mentioned is possible?
Not sure what you mean. We have -main
, we just don't use AOT.
Oh I was just referring to this sentence which might have been read a bit out of context: There’s no need to create a -main function – the Boot tasks can call directly into our code.
Oh, right. Yeah, for a lot of "task-based" stuff we just write a deftask
in build.boot
that does a require
of the namespace in our code and then resolve
the function we want to call, and then calls it.
Ok, so if I were to switch to Boot, I am not sure how to translate the :main
and :profiles
lines that lein generated for me. I'm still very new and don't even know what they do, but I assume :main
is setting the starting package for CIDER to automatically switch to when it starts a REPL.
For example
(deftask sql-migration
"Run SQL migrations to bring database up to desired level."
[]
(comp (migration-context)
(with-pass-thru fs
(require '[worldsingles.data.migration :as dm])
((resolve 'dm/sql-migration)))))
:main
specifies the namespace that contains -main
for when you run your program. I didn't know CIDER paid any attention to that.
:profiles
generally would become tasks in your build.boot
file that create the environment that the profiles contain.
How complex is your project.clj
file?
I literally just started. It looks like:
clojure
(defproject mfiano/crawler "0.1.0-SNAPSHOT"
:description "TODO"
:url "TODO"
:license {:name "MIT"
:url ""}
:dependencies [[org.clojure/clojure "1.8.0"]
[clojure.java-time "0.3.1"]]
:main ^:skip-aot mfiano.crawler.core
:profiles {:uberjar {:aot :all}})
OK, so your :profiles
doesn't do much.
Tell you what, in a separate folder, run boot -d boot/new new -t app -n mfiano/crawler
and look at the build.boot
file it creates.
Ok looking at it.
You should just be able to copy that into your current project, then edit the :dependencies
line to specify Clojure 1.8.0 (instead of the latest RELEASE) and add [clojure.java-time "0.3.1"]
and you'll be all set.
I'll try that...
boot build
will create the uberjar for you, boot run
will run the program. If you rename your project.clj
file, CIDER jack-in should "just work".
It seems to take less time to start a REPL anyway
Oh, just noticed, it'll assume your main namespace is mfiano.crawler
-- you'll need to update that to mfiano.crawler.core
Yes, Boot only runs one JVM. Lein runs two.
One sec...let me edit my deps and see if this works
(and the downside of that is it uses whichever version of Clojure is specified in ~/.boot/boot.properties
by default, not what's in build.boot
)
(which is a bit confusing)
Oh let me see what I have
Ah same ok
Ah, boot doesn't have the package magic
"package magic"?
CIDER starts a REPL in the boot.user
ns, whereas with lein it started in the mfiano.crawler.core
ns
Ah, ok. I never worry about that since I never type into the REPL anyway.
Sorry, namespace, not package. CL terminology habits
I just eval forms from the editor -- and that switches the REPL to the right ns anyway.
I eval'd a form and it stays in boot.user
Hmm, ProtoREPL switches the REPL to the ns of the file you're eval'ing forms from -- I assumed CIDER would do the same.
I think CIDER paid attention to the :main
section to autostart in a ns
Clearly, yes.
I'm sure there's a CIDER hot key to switch ns
Oh there is
But, is there an equivalent boot thing like :main
. Maybe it'll do the same thing?
Don't know. You'd have to read the CIDER docs for that.
Oh, ok. I was asking what the build.boot equivalent of project.clj's :main
section would be.
Hmm, I bet lein repl
switches to the :main
ns? So maybe you could do it via the Boot repl
task. Let me check.
Oh let me see
Well, you can use boot repl -n my.ns
but that doesn't help you with CIDER.
Yeah lein repl
starts me in my own ns too
OK, so maybe it's not CIDER behavior causing that.
Nope appears not. I'll read the boot docs. Thanks for all your help.
Edit your build.boot
and add this
(ns-unmap *ns* 'repl)
(deftask repl
[]
(boot.task.built-in/repl :init-ns 'mfiano.crawler.core))
(took me a while to make it work!)
Right, but CIDER is not going to call that task I don't think?
Yeah, it should. That's how it starts a REPL.
Oh, nice. I'll try that
It may try to pass some options tho'... not sure... so that may need to be updated with those too...
It probably uses -s
to start a server... let me check the docs...
That errors when I call cider-jack-in
Yeah, pretty sure it needs the -s
option. Try this:
(ns-unmap *ns* 'repl)
(deftask repl
[s server bool "Start REPL server only"]
(boot.task.built-in/repl :init-ns 'mfiano.crawler :server server))
If CIDER passes extra options, those would need to be added too. Oh wait, I'm being an idiot here! It would be simpler just to set a default task option for repl! Hang on...
errors
Yeah, that was all way too complex! Sorry. in the task-options!
call, just add this:
repl {:init-ns 'mfiano.crawler.core}
(I added it just above the jar
defaults).(and remove that ns-unmap
call and the deftask repl
)
Great it works!
So that (`task-options!` for repl
) is the Boot equivalent of lein repl
reusing the :main
setting.
(but in Boot, the initial REPL namespace and the AOT main ns are configured separately)
Sorry for the wild goose chase there!
That's ok. I appreciate this, thanks. This is going to save me a lot of time, as I develop on a really modern machine and on an under-powered netbook on the go, and this decrease in startup time due to 1 JVM instance is going to be very nice.
I have to wait about a minute for lein on my netbook...it's been horrible.
@seancorfield I do get some warnings on the command line with boot.
A few of the following. Are these harmless? Classpath conflict: org.clojure/clojure version 1.8.0 already loaded, NOT loading version 1.10.0-alpha4
Sorry, I was off feeding the cats. That warning says that the version Boot originally loaded was 1.8.0 (from your ~/.boot/boot.properties
file I expect) but something in you build.boot
is trying to load 1.10.0-alpha4 (probably as "RELEASE"
).
So it's harmless but important if you actually want to be using a version other than 1.8.0 @mfiano
I generally work with the latest release of Clojure myself. I have
BOOT_CLOJURE_VERSION=1.10.0-alpha4
in my boot.properties
file.Thanks
(and then I just specify "RELEASE"
in most of the build.boot
files for org.clojure/clojure
)
If you want Boot to use a specific version, you can set the environment variable for the the command:
BOOT_CLOJURE_VERSION=1.9.0 boot repl
if you wanted 1.9.0 (and you're on Mac or Linux -- no idea how to specify an env var for a single command in Windows)@seancorfield Thank you. Is it possible to sync the build file and properties to use the same Clojure version?
@mfiano Good question... Let me try something...
So, yes, since build.boot
is "just" Clojure code, you can use (clojure-version)
to get the current Clojure version as a string in the Build file. You just need to be a bit more careful about what is quoted in the expression
(set-env! :resource-paths #{"resources" "src"}
:source-paths #{"test"}
:dependencies [['org.clojure/clojure (clojure-version)]
['adzerk/boot-test "RELEASE" :scope "test"]])
That makes sense
I moved the '
from outside the vector-of-vectors to the inside, quoting just the symbols that I don't want evaluated.
could probably just backtick it and use ~@ for the version?
I might not have that reader macro correct for unquote...haven't actually done that in this lisp yet 🙂
We actually build our dependency vectors dynamically at work. Our build.boot
reads a version.properties
file to get the "pinned" versions of libraries we use and then we process all the dependency vectors to replace what's in the build.boot
file with the actual versions we want to use.
I wouldn't use backtick or ~
here -- that's overkill. You just want to quote the symbol names to prevent evaluation.
I mean instead of adding a quote on the first element of every dependency's vector, couldn't you just quote the whole outer vector and unquote the one expression you need to eval?
If you still wanted to quote everything except the Clojure part you could do
(conj '[[adzerk/boot-test "RELEASE" :scope "test"]
[other deps ... ]]
['org.clojure/clojure (clojure-version)])
Since it's "just code".
> I mean instead of adding a quote on the first element of every dependency's vector, couldn't you just quote the whole outer vector and unquote the one expression you need to eval? (edited) Ah, gotcha. Yes, you could have
`[[org.clojure/clojure ~(clojure-version)]
[adzerk/boot-test "RELEASE" :scope "test"]]
Oh I just saw you typed the same thing.
Thanks 🙂
I think we'll see a shift toward using deps.edn
and clj
in the near future.
And either standalone uberjar build tools or add-ons for Lein/Boot (I maintain boot-tools-deps
for that purpose).
I am liking boot better so far though
I've already converted the Contrib projects I maintain from using Leiningen (as a dev/test convenience) to just using clj
and Cognitect's test-runner
.
For example https://github.com/clojure/java.jdbc/blob/master/deps.edn and https://github.com/clojure/core.cache/blob/master/deps.edn
Running tests is as simple as clj -A:test:runner:1.8
or clj -A:test:runner:master
to test against Clojure 1.8.0 or against master-SNAPSHOT
How does conj without an input collection work in a transducer here :
(transduce (comp (map inc)) conj (range 5)) ; [1 2 3 4 5]
@xtreak29 (conj)
=> []
Hi, I m super new to clojurescript and having trouble using semantic ui components in reagent hiccup syntax I m able to use semantic ui components where html tags are expected by using 😆 But when I try to pass a semantic component to another semantic component as props (in code it is :trigger props), I m getting undefined error in console. I have spent like hours in this problem, but not able to find solution. thanks for the help.
What semantic lib are you using? I've only used soda-ash, which uses react semantic ui, but in cases where a semantic component expects another component you'd have to pass the raw js function, and not an adapted reagent component
something like this:
(:require [reagent.interop :refer [$]])
...
[:> modal {:trigger ($ js/semanticUIReact :Button)}
and how can I pass props to :Button component, like callback etc.
haven't heard about soda-ash before, I will give it a try
ah, I'm not sure. Maybe its possible to reactify a regular reagent component to pass props. Or some simpler approach. I haven't actually had to pass props to such a component before
Soda-ash is a nice wrapper. I've seen several people asking questions about semantic in #reagent , maybe worth asking there too
Sure I will use that channel, It is my first time with slack and clojure community. So it will take some getting used to But my first interaction with clojure community is awesome You people are super helpful Thanks buddy
@umardaraz4747 also see https://github.com/reagent-project/reagent/blob/master/docs/InteropWithReact.md
I’d definitely say you’ll get good answers for reagent sorts of questions like this in the #reagent channel too
@umardaraz4747 Seems there is an example on the soda-ash readme that does what you're trying to do
[sa/Modal {:trigger (reagent/as-element [sa/Button "Show Modal"])}]
I'm sure the same approach would work outside soda-ash too@roosta I tried the solution and it worked like a charm 🙂
Can someone tell me what's wrong with my usage of tree-seq?
(defn get-children-seq
[node]
(tree-seq
(fn has-children? [n] (pos-int? (count (:children n))))
(:children node)
node))
(get-children-seq
{:something "A"
:children [{
:something "B"
:children []}]})
IllegalArgumentException Key must be integer clojure.lang.APersistentVector.invoke (APersistentVector.java:294)
@jonjanisch the second arg to tree-seq
has to be a function. (try just :children
)
the docstring does say it's a function though:
=> (doc tree-seq)
-------------------------
clojure.core/tree-seq
([branch? children root])
Returns a lazy sequence of the nodes in a tree, via a depth-first walk.
branch? must be a fn of one arg that returns true if passed a node
that can have children (but may not). children must be a fn of one
arg that returns a sequence of the children. Will only be called on
nodes for which branch? returns true. Root is the root node of the
tree.
nil
yeah, it's my fault. I was looking at an example on stackoverflow and didn't notice the second arg was an anonymous function (using #)
should have looked at the docstring. The error message had me scratching my head a bit 🙂
as for the error, it sure is rather obtuse; though for future reference, you get that error when calling a vector as a function with a non-integer argument
"predicate" is just a name for a function that returns a boolean (true or false) result
or in many cases non-nil (for "true") or nil (for "false")
so you can just define your own predicate that returns a true/false (non-nil/nil) result
@manutter51 If a function ends in ?
, it's considered more idiomatic for it to specifically return either true
or false
/cc @saurabhkukade
Lots of functions can be used as predicates without being purely Boolean-returning tho'.
@seancorfield That's right, I remember that now that you mention it. Thanks!
how to get everything with function get-in
. usually it gets some part of what is required, but I want to get everything with this function
can you give an example of what you have and would like to extract @poiga? get-in
pulls data from one path down a datastructure
or doesn't change the input, you can use merge to replicate what or does though
(merge {:carved false :features [] :distance -1} cell)
- bind that in a let block shadowing the value of cell
Thanks!
you can also move the keys destructure into the let block to have that part work correctly (after the merge)
putting the keys destructure on the same line as the merge is valid, but just adds noise - it doesn't make faster code or anything
Makes sense. Thanks
I have
(defmacro domain
[name & body]
`{:attrs {:name (str '~name)}})
, which allows me to do (domain foo)
to get {:attrs {:name "foo"}}
. How should I write the macro such that when i do (domain (str 11))
, I get {:attrs {:name "11"}}
instead of {:attrs {:name "(str 11)"}}
? Or is there no way to do that without a conditional in the macro?@ackerleytng in one case you're passing a symbol, and wanting it to be coerced to a string. in the other you're passing a list, and wanting it to be evaluated. how do you envision this happening without a conditional?
haha i see
i thought if the macro could be written such that evaluation is done before the macro is applied, sort of like functions
if i had (defn foo [bar] (+ bar 1))
, and i called it with (foo (+ 2 3))
clojure will actually do (foo 5)
, right?
macros are run and expanded at compile time, so the only thing they have available to them is the unevaluated data you pass to it. to have something be evaluated, you have to return it from the macro
but i can manipulate the data passed in to the macro?
like
(defmacro domain
[name & body]
`{:attrs {:name (str (first ~name))}})
(domain [1 2])
oh but
(macroexpand-1 '(domain [1 2]))
; {:attrs {:name (clojure.core/str (clojure.core/first [1 2]))}}
yeah, correct. but consider the following:
(def x 2)
(foo x)
if foo
is a function, x
will be evaluated and foo
will be passed 2
. however if foo
is a macro, foo
will simply be passed the raw symbol x
i see
does this mean that the process of macroexpansion only "pastes" [1 2]
where ~name
was?
creating data from a literal like a
, [1 2]
, or {:a 2}
also happens at compile time, which is why macros can 'see' them
boot.user=> {(inc 1) 2 (inc 1) 2}
boot.user=> java.lang.IllegalArgumentException: Duplicate key: (inc 1)
clojure.lang.LispReader$ReaderException: java.lang.IllegalArgumentException: Duplicate key: (inc 1)
@mfikes thanks, how would i do that?
@ackerleytng You can execute any code you'd like in order to produce the form you want to return. Here is one that involves calling eval
:
(defmacro domain
[name & body]
(let [x (str (eval name))]
`{:attrs {:name ~x}}))
this doesn't seem right, because if x
were evaluated at compile time, macroexpand
would have thrown that error already?
so since it's only thrown when (foo a)
is run, then x
is sort of just pasted in, but the result, a
, is evaluated at runtime. did I get it right?
look at the let
. it's evaluated (it's already 2
after expansion). the same applies to the x
. it's just that it's evaluated to the plain symbol a
, since that's what x
is
and then at runtime (after expansion):
boot.user=> (eval `~y)
java.lang.RuntimeException: Unable to resolve symbol: x in this context
clojure.lang.Compiler$CompilerException: java.lang.RuntimeException: Unable to resolve symbol: x in this context, compiling:(null:1:1)
boot.user=> (defmacro foo [x] (prn (type x)))
#'boot.user/foo
boot.user=> (foo a)
clojure.lang.Symbol
nil
i see
so where does the evaluation stop?
i mean, usually a symbol will be evaluated to find the value
but in a macro that doesn't happen?
as in, in the let, it expands x until it gets 2
ah...
i see
ok thanks so much @U61HA86AG
i will think about it again after work
thanks!
you might find this helps: https://aphyr.com/posts/305-clojure-from-the-ground-up-macros
boot.user=> (defmacro foo [x] `[~x ~(let [x 2] x)])
#'boot.user/foo
boot.user=> (macroexpand '(foo a))
[a 2]
boot.user=> (foo a)
java.lang.RuntimeException: Unable to resolve symbol: a in this context
clojure.lang.Compiler$CompilerException: java.lang.RuntimeException: Unable to resolve symbol: a in this context, compiling:(null:1:1)
It is a fairly common pattern to do some processing on the forms passed prior to generating the form to pass back to the compiler.
this doesn't seem right, because if x
were evaluated at compile time, macroexpand
would have thrown that error already?
so since it's only thrown when (foo a)
is run, then x
is sort of just pasted in, but the result, a
, is evaluated at runtime. did I get it right?