Fork me on GitHub
#beginners
<
2021-02-06
>
zackteo02:02:30

How do I convert this - "[1, 2, 3, 5, 7, 11, 13, 17, 19, 23]\n" to a clojure vector? Is there a simple way to do this?

dorab02:02:40

read-string?

zackteo02:02:05

Wow, okay! Thanks 🙂

dpsutton03:02:57

far more preferable to use clojure.edn/read-string for this type of thing.

West05:02:43

Hey guys, so I’m trying to leverage a https://github.com/phax/ph-css, but I really am not comfortable with OOP at all. I’m trying to leverage this library but don’t know how classes and methods work in Java, let alone how to use them in Clojure. So I know that methods work like functions. Sometimes you need to create an object from another data type using (new ClassName). When I try to run line 20 I get an error: No matching method readFromString found taking 1 args for class com.helger.css.reader.CSSReader What that tells me is that I didn’t properly call the method I’m looking for, though I don’t think I’m in the wrong place. I need help understanding what exactly is going wrong here.

seancorfield05:02:55

@c.westrom I looked over that repo and it took me a while to find a link to the API JavaDocs for it... https://javadoc.io/doc/com.helger/ph-css/latest/index.html

West05:02:48

It looks like it takes 3 arguments.

static CascadingStyleSheet --- readFromString(String sCSS, Charset aFallbackCharset, ECSSVersion eVersion)
Read the CSS from the passed String using a byte stream.

seancorfield05:02:51

If you look for readFromString you'll see eight possible signatures (yikes!) and they all take a String as the first argument (sort of expected) but they all take at least one extra argument... some take more than one extra...

seancorfield05:02:22

This may be the easiest one to call? static CascadingStyleSheet readFromString(String sCSS, ECSSVersion eVersion)

seancorfield05:02:24

At least they are static methods so you don't have to worry about creating an object instance to work from -- Clojure functions all compile down to static methods, so think of static methods as just plain ol' functions.

seancorfield05:02:37

So maybe the easiest thing to pick there is LATEST, so you can add (com.helger.css ECSSVersion) to your :import clause and then use ECSSVersion/LATEST as the second argument.

seancorfield05:02:59

