Fork me on GitHub
#beginners
<
2018-04-04
>
zaphodious01:04:18

Lets say that I want to use node modules in a cljs library, because that seems pretty cool. How do I include the dependency so that library consumers just have to require my library?

justinlee02:04:46

@achythlook are you targeting node or the browser and how do you intend to distribute your library? it isn’t easy to do this generically. lots of different choices with different tradeoffs

justinlee02:04:11

and how are you including your node modules currently (double bundle, shadow-cljs, npm-deps, foreign-libs)

zaphodious02:04:02

Targeting the browser, and clojars. I was hoping to use npm-deps, but it doesn't seem to work at all with ring-cljsbuild so I can't test it with my current testing setup.

zaphodious02:04:14

Its not a huge necessity, but given that Google has done a lot of the work I would otherwise be doing (in their workbox-sw npm lib) it seems like a good dependency to include.

justinlee02:04:15

i’ve heard people talk about “upstream dependencies” around npm-deps. i think this is what they are talking about

justinlee02:04:40

but i don’t use npm-deps so i’m not sure

zaphodious02:04:31

Y'know, reading the source for workbox's npm module... I don't need it. It literally just downloads the actual code from google's servers.

zaphodious02:04:58

So screw it. cljs-oops exists for a reason

zaphodious02:04:21

I'm kinda disappointed, though. Workbox isn't compatible with Closure, and being a Google product you'd think that they'd include it with the stdlib.

john03:04:24

when I was playing with service workers, working with workbox seemed like more work than it was worth

john03:04:36

I wasn't using the caching though

Michael Fiano04:04:12

So I have an extensive lein "user" profile in my ~/.lein/profiles.clj file global to all projects. Am I correct in thinking that a "dev" profile should not be defined in that file, and that its only purpose is project-specific dev configuration that should be applied to all parties working on it, completely separate but merged with my user profile? If that's the case, does a "dev" profile even make sense for a 1-man development team?

zaphodious04:04:37

@mfiano I look at it this way - a "dev" profile is designed to declare what things a given project needs at dev time, regardless of what the .lein/profiles.clj says. If you ever clone your repo to another computer, it will help you not have so many headaches. If someone else comes along to use your code, even far in the future, they'll have a dev set up that will work without having to hunt you down.

zaphodious04:04:02

