Fork me on GitHub
#beginners
<
2020-09-16
>
Jack Arrington02:09:16

Is the only reason to using (testing...) in clojure.test for self-documentation? Any reason to use them over just splitting tests into individual (deftest..) blocks?

practicalli10:09:20

As has been mentioned, I use (testing ,,,) to help narrow down where failing tests are located, especially useful when you have a lot of tests. Its also useful for grouping tests by purpose or intent when you have numerous assertions to run for a single function. I always use a deftest to test a specific function, so testing allows breaking assertions up logically within the deftest I have some simple principles for writing test code http://practicalli.github.io/clojure/testing/unit-testing/#simple-principles-for-writing-test-code

Cory02:09:12

you can define deftest scoped let blocks, which can be very useful. which is to say the relation between them is block contextual.

Cory02:09:08

tests are still just functions and you can compose them as such 😎

Jack Arrington02:09:34

Hm, I'm not sure I know what you mean. Sure I could do:

(deftest my-test
  (let [some-var ...]))
but I could do that same thing with testing:
(testing "something something"
  (let [some var ...]))
I guess I'm asking, what's the point of the testing macro at all when there is deftest?

Jack Arrington02:09:33

https://clojuredocs.org/clojure.test/testing is what I'm referring to, just to make sure we're on the same page 🙂

dpsutton02:09:33

(t/deftest foo (t/testing "this could describe what you want" (t/is (= 1 2))))
(foo)

FAIL in (foo) (form-init14706425140162863748.clj:16)
this could describe what you want
expected: 1
  actual: 2
    diff: - 1
          + 2
it can add context and descriptions in error messages, in addition to serving as documentation in the test definitions

seancorfield03:09:23

I find testing very useful when I have a deftest for a function and want to logically group assertions based on what scenarios they are checking.

seancorfield03:09:23

See, for example, this test for next.jdbc's get-connection protocol implemented on various data types https://github.com/seancorfield/next-jdbc/blob/develop/test/next/jdbc/connection_test.clj#L88

seancorfield03:09:38

^ @mail985 is that a useful example?

Jack Arrington11:09:14

It is and that answers my question! Thanks all 🙂

sb08:09:08

how to possible export the full clojurescript project into a single *.js file? (I saw somewhere on github.. but I don’t know where.. could you help me?)

Lu08:09:28

What tool are you using to build your cljs?

Lu08:09:28

What tool are you using to build your cljs?

Jack Arrington11:09:16

Check out shadow-cljs. There is a #shadow-cljs channel here too

Lu08:09:29

When you build the js bundle for your prod env all the cljs goes into a js file

Josef Richter08:09:45

hi, I have a checkbox in a form and I was wondering whether there was a nicer syntax for the submit action here, please:

[:input {:type :checkbox
             :checked checked
             :onchange "this.form.submit()"}]

Josef Richter08:09:29

I mean replacing "this.form.submit()" with just :submit or something like that…?

baptiste-from-paris08:09:10

If you have a button you don’t need to use this.form.submit fn

Josef Richter08:09:32

@U2N9GDB1U thank you. I had a button before. But this is a checklist, so I need a checkbox 🙂

baptiste-from-paris08:09:48

if you have a button you don’t need any js, just put a required attribute on the checkbox and the user has to choose at least one checkbox

Josef Richter21:09:16

@U2N9GDB1U I need to send a post request to the backend every time the user changes the state of the checkbox. it’s a todo list. I am actually not submitting a whole form. it’s a “form” that includes just two elements: one input type=hidden + the checkbox (previously a button type=submit).

mm12:09:20

Hi quick question, can I reference a function in another package without requiring it? Basically I just want to hold references to functions, but would love to avoid requiring it, I can reference using full package.

Mitch12:09:48

Depending on your use-case, you might just use quoted vars (something like #'reagent.core/ratom ) and then just make sure that the symbol resolves properly before using it

jsn12:09:50

@roguas why do you want to avoid requiring it, though?

mm13:09:25

trying to refactor some code that was dynmically loading symbols, so its a step in direction towards require

Marcus13:09:40

hi! When do you use maps and when do you use records?

mm13:09:56

I think records are mostly handy when it comes to protocols. So that you can have a generic way of processing different types of records.

Mitch13:09:26

Accessing fields in records is faster, too, so they are useful when performance is critical

Marcus14:09:36

@roguas @UF9E03ZEX ok thanks! Do you also use it to increase readability of the code? As it adds a bit more structure than maps. Or do you think maps with spec provides the same clarity?

Mitch14:09:27

I think the general approach is to just use maps with spec. The idea behind this is that the shape of your map is "self-documenting" in a sense. For example {:name "Mitch" :employee-number "1020.12"} is descriptive enough, without going through all of the OOP ceremony of creating decorators (when we want to accrue data) or interfaces (when we only want to act on a subset of the keys).

Marcus14:09:49

Ok. Great. Then I think we all have the same understanding. Protocols for polymorphism on type, plain maps for data and maps with spec for expressing composability and other rules when needed.

Marcus14:09:49

Thanks! Appreciate your feedback! 🙂

j14:09:41

I'd like to make a function that increases each element of a vector by its position in the vector, with position starting at 1. For instance [0 1 2] becomes [1 3 5], or [3 4 5] becomes [4 6 8]. Here's my current attempt: (map + [3 4 5] (range 1 (inc (count a)))) I was wondering if there's a more idiomatic way of doing this? Thanks!

delaguardo14:09:41

(map-indexed #(+ (inc %1) %2) [3 4 5])

j14:09:54

Thanks @U04V4KLKC! I didn't know about map-indexed. Why do we need a second argument %2 and where does its values come from?

delaguardo14:09:52

map-indexed expect first argument to be a function of two arguments where first — position of element in collection, second — element

j14:09:36

Ah! I understand now! Thanks again!

delaguardo14:09:07

in anonymous function written via #( dispatch macro you can refer to first argument as % or %1 , second — %2 etc.

delaguardo14:09:40

there is also %& to make a function of variable amount of arguments

j14:09:13

I didn't know about %&! That'll be very helpful!

jsn14:09:27

(map-indexed (partial + 1) [3 4 5]) 🙂

delaguardo14:09:06

^ even better) cool)

