class Stub
  def initialize(clazz, include_super = false)
    @clazz = clazz
    meta = class << self; self; end
    methods = clazz.public_instance_methods(include_super)
    @called_table = Hash.new(false)
    @returns_table = Hash.new()
    @errors_table = Hash.new()
    methods.each do |method_name|
      add_reader(meta, "#{method_name}_called?") { 
        @called_table[method_name]
      }

      add_writer(meta, "#{method_name}_return") { |value| 
        @returns_table[method_name] = value 
      }

      add_writer(meta, "#{method_name}_error") { |error| 
        @errors_table[method_name] = error 
      }
      
      add_reader(meta, method_name) { |*args|
        @called_table[method_name] = true
        add_reader(meta, "#{method_name}_params") { args } unless args.empty?
        raise @errors_table[method_name] unless @errors_table[method_name].nil?
        @returns_table[method_name]
      }
    end
  end

  def ==(other)
    return false unless(other.kind_of?(Stub))
    return false unless(@clazz == other.clazz)
    @returns_table == other.returns_table
  end

  private
  def add_reader(meta, method_name, &block)
    meta.send(:define_method, method_name.to_sym, block)
  end

  def add_writer(meta, item, &block)
    meta.send(:define_method, "#{item}=".to_sym, block)
  end

  attr_reader :clazz, :returns_table, :errors_table
  protected :clazz, :returns_table, :errors_table
end