Tbpgr Blog

Employee Experience Engineer tbpgr(てぃーびー) のブログ

Ruby | ActiveSupport::Concernによってモジュールのクラスメソッドincludeを簡潔にする

概要

activesupport::concernによってモジュールのクラスメソッドincludeを簡潔にする

内容

RailsActiveSupport::Concernを利用することによって
Rails以外のRubyプロジェクトでもモジュールのクラスメソッドincludeを簡潔に出来ます。

サンプル仕様

下記記事で照会した、標準入力Validation用のモジュールをサンプルとします。

Ruby | 標準入出力処理時のValidationをクラスマクロで共通化Comments
http://d.hatena.ne.jp/tbpg/20130625/1372165415

ActiveSupport::Concernを利用しなかった場合のモジュール

standard_io.rb

module StandardIo
  def self.included(klazz)
    klazz.extend(ClassMethods)
  end

  def validate
    self.methods.grep(/^validate_.*/).each do |m|
      return false unless method(m).call
    end
    true
  end

  def args_has_index?(index)
    $*.size > index
  end

  module ClassMethods
    def validate_args_counts(count)
      define_method "validate_args_counts" do
        $*.size == count
      end
    end

    def validate_us_dollar(index)
      define_method "validate_us_dollar_#{index}" do
        return false unless args_has_index?(index)
        if ($*[index] =~ /^[\d\.]+$/)
          return true
        end
        false
      end
    end

    def validate_file(index)
      define_method "validate_file_#{index}" do
        return false unless args_has_index?(index)
        FileTest.exist?($*[index])
      end
    end
  end
end
利用側クラス

standard_io_user.rb

# encoding: utf-8
require_relative "standard_io"

class Hoge
  include StandardIo
  validate_args_counts 4
  validate_us_dollar 0
  validate_us_dollar 1
  validate_file 2
  validate_file 3

  def validate_range()
    _validate_range(0, (1..3))
  end

  def _validate_range(index, range)
    range.include?($*[index].to_i)
  end
end

hoge = Hoge.new
puts hoge.validate
変更前結果
$ruby standard_io_user.rb 1 2 standard_io.rb active_suport_concern.yml
true
ActiveSupport::Concernを利用した場合のモジュール
# encoding: utf-8
require 'active_support'

module StandardIoAfter
  extend ActiveSupport::Concern

  module ClassMethods
    def validate_args_counts(count)
      define_method "validate_args_counts" do
        $*.size == count
      end
    end

    def validate_us_dollar(index)
      define_method "validate_us_dollar_#{index}" do
        return false unless args_has_index?(index)
        if ($*[index] =~ /^[\d\.]+$/)
          return true
        end
        false
      end
    end

    def validate_file(index)
      define_method "validate_file_#{index}" do
        return false unless args_has_index?(index)
        FileTest.exist?($*[index])
      end
    end
  end

  def validate
    self.methods.grep(/^validate_.*/).each do |m|
      return false unless method(m).call
    end
    true
  end

  def args_has_index?(index)
    $*.size > index
  end
end
利用側クラス
# encoding: utf-8
require_relative "standard_io_after"

class HogeAfter
  include StandardIoAfter
  validate_args_counts 4
  validate_us_dollar 0
  validate_us_dollar 1
  validate_file 2
  validate_file 3

  def validate_range()
    _validate_range(0, (1..3))
  end

  def _validate_range(index, range)
    range.include?($*[index].to_i)
  end
end

hoge = HogeAfter.new
puts hoge.validate
変更後結果
$ruby standard_io_user_after.rb 1 2 standard_io.rb active_suport_concern.yml
true