Fork me on GitHub
#beginners
<
2019-02-07
>
Ajay04:02:12

Hi, I am struggling to understand what is wrong with this piece of code, (.withBody (.withHeader (.withStatus (WireMock/aResponse) 200) "Content-Type" "application/json;charset=UTF-8") "{'abc': 'xyz'}"), 1. I get an exception - Execution error (ClassCastException) at ... java.lang.String cannot be cast to [Ljava.lang.String;, I do not understand why this exception comes. 2. I am trying to follow the first Java example here - http://wiremock.org/docs/getting-started/ 3. Generally how do you debug these cases

seancorfield04:02:50

@ajay.rivendell The most likely cause is that one of the (Java) methods you're calling is variadic and has a signature with String... which actually means an array of strings, not zero or more strings.

Ajay04:02:04

Ok, let me check that ...

dpsutton04:02:57

I'm assuming it's the with headers method

seancorfield04:02:30

It would be a lot easier to figure out if they had a simple JavaDoc API website but I can't find that!

5
Ajay04:02:28

and I found this through clojure.java.javadoc

seancorfield04:02:14

My link was to the actual source code.

Ajay04:02:04

Ok, got it now! Thank you! 👍:skin-tone-3:

seancorfield04:02:15

So it needs to be (.withHeader (..) "Content-Type" (into-array String ["application/json;charset=UTF-8"]))

seancorfield04:02:26

Horrible Java "builder" patterns! Ugh!

🙂 5
seancorfield04:02:37

LMK if that works.

Ajay04:02:23

yes ... trying it now

Ajay04:02:12

it worked 🍻, thank you!

caleb.macdonaldblack05:02:11

Can a transducer be made to take 1 element and split it into n number of elements and put them on the queue?

caleb.macdonaldblack05:02:54

[{:a 1 :b 2}] -> [{:a 1} {:b 2}]

Alex Miller (Clojure team)05:02:32

user=> (into [] (mapcat #(map (fn [e] (apply hash-map e)) %)) [{:a 1 :b 2} {:c 3 :d 4}])
[{:a 1} {:b 2} {:c 3} {:d 4}]

Alex Miller (Clojure team)05:02:30

only top level is transducing here, inner is not

caleb.macdonaldblack05:02:46

Nice solution. I should have expanded upon my expected output. The logic for splitting will need to be hard coded. Some keys in the map will duplicate (Specifically a timestamp & a device id) and some will split (different types of readings for the timestamp & device).

caleb.macdonaldblack05:02:32

However it's good to know mapcat is what I need here

Alex Miller (Clojure team)05:02:06

yeah, mapcat is the main “expanding” transducer

caleb.macdonaldblack05:02:35

I managed to do it with mapcat. the keys a & b will be hard coded so there is no way for me to simplify it further

seancorfield06:02:24

@caleb.macdonaldblack You can parameterize the splitter like this

user=> (defn split-keys [ks] (apply juxt (map #(fn [m] (select-keys m [%])) ks)))
#'user/split-keys
user=> ( (split-keys [:a :b]) {:a 1 :b 2} )
[{:a 1} {:b 2}]
user=>         

juxt 5
seancorfield06:02:33

So you can define your splitter function for any set of keys, and then do

(eduction 
  (comp
    (map splitter)
    (mapcat identity))
  [{...} {...}])

seancorfield06:02:38

And you can get your total sequence of unique keys to feed to split-keys by (set (mapcat keys [{...} {...}]))

caleb.macdonaldblack06:02:32

@seancorfield That splitter is a great idea. However, i need some keys not specified to stay. So I modified your solution to the following which works for me now

(defn split-keys [ks]
  (apply juxt 
    (map
      #(fn foo [m]
         (select-keys m (cons % (set/difference (set (keys m)) ks))))
      ks)))
((split-keys [:a :b]) {:a 1 :b 2 :c 3})
=> [{:a 1, :c 3} {:b 2, :c 3}]

caleb.macdonaldblack06:02:45

So ultimately I end up with something like this. I'm really happy with how this turned out

(defn- ->device-event-row [id timezone]
  (fn [{:keys [data.interval/datetime] :as row}]
    (let [[k v] (first (dissoc row :data.interval/datetime))
          [read-type uom] (str/split (name k) #"-")
          uom (str/upper-case uom)]
      {:timestamp datetime
       :value     v
       :read-type read-type
       :uom       uom
       :timezone  timezone
       :device-id id})))

(def batch-n 1000)

(defn split-keys [ks]
  (apply juxt
    (map
      #(fn foo [m]
         (select-keys m (cons % (set/difference (set (keys m)) ks))))
      ks)))

(def row-splitter
  (split-keys [:data.interval/energy-wh :data.interval/demand-kva :data.interval/power-w]))

(defn batch-rows [{:keys [device/id device/timezone]} meter-data]
  (let [->device-event-row (->device-event-row id timezone)]
    (eduction
      (comp
        (map row-splitter)
        (mapcat identity)
        (map ->device-event-row)
        (partition-all batch-n))
      meter-data)))

caleb.macdonaldblack06:02:35

Then I'm going to batch those into a database

5
seancorfield06:02:00

Clojure is so wonderful for data transformation 🙂

👍 25
5
Karol Wójcik09:02:14

Is there a way to gen-class which implements generic interface with some types?

noisesmith18:02:32

generics don't exist, you can implement any interface

noisesmith18:02:15

that is, the type parameter is a fiction, it's enforced by the java compiler but on the bytecode level (where clojure operates), there's nothing

Raymond Ko20:02:42

Hello, all. Is the current consensus that you should avoid using

(:use)
in
(ns)
due to it not working in ClojureScript and to avoid symbol conflicts?

Lennart Buit20:02:38

I think in general you want to have control over what and what you are not requiring

futuro20:02:59

I personally avoid :use and :refer :all because it hurts understandability of code.

👍 5
futuro20:02:47

With a short namespace alias in the :require form, I save typing while still making it immediately evident where a function/var came from.

Lennart Buit20:02:49

(it also can break reloading of code without restarting your repl)

Lennart Buit20:02:23

funny, I started to make more namespace aliases longer lately

Lennart Buit20:02:39

the few-letter-acronyms became too much

futuro20:02:20

At work, some of the namespace aliases were used so often that a single letter sufficed. But other namespaces were rarer, so I used the longer form.

futuro20:02:12

I like using aliases because I can jump to the top of the file and immediately learn what namespace is being referenced. Then what to call them, for me, comes down to what’s idiomatic in a project.

futuro20:02:12

So I like both, depending on context :)

seancorfield21:02:23

Also, with aliases, if your editor has live code completion, when you type (nsa/ it will offer up all the (public) symbols in whatever namespace nsa is an alias for. Harder for it to do that with used/`refer`ed names.

Lennart Buit21:02:07

also, cursive doesnt appear to discover unused require/refers

Raymond Ko21:02:21

Yeah, I agree with all of this. Been using Joker to do linting, and it warns against this.

seancorfield21:02:15

Big +1 for Joker! Very handy for tracking unused stuff and weirdly constructed code.

Raymond Ko21:02:38

What is in the nsa namespace? 😉

seancorfield21:02:19

@raymond.w.ko It's meant to indicate "some arbitrary ns alias in your code"

Raymond Ko21:02:55

Wow, I just realized how accurate the "It's just data" meme is for my own question...

seancorfield21:02:58

(I typed various things before just giving up and pressing enter with nsa in the code)

kenj21:02:13

When writing ->> expressions, is there a simple way to print out intermediate values in the chain for debugging purposes? I’ve found myself using let instead to print out intermediate bindings, in cases where a thread macro would be a perfect fit

Lennart Buit21:02:05

(map (fn [v] (println v) v))

Lennart Buit21:02:10

or actually what someone else is saying 😛

RodgerDodger21:02:31

Greetings! If I have a return value of [(1 2) (21 22) (41 42)], what would be the best way to get each index of each element into its own result, so it becomes [(1 21 41) (2 22 42)]?

manutter5121:02:08

@risinglight there’s probably a better way, but I just define a trace function like

(defn trace [thing]
  (prn thing)
  thing)
and stick it in the middle of the stack

dpsutton21:02:37

(apply map vector [[1 2] [21 22] [41 42]]) ;; => ([1 21 41] [2 22 42])

RodgerDodger21:02:17

@dpsutton wow, I was making that much too complicated. Thank you!

dpsutton21:02:37

the trick is map can take many collections. be aware of what happens when their lengths are different

dpsutton21:02:47

play in the repl and get it working for you

👍 5
kenj21:02:15

@manutter51 I actually wrote a trace function just like that, but I used it to wrap one of the intermediate expressions (causing an arity error from the macro inserting another argument to trace), instead of just inserting the function itself into the pipeline… I feel like I’m not nearly smart enough to write Clojure most days 🙁

manutter5121:02:41

I know the feeling, but I had it a lot worse when my day job was writing Java 😉

manutter5121:02:12

Clojure seems to be getting easier with practice more than Java ever did though. For me at least.

kenj21:02:05

I guess that’s the hope… keep banging head against problem until it hurts less 🙂

Lennart Buit21:02:35

perseverance is such a great skill ^^

grierson22:02:02

How do I :require a method from a defrecord? I have a namespace with a function that takes a record and calls a method on the record.

noisesmith22:02:39

the method function belongs to the namespace that defines the protocol

noisesmith22:02:10

if it's an interface and not a protocol, there's a method but no function

Ryan Haskell-Glatz23:02:05

I know this isn't the world's most impressive program, but I just made my first Clojure thing!

👏 25
🙌 10
Ryan Haskell-Glatz23:02:01

Hope you folks like guessing games 😅

noisesmith23:02:53

meta-game: try to make the game run out of stack before guessing your number :D

noisesmith23:02:27

with some refactoring it could use recur instead of self-call of guess, but realistically I think overflow is unlikely

👍 5
dpsutton23:02:42

you'd have to be really bad at the game 🙂

dpsutton23:02:46

nice work ryan

☺️ 5