Fork me on GitHub
#beginners
<
2018-09-03
>
m13103:09:17

I have some user config values where I want to let the user define key maps - I was going to store it as a map in an rc file that I am pulling into my runtime via (read-string (slurp "/path/to/file")) - however, none of the following seems to work out to invoke the call in code when read like this: `

m13103:09:42

{:a some-call-in-my-ns
 :b #(println "test")
}

m13103:09:18

if I try ((:a file-def)) or resolve or apply it doesn't seem to work

m13103:09:58

ah, seems to just need to be wrapped in eval

dpsutton03:09:18

@m131 :a and :b are bound to functions in this case, not the result of calling those functions. do you want {:a (some-call-in-my-ns)}?

noisesmith07:09:40

read-string shouldn't resolve symbols to functions in your ns, it only reads

Clojure 1.9.0
+user=> (read-string "+")
+
+user=> (type (read-string "+"))
clojure.lang.Symbol
+user=> (= '+ (read-string "+"))
true
+user=> ('+ 1 1)
1

stardiviner09:09:21

This is the source code of library kce-clj. I want to use this function write-file. I'm confused on the writer. What argument should I pass in as writer? Here is my try: `

stardiviner09:09:36

(defn- write-to-org-file
  (with-open [w ( "")]
    (orgmode/write-file w "")))

andersmurphy09:09:34

Hi, when using s/fdef to spec a function how do you specify :args for a function that doesn’t take any arguments?

funyako.funyao15611:09:15

@andersmurphy I think you don't need to specify it

alexmiller12:09:43

you don’t have to specify it, but (s/cat) works

andersmurphy12:09:58

So if I omit :args stest/check fails with a :no-args-spec message. But if I use the :args empty? it seems to work. (s/cat) works too. Thanks for the help. 🙂

alexmiller14:09:06

Ah, for check you will need it (because it uses the args generator to invoke). I will note that in fp, 0 arg functions are unusual because there is exactly one input and therefore exactly one output (and thus it can be a constant instead) OR its stateful, in which case a spec may be weird.

andersmurphy14:09:11

Yeah that’s a good point. I don’t see it coming up often. It was an impure function where part of the output was random. Probably didn’t need a spec. But I’m using spec everywhere at the moment to get a feel for it 😄. Thanks again for the help.

sb13:09:30

