ページ

2013-11-17

コマンドのハードコーディングを回避する仕組み

/bin/sh決め打ちとかそういうのを回避するために使う。こういうの、他の人も色々書いてる気がするけど。

(defvar alternate-program-table
  (make-hash-table :test 'equal))

(defmacro define-alternate-program (program alt)
  `(puthash ,program ,alt alternate-program-table))

(defun alternate-program (program)
  (gethash program alternate-program-table))

(defadvice start-process (around kludge-for-hard-coding (name buffer program &rest program-args) activate)
  (let* ((alternate (alternate-program program))
         (program (or (if (consp alternate) (car alternate) alternate) program))
         (program-args (if (consp alternate) (append (cdr alternate) program-args) program-args)))
    ad-do-it))

こういう感じに使う。

(defmacro when-windows (&rest body)
  `(if-windows (progn ,@body)))

(when-windows
  (define-alternate-program "/bin/sh" '("fakecygpty" "/bin/sh")))

Cygwin環境とfakecygptyがちゃんとあれば、term.elのansi-termとかがWindowsでもきちんと動作するように。

2013-03-03

HelmとSKKのキーバインドの競合

正確に言うとHelmじゃなくって、helm-files.elが読み込むdired-x.elSKKがC-x C-jのキーバインドで競合する。

(setq dired-bind-jump nil)

Helmを読み込む前に書いておくとC-x C-jにdired-xの機能が割り当てられなくなるため、競合を回避できる。dired-bind-jumpのdocstring曰く

Non-nil means bind `dired-jump' to C-x C-j, otherwise do not.
Setting this variable directly after dired-x is loaded has no effect -
use \\[customize].

とのことなので、くれぐれも設定する位置には注意すること。

この問題自体は既知の問題らしくて、「dired-x C-x C-j」で検索するといくつも情報が出てくる。

2013-01-17

LinuxでのJava SE JDKインストール手順メモ

多少手順が必要だったので現時点での注意点を自分用にメモ。

まず、検索で最初に引っかかるjava.comからはJREしかダウンロードできないので、JDKをダウンロードするのはOTNのJavaのページから。(java.comには開発者向けのJDKの案内やリンクなどはないように見える)案内に従って、米国のサイト経由で自分の環境に合ったパッケージ、あるいはアーカイブをダウンロードする。

ダウンロードが終わったら、パッケージを利用する場合はパッケージ管理ツールを使い、手動でインストールする場合はアーカイブを展開して/optなどに手動でインストール。詳細はダウンロードのページからインストールのガイドにリンクが張ってあると思われるのでそれを参照。JDK 7の場合は"JDK 7 Installation for Linux Platforms"。

その後は、手動でJava SEのバージョンを管理するのであれば、シンボリックリンクなども利用しつつ、PATH環境変数を利用して管理。dpkg由来のupdate-alternativesで自動化するのであれば、

% update-alternatives --get-selections

でJavaに関連する既存のグループを調べつつ、

% sudo update-alternatives --install /usr/bin/java java /usr/java/jdk1.7.0_11/bin/java 40
% sudo update-alternatives --config java
% sudo update-alternatives --install /usr/lib64/browser-plugins/javaplugin.so javaplugin /usr/java/jdk1.7.0_11/jre/lib/amd64/libnpjp2.so 40
% sudo update-alternatives --config javaplugin

といった感じで設定を変更する。手動で設定を切り替えるなら、優先度の値は何でも構わない。

2013-01-16

Ruby on Rails

色々とあって、Ruby on Railsを試しているところなんだけれど、ウェブアプリケーションを作るときに必要になる部分がかなり高度に抽象化、自動化されている感じで、人気がある理由が少し理解できた気がした。ここまで洗練させるにはかなりの労力が必要だったんじゃないかと考えると、開発してきた人たちを素直に称賛したい所存。

そしてMVCアーキテクチャ。こういう方向性のフレームワークに触るのはMFC以来かも。もう記憶が曖昧。

今だと、こういうので作ったアプリケーションを公開するのにHerokuとかのPaaSを使ったりする感じだろうか。良い時代だと思う。割と今更感溢れる感想だけど。

2012-09-25

percent-encoding

Qiitaに投稿したパーセントエンコーディングについてのTipsにも書いたんだけど、自分の知ってるライブラリはどうも帯に短し襷に長しといった感じで、

  • application/x-www-form-urlencodedも扱える(似ているものなので、同じライブラリで扱いたい)
  • ASCIIに収録されていない文字を任意のエンコーディングでオクテット列に変換し、パーセントエンコーディングできる(今なら大体UTF-8で済みそうだけど、できれば他のエンコーディングも扱いたい)

という条件のものは見つからず、色々試行錯誤していた。

そんな折に@snmstsさんが教えてくださったのがdo-urlencodeで、普通のパーセントエンコーディングもapplication/x-www-form-urlencodedも両方扱えるし、UTF-8決め打ちとはいえ自分はUTF-8くらいしか使わないだろうから良いか、ということで使ってみた。

それで、使ってみて気付いたんだけど、どうもメモリの消費がちょっと多い。そしてちょっと遅い。

(let ((str (map 'string (lambda (_)
                          (declare (ignore _))
                          (code-char (random 255)))
                (make-string (* 1024 1024)))))
  (null (time (puri::encode-escaped-encoding str puri::*reserved-characters* t)))
  (null (time (urlencode:urlencode str))))

;; CCL 1.8
;; (PURI::ENCODE-ESCAPED-ENCODING STR PURI::*RESERVED-CHARACTERS* T)
;; took 82,384 microseconds (0.082384 seconds) to run.
;; 13,839 microseconds (0.013839 seconds, 16.80%) of which was spent in GC.
;; During that period, and with 2 available CPU cores,
;; 64,990 microseconds (0.064990 seconds) were spent in user mode
;; 13,998 microseconds (0.013998 seconds) were spent in system mode
;; 18,647,856 bytes of memory allocated.
;; 40 minor page faults, 0 major page faults, 0 swaps.
;; (URLENCODE STR)
;; took 7,272,771 microseconds (7.272771 seconds) to run.
;; 1,337,318 microseconds (1.337318 seconds, 18.39%) of which was spent in GC.
;; During that period, and with 2 available CPU cores,
;; 7,079,924 microseconds (7.079924 seconds) were spent in user mode
;; 171,974 microseconds (0.171974 seconds) were spent in system mode
;; 1,178,938,384 bytes of memory allocated.
;; 264 minor page faults, 0 major page faults, 0 swaps.

;; SBCL 1.0.58
;; Evaluation took:
;; 0.053 seconds of real time
;; 0.052993 seconds of total run time (0.046993 user, 0.006000 system)
;; 100.00% CPU
;; 124,622,974 processor cycles
;; 18,647,216 bytes consed
;;
;; Evaluation took:
;; 3.412 seconds of real time
;; 3.395483 seconds of total run time (3.268503 user, 0.126980 system)
;; [ Run times consist of 0.404 seconds GC time, and 2.992 seconds non-GC time. ]
;; 99.50% CPU
;; 7,962,815,308 processor cycles
;; 770,256,208 bytes consed

これはpuriのエンコーダと比較した結果なんだけど、4MB分の文字列を扱うのにCCLで1GB超、SBCLで700MB超のメモリを使っている。ワーオ。

コードを読んだところ、どうもエスケープ一回ごとに文字列とベクタのアロケーションが起きるようになっていた。ここを何とかすればメモリ消費量や処理速度が改善できるんじゃないだろうかうへへ、ということで改造することに。

で、試行錯誤の結果、大幅にメモリ消費量と速度は改善した。したんだけど、どうも中身が完全に別物になってしまった。総書き換えといった感じで、これを作者に取り込むように主張しても、「お前これ同じなの関数のインターフェイスだけやん」と言われる未来が容易に想像できたので、仕方なく別のライブラリに仕立てることにした。「自分で書いてしまったりしがち」とかQiitaのTipsに書いておいてこれだから割と救いようがない。

そうと決めたらもう開き直って、UTF-8以外のエンコーディングのサポートとか、puriで見かけて良いと思った、どの文字をエスケープするか指定できる機能とかも付けてみた。その結果がこれGitHubのミラーもある。

普通に使う分には難しいことはなく、

(percent:encode str)

とすればエンコードできるし、

(percent:decode str)

とすればデコードできる。エンコードやデコードする文字を指定する場合はこんな感じ。

;; 特定の文字だけエンコードしたり
(percent:encode "/usr/bin/["
                :test (lambda (x)
                        (or (percent:unreservedp x)
                            (= x #x2f))))    ; '/'
;=> "/usr/bin/%5B"

;; 特定の文字だけデコードできる
(percent:decode (percent:encode "a:b/c" :test (constantly nil))
                :test #'percent:alphap)
;=> "a%3Ab%2Fc"

こんなことできて何が嬉しいの? という風に思うかもしれないけど、URIはそれぞれのコンポーネントで許される文字が違うので、そういうのに対応するときに便利。あとはする必要がない文字までエンコードしてるURIの正規化とか、規格に沿わない実装に対応するのにも使える。詳しい使い方はREADMEやユニットテストを参照のこと。

あんまり需要はないと思うけど、自分で使うために書いたので問題ない。将来的にもっと良さげなライブラリを見つけたらそっちを使うかも。というか、誰か書いてください。