Shell scripting のお供に Planck を推してみたい

最近仕事でちょっとしたスクリプト（ほとんどがファイル操作＆ファイル名編集に正規表現を少し使う程度）を書く機会が何度かあり、そういった「ちょっとした機会」にでも Clojure を使えたらなぁ、と思っていました。[^1]

[^1]: 日々の仕事にClojureを持ち込みたかっただけ、とも言いますが。

そういった用途に、最近だと [babashka](https://github.com/borkdude/babashka) 、少し前からだと [lumo](http://lumo-cljs.org) 、[planck](https://planck-repl.org) 、等が候補になるかと思います。各々特長がありますが、ちょっとマイナー（？失礼）な　planck について気に入った点、そうでなかった点等々調べてみたことを書いてみようと思います。

# Planck とは
実行エンジンに [JavaScriptCore](https://developer.apple.com/documentation/javascriptcore) (Safari / WebKit2 に使われてるやつ) を使った、ClojureScript の処理系、です。普通に REPL を起動してインタラクティブに操作することもできますし、ClojureScript で記述したスクリプトを食わせてバッチ的に処理させることもできます。まあ普通に shell みたいなもの、ですね。
JVM 上の Clojure と対比して、「起動がやたら速い」ので、ちょっとしたスクリプト記述にはちょうど良いですね。

# 使い方(超ざっくり)
planck の使い方について、以下にざっくりと示します。
## インストール
[公式](https://github.com/planck-repl/planck)には macOS(homebrew)、Ubuntu(apt-get)のインストール手順が記載されていますが、linux であれば条件があえば[ビルドできるかもしれません](https://github.com/planck-repl/planck/wiki/Building)。
## REPL
`planck` または `plk` コマンドで REPL に入ります。

```shell
bash$ plk
ClojureScript 1.10.520
cljs.user> 
```

TAB キーによる completion もある程度効くようです。ただ、planck 自体は nREPL をサポートしていないので、[CIDER](https://cider.mx) や [vim-iced](https://github.com/liquidz/vim-iced) といった強力な IDE が使えるわけではありません。それでも、emacs から使う分には、inf-clojure 経由で REPL を使うことができます(設定については[GUIDE](https://planck-repl.org/guide-all.html)参照)。
## ワンライナー
`-e` に続けて式を書けば評価してくれます。

```shell
bash$ plk -e ‘(range 10)’
(0 1 2 3 4 5 6 7 8 9)
bash$
```

## スクリプト

```clojure:hello.cljs
(println “Hello World!”)
```

```shell
bash$ plk hello.cljs
Hello World!
bash$
```

あるいは、shebang に書いておいて実行

```clojure:hello.cljs
#!/usr/bin/env plk
(println “Hello World!”)
```

```shell
bash$ chmod +x hello.cljs
bash$ ./hello.cljs
Hello World!
bash$
```

ここまでは簡単ですよね。
## 使える機能(API)
Clojure/JVM の場合だと単体でJVM標準のAPIが使えますので、特に外部ライブラリに頼らずともファイル操作程度のことはできますし、JVM 由来の `clojure.java.io` あたりを使えばより簡単にプログラミングできます。

一方 planck の場合は、shell scripting に必要な機能、REPL実装に必要な機能、は、名前空間 `planck.*` に用意されています。

* planck.core
* planck.repl
* planck.io
* planck.shell
* planck.http
* planck.environ

細かな説明は割愛しますが、例えば `(require ‘[planck.io :as io])` としておけば、 `(io/as-file “filename”)` のように、Clojure/JVM の `clojure.java.io` っぽい書き方ができます[^2]。

[^2]: nodejs 由来の lumo の場合は、nodejs 由来のファイルシステムAPI (readFileSync 等)がまるっと使えますが、planck.io のように整理されたAPIが用意されているわけではありません。

## 外部ライブラリとの連携
JavaScript ベースなので npm でインストールできるライブラリを使いたいところですが、planck は JavaScriptCore ベースなので残念ながら使えません。とはいえ、何も手がないわけではなく、　[cljsjs](http://cljsjs.github.io/) に登録されているものであれば、（ものによっては）使えるようです。

(例1) moment

```shell
bash$ plk -Sdeps ‘{:deps {cljsjs/moment {:mvn/version “2.24.0-0”}}}’
ClojureScript 1.10.520
cljs.user=> (require ‘moment)
nil
cljs.user=> (.format (moment) “YYYY-MM-DD HH:mm:ss,SSS”)
“2019-12-15 22:55:29,627”
cljs.user=>
```

(例2) AWS JavaScript SDK [^3]

```
bash$ plk -Sdeps ‘{:deps {cljsjs/aws-sdk-js {:mvn/version “2.421.0-0”}}}’
cljsjs.user=> (require ‘cljsjs.aws-sdk-js)
cljsjs.user=> (def s3 (AWS.S3.))
#’cljsjs.user/s3
cljsjs.user=>
```

[^3]: 例では aws-sdk-js を使っています。これとは別に cljs-aws というパッケージもありましたがこちらはエラーがでて planck からは使えませんでした。

# 所感
自分でもまだ planck でスクリプトをがっつり書いたわけではありませんが、Clojure のプログラミング言語としての使いやすさはとても魅力的なので、仕事の傍らででも使えればなぁ、とは思います。あと、気になった点について、以下にまとめておきます。

* lumo は nodejs ベースなので、npm 由来のパッケージを使える点は優位。
* lumo は nodejs ベースなので、Windows でも動く（一応動いた）。JavaScriptCore ベースの planck は、今のところ Windows 環境で動いている実績はなさそう(msys2等含む)。
* planck.io のようなビルトインがあるのは有り難い。JavaScript 的な「何でも非同期」なAPI ではなく、clojure.java.io と同じ感覚で使える、というのは planck の良いところだと思う。
* planck / lumo はどちらも起動が速いのだが、babashka にはやはり負けてしまう(GraalVM native image なのでそりゃそうだ、としかいいようがない)。
* ただし、babashka と違い、lumo / planck は、cljsjs 由来のライブラリへの依存を足してやることでスクリプト基盤そのものを拡張することができる点は優位かも。
* [closh](https://github.com/dundalek/closh) ってやつもあるが...今回は未調査。

以上です。