Fork me on GitHub
#beginners
<
2021-10-04
>
zackteo07:10:12

I'm trying to get this example working in Clojure https://developers.line.biz/en/reference/messaging-api/#send-push-message

final LineMessagingClient client = LineMessagingClient
        .builder("<channel access token>")
        .build();
but I can't seem to get the above working. my first instinct was
(def client (-> (LineMessagingClient.)
                (.builder channel-access-token)
                .build))
but seems like there is no constructor https://javadoc.io/doc/com.linecorp.bot/line-bot-api-client/latest/com/linecorp/bot/client/LineMessagingClient.html Should I be using something like proxy etc. (Also I feel that Spring Boot examples tend to make Java interop less direct)

Lennart Buit08:10:19

builder looks like a static method, so perhaps (LineMessagingClient/builder "<channel access token>")

zackteo08:10:30

Thanks @lennart.buit you were right! 😄

popeye10:10:44

I was looking into mount example mentioned here https://github.com/tolitius/mount/blob/master/dev/clj/app/example.clj#L17 , we are not passing any argument to (mount/start) how all state will be initialised here ?

popeye11:10:41

Does start just takes number of states present in namespace? according to https://github.com/tolitius/mount#recompiling-namespaces-with-running-states

Ben Sless14:10:21

This is an opinion, but if you're just starting I recommend against using mount

Ben Sless14:10:33

Start takes states explicitly or starts them implicitly by the order of require-s

popeye14:10:17

Which one I can use?

Ben Sless14:10:04

In my opinion, start with Component

popeye14:10:01

Next I was planning to learn it

Old account11:10:04

How can I make (.plus (Instant/now) EXPIRY_DAYS ChronoUnit/DAYS) human readable?

popeye11:10:22

Do you need something like ?

(-> ChronoUnit/DAYS
    EXPIRY_DAYS
    (Instant/now)
    .plus)

Old account11:10:56

😄I mean when printing out

popeye11:10:02

are they three parameters you are passing? or calling function one by one

Old account11:10:55

(prn (.plus (Instant/now) EXPIRY_DAYS ChronoUnit/DAYS))

Maravedis11:10:47

NOt sure if it's what you're looking for, but I strongly recommend https://github.com/dm3/clojure.java-time, which is super easy to use, comes with formatters, easy to use functions and much more. I love it.

Maravedis11:10:53

Your code would be re-written as:

(plus (instant) (days EXPIRY_DAYS))
And if you want to format it :
(-> (instant)
    (plus (days EXPIRY_DAYS))
    (format))

sova-soars-the-sora02:10:17

I did something pretty hacky a while ago to make Date. more readable:

(defn v-time [timestamp]
  (let [dos (java.util.Date. timestamp)]
    (str (subs dos 0 10) " " (subs dos 24 48) " " (subs dos 10 20))))

sova-soars-the-sora02:10:43

You pass in unix time and you get something "human readable" out

Jelle Licht11:10:33

I wrote a library with quite some namespaces; what is the most idiomatic way to offer a (ns mylib.porcelain)that simply re-exports most of the relevant functions and macros? I looked at intern, which doesn’t seem to work for macros, and I looked at simply re-`def`/`defmacro`-ing everything.

Lennart Buit12:10:47

There are tools for this, but personally, I’d say write your ‘api’ in an .api or .core namespace in plain old Clojure. Re-exporting comes with lots of tool caveats (for one, Cursive doesn’t understand re-exported vars).

1
Jelle Licht12:10:34

The no-magic, no surprises approach sounds appealing indeed, thanks!

Lennart Buit12:10:31

obvious code is best code 🙂

pavlosmelissinos12:10:18

> I looked at simply re-`def`/`defmacro`-ing everything I agree, this is fine. It's your API, it's better to devote some of your time to it and be explicit about how you expect the users to use your library. I'd suggest that you also consider defn instead of def. def might seem like less effort because you don't have to type as much but with defn you can have different docstrings for the users vs for contributors and maybe even (slightly) different signatures, which can be useful.

noisesmith15:10:42

both def and defn will ignore the original doc string, and require adding a new one

pavlosmelissinos16:10:06

Right, didn't realize that def can also have a docstring, thanks. That makes sense actually.

noisesmith17:10:09

and with either def or defn you can copy the metadata of the original as part of the declaration

noisesmith17:10:42

or maybe it's simpler with intern actually

(cmd)noisesmith.gui=> (intern *ns* (with-meta 'my-conj (meta #'conj)) conj)
#'noisesmith.gui/my-conj
(cmd)noisesmith.gui=> (doc my-conj)
-------------------------
noisesmith.gui/my-conj
([coll x] [coll x & xs])
  conj[oin]. Returns a new collection with the xs
    'added'. (conj nil item) returns (item).  The 'addition' may
    happen at different 'places' depending on the concrete type.
nil

fabrao17:10:32

Hello all, How do I access

