Fork me on GitHub
#clojure
<
2016-01-29
>
currentoor00:01:31

Is there a way to globally expose a macro or function in lein?

currentoor00:01:47

so I won't have to require it everywhere?

solicode02:01:33

@tom create-window takes process as the first parameter, so you should be able to do either: create multiple windows in the same process, or create a new window with a different process.

(let [another-process (create-process)]
  (w/create-window another-process ...))

solicode02:01:24

But honestly, I don’t know what to do with clj-thrust since the Thrust maintainer seems to have given up on it

solicode02:01:39

which is why I haven’t released a non-snapshot version yet

bbss03:01:03

if I want to change a handler in a running jetty server from the repl how do I approach that? When I try to store the server in a var (def running (run-jetty ..)) it's unbound. So I have to restart the whole jvm/repl session just to try out a new function, that seems very unclojurish to me so there must be a better way. I have used a little mount in clojurescript but not sure how to approach this.

jonahbenton03:01:02

hey @bbss have you seen Stuart Sierra's Reloaded workflow http://thinkrelevance.com/blog/2013/06/04/clojure-workflow-reloaded, his component library: https://github.com/stuartsierra/component and Daniel Szmulewicz' System library: https://github.com/danielsz/system ?

jonahbenton03:01:34

There are components for jetty that handle stop + start within the repl. You can do the same with Mount in Clojure; from a learning perspective though there's probably more documentation available for Component

bbss03:01:36

Yeah I had seen component and read good discussions between proponents of both. But I was afraid that yeah, component has a lot more examples online.

jonahbenton03:01:30

sure- the basic idea for jetty can just be gleaned from the source: https://github.com/danielsz/system/blob/master/src/system/components/jetty.clj

donaldball03:01:20

You don’t need the component dependency graph to get started; you just need a lifecycle for your server.

donaldball03:01:49

But you’ll be happier if your system state is managed coherently, probably

jonahbenton03:01:14

yeah, it's easy to get started just with tools.namespace and the refresh function, and manual lifecycle at the repl, then decide what pattern to adopt to manage state

bbss03:01:32

@donaldball I understand that, but just getting started understanding clojure workflow so that is a bit much to take on now. In ClojureScript figwheel is quite easy, auto reload.

bbss03:01:40

@jonahbenton: I'll have a look at that too. Thanks.

donaldball03:01:44

If you’re just looking for handlers that reload when you change their source, there’s a ring middleware that allows that

jonahbenton03:01:57

sure- yeah, the main difference working on the server compared the client is that instead of just consuming services, you're usually (also) providing them, so you wind up needing some kind of lifecycle management

bbss03:01:00

hmm but sufficiently complex front-end apps communicate back as well right? It just seems front-end can more easily say well lets just reload everything, because there are not many people depending on services so it's less important to be careful what to bring down.

jonahbenton03:01:16

yes, front end can just reload everything because generally it doesn't directly manage anything that corresponds to some machine level resource, like a listening socket, or a database connection- though if you were using local storage or some other physical resource on the front end, similar issues would apply. you would need to be careful about the order in which things were done and unwound

tom03:01:28

@solicode: That's too bad, clj-thrust is extremely easy to use, nice work.

bbss03:01:03

I am confused by two things in this example: https://github.com/danielsz/system/blob/master/src/system/components/jetty.clj 1. How come in this case server (run-jetty ..) does seem to bound? It imports from the same namespace. 2. where does map->WebServer come from. Is it some kind of constructor syntax sugar?

jonahbenton03:01:56

1. see in line 4 the :refer [run-jetty]? https://github.com/danielsz/system/blob/master/src/system/components/jetty.clj#L4 that brings that symbol into the namespace

bbss03:01:48

okay, so when I evaluate that in the repl it's not yet in the same namespace?

jonahbenton04:01:01

2. yes, exactly, defrecord is a macro that creates a number of constructor functions

bbss04:01:25

good to know simple_smile

jonahbenton04:01:38

when you use require in the repl (or in a source file), you have a few choices for bringing in symbols from the require'd namespace. if you use the :as form, you introduce a- usually short- symbol that, when suffixed with /, lets you use any symbol in the require'd namespace

jonahbenton04:01:01

if you use the :refer form, then you can bring in specific symbols from the required namespace without any prefix

jonahbenton04:01:01

