Skip to content

Commit e7b1312

Browse files
author
Kapil Reddy
committed
Add new material for IN/Clojure 2020
1 parent b4690ba commit e7b1312

File tree

154 files changed

+5953
-1925
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

154 files changed

+5953
-1925
lines changed

README.md

+31-85
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,55 @@
11
# Clojure intermediate workshop
22

3-
# Setup Instructions
3+
## Setup instructions
44

5-
Just do the following one by one, and you should be fine.
5+
### Java 11
6+
You will need java to work with this workshop content.
67

7-
## Java 8
8+
First check if you have Java 11. You can do this by running the following command:
9+
`java -version`
810

9-
You will need Java to work with this Clojure workshop content.
11+
If Java is not installed please register at this link and download it for free from the following link.
12+
https://www.oracle.com/technetwork/java/javase/downloads/jdk11-downloads-5066655.html
1013

11-
First, make sure you have Java 8.
14+
You can verify that java has been installed properly by running the following command
15+
`java -version`
1216

13-
- Run `java -version` in your terminal.
14-
- If Java is not installed, please [download and install Java 8 from here](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html).
15-
- Once you are done, `java -version` should show you a Java 1.8.x version.
17+
We have not tested this project with Java versions other than Java 11 hence it is highly recommended
18+
that you have this one installed
1619

17-
Notes:
20+
### Leiningen
21+
Follow Leiningen setup instructions mentioned here: https://leiningen.org/
1822

19-
- If you have Java 9+, that should be OK too.
20-
- The LightTable editor is known to break with Java 9. Use Java 8 if you are keen on using LightTable.
21-
- We have not tested this project with Java 7 and earlier.
23+
Fire up a REPL by running the following command `lein repl`. This should give you a repl
24+
prompt. Enter `(+ 1 2)` and press enter. You should get back `3` as the result.
2225

26+
Additionally run `lein --version` to ensure that the correct version of lein has been installed.
2327

24-
## Leiningen
28+
This project is tested with Leiningen 2.9.1. It is highly recommended that you use the same version.
2529

