choice-program 20161230.1721(in MELPA)
parameter based program

概要

choice-program.el は、

  1. 候補リストを得て
  2. その候補に対して何らかのアクションを行う

プログラムを実行することを支援します。

たとえば、gitでは

  1. git branch でブランチのリストを得て、
  2. git checkout でそのブランチに切り替えます。

Rubyのパッケージ(gem)を扱う gem

  1. gem search で全gemのリストを得て、
  2. gem install でそのgemをインストールします。

このようなプログラムでは
候補リストからアクションを選択できると、
とても便利ですよね!

そこでchoice-program.elが役立ちます。

リストを得るのは
同期プロセスで行われるので
多少待たされますが、

アクションは
compilation-mode を使うため
待たされません。

インストール

パッケージシステムを初めて使う人は
以下の設定を ~/.emacs.d/init.el の
先頭に加えてください。

(package-initialize)
(setq package-archives
      '(("gnu" . "http://elpa.gnu.org/packages/")
        ("melpa" . "http://melpa.org/packages/")
        ("org" . "http://orgmode.org/elpa/")))

初めてchoice-programを使う方は
以下のコマンドを実行します。

M-x package-install choice-program

アップグレードする方は、
以下のコマンドでアップグレードしてください。
そのためにはpackage-utilsパッケージが必要です。

M-x package-install package-utils (初めてアップグレードする場合のみ)
M-x package-utils-upgrade-by-name choice-program

使い方

候補選択は

$ ${interpreter} ${program} ${selection-args}

で行われます。

アクションは

$ #{interpreter} ${program} ${choice-switch-name} 選択した候補

で行われます。

git ではそのまま使えます。

以下の設定で
M-x git-checkout
が定義されます

(require 'choice-program)

(defvar git-checkout-instance
  (choice-prog nil
	       :interpreter nil         ;スクリプトではないときはnilの指定が必須
	       :program "git"
               :buffer-name "*git-checkout*"
	       :verbose-switch-form ""  ;おまじない
               :choice-prompt "Branch"
	       :choice-switch-name "checkout" ;アクションを行うときの引数
	       :selection-args '("branch") ;候補選択のときの引数(これはリストで渡す)
	       :documentation
               "Run git-checkout from git-branch")
  "The git-checkout object instance.")

(choice-prog-create-exec-function 'git-checkout-instance 'git-checkout)

20170105104508.png
Fig1: emacsリポジトリでM-x git-checkoutを実行する(ivy を有効にした状態で)

20170105104515.png
Fig2: emacs-25を選択すると git checkout が実行される

補完は
completing-read を使っていますので、

helm/ido/ivy/anythingなど
お好きなインターフェースを
使ってください。

制限

selection-args
引数をリスト渡す必要があるため、
アクションに渡すための
加工ができません。

たとえば、
emacsの開発リポジトリにおいて
git branch を実行すると

  dynamic-modules-rc2
  emacs-25
* master
  xwidget
  xwidget_mvp

と出ますが、
最初の2列を削除できません。

幸い
現在のブランチである master
選択することはないので
問題はありません。

gem list のように
バージョンも表示される場合は、
ラッパースクリプトで
gem名のみを取り出す必要があります。

$ gem list
- (1)
0mq (0.5.3)
0xffffff (0.1.0)
10to1-crack (0.1.3 ruby)
略

【重要】過度な抽象化は逆に理解を困難にさせる

とはいえ、正直なところ
この程度のことならば、

わざわざ複雑な
choice-program.elを
使わなくても

簡単なコマンドを
定義すればいいだけです。

choice-program.elは
eieioというオブジェクト指向
で書かれているため、

初見さんがプログラムを
理解して使いこなすまでに
時間がかかります。

この程度ならば
普通に自分でコマンドを
定義した方が楽ですし、
理解が容易です。

(defun git-checkout (branch)
  (interactive
   (list (completing-read
          "Branch: "
          (split-string
           (shell-command-to-string "git branch | grep -v '^\\*' | cut -c3-" ) nil t)
          nil t)))
  (compilation-start (format "git checkout %s" branch)))

上記のM-x git-checkoutは

  • list
  • completing-read
  • split-string
  • shell-command-to-string
  • compilation-start
  • format

と初歩的な関数のみで
構成されています。

どちらが理解しやすいのかは
火を見るよりも明らかです。

しかも
grep -v で現在のブランチ、
cut で余計なスペースを
取り除いています。

過度の抽象化は
かえって理解を困難にさせる
ということの見本です。


本日もお読みいただき、ありがとうございました。参考になれば嬉しいです。