まねして勉強

最近になって ruby を使うようになりました.

といっても週一ぐらいの頻度なのですが.

RailsによるアジャイルWebアプリケーション開発 第2版

を読んでいて,ActiveRecord 便利だなー,とか思いながら使ってました.


そんな中で ruby の勉強がてら,マイグレーションのまねごとをしてみた次第です.
勉強は,既存のコードを読んで自分なりに実践してみるのが一番かと.

参照したファイル/ディレクトリ

ubuntu 8.04 です.

成果物

バッチ処理してみました.

/${BATCH_ROOT}
  ├ run.rb    ← これを 'ruby run.rb' する
  ├ 001_ope1.rb
  ├ 002_ope2.rb
  ├ 003_ope3.rb
  ...
# 拡張
class String
  def camelize(upcase_first_letter = true)
    if upcase_first_letter then
      return self.gsub(/\/(.?)/) { '::' + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
    else
      return self.first + self.camelize()[1..-1]
    end
  end
  def constantize
    return Object.module_eval("::#{self.camelize}")
  end
end

# バッチ実行
class BatchExecutor
  def initialize(directory, exclude_paths, call_method)
    @directory, @exclude_paths, @call_method = directory, exclude_paths, call_method
  end

  def run(arguments = nil)
    collect_classes(@directory, @exclude_paths).each {|k|
      # 今回は number を無視
      if arguments then
        k.new.send(@call_method, arguments)
      else
        k.new.send(@call_method)
      end
    }
  end

private
  def collect_classes(directory, exclude_paths)
    klasses = collect_files(directory, exclude_paths).inject([]) {|ks, f|
      load(f)
      number, name = get_number_and_classname(File.basename(f))
      ks << create_numbering_class(name, number.to_i)
    }
    return klasses.sort_by {|e| e.number }
  end

  def collect_files(directory, exclude_paths)
    files = []
    Dir.glob(directory + '/*.rb').each {|f|
      files << f if !exclude_paths.include?(f)
    }
    return files
  end

  def get_number_and_classname(filename)
    return *filename.scan(/([0-9]+)_([_a-z0-9]*).rb/).first
  end

  def create_numbering_class(name, number)
    klass = name.camelize.constantize
    class << klass
      attr_accessor :number
    end
    klass.number = number
    return klass
  end
end

何というか,やりたい放題っすね.

実行部分.

if $0 == __FILE__ then
  self_path = File.expand_path(__FILE__)
  directory = File.dirname(self_path)
  exclude_paths = [self_path]
  BatchExecutor.new(directory, exclude_paths, :run).run(['引数渡したよ'])
end


ruby 書きやすいですね.