Hello, how to possible put in the split function (clojure.string/split text-here #"<<regex variable depend on input>>" a variable to the regex part?

gon13:09:24

you can use re-pattern

sb13:09:08

thanks!!

lockdown-17:09:41

is it common to see spec used for external input validation?

seancorfield17:09:37

@lockdown- You mean for things like REST API parameters? Or web form input parameters? We use it for that all the time.

seancorfield17:09:45

(let [params (s/conform ::api/some-spec (:params req))]
  (if (s/invalid? params)
    (make-response (s/explain-data ::api/some-spec (:params req)))
    (process params)))
Something like that.

caio.cesar.g.souza13:09:44

Cool! 😄 @seancorfield I’m curious about write spec… If I would write a specific spec for each form or not, or just use the same spec that describe my entity domain…

seancorfield16:09:56

That would depend on several things. First, do your web forms map 1:1 onto your domain model? If not, you need different specs. Second, web form input is always strings so you either need a spec that accepts string and "succeeds" if those strings can be converted to the appropriate data types -- and then actually parse the strings into data, or you need to write that coercion into your specs (which we do) which means they take strings as inputs and produce various data types -- and those spec probably aren't suitable for your domain model (which likely should not have strings in several fields!).

seancorfield16:09:17

So we have "API specs" that accept strings and produce strings, numbers, Booleans, dates, etc; and then we have "domain specs" that use exactly the data types we need in the domain. We often use the latter to guide our persistence functions (using s/form on the domain specs to get the list of keys in maps and then transform those to SQL entity names -- replacing - with _ -- so we can auto-generate CRUD functions from domain specs via macros).

seancorfield16:09:33

(That requires your database schema and your domain model are 1:1 which is not the case for all our tables so we also have custom transformation code for going between the domain model and the database and back)

caio.cesar.g.souza18:09:38

This is really interesting. I will give a try in this way. Thanks so much!

lockdown-17:09:07

@seancorfield web forms

seancorfield17:09:07

I think spec is good for that, yes.

jaihindh.reddy18:09:50

How do you guys englishify the output of explain-data

dadair18:09:25

@jaihindh.reddy I’ve recently started using https://github.com/alexanderkiel/phrase and some simple functions for validating maps where each key is a field in a form

jaihindh.reddy18:09:24

this seems more practical. Expound generate weird responses sometimes.

seancorfield19:09:12

@jaihindh.reddy We have a custom mapper function from explain-data to our domain (to produce specific numeric error codes -- and we have localized error messages based on those codes).

seancorfield19:09:46

That custom mapper understands the kinds of spec failures we can have, and has some heuristics built into it for our domain.

sjharms21:09:55

If I have two maps and want to join them by a map key's value, is there a easy way to do that?

(def m1 {:a 1 :stuck_out_tongue: 2 :c "match"})
(def m2 { :e "match" :f 1})
;; result would be {:a 1 :stuck_out_tongue: 2 :c "match" :f 1}

sjharms21:09:37

In this case if m1 :c contents matches m2 :c contents then add key :f to m1

sundarj21:09:09

@sjharms are you looking for merge?

=> (merge {:a :foo} {:a :bar :b :baz})
{:a :bar, :b :baz}

sjharms21:09:46

I think I might be looking at merge or merge-with but I am interested in comparing the key's value when merging

lilactown21:09:23

@sjharms are you interested in anything other than taking one over the other?

sjharms21:09:18

Potentially a set of keys. I think what I am asking is, can I join maps like I can join SQL tables? Ie (select * from m1,m2 where m1.c = m2.c)

risinglight21:09:44

Out of curiosity, how does one document the shape/structure of their data structures when just using maps? In languages w/ classes, the class definition is mostly self documenting, but w/ maps, do you just rely on the “create” function? Show an example in comments? Examine it in the REPL?

alexmiller21:09:51

The clojure.set ns has some basic relational algebra fns for sets of maps

mfikes21:09:15

In particular clojure.set/join looks useful

sjharms21:09:16

Thank you, that is what I am looking for

andy.fingerhut21:09:41

@risinglight spec is often used for documenting data structures in Clojure, as well as other run-time checking that you can opt into.

sasha50422:09:17

im learning clojure

sundarj22:09:33

@sasha504 welcome 🙂

sasha50422:09:45

eyy you're here, neat

sasha50422:09:56

im the person you just told about this on discord fyi

sundarj22:09:32

ah, i thought so. nice!

sasha50422:09:35

that is one cursed emoji

risinglight22:09:28

spec looks really awesome, but also has a learning curve. I was wondering what other simpler options might be until I get around to getting good at spec

sasha50422:09:12

does anyone know of a good tutorial for getting started with seesaw?

sundarj22:09:11

@sasha504 have you checked out the wiki? https://github.com/daveray/seesaw/wiki a REPL tutorial is linked there

sasha50422:09:36

I followed that but I'm not sure how to put it all together

seancorfield22:09:51

@risinglight I think anything that lets you describe, document, and/or validate the shape/structure of your data structures is going to have a learning curve. Spec is built-in and well-documented (and is increasingly going to be "the way" that this is done -- reflected in books and code). Prior to spec, folks might have pointed you at Schema -- which has a similar learning curve -- or even core.typed (which has an even steeper learning curve).

stardiviner23:09:24

Is there somebody can help test following code? I have different result on my machine. When I run lein repl under project root, and execute following test code works fine. But in Emacs CIDER [C-M-x] evaluate code report error: ParseException Unparseable date: "Tuesday, November 22, 2016 10:50:09 AM" java.text.DateFormat.parse (DateFormat.java:366) test code:

clojure
(import 'java.util.TimeZone)
(import 'java.text.SimpleDateFormat)

(defn- parse-dt-
  [dt tz_id]
  (let [tz  (java.util.TimeZone/getTimeZone tz_id)
        fmt (doto (java.text.SimpleDateFormat. "EEEEEEEEEEEE, MMMMMMMMMMMM dd, yyyy hh:mm:ss aaa")
              (.setTimeZone tz))]
    {:timestamp (.parse fmt dt)}))

(def tz_id (.getID (java.util.TimeZone/getDefault)))
(def tz (java.util.TimeZone/getTimeZone tz_id))

(parse-dt "Tuesday, November 22, 2016 10:50:09 AM" "UTC")
(parse-dt- "Tuesday, November 22, 2016 10:50:09 AM" tz_id)

sasha50423:09:37

I'd like to convert a atom of a list to JSON, how could I do this?

sasha50423:09:50

clojure
(def list (atom ["Jeff" "John" "Ann"]))
(println (json/write-str list))

sasha50423:09:56

and list needs to be an atom as I need to update it

michael.gaare23:09:46

you need to deref your atom with either deref or @ when you pass it to json/write-str

sasha50423:09:03

what does that do

michael.gaare23:09:16

Gets the value out of the atom

sasha50423:09:24

well it worked, thank you

sasha50423:09:55

how can I create and MD5 hash from a string?

lilactown23:09:38

there’s not a built-in clojure function for it, but you can either use Java interop or a library

sasha50423:09:43

i tried a method I found on stackoverflow but it requires writing java and I dont like it

sasha50423:09:52

what library would you recommend

lilactown23:09:17

just googling I found this one https://github.com/tebeka/clj-digest. seems popular ¯\(ツ)

lilactown23:09:04

what are you using MD5 for, if I may ask?

sasha50423:09:49

who doesn't like a good ol fashioned checksum

sasha50423:09:34

hmmm, doesnt work

sasha50423:09:52

pear.core=> (:require 'digest)
nil
pear.core=> (digest/md5 "hello")

CompilerException java.lang.RuntimeException: No such namespace: digest, compiling:(/tmp/form-init3043024428222783456.clj:1:1) 
pear.core=> (digest/md5 "hello")

CompilerException java.lang.RuntimeException: No such namespace: digest, compiling:(/tmp/form-init3043024428222783456.clj:1:1)

lilactown23:09:49

when in a REPL, you’ll want to use the form (require 'digest) - no :

lilactown23:09:34

the keyword form (:require ...) is only used inside of (ns pear.core ...) forms

sasha50423:09:06

ok, now it doesnt work in my actual program

sasha50423:09:10

(ns pear.core
  (:gen-class)
  (:require [clojure.data.json :as json])
  (:require 'digest))

lilactown23:09:38

(ns pear.core
  (:gen-class)
  (:require [clojure.data.json :as json]
            [digest]))

lilactown23:09:27

you don’t have to wrap it in brackets like [digest] but I do out of habit

sasha50423:09:41

still doesnt work

lilactown23:09:43

it makes it easier to add an :as d or something later

sasha50423:09:53

(ns pear.core
  (:gen-class)
  (:require [clojure.data.json :as json])
            [digest])

lilactown23:09:53

what’s the error?

sasha50423:09:03

Caused by: java.lang.RuntimeException: No such var: clojure.core/digest

lilactown23:09:34

🤔 that doesn’t make much sense to me. did you reload your ns?

sasha50423:09:44

how do I do that

sasha50423:09:54

im just calling lein run each time

sasha50423:09:40

sorry, im not used to JVM or functional languages

lilactown23:09:43

can you paste the whole error?

lilactown23:09:01

it’s okay 😄 clojure is weird even for people who have experience in both!

lilactown23:09:07

🤔 it’s working for me when I require it into a REPL

sasha50423:09:19

yeah it worked in REPL

lilactown23:09:51

just confirming, in your code above you’re missing a ) at the end of the (ns ... form

lilactown23:09:03

was that a copy+paste error or is that how it is in your file?

sasha50423:09:21

heres what i have now

sasha50423:09:31

(ns pear.core
  (:gen-class)
  (:require [clojure.data.json :as json])
            [digest])

sasha50423:09:39

oh i see lol

sasha50423:09:57

put a paren in the wrong place lmao

sasha50423:09:21

i hav map, how can I access item in it

lilactown23:09:30

a few different ways. I like to use this site for a quick reference on those kinds of things: https://clojure.org/api/cheatsheet