Fork me on GitHub
#lumo
<
2017-06-10
>
mattford14:06:00

Hi, i’m failing to understand some code.

mattford14:06:22

#!/usr/bin/env lumo

(require '[cljs.pprint :as pp :refer [pprint]])

(def github (js/require "github"))
(def githubapi (github.))

(.. githubapi (authenticate #js {:type "netrc"}))

(-> (.. githubapi -users (getOrgs {}))
    (.then #(:data (js->clj % :keywordize-keys true)))
    (.then #(map :login %))
    (.then #(println %)))

mattford14:06:33

I wrote the above and when I run I get

mattford14:06:49

(madedotcom MastodonC Callitech MissGuided)

mattford14:06:27

But if I change the last line of the code

mattford14:06:38

to a map it doesn’t work

mattford14:06:14

(-> (.. githubapi -users (getOrgs {}))
    (.then #(:data (js->clj % :keywordize-keys true)))
    (.then #(map :login %))
    (.then #(map println %)))

pesterhazy14:06:49

which npm package is that?

mattford14:06:43

uses promises (I dont’ know much about node or promises) I’m just playing with Lumo as a script env at the mo.

pesterhazy14:06:43

I get UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: ~/.netrc authentication type chosen but no credentials found for ''

mattford14:06:05

hmmm yeah you need a ~/.netrc to authenticate to github

pesterhazy14:06:11

how do I do that?

mattford14:06:39

You’d have to create a personal access token in github and then setup the ~/.netrc file

mattford14:06:48

Let me do it on a public method so you don’t have to faff.

pesterhazy14:06:02

got it to work

pesterhazy14:06:41

replace the maps with mapvs

mattford14:06:01

I tried doall

pesterhazy14:06:13

doall should work as well

pesterhazy14:06:25

alternatively, the last one could use run! instead of map

pesterhazy14:06:56

it works for me then - I get one organization back

pesterhazy14:06:43

what does it print for you with run!?

pesterhazy15:06:12

(doall (map println %)) also works for me

mattford15:06:49

replace map with doall instead of wrapping it

mattford15:06:01

been puzzling over that for a good whilst!

mattford15:06:16

😞 and then 🙂

pesterhazy15:06:19

hehe yeah laziness gets everyone, now and then

pesterhazy15:06:38

btw not sure about the wisdom of those consecutive promises if the steps aren't async

pesterhazy15:06:05

although I've seen this frequently in node code, so not picking on you

mattford15:06:42

the whole github api is promised based

mattford15:06:00

and I cant’ extract the values of promises (as I understand it)

mattford15:06:08

what else can I do?

pesterhazy15:06:20

I mean you could use a single .then step no?

mattford15:06:12

that map doesn’t actually print but calls other promises

mattford15:06:00

which could be combined into a single .then

mattford15:06:40

I kinda liked the monadic nature of multiple .thens but if that’s not good Clojure style I shall change 🙂

pesterhazy15:06:48

don't know about that, but it just seems pointless to me (in js as well as in cljs)

pesterhazy15:06:13

node programmers in general seem to be seeking asynchrony like the moth seeks the flame... I just don't understand why

mattford15:06:27

I was wondering about a then-> threading thingy

pesterhazy15:06:16

interesting idea

pesterhazy15:06:37

although that could encourage the async step where it's not needed I suppose?

mattford15:06:13

I have to confess the async nature of the node github api has put me off somewhat.

pesterhazy15:06:35

all io in node is async, give or take

mattford15:06:35

Seems as soon as I use it i’m trapped.

pesterhazy15:06:46

at least all network io for sure

pesterhazy15:06:55

agree, it's contagious

mattford15:06:32

Was porting a script I use to clone all my repos across all orgs to Lumo as an experiment.

mattford15:06:59

Those async steps which aren’t really needed.

mattford15:06:10

Do they just resolve immeadiately?

pesterhazy15:06:27

i feel cljs macros could help mitigate the pain, with the right syntax

mattford15:06:31

i.e how bad is it?

pesterhazy15:06:42

but not sure what that syntax would look like

mattford15:06:59

Might have a play later 🙂 thanks for the help

mattford17:06:48

Any thoughts on this style

mattford17:06:18

#!/usr/bin/env lumo

(require '[cljs.pprint :as pp :refer [pprint]])

(def github (js/require "github"))
(def githubapi (github.))

(defn then->
  "Promise threading"
  [promise & callbacks]
  (reduce (fn [promise callback] (.then promise callback))
          promise
          callbacks))

(.. githubapi (authenticate #js {:type "netrc"}))

(defn getReposForOrg
  "Get all the repos for an Org"
  [org]
  (then-> (.. githubapi -repos (getForOrg #js {:org org}))
          #(:data (js->clj % :keywordize-keys true))
          #(map :ssh_url %)
          #(pprint %)))

(defn getOrgs
  "Get the organisations for an authenticated user"
  []
  (then-> (.. githubapi -users (getOrgs {}))
          #(:data (js->clj % :keywordize-keys true))
          #(map :login %)))

(then-> (getOrgs)
        #(mapv getReposForOrg %))

dominicm17:06:04

I wonder if it would be difficult to "promisify" callback style code by using a canary for where the callback would go?

dominicm17:06:32

obviously, the macro would essentially just generate that tree structure, but still

anmonteiro17:06:58

^ this will be in the next Lumo

dominicm17:06:43

Bluebird had this, didn't get much use, it's a bit of a 80% solution

richiardiandrea18:06:16

then-> still reads better imho, I like the above

mattford21:06:03

hmmm I’ve written some macros in lumo repl

mattford21:06:11

Struggling to debug.

mattford21:06:12

macroexpand doesn’t seem to do anything?

anmonteiro21:06:55

macros in self-hosted ClojureScript behave a little differently

mattford21:06:12

ah I hadn’t appreciated that