Fork me on GitHub
#clojurescript
<
2018-05-30
>
lilactown00:05:29

is there a way to have a multimethod dispatch on type in CLJS?

lilactown00:05:51

clojure examples use class but that doesn’t seem to exist

lilactown00:05:12

I’m currently using type but I can’t figure out exactly how I should dispatch on e.g. if a value is a function

lilactown00:05:36

right now I’m using

(defmulti create-element type)

(defmethod create-element cljs.core/Keyword [v] "key")
(defmethod create-element (type (fn [] "k")) [f] "function")
but type (fn []) seems gross

pesterhazy09:05:30

@lilactown you could use a protocol for this

pesterhazy09:05:27

One of the reasons why protocol exist is that you can extend native types

lilactown13:05:04

so basically I would create a protocol for my create-element fn and then extend e.g. cljs.core/IFn?

pesterhazy14:05:04

You can extend functions directly, see this docstring https://cljs.github.io/api/cljs.core/extend-type

lilactown14:05:54

I see, thanks!

pesterhazy10:05:34

How do I turn #js{"a" "b"} into {:a "b"} while avoiding js->clj?

pesterhazy12:05:12

Thanks, that's useful

pesterhazy12:05:30

For the non-recursive case, this should work

(defn js-obj->hash-map [o] (->> o js-keys (mapcat (fn [k] [k (goog.object/get o k)])) (apply hash-map)))

thheller12:05:55

yeah but much less efficient, reduce will be much faster. could even add transients on top for extra boost.

pesterhazy10:05:12

For arrays there's simply vec but hash-map won't work for js-objects

djwelch66611:05:48

Hi, I am trying to setup a new clojure script build using the new tools stuff (deps.edn, clj) and have run in to a few issues. When I run clj --main cljs.main -c sam.core -r it works and builds however when I run the browser it is trying to connect to the repl on localhost. Fine, but I am running it in a vm which is on 192.168blah. So I'm trying to set the host using clj --main cljs.main -c sam.core -ro "{:host \"192blah\"}" -r but the clj just compiles and doesn't run the repl. I have tried using clj --main cljs.main -c sam.core -r -ro "{:host \"192blah\"}" which does run the repl, but the host is still the same.

djwelch66611:05:00

How can I make the browser call the repl back on the 192 address and not localhost?

hlolli13:05:34

Trying to silence Refused to get unsafe header when checking if header exists on the response.

(defn check-if-header-exists [xhr header-name]
  (some? (try (.getResponseHeader xhr header-name) (catch Exception e nil))))
But this won't cut it, someone has idea how to silence this error, or use different way of checking if response header exists?

Yehonathan Sharvit14:05:35

What is the best way to package a clojurescript library so that it can be used inside a javascript project?

darwin14:05:19

@viebel but mori.js had to solve this, not sure if it is the best, but maybe you can get some inspiration there[1], maybe mori-export has some clues [1] https://github.com/swannodette/mori

darwin14:05:25

in general you will have to bake-in all parts of cljs.core which are being used by your library code

Yehonathan Sharvit14:05:03

what do you mean by “bake-in” @darwin?

darwin14:05:01

assuming javascript projects consuming your library do not use google closure compiler and have no awareness of cljs

Yehonathan Sharvit14:05:38

I was thinking of simply defining the public functions of my library with ^:export

darwin14:05:30

yes, that should work, and you compile with :advanced, so gcc will do that baking for you

darwin14:05:14

mori even uses modules to split the code, as you can see here, not sure if :output-wrapper false is needed https://github.com/swannodette/mori/blob/master/project.clj#L24-L38

bhauman14:05:33

@djwelch666 you could try figwheel-main

djwelch66614:05:41

Yeah will check that out, looks good

bhauman15:05:41

sweet let me know how it goes

bhauman15:05:00

you will need to set the host in the figwheel-main.edn file

bhauman15:05:23

{:ring-server-options {:host ...}}

djwelch66620:05:01

I've just got around to trying it out now. Unfortunately work got in the way. Worked perfectly thanks very much, seems very polished. Only issue was I had to set :open-url false since no x windows, but the config didn't validate, so I set :validate-config false and everything was fine :thumbsup:.

bhauman14:05:24

