clj-scratch
clj-scratch copied to clipboard
Clojure REPL with features loaded ready to be productive
Scratch
Clojure REPL with features loaded ready to be productive
Being able to explore a problem with programming tools in an interactive fashion can be very productive.
There have been countless times I had to do some one-off investigating
and a wrote a quick shell one-liner that grew into a monster of ten pipes
with five sub-shells, three xargs
and quoted quotes within quoted quotes.
Clojure is an amazing tool for interactive tasks, but just starting up a plain REPL, it's hard to be productive right away for one-off tasks. You need to load some additional libraries depending on your context.
scratch
is an opinionated toolbox to have everything ready
whenever I realize my shell commands are getting out of hand again.
Of course loading all these dependencies comes at a cost, however not being interrupted while working on a problem can be a good trait-off, especially if you keep the same REPL session running for most of the time anyways. The most common tools are required by default and the other dependencies can be loaded on demand.
Run It
Try it out with:
clojure -Sdeps '{:deps {clj-scratch {:git/url "https://github.com/jorinvo/clj-scratch" :sha "c7dfa3e6f496e30d5ff39506fb893c5fc733081c"}}}' -m scratch
A Git hash can be used to simply try out the REPL without downloading anything manually, but I prefer using a local copy of the repository so I can easily adopt changes as I go.
I created an alias like this:
alias scratch='clojure -Sdeps "{:deps {clj-scratch {:local/root \"/path/to/clj-scratch\"}}}" -m scratch'
Features
Dev Tools
- Use rebel-readline with all its nice tools and shortcuts
- Pretty printed REPL output
- CIDER nREPL server to connect from your editor
- View docs with
(doc map)
- View source with
(source map)
- List public vars with
(dir clojure.string)
- Search vars with
(apropos str)
- Quick info about Java methods of an object with
(jmethods "string")
- Table output with
(print-table (jmethods 0))
OS
- Info About Operating System in vars
username
,home
,pwd
,os
- Run shell commands using
(sh "cowsay" "hi")
File System
- Directory listing with
(ls)
or(ls "some/path")
- Check file properties with helpers like
(dir? "some/path")
and(exists? "some/path")
- Also
clojure.java.io
is available asio
. Checkout(jmethods (io/file "."))
JSON
- Using jsonista
- Read JSON from file or streams with
(json/read (io/file "some.json"))
- Output data as JSON with
(json/str data)
,(json/strp data)
or(json/write "path/out.json" data)
Networking
- Check network types with helpers like
(valid-port? 112233)
or(valid-url? "not-valid")
- Get host name from URL with
(hostname "https://example.com")
- Get a random free port with
(get-free-port)
- Ping a domain with
(ping "example.com")
- Get IPs for a domain with
(nslookup "example.com")
Aleph
Aleph provides great tooling to work with HTTP, WebSockets, TCP and UDP as client and server.
It's included as dependency but not loaded by default:
(require '[aleph.http :as http]
'[aleph.tcp :as tcp]
'[aleph.udp :as udp]
'[byte-streams :as byte-streams]
'[manifold.stream :as stream]
'[manifold.deferred :as deferred])
Example - Make a HTTP requests:
(-> @(http/get "https://example.com") :body byte-streams/to-string)
Checkout Aleph for more.
HTML
- hiccup to generate HTML
- Parse HTML with tagsoup
- Use specter to transform deeply nested structures (like HTML!)
The tools are included as dependencies but not loaded by default:
(require '[hiccup.core :refer [html]])
(require '[com.rpl.specter :as specter])
(require '[pl.danieljanus.tagsoup :as tagsoup])
(def data (tagsoup/parse "https://example.com"))
(def CHILDREN (specter/nthpath 2))
(defn where-tag [tag]
[(specter/pred #(= tag (first %))) CHILDREN])
(def TITLE [CHILDREN
(where-tag :head)
(where-tag :title)])
(html (specter/transform TITLE str/upper-case data))
SQL
-
jdbc
is available - Make sure to require it first:
(require '[clojure.java.jdbc :as jdbc])
- SQLite, PostgreSQL and MySQL drivers are included
Working with time
- Using java-time
(require '[java-time :as time])
- There are excellent examples here
Cryptography
- buddy is included to provide crypto functionality
(require '[buddy.core.hash :as hash]
'[buddy.core.mac :as mac]
'[buddy.core.codecs :as codecs]
'[buddy.core.codecs.base64 :as base64]
'[buddy.hashers :as hashers])
- Common namespaces are available:
hash
,mac
,codecs
,base64`` hashers
- sha hash:
(-> (hash/sha256 "some val") (codecs/bytes->hex))
- base64 string:
(codecs/bytes->str (base64/encode "some val"))
More core data structures
Commonly used core namespaces are already available:
[clojure.edn :as edn]
[clojure.data :refer [diff]]
[clojure.set :as set]
[clojure.string :as str]
[clojure.walk :refer [postwalk]]
[clojure.spec.alpha :as spec]