DDD読んでて、ちょっと練習。

module Feature
  AAA = :AAA
  BBB = :BBB
  NOMAL = :NOMAL
end

class Container
  attr_accessor :drums, :features

  def initialize(&block)
    @drums = []
    @features = []
    instance_eval(&block)
    self
  end

  def safely_pack?
    @drums.each{|drum|
      unless drum.product.container_specification.satisfined_by?(self)
        return false
      end
    }
    true
  end
end

class Drum
  attr_accessor :product

  def initialize(&block)
    instance_eval(&block)
    self
  end
end

class Product
  attr_accessor :container_specification, :name

  def initialize(&block)
    instance_eval(&block)
    self
  end
end


class ContainerSpecification
  attr_reader :required_feature
  def initialize required_feature
    @required_feature = required_feature
  end

  def satisfined_by?(container)
    container.features.include?(required_feature)
  end
end

# xxx RSpec が使えなかったので。。。
def context desc, &block
  def should message, &block
    def expect_safely actual
      raise "期待通りでない"  unless actual
      puts "pass"
    end

    def expect_not_safely actual
      raise "期待通りでない"  if actual
      puts "pass"
    end
    block.call
  end
  block.call
end

context "基本機能しか持たないコンテナ内に、機能BBBを要求する 化学製品を含んだドラム缶がある場合" do
  should "要求を満たしてないと返すこと" do
    container_nomal = Container.new {
      @features = [Feature::NOMAL]
      @drums << Drum.new {
        @product = Product.new {
          @name = "product_bbb"
          @container_specification = ContainerSpecification.new(Feature::BBB)
        }
      }
    }

    expect_not_safely container_nomal.safely_pack?
  end
end


context "基本機能しか持たないコンテナ内に、基本機能のみを要求する化学製品を含んだドラム缶がある場合" do
  should "要求を満たしていると返すこと" do
    container_nomal = Container.new {
      @features = [Feature::NOMAL]
      @drums << Drum.new {
        @product = Product.new {
          @name = "product_nomal"
          @container_specification = ContainerSpecification.new(Feature::NOMAL)
        }
      }
    }
    expect_safely container_nomal.safely_pack?
  end
end


context "AAA, BBB, 基本機能を持ったコンテナ内に、 AAA,BBB,基本機能をを要求する 化学製品が含んだドラム缶がある場合" do
  should "要求を満たしていると返すこと" do
    container_aaa_bbb = Container.new {
      @features = [Feature::AAA, Feature::BBB, Feature::NOMAL]

      @drums << Drum.new {
        @product = Product.new {
          @name = "product_aaa"
          @container_specification = ContainerSpecification.new(Feature::AAA)
        }
      }

      @drums << Drum.new {
        @product = Product.new {
          @name = "product_bbb"
          @container_specification = ContainerSpecification.new(Feature::BBB)
        }
      }

      @drums << Drum.new {
        @product = Product.new {
          @name = "product_nomal"
          @container_specification = ContainerSpecification.new(Feature::NOMAL)
        }
      }
    }
    require 'pp'
    pp container_aaa_bbb
    expect_safely container_aaa_bbb.safely_pack?
  end
end