Fork me on GitHub
#beginners
<
2019-06-19
>
johnjelinek01:06:07

I have some weird shenanigans going on. I have a log message that indicates an error:

{:dal.secretsmanager/secret-id
"dev/kashoo_bearer_token",
:dal.secretsmanager/token "51680555-f0c4-43ef-a5db-c5c75e7e5cdf",
:clj.core/step "createSecret"}

Assert failed: (s/valid? :dal.secretsmanager/secret-id secret-id): java.lang.AssertionError
java.lang.AssertionError: Assert failed: (s/valid? :dal.secretsmanager/secret-id secret-id)
at dal.secretsmanager$read_secret_metadata.invokeStatic(secretsmanager.clj:43)
at dal.secretsmanager$read_secret_metadata.invoke(secretsmanager.clj:43)
at clj.core$secret_already_created_QMARK_.invokeStatic(core.clj:33)
at clj.core$secret_already_created_QMARK_.invoke(core.clj:30)
at clj.core$route_event.invokeStatic(core.clj:86)
at clj.core$route_event.invoke(core.clj:79)
at clj.core$_handleRequest.invokeStatic(core.clj:110)
at clj.core$_handleRequest.invoke(core.clj:104)
at clj.core.handleRequest(Unknown Source)
however, I take that same input and call it in my repl and no error:
(let [{::secretsmanager/keys [secret-id token]} event
      {:keys [step]} event]
  (do (pprint event))
  (secret-already-created? secret-id token)) ; =>

{:dal.secretsmanager/secret-id
 "dev/kashoo_bearer_token",
 :dal.secretsmanager/token "51680555-f0c4-43ef-a5db-c5c75e7e5cdf",
 :clj.core/step "createSecret"}

true

johnjelinek01:06:59

why would that map be valid in the repl and not in the environment where it runs?

andy.fingerhut01:06:39

Do you perhaps have assertions disabled in your REPL somehow?

johnjelinek01:06:56

no, but I did just put a pprint in and I see that somehow the first param being passed to secret-alreadycreated? is nil

johnjelinek01:06:18

I'm not sure how it's becoming nil yet

johnjelinek01:06:29

(let [{:secretsmananger/keys [secret-id token]} event
            {::keys [step]} event]
...)
is there some way that this mapping is wrong and resulting in a nil?

johnjelinek01:06:59

for context, an event is generated by this:

(defn- marshal-event [event]
  (let [{id :secret-id
         token :client-request-token
         step :step} event]
    {::secretsmanager/secret-id id
     ::secretsmanager/token token
     ::step step}))

johnjelinek01:06:19

I think I found it: s|:secretsmananger/keys |::secretsmanager/keys|

Daouda01:06:37

Hey folks, can you explain difference between what agent, atom, ref is and an example of use case?

Daouda02:06:36

yeah, but I’m still confused 😞

hiredman02:06:35

There are kind of two ways to talk about agents, one is by comparing them to clojures other reference types, the other is by comparing and contrasting them with actors, which you may be familiar with from other languages

hiredman02:06:54

