Fork me on GitHub
#beginners
<
2018-09-03
>
ahungry03: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: `

ahungry03:09:42

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

ahungry03:09:18

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

ahungry03: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?

fmn11:09:15

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

Alex Miller (Clojure team)12: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. 🙂

Alex Miller (Clojure team)14: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

👍 4
sb13:09:08

thanks!!

johnj17: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.

😎 8
👍 12
Caio Guedes13: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 Guedes18:09:38

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

seancorfield17:09:07

I think spec is good for that, yes.

jaihindhreddy-duplicate18: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

👏 8
jaihindhreddy-duplicate18: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).

👍 8
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)

kenj21: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?

Alex Miller (Clojure team)21: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.

Cheese Cake Aficionado22:09:45

eyy you're here, neat

Cheese Cake Aficionado22:09:56

im the person you just told about this on discord fyi

sundarj22:09:32

ah, i thought so. nice!

Cheese Cake Aficionado22:09:35

that is one cursed emoji

💯 12
kenj22: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

Cheese Cake Aficionado22: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

Cheese Cake Aficionado22: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)

Cheese Cake Aficionado23:09:37

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

Cheese Cake Aficionado23:09:50

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

Cheese Cake Aficionado23:09:56

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

mg23:09:46

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

👍 4
mg23:09:16

Gets the value out of the atom

Cheese Cake Aficionado23:09:24

well it worked, thank you

Cheese Cake Aficionado23: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

Cheese Cake Aficionado23:09:43

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

Cheese Cake Aficionado23: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?

Cheese Cake Aficionado23:09:49

who doesn't like a good ol fashioned checksum

Cheese Cake Aficionado23: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

Cheese Cake Aficionado23:09:06

ok, now it doesnt work in my actual program

Cheese Cake Aficionado23: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

lilactown23:09:43

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

Cheese Cake Aficionado23:09:53

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

lilactown23:09:53

what’s the error?

Cheese Cake Aficionado23:09:03

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

lilactown23:09:34

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

Cheese Cake Aficionado23:09:54

im just calling lein run each time

Cheese Cake Aficionado23: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

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

Cheese Cake Aficionado23: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?

Cheese Cake Aficionado23:09:21

heres what i have now

Cheese Cake Aficionado23:09:31

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

Cheese Cake Aficionado23:09:57

put a paren in the wrong place lmao

Cheese Cake Aficionado23: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