Fork me on GitHub
#beginners
<
2020-03-19
>
johnjelinek05:03:03

@seancorfield: any idea why this doesn't work with (builder/to-java?

johnjelinek05:03:06

I suspect it has to deal with passing in a Map<String,String>

seancorfield17:03:21

Can you put a small, self-contained example, with deps.ednand a single .clj file in a GitHub repo so I can take a look? I don't even know how to test the code you're showing without that information.

seancorfield03:03:30

Thank you @U0FEHF1RS! I'll take a look tomorrow (I'm off work, so it'll be a good OSS day)

👍 4
johnjelinek03:03:42

I hope you're staying safe re: COVID-19

seancorfield03:03:26

The Bay Area is under complete lockdown. We're only allowed out of our homes to go to the grocery store/doctors etc.

seancorfield03:03:15

So far, we're okay. But it's kinda "Mad Max" out there right now... shelves are empty of a lot of stuff...

seancorfield04:03:19

@U0FEHF1RS I tried this in the REPL tonight and using :requestParameters instead of :request-parameters works.

seancorfield04:03:36

And that makes sense to me for builder-based constructions.

seancorfield04:03:48

java.data doesn't do a-b to aB style translation, now that I look at it.

seancorfield04:03:03

Also, you can simplify your code to this

(builder/to-java IntegrationOptions {:requestParameters {"a" "b"}})

seancorfield04:03:27

java.data will deduce the builder class and it will know how to construct it.

johnjelinek05:03:12

oic! Good find! I was pretty certain I was using train-case for other things, maybe not

johnjelinek05:03:41

also, when I was simplifying before without setting the builder-class it was not deducing correctly

seancorfield05:03:58

:kebab-case, :snake_case

seancorfield05:03:19

:headlessCamelCase, :CamelCase

seancorfield05:03:40

There are libs that use :kebab-case (and turn then into .kebabCase function calls) but java.data is not one of them -- although that is not clear from the documentation (I need to work on that some more... maybe tomorrow?)

👍 4
seancorfield21:03:37

I've updated the java.data README today to (hopefully) make it clearer that properties should be :camelCase in general.

hindol06:03:54

There is another one, which walks you through building an e-commerce experience. Let me find it.

Gulli07:03:27

Ahh thanks!

Michaël Salihi08:03:17

If you interrested by Clojurescript and SPA too, you have this excellent course https://www.learnreagent.com/

Michaël Salihi09:03:25

Ah and after learning Reagent, of top of that, you can also watch the Re-frame (2h video free): https://www.jacekschae.com/learn-re-frame-free

Bobbi Towers00:03:37

I tried recording myself going through that tutorial while I was watching my friend's kid, and the result was quite funny: https://www.youtube.com/watch?v=S0zeha5kukQ&amp;t=693s

Endre Bakken Stovner10:03:48

I have a lot of atoms, often changing one leads to changing others which again need to change others. Like if A is changed B needs to be changed which means C needs to be changed and so-on. This feels like an antipattern. Is it? Does it have a name? Are alternatives discussed somewhere? I am considering using a rule-based system to find out what changes need to be made all at once and then doing them, in succession.

Ben Sless10:03:37

First, it sounds like maybe you could use one atom and keep these values as keys in a map which you will update. Second, you can let the state live in the scope of your process (in the computation sense, not OS sense), i.e. if all those atoms were bound variables inside a loop, you wouldn't need to change them, but to just recur

fricze10:03:11

What was the reason to use atoms? Do you have a huge data structure that you wanted to divide, or do you want to model a bunch of processes connected together?

Endre Bakken Stovner11:03:28

Okay; but the values in the map depend on each other. If the value belonging to :A is changed then the value belonging to :B should change.

Endre Bakken Stovner11:03:36

I use atoms to have data in a global state which is visible to others. I want to make my system extensible (e.g. add a new widget to the dashboard which shows some new aspect of the data). Then all the data in my system needs to be visible to others. The splitting up into different atoms was because if one changes then others need to change.

Ben Sless11:03:44

Yes, and if you save them all in keys you can keep as configuration the relations which describe which updates need to occur (as another map?) Also for the use case you're describing, you can use something like what I wrote https://github.com/bsless/more.async/blob/master/src/main/clojure/clojure/more/async.clj#L250 to create a sort of push/pull state, which everyone can query, can be updated from outside, will always be consistent and is contained inside a computational process. But think about what fricze said about perhaps modelling them as a bunch of processes communicating with each other, then the logic of who updates whom will be in the topology of your connectivity

Endre Bakken Stovner12:03:11

I will read more up on processes, thanks. I have never used queues myself (directly at least 😳).

fricze12:03:31

you really should try to distinct processes/events from your data

fricze12:03:07

there’s no problem in keeping data in one structure that you can query

fricze12:03:24

are you building UI application?

Ben Sless13:03:45

> queues Queues are great. Highly recommend getting to know core.async and watching The Language Of The System

Endre Bakken Stovner14:03:58