I can help you get it set up if you have any problems

Yehonathan Sharvit14:05:07

@darwin do you think it will also work if I include 2 cljs libraries from javascript? I am afraid that there might be conflicts between the variable names generated by google closure compiler

darwin14:05:15

i think they are likely to clash unless you are extra careful

darwin14:05:17

by extra careful I mean compiling both cljs libraries as modules of a single gcc build (advanced mode)

Yehonathan Sharvit14:05:37

Yeah. This is what I thought

darwin14:05:47

but this is just my theory, I have never tried something like this

theeternalpulse15:05:02

Are there any community standards as to how to name functions (for example should functions that mutate atoms end with !, should js constructs be named differently than clojure ones, etc?)

lilactown15:05:28

side-effectful things usually end in !, yeah

lilactown15:05:19

usually host constructors/etc. get a camelcase name (e.g. MyConstructor)

dominicm15:05:46

How do clojurescript libraries specify their :npm-deps?

🤷 4
lilactown15:05:34

I think there’s some support for lein-npm

lilactown15:05:44

but I too am struggling with this problem

dominicm15:05:02

you set it in deps.cljs

dominicm15:05:11

just figured it out 🙂

dominicm15:05:28

(so that it works transitively that is)

darwin15:05:54

@theeternalpulse when using core.async, I try to prefix all block-returning functions to with go- prefix, and I don’t write functions which would return mixed results, e.g. sometimes blocks and sometimes other values

lilactown15:05:23

is there a core function to shallowly convert a clj map to js obj?

lilactown15:05:30

similar to #js but works with arbitrary maps

lilactown15:05:43

not just those with map literal syntax

bhauman15:05:40

@lilactown I don't think so

bhauman15:05:28

but you could copy clj->js locally and make it conditionally recursive

bhauman15:05:16

or just remove the recursion all together

bhauman15:05:06

its a good post

bhauman15:05:36

the elements of clojure book goes even further but I haven't read it yet 🙂

theeternalpulse15:05:23

I read the naming chapters but it's not contextual so far, it's more of a high level "what you should think about when naming"

theeternalpulse15:05:47

Too much sci-fi getting in the way of my programming books

bhauman15:05:56

I should really read that thing

pesterhazy16:05:59

@lilactown see the discussion a few hours ago here

pesterhazy16:05:22

I think this should be a core function

pesterhazy16:05:10

People reach for the recursive js->clj when they actually want a shallow conversion

lilactown16:05:11

seems silly to have #js and no function variant of it

pesterhazy16:05:59

