Fork me on GitHub
#beginners
<
2017-08-30
>
donyorm02:08:23

So I have this sort of statement in an let statement. Is there any better/more idomatic way to conditionally accept an object? I know of if-let but if I understand it right it wouldn't work in this situation, since I want the img object itself, not the result of .isError.

(let [url-img (Image. url)
          img (if-not (.isError url-img)
                url-img
                (Image. (.toString (io/resource config/missing-image-location))))]
;;code using img (url-img is not used) here
)

noisesmith16:08:32

just a semantic nitpick, clojure doesn’t have statements (let and if-not are expressions, they return values)

Chris Bidler03:08:03

(let [url-img (Image. url)
      img  (if (.isError url-img)
            (Image. (.toString (io/resource config/missing-image-location))))
             url-img)]
;;code using img (url-img is not used) here
)
maybe?

Chris Bidler03:08:22

wow it’s really a challenge to get the monospace spacing right when you copy/paste into the non-monospace edit box 😬

shaunlebron03:08:30

@donyorm a small function is idiomatic here:

(defn safe-img [url]
  (let [img (Image. url)]
    (if-not (.isError img)
      img
      (Image. (.toString (io/resource config/missing-image-location))))))

(let [img (safe-img url)]
  ;; code using img
  )

emilaasa10:08:32

More newbie time! I want a function that takes a map, and depending on a integer value n in that map returns a new map with an appropriate key added.

;; If n =< 1, return {:n 1 :red}
;; If n > 1 AND n =< 2, return {:n 2 :orange}
;; If n > 2, return {:n 3 :green}
How do I construct such a function in a clojure/lispy way?

emilaasa10:08:51

Also I'm looking for a resource that answer these types of newbie questions 😃

emilaasa10:08:38

To clarify, the part I'm struggling with is how do conditionally return data

sundarj11:08:07

http://clojuredocs.org/clojure.repl/find-doc is handy for answering these types of questions

roosta11:08:11

@emilaasa

(defn cond-ret
  [{:keys [n] :as in}]
  (cond
    (<= n 1) (assoc in :color :orange)
    (and (> n 1) (<= n 2)) (assoc in :color :red)
    (> n 2) (assoc in :color :green)
    :else "Something wrong happened"))

(cond-ret {:n 2})

emilaasa11:08:02

Lol find doc is awesome

emilaasa11:08:10

This language feels like cheating

sundarj11:08:17

hahah, tbh a language should feel like cheating 😄

emilaasa11:08:50

Damn I need a comprehensive noob book

emilaasa11:08:03

maybe I should read the braveclojure one a bit better >D

sundarj11:08:49

@emilaasa i can recommend Joy of Clojure, though it's quite a bit more in-depth than Brave

emilaasa11:08:21

I usually have to bash my head against a reference style book for a while before I feel really comfortable!

sundarj11:08:45

no shame in that :~)

emilaasa11:08:22

Nah you have to be shameless to be an effective newbie! 😃

emilaasa11:08:53

I really appreciate the support here, my first few days of trying clojure has been great in no small part because of the slack and discord

genmeblog12:08:06

question: I have list of sequences containing numbers, I want to get one resulting sequence as a sum input sequences by consequtive values

genmeblog12:08:38

ex. [ [1 2 3] [1 1 1] [9 8 7]] -> [11 11 11]

Lucas Barbosa12:08:16

@tsulej (apply map + [[1 2 3] [1 1 1] [9 8 7]])

Lucas Barbosa12:08:35

although this will give you a lazy-seq

Lucas Barbosa12:08:45

I don’t know if there’s a direct way to produce a vector

genmeblog12:08:07

omg, obvious... thx!

genmeblog12:08:11

I don't need vector

Lucas Barbosa12:08:18

there is, mapv instead of map

daiyi13:08:15

hello! what's a nice way to get a collection or primitive's type as a string? using clojure.core/type gives a function, and then I'm not sure how to get the name of that function into a human-readable string

(type []) ;; => cljs.core/PersistentVector
(str (type[]))  ;; => "function (meta,cnt,shift,root,tail,__hash){\nthis.meta = meta;\nthis.cnt = cnt;\nthis.shift = shift;\nthis.root = root;\nthis.tail = tail;\nthis.__hash = __hash;\nthis.cljs$lang$protocol_mask$partition0$ = 167668511;\nthis.cljs$lang$protocol_mask$partition1$ = 8196;\n}"

