Fork me on GitHub
#clojurescript
<
2017-01-04
>
qqq02:01:28

Is there anyway, in cljs, to split a single namespace across multiple files?

tbaldridge02:01:09

Tonight @qqq continues the quest to try every way to not use only one clj file

qqq02:01:37

@tbaldridge: I got it working with clj, but cljc also compiles at cljs, and that's the problem I'm running into 🙂

tbaldridge02:01:41

I have to ask, what are you trying to do?

qqq02:01:10

so I don't like large files, as I find them difficult to navigate due to my editing habits (no fault of the editor)

qqq02:01:23

I also don't like lots of small namespaces becuase importing is a mess

qqq02:01:35

I really like the SO structure of how core.clj works -- on enamespace, across multiple files

qqq02:01:46

it works fine for me in clj, but unfortunately does not work well in cljs

tbaldridge03:01:55

Then I gotta say, change your editing habits. Multi thousand line files are pretty standard in Clojure. Look no further than spec for examples

qqq03:01:20

that's pretty insane, I like small modules of 50-200 lines; it's just unfortunate clj's support for "import from this and export this" isn't as nice as I'd like it to be

tbaldridge03:01:51

But why? If it fits in a logical unit, why break it up?

tbaldridge03:01:14

Computers are great at searching files. That kind of what I'm getting at. A great way to edit lisp is to navigate via definitions where it doesn't matter where forms are in a file.

qqq03:01:37

1. I've never been in a situation where a logical unit is > 300 LOC 2. tbaldridge: well, if they're not in one logical unit, why should they be in the same namespace? 3. qqq: I don't have a good response. 4. tbaldridge: checkmate

qqq03:01:13

I guess they should be in separate modules, and I just need better require/import management.

qqq03:01:10

cljs blocks :refer-all; if I have multiple files that share common linew inside of (:require ... ), is there a way to def a variable there and not repeat myselv in every namespace ?

tbaldridge03:01:36

@qqq no, what I'm saying is, a logical unit of code should not be constrained by 300LOC. Let's do a quick survey of some Clojure core namespaces. clojure.core.async - 1.1k loc clojure.spec - 1.9k loc clojure.core.logic - 2.8k loc clojure.core.match - 2.1k loc clojure.test.check.generators - 1.5k loc

ustunozgur03:01:48

not sure where cljs support is with that.

qqq03:01:56

@ustunozgur : alot of important people bashed that yesterday

tbaldridge03:01:32

@qqq so I say, break apart namespaces where someone is likely to want A but not B. Aside from that, just stick it all in one place. It really is easier that way.

qqq03:01:55

@tbaldridge: https://github.com/halgari/odin/blob/master/src/com/tbaldridge/odin.clj <-- I understand that odin was created for educational purposes to go with your videos; in a "production environment", would odin be 1 single file instead of 4 files that are 100-400 lines long ?

tbaldridge03:01:12

that's a great question. There I mostly broke it apart based on a public API and private API (stuff in unification.clj is not public). And from there based on if you'd want A vs B. So you can choose not to import the Datomic bits if you don't need them

tbaldridge03:01:02

And also Odin doesn't have a hard dependency on several libraries. For example you don't need Datomic as a project dependency if you never require the context.datomic namespace. Same for context.xml

qqq03:01:33

re: your earlier point: https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj <-- I never realized clojure.core was a single file with 7k+ lines

tbaldridge03:01:55

same with cljs

qqq03:01:30

alright; so I guess . should be doing "largest reasonable unit" rather than "refactor into smallest reasonable unit"; then I should get better at emacs to manage going through files that are thousands of lines long

ustunozgur03:01:07

I think separating into multiple files prematurely gives a false sense of tidiness.

qqq03:01:31

@ustunozgur : given the number of imports I am doing ; I unfortunately have to agree

tbaldridge03:01:44

Perhaps, but I see it as part of paredit/parnifer's view of structural editing. Just like you can copy/paste code based on logical blocks (s-exprs) so you should be able to navigate based on "jump to definition" and "find usages"