j14:09:30

What is happening there with partial? I see that it takes a function + and a variable amount of args.

jsn14:09:53

it creates a function that calls + with args 1 and any other args provided to it

j14:09:46

What are the args in this case? first arg is 1, second arg is index position? , third arg is [3 4 5]?

delaguardo14:09:15

third is an element from that position

jsn14:09:16

the 3rd arg is the value at that position, yes

j14:09:37

oh! I have it backwards! Second arg is [3, 4, 5], and third arg is value at that position?

jsn14:09:18

see the map-indexed docs perhaps?

j14:09:42

ok, thanks @UTQEPUEH4, I'll read it again!

jsn14:09:19

my example can be rewritten as follows:

user=> (def f (partial + 1))
#'user/f
user=> (map-indexed f [3 4 5])
(4 6 8)
user=>

jsn14:09:55

so, (partial + 1) returns a function, map-indexed then calls that function for each vector element

j15:09:21

Ahh! I see now, that's why @U04V4KLKC said "third is an element from that position"

j15:09:49

Thank you both so much! 🙏 I learned a lot just now

mpemer15:09:57

this is awesome - good stuff and great community

Marcus14:09:43

I have two local clojure projects A and B (using lein). What is the best way to call functions in B from A?

andy.fingerhut14:09:28

The best way depends on your goals and desires. One way is to run the command lein install in the root directory of project B, which if successful will create a JAR file for selected files of project B and write it into your $HOME/.m2 directory. Then add that artifact as a dependency in project A's project.clj file, and then require project B's namespace(s) containing the functions you want to call into project A's code.

andy.fingerhut14:09:16

If you later change code in project B, that will have no effect on the contents of that JAR file, unless you do lein install again to create another JAR file.

walterl14:09:49

If you want to you "live" changes in B, in A, what I've done before is add B as a dep of A, and then (from A's root):

mkdir checkouts
ln -s /path/to/B checkouts/

marshall15:09:26

clojure tools deps lets you use local paths in your dependency definitions https://clojure.org/guides/deps_and_cli#_using_local_libraries

marshall15:09:42

so you can reference other local projects via their path in your filesystem

Marcus20:09:47

@U0CMVHBL2 @UJY23QLS1 @U05120CBV thank you very much. I will check out these variants. :)

Jeff Evans16:09:56

does a struct-map have an ordering?

andy.fingerhut19:09:00

If you are looking for a kind of map with ordering guarantees on the key/value pairs, there are several linked from the Clojure cheatsheet in the "Maps" section: https://clojure.org/api/cheatsheet

andy.fingerhut19:09:15

I do not know whether a struct-map has any ordering guarantees.

andy.fingerhut19:09:01

I don't know if struct-map's are considered deprecated, but typically record or plain maps are much more commonly used.

Jeff Evans19:09:44

thanks for the insights

Jeff Evans19:09:54

invoking sorted? suggests that it doesn’t

andy.fingerhut19:09:40

sorted? might only return true for a few sorted collection types built into Clojure. Third party ones, which several of the ones linked from the Cheatsheet are, I have no idea what they return when passed to sorted?

kkruit16:09:10

Hey all, I'm trying to get the local timezone on my server. I'm running centos in docker and when i run date from bash i get Wed Sep 16 10:41:44 MDT 2020 but when I try to get my timezone in the repl it looks like this. (ZoneId/systemDefault) => #object[java.time.ZoneRegion 0x45024d57 "UTC"]

kkruit16:09:41

I'm not sure how to narrow down what the cause might be. eg docker, repl, java, centos, clojure

hiredman16:09:21

definitely not clojure

hiredman16:09:48

but if I may make a suggestion, go in the other direction, get everything on your server in utc

dpsutton16:09:48

