assert_gem, assert_ruby
実際の仕事でgemのバージョンによってテスト結果が違っている、ということで悩んだことがあり、gemやrubyのバージョンは自動テストでチェックするべきだなーって思いました。
こんな感じで書きたい。
require File.dirname(__FILE__) + '/../test_helper' class EnvironmentTest < ActiveSupport::TestCase def test_environment assert_ruby("1.8.6") assert_gem("log4r", "1.0.5") assert_gem("mongrel", "1.1.x") if /java/ =~ RUBY_PLATFORM assert_gem("gettext", "1.90.x") else assert_gem("gettext", "1.90.x", "1.10.x") end end end
xの部分は数字ならOK。>= とかでチェックできたらいいかもとも思ったんですけど、実際仕事で使う場合、そういう風に書きたいケースって少ないだろうなーって思いました。プロジェクトで使うバージョンを列挙した方が間違いない感じがします。
で、そんな風に書けるようにするコードはこちら
class Test::Unit::TestCase def version_str(*versions) versions.map do |version| version.gsub(/\./, "\\.").gsub("x", "\\d+") end end def assert_ruby(*versions) versions = version_str(*versions) regexp = Regexp.union(*versions.map{|version| Regexp.new("^#{version}$") }) assert_match(regexp, RUBY_VERSION) end GEM_NAME_PATTERN = /.*?\-\d.*/ def assert_gem(name, *versions) regexp = Regexp.union(*version_str(*versions).map{|version| Regexp.new("#{name}-#{version}") }) gem_pathes = Gem.all_load_paths.map{|path| path.gsub(Gem.dir, '')} gem_names = gem_pathes.map do |path| parts = path.split('/') parts.reverse.detect{|part|GEM_NAME_PATTERN =~ part} end return true if gem_names.any?{|gem_name|regexp =~ gem_name} found_gem_names = gem_names.select{|gem_name|gem_name.include?(name)} if found_gem_names.empty? fail "#{name} #{versions.join(' or ')} not found" else fail "#{found_gem_names.join(', ')} found but #{versions.join(' or ')} of #{name} not found" end end end
gemの名前を取得するのにGem.all_load_pathsを使ってパスを取得してごにょごにょしてますが、もっといい方法がありそうな予感がしてます。どなたかご存じだったら教えてほしいです〜