Detailed assert macro for Crystal

assert 2 + 2 == 5
#< 2 + 2 => 4 == 5 <= 5 (AssertionError)
assert "a,b,c".split == "a b c".split
#< "a,b,c".split => ["a,b,c"] == ["a", "b", "c"] <= "a b c".split (AssertionError)
assert [2, 4, 6].any? &.odd?
#< [2, 4, 6].any?(&.odd?) (AssertionError)

 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
class AssertionError < Exception
end

# If `cond` is `false`, raise `exc`.
# If `exc` is not provided, `AssertionError` will be raised instead with information about the faulty expression.
# If the expression is a comparison, the result of each side of the comparison will also be shown.
macro assert(cond, exc = nil)
  unless {{ cond }}
    {% if exc %}
      raise {{ exc }}
    {% else %}
      {% if cond.is_a? Call && %w(== != < > <= >=).any? {|s| s == cond.name.stringify} %}
        {% a = cond.receiver; b = cond.args[0] %}
        %error = "#{{{ a.stringify }}} => #{{{ a }}} {{ cond.name }} #{{{ b }}} <= #{{{ b.stringify }}}"
      {% else %}
        %error = {{ cond.stringify }}
      {% end %}
      raise AssertionError.new(%error)
    {% end %}
  end
end

# Assert only in debug mode
macro debug_assert(cond, exc = nil)
  ifdef !release
    assert({{ cond }}, {{ exc }})
  end
end

Crystal programming language

Created
Comments powered by Disqus