Fork me on GitHub

I have a text file I want to use as input. I can't open this file in Javascript without getting cross origin request errors. Is there an easy way I can get the contents of this text file into a variable, so I can continue rapid development, without having to wory about the cross origin request errors?

Lennart Buit06:02:43

So I’d assume we are talking clojurescript now. I think your best bet is either by serving it from your computer OR adding a file field to your page

Lennart Buit06:02:07

If you are serving it from your computer, you must correctly set the cross origin request headers


So I've setup a webserver with http-kit which serves my html file. This html file also includes my clojurescript code which I compile using lein-cljsbuild . How would I go about adding a javascript library which doesn't have a clojurescript wrapper to my project so that I can use it in my clojurescript file?


@nicholas.jaunsen there's lots of ways to skin that cat. A main one is the "foreign libs" route.( There's various mechanisms to try to integrate with npm too - some ship with core and some tools, like shadow-cljs is well known for wrangling npm deps for cljs.


But the old school "add a script tag to your html file" works too. You just have to make sure that you're taking care of externs:


You may want to hunt down a larger example project that uses http-kit, to see how things are put together. If you have most experience with a traditional LAMP stack, then yogthos's luminus framework (collection of libs) is a great jump off point:


here's an "http-kit adapter" for luminus, for pointers on how http-kit would fit into the luminus framework


Well, I was hoping luminus docs had more examples of leveraging foreign js libs. Looks like the main docs are using mostly packaged things, per (see the webjars stuff)


But in any case, if you're leveraging server side framework like luminus over something like http-kit, you'll often be defining the delivery of your 3rd party js assets in the server-side logic, using script tags in your hiccup forms or something like that. Whereas, if you're going the mostly SPA route (which you can still serve up from http-kit) then folks usually stick to wrapping js libs as cljs packages so that deps are available to code via native cljs :require dep resolution (rather than via interop calls).


I think I posted this to the wrong channel (it’s just vanilla compjure, not compojure-api), so I am cross-posting here (I hope that is okay)


I'm trying to commit to Running with Scissors.... I am curious how people structure their projects to bring in repl tools they always use, repl tools that are project specific, and/or preserving repl explorations


right now I have a src dir and a siderail dir with a user.clj in it, but that file is getting kind of wild and unruly


for repl explorations, I like having multiple forms in a file like #_(fire-missiles) - that can be in the actual source, or a test, or a dedicated file for repl explorations


bonus, having a multi line version

makes it easier to use with editor integrations or even copy/paste


I think i've heard @hiredman keeps around a lot of history. I'd be interested to hear his approach if he has time


something like 6kloc of just explorations, repl history, etc


also if you use the nrepl terminal UI, all your history is in a file in the top level of the project .nrepl_history


you can copy paste from that


if CIDER / fireplace etc. don't have that, it would be a trivial feature to implement...


CIDER has a repl history that is browsable, saveable, etc


not sure about fireplace.


yeah, not surprised at all :D


I keep a couple of files called scratch.clj stored in different places


my personal ~/src/scratch.clj is 9kloc right now, and I have another for work related odds and ends


if I write clojure that doesn't immediately belong in another file it starts there


you copy and paste? can you easily associate the file with a repl?


yeah, I copy and paste


I also have a scratch.lua, .go, .sh, and .sql


I have the same for every project. It‘s in the project root and is something like „my repl history - the good parts“


yeah, and a good scratch file is very stream of consciousness, not much going back and editing, lots of duplicaction


a single scratch file seems much more of a better idea than my hundreds of randomly named, randomly placed snippet files I can never find


this is the sort of ideas we pay you for @hiredman

😂 1

For users of reagent, a question, assuming @name becomes a primitive JS string, how does Reagent know that a component used an atom? Does it measure/snapshot check which atom has been deref on first render?


@raymond.w.ko the r/atom code checks for surrounding context when you deref, and registers itself with the template if it finds one


