module Minitest::Spec::DSL

def self.extended obj # :nodoc:

:nodoc:
def self.extended obj # :nodoc:
  obj.send :include, InstanceMethods
end

def after _type = nil, &block

def after _type = nil, &block
  define_method :teardown do
    self.instance_eval(&block)
    super()
  end
end

def before _type = nil, &block

def before _type = nil, &block
  define_method :setup do
    super()
    self.instance_eval(&block)
  end
end

def children # :nodoc:

:nodoc:
def children # :nodoc:
  @children ||= []
end

def create name, desc # :nodoc:

:nodoc:
def create name, desc # :nodoc:
  cls = Class.new(self) do
    @name = name
    @desc = desc
    nuke_test_methods!
  end
  children << cls
  cls
end

def describe_stack # :nodoc:

:nodoc:
def describe_stack # :nodoc:
  Thread.current[:describe_stack] ||= []
end

def it desc = "anonymous", &block

def it desc = "anonymous", &block
  block ||= proc { skip "(no tests defined)" }
  @specs ||= 0
  @specs += 1
  name = "test_%04d_%s" % [ @specs, desc ]
  undef_klasses = self.children.reject { |c| c.public_method_defined? name }
  define_method name, &block
  undef_klasses.each do |undef_klass|
    undef_klass.send :undef_method, name
  end
  name
end

def let name, &block

def let name, &block
  name = name.to_s
  pre, post = "let '#{name}' cannot ", ". Please use another name."
  methods = Minitest::Spec.instance_methods.map(&:to_s) - %w[subject]
  raise ArgumentError, "#{pre}begin with 'test'#{post}" if
    name =~ /\Atest/
  raise ArgumentError, "#{pre}override a method in Minitest::Spec#{post}" if
    methods.include? name
  define_method name do
    @_memoized ||= {}
    @_memoized.fetch(name) { |k| @_memoized[k] = instance_eval(&block) }
  end
end

def name # :nodoc:

:nodoc:
def name # :nodoc:
  defined?(@name) ? @name : super
end

def nuke_test_methods! # :nodoc:

:nodoc:
def nuke_test_methods! # :nodoc:
  self.public_instance_methods.grep(/^test_/).each do |name|
    self.send :undef_method, name
  end
end

def register_spec_type *args, &block

def register_spec_type *args, &block
  if block then
    matcher, klass = block, args.first
  else
    matcher, klass = *args
  end
  TYPES.unshift [matcher, klass]
end

def spec_type desc, *additional

def spec_type desc, *additional
  TYPES.find { |matcher, _klass|
    if matcher.respond_to? :call then
      matcher.call desc, *additional
    else
      matcher === desc.to_s
    end
  }.last
end

def subject &block

def subject &block
  let :subject, &block
end

def to_s # :nodoc:

:nodoc:
def to_s # :nodoc:
  name # Can't alias due to 1.8.7, not sure why
end