GitHub のプルリクエストを fetch しとくと便利

GitHub や GHE を使って多人数で開発していると,プルリクエストを横断して試す必要が頻繁に発生すると思います.
プルリクエストを次々に試したり,#30 と #31 をマージした結果を試したい!なんてケースもあるのではないでしょうか.

GitHub では git ls-remote すれば分かるように,プルリクエストの番号と対応したブランチがリモートに存在しているので,これを取得してみます.

.git/config に追記(あるいは git remote add とかで適当に)

[remote "pr"]
    url = git@github.com:yourusername/yourrepos.git
    fetch = +refs/pull/*:refs/remotes/pr/*

あるいはこんな感じ(丸投げ): https://gist.github.com/3342247

git fetch で取得します.

$ git fetch pr
...
 * [new ref]         refs/pull/1/head -> pr/1/head
 * [new ref]         refs/pull/1/merge -> pr/1/merge
 * [new ref]         refs/pull/10/head -> pr/10/head
 * [new ref]         refs/pull/10/merge -> pr/10/merge
 * [new ref]         refs/pull/100/head -> pr/100/head
 * [new ref]         refs/pull/100/merge -> pr/100/merge
 * [new ref]         refs/pull/101/head -> pr/101/head
...

さてこれができるようになると,こんなのが簡単にできます.(以下の例でローカルブランチ名など適当なので適宜好みで)

PR #30 を追いかけたい:

$ git checkout pr/30/head -b 30h
...
... #30 が更新されたら追従
$ git pull

PR #31 の GitHub による自動マージ結果を取得したい

$ git checkout pr/31/merge -b 31m

PR #32 に #33 をマージしたものを使いたい

$ git checkout pr/32/merge -b 32_33
$ git merge pr/33/head

のようにできます.一般的には「どこの(誰の)レポジトリのどのブランチ」という情報が必要なのですが,この方法なら番号だけ知っていればいい分楽に操作できるはずです.

なお,特にドキュメントに書いてある情報ではなさそうなので,上記の内容についての保証はしかねます.

Rails 3.2.9 では integer なカラムに紐付いた属性に Numeric・Boolean 以外の内容を入れたときの挙動が変わった

http://blog.eiel.info/blog/2012/11/16/rails-329-default-scope/ 読んで,「前からそうじゃなかったっけ?」と思ったので確認した.

そもそも default_scope の挙動が変わったのではなく,代入時のキャストの挙動が変わったようだ.(ここでは default_scope に配列を配置することの是非は置いておく)

rails g model item price:integer

という例では,以下のような状態になる

1.9.3-p286 :022 > Rails.version
 => "3.2.8"
1.9.3-p286 :023 > item.price = [100,200,300]
 => [100, 200, 300]
1.9.3-p286 :024 > item.price
 => 1
1.9.3-p286 :020 > Rails.version
 => "3.2.9"
1.9.3-p286 :021 > item.price = [100,200,300]
NoMethodError: undefined method `to_i' for [100, 200, 300]:Array

https://github.com/rails/rails/pull/7582 による修正で要するに「integer のカラムに配列とか数字じゃないもの入れたら普通は例外になる」という仕様.まあそりゃそうだよな.

google-spreadsheet-ruby 試した

GoogleSpreadsheet で定時ログ出力みたいのできないかなーと思って gimite/google-spreadsheet-ruby 試してみたけどなかなかヨサゲ。

てきとーなサンプルはこれ。 https://gist.github.com/3775235

とりあえずカラム名と値与えてあげれば追記していける Worksheet#list のインタフェースが使いやすい。

worksheet.list.push("日付" => "2012-09-24 18:00:00", "カウント" => 320)
worksheet.list.push("日付" => "2012-09-24 19:00:00", "カウント" => 249)
# :
worksheet.save

こんな風に(追加なら)行も列も全然気にしないでいけるのが素晴らしい。

[Node]Backbone.js + Sinon.js で callback をテストしようとしてハマる

端的に言うと以下のコードは想定通りに動かない。(Node のコンソールで)

var Backbone = require('backbone')
var Sinon = require('sinon')

var m = new Backbone.Model({ 'foo': 'bar' })
var f = function(){ console.log("===> Callback called") }

m.on('change', f)
Sinon.spy(this, 'f')
m.set('foo', 'hoge')

f.called // => false

m.on('change', f) した時点で f の参照自体が m に束縛されていて、その後いくら spy で this.f をすげ替えても、 m のコールバックで呼ばれる処理には影響しない。

その処理以降を次のように変えてやれば動く。

m.on('change', function() { f() })
Sinon.spy(this, f)
m.set('foo', 'hoge')

m.called // => true

実際に backbone + coffee + mocha で使うときにはこんな感じになる。

# in view
class FooView extends Backbone.View
  initialize: ->
    _.bindAll @
    @model.on 'change', => @render()
    #....

# in spec (変数定義は適切な場所へ移動すべし)
  it 'change cases rendering' do
    model = new Backbone.Model foo: 'bar'
    view = new FooView model: model
    render = sinon.spy(view, 'render')
    model.set('foo', hoge')
    render.called.should.be.true


あるいは(この例の場合) render の中身の動作を spy してもよいだろう。

responders と RSpec

responders で書き換えられた scaffold で RSpec が通らなくなる件。

Post の内容がエラーかどうかを判定するのに、 scaffold では AR::Base#save の戻り値で判定しているため、Spec は次のようになっている。(ここでは ItemsController の Spec と仮定する)

      it "re-renders the 'new' template" do
         # Trigger the behavior that occurs when invalid params are submitted
        Item.any_instance.stub(:save).and_return(false)
        post :create, {:item => {}}, valid_session
         response.should render_template("new")
       end

一方で responders で生成されるコントローラの判定は respond_with(@resource) で行われるため、AR::Base#errors の内容で判定される。
そのため save を stub してしまうと、 errors が生成されないためエラーと判断されない。

save を stub しないようにして、 invalid なパラメータを与え save に失敗し errors を生成するか、あるいは errors を stub してやればよい。

        Item.any_instance.stub(:save).and_return(false)
        Item.any_instance.stub(:errors).and_return({:name => 'invalid'})
        post :create, {:item => {}}, valid_session

2012-05-22追記: ライブラリ名をずっと間違えて書いていたのでしれっと直した。

久々に Ruby toolbox を眺めてみたメモ

ほんとにメモだけ。

チェックしておくと便利そう

検証しないといけない気がする