26-
Follow [Leiningen setup instructions here](https://leiningen.org/).
30+
**WARNING** This project will break with Leiningen 3.0.0 or higher
2731

28-
### Fire up a REPL
32+
### Intellij
2933

30-
- Clone this project
31-
- Open your terminal, and do the following.
32-
- `cd` into this project's root directory
33-
- Use `lein repl` command to start a REPL with Leiningen.
34-
- Wait for it... the REPL will start and print out a message with some
35-
useful information
36-
- Locate the `port` and `host` information in the message. We will need this information soon.
34+
You can download Intellij by following the instructions here: https://www.jetbrains.com/idea/download/index.html
3735

38-
Note:
36+
You are free to use the editor of your choice as long as you can do the following with it:
3937

40-
- [Boot](http://boot-clj.com/) should be fine too, but you may need to generate your own _boot_ file(s).
38+
* Jump to definition for Clojure or Java sources
39+
* Start or connect to a REPL
40+
* Structural editing with paredit / parinfer
4141

4242

43-
## Code Editor and Tooling
43+
We will be using Intellij + Cursive for this workshop hence it is highly recommended that you have it installed. For Intellij,
44+
we recommend version 2019.3.2 or later.
4445

45-
Set up an editor and figure out how to evaluate Clojure code with it.
46-
We are fine with you choosing the editor as long as your editor can do,
4746

48-
- Connect to a Clojure REPL from the editor
49-
- Evaluate snippets and/or entire namespaces in the connected REPL from the editor.
50-
- Code navigation
51-
- Paredit / Parinfer
47+
### Cursive
5248

53-
Editors we can help out with
54-
- Emacs
55-
- Vim
56-
- Cursive
49+
You can get started with Cursive by following the instructions here: https://cursive-ide.com/userguide/
5750

5851

59-
### Cursive (IntelliJ)
52+
### Postman
53+
You can download Postman by following the instructions here: https://www.postman.com/downloads/
6054

61-
If you don't have an editor setup, we suggest you use Cursive with IntelliJ. Please follow instructions from [here](https://cursive-ide.com/userguide/).
62-
Do note that you may need to use it in trial mode or get an appropriate license ahead of time. There's a cost-free license available for personal/non-commercial hacking.
63-
64-
65-
# Further reading
66-
67-
## Inspiring and insightful source code
68-
69-
### [Clojure Core](https://github.com/clojure/clojure/tree/master/src/clj/clojure)
70-
This one is not a surprise, but reading sources in the core Clojure library (with the clojure.core namespace being a good starting point) is highly recommended. This one comes _directly_ from the masters, and it can not get more idiomatic (and simpler, really) than this.
71-
72-
### [Monger](https://github.com/michaelklishin/monger)
73-
74-
Monger uses official Java client for talking with Mongo. This is a standard way of writing database wrappers.
75-
Few interesting parts,
76-
- [monger.query/exec](https://github.com/michaelklishin/monger/blob/master/src/clojure/monger/query.clj#L87) uses doto to run a bunch of Java methods
77-
- [monger.query/exec](https://github.com/michaelklishin/monger/blob/master/src/clojure/monger/query.clj#L87) also uses Protocols [monger.conversion/ConvertToDBObject](https://github.com/michaelklishin/monger/blob/6bf528ed5b8a21153e3df1aa0cd1d88e08f31e3a/src/clojure/monger/conversion.clj#L52) and [monger.conversion/ConvertFromDBObject](https://github.com/michaelklishin/monger/blob/6bf528ed5b8a21153e3df1aa0cd1d88e08f31e3a/src/clojure/monger/conversion.clj#L108) to convert objects at boundary. Monger converts mutable data List/DBList to Clojure vectors.
78-
79-
### [Carmine](https://github.com/ptaoussanis/carmine)
80-
Carmine is Redis client and is written almost from scratch.
81-
- API is built with a [macro](https://github.com/ptaoussanis/carmine/blob/master/src/taoensso/carmine.clj#L21)
82-
- An atom is used to collect [test](https://github.com/ptaoussanis/carmine/blob/d00b61afb25426c8ec44f24bf544ae85dc93a4af/test/taoensso/carmine/tests/main.clj#L249) results
83-
- Exercise - Can we use core.async here to remove dependency on Thread/sleep?
84-
- It uses [IConnectionPool](https://github.com/ptaoussanis/carmine/blob/d00b61afb25426c8ec44f24bf544ae85dc93a4af/src/taoensso/carmine/connections.clj#L42) to create different implementations of connection pool
85-
- It uses a [edn file](https://github.com/ptaoussanis/carmine/blob/7d0e6f054a42473af4c513869491b752567f3cec/src/commands.edn) to map list of commands Redis supports to Carmine API functions using [defcommands macro](https://github.com/ptaoussanis/carmine/blob/d00b61afb25426c8ec44f24bf544ae85dc93a4af/src/taoensso/carmine/commands.clj#L275)
86-
87-
### [core.cache](https://github.com/clojure/core.cache)
88-
core.cache is Clojure contrib library. It provides in-memory implementations of different caching strategies
89-
- [core.cache/defcache](https://github.com/clojure/core.cache/blob/master/src/main/clojure/clojure/core/cache.clj#L67) is a macro that reduces repetition of defining a type
90-
- [This](https://github.com/clojure/core.cache/blob/master/src/main/clojure/clojure/core/cache.clj#L224) shows that mutation to cache creates a new value
91-
92-
### [clucy](https://github.com/weavejester/clucy/blob/master/src/clucy/core.clj)
93-
This one is old, but it really stands out for a few reasons as far as learning goes
94-
- A concise example that shows Java inter-op
95-
- Careful design considerations, and thus what a succinct piece of code within a single namespace can achieve
96-
- Clever use of `meta` attributes on `vars`
97-
98-
### [Durable Queue](https://github.com/Factual/durable-queue)
99-
This one pushes some limits on Clojure-Java interop without descending down into Java (language) land. An instructive piece of source, all within a single namespace.
100-
101-
## Links
102-
- [Clojure ground up](https://aphyr.com/tags/Clojure-from-the-ground-up))
103-
- [Clojure toolbox - list of clojure projects/libraries](https://www.clojure-toolbox.com)
104-
105-
## Copyright and License
106-
107-
Copyright � 2018-2019 [IN/Clojure](https://inclojure.org/).
108-
109-
Distributed under the [MIT license](https://github.com/inclojure-org/clojure-by-example/blob/master/LICENSE).
55+
The recommended version of Postman is 7.17 or later

level_up

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/bin/bash
2+
total_chapters=10
3+
if [ -f .current_level ]
4+
then
5+
current_level=$(<.current_level)
6+
else
7+
current_level=1
8+
fi
9+
10+
next_level=$[(current_level%total_chapters)+1]
11+
echo $next_level > .current_level
12+
echo "Moving to savepoint:" $next_level
13+
14+
# if [ -f ./workshop-app/target/ ]
15+
# then
16+
# rm -r ./workshop-app/target/
17+
# fi
18+
19+
# if [ -f ./workshop-app/.nrepl-port ]
20+
# then
21+
# rm -r ./workshop-app/.nrepl-port
22+
# fi
23+
24+
# if [ -f ./workshop-app/prod_database_1.sqlite ]
25+
# then
26+
# rm ./workshop-app/prod_database_1.sqlite
27+
# fi
28+
29+
## backing your solution
30+
# mkdir -p ./your-solutions/$current_level/src/ ./your-solutions/$current_level/test/
31+
# cp -R ./workshop-app/src/ ./your-solutions/$current_level/src/
32+
# cp -R ./workshop-app/test/ ./your-solutions/$current_level/test/
33+
34+
rm -r ./workshop-app/src/ ./workshop-app/test/
35+
mkdir -p ./workshop-app/src/ ./workshop-app/test/
36+
37+
cp -R ./save-points/$next_level/src/ ./workshop-app/src/
38+
if [ -d ./save-points/$next_level/test ]
39+
then
40+
cp -R ./save-points/$next_level/test/ ./workshop-app/test/
41+
fi

project.clj

-30
This file was deleted.

restart

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/usr/bin/env bash
2+
3+
level=${1:-1}
4+
echo $level > .current_level
5+
echo "Resetting to save point:" $level
6+
# if [ -f ./workshop-app/target/ ]
7+
# then
8+
# rm -r ./workshop-app/target/
9+
# fi
10+
11+
# if [ -f ./workshop-app/.nrepl-port ]
12+
# then
13+
# rm -r ./workshop-app/.nrepl-port
14+
# fi
15+
16+
17+
# if [ -f ./workshop-app/prod_database_1.sqlite ]
18+
# then
19+
# rm ./workshop-app/prod_database_1.sqlite
20+
# fi
21+
22+
# backing your solution
23+
# mkdir -p ./your-solutions/$level/src/ ./your-solutions/$level/test/
24+
# cp -R ./workshop-app/src/ ./your-solutions/$level/src/
25+
# cp -R ./workshop-app/test/ ./your-solutions/$level/test/
26+
27+
rm -r ./workshop-app/src/ ./workshop-app/test/
28+
mkdir -p ./workshop-app/src/ ./workshop-app/test/
29+
30+
cp -R ./save-points/$level/src/ ./workshop-app/src/
31+
if [ -d ./save-points/$next_level/test/ ]
32+
then
33+
cp -R ./save-points/$next_level/test/ ./workshop-app/test/
34+
fi

save-points/.idea/.gitignore

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

save-points/.idea/runConfigurations/WorkshopSavePointREPL.xml

+14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
(ns workshop-app.core
2+
(:gen-class))
3+
4+
5+
(defn -main
6+
[& _]
7+
(println "Hello World!!!"))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
(ns workshop-app.clj-to-java-interop)
2+
3+
(gen-class :name org.inclojure.Demo
4+
:init init
5+
:prefix "-"
6+
:state "state"
7+
:methods [[getName [] String]
8+
[setName [String] void]])
9+
10+
11+
(defn -init []
12+
"State a hash map."
13+
[[] (atom {})])
14+
15+
16+
(defn -getName
17+
[this]
18+
(:name @(.state this)))
19+
20+
21+
(defn -setName
22+
[this name]
23+
(swap! (.state this) assoc :name name))
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
(ns workshop-app.core
2+
(:gen-class)
3+
(:require [ring.adapter.jetty :as raj]
4+
[ring.middleware.params :as rmp]
5+
[ring.middleware.keyword-params :as rmkp]
6+
[workshop-app.routes :as war]
7+
[workshop-app.middlewares.users :as wamu]
8+
[workshop-app.db.sqlite :as wads]))
9+
10+
11+
(defn -main
12+
[& _]
13+
(wads/create-table wads/conn)
14+
(raj/run-jetty (-> war/app-routes
15+
rmkp/wrap-keyword-params
16+
rmp/wrap-params
17+
wamu/handle-any-exception
18+
wamu/reject-uri-ending-with-slash)
19+
{:port 65535
20+
:join? false}))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
(ns workshop-app.db.in-mem
2+
(:refer-clojure :rename {update cc-update
3+
read cc-read}))
4+
5+
6+
(def conn (atom {}))
7+
8+
(defn create!
9+
"Create an entry for k in our given in memory datastore."
10+
[c k v]
11+
(assert (some? k) "key cannot be nil.")
12+
(swap! c assoc k v))
13+
14+
15+
(defn update!
16+
"Update the entry for k to value v or add it if it doesn't exist in our in memory datastore."
17+
[c k v]
18+
(assert (some? k) "key cannot be nil.")
19+
(swap! c assoc k v))
20+
21+
22+
(defn delete!
23+
"Delete the entry for k in our in memory datastore."
24+
[c k]
25+
(assert (some? k) "key cannot be nil.")
26+
(swap! c dissoc k))
27+
28+
29+
(defn read
30+
"Read the entry for k in our in memory datastore."
31+
[c k]
32+
(assert (some? k) "key cannot be nil.")
33+
(get @c k))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
(ns workshop-app.db.mongo)
2+
3+
4+
(defonce r-db (atom {:foo :bar}))
5+
6+
(defn fetch
7+
[k]
8+
(Thread/sleep (rand-nth [100 300]))
9+
(clojure.core/get @r-db k))
10+
11+
(defn set
12+
[k v]
13+
(Thread/sleep (rand-nth [ 100 300]))
14+
(swap! r-db assoc k v))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
(ns workshop-app.db.redis)
2+
3+
(defonce r-db (atom {}))
4+
5+
(defn fetch
6+
[k]
7+
(Thread/sleep (rand-nth [20 20 20 20 20 20 20 300]))
8+
(clojure.core/get @r-db k))
9+
10+
(defn set
11+
[k v]
12+
(Thread/sleep (rand-nth [20 20 20 20 20 20 20 300]))
13+
(swap! r-db assoc k v))

0 commit comments

Comments
 (0)