(js-obj-seq #js{"a" "b" "c" "d"} which returns the same as (seq {"a" "b" "c" "d"}) would be useful

pesterhazy16:05:31

@lilactown well there (js-obj "k1" "v1" "k2" "v2")

bhauman17:05:54

@rnagpal super difficult to answer quickly. spec is a core part of the clojure eco system. so using it has many of the advantages of using standard libraries. It is also more general that plumbatic schema and you can express more with it.

justinlee17:05:58

my other two cents: schema is considerably less complicated and in some sense is more complete than spec. you can add checking to a function, checked closed maps, and get readable error messages without any add-ons. the method for specifying the shape of collections pretty much looks like the shape of the data, whereas with spec it is much more verbose. i think all of these things can be fixed with add-on libraries in spec, but the ramp up time will be greater. (still, spec is the “standard” so it is probably worth the effort)

justinlee17:05:28

by “more complete” i mean in terms of tooling, not in terms of the type checking you can do. spec is more powerful in that regard

bhauman17:05:14

but there are a ton of batteries in that

justinlee17:05:51

nice. that library has a schema-like specification format. if i could get that + spell-spec + expound and figure out how to instrument side-effecting functions i think i could switch to spec

bbrinck17:05:36

@lee.justin.m can you talk a little more about “figure out how to instrument side-effecting functions”? I’m not sure what you mean

justinlee17:05:24

the last time i tried to instrument a side effecting function it called the function like 20 times, which, of course, is bad. i believe i was told in the spec channel that that is expected behavior

justinlee17:05:34

that was the moment i switched to schema 🙂

bbrinck17:05:32

Hm, that is surprising. I thought check would call the function but not instrument itself, but I may be incorrect

bbrinck17:05:36

The only case I can think of why that might occur would be fspec specs

justinlee17:05:51

@bbrinck I’m trying to find that code attempt in git but based on memory I was using fdef and then I seem to recall there is some kind of instrumenting variable you set to get automatic checks on the arguments

bbrinck18:05:43

@lee.justin.m There very well may be cases where this occurs, but in my simple experiments, it doesn’t occur (but I may be doing something different than you intend) - https://gist.github.com/bhb/e8328ce1c15c3fc6f5f4ea71cabfa076

bbrinck18:05:36

certainly if you do something like exercise-fn, that would run the code https://clojuredocs.org/clojure.spec.alpha/exercise-fn

bbrinck18:05:13

maybe if one of the args was specced with fspec?

Alex Miller (Clojure team)18:05:14

fspecs are the only case where that happens

Alex Miller (Clojure team)18:05:32

the function is tested by running its arg generator and invoking the function

justinlee18:05:38

okay yea i looked back. it was an fspec issue

bbrinck18:05:13

ah, gotcha

bbrinck18:05:25

I would think in most cases, you could spec a side-effecting function using fdef with no issues then, you wouldn’t need to use fspec in that case

Alex Miller (Clojure team)18:05:16

it is specifically a case in specing functions that take a function argument spec’ed as an fspec

Alex Miller (Clojure team)18:05:30

one workaround is to use ifn? instead

bbrinck18:05:41

@lee.justin.m I haven’t used it myself, but if you like the way that schema adds type data to a function, orchestra has something similar: https://github.com/jeaye/orchestra#defn-spec

Alex Miller (Clojure team)18:05:47

and it’s also possible to swap this in as an alternate spec while doing check

Alex Miller (Clojure team)18:05:29

I think in hind sight that the fspec behavior has been more problematic than useful

Alex Miller (Clojure team)18:05:24

I’d be in favor of changing it and I think the last time I talked to Rich about it was in the early days and we’ve learned a lot since then

justinlee18:05:29

@bbrinck thanks yea I knew I’d seen something like that. I have a bit of analysis paralysis with the add-on libraries right now with spec but one day I’ll dive in and figure out a solution that serves my needs (e.g. consider how and whether orchestra and spec-tools work together). I didn’t realize that the fspec issue isn’t that big of a deal when I ran into it. I think I was just frustrated at all of the complexity and I just wanted something that would tell me if I typoed the key of a map or dropped some brackets and would also be a bit more self-documenting. schema really fits the bill there at the moment

👍 8
bbrinck18:05:50

@alexmiller I can see why the current behavior is unexpected (and requires test.check to be loaded IIRC), so I can see the case for changing it. Out of curiosity, what might the new behavior look like for fspec?

Alex Miller (Clojure team)18:05:37

I think the best suggestion I’ve heard is to also wrap and instrument the fn arg

Alex Miller (Clojure team)18:05:04

so that when it’s invoked you could verify the args of fn arg (and maybe ret)

Alex Miller (Clojure team)18:05:19

it’s more deferred but less surprising

Alex Miller (Clojure team)18:05:06

seems like that would be preferable to now, which is that people don’t like the current behavior and stop using fspec :)

bbrinck18:05:30

@alexmiller Seems sensible to me, much more consistent with how fdef instrumentation works. And +1 for checking return values both for fspec and fdef 🙂

justinlee18:05:38

yes! or maybe I can send him a cake and a thank you card if he does it all by himself. 🙂

🍰 8
Alex Miller (Clojure team)18:05:42

that’s a separate issue

bbrinck18:05:57

just using any excuse to advocate for it 😉

Garrett Hopper19:05:42

Am I missing something? clj -m cljs.main -co '{:npm-deps {"lodash" "4.17.4"} :install-deps true}' -re node This should start a node cljs repl after installing some npm modules, right?

Garrett Hopper19:05:50

It just exits immediately without doing anything.

Garrett Hopper19:05:12

@dnolen Hmm, ok. Some reason I didn't think it was working with that either earlier. I get a repl now, but npm modules aren't installed.

dnolen19:05:03

-co is --compile-opts, try -ro for --repl-opts

dnolen19:05:17