The reference type stuff is really good because you get in to how clojure models identity, and there is a great rich talk about it, and the agent stuff is just kind of an addendum to that (which is fine because agents aren't really used much anyway)

hiredman02:06:54

An agent is a reference type, sort of like a pointer. You can deref it to get it's value, and it's value can change. Clojure has a number of reference types that have different rules that govern how their values change over time

hiredman03:06:50

Agents are asynchronously (changes are queued up and happen later) and atomically (one change at a time is executed, and only complete changes are visible) updated

andy.fingerhut02:06:13

If you want to transfer money from one account to another without it getting lost or double-counted temporarily, you either need (a) to put the state of each account into its own ref, and use a ref transaction to do the money transfer, or (b) put the state of both accounts (and perhaps many more) into one place, like an atom or agent, and update the information about both accounts in the same update operation.

andy.fingerhut02:06:08

That maybe helps illustrate the difference between the ability of refs to perform coordinated updates across more than one ref, whereas that is not possible across multiple agent or atom instances.

chepprey03:06:39

In Clojure, what's the right word for what I used to all "objects" in Java? Like, think of collections of homogeneous, composite values. "Customers" "Books" "Movie listings" ---- things like this. What do we call these?

seancorfield04:06:43

Composite values in Clojure are hash maps. We have collections of those.

seancorfield04:06:57

@chepprey There is only "data" in Clojure really.

seancorfield04:06:32

Perhaps the closest thing to a "common name" is https://clojure.org/guides/spec#_entity_maps ...

Crispin04:06:38

maybe a "record" is somewhat like a (immutable) java object. (defrecord ...)

Crispin04:06:20

I just use hashmaps. But records are there I think for speed.

chepprey04:06:29

I'm just using hashmaps too, I'm not doing anything idunno substantial, not yet. Just a tinkering noob with a pet project. I wanted to ask a completely different question, and then worried that I didn't have the right word to use for what I keep thinking of as "object".

seancorfield04:06:30

Prefer hash maps to records.

chepprey04:06:26

Let me ask the question, with bad terminology, then maybe you can see what I mean...

chepprey04:06:43

So I got this vector of objects. Each object has a timestamp. I want to transform this vector into some other datastructure such that I can group the objects up by calendar date.

seancorfield04:06:55

A vector of hash maps?

chepprey04:06:12

fwiw the point of transforming the data in the vector is to create hiccup for rendering html representation of this data.

chepprey04:06:31

The raw data is indeed a vector of hashmaps

seancorfield04:06:42

Then just call them maps or hash maps.

Crispin04:06:36

Id phrase it "I have a vector of hashmaps. Each hashmap has a key :timestamp with a timestamp as a value"

seancorfield04:06:44

"So I got this vector of maps. Each map has a timestamp. I want to transform this vector into some other datastructure such that I can group the maps up by calendar date." 🙂

chepprey04:06:07

just like that huh? ok. 😄

Crispin04:06:27

and you want group-by 🙂

chepprey04:06:53

[[ races to clojuredocs tab, ctrl-s... ]]

Crispin04:06:42

pass in a function that takes one of these hashmaps, and returns a key to group under. You would make your own little func that returns some value representation of your 'interval'

chepprey04:06:46

omg group-by that's cheating

andy.fingerhut04:06:32

You can re-implement group-by yourself if it helps you feel less like cheating 🙂 Or, just move on to the next part of the task you started with, smoothly and efficiently.

chepprey04:06:20

well it'd be a good thing for me to at least peruse the sourcecode to see if I had a chance at hacking it out myself

andy.fingerhut04:06:17

When first reading its source, you may want to ignore the call to persistent!, replace (transient {}) with {}, and replace assoc! with assoc. If you understand it with those changes, then go back to the original, which has those things in there for lower CPU time cost for calculating the result.

Crispin04:06:49

you could think about it as a reduce over that vector. You have a whole bunch of things to go in (the collection of items), and one composite 'thing' to come out (the hashmap representing the final grouping). Good indicator it could be done with reduce. There will be multiple ways to do it of course...

chepprey04:06:49

I swear sometimes i think i need some kind of medication to help me with suffering "the shakes" when I can't just solve every problem with building mutating for-loops

andy.fingerhut04:06:53

It is a mental shift, to be sure, that even experienced Clojure developers experience sometimes, especially if they switch between programming languages often enough.

chepprey04:06:59

Interesting. Ya, I've been studying reduce, reduce-kv lately, seemed like these were in the neighborhood of what i needed

chepprey04:06:12

... but didn't quite fit. Then I figured I'd go recursive, loop-recur... while having a guilty feeling like "if you're using loop-recur you can probably find a more functional way to do it"

Crispin04:06:32

theres nothing wrong with using loop recur. I used it a lot when beginning. And having a really firm grounding in loop/recur really helps you long term.

seancorfield04:06:20

Hmm, you need to be careful: Clojure's loop/`recur` is not like loops in most languages. I'd advise beginners to try to avoid it as much as possible. There's nearly always a better option.

Crispin04:06:10

I found not only that loop/recur really helped me bridge early on, I found it greatly improved my loopy code in other languages

chepprey04:06:13

my project impacts nobody but me so, bull-in-china-shop approach is low risk 😉 I'm a Clojure beginner but I've been slinging corporate Java for 24 years. So i dunno where i fall on the overall beginner spectrum. I think i get the uniqueness of loop recur tho (the fallback approach when you don't have TCO in the jvm)

Crispin04:06:44

i still use loop/recur all the time inside core.async in cljs. making web games.

seancorfield04:06:01

@chepprey Your biggest adjustment is going to be that you have no assignment statement (and our "objects" are all immutable) 🙂

Crispin04:06:10

I started with clj. Came from long time python. then cljs came later

Crispin04:06:22

but I have friends who started with cljs went the other way

Crispin04:06:29

whatever your path is...

seancorfield04:06:40

I started doing Java back in '97 I think (after doing C++ for years before that), so I sympathize with where you're coming from @chepprey

chepprey04:06:11

oh i ❤️ immutability. I'm a total fanboy of the RichH church of language opinion

rich 4
chepprey04:06:44

been watching the talks since clojure first came out. I created the 4clojure google group many years ago 😎 but it's only been the last couple months that I actually finally knuckled down and REALLY made something with it

Crispin04:06:25

@deleted-user I think look for a tutorial or guide that sets you up with figwheel

Crispin04:06:54

lein new figwheel myproj is a good way to start. cause its quite simple template

Crispin04:06:03

just client side

Crispin04:06:15

with all your hotloading goodness setup

Crispin04:06:45

there you can play with just cljs, without having to think about server side, clj, nrepl etc

seancorfield04:06:03

(or take a look at shadow-cljs which is getting a lot of praise too -- Eric Normand wrote glowingly about it in his latest newsletter)

chepprey04:06:11

that one is also purely client-side

Crispin04:06:49

then when you are ready add in the server side. and then when you are ready for alien spaceship features, start writing cljc

Crispin04:06:12

which is truly a transformative experience

seancorfield04:06:28

I last did cljs back in 2014/2015 when tooling was very primitive. I plan to set most of this weekend aside to revisit cljs 🙂

chepprey04:06:51

transformative - but only produces a new altered copy of you, leaving the original you unchanged.

Crispin04:06:57

figwheel is amazing.

Crispin04:06:12

cljc made me realise that its so much more than just "the same language on server and client"

Crispin04:06:23

so much more that using something like js

Crispin04:06:47

because you can intersperse in the same file, client, server, and both

chepprey04:06:25

question - i started w/ my server side first, using emacs/cider... I got used to editing code and eval'ing individual eh functions (forms?) c-x c-e...

Crispin04:06:34

so for instance, my latest project is a multiplayer online game. And I wan write 'workflows' in cljc, that start with the initial client code, then the server function to handle that network message, which then sends back to the client (the receiving client func comes next)

Crispin04:06:00

and the file reads top to bottom of the complete network protocol

chepprey04:06:05

but when i went to the cljs / shadow-cljs tutorial project, that became such that saving the file is what re-evaled everything in the file

Crispin04:06:34

yeah I use cider. and fighweel hotloading together.

chepprey04:06:58

i wondered if that is specific to shadow-cljs, maybe figwheel works more fine-grained? I've also read you CAN use figwheel and shadow together, although I don't understand what that would really mean.

Crispin04:06:20

does shadow use figwheel?

seancorfield04:06:02

I'm used to just eval'ing code from my editor directly into a running image -- I don't like save/watch/reload workflows so I hope I won't have to do that with cljs!

chepprey04:06:06

@crispin that sounds awesome. In my environment there is no figwheel. But it's a good question, what would it bring to the table w/ shadow-cljs, i'm not really sure

Crispin04:06:32

figwheel brings up compile errors on your DOM

Crispin04:06:37

hihglights the code

seancorfield04:06:44

(I thought it was either/or? You use figwheel or you use shadow-cljs?)

Crispin04:06:46

you can click on it and it drops your editor to that line

Crispin04:06:00

its mostly the hotloading functionality

Crispin04:06:22

so save file, code is compiled, passed over websocket, inserted into js runtime

chepprey04:06:29

@seancorfield 🤷 perhaps that's true. Maybe I can google around and find what I was reading that suggested both could work together...

Crispin04:06:43

huh yeah. shadow looks like figwheel.

Crispin04:06:10

filling the same spot I think. Use whichever you prefer

chepprey04:06:15

Scroll down to Yogthos' comment

Crispin04:06:27

but shadow should also work with cider repls

Crispin04:06:58

yeah. so its another hotloader. fighweel works with browser and node. and so does shadow.

chepprey04:06:24

OK so I just tried in my Emacs/cider, I have a shadow-cljs REPL, in my source file (not directly the repl) I just did a (def n 3) c-x c-e and it eval'd. Type "n" in the repl and I got 3.

Crispin04:06:31

I don't use node. I just use JVM server side.

chepprey04:06:58

I'm not sure why I thought I had to save the file. Anyhoo - eval'ing forms seems to work as expected.

Crispin04:06:20

yeah. and c-c k for full namespace re-eval (without save)

Crispin04:06:49

so in the file you have a namespace, say (ns foo.core ...)

Crispin04:06:16

and in that file, in that namespace you eval (c-x c-e) a definition like (def n 3)

Crispin04:06:23

(this is ALL cljs files)

Crispin04:06:35

no go over to the console on the browser window and type

Crispin04:06:38

foo.core.n

Crispin04:06:04

you can see its there in the pages js context under its namespace

Crispin04:06:22

(in advanced compilation these names get minimised, but you can see how it does it)

Crispin04:06:50

so figwheel/shadow can be hotloading you files when saved into the browser context

Crispin04:06:05

and you can be linked and evaling inside cider aswell

Crispin04:06:18

you should also get println logging into you emacs repls

Crispin04:06:49

add the chrome clojure dev tools, and you can open and examine clojure datastructures inside the console in the browser

Crispin04:06:28

so if you did (js/console.log "my thing:" my-thing) or (println ...)

Crispin04:06:39

that would log out to the browser console

Crispin04:06:44

with little colapsey arrows

chepprey04:06:52

yes, i've had that going already (logging)

Crispin04:06:53

that you can open up and examine as clojure data

Crispin04:06:12

I don't know any other stack like this. It's heaven.

chepprey04:06:25

actually have a TODO to check out tap> for logging

chepprey04:06:46

dunno if it's in cljs yet tho (my todo was for clj)

Crispin04:06:02

when you get server and client together, cider routes automatically!

Crispin04:06:20

so you have two emacs repls, one server clj, one client cljs

Crispin04:06:33

and if you c-x c-e in a clj file, it routes it to the server repl

Crispin04:06:45

and if you are in cljs, routes it to client repl

Crispin04:06:52

and in cljc to both

Crispin04:06:30

I also use c-x c-e in cljs namespaces to examine and debug

chepprey05:06:03

man i wish we could use this stuff @ my day job.

Crispin05:06:05

so if there is, say, (defonce state (r/atom {}))

Crispin05:06:22

after that I put #_ @state

Crispin05:06:40

that is. ignore the next form (so it sompiles without it), and then deref state

Crispin05:06:18

you can put your cursor after the @state, go 'eval' in cider, and it will pretty print out whats in the state atom on the client

Crispin05:06:31

awesome for debugging

Crispin05:06:47

build little snippets in cljs and eval them to examine state deeply

chepprey05:06:55

like 5 years ago i was trying like hell to get other devs interested in clj.... we make full-stack stuff. Having the same language on client & server is SO useful it's why we actually use GWT a lot, even still now. ..... but, tragically in 2014 our wee company got bought by supermassive black hole borg company, and i suddenly became a very small fish in a huge pond, and changing away from Java & JS is not an option. 😢

Crispin05:06:33

yeah, I hear you. Not everyone is ready to walk the path. :man_in_lotus_position:

lilactown05:06:45

tap> is in latest CLJS

👍 4
manas_marthi05:06:12

hi all, I am working behind proxy and cannot connect to maven central directly. In case of lein, I am using :mirrors to specify artifactory URL. I want to try clj tools now. How to specify artifactory url in deps.edn?

seancorfield05:06:39

:mvn/repos at the top level

johnjelinek05:06:06

what's your favorite way to namespace your projects? I tend to have core for orchestration actions (bringing it all together), I tend to have util for pure functions and dal/`data_access` for functions with side effects

seancorfield05:06:44

I try to avoid core as much as possible -- that's really just a weird artifact of Leiningen's default from long ago.

😮 4
seancorfield05:06:05

util is also something else I try to avoid (that said, I think we have one at work).

😮 4
johnjelinek05:06:40

😆 now that I guess I'm doing everything not to do, what do you like to do instead?

seancorfield05:06:11

It's hard to generalize. At work, when we started, we used worldsingles as a prefix for most namespaces and kept them broader and somewhat generic. So we had worldsingles.user, worldsingles.search, worldsingles.reporting etc.

seancorfield05:06:50

We've since adopted ws as a prefix and gone to more deeply nested naming.

seancorfield05:06:14

Simple examples: ws.search.common, ws.search.elastic, ws.search.discovery (that's another search engine).

johnjelinek05:06:09

oic ... so you don't group things by queries vs commands or pure vs side-effects?

seancorfield05:06:35

ws.messaging.io.mysql, ws.messaging.logging

seancorfield05:06:33

It generally makes more sense to organize to match the domain, in my opinion. Trying to split code based on its implementation is rather artificial.

seancorfield05:06:58

That said, as shown above, we do have some namespaces that are all about side effects 🙂

👍 4
johnjelinek05:06:20

cool, thanks for the tips

seancorfield05:06:54

Some things to consider: it's common practice, when you require/`as` to use the last segment of the namespace as the alias -- so you don't want to reuse that last segment too often or you won't be able to require in those namespaces without inventing new aliases.

seancorfield05:06:38

Also, many editors only show the filename on the tab, not the path, so you don't want lots of some/thing/core.clj files 🙂

markx06:06:07

What’s the difference between concat and lazy-cat?

Crispin06:06:20

looks like lazy-cat is concat but is lazy in its consumption of input sequences. That is the body of one of the input sequences will only be invoked when the element is pulled from the outer lazy sequence

Crispin06:06:38

I've never used lazy-cat, but it is literally a macro that wraps its args in lazy-seq and passes those to concat.

markx06:06:57

but concat also returns a lazy-seq

markx06:06:31

so (lazy-cat xs ys) === (concat (lazy-seq xs) (lazy-seq ys)) === (lazy-seq (some-real-concat-func (lazy-seq xs) (lazy-seq ys)))

markx06:06:58

So I still don’t see the difference.

Crispin06:06:58

they both return a lazy-seq

Crispin06:06:27

so if I go (concat a b c d e f g h i j k l m) a...m are all evaluated. and the value is passed into concat... which returns a lazy-seq

Crispin06:06:22

if I go (lazy-cat a b c d e f g ...) non of them are evaluated... until they are needed... by consuming elements of the return value from lazy-cat

markx17:06:35

I think I got the idea. So it’s function vs macro, and the difference is not the return value or the goal, but whether the args are evaled when invoking. Thanks!

Crispin06:06:04

imagine if those body args, a to m, were something very concrete. Like a loop/recur that returns a collection

Crispin06:06:21

in the concat, they'll all run first, and then pass their collections to concat

Crispin06:06:45

in lazy-cat they will evaluate, and cache, their values as needed

Crispin07:06:45

I guess its tricky to see because if you pass lazy-seqs themselves into concat, it would behave just the same

jason poage07:06:13

How do I import compiled cljs files into my react project? i created an example of what im trying to do here https://github.com/jpoage1/cljs-testing/tree/master/src

Crispin07:06:13

@jason821 there are many ways. are we doing development or release builds? Are you preserving namespaces or minifying/munging them? Are you integrating with existing javascript react code?

Crispin07:06:16

if you turn advanced compilation off on your production build: set :optimizations :simple here: https://github.com/jpoage1/cljs-testing/blob/master/project.clj#L47

Crispin07:06:02

then you can build, with lein cljsbuild once min a js artifact that will be written here: https://github.com/jpoage1/cljs-testing/blob/master/project.clj#L45

Crispin07:06:17

do that, then open the js file in an editor and have a look

jason poage07:06:28

i have a react project that i want to finish writing in clojurescript and eventually rewrite the javascript parts

jason poage07:06:02

im not sure how to answer those questions, i guess i dont have any release builds and its still in the development stage. its not fully functional quite yet

dangercoder07:06:40

Are there any good tutorial on how to get started with Clojure using Maven? I am in the java enterprise.

Crispin07:06:03

@jason821 there are many ways to do it but your big problem will be conflicting versions of react. Your cljs dependency (reagent/om/rum) will bring its own react dep, and your js will bring their own. There are different ways to resolve the conflict. My advice, seeing as you are still in dev, and you intend to rewrite the whole thing anyway, is to start with fresh cljs toolchain using whatever library you choose, and then drop in the old js react components as js source code feeding into the compiler, to build a single optimized .js output artifact at release.

Crispin07:06:02

you can feed the old js in as inputs to the compiler, or you could keep them seperate and import the scripts into the browser. I would want to try to get it feeding in pre compiler so it passes through the google closure compiler optimizer with the cljs compiled source.

Crispin07:06:57

you can mount js react components pretty easily in reagent/om/etc

jason poage07:06:07

It’s so close to done that most, if not all, of the react components are already written. i can read, write and display the data as expected, but i havent implemented the delete and put operations yet. other things like cookies, authentication and sessions i havent even started with.

jason poage07:06:26

i can console.log the value of my clojure function from react now that i did what you suggusted, but now i get “failed to compile” from react

jason poage07:06:49

with lots of “Expected an assignment or function call and instead saw an expression” errors

Crispin07:06:20

where do you get "failed to compile"?

jason poage07:06:35

instead if displaying content, it displays

Crispin07:06:55

the artifact produced by cljsbuild should not be fed into another compiler...

jason poage07:06:58

“failed to compile” along with two thousand lines “Expected an assignment or function call and instead saw an expression” and at the very end “Java is not defined”

Crispin07:06:01

is thats what happening?

Crispin07:06:16

going into some node thing?

Crispin07:06:37

you want to bring that cljs .js artifact in at page root

jason poage07:06:44

so the only way to do it is to feed js into a cljs compiler?

Crispin07:06:45

with a script tag

jason poage07:06:38

how do i call clojure from javascript then? do i need to import anything?

Crispin07:06:57

after that is loaded, you will have the namespaces in the js window namespace

jason poage07:06:21

will i be able to access it within react?

Crispin07:06:51

so myproj.core namespace function my-func

Crispin08:06:07

is at js: myproj.core.my_func

jason poage08:06:15

so i dont need to import it into react, i just need to call the namespace?

Crispin08:06:32

just be aware, when you switch on advanced compilation this is no longer true

Crispin08:06:43

but one thing at a time

Crispin08:06:57

(in advanced, myproj.core.my_func may be Cx.Od.f4 one compile and http://qG.ar.bb the next. You have to declare 'exports' to preserve the clean namespace interface of select functions)

Crispin08:06:32

you will want to also probably :exclude the inbuilt react from your cljs deps if you have them

Crispin08:06:11

so if you add a dep to your cljs project of reagent, that will bring its own react, and that react will be bundled and minified into that js. So you need to :exclude it

jason poage08:06:25

i probably wont be using react with cljs conisedering most of the react stuff is done, so dependency shouldnt be an issue

Crispin08:06:40

ok cool. then theres no problem

jason poage08:06:18

so i include the compiled js file in the index.html in a script tag in the head section?

Crispin08:06:25

you can coral the data in and out of js with clj->js or the reader macro #js

Crispin08:06:56

after that script is loaded, check the namespace is there in your console

Crispin08:06:00

and you can call it

jason poage08:06:16

ok so i did that. now how would i reference from within the js project.core.hello_world()?

jason poage08:06:37

because i tried it just like that, and it says project not defined

jason poage08:06:18

or well in my case, the project name is “hello_world” and the function is hello_world.core.hello_world

Crispin08:06:34

do you have the hello_world in the console at all

Crispin08:06:46

like go in and type hello_wo... see if it completes

Crispin08:06:21

open the compiled js artifact

Crispin08:06:38

search for hello_world=... is it in there?

jason poage08:06:18

the output from the function shows up in the developer console, but somehow it still says hello_world is not defined. im not sure how it thinks its not defined but can still access its value

jason poage08:06:38

console.log(hello_world.core.HelloWorld())

Crispin08:06:48

so you go to console

Crispin08:06:02

type hello_world and hit enter. what does it say?

jason poage08:06:36

it gives me the object from the hello_world namespace

jason poage08:06:11

and says the function is located on line 2122

jason poage08:06:18

is somehow the react script is getting rendered before the clojure script?

jason poage08:06:12

i tried moving it to the top of the document but still nothing. the error in the console shows up after the output of console.log also

Crispin08:06:50

can you delay the mount of the root react component in the js until the namespace is loaded and defined?

jason poage08:06:11

with set timeout?

Crispin08:06:12

or allow it to be null, and repaint it later when its not?

jason poage08:06:30

yeah ill give that a shot

Crispin08:06:36

its not ideal

Crispin08:06:46

but it can get you started

Crispin08:06:28

the other thing to check is any async/defer props on script tags in your html. both the cljs build and the javascript

jason poage08:06:56

it seems that for every file that uses that name space i would have to make that check, because it imports and checks if its defined before the scripts are ever even executed

Crispin08:06:34

Im starting to get outside my paygrade, because I do it reverse. Import the js into a cljs project and bundle as a single artifact.

jason poage08:06:46

lol i cant believe how difficult this is

Crispin08:06:10

Im not sure how you are calling the cljs. cant you just go hello_world.core.hello_world() in the code?

Crispin08:06:19

the browser is well complicated

Crispin08:06:26

you've only scratched the surface

jason poage08:06:30

yes, thats whats happening. it both knows the value and thinks its undefined

Crispin08:06:57

it could be your js compiler?

Crispin08:06:04

not sure of your js toolchain

jason poage08:06:13

im using the react scripts

Crispin08:06:13

no sure of any js toolchain cause I don't use them

jason poage08:06:21

the only option i can think of is have a file that does a check on the name space then exports the namespace. ill give that ashot

jason poage08:06:42

then ill just have to import that file if i want to use the namespace

Crispin08:06:09

so are you going foo = require('....')? with the cljs namespace?

Crispin08:06:56

try not doing that. Just use the namepace

jason poage08:06:14

how do i create an async function that returns a value after a timeout?

jason poage08:06:07

oh yeah you dont do javascript lol

Crispin08:06:44

i get the feeling your js react side is trying to be 'clever'

Crispin08:06:52

and thats printing the undefined?

Crispin08:06:13

why not just try a timeout

Crispin08:06:56

setTimeout(1000,function(){/mount react root/});

jason poage08:06:40

it loads the files, does error checking. then executes the scripts. at least thats how its acting. but its not quite exactly like that though because console.log gets executed just fine. it doesnt make sense

jason poage08:06:30

so im working a file that will return the namespace once its been loaded. hopefully that does the trick

Crispin08:06:36

also instead of :simple try :whitespace under :optimization just.. in... case...

Crispin08:06:40

might be the simple optimisations stuffing with the interop?

jason poage08:06:34

my idea for it to timeout first doest work and i know why now. it has nothing to do with the order things are loaded or executed. the timeout doesnt work, because “typeof hello_world” returns “object” but then later react says is undefined because its not actually defined within react.

jason poage08:06:01

im going to give :whitespace a shot

Crispin08:06:06

and the cljs js compiled artifact be the first script tag

Crispin08:06:24

i thought script tags were blocking...

jason poage08:06:16

im thinking its not the script tags and its the compiler.

Crispin08:06:48

js ocmpiler, or cljs compiler?

Crispin08:06:33

are there options to make is less strict. So you can use an expression that it just accepts, and doesn't try to source and examine at compilation?

jason poage08:06:59

like its ignoring the script tag, but the browser regonizes it so it the browser reads the value from the cljs but the react part of it doest recognize it in its own script so it thinks its not defined

jason poage08:06:16

im not sure but probably

Crispin08:06:23

yeah and thats at js compile time?

Crispin08:06:32

that it doesnt recognise

Crispin08:06:39

thinks its undefined?

jason poage08:06:57

it doest give me the error in the terminal

Crispin08:06:54

Im not familiar with how the nodejs react tooling works

Crispin08:06:19

so if you create a function in js side, that calls the function in cljs

Crispin08:06:11

so in js, function test_call() { return hello_world.core.hello_world(); };

Crispin08:06:21

and then load the page up with both scripts loaded

Crispin08:06:38

and then, in the console, go test_call()

Crispin08:06:45

does hello_world run?

Crispin08:06:16

(i want to see if the js compiler preserves the call inside the function)

jason poage08:06:00

the test_call() is undefined

Crispin08:06:15

there is no test_call?

Crispin08:06:25

or it returns undefined?

jason poage08:06:42

uncaught reference error

Crispin08:06:29

the js compiler at least needs to output the code, or an error. check the settings of the js compiler

jason poage08:06:39

the window variable doesnt return any of the functions in my react app, at least not on the top level. its probably nested somewhere

jason poage09:06:30

so i got it working

jason poage09:06:11

you have to reference it from the window object, which i think you said something about that earlier. so window.hello_world.core.myFunc() works just fine

jason poage09:06:32

I can’t believe how many hours I spent on this.

jason poage09:06:18

thanks for all your help, i really wouldnt have been able to figure this out without you!

Crispin09:06:09

glad I can help

Crispin09:06:21

you wanna try advanced compilation now?

jason poage09:06:34

yeah i already did.

Crispin09:06:47

and you added the :export metadata?

jason poage09:06:49

lol it was the last thing i tried before i actually tried the thing that works

jason poage09:06:01

what does that do?

Crispin09:06:01

ill get a link

jason poage09:06:46

this is going to be so awesome. i can finally start writing clojurescript =D

Crispin09:06:23

you add :export key metadat to the function (defn ^:export my-func [] ...)

jason poage09:06:33

oh yeah i’ve done that

Crispin09:06:37

and that func wont be munged by the advanced compile

Crispin09:06:50

it should be exposed for calling from the other js artifact

Crispin09:06:16

those docs will go into more details now you've got it working

jason poage09:06:28

now i just have to figure out how to call javascript from clojure (not clojurescript), and i’ll be all set

Crispin09:06:42

you use the js namespace

jason poage09:06:48

is migrating from clojurscript to clojure pretty easy?

Crispin09:06:07

(js/my_js_func ...)

jason poage09:06:38

because after i rewrite my backend in clojurescript, i would want to just go to clojure. i would only write it in clojurescript if it would make it easier to make the migration from javascript

jason poage09:06:00

so you can call javascript and java from clojure?

Crispin09:06:52

its different. cljs is not js. and something like figwheel + reagent is a lot more than react.

Crispin09:06:13

the datastructures are obviously completely different

Crispin09:06:36

you will have seams... edges... where data needs to be coralled and reformatted form the js world to the cljs world

Crispin09:06:41

and visa versa

Crispin09:06:52

going all in on cljs that is not the case

jason poage09:06:55

i can just format to json though, or is there a better way?

Crispin09:06:02

you will have to

Crispin09:06:15

depends what your doing and talking to

Crispin09:06:36

I use transit + msgpack between client and server

Crispin09:06:18

just saying that theres cljs<->js interop... and then theres it just written in cljs. With atoms and reactive hotloading state preserving joy. And bolt devcards on...

Crispin09:06:37

java and clojure have full interop aswell yes

jason poage09:06:55

but not clojure and javascript?

Crispin09:06:07

cljs and javascript do

Crispin09:06:34

so you can interop between C# and http://clojure.net

jason poage09:06:41

so if i migrate 100% to cljs on the backend, how would i switch over to clj? how much different is clojure from clojurescript?

Crispin09:06:54

i use clojure on backend

Crispin09:06:07

but you could also use cljs on node if you want cljs on both ends

jason poage09:06:16

thats the end goal, but right now i have javasript on the backend

jason poage09:06:24

so im not sure if i should go from javascript to clojurescript to clojure, or if i should just go straight from javascript to clojure.

Crispin09:06:27

clj on jvm is very powerful. lots of great libraries and ecosystem. multithreaded joy. has more advanced construct of time primatives if they are needed (cljs only has atoms. clj has refs and agents).

Crispin09:06:37

but your server is already written in javascript

Crispin09:06:31

also, how well do you know node. If you are a node gun... maybe you want to leverage that knowledge

jason poage09:06:26

would it make more sense though to migrate to clojurescript first though, or would it make more sense to just migrate to clojure? the backend is more flexible, because i can have two servers talk to each other, i could hypothetically have my backend server written in several unrelated languages

jason poage09:06:12

or i could have the front end talk to the server it needs for the particular data it wants

Crispin09:06:01

maybe you dont need to rewrite the backend at all?

jason poage09:06:14

well if clojure can offer me more because it runs on the jvm, why not?

Crispin09:06:15

IMHO it offers you much more

Crispin09:06:42

also, it tends to be the setup most people use. So the path is more well trodden. Less weird issues. Better integration

Crispin09:06:17

I start my projects with the luminus template when doing client and server.

Crispin09:06:46

it might be a good little walkthrough to go through, so you can see the client and server set up togather and how it works.

Crispin09:06:35

http://www.luminusweb.net/ there are other options, too. But this works for me.

jason poage09:06:08

that just basically gives you a bunch of tedious monotonous code so that you dont have to write it yourself or something? lol im not familar with using templates, i usually just write everything from scratch haah

Crispin09:06:13

yeah its just all that really tedious stuff set up for you

jason poage09:06:34

will it help me with a project that i’ve already started?

Crispin09:06:47

not so much. And impossible to 'update' later. Like as the luminus template improves, you don't get it in your old projects.

Crispin09:06:33

you can port the stuff over if you want. There are other projects. and even frameworks now. I haven't really used them.

jason poage09:06:20

so its almost better to just not even use a template then you dont have to worry about upgrading lol

jason poage09:06:12

is luminous comparable to rails? i’ve only experimented with rails, i started building a web site and halfway through i decided it was too complicated and dumbed down for me lol i plan on revisiting it sometime but for what im doing now, clojure makes more sense

Crispin09:06:56

not really. rails is more a framework. luminus is just a templated project with a bunch of other libraries included

jason poage09:06:23

so that you dont have to go out looking for those libraries?

Crispin09:06:34

there are clojure web frameworks, comparable to rails. like arachne or Om next? I'm not across them, but I know they exist.

jason poage09:06:37

true. it seems so far that if i only learned luminous, i wouldnt really need to learn anything else to do a majority of web development then

Crispin09:06:58

its a good starting point. But if im doing client only code (like a gamejam webgame) I use the figwheel template.

jason poage09:06:30

well this is confusing lol so many options

Crispin09:06:50

I would keep it simple

Crispin10:06:01

you only just got cljs code working

Crispin10:06:05

just stick to that

Crispin10:06:11

forget about server side for now

Crispin10:06:30

spend 6 months learning cljs and just using that cljs where you have it now

jason poage10:06:05

well i already have a server side app, but its seperate from the project im already working on

Crispin10:06:22

one thing about clojure that I didnt realise when I started is it is both very broad and very deep as a language

jason poage10:06:12

i created a simple server side clojure app that does several types of calculations and accepts a json object as input to generate a bunch of values based on the input. but then i have my js backend which is for the project im working on

Crispin10:06:14

like you can go down down down into one little thing, and its deep. like a full logic programming engine in core.logic

Crispin10:06:28

but you dont ever need to learn any of that

Crispin10:06:34

and its also broad

Crispin10:06:08

its running as js in your browser, and on node, and react-native on mobile, and on the JVM, and people are making .net apps with it....

jason poage10:06:53

you’re talking about core.logic doing all those things?

Crispin10:06:54

so just find where it helps you out, and use it there first. You don't need to chase all the butterflys at once. The mountain will wait for you.

Crispin10:06:27

no. core.logic is logic programming engine that comes associated with clojure. So think the language prolog

Crispin10:06:36

its like a lispy-prolog, embedded in clojure

Crispin10:06:16

theres deep holes everywhere you can go down

jason poage10:06:36

just focus on what i need at the time though im guessing is the thing to do

Crispin10:06:52

just start somewhere and use ti

Crispin10:06:58

and be patient

jason poage10:06:35

each of it is just someone else’s idea of the implementation

zav11:06:24

Hey all, pretty beginner question. I'm working on building an API using Ring and Compojure but I've been out of the Clojure world for about 2 years now and I'm hitting some weird behavior I haven't seen in a while. The code is really simple right now,

(defn- hook-handler
  "Handler for processing GitHub webooks."
  [req]
  (content-type 
    (response (:body req)) 
    "application/json"))

(defroutes app-routes
  (GET "/" [] (response "Success!"))
  (POST "/hook" request hook-handler) 
  (route/not-found "Not Found"))

(def app
  (-> app-routes
      (wrap-defaults api-defaults) ;; Ring middleware
      (wrap-json-response)))  ;; Ring middleware
But when I navigate to to just look at the response for a GET to /, I get a pop-up asking to download a file of type application/octet-stream. I've attached a screenshot if it helps. Any idea what's going on here?

Crispin11:06:29

try (ring.util.http-response/ok "Success!")

zav11:06:57

I still get that popup using ok. I did get it to work by using the ring.util.content-type function and casting it to text/html and application/json so I'm going to roll with that

valerauko12:06:58

debug the response map, see if the Content-Type header gets set correctly

metehan12:06:24

I am using a validator package and it produces results like this-> {:email ("E-mail"), :pass ("Şifre")} how can I remove paranthesis is there a method to apply a function to all map values. (Expected result: {:email "E-mail", :pass "Şifre"})

tavistock12:06:15

yes but not in core, https://github.com/weavejester/medley/blob/master/src/medley/core.cljc#L91, (into {} (map (fn [[k v]] [k (first v)]) my-map)) would work too

Markus Åkerlund Larsson12:06:35

How do I get a working Clojurescript repl in Cursive? I've started one using the functions in figwheel-sidecar.repl-api, but after I do, I can't load and cljs namespace that depends on other of my namespaces, ordinary clojure namespaces fail if they have :gen-class, and can't find any libraries

metehan12:06:58

thank you very much

Markus Åkerlund Larsson13:06:18

@manutter51 that seems to still have the same issues when loading clojure namespaces, and it would be nice to have to option to use nREPL

manutter5113:06:34

That’s odd, it’s working fine for me, although without the nREPL of course. Maybe you have a version conflict somewhere? There’s also File -> Invalidate Caches / Restart… Sometimes that clears out weird glitches.

Radek14:06:46

Guys, what is the convention for placing tests? Do you have them 1) in the same file as src 2) in the separate file next to source 3) in dedicated <project>/test/ 4) else ?

