Fork me on GitHub
#beginners
<
2019-09-26
>
geofftate08:09:13

hi. I've just started using Cursive. What is the equivalent ctrl+shift+f command to format code? What does the default ctrl+alt+l do?

geofftate08:09:52

seems to be only for consistent indentation? Using it for this doesn't do anything..

(+
  3

  2)

geofftate08:09:57

I'm following 4-clojure right now, and I'm just being OC about this example (= 8 ((fn add-five [x] (+ x 5)) 3))... seems not formatted for readability.

practicalli-johnny11:09:45

This and many other 4Clojure tests are single and relatively short expressions. You will see lots of these in the 4Clojure challenges. This particular example is a function call to = with two arguments, so there is a case for saying there is little room for additional formatting.

practicalli-johnny11:09:51

In my own 4Clojure examples I do format function definitions, but tend to leave simple expressions on one line https://github.com/practicalli/four-clojure I have a number of 4Clojure walk throughs on my YouTube channel if it helps http://yt.vu/+practicalli

geofftate08:09:22

looks like there isn't a gofmt for clojure yet? I guess I have to ignore this for now

kelveden09:09:33

With Cursive (and IntelliJ in general for that matter) just hit the Shift key twice to bring up a search dialog which allow you search for (amongst other things) commands. Against each it'll also display the shortcut key (if any). In your case it's probably Ctrl+Alt+L.

kelveden09:09:03

Also, on a related note if you're new to Cursive you might find the commands under structural code menu useful. (Edit->Structural Editing).

herald09:09:21

Unfortunately there's not! cljfmt is the closest available currently, but it will only fix indentation, not "opinionated" things like the line breaks in your examples.

manutter5111:09:57

@thirdy.derivera Cursive generally formats stuff according to the Clojure Style Guide (subject to any customizations you might make in the Preferences), but it won’t do things like condensing vertical spaces like in your example. And I agree, your 4clojure example could definitely use some nicer formatting.

manutter5111:09:14

Here’s the style guide link for anyone who might not have it: https://github.com/bbatsov/clojure-style-guide

practicalli-johnny11:09:45

This and many other 4Clojure tests are single and relatively short expressions. You will see lots of these in the 4Clojure challenges. This particular example is a function call to = with two arguments, so there is a case for saying there is little room for additional formatting.

practicalli-johnny11:09:51

In my own 4Clojure examples I do format function definitions, but tend to leave simple expressions on one line https://github.com/practicalli/four-clojure I have a number of 4Clojure walk throughs on my YouTube channel if it helps http://yt.vu/+practicalli

bartuka11:09:12

hi people, I'm having some good time with dates in clojure. There are some corner cases that is killing me. I created a function to convert # inst (java.util.Date) to java.time.LocalDate

(defn date->localdate
  "Convert #inst objects into java.time.LocalDate."
  [date]
  (-> date
      (.toInstant)
      (.atZone (ZoneId/systemDefault))
      (.toLocalDate)))
when I try to convert #inst "1550-12-31T23:59:59.999-00:00" I get a localDate of "1551-01-10"

bartuka11:09:40

I tried to use clj-time.coerce to see if I did something wrong and to my surprise they also provide the same answer

bartuka11:09:30

this behavior happens until #inst "1581-12-31T23:59:59.999-00:00"

andy.fingerhut13:09:31

It is because of Pope Gregory! 🙂

andy.fingerhut13:09:24

Imagine, there were 150 years of countries neighboring each other in Europe where their calendars were 10 days off from each other, and different countries switched in different years. Must have been a pain in the neck.

danielneal13:09:05

why can’t time be the same everywhere

manutter5113:09:12

A lot of Eastern Orthodox churches are still on the Julian calendar, which is why they celebrate Christmas in January.

bringe15:09:20

Hello. I'm writing tests and wondering something that has vexed me before. If I have a series of pure functions that are called to build up a larger map, each one acting on different values, but each function outputting something possibly different depending on the previous value and possibly another thing passed in (let's say a config).

(defn get-large-map
  [config]
  (->> {}
       (a config)
       b
       (c config)
       (d config)
       e
       f
       (g config)))
Maybe this comes down to personal style/taste, but I can't figure out the best way to go about writing tests for this code. Do I write tests for each function in the chain, covering each output case for that function, and then also write a test for the different overall outputs of get-large-map? My concern is that when I write a test for the output of b, if checking against the whole map outputted, I'm also testing a again, and so on with each successive function in the chain. Then later if I change something in the way a outputs, it likely will break the tests for every function after a, since a is the "seed."

