Skip to content
Tags

分割設定ファイルローダ、el-initをリリースしました

2015/01/27

リポジトリはこちらです。

el-initは init-loader のように、分割された設定ファイルを 読み込むためのローダです。 init-loaderでは load を使って設定ファイルを読み込むのに対し、 el-initでは require を使用します。 そのためにいくつかのinit-loaderには無い制約が存在します。

インストール

el-initは melpa に登録してあるので、emacsで

M-x package-install el-init

とすることでインストールできます。

基本的な使い方

例としてel-initで読み込みたい設定ファイルが ~/.emacs.e/init にあるとして、 それらをel-initで読み込むには次のようにします。

(require 'el-init)

(el-init-load "~/.emacs.d/init"
              :subdirectories '("."))

こうすることによって、 ~/.emacs.d/init にある設定ファイルが require を使って読み込まれます。

ただし、ロードに ruquire を使っているので、設定ファイルに適切な provide 式を記述しておく必要があることに注意してください。 そうしないとエラーが発生します。

provide の記述は少々面倒なので、el-initには el-init-provide という ユーティリティ関数が用意されています。 これはファイル名を元に provide を呼び出します。 これを各設定ファイルの最後に書き加えてください。

(require 'el-init)
(el-init-provide)

(require 'el-init) はなくても動作しますが、書いておくことをおすすめします。

ロード順の決定方法

el-initとinit-loaderの大きな違いはロード順の決定方法にあります。 init-loaderではファイル名の番号付けによってロード順が決定するのに対し、 el-initでは基本的に require の仕組みを利用します。

従って、ある設定ファイルが他の設定ファイルに依存している時、 依存先のファイルを require することによって期待するロード順に なるようにします。

例えば init-bar.elinit-foo.el に依存しているなら

;; init-bar.el
(require 'init-foo)

とします。

el-initには require を使う方法以外にもう1つ、 ロード順を決める方法があります。 それはディレクトリを分ける方法です

これは、パッケージマネージャの初期化やロードパスの整備などの環境設定ファイルと 各パッケージ向けの設定ファイルのような、直接依存関係があるわけでは無いが ロード順の関係は存在する場合に便利です。

例えばパッケージマネージャの設定が ~/.emacs.d/init/pm に、 各パッケージ向けの設定が ~/.emacs.d/init/config にある場合、 el-init-loadsubdirectories 引数を次のようにします。

(el-init-load "~/.emacs.d/init"
              :subdirectories '("pm" "config"))

こうすることで最初に ~/.emacs.d/init/pm にあるファイルが読み込まれ、 次に ~/.emacs.d/init/config にあるファイルが読み込まれます。

require を使用することによる制約について

1つは上で述べたように provide を呼び出す必要があることで、 もう1つは設定ファイル名を他のemacs lispと被らないようにする必要がある、 ということです。 ファイル名が被ってしまうと、他のemacs lispをシャドウすることになるので 注意してください。

require ラッパーについて

el-initには require ラッパーという仕組みがあります。 これは設定ファイルを読み込む際に使用する require を ラップできるようにするもので、el-initでは 設定ファイル内で発生したエラーの記録やロード時間の計測に この仕組みが使われています。

el-initにはすでにいくつかのラッパーが定義してあります。 使用するラッパーを指定するには el-init-loadwrappers 引数を使用します。

例えばエラーを記録する el-init-require/record-error と ロード時間を測る el-init-require/benchmark を使いたいなら、 次のようになります。

(el-init-load "~/.emacs.d/init"
              :subdirectories '(".")
              :wrappers '(el-init-require/record-error
                          el-init-require/benchmark))

ちなみにデフォルトでは el-init-require/record-error のみが使用されます。

また、ラッパーは自作することも可能です。 ラッパーは require と同じ引数を持つ関数として定義し、 その中で require の代わりに el-init-next を呼び出します。

例として el-init-require/ignore-errors は次のように定義されています。

(defun el-init-require/ignore-errors (feature &optional filename noerror)
  (ignore-errors (el-init-next feature filename noerror)))

wrappers で指定されたラッパーは、リストの先頭のラッパーが呼びだされ、 そのラッパーが el-init-next を呼ぶことでリストの次のラッパーを呼び出し、 そしてまたその次へと呼び出しが行われ、リストの最後のラッパーで el-init-next が呼び出されることで require が呼び出されます。

また、 el-init-next を呼び出さないようにすれば、特定のファイルだけ 読み込みをスキップすることができます。 el-init-require/system-case ではこの仕組みを利用しています。 ただ、オーバーライドとの関係で設定ファイル内からの require でも 同様に動作するため、el-initの読み込み対象には含めたくないけど設定ファイルから require されたら読み込まれてほしいというような場合にはディレクトリを 分けておくの方が無難でしょう。1

el-init-load の引数について

el-init-load の引数は次のようになっています。

(el-init-load directory
              &key
              subdirectories
              wrappers
              override
              override-only-init-files)

directory

これはロードの基準となるディレクトリを指定します。

subdirectories

これは実際にロードの対象にするディレクトリを指定するリストです。 directory からの相対パスのリストで、このリストの先頭のディレクトリから 順にロードが行われます。 もし、 directory 自身も含めたい場合には、”.”も含める必要があることに 注意してください。

また、ディレクトリと中にあるディレクトリを再帰的に対象に含めたい場合には、 2番目の要素が t のリストを指定します。

次のようなディレクトリ構成の時に

~/.emacs.d/init
├── config
│   ├── ext
│   │   └── init-helm.el
│   └── lang
│       └── init-javascript.el
└── pm
    └── init-package.el

config 内を再帰的に対象にしたいなら、次のようにします。

(el-init-load "~/.emacs.d/init"
              :subdirectories '("pm" ("config" t)))

デフォルト値は

(".")

です。

wrappers

ロードする際に使用するラッパーを指定します。 デフォルト値は

(el-init-require/record-error)

です。

override

これは設定ファイル内で呼ばれた require に対してもラッパーを 有効にするかどうかのオプションです。 デフォルトでは t で、有効にしています。

override-only-init-files

これは設定ファイル内で呼ばれた require に対してラッパーを 有効にする場合、設定ファイルに対してのみラッパーを作用させるための オプションです。 この引数がnon-nilなら、ラッパーは設定ファイルにのみ作用し、 ライブラリのロードには作用しません。 デフォルトでは t です。 設定ファイルかどうかは el-init-load の対象かどうかで決まります。

狙い

el-initの主な狙いは2つあります。

1つは分割した設定ファイルそれぞれがemacs lispファイルとして 適切に記述できるようにすることです。 つまり auto-async-byte-compile.el のような形でバイトコンパイルをしても 警告が出ない、もしくは正しい警告が得られるようにすることです。 そのために設定ファイル自身に依存関係を明示できるよう require を使用しています。

そして、もう1つはユーザーが自由にロード処理を 選択、拡張できるようにすることです。 このために require ラッパー機能があります。

以前のel-initとの違いについて

現在のel-initは、以前紹介した時に比べて色々と変更がなされているので 注意してください。 レキシカルスコープが有効になっていたり、接頭辞が el-init: から el-init- に変更されています。 詳しくは ChangeLog.org を確認してみてください。

また、当時のコードはバージョン0.0.9としてタグを打ってあるので、 githubのリリースからアーカイブをダウンロードすることができます。 どうしても古いバージョンが必要な人はそちらを使ってください。

開発について

travis ciを使うにあたって下記のページを参考にしました。

テスト用のemacsは evm を使って用意しています。 テストしているバージョンは24.1から24.4までです。 23系列が無いのはcaskが動かないからです。

バイトコンパイル時の警告もテスト対象にしていますが、 組み込みでない cl-lib を使うと警告が出てしまうので、 emacs 24.1と24.2は警告を許すようにしました。

また、カバレッジ計測に undercover.el を使っています。 undercover.elについては下記のページを参考にしました。

edebugをもとにしているということで、計測対象をバイトコンパイルすると 計測できないことに気付かずしばらくハマりました。 また、現状では cl-defun もうまく計測できないようです。

今後について

el-initについてはあまり大きな変更は予定していません。 それと今回紹介しなかった機能に el-init-record というものがあって、 それのビューアを今作っています。 それでエラー内容やロード時間が確認できるようになる予定です。

また、el-initでは機能廃止の際に削除されるまでの間、 なるべく警告が出るようにしているので、 アップデートした際には注意してみてください。

最後に

もし、質問などがあればこのブログのコメントか twitter や githubの issues で 聞いてもらえるとありがたいです。

Footnotes:

1

オーバーライドされた require からの呼び出しかどうかを判定する APIを用意するか検討中です。

広告

From → Emacs

コメントする

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。