Class: Assertor

Inherits:
AE::BasicObject
Includes:
AE::Subjunctive
Defined in:
lib/ae/assertor.rb,
lib/ae/subjunctive.rb

Overview

module AE

Instance Method Summary collapse

Methods included from AE::Subjunctive

#a, #be

Methods inherited from AE::BasicObject

find_hidden_method, hide, reveal

Constructor Details

#initialize(delegate, opts = {}) ⇒ Assertor

New Assertor.



25
26
27
28
29
30
# File 'lib/ae/assertor.rb', line 25

def initialize(delegate, opts={}) #, backtrace)
  @delegate  = delegate
  @message   = opts[:message]
  @backtrace = opts[:backtrace] || caller #[1..-1]
  @negated   = !!opts[:negated]
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(sym, *a, &b) ⇒ Object (private)

Converts a missing methods into an Assertion.



157
158
159
160
161
# File 'lib/ae/assertor.rb', line 157

def method_missing(sym, *a, &b)
  pass = @delegate.__send__(sym, *a, &b)
  #pass = @delegate.public_send(sym, *a, &b)
  __assert__(pass, @message || __msg__(sym, *a, &b))
end

Instance Method Details

#=~(match) ⇒ Object

Ruby seems to have a quark in it’s implementation whereby this must be defined explicitly, otherwise it somehow skips #method_missing.



144
145
146
# File 'lib/ae/assertor.rb', line 144

def =~(match)
  method_missing(:"=~", match)
end

#assert(*args, &block) ⇒ Object

Internal assert, provides all functionality associated with external #assert method. (See Assert#assert)

NOTE: I’m calling YAGNI on using extra arguments to pass to the block. The interface is much nicer if a macro is created to handle any neccessry arguments. Eg.

assert something(parameter)

instead of

assert something, parameter


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
# File 'lib/ae/assertor.rb', line 54

def assert(*args, &block)
  return self if args.empty? && !block

  target = block || args.shift

  if ::Proc === target || target.respond_to?(:to_proc)
    block  = target.to_proc
    match  = args.shift
    result = block.arity > 0 ? block.call(@delegate) : block.call
    if match
      pass = (match == result)
      msg  = @message || "#{match.inspect} == #{result.inspect}"
    else
      pass = result
      msg  = @message || block.inspect  # "#{result.inspect}"
    end
  elsif target.respond_to?(:matches?)
    pass   = target.matches?(@delegate)
    msg    = @message || matcher_message(target) || target.inspect
  else
    pass   = target     # truthiness
    msg    = args.shift # optional mesage for TestUnit compatiability
  end

  __assert__(pass, msg)
end

#exception?(object) ⇒ Boolean

Is the object and Exception or an instance of one. – TODO: Should we use a more libreral determination of exception. e.g. respond_to?(:exception). ++

Returns:

  • (Boolean)


132
133
134
# File 'lib/ae/assertor.rb', line 132

def exception?(object)
  ::Exception === object or ::Class === object and object.ancestors.include?(::Exception)
end

#expect(*args, &block) ⇒ Object

Internal expect, provides all functionality associated with external #expect method. (See Expect#expect)

– TODO: Should we deprecate the receiver matches in favor of #expected ? In other words, should the || @delegate be dropped? ++



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
# File 'lib/ae/assertor.rb', line 88

def expect(*args, &block)
  return self if args.empty? && !block_given?  # same as #assert

  target = block || args.shift

  if ::Proc === target #|| target.respond_to?(:to_proc)
    #block = target.to_proc
    match = args.shift || @delegate
    if exception?(match)
      $DEBUG, debug = false, $DEBUG  # b/c it always spits-out a NameError
      begin
        block.arity > 0 ? block.call(@delegate) : block.call
        pass = false
        msg  = "#{match} not raised"
      rescue match => error
        pass = true
        msg  = "#{match} raised"
      rescue ::Exception => error
        pass = false
        msg  = "#{match} expected but #{error.class} was raised"
      ensure
        $DEBUG = debug
      end
    else
      result = block.arity > 0 ? block.call(@delegte) : block.call
      pass   = (match === result)
      msg    = @message || "#{match.inspect} === #{result.inspect}"
    end
  elsif target.respond_to?(:matches?)
    pass = target.matches?(@delegate)
    msg  = @message || matcher_message(target) || target.inspect
  else
    pass = (target === @delegate)
    msg  = @message || "#{target.inspect} === #{@delegate.inspect}"
  end

  __assert__(pass, msg)
end

#flunk(message = nil) ⇒ Object



137
138
139
# File 'lib/ae/assertor.rb', line 137

def flunk(message=nil)
  __assert__(false, message || @message)
end

#not(msg = nil) ⇒ Object

Negate the meaning of the assertion.

TODO: Should this return a new Assertor instead of inplace negation?



35
36
37
38
39
# File 'lib/ae/assertor.rb', line 35

def not(msg=nil)
  @negated = !@negated
  @message = msg if msg
  self
end

#send(op, *a, &b) ⇒ Object



149
150
151
# File 'lib/ae/assertor.rb', line 149

def send(op, *a, &b)
  method_missing(op, *a, &b)
end