tbaldridge03:01:19

sounds like "jump to definition" is M-. in emacs

qqq03:01:20

yes, but I'm at the point where if I dump everything into one file, the # of entires I have overflows a single speedbar screen (that has full vertical height)

qqq03:01:32

but then again, that should not matter

qqq03:01:36

if I'm jumping around with imenu

qqq03:01:24

I guess the psychological problem is as follows: with code folding, previously, I could "fold all my code" -- then see all defs in a single screen; this is no longer possible when I'm dealing with files of length 5k loc

qqq03:01:36

but there's no reason why "all declarations have to fit on a single screen"

tbaldridge03:01:15

oh I see, the tree-view of the file.

qqq03:01:34

yes, it uses imenu /regex to get a list of all defns / defs

qqq03:01:46

then it shows it in a vertical bar, and click,ing on it jumps me to the corresponding line in the file

qqq03:01:53

code folding sorta does the same thing

qqq03:01:55

alright, here's what I'll do

qqq03:01:10

I'll try this "large namespace" approach for a month or so, and if it doesn't work, I'll come back and complain later 🙂

qqq03:01:18

@tbaldridge: thanks for your time / discussion

tbaldridge03:01:00

no problem. And there's really no "right way" when it comes to editing. As long as you don't feel like you're fighting the language runtime

martinklepsch07:01:48

Can you think of some interesting/nice event systems for ClojureScript which are not focused on a specific react wrapper?

martinklepsch07:01:54

