Migrationで利用可能なネイティブデータタイプを調べる方法
現在使っているConnection
1 ActiveRecord::Base.connection .native_dat abase_type s.keys 2 => [:boolean, :date, :binary, :datetime, :string, :integer, :decimal, :primary_ke y, :time, :float, :timestamp, :text]
現在使っているConnection
1 ActiveRecord::Base.connection .native_dat abase_type s.keys 2 => [:boolean, :date, :binary, :datetime, :string, :integer, :decimal, :primary_ke y, :time, :float, :timestamp, :text]
ブラックボックスなシステムを間に挟んで caller と callee 間で通信を行なう Wormholeのバージョン0.1.2 をリリースしました。
新しい機能:
1 w = Wormhole.catch do 2 end #=> Wormhole::LateReturn Error 3 (snip) 4 w.return 5 6 Worrmhole.catch do 7 end.return # => OK
ついでにWormholeの使用例を。
app/contro
1 require 'wormhole' 2 class FooController < Applicatio nControlle r 3 def index 4 Wormhole.catch do 5 render :action => 'index' 6 end.return do |result| 7 result[:html] = "Hello, world!" 8 end 9 end 10 end
app/views/
1 <% Wormhole.throw do |result| %> 2 <%= result[:html] #=> 'Hello, world!' %> 3 <% end %>
Viewのコードから一端Controller
このように、おいそれとは変更できないようなフレームワークのコードを跨いで、呼び出し側と呼び出し元の間で情報のやり取りを行なう事ができます。
D言語やPythonのように、複素数リテラルが欲しかったのですが、 無かったのでそれっぽい動きをさせるようにNumeric#iを定義してみました。
numeric_i.
1 require 'complex' 2 3 class Numeric 4 def i 5 self * Complex::I 6 end 7 end
これだけです。あとは以下のようにして使います。
1 require 'numeric_i' 2 3 1 + 1.i #=> Complex(1, 1) 4 (Math::E ** (Math::PI.i)).real #=> -1.0
(自分が)簡単に使えるように、GitHubでGemを作っておきました。 利用する場合は以下の手順で導入できます。
1 gem sources -a http://gems.github.c om 2 sudo gem install genki-nume ric_i
名前空間のお陰で、シンプルなGemも気軽に公開できて良い時代ですね。
See Also
昔は違った気がするのですが、手元の環境のautotest(ZenTest-3.
全部テストを実行するのは大変なので、とりあえず、.autotest
でパッチを当てて回避しました。
1 class Autotest 2 alias_method :handle_res ults_old, :handle_res ults 3 undef_meth od :handle_res ults 4 5 def handle_res ults(results) 6 failed = results.scan(self.failed_res ults_re) 7 completed = results =~ self.completed_ re 8 9 self.files_to_t est = consolidat e_failures failed if completed 10 11 color = completed && self.files_to_t est.empty? ? :green : :red 12 hook color unless $TESTING 13 14 #self.taint ed = true unless self.files _to_test.e mpty? 15 self.tainted = !self.files_to_t est.empty? 16 end 17 end
L14-15行目が修正箇所です。
メモもかねて。
RAILS_ROOT
でautotestを実行。起動時に全部のテストを実行するのでちょっとだけ重くなるかもしれません。それ以降はテストファイルやモデル、コントローラファイルなどを修正する度に該当のテストが走ります。
autotestを-f
オプションを付けて立ち上げると、Fast startモードになり、最初に全部のテストを実行しなくなります。
KagemushaでActiveReco
1 singleton method bound for a different object (TypeError)
というエラーが発生するという問題がありました。
このままでは困るので、とりあえず動くようにしてみました。
Unboundにしなければ問題は起こらないと思ったので、
instance_m
の代わりにalias_meth
を使っています。
kagemusha_
1 require 'uuidtools' 2 3 class Kagemusha #:nodoc: 4 def swap #:nodoc: 5 original_class_metho ds = {} 6 original_i nstance_me thods = {} 7 8 @class_meth ods.each { |name, proc| 9 if proc 10 begin 11 # replace method 12 #method = @meta.insta nce_method (name) 13 method = random_nam e 14 @meta.instance_e val { alias_meth od method, name } 15 @meta.instance_e val { define_met hod(name, proc) } 16 original_c lass_metho ds[name] = method 17 rescue NameError 18 # insert method 19 @meta.instance_e val { define_met hod(name, proc) } 20 original_c lass_metho ds[name] = false 21 end 22 else 23 begin 24 # remove method 25 #method = @meta.insta nce_method (name) 26 method = random_nam e 27 @meta.instance_e val { alias_meth od method, name } 28 @meta.instance_e val { undef_meth od(name) } 29 original_c lass_metho ds[name] = method 30 rescue NameError 31 # nop 32 end 33 end 34 } 35 36 @instance_m ethods.each { |name, proc| 37 if proc 38 begin 39 # replace method 40 method = @klass.instance_m ethod(name) 41 @klass.instance_e val { define_met hod(name, proc) } 42 original_i nstance_me thods[name] = method 43 rescue NameError 44 # insert method 45 @klass.instance_e val { define_met hod(name, proc) } 46 original_i nstance_me thods[name] = false 47 end 48 else 49 begin 50 # remove method 51 method = @klass.instance_m ethod(name) 52 @klass.instance_e val { undef_meth od(name) } 53 original_i nstance_me thods[name] = method 54 rescue NameError 55 # nop 56 end 57 end 58 } 59 60 return yield 61 ensure 62 original_c lass_metho ds.each { |name, method| 63 if method 64 # replace method 65 #@meta.insta nce_eval { define_met hod(name, method) } 66 @meta.instance_e val { alias_meth od name, method } 67 @meta.instance_e val { undef_meth od method } 68 else 69 # remove method 70 @meta.instance_e val { undef_meth od(name) } 71 end 72 } 73 original_i nstance_me thods.each { |name, method| 74 if method 75 # replace method 76 @klass.instance_e val { define_met hod(name, method) } 77 else 78 # remove method 79 @klass.instance_e val { undef_meth od(name) } 80 end 81 } 82 end 83 84 private 85 def random_nam e 86 [UUID.random_128 ].pack("m").tr("=\n", '') 87 end 88 end
テストのC0カバレッジを上げるために、 何度もrcovを手で実行していたのですが、 テストの数が多くなってくると非常に時間がかかって面倒なため、 自動化するRakeタスクを作りました。
1 namespace :rcov do 2 desc 'Automate rcov' 3 task :auto do 4 interval = (ENV['INTERVAL'] || 10).to_f 5 org_path = File.join(RAILS_ROOT, 'coverage', '*') 6 pub_path = File.join(RAILS_ROOT , 'public', 'coverage') 7 sh "mkdir -p #{pub_path}" 8 loop do 9 Rake::Task['spec:rcov'].execute nil 10 sh "cp -Rf #{org_path} #{pub_path}" 11 sleep interval 12 end 13 end 14 end
使い方はRAILS_ROOT
1 % rake rcov:auto INTERVAL=10
指定した時間間隔(秒)ごとにspec:rcov
を実行します。
実行した結果はRSpecのデフォルトでは
RAILS_ROOT
に出力されるので、これを
public/cov
に上書きコピーしています。
あとは、ブラウザで/coverage
を見ればOKです。
public/cov
は間違ってデプロイしないように.gitignore
やsvn:ignore
に登録しておきましょう。
メソッドやProcの内部で継続(Continuati
前準備。
1 a = nil 2 foo = proc{callcc{|a|}; 1} 3 bar = proc{foo.call; 2} 4 baz = proc{a.call; 3}
実験開始。
1 >> foo.call 2 => 1 3 >> baz.call 4 => 1 5 >> bar.call 6 => 2 7 >> baz.call 8 => 2
なるほど。
ちょっと必要に駆られて、 Wormhole というライブラリを書きました。
インストールはGitHubから行えます。
1 sudo gem sources -a http://gems.github.c om 2 sudo gem install genki-worm hole
メソッドの内部を実行中に、呼び出し元に一旦処理を戻し、 中断した場所から処理を継続する機能を提供します。
例えば、以下のようなプログラムに対して、
1 require 'rubygems' 2 require 'wormhole' 3 4 def foo 5 puts "foo" 6 Wormhole.throw :foo => 'hello' do |data| 7 puts data[:foo] 8 end 9 puts "bar" 10 end 11 12 Wormhole.catch do 13 foo 14 end.return do |data| 15 puts data[:foo] 16 data[:foo] = 'world!' 17 end
結果として、以下のような出力を得ます。
1 foo 2 hello 3 world! 4 bar
処理を中断したいところで Wormhole.t
を呼び出して、
外側から Wormhole.c
で受け止めます。
catch
が完了したら、Wormhole
オブジェクトが返るので、
return
で中断箇所に戻ります。
Wormhole.t
はHashを受け渡すことができます(省略可能)。
また、catch
ブロックとreturn
は上記の例のように続けて記述します。
catch
の戻り値を適当な変数に代入して、後でreturn
を呼び出すことも可能ですが、その場合、catch
を抜けた直後から
return
を呼ぶまでの区間が二度実行されてしまいます
(この辺が最初に例外を使って実装してた理由ですね)
中断箇所から処理を再開するために callcc
を使っています。
callcc
は面白いですね。
更新履歴
以前笹田さんに、procのソースが見たいとお願いしてみたことがあったのですが、 それをRubyコードレベルで実現するライブラリを見つけたので紹介します。
I wrote this a while ago and it works by extracting
a proc's origin file name and line number from its .inspect string and using the source code (which usually does not have to be read from disc) -- it works with procs generated in IRB, eval() calls and regular files. It does not work from ruby -e and stuff like "foo".instance_ eval "lambda {}".source probably doesn't work either.
オリジナルはメールの添付ファイルとしてくっついているので、ソースを見たい場合は こちらから見るといいかもしれません。
使い方はこんな感じです、
1 code = proc{puts "Hello World"} 2 puts code.source #=> puts "Hello World"
これは久々に面白いものを見た気がします。