Fork me on GitHub
#clojurescript
<
2016-05-02
>
gowder03:05:01

Out of curiosity, has anyone ever tried to use cljs to generate JavaScript for apple's "JavaScript for automation" applescript alternative?

shaunlebron03:05:49

@gowder: interesting, haven’t played with it. haven’t heard anyone trying that yet

shaunlebron03:05:58

@gowder: what are you using it for?

gowder03:05:29

@shaunlebron: Right now, nothing at all, I was just kicking around the idea.

shaunlebron03:05:58

@gowder: ah, was just wondering what’s possible with it that might compel more people here to try or look into it

gowder04:05:55

@shaunlebron: people do all kinds of interesting stuff with AppleScript... obvious possibilities include stuff like feeding the text of Apple notes into a machine learning pipeline...

escherize04:05:20

What's the best way to make this more idiomatic?

(defonce messages (atom []))
(.forEach (.watch (.limit (.order chat "datetime" "descending") 8))
          (fn [x] (->> (js->clj x :keywordize-keys true)
                       (reset! messages))))

escherize04:05:45

maybe with -> ?

escherize04:05:00

(-> chat
    (.order "datetime" "descending")
    (.limit 8)
    (.watch)
    (.forEach
     (fn [x] (->> (js->clj x :keywordize-keys true)
                  (reset! messages)))))

escherize05:05:09

or is there some way to use ..to make this code better?

escherize05:05:01

(.. chat
    (order "datetime")
    (limit 8)
    (watch)
    (forEach
     (fn [x] (->> (js->clj x :keywordize-keys true)
                  (reset! messages)))))
seems to work. Any reason to pick one over another?

slipset05:05:12

There is also https://github.com/mfikes/planck/issues/122 which kind of explains why this is pain IIRC

magnars10:05:22

