module Sus::Context

def self.extended(base)

def self.extended(base)
	base.children = Hash.new
end

def add(child)

def add(child)
	@children[child.identity] = child
end

def after(&hook)

@parameter hook [Proc] The block to execute after each test. An `error` argument is passed if the test failed with an exception.

After hooks are usually invoked in the reverse order they are defined, i.e. the last defined hook is invoked first.

Include an around method to the context class, that invokes the given block after running the test.
def after(&hook)
	wrapper = Module.new
	
	wrapper.define_method(:after) do |error|
		instance_exec(error, &hook)
	rescue => error
		raise
	ensure
		super(error)
	end
	
	self.include(wrapper)
end

def around(&block)

@paremeter block [Proc] The block to execute around each test.

The top level `around` implementation invokes before and after hooks.

Around hooks are called in the reverse order they are defined.

Add an around hook to the context class.
def around(&block)
	wrapper = Module.new
	
	wrapper.define_method(:around, &block)
	
	self.include(wrapper)
end

def before(&hook)

@parameter hook [Proc] The block to execute before each test.

Before hooks are usually invoked in the order they are defined, i.e. the first defined hook is invoked first.

Include an around method to the context class, that invokes the given block before running the test.
def before(&hook)
	wrapper = Module.new
	
	wrapper.define_method(:before) do
		super()
		
		instance_exec(&hook)
	end
	
	self.include(wrapper)
end

def call(assertions)

def call(assertions)
	return if self.empty?
	
	assertions.nested(self) do |assertions|
		self.children.each do |identity, child|
			child.call(assertions)
		end
	end
end

def describe(subject, **options, &block)

def describe(subject, **options, &block)
	add Describe.build(self, subject, **options, &block)
end

def each(&block)

def each(&block)
	self.children.each do |identity, child|
		if child.leaf?
			yield child
		else
			child.each(&block)
		end
	end
end

def empty?

def empty?
	@children.nil? || @children.empty?
end

def file(path)

def file(path)
	add File.build(self, path)
end

def full_name

def full_name
	output = Output::Buffered.new
	print(output)
	return output.string
end

def include_context(shared, *arguments, **options)

@parameter options [Hash] The options to pass to the shared context.
@parameter arguments [Array] The arguments to pass to the shared context.
@parameter shared [Sus::Shared] The shared context to include.

Include a shared context into the current context, along with any arguments or options.
def include_context(shared, *arguments, **options)
	self.class_exec(*arguments, **options, &shared.block)
end

def inspect

def inspect
	if description = self.description
		"\#<#{self.name || "Context"} #{self.description}>"
	else
		self.name
	end
end

def it(...)

def it(...)
	add It.build(self, ...)
end

def it_behaves_like(shared, *arguments, **options, &block)

def it_behaves_like(shared, *arguments, **options, &block)
	add ItBehavesLike.build(self, shared, arguments, **options, &block)
end

def leaf?

def leaf?
	false
end

def let(name, &block)

def let(name, &block)
	instance_variable = :"@#{name}"
	
	self.define_method(name) do
		if self.instance_variable_defined?(instance_variable)
			return self.instance_variable_get(instance_variable)
		else
			self.instance_variable_set(instance_variable, self.instance_exec(&block))
		end
	end
end

def print(output)

def print(output)
	output.write("context ", :context, self.description, :reset)
end

def set_temporary_name(name)

def set_temporary_name(name)
	# No-op.
end

def to_s

def to_s
	(self.description || self.name).to_s
end

def with(subject = nil, unique: true, **variables, &block)

def with(subject = nil, unique: true, **variables, &block)
	subject ||= variables.inspect
	
	add With.build(self, subject, variables, unique: unique, &block)
end