-co is for -c, -ro is for -r

Garrett Hopper19:05:45

Ok, I thought -ro was for the repl-env arguments, which didn't seem very useful.

Garrett Hopper19:05:51

Still no dice with -ro though.

dnolen19:05:06

oh hrm sorry you’re right 🙂

Garrett Hopper19:05:09

clj -m cljs.main -r -ro '{:npm-deps {"lodash" "4.17.4"} :install-deps true}' -re node

dnolen19:05:27

just checked -h yeah -ro is for repl-env

dnolen19:05:37

-co should work

Garrett Hopper19:05:44

I guess -co is only used when actually compiling. Oh well; I was just trying to understand why.

dnolen19:05:55

no it should work with -r

dnolen19:05:04

-co + -r, I was just misremembering

Garrett Hopper19:05:18

Does the order of arguments matter at all?

dnolen19:05:30

however you really need to specify -d

dnolen19:05:40

otherwise Node relative paths isn’t going to work

dnolen19:05:44

we’ll create a temp directory

Garrett Hopper19:05:55

It doesn't seem to do anything with -d when running a repl.

dnolen19:05:42

clj -m cljs.main -co '{:npm-deps {"lodash" "4.17.4"} :install-deps true}' -d out -re node -r works for me

dnolen19:05:01

then (require '["lodash/array" :as a]) (a/nth #js [0 1 2] 1) works

Garrett Hopper19:05:23

Strange clj -m cljs.main -r -co '{:npm-deps {"lodash" "4.17.4"} :install-deps true}' -re node -d tree doesn't work, but clj -m cljs.main -co '{:npm-deps {"lodash" "4.17.4"} :install-deps true}' -d tree -re node -r does.

Garrett Hopper19:05:03

-r after -co fixes it.

dnolen19:05:07

-r must come last

dnolen19:05:08

same as -c

Garrett Hopper19:05:21

Oh, ok. I didn't know that.

dnolen19:05:44

-h -> “The init options may be repeated and mixed freely, but must appear before any main option.”

dnolen19:05:57

so it’s documented but like anything - easy to miss

Garrett Hopper19:05:37

That makes sense. 🙂 Thanks I'll RTFM next time. 😉

dnolen19:05:10

I wrote it and I couldn’t remember, so it’s working 🙂

johanatan19:05:26

is there a function that takes a thing, compares it via some comparator and if that thing passes the check transforms it. otherwise, it returns the original thing. if this doesn't exist, what would be a good name for it? [want to write it myself but can't think of a good name]

Garrett Hopper19:05:52

