t

メモ

Incremental Search + Multiple Cursors

「複数カーソル」というものが便利だと教わった。調べてみたところ multiple-cursors.elsmartrep.el を使えば Emacs でも似たようなことができそうだったので、真似をしつつ設定を追加してみた。

まずは isearch-forward した状態から mc/mark-next-like-this したい。

(define-key isearch-mode-map (kbd prefix)
  #'(lambda ()
      (interactive)
      (push-mark isearch-other-end t 'activate)
      (isearch-exit)))
(smartrep-define-key global-map prefix ...)

これだと prefix を押さなければいけない回数が多くて嬉しくないのだけど、さしあたり良い案を思いつけなかった。

あとは選択状態に合わせてスクロールさせたい。これは mc/cycle-forwardmc/cycle-backward を呼ぶだけなので易しい。

(defun mc/mark-next-like-this-and-cycle-forward ()
  (interactive)
  (mc/mark-next-like-this 1)
  (mc/cycle-forward))
(smartrep-define-key global-map prefix
  '(("C-v" . 'mc/cycle-forward)
    ("M-v" . 'mc/cycle-backward)
    ("n"   . 'mc/mark-next-like-this-and-cycle-forward)
    ...))

ついでにsmartrepによるコマンド実行中はキー入力をエコーしないようにしたら快適だった。

First Step of Customizing Magit

主に magit-status, magit-show-level-4, magit-commit を快適に使うべく、いくつかのサイトを参考に設定してみた。

;; http://d.hatena.ne.jp/syohex/20130904/1378310201
(defadvice magit-status (around magit-fullscreen activate)
  (window-configuration-to-register :magit-fullscreen)
  ad-do-it
  (delete-other-windows))
(defun my/magit-quit-session ()
  (interactive)
  (kill-buffer)
  (jump-to-register :magit-fullscreen))