bringe15:09:36

But if I only write functions for get-large-map against the entire outputted map, then there's no real need to test a, b, and so on. However, I think that one test would require several cases, and again if I change something in the way a outputs, all those cases likely break.

bringe15:09:42

Maybe each test should not be checking against the whole map outputted (a "snapshot" test), and instead be checking only the keys/values it modified?

andy.fingerhut15:09:26

If the purpose of b is to add 2 keys to its input map, and pass everything else through unmodified, then it does seem that a test that passes in a map with 10 keys, and verifies that those 10 keys come through unmodified, would be an overly-detailed test of b

andy.fingerhut15:09:18

Also, consider that perhaps not all functions need tests.

andy.fingerhut15:09:55

If b is add 2 keys to the map and pass everything through unmodified, and the keys are constant, and the values are simple functions of the input, maybe don't bother to write a test for b. If e is a function you have never written before, and you are not sure you understand all of the cases yet, but you think maybe you have it correct, perhaps that could use some tests, especially near the edges of your understanding.

bringe15:09:59

Ah I see. I just need to put a little more upfront thought into test writing. Thanks

bringe15:09:24

"Hammock driven development" 😄

andy.fingerhut15:09:28

I mean, if you are in a work environment where you are pressured to write tests for every single function, then ... maybe have a discussion with colleagues about whether they actually do that, and what they consider acceptable. If there are no team requirements here, then testing I think is best done where you think you are most likely to have mistakes.

andy.fingerhut15:09:59

If b is as simple as I described, maybe you write one test case for it, and it only checks that the two new keys are present in the return value.

bringe15:09:39

Yeah that makes sense. I've taken it upon myself to write these tests, and the team approves, but it's up to me how they're written. I'll try to keep it simple, like you said.

csd18:09:04

I have a complicated regex that I'd like to add some comments to, by doing something like

(re-pattern (str "\s+" ; blah
                 "\w+" ; blah
                 "etc"))
but I'm getting an error about unsupported escape characters. What's the most literate way of dealing with this?

csd18:09:14