IOW, (require '[clojure.string :as s]) means you can say s/join or s/lower-case

jonahbenton04:01:43

or you can do (require '[clojure.string :refer [join lower-case]) to bring those symbols in directly, as though you defined them yourself

bbss04:01:26

right, I think I got that, but in my repl when I evaluate my namespace and run jetty-server it seems not to bind to the def var

bbss04:01:48

should that return server?

jonahbenton04:01:03

what error message are you getting?

bbss04:01:31

I am not getting an error message, it starts the server (which might explain it does not return)

jonahbenton04:01:51

ah, so that's the :join? option

jonahbenton04:01:07

you want to (assoc options :join? false)

jonahbenton04:01:38

(.join server) waits for the server to be stopped

jonahbenton04:01:38

the use case is- the .start server step is the last thing you're doing at application startup initialization time/e.g. in -main. unless you have something to keep your application main thread busy, it will exit and your service will stop. (.join server) is a cost-free way of running an infinite loop to keep your server alive

bbss04:01:43

thanks a bunch!

jonahbenton04:01:51

sure thing, good luck!

solicode04:01:31

@tom Thanks. I should at least finalize a 0.1.0 and release that in case anybody is currently using it. I'll have to revisit Electron and see what's possible there. I mean, Electron is fine if you're starting new applications from scratch with ClojureScript, but I created clj-thrust specifically for running already existing Clojure web apps on the desktop. It's unfortunate that Thrust is no longer maintained, because I really like the language-agnostic approach they went with.

solicode04:01:09

It might be possible to achieve something similar with Electron by adding an RPC layer over it, but that's going to be more work on my side. I’ll look into it though.

jethroksy07:01:22

I have a question regarding Component

jethroksy07:01:36

I'm trying to define a websocket component, but assoc is giving me weird results

jethroksy07:01:19

so the relevant part is:

(start [component]
    (let [ws-url (slack/get-ws-url)
          conn (slack/rtm-connect ws-url)]
      (log/info ws-url)
      (assoc component
             :url ws-url)
      (log/info component)
-------elided---------

jethroksy07:01:10

log/info tells me ws-url exists, but even after the assoc, I see that :url is not changed in component

jethroksy07:01:15

16-01-29 07:55:57 jethroksy INFO [tob.components] - 
16-01-29 07:55:57 jethroksy INFO [tob.components] - #tob.components.WSClient{:id 21, :msg nil, :status nil, :url nil, :conn nil}

agile_geek08:01:10

@jethroksy: is the component returned from the start fn?

jethroksy08:01:12

ah ok it was being returned in the let block

jethroksy08:01:16

it works now!

agile_geek08:01:42

You need to return component from start (and potentially stop too)

fadrian08:01:11

@jethrosky, IINM, assoc doesn't change component. It returns a new map with the :url kry attached.

agile_geek08:01:57

Yep. And start is just a fn like any other so it needs to return the resultant 'new' component.

jethroksy08:01:00

component was being returned, but as the last expression of the let block

jethroksy08:01:05

that seemed to be making the difference

jethroksy08:01:10

probably because of scoping

fadrian08:01:41

The second log won't see it. Ahd the value of the log routine will be returned

agile_geek08:01:15

which would be nil

jethroksy08:01:43

oh gosh what was I thinking

jethroksy08:01:45

was following someone's code blindly

grounded_sage08:01:50

I like the GUI Observer they have in Elixir/Erlang land. Is there a JVM equivalent or something similar?

bbss09:01:37

@borkdude: thanks, having a look simple_smile

jindrichm11:01:29

Is there a more idiomatic way of applying a function to non-nil arguments only than #(when % (f %))?

mpenet11:01:29

if it's in a chain: (some-> x function)

jindrichm11:01:55

I'd prefer a function that I can comp. However, #(some-> % f) doesn't seem better than the solution above.

borkdude12:01:59

@jindrichm: there is also fnil, but it works differently

borkdude12:01:19

((fnil #(Integer/parseInt %) "0") nil) ;;=> 0

borkdude12:01:42

Another common nil pattern is: (when-let [x ...] (f x)). It all depends on your context

jindrichm12:01:08

Yes, I've thought about fnil, but it solves a different problem.

jotaro13:01:35

@jindrichm: how about custom macro?

(defmacro when-ex
  ([x & args] `(if ~x (do [email protected]))))

(macroexpand '(when-ex x (f 1) (g 2) (h 3) ))
;;=> (if x (do (f 1) (g 2) (h 3)))

jindrichm13:01:56

A macro could do, but a simpler one would suffice. I need to apply a single function to a single argument.

jotaro14:01:30

then, this must be it simple_smile

(defmacro when-ex
  ([x f] `(if ~x (do ~f))))

jotaro14:01:19

oh wait.. nop

jotaro14:01:51

this time is real

(defmacro when-ex
  ([x f] `(if ~x (do (~f ~x)))))

(macroexpand '(when-ex x f))
;;=> (if x (do (f x)))

jindrichm14:01:11

Why not simply this?

(defmacro when-ex `(when ~x (~f ~x)))

jotaro14:01:17

right.. sigh haha

mbertheau16:01:03

How do I check if something is in a vector? I.e. if :a is in [:a :b :c]?

rm16:01:50

(some #{:a} [:a :b :c])

mbertheau16:01:32

Thanks! Not very readable though.

rickmoynihan16:01:49

What precisely does this bit of the RING spec mean?

rickmoynihan16:01:07

the seq of strings bit

rickmoynihan16:01:59

interesting aside - has anyone converted the ring spec into a prismatic schema definition?

jonahbenton16:01:40

@rickmoynihan: the http spec (well, http/1) permits multiple instances of the same header name to be sent from either client or server. The seq of strings represents the case where the server received a such a request

rickmoynihan16:01:14

@jonahbenton: cool - I get that - I guess my question is, is it referring to a format like this {"Accept" ["application/json" "text/plain"]

rickmoynihan16:01:36

whats ambiguous is if it means the seq is in value position... I guess it must

agile_geek16:01:04

@rickmoynihan: Yes. But that would result in two header entries for Accept

rickmoynihan16:01:16

@agile_geek: yes - which is allowed

agile_geek16:01:08

I think you could do it with one like this:

{"Accept" "application/json, text/plain"}

agile_geek16:01:25

as the http spec allows comma separated values

agile_geek16:01:00

in this case the value in the map is a string with comma separated values rather than a seq of strings

rickmoynihan16:01:12

@agile_geek: yeah - I know you can do that... I'm just wondering what data structures are valid according to the ring spec

agile_geek16:01:35

Those two examples

rickmoynihan16:01:55

actually reading it again it isn't ambiguous - it does say "These values..."

gtrak16:01:57

Anyone know why all the core.match examples seem to introduce an extra level of nesting to the item and match-patterns? https://github.com/clojure/core.match/wiki/Basic-usage#vector-types

gtrak17:01:15

works fine without the extra [ ]

jjttjj17:01:40

is there a name for the pattern where i wrap a bunch of functions around each other to modify a map which is a response to an api call? So like middleware sort of but I only have access to responses, not requests. Is that just called a "pipeline" do any notable clojure libs use this?

danielytics17:01:50

@gtrak: It is my understanding that its similar to vector destructuring in function arguments: (fn [a b c] vs (fn [[a b c]] - the former is a function with 3 arguments, the latter is a function with one argument that is a vector with three elements. So in core.match, [[a b c]] means “match one thing, which is a vector with three elements”. Do you have a code snippet showing it work without the extra []?

hlship17:01:59

Q about reader conditionals. It looks like the well-known tags are just :clj, :cljs, etc. Is there any thought about a version number?

hlship17:01:29

I may want to build against a newer version of Clojure and polyfill. Example: if reader conditionals had existed in 1.6, we could polyfill clojure.core/update into 1.6 and use the real implemenation in 1.7.

hlship17:01:14

But we'd need a way of knowing the version of the platform we are executing on.

hlship17:01:50

I suppose the *clojure-version* var would help.

jonahbenton18:01:26

@jjttjj yes, and there are many ways to do this. one common way is with a threading macro- (-> response-map fn1 fn2 fn3) where each of f1, f2 and f3 return the modified response map. this is for cases where the series of operations are statically defined, e.g. by the programmer.

jonahbenton18:01:55

@hlship for platform-specific symbol existence, maybe use resolve? it looks like platform-specific version checks appear to have been discussed as part of the feature expressions proposal- predecessor to reader conditionals- but were considered problematic/out of scope. http://dev.clojure.org/display/design/Feature+Expressions

timmw18:01:37

Hi. I'm sending a bunch of http requests async using http-kit and passing in a callback to handle the response. Can anyone tell me how I ensure all responses are processed before the program exits? Thanks

jonahbenton18:01:11

@timmw each request should give you a promise, whether you give it a callback or not, so you can use the doseq pattern in http://www.http-kit.org/client.html#combined

timmw19:01:32

Ah right. I was thinking that would cause each promise to block as it's processed, but as each promise is in its own thread that wouldn't be the case, right?

jonahbenton19:01:22

right, your doseq code will block on individual undelivered promises. the work on the http-kit side isn't blocked

timmw19:01:39

and dorun would be equally valid?

timmw19:01:10

actually I'd need to deref inside the doseq?

jonahbenton19:01:14

well, in order to ensure all responses have been processed, you need to deref each promise. dorun won't do that on a seq of promises.

timmw19:01:30

cool, thanks for your help

symbit19:01:46

.. trying to write a function to take a list of sorted joda weekday dates and group them into full (5) weekday subvectors. When weekdays are skipped/missing that whole week should be excluded. It seems to have some likeness to partition-by and take-while. Any help is welcome. Thanks!

jonahbenton19:01:33

@symbit joda time should have a week of year fn, so you could partition on that, exclude groups with less than 5 members, concat the remaining groups and then partition by day of week

symbit19:01:24

@jonahbenton good idea. Thanks. (clj-time.core/week-number-of-year (clj-time.core/date-time 2016 1 14))

symbit20:01:35

`(->> xs (partition-by c/week-number-of-year) (filter #(= (count %) 5)))`

symbit20:01:12

@jonahbenton: works thanks for the tip!

jonahbenton20:01:18

@symbit sure thing good luck!

arcdrag20:01:36

Are all dates in the same year?

arcdrag20:01:15

If your sequence went something like Jan-1, 2014, Jan 2nd 2015, Jan 3rd 2016, Jan 4th 2016, Jan 5th 2016 you might get a false positive.

ezmiller20:01:00

How can I swap out a single value in an atom that contains a map?

ezmiller20:01:54

For example, if I have (def app-atom (reagent/atom {:text “some text” :name “some name"})), how would I swap just the name?

lvh20:01:01

michaeldrogalis: Is this the best place to ask questions about Onyx, or the Gitter/somewhere else?

tord20:01:23

@ezmiller: Is (swap! app-atom assoc :name "some other name") what you want?

ezmiller20:01:49

Can you explain that code? Why is the assoc not surrounded by parens?

tord20:01:46

That's simply how swap! works. It takes an atom, a function (here, assoc) and a number of arguments that should be passed to this function along with the value of the atom.

tord20:01:05

It was a little confusing for me too in the beginning.

jaen20:01:50

This is equivalent to (swap! app-atom #(assoc % :name "some other name")) if that helps.

jaen20:01:08

The function is just written so that you can omit the parens for readability.

tord20:01:28

In general, (swap! some-atom some-function arg-1 arg-2 arg-3) is simply shorthand notation for (reset! some-atom (some-function @some-atom arg-1 arg-2 arg-3).

ezmiller20:01:33

This is very helpful

jaen20:01:34

@tord I don't think that's strictly true

michaeldrogalis20:01:36

@lvh: #C051WKSP3 or Gitter, I usually have both open.

jaen20:01:54

Atoms have different methods handling reset! and swap!

jaen20:01:44

(probably because the equivalent you wrote doesn't guarantee that some-function will get the current value of the atom at the time you try to commit into STM)

jaen20:01:50

But nonetheless it's still a useful way to think about that.

tord20:01:52

@jaen: Interesting. Is this just an optimization, or are the cases where the two expressions give different results?

jaen20:01:18

I'm no Clojure internals guru, but I imagine that with high contention you could get inconsistent results.

tord20:01:42

Makes some sense, yes. Thanks for pointing this out.

jaen20:01:13

for(; ;) is pretty interesting; does that force a synchronisation point or what?

jaen20:01:14

Ah lol, of course

jaen20:01:25

It just loops until the CAS succeeds.

jaen20:01:06

Yeah it is, was just confused at first, didn't have to do much low-level threading in my life

arcdrag21:01:45

Maybe I’m missing it in the docs, but is there a way to turn off shrinking for a test.check test?

michaeldrogalis21:01:33

@arcdrag: You turn it off per generator, I believe. (gen/no-shrink)

arcdrag21:01:09

Awesome, that’s what I was looking for. Thanks.

shriphani23:01:09

Hi, I am curious if folks here use a linter for their clojure code.

shriphani23:01:37

I’ve tried one (eastwood) and it crashed.