daiyi13:08:50

if I use str on the function returned by type doesn't give me the kind of human-readable name I'd like to have (':

daiyi13:08:10

oh wait I need to ask this in #clojurescript I think

Drew Verlee13:08:07

can someone show me an example where the reduction thats part of a transducer that counts the number of items?

stvnmllr214:08:53

Any chance there is a built-in function to do

[[[:a] [:c]] [[:b]]]
->
[[:a] [:c] [:b]]

Sam H14:08:17

apparently flatten1 works:

cljs.user=> (flatten1 [[[:a] [:c]] [[:b]]])
([:a] [:c] [:b])
@stvnmllr2

stvnmllr214:08:36

wow! thanks @shan glad I asked

Sam H14:08:10

found it after trying flatten and then searching for any other functions that were similar using (find-doc "flatten")

stvnmllr214:08:14

wait. where is flatten1?

Sam H14:08:24

oh, might be a cljs thing

stvnmllr214:08:37

well.. that's even better. Because that's were i'm using it 🙂

stvnmllr214:08:50

just tried clojure first

Sam H14:08:40

I usually use lumo for a quick repl, which is based on cljs.

stvnmllr214:08:06

Thanks. I'll look into that. On windows so never got a js repl working. But lumo say it works. so will check it out.

jeeq14:08:09

Hi not necessarily clojure question but I’m going over web dev with clojure book (ch 7 database) - the example uses Jdbc4Array (org.postgresql.jdbc4.Jdbc4Array) but it seems that class was deprecated v42 onwards. I can’t seem to find any reference to what to use or even mention of it in changelog (https://jdbc.postgresql.org/documentation/changelog.html#version_42.0.0) Anybody know what happened to it?

jeeq15:08:09

ah cool. I ended up using org.postgresql.jdbc.PgArray as it had similar api. it seemed to work for me. thank you! I didn’t realize I could check pgjdbc (actually, didn’t know that existed) 🙂

Lucas Barbosa15:08:17

Where do you guys draw the line between :require and :use? What should I refer into the current namespace? Is there any rules/good practices to follow?

dpsutton15:08:43

use require with an alias

dpsutton15:08:57

(:require [clj-http.client :as http]
            [cheshire.core :as json]
            [buddy.sign.jwt :as jwt]
            [buddy.sign.jwe :as jwe]
            [buddy.core.keys :as ks]
            [clj-time.core :as t]
            [clj-time.coerce :as convert])

Sam H15:08:22

I liked this blog post that had some opinions on readable clojure: http://tonsky.me/blog/readable-clojure/#dont-use-use

Lucas Barbosa15:08:16

Thanks! I like the idea of always using qualifiers better than trying to figure out where stuff is coming from

vinai15:08:32

For example, aggregate-history might look like this:

{"1" [{:event :bar, :data {:id "1"}}
      {:event :baz, :data {:payload "whatever}}]}

Sam H15:08:01

so line 3 is printing something out but the for is skipping?

vinai15:08:23

The above output is what is printed on line 3.

Sam H15:08:01

not sure if for works with maps as I think it’s expecting a seq

sundarj15:08:09

for is lazy

sundarj15:08:24

you should use doseq for side-effects

vinai15:08:25

I thought for was for side effects.

Sam H15:08:41

ah yeah, nice spot

vinai15:08:08

Yess, thanks @sundarj!

sundarj15:08:15

no worries

vinai15:08:36

´doseq` requires a vec but dorun works with the lazy list.

ghadi15:08:45

doseq does not require a vector

vinai15:08:46

Thanks very much!

ghadi15:08:13

otherwise it would be called dovec simple_smile

vinai15:08:27

I get a doseq requires a vector for its binding in

ghadi15:08:11

what that means is that you wrote:

(doseq seq ....)
instead of
(doseq [elem seq]
  (do something with elem))

vinai15:08:42

Ah, okay. I wrapped the for in the doseq. Thanks again

vinai15:08:50

(doseq (for [x [:a :b :c]]))

sundarj15:08:02

doseq works like for, but for side-effects

ghadi15:08:32

right. doseq throws away the results of calling a side effect on each element

vinai15:08:34

Okay, I hope I learned that now 🙂

vinai15:08:44

Much appreciated!

vinai15:08:48

I was stumped.

ghadi15:08:50

no problem

rinaldi16:08:27

What's the best way to make a Clojure binary available on a package registry? Comparing with Node.js, if I want to install a CLI foo I can just do npm i foo -g and have it available in $PATH right away (there's a bin key on the manifest that can point to a JavaScript file to be compiled as a binary). What is the best practice to achieve the same result in Clojure?

akiroz16:08:59

@rinaldi AFAIK, there's no easy way to do this in Clojure, the best way I can think of is to put dependencies in the global lein profile like:

;; ~/.lein/profile.clj
{:user {:dependencies [[your-app "1.0.0"]]}}
then run:
lein run -m your-app.main
lein will run the -main function inside the your-app.main namespace

akiroz16:08:30

Clojure is probably not the best language for writing CLI tools since it takes so long to start up...

akiroz16:08:04

You could do it in ClojureScript using the Lumo runtime (based on node.js) but there's no standard way to install stuff from a repo.

driphter16:08:13

The most similar solution to using npm would be using Clojurescript with node/npm 😛

Chris Bidler16:08:54

But I think what @rinaldi is asking about isn’t how to create a binary in say, Planck or Lumo, but rather whether there’s something akin to NPM that lets you register a Lumo binary

Chris Bidler16:08:20

like imagine being able to type cljpm i -g nyancat-repl at a prompt and pull down from Clojars someone else’s awesome Lumo binary that runs a CLJS repl with Nyancat in it somehow

Chris Bidler16:08:11

it’s totally possible to build a pretty darn fast CLI app with Lumo but the registry to publish, discover, download those things doesn’t exist for the Clojure or Clojurescript ecosystem, AFAIK

driphter16:08:26

@chris_johnson Couldn't you just target nodejs with Clojurescript though? I suppose there's also the usual general purpose package managers (pacman, apt, homebrew, chocolatey, etc.) as well.

Chris Bidler16:08:04

oh, I see - so build a Lumo thing and put it on npm

Chris Bidler16:08:22

I suppose that could work, I haven’t tried it so I offer no guarantee 🙂

driphter16:08:27

It doesn't have to be Lumo specific

Chris Bidler16:08:27

right, but the original question was about adding CLI binaries and that’s Lumo’s wheelhouse (or Planck’s)

akiroz17:08:49

you can also require users to install lumo via npm: npm i -g lumo my-app then execute your cljs files using lumo:

#!/usr/bin/env lumo
(ns my-app.core)
(println "Hello World!")
set your package.json's bin to core.cljs

Lucas Barbosa17:08:27

Guys, I’m playing around with Ring and Compojure to craft a web service. I’m thinking about how to approach authentication and authorization. At first, I thought about using middlewares, because I’m used to deal with these topics in Java and JAX-RS using ContainerRequestFilters. But now, I realized that those filters in JAX-RS are post match filters, and Ring middlewares are pre match, right? If I’m not wrong about this, then how should I approach authentication and authorization? Should I invoke a function inside every handler that needs them? Or maybe wrap the handlers themselves inside of the auth functions, like this: (GET "secret/" request (wrap-auth handler))

akiroz17:08:50

@lvbarbosa middlewares are exactly functions that wraps handlers

Lucas Barbosa17:08:47

@akiroz but aren’t they intended to be used like this? (wrap-auth (GET "secret/" request handler)) instead of this (GET "secret/" request (wrap-auth handler))?

akiroz17:08:20

they are the same, GET works like a middleware too

akiroz17:08:38

well, the order is not the same, but you get the idea

Lucas Barbosa17:08:06

What if, in the second form, the wrap-auth function is invoked and the requesting user is not authorized?

Lucas Barbosa17:08:15

Let me reformulate the question

Lucas Barbosa18:08:26

Facts: 1. Let’s say I have two routes, specified to the application exactly in this sequence: secret and not-secret; 2. The secret endpoint is wrapped inside the wrap-auth middleware, which checks the HTTP headers for a token, whatever, like this: (wrap-auth (GET "secret/" request handler)); 3. I am not authorized to access the secret endpoint. Usage: If I issue a request to the not-secret endpoint, the handler of secret will be tried first, won’t it? Because of the order I specified them (in defroutes, let’s say) Since the wrap-auth is invoked and I get a big UNAUTHORIZED as a response, Compojure will stop trying to match the routes, since a non-nil value was returned. This is what I am calling a pre match filter. I am assuming that putting the middleware after the route will make it post match and avoid the premature termination, like this: (GET “secret/” request (wrap-auth handler)) Am I missing something?

Lucas Barbosa18:08:47

Does it make sense at all? Maybe I got everything wrong

rinaldi18:08:51

@akiroz @chris_johnson @mfikes @driphter Thank you for your input. Distributing a ClojureScrpit binary via npm sound feasible. I've seen people do that. I guess I'm gonna write this CLI in Go then 🙂

akiroz18:08:03

@lvbarbosa oh, that's right, your auth middleware returns an unauthroized response instead of nil, you'll need to wrap it after the GET

Lucas Barbosa18:08:04

@akiroz do you think that is a good place to put the auth-dealing code?

akiroz18:08:24

If you have a path prefix that needs auth, you can do:

(context "/secret" []
  (auth-middleware
    (routes
      (GET ...)
      (POST ...)
      )))

Lucas Barbosa18:08:06

I’ve tried to find more information on the Compojure documentation, but I did not find anything. I am also a little bit afraid, because I don’t know how the GET macro works. Will it return nil automatically if the route isn’t matched? I also tried to read the code for the GET macro in the github repo, but it was too complicated for me since I’m a beginner

Lucas Barbosa18:08:04

Oh, that’s nice.. I didn’t associate the use of contexts and middleware. It will be nice to aggregate secure routes together

akiroz18:08:29

yeah, I think this is one of the weaknesses of compojure. data > functions >>> macros

dadair18:08:17

is there an idiomatic way of achieving [[:a :b :c] [:a :b] [:a]] given [:a :b :c]?

noisesmith18:08:07

perhaps (take-while seq (iterate rest [:a :b :c]))

noisesmith18:08:08

oh, wrong direction, you want drop-last

noisesmith18:08:13

drop-last for lazy-seq or list, but pop works for vectors (and is more efficient)

dadair18:08:44

awesome, thanks @noisesmith!

hmaurer20:08:57

Quick question: is it acceptable to ask for a quick review of some code on gist here?

hmaurer20:08:11

for learning purposes (e.g. am I doing anything silly)

sundarj20:08:37

well, i would say so

hmaurer20:08:00

In that case I would appreciate if anyone can take a look at this (very simple) code: https://gist.github.com/hmaurer/6ae4142be2bb9dc43f20bb80f079de38 🙂

sundarj20:08:11

looks pretty good to me, though i am by no means an expert

sundarj20:08:33

only thing i would say is, i personally would use destructuring more

sundarj20:08:11

also maybe having the datomic/entity call inside pull-extra-info is a bit of a complecting

sundarj20:08:27

(nit-picking)

eggsyntax23:08:17

A few minor suggestions from a very quick read-through, some of which are purely personal preference: - I would tend to pull a helper fn or two out of init-attributes so that init-attributes is more quickly readable. - A couple of your if and if-let would be better as when and when-let. - I’d be tempted to pull out a little helper fn that captures something like (when <something> (throw (Exception. (str <something-else>)))), possibly with the doseq as well if it generalizes well to validate-ref-attribute. Or I might try it & then decide it’s not a big-enough simplifier, and pull it back out. throw-when maybe? - Definitely second @sundarj on the destructuring — eg the let statement in validate-ref-attribute. You might be able to replace one or two of your if-let with that, in cases where nil-punning would work OK. - In general, looks good!

hmaurer09:08:44

@sundarj @U077BEWNQ thanks to both of you, that was very helpful 🙂

rgdelato21:08:16

is there an easy way to turn a JS object into a CLJS ordered map such that key order is preserved?

moogey22:08:06

I don’t think key order is guaranteed in JS objects.

rgdelato22:08:35

it's not guaranteed in the spec, though it tends to be preserved in practice

hmaurer22:08:53

@rgdelato I know this isn’t helping with your question, but why do you need to reply on the order of properties in an object?

hmaurer22:08:14

it seems a bit brittle; from what I gather even though order is preserved in most browsers the actual order may vary from implementation to implementation

rgdelato22:08:50

So I wrote a one-off script that took some JSON files and generated a CSV file... and now that a bunch of data has been entered into that CSV document, I'm hoping to write another one-off script to turn it back into a JSON file again So yeah, it doesn't need to be robust, it just needs to work once. 😄

hmaurer22:08:56

@rgdelato granted that’s not the cleanest option, but you could convert your object to a list of tuples