(I'm wondering if there's some way of doing this that won't require adding an extra slash for escapement to each existing slash.)

lilactown18:09:19

I think in re-pattern you need to double escape

csd18:09:36

(Which would detract from the readability that I'm trying to achieve)

lilactown18:09:31

oh, it looks like the built in regex tag has support for comments

csd18:09:38

oh really?

lilactown18:09:55

;; If you want to embed (ignored) whitespace and comments from #
;; characters until end-of-line in your regex patterns, start the
;; pattern with (?x)
user=> (re-find #"(?x)  # allow embedded whitespace and comments
                  \\    # backslash
                  \d+   # one or more digits
                  \s+   # whitespace
                  \S+   # non-whitespace"
                "\\ it sh0uld match in \\5 here somewhere.")
"\\5 here"

csd18:09:25

oh amazing

csd19:09:43

thank you

noisesmith19:09:28

it's not like clojure implemented any of that, it's standard Java regex syntax :D it's nice though

dpsutton19:09:50

and doesn't work in cljs

😭 4
noisesmith19:09:42

this site is great for cross platform regex translation and features https://www.regular-expressions.info/

noisesmith19:09:28

https://www.regular-expressions.info/javascript.html

No \A or \Z anchors to match the start or end of the string. Use a caret or dollar instead.
No atomic grouping or possessive quantifiers.
No Unicode support, except for matching single characters with \uFFFF.
No named capturing groups. Use numbered capturing groups instead.
No mode modifiers to set matching options within the regular expression.
No conditionals.
No regular expression comments. Describe your regular expression with JavaScript // comments instead, outside the regular expression string.

csd19:09:10

so is (?x) a pcre thing? because i don't see it in man pcrepattern

csd19:09:26

the javadoc suggests it is

noisesmith19:09:47

@csd it's documented here, if you select Java and Perl in the dropdowns for comparison you can see both support it https://www.regular-expressions.info/refmodifiers.html

noisesmith19:09:02

sadly there's no URL anchor to link directly to a pair of langauges

noisesmith19:09:07

😆 if you pull up Javascript on that page, it has n/a or no for every single feature

csd19:09:48

i see. (?x) enables PCRE_EXTENDED which enables comments via #

noisesmith19:09:21

oh, interesting, you can get some of those features in js via a library https://www.regular-expressions.info/xregexp.html

awb9920:09:02

I want to send the pprint/print-table result to a file. How would I redirect the out to a file?

chrisulloa20:09:10

with-out-str should do the trick @hoertlehner

awb9920:09:47

hahah! I had even seen this expression somewhere in my code. I assumed I wanted to remove \r\n in the strings.

awb9920:09:12

I read it like "without string"

chrisulloa20:09:34

(spit "file.txt" (with-out-str (clojure.pprint/pprint {:a "a" :b "b"})))

seancorfield20:09:04

@hoertlehner

user=> (require '[ :as io])
nil
user=> (binding [*out* (io/writer "print.out")]
(clojure.pprint/pprint {:a 1 :b {:c 2 :d 3} :e 4}))
nil
user=> (slurp "print.out")
"{:a 1, :b {:c 2, :d 3}, :e 4}\n"
user=> 

8
✔️ 4
seancorfield20:09:29

Any code executed inside the binding that writes to stdout *out* would append to that file.

seancorfield20:09:01

(funny that we both answered with pprint when you asked about print-table -- but the same principles apply)

awb9920:09:17

I could not find that in the docs.

andy.fingerhut20:09:35

The cheatsheet is not intended to be complete documentation, but it does give a clue about this in the IO "to writer" section, to use binding on *out*: https://clojure.org/api/cheatsheet . and also http://jafingerhut.github.io/

awb9920:09:20

@andy.fingerhut I had looked at a cheatsheet, this is where I had the idea to ask this question. Because before I looked at the source, and only saw printlns in the print-table function. So I thought that that would not be logical..

noisesmith21:09:44

alternatively, pprint takes a writer argument and it's easy to make a string writer

user=> (let [w (java.io.StringWriter.)] (pprint {:a 0 :b 1} w) (str w))
"{:a 0, :b 1}\n"

noisesmith21:09:37

that one doesn't work for print-table though

David Omar21:09:06

Hi. How could I retreive the key of the maximum value inside a map? I'm trying to return the most frequent element in a vector. I've already made a frequencies map using frequencies, but I don't know how to retrieve the key with the highest value (which whould be the most frequent element inside the original vector).

David Omar21:09:25

(last (keys (sort-by val freq-map))) works. But I'm not sure it's the best solution.

noisesmith21:09:42

user=> (apply max-key val (frequencies [:a :b :c :a :b :a]))
[:a 3]
*edited to make the return value more clear

noisesmith21:09:03

the return value is the key/value pair where the value had the largest number

David Omar21:09:40

If you had to choose only the key would you do (first (keys (apply max-key val (frequencies [:a :b :c :a :b :a]))) or the other solution?

noisesmith21:09:05

(key (apply max-key val (frequencies ...)))

David Omar21:09:39

Oh, didn't know I could call just key. Thanks for the help. I'll use that.

noisesmith21:09:15

that is probably a good candidate for ->> pipelining instead of nesting (or let with named intermediate values)

noisesmith21:09:26

that call to keys would have errored because a k/v pair is more vector-like than map-like

noisesmith22:09:26

you can use first instead of key or peek, last or second instead of val, but I think in this case key/val make things clearest

David Omar22:09:14

I assumed key would work for a single-keyed map. I've looked for "key" in clojure docs and it receives "e", a map entry. Is it possible to create a map entry without creating a map? I did is based on a few examples in the docs: (key (first {:a 1}))

noisesmith22:09:57

right - the max-key call above returns a map-entry

noisesmith22:09:33

you can create a map-entry via interop, but wanting to do so is probably a sign you are doing something wrong

noisesmith22:09:36

user=> (key (clojure.lang.MapEntry. :a 0))
:a

David Omar22:09:15

Oh, no. I was just wondering. Thank you.

seancorfield22:09:11

Interestingly, there's a predicate to test for such a thing -- map-entry? -- but no matching constructor function.

noisesmith23:09:33

based on code I've seen that attempts to use map-entries directly, my suspicion is that the reason it isn't provided is that it's not what real code needs; if your performance needs are such that you require creating a map-entry instead of a two element vector, you probably shouldn't even be writing clojure code

noisesmith23:09:42

best case you end up with code of limited utility that acts like the idiomatic version without actually being meaningfully different

noisesmith23:09:52

more likely you introduced tech debt / bugs

dpsutton23:09:33

I thought it was principally used for when walking or traversing to distinguish regular vectors from key value pairs

dpsutton23:09:55

For when the heuristic 2 element vector isn’t reliable

noisesmith23:09:38

sadly that only works with prewalk or more specifically, sadly that doesn't work for clojure.walk/postwalk, as it never creates map-entries

andy.fingerhut23:09:52

If you really want it, there is

user=> (map-entry? (clojure.lang.MapEntry/create 1 2))
true