八発白中

技術ブログ、改め雑記

Shellyの新しい使い方を紹介します

http://instagram.com/p/cBIfpetp_c/

今、同僚と温泉ハッカソン(温泉なし)のため琵琶湖のほとりに来ています。琵琶湖初めて見たら普通に砂浜で若者 (5歳前後) とかが水着で泳いでたりするし海っぽい。おじさんがその辺の木にハンモック吊るして寝てた。

意外にも京都市内から電車で30分とかで来られるから次はハック以外の目的で来てもいいかもしれない。今回はちょっと昼ごはんのついでに散歩したくらいだった。

一泊二日なので今日が最終日ですが、新しいものを作ったので紹介します。

Shelly、覚えてますか

ShellyというCommon Lispのライブラリ & ユーティリティがあります。去年のKyoto.lisp TT #1で紹介しました。

ShellyはCommon Lispの関数をシェルから呼び出せるようにする便利ツールです。

たとえば、drakma:http-requestでHTTPリクエストをする場合、以下のようなコマンドをターミナルで実行します。

$ shly -Ldrakma http-request http://www.hatena.ne.jp/

Common Lispライブラリのインストール、アップデートは以下のように書けます。

$ shly ql:quickload :clack
$ shly ql:update-all-dists --prompt nil

「こんなもん、SLIMEから直接S式叩けばいいじゃん」って思われる方もいるかもしれませんが、僕はLispを書いてるとき以外はターミナルで作業しているので、シェルコマンドで使えるとうれしい場面も多いです。他にもShellyにはいくつも利点があります。

  • サーバで実行する場合は常にSwankサーバが起動しているわけではない
  • 同じコードを処理系を自由に切り替えて実行できる (CIサーバなどで便利)
  • パイプ使って出力を他のコマンドに渡したりできる

処理系に依存せずLispコードを手軽にシェルから実行できるので、割と面白いプロジェクトだと思います。

ただ、長い

ただ使ってみて思ったのは、シェルコマンドとして使うにはコマンドが複雑になり過ぎることが多いです。

$ shly -Lquickdocs start-server --mode :production --port 8080 --debug nil

引数はすべて覚えておく必要がありますし、キーワード引数の多いような関数はコマンド自体が非常に長くなってしまいます。

たぶんSLIMEで実行したいコマンドと、シェルコマンドとして実行したいコマンドで求められるものが違ってくるんですよね。シェルコマンドだとなんでもはできなくていいけど、短いコマンドでさくさく実行できるほうがいい。

使いたいコマンドが一個程度ならaliasとか張ってしまえばいいんですが、引数を微妙に変更して実行したい、とかなると複雑なスクリプトを書く必要があります。そのため僕はMakefileを作ってWebアプリの起動管理をしていました。

$ make start SERVER_PORT=8080

必死にワンライナーを組み立てるMakefileを書く残念さったらない。

shlyfile

そこで、Shellyを改良して、プロジェクトに特化したコマンドを簡単に提供できるようにしました。

"shlyfile" というファイルをプロジェクトディレクトリ直下に置き、そこで shly コマンドを実行するとビルトインコマンドのようにプロジェクトコマンドが実行できます。

たとえば以下のようなshlyfileを作った場合、

;; shlyfile
(defun test ()
  (asdf:test-system :clack))

プロジェクトルートでshly testすればテストが走るようになります。

$ shly test

Quickdocsでも早速shlyfileを導入しました (ファイルをみる)。

(defun start (&key (mode :production)
                   (server-port 8080)
                   (swank-port *default-swank-port*)
                   (server :fcgi)
                   (error-log #p"/dev/null"))
  (quickdocs.server:start-server :mode mode :debug nil :server server :port server-port :error-log error-log)
  (swank:create-server :port swank-port :style :spawn :dont-close t))

shly start --port 8080 などでWebサーバとSwankサーバを起動できます。

試すには

Shellyのリポジトリをcloneしてインストールが必要です。

$ git clone https://github.com/fukamachi/shelly
$ cd shelly
$ SHELLY_PATH=. bin/shly install
LISP_IMPL isn't set. Auto detecting...
Installed Lisp: sbcl, ccl, alisp, clisp, cmucl
Which do you prefer? [sbcl] : ccl
Warning: Core image wasn't found. It is probably slow, isn't it? Try "shly dump-core".
To load "shelly":
  Load 1 ASDF system:
    shelly
; Loading "shelly"


Successfully installed!
Add this to your shell rc file (".bashrc", ".zshrc" and so on).

    PATH=$HOME/.shelly/bin:$PATH

これで ~/.shelly/bin/shly にコマンドがインストールされるのでPATHを通せばshlyコマンドが使えるようになります。

おわりに

Kyoto.lispで紹介したときは、面白いけど利用場面が限られる、という感じだったけど、今回の修正でライブラリ提供者がインターフェイスとしてシェルコマンドを簡単に提供できるようになったのは大きいと思います。

今後、プロジェクト固有だけでなく、Shellyプラグインのようなもので開発環境グローバルで使えるコマンドが増やせるようにすればより面白くなりそうです。ClojureLeiningenにイメージは近いかなー。

lein new [project name]とかはこんな感じでinitファイルに書けばよさそう。

#+shelly
(ql:quickload :cl-project)
#+shelly
(defun new (path &key name description (license "LLGPL"))
  (cl-project:make-project path
                           :name name
                           :description description
                           :author "Eitarow Fukamachi"
                           :email "e.arrows@gmail.com"
                           :license license))

shly new sunaba --description "良い子の砂場。"みたいにするとsunabaライブラリのテンプレートが生成される。便利。

利用範囲が広いので、皆さんいろいろ試してみてください。