public class GoogleAuthorizationCodeFlow { ....
   public static class Builder extends AuthorizationCodeFlow.Builder
   {
      public Builder(HttpTransport transport, JsonFactory jsonFactory, GoogleClientSecrets clientSecrets, Collection<String> scopes)
      { ....
? (GoogleAuthorizationCodeFlow$Builder/Builder. HTTP_TRANSPORT JSON_FACTORY (generate-secrets) SCOPES) ?

fabrao17:10:29

oh, I missed GoogleAuthorizationCodeFlow$Builder declaration

fabrao17:10:07

why casting to other class it show source class?

(:import [com.google.api.client.json JsonFactory]
   [com.google.api.client.json.gson GsonFactory])

(def JSON_FACTORY (cast com.google.api.client.json.JsonFactory (GsonFactory/getDefaultInstance)))

(type JSON_FACTORY) -> com.google.api.client.json.gson.GsonFactory 
why?

emccue18:10:05

cast doesn't change anything - it just adds an assertion to the compiled bytecode

emccue18:10:32

if you were to do the same thing in java you'd get the same behavior

emccue18:10:59

(defn type 
  "Returns the :type metadata of x, or its Class if none"
  {:added "1.0"
   :static true}
  [x]
  (or (get (meta x) :type) (class x)))

(defn class
  "Returns the Class of x"
  {:added "1.0"
   :static true}
  ^Class [^Object x] (if (nil? x) x (. x (getClass))))

emccue18:10:36

JsonFactory JSON_FACTORY = (JsonFactory) GsonFactory.getDefaultInstance();
System.out.println(JSON_FACTORY.getClass());

emccue18:10:16

in the context of clojure cast lets you avoid some reflection calls

hiredman18:10:17

clojure.core/cast is pretty much never what you want

fabrao18:10:23

the problem is that the Builder won´t recognize the ctor

fabrao18:10:50

No matching method Builder. found taking 4 args for class com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow$Builder

schmee18:10:25

@U0YJJPFRA does the ctor have a varargs parameter?

fabrao18:10:30

ctor is that Builder does not fit with args

hiredman18:10:36

you aren't calling a constructor

hiredman18:10:03

you are calling a method named Builder on the class com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow$Builder and passing it 4 arguments

hiredman18:10:57

you want something like (com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow$Builder. 1 2 3 4) not whatever you are doing

hiredman18:10:44

(you added an extra /Builder in there, which is syntax for calling a static method)

fabrao21:10:16

oh, yes, you right

orpheus18:10:40

Hey guys/gals. I ran into this discussion https://stackoverflow.com/questions/7491360/how-do-you-return-from-a-function-early-in-clojure#:~:text=There%20isn't%20a%20return,something%2C%20in%20these%20cases%20nil%20. and the accepted answer says if your algorithm needs a return statement, it's a major code smell. I thought I needed a return statement for what I’m trying to do, and was wondering if someone could point me to a better way of writing this: I’m looping through a vector using doseq to save files from an http request, but if one of those looped objects is themselves a vector and not a map, I wanted to ‘return’ or ‘throw’ a bad-request. But do-seq returns nil so my (if (vector? file) (bad-request "Not a map") doesn’t actually return and make it to the http-response. Any suggestions?

orpheus18:10:23

(defn handle-file-upload [params]
  (if (vector? (params :file))
    (doseq [file (params :file)]
      (if (vector? file)
        "Cannot parse request body. Found a vector within the file vector. Expected maps.\n"
        (copy-file-local file))
      )
    (if (map? (params :file))
      (copy-file-local (params :file))
      "Expected file request to be a map.\n"))
  )

(defn upload-route []
  (wrap-multipart-params
   (POST "/upload" {params :params}
         (let [res (handle-file-upload params)]
           (if (nil? res) (response "File uploaded\n")
               (bad-request res)))
         )))

emccue18:10:05

so there are a few approaches

emccue18:10:09

the most manual - loop

emccue18:10:48

(if (vector? (params :file))
  (loop [[file & rest] (params :file)]
    (if (vector? file)
      "Cannot parse request body. Found a vector within the file vector. Expected maps.\n"
      (do 
        (copy-file-local file)
        (recur rest)))
  ...)

emccue18:10:10

a little less manual - reduce and reduced

emccue19:10:13

(reduce
  (fn [_ file]
    (if (vector? file)
      (reduced "Cannot parse request body. Found a vector within the file vector. Expected maps.\n")
      (copy-file-local file)))
  (params :file))

emccue19:10:44

both work fine

orpheus19:10:56

Sweet, thank you very much for this.

orpheus19:10:25

So if you don’t recur a loop it won’t continue?

emccue19:10:45

and recur needs to be in tail position

1
emccue19:10:51

my code there might be a bit wrong - i think you need to check if file is nil which happens at the end w/ the loop - but i think it still shows you some ways to do what you want

orpheus19:10:11

Yes it does, I just read through loop and reduced in the docs, just what I was looking for thank you. A little surprised there isn’t a foreach macro, I guess that’s pretty much just a loop ?

George Silva19:10:28

Hello Friends! I just made my first API with compojure-api and it is very very cool. Just wanted to thank everyone for the support. The Clojurians community is amazing and I always get a lot of cool tips here.

👆 2
🎉 1
George Silva19:10:34

Of course it's super silly and stupid, but I can change an atom from the outside world.

George Silva19:10:48

(ns econ.core
  (:require [compojure.api.sweet :refer :all]
            [ring.util.http-response :refer :all]
            [schema.core :as s]))

(s/defschema Transaction {:amount s/Num
                          :account s/Str
                          :type (s/enum :outbound :inbound)})


(def transactions (atom []))


(defn add-transaction [transaction]
  (swap! transactions conj transaction))


(def app
  (api
   :swagger
   {:ui "/"
    :spec "/swagger.json"
    :data {:info {:title "Econ API"
                  :description "Econ API Documentation"}
           :tags [{:name "api" :description "Econ API documentation."}]}}

   (context "/api" []
     :tags ["api"])

   (GET "/transactions" []
     :return [Transaction]
     :summary "Returns all transactions"
     (ok @transactions))
   (POST "/transactions" []
     :return Transaction
     :body [transaction Transaction]
     :summary "Echoes a transaction"
     (do
       (add-transaction transaction)
       (ok transaction)))))

Andrei Stan19:10:42

Hello guys, i struggle finding a way to filter the first vector, with the pred: • name_A = name_B, but age_A not= age_B

(let [list-A [{:name "unique_A_name" :age "99"} {:name "joyce" :age "25"} {:name "connor" :age "32"} {:name "brad" :age "21"}]
      list-B [{:name "joyce" :age "77"} {:name "connor" :age "60"} {:name "brad" :age "21"}]]
<filter?! function here>)
the expected result is a list of items that have same :name but different :age  ({:name "joyce" :age "25"} {:name "connor" :age "32"})
Thank you in advance!

pyry19:10:14

Struggling to find a way to filter the items suggests that you might want to structure your data differently, if it's in your control.

pyry19:10:05

Do you explicitly want the returned list be a filtered version of list-B (ie. in the same order)?

pyry19:10:46

One approach would be to (group-by :name list-A) and then check elements of list-B against that.

dgb2319:10:19

(let [list-A [{:name "unique_A_name" :age "99"} {:name "joyce" :age "25"} {:name "connor" :age "32"} {:name "brad" :age "21"}]
      list-B [{:name "joyce" :age "77"} {:name "connor" :age "60"} {:name "brad" :age "21"}]]
  (filter (fn [person]
            (some #(and (not= (:age %) (:age person))
                        (= (:name %) (:name person))) list-B))
          list-A))

dgb2319:10:33

the above is inefficient/brueforce though

dgb2319:10:18

but you can take it as a baseline to make it less wasteful maybe

dgb2319:10:24

and yes my instinct is also what @UCYS6T599 said, the datastructure feels wrong. It sounds like you want to deal with relations here (sets of maps) and maybe some of the clojure.set operations, depending on the context surrounding that code.

dgb2319:10:37

take a peek here if you didn’t have already, might be useful: https://clojuredocs.org/clojure.set

emilaasa19:10:00

This is a nice tutorial on creating lookup maps which are generally very useful in my day to day job; https://www.youtube.com/watch?v=n0BTsKVs1Lw

emilaasa19:10:26

(into {} (map (juxt :name identity) list-b)) might be how I'd start if I was solving the above problem

☝️ 1
dgb2320:10:35

sorry I couldn’t figure out a better data structure. but I edited my above suggestions to be a bit more efficient. It works but I think there must be something more elegant and efficient.

Fredrik22:10:34

I second finding a representation of your data more amenable to the kinds of queries you'd like to do. If that's not an option, you can get quite expressive using clojure.set. The following

(set/difference (set/join list-A list-B {:name :name})
                                    (set/join list-A list-B {:name :name :age :age}))
returns a set of the values in list-A you want to keep. You can convert this into a vector, or, to preserve order, use this set as a predicate with filter.

Andrei Stan17:10:39

thank you all for your time and effort,

(let [list-A [{:name "unique_A_name" :age "99"} {:name "joyce" :age "25"} {:name "connor" :age "32"} {:name "brad" :age "21"}]
      list-B [{:name "joyce" :age "77"} {:name "connor" :age "60"} {:name "brad" :age "21"}]]
  (filter (fn [person]
            (some #(and (not= (:age %) (:age person))
                        (= (:name %) (:name person))) list-B))
          list-A))
@U01EFUL1A8M’s solution works for me

Andrei Stan17:10:34

i will try the other solutions also and read the links provided. Thanks

Fredrik17:10:04

As long as all names are unique,@U01EFUL1A8M's solution will work perfectly. My solution is actually not correct, due to how set/join can pick a key's value from either list.

Fredrik17:10:07

If a name can appear more than once in list-B, you need to deal with that somehow. I don't know if that's a possible scenario for your code.

(let [n (group-by :name list-B)
      na (group-by (juxt :name :age) list-B)]
  (filter (fn [person]
            (and (get n (:name person))
                 (nil? (get na (juxt :name :age person)))))
          list-A))