I found potok (https://github.com/funcool/potok) which is actually quite nice but unfortunately is a slight bit too opinionated

qqq07:01:56

reagent has it's reactive atom // is that too low level?

martinklepsch08:01:16

I’m more looking for something along the lines of re-frame’s dispatching stuff, zelkova, etc

qqq08:01:36

I've used re-frame, but not xelkova; what exactly are ou looking for? fundamentally there's a bucnh of nodes, there's a topolotical sort, and other stuff gets updated with nodes gets updated

martinklepsch08:01:55

Something I can put events in that handles them in some async manner. Something like interceptors would be nice to implement my own stuff on top of that.

pesterhazy08:01:47

@martinklepsch I'd love something like that too... I think

martinklepsch08:01:02

You think.. 😄

pesterhazy08:01:18

well I'm not sure if I even need the async part

pesterhazy08:01:38

a dead simple pub/sub mechanism would be ideal

pesterhazy08:01:56

also ideally not tied to any specific React wrapper

martinklepsch08:01:22

I’d be happy to brainstorm & jot down some ideas/requirements

pesterhazy08:01:31

my main use case is navigation events

pesterhazy08:01:01

my reagent components want to do something when you navigate to a screen X

pesterhazy08:01:19

and it turns out lifecycle methods are not the best place to do that

pesterhazy08:01:03

instead, IMO those events should be triggered by the navigation events ("user navigates to screen X")

pesterhazy08:01:55

the "things I want to do" include ajax requests, animations, setting timers. sending analytics events

pesterhazy08:01:05

does that make any sense?

martinklepsch09:01:01

@pesterhazy have you used re-frame?

metametadata09:01:41

basically you can add a handler for the global "enter-new-page" event

pesterhazy09:01:16

@martinklepsch I've read all the docs (and am a big fan) but I'm not using it right now

pesterhazy09:01:42

I think it solves (a lot of) other problems

pesterhazy09:01:47

not sure if it really solves mine

pesterhazy12:01:45

that's amazing

pesterhazy12:01:30

how did I not know about this?

urbanslug13:01:23

Where does this file exist cljs.core.async.macros ?

hlolli13:01:38

the amount of hidden treasures in google.closure is unbelieveable, and too little documented within the cljs interop. Some todo for all of us.

robert-stuttaford13:01:32

holy moly, so true, @hlolli. the number of times i’ve been able to remove cljs libs (cljs-http, cljs-time in particular) just by accepting some interop

martinklepsch13:01:19

The DateTime stuff in closurelib is just 👌

robert-stuttaford13:01:17

yep. and it’s all already sitting there. no need to add any deps

pesterhazy14:01:21

The Lisp-Lover's Illustrated Guide to Google Closure

curlyfry14:01:30

I've thought about that recently as well, would love some sort of curated list of the closure functions that are the most useful with cljs. For example, goog.history seems to be used a lot while goog.functions is basically useless from cljs

pesterhazy14:01:28

there's also goog.async.Delay and friends, pretty useful

robert-stuttaford14:01:08

i must say, for that, i prefer to bring in core.async

robert-stuttaford14:01:43

being able to put transducers on dom event chans is just too damn cool 🙂

pesterhazy14:01:05

core.async also brings in a bit of complexity

isak15:01:28

compared to what?

isak15:01:33

nm, i see you mean goog.async.Delay

dhruv118:01:56

In my clojurescript code (*.cljs files), how can i access functions or vars defined the clojure code (*.clj file)

kim019:01:47

mm is om.next useable today, or still in the oven ?

selfsame19:01:56

what's the setup for working with self hosted cljs these days?

selfsame19:01:43

meaning I'd like to get a cljs repl up without jvm/lein

kim019:01:57

on osx I use planck

selfsame19:01:00

on windows, think https://www.npmjs.com/package/cljs-repl is what I want though

selfsame19:01:37

ooh nice, will do!

mfikes19:01:00

Joel Martin’s REPL is what all the other self-hosted REPLs were derived from 🙂

kim019:01:24

any reason to choose lumo over planck on osx ? 🙂

mfikes19:01:59

In other words, if you’d like access to what Node offers, Lumo is great. Planck is based on JavaScriptCore.

selfsame19:01:58

anything happen with non JVM package management? Remember there was some talk about it a few months ago

kim019:01:35

I’m torn between learning reagent vs om.next .. and honestly cannot google if om.next is released or still in alpha/beta

mfikes19:01:05

I can’t recall who it was that was messing around with non-JVM package management...

futuro20:01:28

When ya'll enter "\\" into a cljs repl, what do you get?

stbgz20:01:29

@kim0 you can use https://github.com/eginez/calvin to get package management without the jvm

futuro20:01:40

I'm getting a string with two back-slashes, which feels wrong

futuro20:01:44

but I get it in lumo and planck

mfikes20:01:44

You get the same in ClojureScript and Clojure ”\\”

futuro20:01:50

@kim0 I believe om.next is still alpha, but the #om channel would know more

futuro20:01:36

Cool, thank you 🙂

ambrosebs20:01:16

how do I get a clojurescript REPL in Cursive?

selfsame20:01:16

@stbgz ah great hadn't seen calvin

mfikes20:01:32

@ambrosebs One way is to start a Clojure REPL and then “piggyback” into a ClojureScript one.

ambrosebs20:01:10

I'm familiar with that from vim-fireplace -- any instructions for cursive?

mfikes20:01:49

@ambrosebs Have you figured out how to create a Clojure REPL? (If not, right click on your project.clj and make one.)

ambrosebs20:01:08

got one working

mfikes20:01:42

Cool. One other thing @ambrosebs is to ensure that it has cljs picked in the little pulldown.

ambrosebs20:01:36

it still seems like a clojure repl

mfikes20:01:15

Yeah, that pulldown doesn’t turn it into a ClojureScript REPL—it just informs Cursive how to behave with that REPL in the odd corner cases where it needs to be different.

mfikes20:01:49

So, if you are in a Clojure REPL then do the (repl/repl (node/repl-env)) or whatever form would piggyback you into ClojureScript

ambrosebs20:01:45

@mfikes there's a "input required" dialog box that pops up, is that expected?

ambrosebs20:01:42

I tried rhino

mfikes20:01:19

Ahh.... I oftentimes set up the Cursive REPL to use the third “plain Clojure” option

ambrosebs20:01:55

that works much better 🙂

mfikes20:01:14

Yeah, I think you might lose a feature or two, but it works

ambrosebs20:01:12

I'm running in low power mode anyway 🙂

mfikes20:01:46

@ambrosebs And, if you ever want to mess with Planck from Cursive to mess around with self-hosted stuff, this would help: https://github.com/mfikes/tubular (Planck supports Socket REPL)

tbaldridge21:01:22

Let @cfleming know if you use socket repl, maybe we can bug him enough to get some more socket repl+cursive features 🙂

timgilbert22:01:27

Hey, I feel like this is a beginner question, but I'm trying to parse URLs out of random text while not losing the intermediate text, is there some function I'm missing to do it? Like I want to go from "Check out which is awesome" to ["Check out " "" " which is awesome"]

timgilbert22:01:50

(re-seq) will give me just the links, and (string/split) doesn't give me the links themselves if I match on eg #"https?://\S+"

timgilbert22:01:20

Feel like there must be an obvious regex-related function I'm missing

notanon22:01:36

does this work for you?

notanon22:01:55

if you put your regex in a capture group i dont think the native js split function removes it

notanon22:01:11

"Check out http://google.com/ which is awesome".split(/(https?:\S+)/); ["Check out ", "http://google.com/", " which is awesome"]

notanon22:01:51

at least in chrome 🙂

notanon22:01:11

the mdn documentation says browsers have diff capture group behavior

timgilbert23:01:09

Well, I've wound up just splitting it on whitespace and then checking them word by word, which works fine but seems kind of inefficient

notanon23:01:50

thats going to be extremely slow

notanon23:01:10

depending on how much text... obviously

timgilbert23:01:38

Yeah. I'm matching on small amounts of text

notanon23:01:51

if you split on this regex (https?:\S+)

notanon23:01:58

you know that every other element is a url

timgilbert23:01:40

That's what I wanted to do, but you never get the matched split elements back from string/split

notanon23:01:51

you didnt see my example?

notanon23:01:57

"Check out http://google.com/ which is awesome".split(/(https?:\S+)/); ["Check out ", "http://google.com/", " which is awesome"]

timgilbert23:01:19

Well, I was hoping to stick to Clojure

notanon23:01:32

i thought you wanted clojurescript?

notanon23:01:50

clojurescript strings are javascript strings

notanon23:01:54

just call .split on them 🙂

timgilbert23:01:30

I see what you mean, I'm just slightly too stubborn to do it that way 😉

notanon23:01:43

lol, ok 🙂

timgilbert23:01:23

In theory the code I'm writing could be run on the server too via cljc, too

notanon23:01:11

if you're in cljc then use the reader conditional to use the java string split vs js string split

notanon23:01:31

thats the whole point, for dealing with host differences

notanon23:01:48

jvm vs browser have different strings and diff regex

notanon23:01:55

this is something that cljc was built for

notanon23:01:42

(the only reason it was built actually)

timgilbert23:01:19

Yeah, but I feel like this is just fundamental string processing, I shouldn't need to drop down to the host language to do it

timgilbert23:01:51

...which is why I felt there must be some function I had just overlooked

notanon23:01:42

did you try the (https?:\S+) regex in re-seq?

notanon23:01:33

let me fire up a cljs repl

timgilbert23:01:36

I did. It works OK on the link case, not good on "this is just text with no link" which I also need to handle

notanon23:01:58

whats wrong in that scenario?

notanon23:01:13

returns empty?

timgilbert23:01:27

I got the best result along those lines with #"(.*?)(https?://\S+)" matching prefix text plus link

timgilbert23:01:34

Yeah, returns nil

notanon23:01:37

(if (empty? result-of-re-seq) return-original-string)

timgilbert23:01:03

Yeah, I could do that

timgilbert23:01:56

I'm fine with the word-by-word solution for now, the perf hit isn't really noticable for my use case and the code is readable

notanon23:01:59

you could use | (regex's or)

notanon23:01:16

(https?://\S+) | (.*)

notanon23:01:26

dunno. sounds like you're good to go though

notanon23:01:16

i would try to avoid putting any uneeded logic in my regex tho

timgilbert23:01:18

Yeah. Thanks for the ideas though

notanon23:01:27

np. good luck, have fun 🙂