ghadi14:06:39

#3

☝️ 4
ghadi14:06:23

usually the test namespace is foo.bar-test if the namespace being tested is foo.bar

ghadi14:06:43

but this is a less strong convention than where the files go $PROJECT/test

Radek14:06:08

Is there a way of running the tests in live REPL when they are placed in the default $PROJECT/test ? Aah, nevermind, got it, you just load the -test namespace to REPL as well 🙂

ghadi14:06:22

there are a few helpers in clojure.test, too @kyselyradek

Radek14:06:14

Yeah, I’m looking at them now. Thank you 🙂

markx17:06:35

I think I got the idea. So it’s function vs macro, and the difference is not the return value or the goal, but whether the args are evaled when invoking. Thanks!

mathpunk19:06:41

I'm living the Running with Scissors life but, I'm not doing a very good job of converting repl experiments into tests. Has anyone got a workflow they're happy with?

8
✂️ 8
seancorfield19:06:23

@mathpunk Are you putting the "repl experiments" inside (comment ,,,) forms in your source files?

seancorfield19:06:52

(that's what I do, so at least the experiments persist, even if they don't get into actual tests)

mathpunk19:06:18

in my main project directory I've got a siderail/user.clj file

mathpunk19:06:22

it's full of do statements

mathpunk19:06:39

