Fork me on GitHub
#beginners
<
2018-02-28
>
duminda03:02:02

Hi, Any suggestions to improve this code? (Roughly the same functionality as C++ multimap, but value is a set). So, it’s a container sorted by key, multiple values for the same key, value kept in a set.

(defn- assoc-multi [ordered-map key value]
  (let [slot (get ordered-map key)]
    (if (nil? slot)
      (assoc ordered-map key #{value})
      (assoc ordered-map key (conj slot value)))))

(defn- dissoc-multi [ordered-map key value]
  (let [slot (get ordered-map key)]
    (if (not (nil? slot))
      (if (= 1 (count slot))
        (dissoc ordered-map key)
        (assoc ordered-map key (disj slot value)))
      ordered-map)))
Tests for the above:
(deftest test-ordered-map-fns
  (testing "assoc-multi"
    (let [coll (into (sorted-map) [[3 #{"x"}] [2 #{"p"}] [1 #{"a"}]])]
      (is (= 3 (count (assoc-multi coll  2 "q"))))
      (is (= #{"l"} (get (assoc-multi coll 4 "l") 4)))
      (is (= #{"p" "q"} (get (assoc-multi coll 2 "q") 2)))
      (is (= #{"x" "y" "z"} (get (-> coll
                                    (assoc-multi 3 "y")
                                    (assoc-multi 3 "z"))
                             3)))
      (is (= [1 #{"a"}] (first coll)))))
  (testing "dissoc-multi"
    (let [coll (into (sorted-map) [[2 #{"p"}] [1 #{"a" "b" "c"}]])]
      (is (= 2 (count coll)))
      (is (= #{"a" "b"} (get (dissoc-multi coll 1 "c") 1)))
      (is (nil? (get (dissoc-multi coll 2 "p") 2)))
      (is (= 2 (count (dissoc-multi coll 3 "x")))))))

duminda03:02:56

Or any ready-made collection I can use for this?

seancorfield03:02:17

@duminda Take a look at the fnil function -- you can collapse that whole function down to an update with fnil conj I think. No need for the conditional.

seancorfield03:02:41

(update ordered-map key (fnil conj #{}) value)
The fnil function lets you provide a value to use instead of nil -- so it's like a built-in conditional.

seancorfield03:02:56

For the dissoc-multi you can combine the let and if using if-let, and (if (not (nil? slot)) ...) can simply be (if slot ...) due to Clojure's nil-punning.

seancorfield04:02:04

so you can just say

(if-let [slot (get ordered-map key)]
  (if (= 1 (count slot))
    ...))

seancorfield04:02:35

You can also streamline the assoc line in dissoc-multi:

(update ordered-map key disj value)

duminda04:02:32

Thanks a lot @seancorfield for the detailed response.

duminda04:02:44

Will try to wrap my head around this.

seancorfield04:02:13

I think I'd probably rewrite dissoc-multi something like this (needs testing):

(let [result (update ordered-map key disj value)]
  (cond-> result
    (empty? (key result)) (dissoc key)))

duminda06:02:16

In figwheel repl (cursive), When I get an error, they always seem a bit crude. They hardly help me understand what I’m doing wrong as I’m just a beginner. Sometimes it takes 5-10 minutes before I figure out there is a simple syntax error in the code. Is this a common thing? Anything I can do to get a detailed error? Any workaround? Below is an example: #object[Error Error: Invalid arity: 0] barely tells me anything about the where in the source code is the problem (line, column, function, etc)

dev:cljs.user=> (defn- make-mm [vals]
       (into (sorted-map)
             (into []
                   (map #([(first %) (set (rest %))]) vals))))
#'cljs.user/make-mm

dev:cljs.user=> (make-mm [[1 "a"]])
#object[Error Error: Invalid arity: 0]
   cljs.core.PersistentVector.G__11027 (jar:file:/Users/duminda/.m2/repository/org/clojure/clojurescript/1.9.908/clojurescript-1.9.908.jar!/cljs/core.cljs:19557:7)
nil
dev:cljs.user=> 

suryapjr10:02:29

(defn error-message   [severity]   (str "OH GOD! IT'S A DISASTER! WE'RE "        (if (= severity :mild)          "MILDLY INCONVENIENCED!" "Doomed")))

suryapjr10:02:58

Why is there a parentheses between if and = in the above code?

sundarj10:02:40

@suryapjr because in Clojure, = is a function, and you call functions by using parentheses

suryapjr10:02:27

(if true "hi" "bye"))

suryapjr10:02:10

Here there is no parentheses between if and true

sundarj10:02:15

because true is simply a value (like "hi" and "bye"), not a function - you don't call it. note that (if = "hi" "bye") also works, but you're not calling =, so it's no different to true

sundarj10:02:42

user=> (= :mild :mild)
true
user=> (= :foo :mild)
false
user=> =
#object[clojure.core$_EQ_ 0xaed0151 "[email protected]"]

suryapjr10:02:56

Very clear !! Thanks !!

suryapjr10:02:46

And how can i write a simple hello world in clojure withour leiningen

suryapjr10:02:49

Thank you !!

sundarj10:02:05

no problem! 🙂

rahul08032710:02:31

@suryapjr Install the clojure CLI tools and can simply run clj hello.clj containing (println "Hello, world!")

suryapjr10:02:21

Coool @rahul080327

mike56610:02:55

@suryapjr You can also just download the jar and say java -jar clojure.jar

suryapjr10:02:54

@mike566 thank you !

alexmiller10:02:10

Actually you can’t as of 1.9 as parts of Clojure have been broken into libs

mike56610:02:29

@alexmiller Thanks… I was mainly on older versions when doing that. (More recently, I just use lein)

paul13111:02:57

Hello everyone 🙂 Ruby developer here, do you have any book recommendations?

sundarj11:02:41

hello! Clojure for the Brave and True and Living Clojure are the go-to beginner books. Joy of Clojure and Programming Clojure are great, more in-depth, books 🙂

paul13111:02:42

Hi @sundarj, thank you. I will get some of the books you recommended!

sundarj11:02:18

enjoy, and welcome!

timok11:02:28

Hi, anyone ever used leaflet for a map in a reagent-app? I am searching for an example since I am new and js-interaction still difficult for me.

hawari.rahman1712:02:31

Hi, how can I manipulate every values of a vector that belongs to a map in a vector?

[{:name "A" :values []}
 {:name "B" :values []}]
So basically, not only doing manipulation to each map (A and B), I also want to manipulate each of their values as well.

schmee14:02:51

Specter is great for this! to apply a function f to each value in :values in all maps:

(transform [ALL :values ALL] f your-list-of-maps)

conan15:02:08

i'd try mapping a function over your vector. the function will be passed each map (A then B) in turn, and you could use update in that function to specify something to do to the :values key. That something is probably another map. e.g.

(def v [{:name "A" :values [1 2 3]}
        {:name "B" :values [4 5 6]}])

(map
  (fn [m] 
    (update m :values #(map inc %)))
  v)

=> ({:name "A", :values (2 3 4)} {:name "B", :values (5 6 7)})

conan15:02:54

update is a function that operates on a map. you give it the name of the key you want to modify (in this case :values) and a function to apply to the value of that key (in this case [1 2 3] or [4 5 6]).

hawari.rahman1706:03:35

Thank you @ @, I'll look into it!

delaguardo12:02:55

(map manipulate-single-value (mapcat :values [{:name "A" :values [...]} ...]))

hawari.rahman1712:02:57

Thank you @delaguardo

derpocious13:02:06

hey all, I'm having trouble using a nodejs package in cljs

derpocious13:02:31

I want to use the package "twit": https://github.com/ttezel/twit

derpocious13:02:49

I have added it to my project.clj :npm {:dependencies

derpocious13:02:06

:npm {:dependencies [[source-map-support "0.4.0"]
                       [xhr2 "0.1.4"]
                       [twit "2.2.9"]
                       ]}

derpocious13:02:23

and then I try to require it in my code:

derpocious13:02:24

[twit :as twit]

derpocious13:02:46

But then I get the error "no such namespace"

derpocious13:02:50

Caused by: clojure.lang.ExceptionInfo: No such namespace: twit, could not locate twit.cljs, twit.cljc, or Closure namespace "twit" in file src/twitter_unfollower/core.cljs {:tag :cljs/analysis-error}

derpocious13:02:41

sorry, what's the difference between npm-deps and :npm { :dependencies }?

sundarj13:02:25

i don't think :npm {:dependencies ,,,}} is valid? unless you're using a plugin

derpocious13:02:00

maybe [lein-npm "0.6.0"]

derpocious13:02:55

But how can I know the right namespace to require?

sundarj13:02:53

i believe it should be the same name as the npm package (so twit in your case)

sundarj13:02:11

but if that's not working with that plugin, i would try using the cljs compiler options directly

derpocious13:02:42

:npm {:dependencies [[source-map-support "0.4.0"]
                       [xhr2 "0.1.4"]
                       ]}
  :npm-deps { 
              :twit "2.2.9"
              }

sundarj13:02:53

no you have to pass it to your cljs compiler options

derpocious13:02:17

(defproject twitter-unfollower "0.1.0-SNAPSHOT"
  :description "Jim's bot"
  :url ""
  :dependencies [[org.clojure/clojure       "1.8.0"]
                 [org.clojure/clojurescript "1.8.51"]
                 [org.clojure/core.async    "0.2.395"]
                 [io.nervous/cljs-lambda    "0.3.5"]
                 [cljs-http "0.1.44"]]
  :plugins [[lein-cljsbuild "1.1.4"]
            [lein-npm       "0.6.0"]
            [lein-doo       "0.1.7"]
            [io.nervous/lein-cljs-lambda "0.6.6"]]
  :npm {:dependencies [[source-map-support "0.4.0"]
                       [xhr2 "0.1.4"]
                       ]}
  :npm-deps {
              :twit "2.2.9"
              }
  :source-paths ["src"]
  :cljs-lambda
  {:defaults      {:role "arn:aws:iam::954459734159:role/cljs-lambda-default"}
   :resource-dirs ["static"]
   :functions
   [{:name   "cljs-twitter-unfollower"
     :invoke twitter-unfollower.core/run-lambda}]}
  :cljsbuild
  {:builds [{:id "twitter-unfollower"
             :source-paths ["src"]
             :compiler {:output-to     "target/twitter-unfollower/twitter_unfollower.js"
                        :output-dir    "target/twitter-unfollower"
                        :source-map    true
                        :target        :nodejs
                        :language-in   :ecmascript5
                        :optimizations :none}}
            {:id "twitter-unfollower-test"
             :source-paths ["src" "test"]
             :compiler {:output-to     "target/twitter-unfollower-test/twitter_unfollower.js"
                        :output-dir    "target/twitter-unfollower-test"
                        :target        :nodejs
                        :language-in   :ecmascript5
                        :optimizations :none
                        :main          twitter-unfollower.test-runner}}]})

derpocious13:02:24

this is my project.clj

sundarj13:02:43

yeah so under :compiler

derpocious13:02:59

:compiler {:output-to     "target/twitter-unfollower-test/twitter_unfollower.js"
                        :output-dir    "target/twitter-unfollower-test"
                        :target        :nodejs
                        :language-in   :ecmascript5
                        :optimizations :none
                        :main          twitter-unfollower.test-runner
                        :npm-deps { :twit "2.2.9" }}}]})

derpocious13:02:50

hmm I am getting the same error still, can't find twit namespace

sundarj13:02:50

i think that's right

sundarj13:02:01

ah, that's strange

derpocious13:02:30

hmm I'll keep trying. thanks

sundarj13:02:19

ah, you might need to run npm install twit

sundarj13:02:27

or pass :install-deps true to the compiler

sundarj13:02:33

@derpocious if you can't get it to work, i've heard that http://shadow-cljs.org/ makes working with npm modules much easier

derpocious14:02:44

Maybe I need to add :install-deps: true

derpocious14:02:01

I can't try it now. I'm on a bus :(

elena.caraba15:02:24

Why is this false: ((or string? int?) 1), but this is true ((or int? string?) 1)

sundarj15:02:29

or returns the first truthy thing you give it. so it's returning the first function you give it (`string?` in the first case, int? in the second)

sundarj15:02:36

user=> (or string? int?)
#object[clojure.core$string_QMARK___5132 0x7906578e "[email protected]"]
user=> (or int? string?)
#object[clojure.core$int_QMARK_ 0x3a022576 "[email protected]"]

sundarj15:02:37

what you want is one of the following:

user=> (or (string? 1) (int? 1))
true
user=> (or (string? "") (int? ""))
true

user=> ((some-fn string? int?) 1)
true
user=> ((some-fn string? int?) "")
true

mfikes15:02:33

Yeah, some-fn is best. On the other hand, if you are trying to write a spec @, then what you have is closer to the way specs work:

(s/valid? (s/or :string string? :int int?) 1)

elena.caraba15:02:45

@ Yes, I'm spec'ing. Thank you all for your answers!

rgdelato16:02:08

sorry if this is obvious, but it's early in the morning and I assume there's a standard function I'm not thinking of. I'd like to take {:foo 1 :bar 2} and {:foo 0.3 :bar 0.4} and return {:foo 1.3 :bar 2.4}

rgdelato16:02:36

my current answer is:

(into {}
  (map 
    (fn [[key val1] [_ val2]] [key (+ val1 val2)])
    {:foo 1 :bar 2} {:foo 0.3 :bar 0.4}))
which is clunky and will break if the keys don't always map in the same order

suryapjr16:02:41

I'm awe-struck with the simplicity of clojure

carr0t16:02:44

@rgdelato (merge-with + {:foo 1 :bar 2} {:foo 0.3 :bar 0.1 :baz 0.5})

carr0t16:02:02

{:foo 1.3, :bar 2.1, :baz 0.5}

rgdelato16:02:29

@carr0t thank you, that's exactly what I was looking for

dpsutton16:02:46

rgdelator, just to point out an error with your longer version, you don't take steps to ensure the keys match. there is no guaranteed order for the keys in a map

dpsutton16:02:45

whoops. sorry about misspelling your name 🙂

dpsutton16:02:37

and importantly, the order of the keys in the literal {:key1 ....} does not imply that that is the order they will be when you map over the key value pairs

dpsutton17:02:33

these all line up:

(map (fn [[k1 v1] [k2 v2]]
       [k1 (and (= k1 k2) (= v1 v2))])
     (into {} (for [x (map (partial + 65) (range 0 26))]
                [(-> x char str keyword) x]))
     (into {} (for [x (map (partial + 65) (range 0 26))]
                [(-> x char str keyword) x])))
however lots of these miss by adding a few extra entries to the "end" of the map:
(map (fn [[k1 v1] [k2 v2]]
       [k1 (and (= k1 k2) (= v1 v2))])
     (into {} (for [x (map (partial + 65) (range 0 26))]
                [(-> x char str keyword) x]))
     (into {} (for [x (map (partial + 65) (range 0 29))]
                [(-> x char str keyword) x])))

dpsutton17:02:08

(note the (range 0 29) is larger than the range of 26 on the other one)

josmith201617:02:20

I created a brand new clojure project to run queries for testing puposes, I am using clojure.java.jdbc to connect to the database, my queries are vey simple, but it is taking ALMOST 10 MINUTES to connect to the database and run one query. Here is how I am calling the query (j/query dw-spec [queries/find-checks]) Heres my query

(def find-checks
  "SELECT * FROM jnl WHERE sourcebid = 'CH' OR sourcebid = 'IC' AND (document_dt > '2017-10-01' AND document_dt < '2018-01-01')")
Is there a way to speed this up? or am I using clojure.java.jdbc the wrong way?

chris_johnson17:02:13

How long does that query take to run at a mysql prompt?

josmith201617:02:56

running the query in datagrip takes less than a second

dpsutton17:02:19

do a query to select the type of 2017-10-01. Is it possible you aren't doing datetime comparisons when using clojure.java.jdbc but are coercing to strings? that could explain the slowdown

josmith201617:02:54

I’ll try that

dpsutton17:02:30

(TO_DATE('2013-02-11', 'YYYY-MM-DD') seems to be the ticket

dpsutton17:02:32

@josmith2016 did it speed it up?

josmith201617:02:50

I haven’t tried that yet, I tried taking out the date stuff altogether just to check if it was the date thing, so my query now looks like this

(def find-checks
  "SELECT * FROM jnl WHERE sourcebid = 'CH' OR sourcebid = 'IC')")

josmith201617:02:01

But its still going pretty slow. I wonder if I set up my project wrong? Does it usually take 5 minutes to start up a basic clojure project?

dpsutton17:02:51

are you using lein? boot? clj? how are you starting this up?

dpsutton17:02:04

and how long does it take you to run this query from the repl?

dpsutton17:02:40

(count (sql/execute conn find-checks)) or whatever it would look like?

josmith201617:02:08

I’m using lein

dpsutton17:02:49

are you using the repl?

josmith201617:02:28

I’m testing it in the repl now

josmith201617:02:43

It’s taking a while in the repl as well

josmith201617:02:37

It’s still running in the repl

dpsutton17:02:04

ok. try the query with the date time conversions

josmith201617:02:24

What library does TO_DATE come from?

inbox17:02:27

Hi all, where would you put some initialization code (such as reading some config) that is meant to be used by the tests? I’m thinking in something like Python’s __init__ or Scala’s package object

inbox17:02:35

so everytime a test file is read an executed, the initialization namespace is implicitly loaded and evaluated

josmith201617:02:06

I changed the date thing, the project starts up a lot faster now, but the query took about five minutes with the date conversion

dpsutton17:02:26

can you show how you are calling the query?

josmith201618:02:03

(j/query dw-spec [queries/find-checks])

josmith201618:02:42

I guess the query was selecting 69,000 rows, is 5 minutes normal for that number?

dpsutton18:02:03

were you printing them by any chance?

dpsutton18:02:16

ah you're probably timing your console

dpsutton18:02:33

try (time (count (...query)))

dpsutton18:02:43

consoles are super slow. woe to you if you're in emacs right now, too

dpsutton18:02:11

(take 4 ....) etc so you can see some of your data

josmith201618:02:53

Thanks @dpsutton

josmith201618:02:14

I know this is really basic but if I have a vector of maps a which equals [{:a 1 :b 2} {:a 3 :b 4}] how would I convert that to a vector which would equal [1 3]?

josmith201618:02:40

1 and 3 being the value for :a in both maps

noisesmith19:02:52

(mapv :a ...)

mathpunk19:02:02

I watched Stuart Halloway's "ETL in Clojure" talk and I'm trying to do my own ETL job based on what I could glean from it. I'm trying to yank about 50k small maps from a service, store them as files, and validate them against a spec. But I'm maybe holding edn wrong.

mathpunk19:02:15

Here's what data I've spit looks like:

josmith201619:02:37

Thanks @noisesmith

mathpunk19:02:55

Here's where my read attempt is failing:

noisesmith19:02:27

anything starting with #object is not readable

noisesmith19:02:58

you can either make your own function to transform each unreadable item before storing, or use a library like transit that lets you define a custom reader or writer for any type you like

noisesmith19:02:33

@mathpunk it's cool that you are using the pinboard api (or appear to be) - that's an awesome app

mathpunk19:02:47

ok so--- if I understand you right, it's reasonable to have transformed the data I got from strings into the datoms that those strings were meant to represent; but that I don't get deserialization for free

mathpunk19:02:52

I'll check out transit

dpsutton19:02:55

Is that where Stuart Sierra moved to?

noisesmith19:02:59

here's an example of setting up transit for custom types - other code in the lib has simple examples of using transit with files https://github.com/noisesmith/poirot/blob/master/src/org/noisesmith/poirot/handlers.cljc

josmith201619:02:47

I have this query "SELECT * FROM jnl WHERE sourcebid = 'CH' AND amount IN (?) AND document_no IN (?)" I’m trying to pass in the result I get from (mapv :amount checks) as parameteres but I’m getting Caused by: java.sql.SQLException: Invalid datatype conversion. Is this because the mapv returns a perstistent vector?

noisesmith19:02:46

@josmith2016 does the query procedure expect a vector of values, does it expect each value to be an argument?

josmith201619:02:03

What do you mean?

noisesmith19:02:33

your query string above, is being used in some query function, the vector is also supplied to this function, correct?

josmith201619:02:37

Yes heres how I call the query

(j/query db-spec [queries/find-checks (mapv :check_amount icchecks) (mapv :check_no icchecks)])

josmith201619:02:42

j is clojure.java.jdbc

noisesmith19:02:41

OK - so the issue here is that your arguments to query need to be something that makes sense for query - I don't think that passing a qeury string followed by two vectors is anything it understands

noisesmith19:02:41

if the two vectors are the params that the query would use, in the right order, use (j/query db-spec (concat [queries/find-checks] (map :check_amount icchecks) (map :check_no icchecks)))

josmith201619:02:35

Can you explain how this should fix the issue?

josmith201619:02:16

I’m getting an error Expecting more arguments

noisesmith19:02:17

@josmith2016 j/query takes three args (third is optional) - a db, a query vector, and an options map

noisesmith19:02:26

hmm - I could be reading this more

dpsutton19:02:50

(jdbc/query db-spec ["SELECT * FROM table WHERE id = ?" 13]) is from the docs

noisesmith19:02:53

but the key thing here is that you are providing two vectors, both options for the query, as separate

dpsutton19:02:00

the syntax @josmith2016 is using is correct i think

noisesmith19:02:37

@dpsutton but why would it allow a single ? to be filled in my a vector of values?

noisesmith19:02:19

the issue here is each individual value needs to be pulled out of the vectors made by mapv, and into the vector with the query string - unless there's a way of putting collection types into sql queries that I'm not aware of here

noisesmith20:02:03

oh I misread this entirely, you do want a collection inside the query, now I get it

noisesmith20:02:13

disregard, I get it now, apologies

ben.borders20:02:32

Im trying to dynamically call java methods on java objects in clojure code based on args being passed in. So for example with java object: builder, and hashmap m

(defn build-proto [builder m]
  (doall (for [[k v] m]
    (do
      (when v
        (let [method (symbol (camel/->camelCaseString (str "set-" (name k))))]
          ((. builder method v)))))))
howeve it is not passing in the value of “method appripriately:
No matching method found: method for class ibotta_pb.system.Entity$EntityUri$Builder
	at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:53)
i’ve tried also using
(defn build-proto [builder m]
  (doall (for [[k v] m]
      (when v
        (let [method (symbol (camel/->camelCaseString (str "set-" (name k))))]
          (eval `(. ~builder ~method ~v))
to eval, but clojure does not know how to evaluate java objects.
Exception in thread "async-dispatch-13" java.lang.RuntimeException: Can't embed object in code, maybe print-dup not defined:
So my question is, how can i make this work?

noisesmith20:02:14

it does know how to evaluate java objects - it is saying it doesn't know how to put something into a form literal

noisesmith20:02:41

if what you emitted was just a symbol for an object or method, it would work - something else (maybe a lambda) is being inserted, that is what causes that error

noisesmith20:02:26

is ~builder the class name of a builder, or an instanciated builder object? that would cause the error

ben.borders20:02:38

instantiated builder object

noisesmith20:02:39

if can emit the calss of the builder, but not an instanciated actual builder

dpsutton20:02:52

@josmith2016 i'm guessing its something simple we are missing. go ask in #sql to see if anyone can answer you. I use datomic at this job so i haven't been in sql for a bit. i bet its gonna be something trivial

noisesmith20:02:04

you can fix it by emitting code to create the builder, or creating code that accepts the builder as a parameter passed in

noisesmith20:02:24

what you can't do is put a specific instance into eval and get it back

ben.borders20:02:10

hmm well the java code i am interoping with is generated and the methods i am trying to implicitly call are all instance methods

ben.borders20:02:59

i guess i dont understand why this doesnt work

(let [method (symbol (camel/->camelCaseString (str "set-" (name k))))]
          (. builder method v))

noisesmith20:02:04

jimbob then the easy thing is to generate a function that accepts the builder, then call that function

noisesmith20:02:11

the builder can't be consumed by eval

josmith201620:02:50

I’ll ask the sql group thanks for trying guys 🙂

noisesmith20:02:18

sorry again for totally misunderstanding

ben.borders20:02:19

@noisesmith i thought thats what i did with

(defn build-proto [builder m]
  (doall (for [[k v] m]
    (do
      (when v
        (let [method (symbol (camel/->camelCaseString (str "set-" (name k))))]
          ((. builder method v)))))))

ben.borders20:02:27

accepts the builder

ben.borders20:02:33

and calls (. builder method args)

ben.borders20:02:42

however, method is not being evaluated

noisesmith20:02:01

@ben.borders right for that to work you need an eval stage to resolve the method and compile

noisesmith20:02:30

so you need eval to create a new function that accepts a builder and calls the method you specify

noisesmith20:02:07

you can't do the method call directly from symbol, but eval helps, you can't eval an embedded object instance, but creating a function helps

noisesmith20:02:16

so use eval to create a function, pass builder to that function

ben.borders20:02:40

ooo interesting!

noisesmith20:02:09

there's other ways to do this, but I think that's straightforward enough

ben.borders20:02:58

thanks a lot! seems straightforward enough

spacemods21:02:27

I'd like to make one-off visuals/controls for backend (JVM) state, without fully wiring them into a web-app. My current idea is something like "Devcards controlled over a websocket". Are there any existing similar tools that I'm missing?

josmith201623:02:09

How do I convert a lazy sequence to a vector?

noisesmith23:02:45

@josmith2016 usually you don't need to, but (vec l) or (into [] l) - into accepts an optional transform

noisesmith23:02:14

almost anything that accepts a vector also accepts a lazy sequence, usually you only need a vector for indexed lookup (efficiency), because you need conj to add at the end rather than the beginning, or because you are generating a let binding or something in a macro

josmith201623:02:46

I’m having issues with this code

(for [x (into [] checks)
                               y (into [] icchecks)
                               :when (and (= (select-keys x [:document_no :amount])
                                             (select-keys y [:check_no :check_amount]))
                                          (not= (:sourcebid x)
                                                "IC"))]
                           [x y])
It’s not matching them up. I’m wondering if I’m not comparing the correct data structures

noisesmith23:02:08

ywah, you don't need into [] in that - that's not doing anything

mikerod23:02:43

@josmith2016 Also, your = will always be false

noisesmith23:02:52

your problem is that select-keys returns a map that still have the keys

mikerod23:02:55

well unless they are empty maps

noisesmith23:02:25

if you want to compare those values in that order, use (= (map x [:document_no :amount]) (map y [:check_no :check_amount]))

noisesmith23:02:35

that's your problem, as mikerod says

josmith201623:02:06

That makes sense thanks

aeudes23:02:09

Hello, guys! I'm new here trying clojure(script) in a new project. I'm looking at the cljs luminus template, and I found that all starts in the init! function... but, where it says that the init! must be called? it's some convention?

noisesmith23:02:31

@aeudes - likely there's a script tag in the html that calls init!

noisesmith23:02:50

the advantage there is that you can load up the js for eg. a test and it wouldn't try to start the whole app

noisesmith23:02:03

(well, at least one advantage there)

aeudes23:02:20

I didn't find a call to init!

aeudes23:02:30

but, it must be in some place...

noisesmith23:02:58

there should be a call, either in the html that loads up the app, or at the top level of one of the namespaces

noisesmith23:02:39

so it ends up in the foo.app ns

noisesmith23:02:56

and the html must load up foo.app

aeudes23:02:02

wow! I haven't seen in that env folder

aeudes23:02:05

thx a lot!

noisesmith23:02:36

that's just the template source, but both of those should have generated files you can find in your local project

aeudes23:02:05

yes.. I found it here

noisesmith23:02:36

the way I do it is instead of having a .app ns that does nothing but call init, I just make a script tag that directly calls init

noisesmith23:02:39

same result though

aeudes23:02:05

I think the difference is that the app ns is referenced by leiningen config... then, there is no need to include a explicit call

aeudes23:02:11

Also, the template used env to customize the start by profile

noisesmith23:02:11

leiningen doesn't exist at runtime though, it's a build tool

aeudes23:02:02

I mean... the leiningen uses the config to generate the js to load the app ns

noisesmith23:02:23

the html file directly loads the app ns

noisesmith23:02:42

oh, I think I see what you mean