This (binding [*out* *err*] ...) gives me a Use of undeclared Var my-ns/*err* error. Is *err* not a thing in clojurescript? I don't see it listed in https://github.com/clojure/clojurescript/wiki/Differences-from-Clojure.

magnars10:05:38

Looking closer, I see *out* is currently not implemented listed tho. So that answers my question at least. simple_smile

darwin10:05:44

hmm, your environment must be broken somehow, for some reason cljs.core is not recognized as your implicit namespace

darwin10:05:40

(my theory)

darwin10:05:14

oh, wait, scrap my words

darwin10:05:37

try something like binding [*print-fn* *print-err-fn*] instead

risto12:05:22

how do you add sourcemap suppport for nodejs?

risto12:05:51

such as when I run a node app and there's a runtime error, have it display the clojurescript trace

risto12:05:21

also, how do you require nodejs modules? I can't seem to find much info on that. I looked at [this](https://github.com/bodil/clojurescript-all-the-way-down), but it's throwing "No such namespace, js" when I do (def source-maps (js/require "source-map-support"))

dnolen13:05:43

@risto :nodejs target will try to load source-map-support if it’s available

dnolen13:05:57

so just npm install source-map-support in your project and you should be good to go.

pbostrom13:05:09

@risto: use cljs.nodejs/require

risto13:05:39

@dnolen: Thanks, that's works! definitely convenient

gowder13:05:35

@slipset: interesting! Actually doesn't look like it would be too hard for basic scripting, judging by your example plus the one posted in the gh issue. Maybe time to play around with this. (I wouldn't necessarily believe hhas's gripes in that issue, though ---I think this is someone with an axe to grind; judging by that comment plus a response to a tweet of mine, s/he just regularly searches for everything relating to AppleScript to complain and link to his/her own libs)

slipset13:05:11

@gowder What sort of bummed me out was that javascriptcore didn’t seem to have access to the osascript thingy. It would have been so nice being able to do (def mail (js/Application "Mail”)) from planck

vikeri14:05:39

@martinklepsch: About :closure-defines, I can’t get it to work with leiningen in project.clj. Is it supposed to be in :builds :my-build or :builds :my-build :compiler? Neither worked for me. It is supposed to override values set with goog-define right?

martinklepsch14:05:08

@vikeri: yes. It's a compiler option so you need to make sure it's passed to the compiler

martinklepsch14:05:18

also in project.clj no quoting is necessary.

vikeri14:05:33

@martinklepsch: Ok, that’s what I did. The issue might be related to my RN setup.

martinklepsch14:05:22

@vikeri: if you look at the main file generated by the compiler it should have appropriate lines for the closure-defines you passed to the compiler

martinklepsch14:05:31

@vikeri: I assume you use none?

vikeri14:05:24

Well the output is target/ios/not-used.js so maybe that has something to do with the error 😛

martinklepsch14:05:14

haha. the closure-defines stuff works by prepending a little thing to the main file so if you're not using the main file it won't work

vikeri14:05:23

Haha alright, continuing the conversation in #C0E1SN0NM then...

jjttjj17:05:56

how do people feel about global state management in clojurescript compared to a backend clojure application? Over the past months i've fully adopted Component on the server side and thoroughly enjoy the repl experience it allows. It has influenced the way I am now building up a client side app. I'm passing local state down the ladder everywhere, taking state as args instead of referring to a global. While this keeps things a little organized, it's also seeming to put a strain on front end api, having to pass around resources everywhere where it would be easier just to silently depend on something like a singleton async channel, and the gains are less pronounced because on the frontend my workflow is based around page refreshes instead of resetting the repl (and i'm fine with this). Basically, is it common for state management to be less strict on client side applications?

niwinz17:05:10

It mainly deppends on that you want

niwinz17:05:38

Independetly if you will use it or not, take a look on https://github.com/tonsky/rum

roberto17:05:59

in the front end, I like using EntityDB http://keechma.com/04-entitydb.html

niwinz17:05:59

it has very interesting and simple approach for model react based ui

jjttjj17:05:47

I'm getting more at this: When you use EntityDB for example do you pass around the reference to the DB in all your functions that use it? Or just have it defined globally somewhere and refer to it throughout all your functions

jjttjj17:05:28

On the server I kind of adapted the passing it as an arg everywhere and along with Component I feel this was beneficial to my workflow, but now going back to client stuff, I'm seeing less benefits to that style, but it's still kinda drilled in my head that "global state is bad"

roberto17:05:36

I’ve only used it with keechma, and there is no need to pass it around because of the way it is architected. I would probably try to emulate the way it is done there if I weren’t keechma: Separate the components(views) from the controllers, and the only way they can communicate is via messaging.

roberto17:05:56

Implement the controller as a record that is instantiated with the application state

jjttjj17:05:33

ok cool thanks i'll look at keechma

neverfox17:05:43

@jjttjj While JS and not CLJS, I would really take a hard look at how Redux does state management.

fasiha18:05:22

@jjttjj: if you're getting started in this space, the re-frame readme is a pretty good intro to redux (plus you'll learn re-frame and start applying it!): https://github.com/Day8/re-frame

fasiha18:05:20

It has a dispatch & subscription mechanism that neatly side-steps needing to pass around your db

jjttjj18:05:42

fasiha: thanks, i'll check that out too

fasiha18:05:14

Also: posh (https://github.com/mpdairy/posh) is a take on re-frame but using datascript for querying/updating your app db (datascript, that thing that looks like datomic)

borkdude18:05:59

I saw a presentation of someone that made mobile apps with clojurescript, but dropped Datascript because it was a little slow on mobile

fasiha18:05:03

@borkdude: oho? Mobile apps, like React Native?

fasiha18:05:00

Ah, gotcha. Still I am planning on using it (Datascript) in my current app to try it out, my users for that will just be my colleagues simple_smile and they'll be on browsers (rather than native).

borkdude18:05:51

Sure, do try

darwin18:05:44

@jjttjj: the problem you have outlined is a real one. A common way how to “pass implicit parameters” is via dynamic bindings. Clojure core library itself relies on this technique a lot. When going from Clojure to ClojureScript this technique is not that useful because it breaks with introduction of async code. Dynamic bindings are not “inherited” by callbacks (or code scheduled asynchronously and we don’t have anything like bound-fn in ClojureScript). This issue has been raised multiple times over time but no acceptable solution was proposed (yet). I would recommend following this JIRA issue where we will discuss possible solutions: http://dev.clojure.org/jira/browse/CLJS-1634

xcthulhu19:05:04

@jjttjj: Keechma is another approach

xcthulhu19:05:58

keechma makes the URL the source of global state, which isn't a terrible idea if you are interested in SEO or server side rendering for performance reasons

roberto19:05:23

I don’t have an issue with passing in the dependency into a function. It makes things much clearer when reading. I’d rather be able to reason about a function later, than save some keystrokes today.

darwin19:05:23

@roberto: right, but there is some limit to that I believe, for example would you explicitly pass a logger service reference into all functions in your system? simple_smile

darwin19:05:18

or would you want to pass “db” reference through functions which don’t care about db, but want to call other functions which possibly need access to the db?

darwin19:05:10

I once did a rewrite of quite complex cljs code to component model “without global vars", and it wasn’t a pleasant experience...

darwin19:05:39

ended up passing “context” parameter as explicit bag of deps into basically all functions

darwin19:05:00

I’m not a Haskell guy, but the problem we are talking about is real. And there exists research papers about it simple_smile Haskell people came up with a language extension for it: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/other-type-extensions.html#implicit-parameters

roberto19:05:05

if a function needs to call another function that queries the db, then that function depends on db

roberto19:05:12

I would want to see that explicitly

roberto19:05:50

instead of pushing the db into a global var, I would probably try to use a channel

borkdude19:05:58

I have a REST application where I pass the db into the handler functions, that way it's very explicit

roberto19:05:05

if I really don’t like passing down the deps

borkdude19:05:20

and also easy for testing

roberto19:05:21

but I personally prefer passing down the deps

roberto19:05:27

yeah, what @borkdude said

darwin19:05:28

I also agree that it is better to pass deps explicitely in parameters but there is a limit to that when it becomes impractical.

roberto19:05:17

I’m afraid I haven’t had any cases where that has been impractical

darwin19:05:29

how would you do that logging use case? I don’t want one global logger, I want to pass loggers explicitly down as a “service"

darwin19:05:46

even clojure is doing that via out/err dynamic vars

borkdude19:05:53

logging and printing is not something I would want to test

borkdude19:05:30

and if I really had to, I could use with-redefs for that exceptional case

roberto19:05:47

i would pass down the logger, since it is a dependency. If for some reason I want to avoid that, then I’d pour some holy water on me and use a global var.

borkdude19:05:05

the reason we went from dynamic vars to db as an argument is lazyness

borkdude19:05:33

in combination with datomic for example you really don't want to have your db in a dynamic var or weird things will happen when you query the db as of some time

roberto19:05:57

everytime I’ve had to deal with a dynamic var, I’ve run into issues

darwin19:05:46

laziness? I don’t get it, going for explicit arg passing is the right thing to do, but verbose and prone to heavy maintenance

darwin19:05:32

you have to be careful with dynamic vars when doing multi-threaded development, must be aware of bound-fn (in Clojure)

darwin19:05:55

as I wrote above, situation in ClojureScript is even worse

roberto19:05:16

another reason not to do so, then

borkdude19:05:07

@darwin: example, we had this: (binding [db (db/as-of ...)] (map #(db/q '[....]) ...) or something. We got the results of the default binding, because evaluation was lazy

darwin19:05:29

so, I don’t have a good solution for my logging case. I want to do it right. But I cannot pass logger into every single function in my code base. I cannot use dynamic binding because it won’t survive async call boundaries. I’m left with no other options.

borkdude19:05:18

@darwin: what are your arguments against a global logger?

darwin19:05:10

the same arguments as against global db reference or any other global thing. I want to be able to pass my own version of logger into functions at any level.

roberto19:05:16

I normally use timbre, which is global, so haven’t had to pass it in as a dep

borkdude19:05:39

@darwin: why do you want to pass your own version into functions at any level?

roberto19:05:11

i have wanted to have individual loggers because certain things I’ve wanted to log differently, but couldn’t figure out how to do that with timbre. If I could do that, I would still pass it down as a dep tho.

darwin19:05:00

why would you ever wanted to do (binding [*out* something-special] …) in Clojure code?

darwin19:05:40

you want to redirect functions like println and similar and capture their output for example

darwin19:05:46

you could do the same with loggers

darwin19:05:00

silence them on demand, capture their output, multiplex them, etc

darwin19:05:16

but this discussion is not about my arguments why it could be useful

darwin19:05:28

take as granted that I have good reasons, and want it

darwin19:05:40

why I can’t implement it?

roberto19:05:47

@darwin did you watch the talk at the conj last year about Conditional Systems?

darwin19:05:04

great talk btw.

roberto19:05:17

sounds like you are trying to do what was exposed in that talk?

borkdude19:05:43

@darwin: well, if your argument was testing, my answer would be: with-redefs.

darwin19:05:46

no, he proposed bindings and I outlined above why bindings don’t work for me under some circumstances

darwin19:05:03

@borkdude: my argument wasn’t testing

borkdude19:05:19

@darwin: I know, that's why I said 'if'

darwin19:05:03

btw. how does with-redefs work for you when you do need to test async code?

darwin19:05:32

with-redefs is just another name for bindings

borkdude19:05:44

in Scala you could do this with implicits, but people usually hate it

roberto19:05:02

I had to work on a scala piece of code once that was littered with implicits

borkdude19:05:02

another way would be default arguments

roberto19:05:14

partially applied functions

darwin19:05:04

good discussion guys, I have to run and do some work now, if you want to help solve my issue, follow http://dev.clojure.org/jira/browse/CLJS-1634

adamfrey20:05:53

I wrote a blog post about using Protocols in ClojureScript, specifically how it is involved with JavaScript interop: http://blog.altometrics.com/2016/05/protocols-in-clojurescript/

fenton20:05:12

how do people store maps with keyword keys into html5 local/session storage?

fenton20:05:24

@adamfrey: ok looks good. thanks!

adamfrey20:05:28

under the hood it uses transit to encode and decode your data structures into strings that can be put into local storage

fenton21:05:43

I wonder why the session-storage doesn't appear to work in my clojure-script repl...hmmm

risto21:05:38

What are some good virtual dom alternatives to Om?

risto22:05:35

Oh, I meant, what are some good non-React virtual dom libraries in ClojureScript?

risto22:05:50

the PATENTS clause makes me nervous

darwin22:05:57

@kingoftheknoll: deps conflicts are tricky, I would first try to include fipp dependency in your top-level project.clj, probably using the latest 0.6.4, hopefully puget will be able to work with this “future” version

darwin22:05:29

including fipp explicitely in your project should have precedence over deps declarations in libraries

kingoftheknoll22:05:16

I’ll give that a try, I’m surprised others haven’t reported this since it’s the stock reagent template… could it be referencing deps outside of my project?

darwin22:05:36

it should show a different error, because figwheel should now be satisfied

darwin22:05:46

if it is really using 0.6.4

darwin22:05:22

does lein deps :tree really confirm it is using fipp 0.6.4? (see the last section where it lists the effective deps tree)

kingoftheknoll22:05:28

[venantius/ultra "0.3.4"] -> [mvxcvi/puget "0.8.1"] -> [fipp "0.5.2"]
 overrides
[lein-figwheel "0.5.2"] -> [figwheel-sidecar "0.5.2"] -> [fipp "0.6.4”]

kingoftheknoll22:05:53

I even tried

[lein-figwheel "0.5.2" :exclusions [fipp]]

kingoftheknoll22:05:17

and explicitly required fipp 0.6.4

darwin22:05:11

:exclusions [fipp] on figwheel will fail, because your problem is that puget brought old version of fipp and figwheel chokes on it

darwin22:05:34

try :exclusions [fipp] on ultra lib, that should leave fipp 0.6.4 as effective version

darwin23:05:06

but my expectation would be that explicitly required fipp "always wins"

darwin23:05:00

venantius/ultra

darwin23:05:22

venantius/ultra requires mvxcvi/puget which in turn requires old fipp

darwin23:05:02

for some reason this old version wins over figwheel’s request to require 0.6.4 versio of fipp (assuming this one is newer)

kingoftheknoll23:05:26

I’m not requiring that lib

kingoftheknoll23:05:32

not sure what is

darwin23:05:54

wait, how exactly do you invoke that lein deps :tree?

kingoftheknoll23:05:15

cd to my project dir, then lein deps

darwin23:05:22

you have put explicit fipp under a :dev profile, that won’t affect your lein deps

darwin23:05:10

you have to do lein with-profile +dev deps :tree to see merged deps from your root :dependencies and :dev :dependencies

kingoftheknoll23:05:01

good news is that doesn’t give me any warnings

kingoftheknoll23:05:35

does that mean I need to run figwheel using with-profile?

darwin23:05:39

hmm, I’m not sure if I’m able to answer

darwin23:05:06

leiningen implemented some implicit magic that some “known” profiles are merged under some circumstances

darwin23:05:32

so it highly depends what commands are you trying to call if that :dev profile will be effective or not

darwin23:05:54

my brain memory does not have space to keep those details in

kingoftheknoll23:05:20

lol I understand. Is there a nuclear option like blowing away my .m2 dirs?

darwin23:05:52

deleting .m2 should not help in this case, your deps repository is perfectly fine

darwin23:05:17

to make sure your :dev profile gets included simply add with-profile +dev to your lein calls

kingoftheknoll23:05:57

thanks for helping

darwin23:05:26

np, let us know if you made it work