What were you saying about -d? It seems to work without it. (It'll install npm deps, and I can require them.)

dnolen19:05:22

well if I recall if you don’t supply -d I thought we made a temp directory for you

Garrett Hopper19:05:39

Nah, no temp dirs were created.

Garrett Hopper19:05:03

@johanatanSounds like a monoid in the category of endofunctor to me. 😛

dnolen19:05:06

@ghopper hrm I’m not convinced 🙂

dnolen19:05:14

I tried with -v and I see temp dirs

Garrett Hopper19:05:25

:man-shrugging:

» clj -m cljs.main -co '{:npm-deps {"lodash" "4.17.4"} :install-deps true}' -re node -r                  ~/tmp/tree
ClojureScript 1.10.238
cljs.user=>
» ls                                                                                                     ~/tmp/tree
deps.edn  node_modules  package-lock.json  package.json
» ls -A                                                                                                  ~/tmp/tree
.cpcache  deps.edn  node_modules  package-lock.json  package.json
»                                                                                                        ~/tmp/tree

dnolen19:05:23

I mean pass -v to see

dnolen19:05:30

REPL will describe what it’s doing

Garrett Hopper19:05:38

I did, and the output with and without -d is the same.

johanatan19:05:00

@ghopper yep, i was thinking the same thing. sounds like functor.fmap from cats could do it. but this "thing" in my case is a string and wrapping it in some functor seems like overkill

Garrett Hopper19:05:55

Yeah, it probably is. Is there a reason you want to have a generalized function with a fancy name to do it?

johanatan19:05:48

just smaller, more declarative than an if/else. i.e., reads more like english: when something-is-the-case transform-something which is 3 tokens vs the 4 it'd be w/ the else clause

Garrett Hopper19:05:19

@dnolen Alright, nevermind. It is copying to /tmp. I thought you were saying it would create a temp directory in the current directory. I see what's going on now.

johanatan19:05:30

basically i want a when that rather than returning nil for the else, returns the original thing

Garrett Hopper19:05:17

@johanatan Like this?

(defmacro transform [x t f]
  `(if (~t ~x)
     (~f ~x)
     ~x))

(transform x #(= 2 %) inc)
=>
(if (#(= 2 %) x)
  (inc x)
  x)

Garrett Hopper19:05:30

With a separate test and transformation function

johanatan19:05:58

yea, but that actually isn't any shorter than: (if (= 2 x) (inc x) x) 🙂

johanatan19:05:14

realized that it is still 4 tokens since the original x has to be specified

Garrett Hopper19:05:08

Yeah, unless you're doing this kind of thing a lot of places or trying to string them together or something, I'd stick with the simple and redundant.

johanatan19:05:34

fair enough. partial application might make sense w/ your transform (but then its macro-ness screws us)

johanatan19:05:16

it could easily not be a macro though

johanatan19:05:29

anyway, thx for the input

Garrett Hopper19:05:14

You could save 3 characters, if you can find a two character name. 😉

(<> x #(= 2 %) inc)
(if (= 2 x) (inc x) x)

Garrett Hopper19:05:37

Yeah, there's no reason for it to be a macro.

johanatan19:05:49

very good point 🙂

johanatan19:05:04

could go full on apl or haskell and make a symbol for it

johanatan19:05:13

[as you did]

Garrett Hopper19:05:21

(defn <> [x t f]
  (if (t x)
    (f x)
    x))

Garrett Hopper19:05:40

Definitely. Does clojure support unicode symbol function names yet?

Garrett Hopper19:05:54

Actually...

(defn ☻ [x t f]
  (if (t x)
    (f x)
    x))
(☻ 5 #(= 5 %) inc)

👍 8
Garrett Hopper19:05:42

I want to find out what APL's symbol for this is now...

bhauman19:05:41

@ghopper if you're feeling experimental, you could try out figwheel.main

bhauman19:05:36

it should work pretty well

Garrett Hopper19:05:30

Oh, nice! Thanks for sharing

👍 4
kwladyka21:05:41

What do you use for navigation with re-frame / reagent / SPA ? Personally I like bidi but with what do you use it? To be precise I am talking about url#/path/to/something or any other solution to let user copy URL to current location. The part which I have to choice is about URL change event and set new URL from the app.

johanatan22:05:37

@kwladyka when i was doing reagent, I used secretary

johanatan22:05:53

and closure lib

kwladyka22:05:02

looks pretty old

kwladyka22:05:10

and unmaintained

johanatan22:05:35

it does what it does

kwladyka22:05:46

anyway I need only this part about URL manage (detect change URL and change it)

johanatan22:05:54

closure lib can do it

johanatan22:05:04

interfacing w/ html5 history

kwladyka22:05:35

I read somewhere it shouldn’t base on history, but I don’t remember the reason 🙂

kwladyka22:05:54

Do you have some example of use?

johanatan22:05:09

let me check

kwladyka22:05:20

*wrote -> read

justinlee22:05:28

for what it is worth, i use secretary + accountant and that works. i’m sure you can do it with bidi too

johanatan22:05:02

(defn hook-browser-navigation! []
  (doto (History.)
    (events/listen
     EventType/NAVIGATE
     (fn [event] (secretary/dispatch! (.-token event))))
    (.setEnabled true)))

johanatan22:05:32

(defn app-routes []
  (secretary/set-config! :prefix "#")

  ;; --------------------
  ;; define routes here
  (defroute "/" [] ...))

kwladyka22:05:00

ok, you convince me to check it deeper, I see accountant has update 3 months ago, not 3 years ago. My mistake.

marlenefdez23:05:26

hi all! I want to get started working on my first ClojureScript/React/Reagent app by implementing the game Hanabi. Does anyone have any suggestions for books/sites tutorials I can use to get started with React/reagent? I've played around a little with clojruescript but would be completely new to webapps/react