@john Workbox is, indeed, a bit involved if one doesn't need caching. After trying to implement similar myself, however, I'm finding the existence of this library to be a life-saver (as in years of my life that I'd lose due to stress and anger, are no longer wasted).

Michael Fiano04:04:19

Ok. That makes a lot of sense. One other thing that doesn't make sense to me is when I create a jar file, does any of my "user" profile stuff make it into it? Or just the project stuff?

Michael Fiano04:04:20

Also side note, forgive me if I'm being dumb. I just never worked with maven or the JVM before I started Clojure a couple weeks ago, and I'm trying to make sense of exactly how the tooling works for distribution.

zaphodious04:04:19

That's okay, we're all dumb at some level. 🙂

zaphodious04:04:36

That being said, these aren't dumb questions

zlrth04:04:33

I have an atom storing some state:

(def c (atom  [{:user "me"  :docs [{:one "two"}]}
               {:user "you" :docs [{:three "four"}]}]))
I'd like to conj another :doc to you, like so:
@c
[{:user "me"  :docs [{:one "two"}]}
 {:user "you" :docs [{:three "four"} {:five "six"}]}]
What combination of swap! and other stuff to i have to do add an element to the vector in :docs ? it's my understanding that update-in only works for nested maps, not arbitrary nested data structures.

zaphodious04:04:51

Honestly, I don't use my .lein/profiles.clj. Every project I start gets dependencies that are honed for it, and though it takes me a minute or two to set up it means that the project.clj is all I need to know to understand the project in the future.

Michael Fiano04:04:58

I see. I missed the part that says user, dev, and a few others are excluded when building an uberjar.

Michael Fiano04:04:12

By the way, what is an uberjar? I've heard of a jar, but... 🙂

zaphodious04:04:40

@mfm Though I know its not necessarily "right" to suggest a library for every problem, I've gotten quite a bit of mileage out of this one for doing exactly the sort of thing you're doing. https://github.com/nathanmarz/specter

zaphodious04:04:57

@mfiano A regular jar is to a dll what an uberjar is to an exe, if I'm not mistaken

zaphodious04:04:19

its a jar with all dependencies, resources, etc bundled in

zaphodious04:04:59

typically, usually, you can run them

Michael Fiano04:04:41

Ok, everything is getting clearer! Now I just have to figure out what AOT is...or rather I know what it means, but not in the context of the JVM

zaphodious04:04:46

Depends on the specific context. For Clojure, it basically means that the code compiles completely for distribution.

seancorfield04:04:58

AOT is evil ... 🙂

zaphodious04:04:40

At the REPL, Clojure compiles on the fly to JVM bytecode. If you wish to distribute a somewhat faster-to-load program (via an executable uberjar), you AOT compile it so that Clojure can skip that step

seancorfield04:04:31

We don't AOT anything at work. We build uberjars as source, no AOT. We run them by running clojure.main and telling it (via -m) which namespace contains our -main that we want to run.

zaphodious04:04:46

It doesn't matter all that much once the executable loads, as everything ends up compiled anyway. Practically its a way to frustrate yourself.

seancorfield04:04:56

We have long-lived server processes so the overhead of compilation at startup isn't really an issue.

Michael Fiano04:04:59

I see. Well that skips a step for me then, being already familiar with long-running Lisp processes that compile on the fly

seancorfield04:04:19

This is bookmarked so I can drop it on anyone who asks about AOT https://gist.github.com/hiredman/c5710ad9247c6da12a99ff6c26dd442e

seancorfield04:04:02

(and he's written a follow-up about how to run Clojure programs without AOT... I'll see if I can find that)

zlrth04:04:00

thanks @achythlook. i've come across that library a couple times, and haven't had enough of a need to learn it. like you say, i'd be interested in a pure clojure solution. funnily enough, the reason i want this in the first place is my data structures are probably so-nested-it's-a-code-smell. so i'm asking for a "non-right" solution...

zaphodious04:04:47

@mfm Ahh, I gotcha. Hangon, lemme do some repling

🌞 4
seancorfield04:04:49

And of course now we have clj and deps.edn for running Clojure programs easily from source with no additional tooling.

zaphodious04:04:26

@mfm Alright, here's an example that looks kinda bad, but it works.

zaphodious04:04:28

(let [orig [{:user "me" :docs [{:one "two"}]} {:user "you" :docs [{:three "four"}]}] payload {:five "six"} t-me (first orig) t-you (second orig) you-docs (:docs t-you) new-you-docs (conj you-docs payload)] [t-me (assoc t-you :docs new-you-docs)])

zaphodious04:04:11

With destructing you can make it look a bit cleaner

zaphodious04:04:12

(let [[t-me {:keys [docs] :as t-you}] [{:user "me" :docs [{:one "two"}]} {:user "you" :docs [{:three "four"}]}] payload {:five "six"} new-you-docs (conj docs payload)] [t-me (assoc t-you :docs new-you-docs)])

zlrth04:04:19

oh that makes sense, @achythlook! thanks. i was thinking, wrongly, that i had to find to get the thing i wanted to update and update it in the same step.

sundarj04:04:18

@mfm just so you know, this works:

=> (def data [{:user "me" :docs [{:one "two"}]} {:user "you" :docs [{:three "four"}]}])
#'boot.user/data
=> (update-in data [1 :docs] conj 42)
[{:user "me", :docs [{:one "two"}]} {:user "you", :docs [{:three "four"} 42]}]

sundarj04:04:21

because vectors are also associative (with indexes as keys)

zlrth04:04:34

@sundarj thanks! question: how would i select "the map containing the kv pair :user "you"? edit: inside that update-in exression, that is

zlrth04:04:09

i think update-in ... [1 .. is selecting the second vector, which i don't necessarily know

zaphodious04:04:01

I don't think that update-in has that ability. Its purely associative. You could write something to tell you which one it is, like this horrible bodge

(get
  (into {}
    (map-indexed
      (fn [i {:keys [user]}]
        [user i])
      samp))
  "you")

sundarj04:04:09

yeah, that's right. if you don't know it, you'd need to do something like

=> (map (fn [m] (if (= (:user m) "you") (update m :docs conj 42) m)) data)
({:user "me", :docs [{:one "two"}]} {:user "you", :docs [{:three "four"} 42]})

zaphodious05:04:12

That's why I use the library I linked to before. It has faculties for doing this sort of thing a bit more simply

zlrth05:04:19

definitely! thanks @achythlook and @sundarj. yeah i'm kinda surprised clojure doesn't have something for exactly this; it's common-enough for me to use vectors to represent "many"-type relationships

zlrth05:04:29

i'm happy for now; and i'll look into specter

zaphodious05:04:09

@mfm Its a bit of a gap, for sure. Thankfully, we have macros and insane people who write macros 🙂

Fahd El Mazouni06:04:58

Hello everyone, what approach worked for you to learn clojure ? (books, blogs, projects...)

seancorfield06:04:13

I started with books -- Clojure in Action and The Joy of Clojure -- and a paid workshop organized by the author of Clojure in Action. There are better books to learn Clojure from these days (Living Clojure, Clojure for the Brave and True, the first two that spring to mind) and The Joy of Clojure is a great book but not a good first book for learning Clojure (I had prior Lisp and Functional Programming experience which is why I started there).

Michael Fiano06:04:19

I already had many years of Lisp experience, so I just had to skim through braveclojure and the clojure docs before I found myself coding on my own.

seancorfield06:04:59

I also found http://4clojure.com to be helpful.

Fahd El Mazouni06:04:25

cool ! thanks I started reading Brave and True but I'm moving slowly

Fahd El Mazouni06:04:08

I use C and Python most so other than basic map filter and reduce (in python) I don't have that much experience with FP

seancorfield06:04:31

Luckily you don't have a lot of OOP teaching you bad habits to unlearn either!

seancorfield06:04:17

Folks coming from a pure Java background can struggle with the shift from encapsulated data and side effects to immutable-data-as-the-api and pure functions...

Fahd El Mazouni06:04:58

what's a good first project idea to build in your opinion >

seancorfield06:04:38

Hmm, hard question. I would say avoid web projects to start with...

seancorfield06:04:08

...something that does pure data transformation or analysis is probably a good place to start.

Fahd El Mazouni06:04:31

implementing a little machine learning library for example ?

seancorfield06:04:12

I'm not sure what that would look like -- there are already great ML libraries available in Java you can use from Clojure (but they have complex APIs in general).

Fahd El Mazouni06:04:33

well if anybody has ideas 😛 I'm buying

seancorfield06:04:30

I was fortunate enough to already be programming on the JVM so I was able to just start writing stuff in Clojure and using it from existing projects... Is there a particular project you would have otherwise tackled in C or Python that maybe you could do in Clojure instead? Or perhaps something you created recently, that you could rewrite in Clojure?

seancorfield06:04:43

(I recommend avoiding web projects as the first thing because Clojure favors composition of libraries over frameworks so there's a lot of "assembly required" -- and front end tooling with ClojureScript is a whole 'nother ecosystem to learn so it distracts from actually learning Clojure)

Fahd El Mazouni06:04:01

I'd like to create a 3D fluids simulation

Fahd El Mazouni06:04:30

(nothing too complicated, was planning on using python)

seancorfield06:04:50

Hmm, I have no idea where you'd even start with that, sorry.

Fahd El Mazouni06:04:52

can it be done in clojure ? (or maybe clojurscript with three.js ? )

seancorfield06:04:13

Yeah, definitely, but I'm the wrong person to ask -- I don't do UI at all.

seancorfield06:04:48

Like I say tho', ClojureScript is a whole new ecosystem to learn that is different to Clojure...

Fahd El Mazouni07:04:41

oh I was under the impression it was basically the same thing. Do you have any resources I can look at to understand how they're different ? (I'll google it in the meantime 😛 )

seancorfield07:04:12

Mostly it's about tooling and the build process and setting up a REPL with your editor that is different. The language is mostly the same.

timo08:04:05

Hi! Is there any good documentation on how to use native js-react components in cljs? I am struggling with a lib called react-datepicker from cljsjs: https://github.com/cljsjs/packages/tree/master/react-datepicker

timo08:04:15

I basically never get how to use this in such a context

<DatePicker
    selected={this.state.startDate}
    onChange={this.handleChange}
/>
I am using it like this so far:
[(r/adapt-react-class (.-default js/DatePicker))]
but that is not working very well. It does not throw any error but display is not working properly.

andre.stylianos09:04:21

@U4GEXTNGZ I'm not too familiar with reagent itself, but after creating the component with r/adapt-react-class you should be able to use it as you do other reagent components without concerning yourself with this context.

andre.stylianos09:04:03

for example (not too sure about the syntax)

[(r/adapt-react-class (.-default js/DatePicker)) 
 {:selected "2017-09-27"
  :on-change #(println "I've received" %)}]

timo10:04:15

@U485ZRA58 Thanks! It works!

[:> (.-default js/DatePicker) {:selected (js/moment())
                                             :on-change #(println "meh!")}]
I now know that I am missing some fundamentals of JS-React-knowledge. I only do CLJ and started some reagent for a project. 🙂

timo08:04:54

How can I set the startDate here?

petr.mensik09:04:54

Is there a way how to convert (io/resource "file.pdf") to a File when called from uberjar? I am unfortunately using PDF manipulation library which accepts only String and File objects as an arguments so I cannot use io/resource directly 😕

petr.mensik09:04:44

There are only 3 ways how to create it - File, String and PDDocument which by itself created from File

rauh10:04:27

@petr.mensik You can create the PDDocument manually by calling with a RandomAccessBufferedFileInputStream

petr.mensik10:04:52

@rauh Thanks, I missed the PDFParser class

petr.mensik10:04:06

However I am not sure how to convert normal InputStream to RandomAccessBufferedFileInputStream - because this one has to implement RandomAccessRead which is PDFBox spefific interface

Russ Olsen14:04:14

Do be aware however that RandomAccessBufferedFileInputStream copies the data from the input stream into a temp file and then works from there. In general Java's io classes treat ordinary files and random access files like two separate worlds.

petr.mensik10:04:30

I have to take a look if I have the same version. However I might find other solution with PDDocument/load, will see

petr.mensik10:04:01

It seems that PDDocument/load works, thx guys

matan13:04:28

> java.lang.RuntimeException: Agent is failed, needs restart do agents really ever restart? 🙂

Alex Miller (Clojure team)13:04:04

or if you set their error mode to automatically do so

lilactown15:04:48

I have a dumb question: I’m using clojure.core.server to create a socket server. however, the server does not keep the process alive when I’m running it as an uberjar

lilactown15:04:47

I tried the naive thing and created an atom that will indicate when to quit the application, and then on -main, I start the server and just loop-recur checking the atom.

lilactown15:04:57

however I’m seeing this eat up a lot of CPU

lilactown15:04:26

what’s the correct way to keep my application running until I want to close it?

Alex Miller (Clojure team)15:04:32

there is an option on the socket server for this

Alex Miller (Clojure team)15:04:19

use :server-daemon false

lilactown15:04:53

:man-facepalming:

lilactown15:04:27

thank you alex! as usual, just RTFM 😅

Surya Poojary15:04:45

Is there any clojureschool web site available

Surya Poojary15:04:53

Like elxirschool

Fahd El Mazouni15:04:33

clojurecademy ?

👍 4
donaldball15:04:10

FWIW, my general pattern for a keep-alive system with clean shutdown behavior is:

(defn -main
  [& args]
  (let [system (start-system)
        runtime (Runtime/getRuntime)
        shutdown? (promise)]
    (.addShutdownHook runtime (Thread. (fn []
                                         (stop-system system)
                                         (deliver shutdown? true))))
    @shutdown?))

greglook15:04:47

I do something similar to the above - for bonus points, make shutdown? visible to the rest of the code by making it a var or putting it in the system map, then you can have a ‘graceful shutdown’ service endpoint that delivers that promise.

lilactown16:04:52

that’s exactly what I was looking for next 🙂 thanks!

Surya Poojary16:04:13

if i have a hi.clj file and a bye.clj file..i want to import functions in hi.clj to bye.clj ..how do i do that ?

schmee16:04:03

in bye.clj:

(ns bye
  :require [hi :refer [your-fn]])

avfonarev16:04:04

What is the most common correct use of defonce?

justinlee16:04:45

in clojurescript, people use it to define their application state so that the code can be hot-reloaded without changing the application state

👍 4
lilactown17:04:38

yep, I used it in clojure (jvm) sometimes as well to track resources like web servers, loading config files, etc. - though I’ve started using things like mount to track those things instead

grierson17:04:15

Is there a lein test-refresh equivalent for clojure.deps?

Alex Miller (Clojure team)17:04:26

No, not that I’m aware if

Alex Miller (Clojure team)17:04:37

No, not that I’m aware of

lilactown17:04:16

@grierson tools.deps & deps.edn are simple tools to handle dependencies - I don’t think it handles anything to do with running tests or watching files for changes

lilactown17:04:32

this would have to be built out by another tool

lilactown17:04:56

I think that leiningen has some support for deps.edn

grierson17:04:04

@lilactown I was following the official docs for Cognitech test-runner. https://github.com/cognitect-labs/test-runner Which says you can run clj -Atest

lilactown17:04:22

that’s still just talking about dependency resolution - it’s showing how you can pull in extra dependencies from different aliases

lilactown17:04:27

ah, I see you edited your comment

grierson17:04:55

Yes, sorry. the paste didn’t update

lilactown17:04:05

yeah, it looks like cognitect has created a test-runner utility that you can load and run via that command 🙂

grierson17:04:40

🙂 Yes. Has no colours or auto test mode though 😞 .

Russ Olsen17:04:05

@lee.justin.m @avfonarev I've seen people use defonce for exactly that in JVM Clojure as well.

grierson18:04:28

Is that a global profile like .lein/profiles.clj?

grierson18:04:55

or copy and paste for each project?

seancorfield18:04:28

clj reads (up to) three deps.edn files: the default installation one, your account's one, and the current folder.

grierson18:04:01

Awesome, I didn’t know that.

grierson18:04:21

And set up for Atom, even better! Thanks.

seancorfield18:04:15

🙂 clj -A:test:proto:nrepl is my friend!

grierson18:04:29

Do you have a write up of your workflow/set-up anywhere? It would be interesting to see.

seancorfield19:04:36

No public write up, I'm afraid. My Atom/ProtoREPL setup is essentially Jason Gilman's "opinionated" setup with the three "refresh" options disabled but I have some custom keymaps etc and several additional packages.

seancorfield19:04:59

As for workflow, it depends somewhat on which project I'm working with... my Clojure Contrib projects mostly use clj / deps.edn now (a few still use Leiningen for dev work). Those I start an external REPL as above then connect to it from Atom. My work projects are all Boot-based so I just "toggle" a Boot REPL from within the project. In all cases, I pretty much never type into the REPL -- I type into source/test files and eval code (into the REPL) but mostly use the inline result display rather than even look in the REPL pane (which I have at the bottom of my screen shrunk down to just three lines).

seancorfield19:04:26

That's following Stu Halloway's approach in his REPL-Driven Development talk (from the middle of last year, to the Chicago Clojure group I believe).

seancorfield19:04:57

Hope that all helps?

grierson20:04:17

That’s great thank you. Having a look over Jason’s Proto repl guide now.

seancorfield18:04:11

I have :test and :runner separated out so I can start a REPL with my test dependencies added in or choose to run Cognitect's test runner

clj -A:test
start a REPL with tests available
clj -A:test:runner
run tests
clj -A:test:runner:1.8
run tests with Clojure 1.8 instead of the default etc.

seancorfield18:04:40

You could combine that with a command-line watcher utility (for whatever O/S you're on).

zaphodious19:04:19

For my clojurescript :advanced compiles, I seem to be consistently hitting 300k on the low end. That seems... oddly big? How do I get that down?

justinlee20:04:43

@achythlook is that all cljs code or are you including a lot of js libraries?

zaphodious21:04:07

Just cljs. Gzipped its about 80kb

dadair21:04:00

Is there a way to get project-global *warn-on-reflection*, excluding external packages? e.g., something like :global-vars {*warn-on-reflection* true} in leiningen but without the noise from libraries?