Thanks both of you. I will read https://www.braveclojure.com/core-async/ and ask some more newb questions afterwards :) @UFJD2TV46 I in the hammock-phase of building a workflow management system, like snakemake or nextflow. It will have a browser UI :)

noisesmith16:03:22

btw this can be done without atoms if you have an event flow design: you make a function that takes an immutable map of data, does some updates, then passes it to your consumers (maybe a list of functions defined by third parties) and lets them attempt updates (which you then validate and accept or reject)

noisesmith16:03:28

this can be done as a reduce inside a reduce

noisesmith16:03:46

the outer reduce consumes a lazy-seq of "inputs" (from whereever...) as data, the inner reduce passes a state through a series of functions (the outside consumers)

noisesmith16:03:23

I wouldn't use core.async unless some aspect of your domain requires out of order / async execution. Async introduces massive brittleness and makes bugs much harder to find, it leads to unintuitive code that's difficult to maintain. Only use it if you can prove you need it.

noisesmith16:03:52

that said, if your domain requires async execution, core.async solves coordination problems very nicely

noisesmith16:03:15

(but it's not a magic juice you pour in your app to make it faster)

Endre Bakken Stovner15:03:58

Thanks noisesmith 🙂 Timothy Baldridge (formerly cognitect) made the same points about queues here: https://www.youtube.com/watch?v=096pIlA3GDo

Endre Bakken Stovner15:03:28

Basically queues introduce non-determinism

Endre Bakken Stovner15:03:04

I will look up event-flow design :)

4
noisesmith15:03:34

right, core.async is a nice DSL over threads and queues, if you look at it from far away and squint in a certain way :D

noisesmith15:03:01

also, when Tim Baldridge gave his clojure/west talk a few years back about core.async, I was working on an app in which I had foolishly used core.async (incorrectly, in many aways), and his advice about how it makes things more brittle and how and when to properly use it helped me turn the app into something much more stable (afaik that app is still in use without dev support today)

👍 4
Aviv Kotek11:03:45

hey, i'm having issues with property-based-testing using test-check, trying to test a simple-custom tokenizer, which returns vector of tokens,

(def alphanumeric-prop
  (prop/for-all [text (gen/generate gen/string-ascii)]
                (let [res (first (tokenize text))]
                  (and (<= (count res) (count text))
                       (some? (re-find #"^[a-zA-Z0-9]*$" res))))))
this leads to Assert failed: Args to tuple must be generators (gen/generate gen/string-ascii) should return a string, how can I get it as a generator and not a string?

magnusdk11:03:16

Hey, try this:

(def alphanumeric-prop
  (prop/for-all [text gen/string-ascii]
    (let [res (first (tokenize text))]
      (and (<= (count res) (count text))
           (some? (re-find #"^[a-zA-Z0-9]*$" res))))))
You don’t have to call gen/generate there 🙂 gen/generate returns a value given a generator, but prop/for-all expects the generator itself

Aviv Kotek13:03:11

awesome 🙂

Aviv Kotek13:03:27

So why should I use gen/sample / gen/generate at all?

magnusdk13:03:30

It is useful for quickly checking out what a given generator generates from the REPL 🙂 It is not used when writing properties or when writing your own generators

Aviv Kotek13:03:17

great, thanks!

👍 4
Aviv Kotek14:03:23

hey, btw - are you familiar if this kind of testing is performed in industry? I'm new to it and curious if to add it on my team

Aviv Kotek14:03:08

And another one 🙂 what are some 'default/pattern' properties you are testing? I'm following this https://dev.to/jdsteinhauser/intro-to-property-based-testing-2cj8 which has some nice examples, but any other source can help out (just some reference when you code and get tired..)

Anik Chowhdury12:03:57

I want to parse yaml file and change some values. How can i do that with and without using any yaml parsing library?

hindol12:03:42

Something like clojure.string/replace? It can work with regular expressions.

👍 4
gibb12:03:15

To me parsing implies you want to build a data structure out of the text. The way I normally do that is use a parsing library, or build a parsing library for more esoteric things. If you just want to change some values, treat it as a stream of text and change the values with regex or the string functions.

👍 4
gibb12:03:54

Perhaps an example input and output would be helpful so we can see what specifically you want to do?

Anik Chowhdury16:03:36

I have done it using slurp clojure.string/slurp and clojure.string/replace . Thanks 🙂

Alex Miller (Clojure team)17:03:12

it is conceptually the same, but the mechanics of how to do it will be different, and I have not figured that out

Alex Miller (Clojure team)17:03:37

but maybe someone that does leiningen stuff could doc that

eval-on-point18:03:49

clojure.data.csv/write-csv has a quote? keyword arg that takes a predicate which decides whether to quote a string

eval-on-point18:03:28

I want to quote all strings, but using the identity function as my predicate seems a little unclear to me. Is there a better way?

seancorfield18:03:18

(constantly true) perhaps?

😁 4
eval-on-point18:03:48

you are the man! awesome