virtus-dirty_attribute について

最近、仕事上の Ruby プロジェクトで、"モデルに変更があった時だけそのモデルに対して update したい" みたいな要望があって、いろいろ調べたのですが、最終的に virtus-dirty_attribute というのを使うことになった。

virtus-dirty_attribute の使い方

https://github.com/ahawkins/virtus-dirty_attribute

README にも書いてあるけど、

class Hoge
  include Virtus.model
  include Virtus::DirtyAttribute

的な感じに include すると、hoge.dirty? とか hoge.clean? とかで変更があったかどうかが見れるという代物。

へー、便利だなー、でも Rails さんそこらへんやってくれないのかしら?と思っていたら、やっぱり一応あった。それが ActiveModel::Dirty。

ActiveModel::Dirty

http://api.rubyonrails.org/classes/ActiveModel/Dirty.html

なにやら define_attribute_methods とか定義したり、各 attribute のメソッドを定義して hogehoge_will_change とか呼んであげたりと、結構色々やってあげなきゃいけなそう。。。

ActiveRecord 使っているとそこら辺勝手にやってくれるらしく、ActiveRecord のモデルでやる文には便利そう。

というわけで

今回 "モデルに変更があった時だけそのモデルに対して update したい" ということがしたかったのは、たまたま ActiveRecord のモデルじゃなかったので、virtus-dirty_attribute で行くのが良さそう。

rbenv 環境下で Atom(Github) で Rspec を動かしてみた

ちょっと前に Atom のβ版の招待申請を出していて、 「Welcome to Atom」というメールが届いて、使ってみたらなかなかいい感じ。

atomRspec のPackage があったので、ちょっと欲が出て install して atomRspec 実行できるようにしたところ、

$ command not found 'rspec'

的なエラーが出て Rspec が実行できなかった。

むーなんで?と思って調べていたところ、 https://github.com/fcoury/atom-rspec/issues/10 の Issue があって、読んでみたら、

Atom uses bash. so, you have to setup .bash_profile/.bashrc as https://github.com/sstephenson/rbenv

と書いてあるではありませんか!

たしかに、この Issue の人同様、私は zsh ユーザーだったので、 .bashrc に rbenv の記述をしたところ、Rspec 実行できた! 勝手にペインを分割してテスト結果も出してくれていい感じ。

sublime text でもできていたことだけど、エディタ内でテストが実行できるとか、 ちょっと感動しますね。

Timecopを使ってみた

概要

ReadMeに、

A gem providing "time travel" and "time freezing" capabilities, making it dead simple to test time-dependent code. 
It provides a unified method to mock Time.now, Date.today, and DateTime.now in a single call.

とあるように、時間を止めたり、時間を進めたりすることができるライブラリ。 中の動きとしてはTIme.now とか、Date.today とかを指定した日時でモックしたり、時間のを進まないようにしてくれる。

Github

使い方

時間を止める

now = Time.Now  # => 2014-01-26 14:18:46 +0900

# 時間を止める
Timecop.freeze(now)

p Time.now # => 2014-01-26 14:18:46 +0900

時間を特定に日時に変更する

t = Time.local(2012, 1, 1, 0, 0, 0)

# 現在時刻をtに変更する
Timecop.travel(t)

sleep(1)
p Time.now # => 2012-01-01 00:00:01 +0900

1秒で進む秒数を変更する

# scaleを10secに変更する
Timecop.scale(10)

5.times.each do
  p Time.now
  sleep(1)
end

# => 2014-01-26 14:13:10 +0900
# => 2014-01-26 14:13:20 +0900
# => 2014-01-26 14:13:30 +0900
# => 2014-01-26 14:13:40 +0900
# => 2014-01-26 14:13:50 +0900

do ~ end で括るか、Timecop.returnを呼ぶとこれらは解除される模様。