Clojurians
#clojure
<
2018-02-22
>

This page is not created by, affiliated with, or supported by Slack Technologies, Inc.

mpcarolin03:02:45

What are your opinions of evil mode for emacs and CIDER/Clojure? Some cursory googling tells me some people love it and others find it conflicts with important hot keys.

lee.justin.m03:02:52

i hated it so much i switched to atom :slightly_smiling_face:

shaun-mahood04:02:25

@mpcarolin It works fine with spacemacs, though it's hard to get stuff like Sayid to work without understanding more than I know about it

seancorfield04:02:40

There's #editors and #spacemacs and #emacs channels in case you want more specific feedback (since this isn't really a Clojure question).

dpsutton06:02:24

can you "unrequire" a namespace?

dpsutton06:02:58

for testing tooling otherwise would never do such a thing :slightly_smiling_face:

seancorfield06:02:39

What do you mean by "unrequire"?

seancorfield06:02:10

You can ns-unmap and ns-unalias all the public symbols in a namespace... is that what you mean?

dpsutton06:02:40

there's a bug in the autoocmplete library if you require a namespace with an alias of user. so i want to write a test and to do so i need to require a file with that alias. and if possible i'd like to "unrequire" after the test

rymndhng06:02:41

you also need to do one more thing: you have to remove the namespace from the *loaded-libs* ref, using require checks this cache and if it’s in there, it won’t load your namespace

seancorfield06:02:04

What about any side-effects of loading the ns? What about defonce where the ns has been required twice -- what would "unrequire" once do? what would "unrequire" twice do?

dpsutton06:02:17