Wow, thanks 🙂


lol. although i'm starting to think that's not the most relevant line of code ... maybe the add watchers part. either way it just tracks who is watching it


I was wondering that since [f] (a vector consisting of 1 function) doesn't change between renders, how does it "know" it has to re-render...


if you look at the IReset protocol underneath that, when the value is changed it notifies watches


so its a bit of bookkeeping of writing down who is watching and when the value changes let those watchers know


and if you chase that around a bit you end up in

(defn- rea-enqueue [r]
  (when (nil? rea-queue)
    (set! rea-queue (array))
  (.push rea-queue r))
which is what ultimately runs on every watching component. it gets scheduled to rerender


the other thing to remember: every reagent component instance gets converted to a React component instance with it's own state and lifecycle


^ very knowledge about React


It's like an atom with a permanent add-watch that triggers a refresh


s [f] looks like a vector with a function that doesn't change, but when it gets rendered, it gets converted to a stateful thing. so when the ratom inside it changes, it triggers a re-render inside the React component instance


the vector is a template that the driver function uses to create the component right?


Like Reagent sort of maps [f] to a React component and the deref marks this React component dirty?


and that component then gets registered for watching the ratom


the deref marks the component as something to update if the ratom is dirty


correct @raymond.w.ko


In my mental model, a swap! triggers it, rather than a deref... Then the diff happens on the React side and any dependent components get updated. Right @lilactown?


i think you are correct


swap! causes the ratom to look up any components that have registered them selves, and then the ratom tells them to eventually forceUpdate


@john that seems to make more sense.


yeah sorry, I misread your message wrong @raymond.w.ko


the deref ties the component and ratom together


reset! / swap! tells the ratom to look up any associated components and start triggering updates.


Okay, thanks all, I think I understand enough to use it confidently. I was worried that it wouldn't get updates.


This still seems like magic to me 😣


it is all a bit magical


no more magical than React is 😛 but perhaps with some idioms that are not as common


The lifecycle stuff is where the magic turns into debt, imo. But perhaps the new hooks stuff will smooth that stuff over.


any sufficiently complicated bookkeeping will appear as magic


if there was a way to do componentDidCatch, I'd never have to use React classes again I think

Nick Stares19:02:50

how do you print a large data structure? seems like at some point (around 100 elements or so) I just get [el el el ...]


but that might be doable with an HOC or render prop


@nickstares0 clojure.pprint/pprint and clojure.pprint/print-table both work great, depending on context


also good with with-out-str

(defn pp-str [x]
  (with-out-str (clojure.pprint/pprint x))


Howdy! I get errors when i run "lein cljsbuild auto" and not sure how to troubleshoot


can't find a log file


user=> (clojure.pprint/print-table (map #(zipmap [:a :b :c :d] (repeat %)) (range 10)))

| :a | :b | :c | :d |
|  0 |  0 |  0 |  0 |
|  1 |  1 |  1 |  1 |
|  2 |  2 |  2 |  2 |
|  3 |  3 |  3 |  3 |
|  4 |  4 |  4 |  4 |
|  5 |  5 |  5 |  5 |
|  6 |  6 |  6 |  6 |
|  7 |  7 |  7 |  7 |
|  8 |  8 |  8 |  8 |
|  9 |  9 |  9 |  9 |

Lennart Buit19:02:54

wow thats pretty neat!

Nick Stares19:02:32

doesn't work for the vector i'm using! I still get ... at the end

Nick Stares19:02:41

slack won't let me post the whole thing but the end is

(with-out-str (clojure.pprint/pprint (converge 200 2)))
{:state-counts {:a 80, :b 120}, :period 85}\n {:state-counts {:a 69, :b 131}, :period 86}\n {:state-counts {:a 73, :b 127}, :period 87}\n {:state-counts {:a 77, :b 123}, :period 88}\n {:state-counts {:a 89, :b 111}, :period 89}\n {:state-counts {:a 78, :b 122}, :period 90}\n {:state-counts {:a 72, :b 128}, :period 91}\n {:state-counts {:a 73, :b 127}, :period 92}\n {:state-counts {:a 73, :b 127}, :period 93}\n {:state-counts {:a 73, :b 127}, :period 94}\n {:state-counts {:a 74, :b 126}, :period 95}\n {:state-counts {:a 64, :b 136}, :period 96}\n {:state-counts {:a 63, :b 137}, :period 97}\n {:state-counts {:a 78, :b 122}, :period 98}\n ...]\n"


oh! the ... is the problem? that's caused by *print-length* iirc (there's some other related vars you can rebind). I misinterpreted your question

Nick Stares19:02:28

Yes! I'm trying to write a large vector to a file and all of the tutorials say to use pprint or pt-str

Nick Stares19:02:01

(with-open [w ( "values.edn")]
    (binding [*out* w]
      (pr-str (converge 100 2))))


user=> (apropos #"^\*print.*")
(clojure.core/*print-dup* clojure.core/*print-length* clojure.core/*print-level* clojure.core/*print-meta* clojure.core/*print-namespace-maps* clojure.core/*print-readably* clojure.pprint/*print-base* clojure.pprint/*print-miser-width* clojure.pprint/*print-pprint-dispatch* clojure.pprint/*print-pretty* clojure.pprint/*print-radix* clojure.pprint/*print-right-margin* clojure.pprint/*print-suppress-namespaces*)
- *print-length* is the main one, but there's some others that have effect too


you can set it to nil to allow arbitrary depth

Nick Stares19:02:35

awesome, so like this?

(def ^:dynamic *print-length* nil)

Nick Stares19:02:47

Or should I write over the one in clojure.core?


with dynamic vars, you can use set! or binding

(ins)user=> (set! *print-length* 5)
(ins)user=> (range)
(0 1 2 3 4 ...)
(ins)user=> (binding [*print-length* nil] (pr-str (range 20)))
"(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)"


binding is better in general, as it avoids the spooky action of global settings

Nick Stares19:02:36

great, i'll use the binding


yeah, for your usage (binding [...] (with-out-str ...)) is likely ideal


just be sure anything lazy is forced before leaving the with-out-str block

Nick Stares19:02:49

Yeah, I think the laziness is my problem. I read that doall will force strict evaluation but that's not doing the trick


doall works on a single level only


but println / prn / pprint will all force the whole input


but they also obey *print-length*, which isn't about laziness, it's about how printing is done (which interacts with laziness but is distinct)

Nick Stares19:02:30

I think I understand the distinction

Nick Stares19:02:40

(with-out-str (binding [*print-length* nil] (clojure.pprint/pprint (doall (converge 200 2)))))

Nick Stares19:02:45

but I would expect that to work

Nick Stares19:02:22

(defn converge [n s]
  "Creates a population of n agents with s possible states and runs a period of interaction
  on that population until all agents have the same state. Returns a
  vector of maps, where each map contains the count of agents after
  each period, e.g. [{:state-counts {:a 1 :b 19} :period 0}
  {:state-counts {:a 0 :b 20} :period 1}]"

  (loop [period     0 
         population (population n s)
         results    (vector (-> (run-period population s) 
                                (assoc :period period)))]

    (if (some #(= % (count population)) (vals (:state-counts (peek results)))) 
      (recur (inc period) population (conj results (-> (run-period population s)
                                                       (assoc :period period)))))))


you don't need doall inside pprint - pprint will eagerly realize the inside as long as *print-length* is nil; if *print-length* isn't nil, it will only force the top level, and no children


and converge itself is not lazy, so there's no point in doall over that - it's the children of converge that might be lazy

Nick Stares20:02:40

Ok, 3 steps of indirection down the children of converge use a fn that returns a lazy sequence via repeatedly


you could do a tree operation to recursively force the input, but the printing code will already force the input up to the limits of *print-length* - hope I'm not repeating myself too much here, want to make sure my point is communicated properly

Nick Stares20:02:00

Yeah, I think I just need to force the input at the bottom leaf of the tree since there is only one lazy seq

Nick Stares20:02:12

Or rather only one place where lazy seqs are introduced

Nick Stares20:02:40

(defn population [n s]
  "Creates a population of n agents that can each have s possible states"
  (repeatedly n (partial new-agent s)))

Nick Stares20:02:11

Thank you so much for helping with all of this as I chase down a rabbit hole...

Nick Stares20:02:55

Is there a better way to put n elements into a collection besides repeatedly? seems like I am not using that fn as intended


you can use (vec (repeatedly ...)) if laziness isn't desirable, also you might consider replacing (partial f arg) with #(f arg) for conciseness / readability

Nick Stares20:02:06

Awesome, that did the trick. Thank you so much!!

Nick Stares20:02:19

and thanks for the readability tip, seems obvious in retrospect 😛


I wish we had one or two character versions of identity, comp, partial apply etc. - so useful, but if they are more than two characters they add some noise...


(of course any of us can define our own aliases for all those functions...)


oh and complement too

Nick Stares20:02:27

ooh, complement is a good one that I forget to use

Lennart Buit20:02:58

partial and compliment are on the long side

Lennart Buit20:02:23

especially when you can ‘fake’ partial by #(fun arg1 arg2 %1 %2 ...)


and complement is (comp not f)

Lennart Buit07:02:57

few characters saving!


@kbosompem I've found it useful to stop the auto run, run lein clean then lein cljsbuild once if I discover a nontrivial error


@noisesmith my lein clean reports no errors and only empties the resource folder but not the target


C:\Sources\moose>lein cljsbuild once Compiling ClojureScript... Compiling ["resources/public/js/app.js"] from ["src/cljs"]... Compiling ["resources/public/js/app.js"] failed. clojure.lang.ExceptionInfo: failed compiling file:resources\public\js\out\cljs\core.cljs {:file #object[ 0x2bfb583b "resources\\public\\js\\out\\cljs\\core.cljs"]} at cljs.compiler$compile_file$fn__3702.invoke(compiler.cljc:1562)


then you might want to update your clean-targets - if you customize where the targets go, clean needs to be updated to stay in sync


in the mean time you can manually remove your target file(s), the point of running clean is that continuous auto-compiles can easily lead to inconsistent state reflecting a transient situation or a bug you already fixed


@noisesmith what i really need is a simple example of a re-frame app with a clojure backend


been wrestling with cljsbuild and figwheel for 2days


I'm not sure what's most up to date / recommended today, but iirc luminus has a lot of good examples and docs


chestnut is also a pretty solid template


has re-frame and http-kit options


@noisesmith luminus was overwhelming. base template's project.clj had 70 lines


@john checking it out now. Thanks

Ian Fernandez19:02:30

how can I compare keys from a list of maps if the entire list of maps, the maps has the same keys?

Ian Fernandez19:02:01

reduce-kv maybe?


you want to assert that the set of keys from each map in a list are the same right?


what kind of comparison? is great for comparing any two maps with the same keys

Ian Fernandez19:02:21

I'm testing if every map in a list of maps has the same keys of a comparison map


(apply = (map #(select-keys % [:my :keys]) inputs))


same keys or same contents?


`(apply = (map keys inputs))`


(apply = (map (comp set keys) [{:a 1 :b 2} {:a 4 :b 5}]))


oh - good call about using set before comparing


often saying what you want (as a property) makes it easy to see what to do


> you want to assert that the set of keys from each map in a list are the same right? (map (comp set keys)) falls out right there. and then you assert that everything in a list is the same

Ian Fernandez19:02:47

yeah it worked

Ian Fernandez19:02:11

I'm new to tests, trying to make some tests