(it's a static field so, again, no object instance to worry about)

West05:02:28

Ok, imma try this out.

West05:02:03

Oh my gosh! It worked!

West05:02:36

That javadoc comes in super handy too.

West06:02:56

Ok, so it wasn’t the syntax or the OO concepts. It was really just me not knowing how to use the docs. Also it was a static method, kinda like most of the http://java.io stuff.

seancorfield06:02:08

[email protected]:~/clojure$ clj -Sdeps '{:deps {com.helger/ph-css {:mvn/version "6.2.3"}}}'
Clojure 1.10.2
user=> (import '(com.helger.css ECSSVersion) '(com.helger.css.reader CSSReader))
com.helger.css.reader.CSSReader
user=> (CSSReader/readFromString "h1 {color: blue;}" ECSSVersion/LATEST)
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See  for further details.
#object[com.helger.css.decl.CascadingStyleSheet 0x73ab3aac "[[email protected]: importRules=[]; namespaceRules=[]; rules=[[[email protected]: selectors=[[[email protected]: members=[[value=h1; sourceLocation=[firstTokenArea=[beginLine=1; beginColumn=1; endLine=1; endColumn=2]; lastTokenArea=[beginLine=1; beginColumn=1; endLine=1; endColumn=2]]]]; sourceLocation=[firstTokenArea=[beginLine=1; beginColumn=1; endLine=1; endColumn=2]; lastTokenArea=[beginLine=1; beginColumn=1; endLine=1; endColumn=2]]]]; declarations=[[[[email protected]: property=color; expression=[members=[[value=blue; optimizedValue=blue; sourceLocation=[firstTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]; lastTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]]]]; sourceLocation=[firstTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]; lastTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]]]; important=false; sourceLocation=[firstTokenArea=[beginLine=1; beginColumn=5; endLine=1; endColumn=9]; lastTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]]]]]; sourceLocation=[firstTokenArea=[beginLine=1; beginColumn=1; endLine=1; endColumn=2]; lastTokenArea=[beginLine=1; beginColumn=17; endLine=1; endColumn=17]]]]; sourceLocation=[firstTokenArea=[beginLine=1; beginColumn=1; endLine=1; endColumn=2]; lastTokenArea=[beginLine=1; beginColumn=17; endLine=1; endColumn=17]]]"]
user=>
Wow, that produces a gnarly-looking result.

West06:02:55

Sure does, but at least it’s something. Now I just gotta coerce all this into the format I want.

West06:02:15

I was able to instantiate a class within Clojure before (if the REPL serves me right) so maybe I can experiment with other libraries now.

seancorfield06:02:05

You might find bean helpful to pick apart Java objects that you get back from stuff like this:

user=> (bean *1)
{:fontFaceRuleCount 0, :supportsRuleCount 0, :ruleCount 1, :allRules [#object[com.helger.css.decl.CSSStyleRule 0x2e140e59 "[[email protected]: selectors=[[[email protected]: members=[[value=h1; sourceLocation=[firstTokenArea=[beginLine=1; ... lots more stuff ...
user=> (map bean (:allRules *1))
({:allDeclarations [#object[com.helger.css.decl.CSSDeclaration 0x5cd61783 "[[email protected]: property=color; expression=[members=[[value=blue; optimizedValue=blue; sourceLocation=[firstTokenArea=[beginLine=1; ... lots more stuff ...
;; but we can see what "shape" these things are:
user=> (map keys *1)
((:allDeclarations :allSelectors :class :declarationCount :selectorCount :sourceLocation))
user=> (bean (:allDeclarations (first *2)))
{:class com.helger.commons.collection.impl.CommonsArrayList, :clone [#object[com.helger.css.decl.CSSDeclaration 0x5cd61783 "[[email protected]: property=color; expression=[members=[[value=blue; optimizedValue=blue; sourceLocation=[firstTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]; lastTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]]]]; sourceLocation=[firstTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]; lastTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]]]; important=false; sourceLocation=[firstTokenArea=[beginLine=1; beginColumn=5; endLine=1; endColumn=9]; lastTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]]]"]], :empty false}
user=>

West06:02:45

I love how it’s called bean lol

seancorfield06:02:47

"Java Beans" are a thing 🙂

West06:02:00

oh man, just searched. Beans everywhere!

seancorfield06:02:16

So I dug a bit further:

user=> (seq (:allDeclarations (first *3)))
(#object[com.helger.css.decl.CSSDeclaration 0x5cd61783 "[[email protected]: property=color; expression=[members=[[value=blue; optimizedValue=blue; sourceLocation=[firstTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]; lastTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]]]]; sourceLocation=[firstTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]; lastTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]]]; important=false; sourceLocation=[firstTokenArea=[beginLine=1; beginColumn=5; endLine=1; endColumn=9]; lastTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]]]"])
user=> (count *1)
1
user=> (bean (first *2))
{:class com.helger.css.decl.CSSDeclaration, :expression #object[com.helger.css.decl.CSSExpression 0x6fd5717c "[members=[[value=blue; optimizedValue=blue; sourceLocation=[firstTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]; lastTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]]]]; sourceLocation=[firstTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]; lastTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]]]"], :expressionAsCSSString "blue", :important false, :property "color", :sourceLocation #object[com.helger.css.CSSSourceLocation 0x7e2f86e6 "[firstTokenArea=[beginLine=1; beginColumn=5; endLine=1; endColumn=9]; lastTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]]"]}
user=> (bean (:expression *1))
{:allMembers [#object[com.helger.css.decl.CSSExpressionMemberTermSimple 0x45d6ef73 "[value=blue; optimizedValue=blue; sourceLocation=[firstTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]; lastTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]]]"]], :allSimpleMembers [#object[com.helger.css.decl.CSSExpressionMemberTermSimple 0x45d6ef73 "[value=blue; optimizedValue=blue; sourceLocation=[firstTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]; lastTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]]]"]], :class com.helger.css.decl.CSSExpression, :memberCount 1, :sourceLocation #object[com.helger.css.CSSSourceLocation 0x3f29e26 "[firstTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]; lastTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]]"]}
user=> (map bean (:allMembers *1))
({:class com.helger.css.decl.CSSExpressionMemberTermSimple, :clone #object[com.helger.css.decl.CSSExpressionMemberTermSimple 0x3b05a99b "[value=blue; optimizedValue=blue]"], :optimizedValue "blue", :sourceLocation #object[com.helger.css.CSSSourceLocation 0x2c43eb8 "[firstTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]; lastTokenArea=[beginLine=1; beginColumn=12; endLine=1; endColumn=15]]"], :value "blue"})
user=>

seancorfield06:02:59

This is kinda typically of heavily OO Java stuff: deeply nested trees of objects instead of just plain data like Clojure would use. Everything I'm calling bean on is a Java object that could just be data in Clojure.

West06:02:57

Writing my own parser seems a lot more within reach now…

West06:02:48

You mean two for loops?

West06:02:12

Yeah, you can do something like this (defn [] ((for [i (x)] i)(for [j (x)] j)))

Adrian Imanuel06:02:49

Hello can we do 2 "for" loops within 1 defn?

(defn asdf
  (for [x (take 4(range 10))]
      'do this)
  (for [x (drop 4(range 10))]
      'do that))

Adrian Imanuel06:02:41

@c.westrom the "x" variable part must differ? you use "i" and "j", while i'm using same "x" for both.

West06:02:55

I don’t think that matters.

West07:02:40

The local variable only applies within the parens at least for the for macro.

Adrian Imanuel07:02:00

idk, but only 1 "for" that's executed

West07:02:18

If that doesn’t work, try wrapping both for loops in a single paren.

Adrian Imanuel07:02:24

only the latter for

West07:02:46

Like this ((for)(for))

West07:02:02

(defn asdf
  ((for [x (take 4(range 10))]
      'do this)
  (for [x (drop 4(range 10))]
      'do that)))

West07:02:10

You can also turn the result into other data types. You can also pass the result of those loops as arguments to another function.

Adrian Imanuel07:02:21

it's result in error

Adrian Imanuel07:02:57

Actually the code is like this

(defn asdf
  (println "hello")

  (for [x (take 4(range 10))]
      'do this)

  (println "world")
  (for [x (drop 4(range 10))]
      'do that))
so the result will be "hello" 1st loop for result "World" 2nd loop for result

Adrian Imanuel07:02:44

I knew it, because take & drop return a lazy seq, only the last of the lazy seq returned use dorun will force it to run https://clojuredocs.org/clojure.core/dorun

(defn asdf
  (println "hello")

  (dorun (for [x (take 4(range 10))]
      'do this))

  (println "world")
  (dorun (for [x (drop 4(range 10))]
      'do that)))

theVastSilence15:02:17

For exercises for a complete beginner, is 4Clojure the best place to start (and finish) before attempting anything else?

alexmiller15:02:08

It’s a good place to start

Stuart15:02:34

4Clojure is using an old version of Clojure IIRC. I also quite like solving problems in Codewars. YOu can start at the easy 8KYU puzzles and work your way up. The nice thing is when you solve it you get to see other peoples solutions voted by Best Practice, I've learned a lot from solving them using my rubbish clojure and then learning much nicer ways of solving the problems and finding functions I didn't know existed.

Stuart15:02:15

It's nota clojure specific site though.

Corin (CWStra)18:02:30

I'm trying to use clojure.spec.test.alpha/check in a cljs repl, but I constantly get an error about needing to require clojure.test.check and clojure.test.check.properties before calling it, even though I did that. Is there a way to make sure the namespaces are properly imported? (find-ns 'clojure.test.check) returns an object, and likewise for properties.

Corin (CWStra)18:02:21

The https://cljs.github.io/api/cljs.spec.test.alpha/check for check uses exists? as a check for the imports, but that returns nil whenever I run it for a namespace. Is that significant, or is that just macro vs. non-macro thing?