woshidan's loose leaf

ぼんやり勉強しています

rubyでライブラリなどを書くとき、Rakefileと相対パスのrequireを使ってクラスの取得やテストをやりやすくする

+---+ lib
|   +-+ some_module
|     +-+-- a_processor
|       |   +-- order.rb
|       |   +-- item.rb
|       +-- b_processor
|       |   +-- order.rb
|       |   +-- item.rb
|       +-- composer.rb # composerは a_processor, b_processor 以下のクラスを必要とする
+---+ test # ここから一括で回せるようにしたい
    +-+ some_module
      +-+-- a_processor
        |   +-- order_test.rb
        |   +-- item_test.rb
        +-- b_processor
        |   +-- order_test.rb
        |   +-- item_test.rb
        +-- composer_test.rb

といった構成のライブラリを作るとして、composer 書いたり、 地味にテストを自動実行できるようにどうしたら良いか調べるのがめんどくさかったのでメモ。

追加分

+---+ lib
|   +-+ some_module
|     +-+-- a_processor
|       |   +-- order.rb
|       |   +-- item.rb
|       +-- b_processor
|       |   +-- order.rb
|       |   +-- item.rb
|       +-- composer.rb
|       +-- a_processor.rb ** 追加
|       +-- b_processor.rb ** 追加
+---+ test
    + Rakefile ** 追加
    +-+ some_module
      +-+-- a_processor
        |   +-- order_test.rb
        |   +-- item_test.rb
        +-- b_processor
        |   +-- order_test.rb
        |   +-- item_test.rb
        +-- composer_test.rb

それっぽく他パッケージにあるクラスを全て読み込む

比較的苦しくない抑えどころに近いんですが、そのパッケージのクラスを丸ごと読み込んでくれるファイル用意して、それを require すると楽そう。

# a_processor.rb
require "#{File.dirname(__FILE__)}/a_processor/order.rb"
require "#{File.dirname(__FILE__)}/a_processor/item.rb"

ただ、明示的にクラスの指定どうこうする必要がない場合は、 Dir クラスなどを使って each で回すと良さそう。

# a_processor.rb をなくしてbuilder.rb 冒頭で
Dir.glob("#{File.dirname(__FILE__)}/a_processor/*").each do |file|
  require file
end

test以下のディレクトリのファイル全てをコマンド一つで実行する

今回は test ディレクトリ以下で rake test で全部実行できればよかったので、下記のような Rakefiletest 直下に置く。 Rakefile はおいたところで Rakefile に書いたタスクが rake xxx (xxxなしだと task :default に定義したものが使われる)実行されるようになるので、書いてから、普通はトップディレクトリにおいて、 ./**/*_test.rb -> ./test/**/*_test.rb にしたほうがいいかとも思った。

# Rakefile

# coding: UTF-8

require 'rake/testtask'

task :default => [:test]

Rake::TestTask.new do |test|
  test.test_files = Dir['./**/*_test.rb']
  test.verbose = false
end

なお、テストファイルで本番用のファイルを要求するときは、そのライブラリ用のベースクラス的なのを用意して、そこで require しておくと楽。

# base_test.rb
require 'test/unit'

Dir.glob("#{File.dirname(__FILE__)}/a_processor/*").each do |file|
  require file
end

Dir.glob("#{File.dirname(__FILE__)}/b_processor/*").each do |file|
  require file
end

Dir.glob("#{File.dirname(__FILE__)}/**.rb").each do |file|
  require file
end

class SomeModule::BaseTest < Test::Unit::TestCase
  include SomeModule

  ...

# 他のテスト用クラスは

require "#{File.dirname(__FILE__)}/path/to/base_test.rb"

class SomeModule::SomeTest < SomeModule::BaseTest

参考