(facts "about resolving namespaces"
           "can resolve a namespace aliased as user"
           (require '[compliment.context :as user])
           (fact "found the aliased namespace"
                 (resolve-namespace 'user *ns*) => (find-ns 'compliment.context)))

dpsutton06:02:53

was just wondering if it was a thing. it's all pure so no side effects. just wondering if it was possible to tidy up after myself

seancorfield06:02:42

Well, require is inherently not pure...

seancorfield06:02:55

And that's Midje isn't it? shudder

dpsutton06:02:20

not my project :slightly_smiling_face:

dpsutton06:02:33

its compliement, what CIDER uses for autocompletion

seancorfield06:02:15

Yeah, it crept into clj-time as a way to test/check the expressions in the readme and I've been trying to extricate us from it ever since...

rymndhng06:02:01

@dpsutton FWIW this is what tools.namespace does to ensure a namespace is removed so it can be loaded again: https://github.com/clojure/tools.namespace/blob/master/src/main/clojure/clojure/tools/namespace/reload.clj#L15-L19 may not be elegant, but may help unblock your test

seancorfield06:02:24

That does nothing for any side-effects of loading the namespace tho'...

dpsutton07:02:04

It's not blocking. I was just wondering if there was a simple solution. All I really want is for the ns interns to report that there is a namespace called 'user' and that one be resolved over the user name space

dpsutton07:02:33

But PR is in and unless the author has any complaints I'm good. Thanks for the suggestions and ideas though everyone

dpsutton07:02:32

But the tools namespace stuff looks cool. I was reading about agents in Alex's recently released book tonight

qqq09:02:34

is there a way to create a namespace whose sole purpose is to export defs, for example, to create

qqq09:02:02

to create a qq.clj whose sole purpose is to export some functiosn from q/a.clj , q/b.clj, q/c.clj, q/d.clj, etc ...

mpenet09:02:31

is there a (clojure|java) lib that does username normalisation/filtering according to rules such as what's described here: https://www.b-list.org/weblog/2018/feb/11/usernames/ ?

mpenet09:02:01

quick googling around suggest there isn't

olical09:02:56

An aside but that's a really interesting article, thanks for sharing!

dominicm09:02:07

I hate his suggestion that emails should be stripped like that. There's plenty of email servers that wouldn't route those to the same place. Plus it's a feature that I can sign up multiple times with different emails, not a bug.

mpenet10:02:29

the email part is debatable clearly

mpenet10:02:41

I am more interested about the username validation/normalisation

mpenet10:02:16

I personally use <mailto:[email protected]|[email protected]> all the time, I hate it when it's rejected

dominicm10:02:28

yeah, exactly.

patrkris10:02:53

Hi everyone. Is there a function to get the namespace part of a qualified keyword? That is, (ns-part :test/key) => "test"

joelsanchez10:02:14

yes, namespace :slightly_smiling_face:

patrkris10:02:23

God damn it! :smile: Of course.

patrkris10:02:41

Yeah, that gives me "key"

fmind12:02:24

Do you guys know a Clojure library that provides REPL helpers similar to the ones in Elixir ? https://hexdocs.pm/iex/IEx.Helpers.html

fmind12:02:14

I'm already using https://clojuredocs.org/clojure.repl, but the functions are more basic (both in term of information and layout)

ido13:02:04

any idea why this isn't working:

=> (def T true)
=> (case true T "true" false "false" "else")
"else"

schmee13:02:05

the arguments to case have to be compile-time constants literals

dominicm13:02:39

@ido The case here is doing the same as (= true 'T) the little ' means this is being treated as a symbol.

manutter5113:02:39

You can use condp instead if you like:

(def T true)
=> #'user/T
(condp = true
  T "true"
  false "false"
  "else")
=> "true"

ido13:02:09

yea, also match works:

=> (require '[clojure.core.match :refer [match]])
=> (def T true)
=> (match true T "true" false "false" :else "else")
"true"

ido13:02:56

but the case was kind of surprising. although it's in the docs :wink:

patrkris14:02:58

To serialize a Clojure data structure that can later be read by clojure.edn/read-string, would I just use clojure.core/pr?

alex43814:02:56

I use pr-str

dominicm14:02:13

@patrkris before handing a data structure over to pr-str it is your responsibility to ensure every element within it converts to edn correctly, just fyi. It catches me out.

patrkris14:02:46

Thanks for the advice

mpenet16:02:39

I ended up porting it quick&dirty: https://github.com/mpenet/thorn

mpenet16:02:28

well part of it, the one that mattered to me anyway

jlfischer19:02:26

I have a quick question/comment on clojure.java.jdbc using a SQLite database. When I do an insert, I get back a result of the form {:last_insert_rowid() 5}. I can pull the id want out using (get result (keyword "last_insert_rowid()")), but it really feels like there shouldn't be those parentheses in that result keyword. Anything I can do about that?

hiredman19:02:35

clojure.java.jdbc has the ability to pass in a function that is then used to map the column names sql sends back to map keys

hiredman20:02:22

being super lazy I would likely do something like (first (vals results))

seancorfield20:02:15

@jlfischer Unfortunately each different database returns generated keys in a different way so it's hard for clojure.java.jdbc to do something generic to just return the key value itself (PostgreSQL helpfully returns the entire inserted row, for example, and some databases don't return generated keys at all). I tend to do (-> (jdbc/insert! ...) first vals first) for DBs that I know will return a ResultSet containing one row with a single key/value pair for the key. In MySQL, you can shorten that to (-> (jdbc/insert! ...) first :generated_key) but SQLite is not so amenable...

seancorfield20:02:34

(I could write a utility function for that but then I'd need to require/refer it everywhere so the inline -> is less work)

yogidevbear21:02:35

What's the best way to update a value within a nested vector? Should I be using something like (update-in [["a" "b" "c"]["d" "x" "f"]] [1 1] "e")? (and before you say it, yes, I know this code errors :simple_smile:)

alexmiller21:02:27

update fns take a function, not a value: (update-in [["a" "b" "c"]["d" "x" "f"]] [1 1] (constantly "e"))

alexmiller21:02:40

assoc is better as mfikes said

yogidevbear21:02:25

I was trying assoc-in initially. Glad I was on the right track. Thanks for the input

ilyab21:02:16

When using`clojure.core.memoize/ttl`, is there a way to get the "age" of the cache? Or the time the data was cached?

yogidevbear21:02:43

@alexmiller @mfikes In that particular instance, using (constantly "e") with assoc-in puts the reference to the function instead of the actual value "e" into the nested vector

mfikes21:02:18

(assoc-in [["a" "b" "c"]["d" "x" "f"]] [1 1] "e")

mfikes21:02:32

assoc-in takes a value, update-in takes an update fn

yogidevbear21:02:48

Ah, that's weird. I was sure I tried that before

yogidevbear21:02:51

Must have had a type

yogidevbear21:02:59

Thanks Mike :+1:

vemv22:02:15

hiya! regex one. trying to pull multiple words out of a parenthesized group. but I only get one

;; input: (re-find magic-regex "foo bar baz DELIM")
;; desired output: [_ "foo " "bar " "baz "]

vemv22:02:55

my attempt was #"([a-z]+\s)DELIM", but at said that only pulls one word, not three

greg31622:02:00

you want re-seq

greg31622:02:48

actually maybe not, if you explicitly want the search to end at DELIM

noisesmith22:02:38

it’s something, but I bet someone else can offer something better:

=> (re-seq #"([a-z]+)\s(DELIM)?" "foo bar baz DELIM")
(["foo " "foo" nil] ["bar " "bar" nil] ["baz DELIM" "baz" "DELIM"])

greg31622:02:13

probably better as a two-step process:

=> (map #(re-seq #"\w+" %) (clojure.string/split "foo bar baz DELIM qux abc 123 DELIM" #"DELIM"))
(("foo" "bar" "baz") ("qux" "abc" "123"))

vemv22:02:25

thank you both! good stuff

vemv22:02:19

two-step may or may not be a good choice for my specific case. I was trying to build something on top of pure regexes (as opposed to computations)

lee.justin.m23:02:28

javascript has this handy shorthand where if the key of the map happens to be the same as the value, you can write { thing } instead of { thing: thing }. Is there a similar shorthand in clojure?

vemv23:02:38

there's no shorthand map literal in clojure

gtrak23:02:48

could probably do something with a reader tag but map literals right now need an even number of expressions

lee.justin.m23:02:44

i never realized how convenient it was until I didn’t have it :slightly_smiling_face:

gtrak23:02:46

but maybe like a reader literal can parse #my/map [:key val symbol :other key] etc. and expand it into a map literal, but clojure maps can have more types as keys than js ones.

noisesmith23:02:12

@gtrak yeah I use a simplified version of that

(cmd)user=> (defmacro keyed [& vs] (into {} (map (juxt (comp keyword name) identity)) vs))
#'user/keyed
(ins)user=> (keyed + * -)
{:+ #object[clojure.core$_PLUS_ 0x180da663 "[email protected]"], :* #object[clojure.core$_STAR_ 0x340da44c "[email protected]"], :- #object[clojure.core$_ 0x37052337 "[email protected]"]}

noisesmith23:02:36

for some reason I find being able to make a macro with 0 quoting quite pleasing

noisesmith23:02:01

related

(cmd)user=> (defmacro locals [] (into {} (map (juxt (comp keyword name) identity)) (keys &env)))
#'user/locals
(ins)user=> (let [a 0 b 1] (locals))
{:a 0, :b 1}

noisesmith23:02:39

that one felt like black magic when I figured it out haha

lee.justin.m23:02:43

yea no kidding

lee.justin.m23:02:29

all of those years of c++ and i’m still disconcerted by the idea that changing what feels like a variable name changes data

lee.justin.m23:02:56

(I know it isn’t remarkable)

noisesmith23:02:37

locals invalidates some common sense clojure expectations about scope and explicitness which makes it feel spooky

gtrak23:02:52

Yeah that's too different from everything else :grinning:

noisesmith23:02:41

but hey I use it as a debugging tool, debugging tools are allowed to be evil because they shouldn’t even get checked into git