1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
module AE
# The Ok mixin is a reusable assertion helper that
# makes it easy to construct parameterized assertions
# with an elegant syntax.
#
module Check
# The Check::Proc class encapsulates a labeled procedure
# for making assertions using the `ok`/`no` methods.
#
class Proc
# Setup new check procedure.
def initialize(options={}, &check)
@name = options[:name]
@message = options[:message] || @name
@check = check
end
#
def message(&block)
if block
@message = message
end
@message
end
#
def message=(msg)
@message = msg
end
# Call check procedure.
def call(*args)
@check.call(*args)
end
#
def to_s(*args)
case @message
when nil
@name.to_s
when ::Proc
@message.call(*args)
else
# TODO: count %\S and apply `% args.map{|a|a.inspect}[0,count]`
@message.to_s
end
end
#
def ok!(*args)
assert(call(*args), to_s(*args))
end
#
def no!(*args)
refute(call(*args), to_s(*args))
end
end
# TODO: Better way to customize error message so it can have
# arguments in the messages ?
# Built-in check procedures.
TABLE = {
:equality => Check::Proc.new(:message=>"should be equal"){|h| h.any?{|a,b| b==a}},
:case_equality => Check::Proc.new(:message=>"should be equal"){|h| h.any?{|a,b| b===a}}
}
#
def self.table
@table ||= TABLE.dup
end
# Define a univerally available ok/no check.
#
# AE::Check.define(:palindrome) do |x|
# x.reverse == x
# end
#
def self.define(name, &block)
table[name] = Check::Proc.new(name, &block)
end
#
def check_table
Check.table
end
# Define an ok/no check procedure. A one-off procedure is defined
# with a block.
#
# check do |x, y|
# x == y
# end
#
# ok 1,1
# no 1,2
#
# The check method can also be used to define reusable checks.
#
# check(:palindrome) do |x|
# x.reverse == x
# end
#
# This will also cause the current check to be set.
# Later in the code, the check procedure can be restored
# by just passing the symbolic name.
#
# check :palindrome
#
# ok 'abracarba'
# no 'foolishness'
#
def check(name=nil, &block)
if name
if block
check_table[name] = Check::Proc.new(:name=>name, &block)
end
@__check__ = check_table[name]
else
#raise ArgumentError if block.arity == 0
@__check__ = Check::Proc.new(&block)
end
end
#
def ok(*args)
__check__.ok!(*args)
end
#
def no(*args)
__check__.no!(*args)
end
# Returns the current check.
def __check__
@__check__ || check_table[:equality]
end
end
end
module AE::World
# It's upto the test framework to include where needed.
include AE::Check
end
|