that function will do this https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/util/TimeZone.html#getDefault() > Gets the default TimeZone of the Java virtual machine. If the cached default TimeZone is available, its clone is returned. Otherwise, the method takes the following steps to determine the default time zone. Use the user.timezone property value as the default time zone ID if it's available. Detect the platform time zone ID. The source of the platform time zone and ID mapping may vary with implementation. Use GMT as the last resort if the given or detected time zone ID is unknown. (System/getProperty "user.timezone") -> "UTC" for me

hiredman16:09:20

very likely docker

kkruit16:09:22

okay, thanks guys. @dpsutton mine also returns "UTC" so I think that gives me somewhere to start looking. Thanks!

hiredman16:09:31

definitely docker

dpsutton16:09:54

yeah. i'm confused. my system timezone is definitely not UTC but running a repl locally is giving me utc

hiredman16:09:04

but consider running in utc, it is good and common practice

hiredman16:09:21

are you on a mac?

kkruit16:09:35

no, i'm on windows

dpsutton16:09:36

interesting, but running just bare clj i get America/Chicago. yes on a mac

dpsutton16:09:35

i apologize. i ran that in a project's repl that explicitly sets {:jvm-opts ["-Duser.timezone=UTC"]}. otherwise it is picking it up correctly

kkruit16:09:47

haha maybe that's what i'm doing

kkruit16:09:24

yeah, that's it LOL

dpsutton16:09:49

but as @hiredman mentioned, that's probably actually a good thing

kkruit16:09:07

is there another way to get the system's timezone? I need to do reporting and it makes more sense for the end user if it show's the servers timezone

kkruit16:09:51

I usually operate in UTC and that's fine but in this instance I need the systems timezone

henryw37409:09:17

(Timezone/getDefault)

dpsutton16:09:37

its common for the server to do everything in UTC and let the client format those times into local timezone

Nazar Trut17:09:29

How do i initialize a sequence by another sequence. So kinda like seq1 = seq2

dpsutton17:09:12

this normally isn't necessary. can you write in pseudocode what you are trying to do?

dpsutton17:09:09

and the reason this isn't usually necessary is because the sequence you are using is probably immutable.

Nazar Trut17:09:42

So what im trying to do is remove "not" in an element, So the user has to enter '(not (not x)) for example, and my function needs to remove both of the "not". So I want it to remove the first not first so then it will be 'not 1', then it will remove the last not in that element, but i have to update my expr after removing the first "not"

Nazar Trut17:09:45

(defn remoove-nots
  [expr]
  (loop [x 1]
    (when (>= x 0)
      (if (= fourth-test (first expr))
          (expr (nth expr 1))                               ;;HERE i want to update expr

        )
      (recur (- x 1))
      )

    )

  )

dpsutton17:09:54

can't quite follow what's going on here but just use expr wherever you want. you haven't changed it.

Nazar Trut17:09:19

I want to chagne it tho

dpsutton17:09:41

you want to change it twice then? sounds like you want to change the result of your change?

Nazar Trut17:09:45

So instead of holding '(not(not x)), i want it to hold '(not x) after goinmg through once

Nazar Trut17:09:00

yeah i wanna change it twice

dpsutton17:09:34

oh, you probably want to add that to your loop and recur. (loop [e expr x 1] ... (recur (rest e) (inc x))) something like that

Nazar Trut17:09:00

what does (rest e) do?

seancorfield18:09:56

@ntrut Returns the rest of the sequence that is in e. I think in your case you want (second e) instead to turn (not (not x)) into just (not x)?

dpsutton18:09:58

Yeah sorry. That was just an example function that returns a “modified” version of expr (I called it e because shadowing can get confusing)

Nazar Trut18:09:32

Yeah i want to turn (not(not x) into (not x)

Nazar Trut18:09:59

but i cant figure out how to update expr in my case

bronsa18:09:39

clojure data structures are immutable

bronsa18:09:44

you don't make changes to data

bronsa18:09:47

you return new instances of transformed data

bronsa18:09:10

I recommend you maybe read a few introductory articles/guides on clojure, it's probably a much different paradigm than what you're used to and it will be really hard to hack your way through it in the dark

Nazar Trut18:09:17

So i need to create a seperate function that returns a new instance of my transformed data and have that loop twice

Nazar Trut18:09:58

I have read a few things but its different once i gotta start coding projects haha

fappy22:09:42

I wonder if you memoize a function foo of 3 arguments, and then use it in a map expression, mapping (partial foo first-fixed-arg initial-but-changing-second-arg) onto a collection, will your desire for memoization survive the use of partial ?

andy.fingerhut22:09:48

It seems like it should to me. If foo is memoized, (partial foo ...) is creating another function that calls foo, which is still memoized.

andy.fingerhut22:09:31

by which I mean, if foo is memoized, it should not become unmemoized by having other functions call it, and (partial foo ...) is just another function that calls foo . (partial foo ...) does not cause any changes in foo's behavior.

andy.fingerhut22:09:34

In a small test scenario, it should be straightforward to verify this by having foo do println or some other kind of debug output, to see when it is being called versus not.

jsn22:09:42

@U0H8WFJ8J in case it's not clear: partial doesn't immediately call foo, so nothing is immediately memoized. Only when the function returned by partial is called, only then foo is called (and that call is memoized)