こっそり quickutil を使ってみた

トラブってたのを一つ前の記事に書いたわけですが、今度は調査メモです。

ネットを彷徨っていたところ quickutil の記事を見付けまして、色々試してみたんですよ。
まあ、公式サイトの http://quickutil.org/ の方で「under maintainance」って書いてあるので駄目元だったんですが。
なんとなく動いた感じなので方法をコッソリと書いておこうかと。
もちろん、やる場合には自己責任です。っていうかメンテ明けまで待つのが正しい態度ですよね…

使うだけなら次のようにすればいいです。
あらかじめ quicklisp を使えるようにしておいて下さい。
使いたいユーティリティは :shuffle だとします。適宜、置き換え願います。
リストを渡すので、一度に複数でも大丈夫のようです。

;; 準備
(ql:quickload 'quickutil)
;; 利用のための宣言(引数はキーワードのリストらしい)
(qtlc:utilize-utilities '(:shuffle))

;; 利用は "qtl:ユーティリティ名" で呼び出す模様
(qtl:shuffle '(3 2 1))

なお、ユーティリティのリストは以下で見られました。

;; 準備
(ql:quickload 'quickutil-utilities)

;; 全部
(qtl-utl:all-utilities)
;; カテゴリの一覧
(qtl-utl:all-categories)
;; カテゴリ内にあるユーティリティの一覧(例では integers カテゴリ)
(qtl-utl:utils-in-category :integers)

Use at your own risk!

いきなり slime が動かなくなった件

原因は不明ながら、slime が急にエラーで動かなくなってしまったので経過をメモ。
(思い出しながら書いているので、あやふやな部分あり)

検索したサイトを見ながら popwin の設定やら ac-slime のインストールやらをしていたら、ある時 M-x slime するとエラーするようになってしまった。
※正確には swank サーバへの接続待ちのままになった。表示通りに M-x slime-abort-connection するとキャンセルされて REPL には入れる。

その状態で (require 'asdf) (require 'alexandria) すると /usr/share/common-lisp/source/cl-asdf/build/asdf-TMP.lisp が FILE OPEN エラーになってデバッガに入ってしまった。
emacs を終了してコンソールから直接 sbcl で実行しても同じエラーになった。

~/.cache/common-lisp/ を削除してみたが直らず。
apt で slime と cl-asdf を再インストールしてもダメ。

以前に作成した以下のファイルを削除したら slime は起動するようになった。

;;;; ~/.config/common-lisp/source-registry.conf
(:source-registry
  (:tree "~/quicklisp/dists/")
  :INHERIT-CONFIGURATION)


require もエラーしなくなった… はず。ただ、相変らず (require 'alexandria) の返り値が nil だったのでダメかと思って作業を継続した。
この時点で最終結果と同じ状態に戻っていたのかもしれない。
(require 'asdf) の返り値が nil だったかは覚えていない。

その後、~/quicklisp/ も削除して slime から (load "/usr/share/cl-quicklisp/quicklisp.lisp") (quicklisp-quickstart:install) で再インストールしてみた。
ここで (ql:quickload 'alexandria) するとインストールが行われ、(alexandria:lastcar '(a b c)) が動作した。
そのまま更に (ql:add-to-init-file) を実行して設定ファイル(sbcl だったので ~/.sbclrc)に quicklisp の自動ロードを設定した。
一旦 emacs を再起動し、require するも返り値は nil のまま。
コンソールから sbcl でやっても同じく nil が返っていたが、何の気なしに alexandria:lastcar をやってみたら動作した。

ふと思い付いて .sbclrc の quicklisp 設定をコメントアウトしてから、コンソールで (require 'alexandria) したらエラーになった。
そのまま (load "~/quicklisp/setup.lisp") したところ alexandria:lastcar が動作した。

quicklisp 設定をコメントアウトしたままの状態で ~/.config/common-lisp/source-registry.conf をエラー前に戻してみた。
そうしたら (require 'alexandria) がエラーせずに nil を返し、alexandria:lastcar も動作するようになった。

元々は .sbclrc の quicklisp 設定はコメントアウトされていたので、結局エラー前と同じ設定に戻ったことになる。
経過から見るとキャッシュを壊していた確率が高いが、問題の原因は特定できず…
とりあえず動作するので、まあいいかと。

最終的にはコンソールでも slime でも以下のように動いている。
(行頭に「?>」があるのがプロンプトと入力内容で、次のプロンプトまでが出力)

?> (require 'asdf)
("ASDF" "asdf" "UIOP" "uiop")

?> (alexandria:lastcar '(a b c))
※以下のエラーが発生した
debugger invoked on a SB-INT:SIMPLE-READER-PACKAGE-ERROR in thread
#:
Package ALEXANDRIA does not exist.

Stream: #

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT] Exit debugger, returning to top level.

(SB-IMPL::READER-FIND-PACKAGE "ALEXANDRIA" #)

※ 0 でデバッガを終了してトップレベルに戻る

?> (require 'alexandria)
nil

?> (alexandria:lastcar '(a b c))
c

以上。

persp-mode を設定してみた(ついでに helm も)

えー、今回は common lisp のコードを書こうと思ったらキーバインドが気になって、init.el を編集してるうちに elisp パッケージ探しに走ってしまい、気が付いたらリファレンスを見ながら elisp を書いていたという yak shaving の最たるものになってしまいました。
なので、せめて動いたコード片だけでも載せておこうと思います。

以下は persp-mode で新規パースペクティブを作成した時(厳密にはバッファがないパースペクティブに切り替えた時)にバッファを選択して登録する設定です。
毎度おなじみ rubikitch 様のサイトからコピーして、四苦八苦しながら希望する動作になるよう改造(改悪?)しました。
ホント、いつもお世話になってます。密度の濃い情報ありがとうございます。 > rubikitch 様
設定した persp-mode のバージョンは 20161226.2218 です。

;;; persp-mode 設定
(setq persp-add-on-switch-or-display t)
(persp-mode 1)
;;; 新規パースペクティブ作成時に追加するバッファを選択する
(defun persp-register-buffers () ; 関数名変更
  (interactive)
  (dolist (bufname (condition-case _
                       (helm-comp-read
                        "Buffers: "
                        (mapcar 'buffer-name (buffer-list))
                        :must-match t
                        :marked-candidates t)
                     (quit nil)))
    (persp-add-buffer (get-buffer bufname))))
;; ここから追加分
(defun persp-register-buffers-if-empty (mode)
  (interactive)
  (if (null (persp-buffer-list)) ; パースペクティブのバッファが空の時だけ
      (persp-register-buffers))) ; 上のバッファ選択関数を呼ぶ
(add-hook 'persp-activated-functions 'persp-register-buffers-if-empty) ; フック名が変わった?

それから、persp-mode 用の helm アクションも見様見真似で作ってみました。
いちおう動いているようですが、使用は自己責任でお願いします。

(defun helm-persp-add-buffer (buffer-or-name)
  (persp-add-buffer (helm-marked-candidates)))
(defun helm-persp-kill-buffer (buffer-or-name)
  (persp-kill-buffer (helm-marked-candidates)))
(setq helm-type-buffer-actions
      (append helm-type-buffer-actions
              '(("Add buffer(s) to perspective" . helm-persp-add-buffer)
                ("Kill buffer(s) from perspective." . helm-persp-kill-buffer))))

以上です。

コードのスタイルを統一するなら EditorConfig

複数の作業環境を渡り歩いてソースコードを編集することって結構ありますよね?
こんな時、新しく編集した部分だけインデント文字(タブかスペース)やオフセットが変わってしまって、手作業でスタイルを合わせる破目になった経験があるでしょう。
テキストエディタが同じなら作業前に設定ファイルをコピーすればなんとかなりますが、違うエディタだと設定に使った時間の方がコーディング時間より長くなったという悲劇(笑い話?)も聞きます。

そんな時に頼りになる最終兵器 EditorConfig を発見しました。
共通の設定ファイルを用意しておけば、エディタにプラグインを入れるだけで同じスタイルで書けるようにしてくれます。
設定できる項目はインデント文字、オフセット幅、改行文字、文字コード等です。
ディレクトリを遡りながら設定ファイルを探すので、スタイルがプロジェクトごとに違っていても対応できます。

興味がわいた方は、分かりやすい説明がここにあるので参照してみてください。

参考

  • 公式サイトはここ
  • Emacs 用プラグインは Github

common lisp で何か書いてみる(その2)

どうも。
最近の投稿ペースが速くて自分でも驚きながら書いています。

さて、引き続き caveman2 で何か書いてみようという話です。
が、今回もまた自前のコードを入力する機会は訪れませんでした…

とりあえず目次は以下の通りです。

  • Road to qlot:quickload
  • 穴居人が立ち上がる時

■Road to qlot:quickload

結論:行ってみた限りでは全部行き止まりでした。

や、色々試したんですよ、ホントに。

qlfile の中身を次のようにして、それぞれコメントアウトしながら全部試しました。

# qlfile

github caveman2 fukamachi/caveman
# git caveman2 https://github.com/fukamachi/caveman.git
# ql caveman2 :latest

インストールコマンドも色々やってみました。

  • プロジェクトディレクトリで
    • (qlot:install :myproj1)
    • (qlot:install)
    • (qlot:install :caveman2)
  • プロジェクトディレクトリの一つ上で
    • (qlot:install :myproj1)
    • (qlot:install)
    • (qlot:install :caveman2)

見付けた変数を変えてみたりもしました。

(setq ql-setup:*quicklisp-home* #P"~/myproj1/")
(qlot:quickload :caveman2)

上の色々な組み合わせも試しました。

最終的に挫折しました…(泣)

■穴居人が立ち上がる時

で、qlot を使わずに caveman2 だけでも動かしてみようと試行錯誤して、こちらは何とかサーバを立ち上げる事ができました。

前回で (ql:quickload :caveman2) は通るようになったので、github の README を読みながら進めていきます。

最初のプロジェクト作成は caveman2:make-project で問題無く終了です。

続いて、とりあえずテスト稼動が目的なので、ルーティングとかデータベース操作とかはどんどん飛ばして、サーバの立ち上げに入るわけです。

書いてある通り、おもむろに (myproj1:start :port 8080) を実行… 当然パッケージ myproj1 が無いと怒られます。
そして毎度の如く、苦闘の日々が始まるのです。

まあ、状況としては windows ユーザに linux の bash プロンプト使わせるようなものですね。
やりたい事は分かってるのに、どうやればいいのか分からないというジレンマに陥るわけです。

最終的に動くようになるまで

  • ファイルパスの指定方法
  • 読み込ませるファイル選択

で悩む事になりました。

パスの指定方法は make-project の引数にあったので、それでいけるはずです。
が、カレントディレクトリが何処なのかとか、うっかり #P を付けずに文字列で書いてしまったりとかで、なかなかうまく行きませんでした。

さらに、読み込むファイルが分からないという点が問題の複雑さに拍車をかけることになります。

コマンドの方は load か require あたりだろうと推測しましたが、ファイルに関しては見当もつかなかったので、考えていても仕方無いと割り切って総当たりして解答に辿り着きました。

誰かの役に立つかどうか怪しいところですが、いちおう最終形を載せておきます。

(ql:quickload :caveman2)
(caveman2:make-project #P"~/myproj1/" :author "myname") ; '#P' を付けないとエラー、ディレクトリは未作成でもよい

(load #P"~/myproj1/myproj1.asd") ; これと次は '#P' 無しでも動いたが、一応付けておく
(load #P"~/myproj1/app.lisp")
(myproj1:start :port 8080)

以上です。

common lisp で何か書いてみる(その1)

いつもの如く、唐突に common lisp の勉強をしようと思い立ち、色々見ながら環境設定をしたのでメモ。

思い付きで行動したので、あちこちで袋小路に突き当たりまくっているのは相変らずである。

■alpine linux で環境設定してみた

始まる前から後のことを考え、docker コンテナで動かすと面白そうということで virtualbox で新しく VM を作って alpine linux をインストールした。
debian とか ubuntu と違って、ISO 起動でインストーラが走ってくれるわけではなくて、Wiki を見ながら何とか導入。
パッケージは sbcl と clisp があったから「apk add」で簡単に入った。
ちなみに何度も「apt install」と入力してしまったのはご愛嬌。

問題はここからで、common lisp のパッケージ管理ライブラリ quicklisp を入れてみたが動かない。
ライブラリ自体の読み込みはできるけれど、そこから他のライブラリの自動ロードをするとデバッグモードになってしまう。
しばらく格闘してみたが、このまま環境設定で時間を食ってもアレなので、alpine は放置することにした。

■debian GNU/Linux で環境設定してみた

というわけで、愛用の debian GNU/Linux の VM を立ち上げて、こっちで環境設定してみた。
慣れ親しんだ「apt-get install」で、あっと言う間に sbcl のインストールが完了。
cl-quicklisp というパッケージもあったので、それも入れた。

で、プロジェクトごとにパッケージ管理をしてくれる(ruby の bundler みたいな) qlot というのを入れてみた。
これもすんなりと入ったので「よーし、これでコードが書けるぜー」とか思いながら、web フレームワークの caveman2 を入れ「ようとし」てみた。
…入ったよ、うん、結果的には。それだけで 1時間かかったのを気にしなければ。

その経緯

  1. qlot が初期化できない
    qlot が入った。ql:quickload でロードした。qlfile 書いた。
    さあ (qlot:install :myproj) …あれ?
    エラーした。
    qlfile を空にしてみてもエラーした。
    ライブラリ取得先を ql から git に変えてみてもエラーした。
    …よし、一旦放置。

  2. ql:quickload で caveman2 をロードできない
    さすがに直接 ql:quickload すれば動くだろう… あれ?
    エラーした。パッケージ名の書き方間違ったっけ?
    文字列で “caveman2” … エラー。
    キーワード形式で :caveman2 … エラー。
    クォートして ‘caveman2 … エラー。

    …落ち着け、キーボードは投げるもんじゃない。
    近場には HHK2Lite(英語) は売ってないんだ。
    それに買ったばかりのディスプレイに当たったらどうする。
    とりあえずお茶でも飲んで落ち着くんだ。

    (30分経過)…ふぅ、今日の茶菓子は美味かった。
    お、よく見たらエラーファイル名あるじゃん。cffi?
    とりあえず「apt-cache search」して… cl-cffi …って、そのまんまかい!
    駄目元でインストールっと。これで直ったら微妙だなぁ…
    (ql:quickload :caveman2) Enter!
    え、通るの?原因これだけ?私の30分を返せ!(←責任転嫁:嫁居ないけど)

  3. 改めて qlot
    んー、これなら qlot も動きそうな気がする。
    (qlot:install :myproj) っと。ん、エラー?
    …落ち着け、深呼吸だ。吸ってー、吐いてー、吐いてー、吐…けるかボケェ!吸わんと死ぬわ!
    ……やめよう、一人ボケツッコミは寂しすぎる…

    そうだ、さっきと同じくダイイングメッセージにヒントがあるに違いない。エラーでプロセス死んでるしな。
    死体は語る、犯人は現場に戻る(違)
    えーと…

    error while parsing arguments to DESTRUCTURING-BIND:
    invalid number of elements in
    ("caveman2:latest")」

    …待て、google 翻訳に頼るんじゃない。たぶん翻訳しても、そんなに変わらんし。
    一つずつ順番に行こう。

    • エラー
    • ↓している間
    • 解釈
    • 引数
    • ↓のため
    • DESTRUCTURING-BIND
    • (区切り)
    • 不正な
    • ↓の
    • 要素
    • ↓の中の
    • “caveman2:latest”

    まとめると
    「DESTRUCTURING-BIND のため(に)引数(を)解釈している間(に)エラー」
    「”caveman2:latest” の中の要素の数(が)不正」
    …ん?「caveman2:latest」って qlfile の書き間違い?
    あー、うん。たしかに違うわ。スペース必要なのね。

    よーし、これで動くはず。今日のおやつを賭けてもいい。
    (qlot:install :myproj) …エラー?え、おやつ抜き?えぇっ?
    くそぅ、この恨み晴らさでおくべきか。(←自業自得)
    二度ある事は三度あるのであるからしてヒントはエラーメッセージにあるのである。
    というわけでチェック!
    Component "myproj" not found
    うん、myproj は見付からないよね、今から作ろうと思ってるんだから。
    ……… もしかして :myproj の部分いらない?
    (qlot:install) っと… あー、うん。動いたね。動いちゃったね。
    私のおやつ返せ!(←再度の責任転嫁:もちろん嫁は居ない)

補足:没収されたおやつはスタッフ(= 私)がおいしくいただきました。

各言語のライブラリ管理ツールまとめ 他

雪降る朝にお届けしております。
最近、微妙に更新が多い感じですが、多分気のせいでしょう。

というわけで、なんとなく情報を集めたので紙からデータに起こしておこうかと思います。

■ ライブラリ管理ツール

出てくる言語の順序に他意はありません。思い付いた順です。経験と検索結果を焼いて砕いて粉にして、スプーン一杯すりきりにしてから載せております。

「コレが無いってどゆこと!」とか「こんなのはライブラリ管理ツールじゃねぇ」といったツッコミ大歓迎です。その熱い思いをコメント欄にぶつけて下さい。
続きを読む

tmlib のイベント処理について

色々あって、少し Quintus に浮気してた時間もあったんですが、また tmlib に戻って来ました。
それで、前からイマイチよく分かっていなかった「オブジェクトのイベント処理」について、ちょっとだけ前進した部分を書いておこうと思います。

他のプログラミング言語で「コールバック」と言われるイベント処理方式については知っていたんですが、tmlib での「イベント処理」がどうなっているのかは良く分かっていませんでした。
それで、ようやく少しだけ理解できたのが「対象オブジェクトの on メソッドを使う」という事です。
今回は tm.display.StarShape で描いた星を左右に往復させるのに tm.anim.Tween を使ったのですが、往路が終わった後に復路の移動を開始する(tmlib での)方法を見付けるのに四苦八苦した次第です。
続きを読む

tmlib でひっかかった点

今日二回目の投稿です。
ここ2日ほど tmlib をいじくり回していたので、途中でひっかかった点を残しておこうかと思います。

・サンプルによっては動かない
結構いろんな場所でサンプルが公開されているのですが、tmlib のバージョン次第で動作しない場合があります。
バージョンが明示的に書いてあればいいのですが、無いとどれだか分からないという…
頑張ってクラスのネームスペース移動とかを修正すると動くかもしれません。
続きを読む

altJSを始めるにあたって

いい加減 Webアプリに必須になってきた javascript を始めてみようと思ったが、素の JS は色々と面倒だという話を聞いた覚えがあったため、altJS と呼ばれる言語の方が良さそうだと思い、調査してみた。
何箇所かWebをサーフィンしてみて、結局のところ次のページが一番参考になった。

モダンな言語でHTML5を開発しよう! 俯瞰して理解するaltJSの比較 (前篇 – TypeScript, CoffeeScript, Haxe)
続きを読む