I originally planned on tackling the second to last chapter of Clojure for the Brave and True (Chapter 12) today which would have taken me one step closer to the goal of finishing it this week but duty calls and our communal issue (within my ClojureFam cohort) needs to be addressed! I will therefore do some more research on my own as to what is causing the issue so we can discuss it in a call. Whatever extra time I find myself lucky to have shall be used for some casual reading that unlucky chapter (it's about the JVM and the Java interop).
Clojure being built on the JVM brings three characteristics to the language:
- Clojure applications run where Java applications run
- Clojure uses Java object for core functionality like reading a file
- Clojure can leverage Java's vast library ecosystem The JVM reads Java bytecode. It then translates it on the fly to machine code that the host will understand. It is just in time compilation.
Here is how you call a method on an object:
(.toUpperCase "hello world") ; => "HELLO WORLD"
(.indexOf "hello world" "w") ; => 6
(java.lang.Math/abs -2) ; => 2
These examples use macro that expand to use the dot special form.
You can also create new objects:
(new String)
(String.) ; this is equivalent
(String. "a string")
Then you can also do more interesting things like, use a Java stack:
(java.util.Stack.)
; => []
(let [stack (java.util.Stack.)]
(.push stack "Latest episode of Game of Thrones, ho!")
stack)
; => ["Latest episode of Game of Thrones, ho!"]
One can also import like this
(Stack.)
; => []
Or even multiple at once
[java.net Proxy URI])
(Date.)
; => #inst "2016-09-19T20:40:02.733-00:00"
That you can also do with ns
(:import [java.util Date Stack]
[java.net Proxy URI]))
- The
System
class lets you interact with the environmentexit
,getenv
,getProperty
(System/getProperty "user.dir")
; => "/Users/dabulk/projects/dabook"
(System/getProperty "java.version")
; => "1.7.0_17"
- The
Date
class,java.util.Date
is useful to tweak the you want a date to be converted to string.
To read and write to a file, you spit
and slurp
:
(spit "/tmp/hercules-todo-list"
"- kill dat lion brov
- chop up what nasty multi-headed snake thing")
(slurp "/tmp/hercules-todo-list")
; => "- kill dat lion brov
; - chop up what nasty multi-headed snake thing"
This will also work on objects other than files.
(let [s (java.io.StringWriter.)]
(spit s "- capture cerynian hind like for real")
(.toString s))
; => "- capture cerynian hind like for real"
(let [s (java.io.StringReader. "- get erymanthian pig what with the tusks")]
(slurp s))
; => "- get erymanthian pig what with the tusks"
We (Team Seneca, of ClojureFam) made some progress on our issue today. Part of our issue is that when browsing the results in Athena (the search function) it is possible for the selected item to not be visible (the list doesn't scroll to the item).
Jeff suggested we use scrollIntoView which actually gets us somewhere. The idea is to grab the element with getElementByClassName
and then run scrollIntoView
. We can place this code is the key up and key down event handler in athena.cljs
:
(= key KeyCodes.UP)
(do
(swap! state update :index dec)
(let [cur-sel (first (array-seq (. js/document getElementsByClassName "selected")))]
(.. cur-sel (scrollIntoView false {:behavior "smooth" :block "center"}))))
(= key KeyCodes.DOWN)
(do
(swap! state update :index inc)
(let [cur-sel (first (array-seq (. js/document getElementsByClassName "selected")))]
(.. cur-sel (scrollIntoView true {:behavior "smooth" :block "center"}))))
There are still some issues: the scrolling actually happens, but it's too eager. It also happens when the element wasn't going to leave the viewport. It needs to happen only the element does leave it.
This comment by @nthd3gr33 is a good summary of where we stand so far.
In this chapter I learned what it means for Clojure to be hosted on the JVM. I also looked into using Java classes in Clojure. I wonder if the same happens with ClojureScript and one is able to use JavaScript methods in ClojureScript.
It's also quite refreshing to be working on an issue. I'm quite happy to have only one chapter of Brave Clojure to read (which hopefully I will do tomorrow). It will be the opportunity to start working on my own issue, while also bridging the gap between Clojure and the Athens web application in terms of knowledge.
Let's end the day with a tally of what I completed:
- Chapter 11 of Clojure for the Brave and True
- Some progress on issue 126 in Athens