(define-key magit-status-mode-map (kbd "q") 'my/magit-quit-session)
(defadvice git-commit-commit (after move-to-magit-buffer activate)
  (delete-window))

;; http://qiita.com/dtan4/items/658a8a7ca06aa8c2da4c
(set-variable 'magit-emacsclient-executable "/usr/local/Cellar/emacs/24.3/bin/emacsclient")

;; http://www.clear-code.com/blog/2012/4/3.html
(set-face-background 'magit-diff-file-header "gray15")
(set-face-background 'magit-diff-hunk-header "gray18")
(set-face-background 'magit-diff-none (face-background 'default))
(set-face-foreground 'magit-diff-none (face-foreground 'diff-context))
(set-face-background 'magit-diff-add (face-background 'diff-added))
(set-face-foreground 'magit-diff-add (face-foreground 'diff-added))
(set-face-background 'magit-diff-del (face-background 'diff-removed))
(set-face-foreground 'magit-diff-del (face-foreground 'diff-removed))
(set-face-background 'magit-item-highlight (face-background 'helm-selection))
(setq magit-diff-refine-hunk 'all)

S3 File Resource for Chef

Chef で S3 からファイルをコピーするのに gist:DavidAllison/5288249 を使うと「S3の認証にIAM Roleを使うことができ、各EC2インスタンスにアクセスキーなどを配布する必要がありません」。これは嬉しい、と思ったら使われているメソッドが deprecated になってしまっていたり AWS SDK for Ruby の新しいメジャーリリースが近づいていたりしていたので少し手を入れてみました。

test-kitchen + kitchen-docker on Mac OS X

追記(2014-10-30): 少しだけ手順が変わった

実は簡単に使える状態になっているのではないか。

まず 公式ドキュメントを参考にしつつ Docker の設定をし、さらに test-kitchen や kitchen-docker をインストールする。

$ export DOCKER_HOST=tcp://127.0.0.1:4243
$ brew install boot2docker
$ boot2docker init
$ for i in {49000..49900}; do
  VBoxManage modifyvm "boot2docker-vm" --natpf1 "tcp-port$i,tcp,,$i,,$i";
  VBoxManage modifyvm "boot2docker-vm" --natpf1 "udp-port$i,udp,,$i,,$i";
done
$ boot2docker up
$ gem install test-kitchen
$ gem install kitchen-docker

次に .kitchen.yml を書く。

---
driver_plugin: docker

driver_config:
  use_sudo: false

provisioner:
  name: chef_solo

platforms:
  - name: ubuntu-12.04

suites:
  - name: foobar
    run_list:
      - "recipe[foo]"
      - "recipe[bar]"
    attributes:

そしてテストする。必要に応じて serverspec なども組み合わせる。

$ kitchen test

追記: ところで kitchen login したいのにパスワードが分からんと思っていたのだけど、どうやら kitchen だったらしい。

Json4s and Enumeration

json4sEnumSerializer がちょっと使いづらい。何となれば二つの Enumeration を同時に扱えない。

import org.json4s.DefaultFormats
import org.json4s.ext.EnumSerializer
import org.json4s.native.JsonMethods.parse
import org.json4s.native.Serialization.write

object E1 extends Enumeration { val v1 = Value }
object E2 extends Enumeration { val v2 = Value }
case class C(e1: E1.Value, e2: E2.Value)

implicit val f = DefaultFormats + new EnumSerializer(E1) + new EnumSerializer(E2)

val c = C(E1.v1, E2.v2)

println(c)                          // C(v1,v2)
println(parse(write(c)).extract[C]) // C(v2,v2)

EnumSerializer の実装を見ると EnumerationClass で他のクラスと区別をつけているようだが、残念なことに classOf[E1.Value]classOf[E2.Value] は区別がつかない。

println(classOf[E1.Value]) // class scala.Enumeration$Value
println(classOf[E2.Value]) // class scala.Enumeration$Value

さてどうしたものか。

追記: ScalaTypeTypeInfo を拡張して Type なり TypeTag なりを持たせるようにしていけば何とかできなくもなさそうだけど、コンストラクタを読み取る部分なども変えないといけないし割に合わなさそうなので当面はあきらめることにした。

$in MongoDB

MongoDB$in の実装がどうなっているのかと思ってソースをちょっと覗いてみた。


まず、ライセンスは AGPL 3.0 らしい。

とりあえず Matcher::matches の中で処理をしているに違いない、と当たりをつけてみる。そこには normal non-regex cases があって matchesDotted が呼ばれている。多分 $in を処理するときは、この中の compareOp == BSONObj::opIN が真になって valuesMatch が呼ばれるんでしょう。そうすると op == BSONObj::opIN なんていうそれっぽい式があって、ここの if 文の中で $in を処理しているように見える。bm の型は ElementMatcher らしいので bm._myset の型である set は pch.h で include してる set っぽい。じゃあ count の時間計算量は要素数 n に対して O(log(n)) とかかなあ。知らんけど。ところで ElementMatcher には _myregex なるものが定義されていて、実際に使われているみたいだけど何かしらん。多分 $regex とかいうやつだなあ。多分 { $in: [ "foo", /bar/i ] } みたいに正規表現を混ぜられたときに使うんだろう。

上記はバージョン 2.4.1 の話ですが、このあたりのコードはどうも大幅に書き直しているらしく、master を見てみると src/mongo/db の下に matcher というディレクトリが出来ていて、$inInMatchExpression という分かりやすい名前のクラスに収まっていた。ちなみに処理そのものは変わっていないみたい。


インデックスが張られていたときのことを考えていなかった。findOne を見ると NamespaceDetailsTransient::getCursor を呼んでいるようなので、そのあたりから読めば良いのかもしれない。

nscala-time and salat

case class と JSON (や BSON) の相互変換は意外と面倒らしい。

salat は JSON をデシリアライズするとき TypeMatchers というクラスを使って場合分けしているようなのだけど、このあたり に com.github.nscala_time.time.Imports.DateTime が入っていないせいか、nscala-time と併せて使おうとすると少し困ることに気づいた。入れると直るのか、直るとしてそんな修正で良いのかは知らない。