so that I can be sure to require and define exactly what I need

mathpunk19:06:13

and then, Past Me, a doofus, extracts the useful functions to namespaces and leaves the do blocks in that user file

mathpunk19:06:29

so I have documented how I used it, but, it is not what I would consider 'test coverage'

johnj21:06:38

Are there any gotchas with rebinding the to the same name inside a let ?

johnj21:06:34

(let [a 1 a (+ a 2)] a)

noisesmith21:06:54

the second binding simply hides the first

👍 4
johnj21:06:28

yep, that's my objective, was wondering if it was considered bad practice

noisesmith21:06:00

it's good as long as it makes things clear - also that translates directly to (as-> 1 a (+ a 2)) (more useful when you have a longer series of bindings)

noisesmith21:06:50

user=> (macroexpand '(as-> 1 a (+ a 2)))
(let* [a 1] (+ a 2))

noisesmith21:06:11

maybe a more helpful example

user=> (macroexpand '(as-> 1 a (+ a 2) (* a a) (dec a)))
(let* [a 1 a (+ a 2) a (* a a)] (dec a))

johnj21:06:27

got it, exactly what I need, had four rebindings

noisesmith21:06:33

@lockdown- also like all the arrow macros, it's set up perfectly to be used inside ->

johnj21:06:03

besides -> ->> does all include stuff like cond-> , some-> etc ? (haven't study those, just grepping through the api)

noisesmith21:06:47

right, they all take an initial value as a first arg

noisesmith21:06:14

which means that if you start with ->, you can do every nesting alternation of them you might need

noisesmith21:06:47

re: that edit, of course -> turns nesting into sequencing :D

johnj21:06:32

knowing some scheme, was accustomed to nesting 😉

johnj22:06:20

as-> is really neat

noisesmith22:06:07

it's useful for algorithms that work in terms of successive updates to a single target value

johnj22:06:37

yep, very useful, clojure has all this neat macros to improve lisp readability

johnj22:06:39

clojure-mode is indenting incorrectly because of calling as-> without the first arg (since is inside a ->)

noisesmith22:06:49

oh yeah, that's a definite gotcha