class Given::NaturalAssertion

Constants

VOID_SEXP
WRAP_WIDTH

Public Class Methods

new(clause_type, block, example, line_extractor) click to toggle source
   # File lib/given/natural_assertion.rb
26 def initialize(clause_type, block, example, line_extractor)
27   @clause_type = clause_type
28   @evaluator = Evaluator.new(example, block)
29   @line_extractor = line_extractor
30   set_file_and_line(block)
31 end

Public Instance Methods

has_content?() click to toggle source
   # File lib/given/natural_assertion.rb
35 def has_content?
36   return true unless NATURAL_ASSERTIONS_SUPPORTED
37   assertion_sexp != VOID_SEXP
38 end
message() click to toggle source
   # File lib/given/natural_assertion.rb
40 def message
41   @output = "#{@clause_type} expression failed at #{source_line}\n"
42   if NATURAL_ASSERTIONS_SUPPORTED
43     @output << "Failing expression: #{source.strip}\n" if @clause_type != "Then"
44     explain_failure
45     display_pairs(expression_value_pairs)
46     @output << "\n"
47   else
48     @output << "Failing expression (possibly truncated): #{source.strip}\n"
49   end
50   @output
51 end

Private Instance Methods

adjust_indentation(string) click to toggle source
    # File lib/given/natural_assertion.rb
170 def adjust_indentation(string)
171   string.to_s.gsub(/^/, '  ')
172 end
assertion_sexp() click to toggle source
   # File lib/given/natural_assertion.rb
79 def assertion_sexp
80   @assertion_sexp ||= extract_test_expression(Ripper::SexpBuilder.new(source).parse)
81 end
assertion_subexpressions() click to toggle source
   # File lib/given/natural_assertion.rb
75 def assertion_subexpressions
76   Sorcerer.subexpressions(assertion_sexp).reverse.uniq.reverse
77 end
contains_multiple_statements?(block_sexp) click to toggle source
    # File lib/given/natural_assertion.rb
130 def contains_multiple_statements?(block_sexp)
131   !(delve(block_sexp,2,0) == :stmts_add &&
132     delve(block_sexp,2,1,0) == :stmts_new)
133 end
delve(ary, *indicies) click to toggle source

Safely dive into an array with a list of indicies. Return nil if the element doesn't exist, or if the intermediate result is not indexable.

    # File lib/given/natural_assertion.rb
142 def delve(ary, *indicies)
143   result = ary
144   while !indicies.empty? && result
145     return nil unless result.respond_to?(:[])
146     i = indicies.shift
147     result = result[i]
148   end
149   result
150 end
display_pairs(pairs) click to toggle source
    # File lib/given/natural_assertion.rb
159 def display_pairs(pairs)
160   width = suggest_width(pairs) + 4
161   pairs.each do |x, v|
162     v = adjust_indentation(v)
163     fmt = multi_line?(v) ?
164     "%-#{width}s\n#{' '*width} <- %s\n" :
165       "%-#{width}s <- %s\n"
166     @output << sprintf(fmt, v, x)
167   end
168 end
eval_sexp(sexp) click to toggle source
    # File lib/given/natural_assertion.rb
152 def eval_sexp(sexp)
153   expr_string = Sorcerer.source(sexp)
154   @evaluator.eval_string(expr_string)
155 end
explain_expected(expect_msg, expect_sexp, got_msg, got_sexp) click to toggle source
   # File lib/given/natural_assertion.rb
62 def explain_expected(expect_msg, expect_sexp, got_msg, got_sexp)
63   width = [expect_msg.size, got_msg.size].max
64   sprintf("%#{width}s: %s\n%#{width}s: %s\n",
65     expect_msg, eval_sexp(expect_sexp),
66     got_msg, eval_sexp(got_sexp))
67 end
explain_failure() click to toggle source
   # File lib/given/natural_assertion.rb
55 def explain_failure
56   binary = BinaryOperation.parse(assertion_sexp)
57   if binary && binary.explain
58     @output << explain_expected("expected", binary.left, binary.explain, binary.right)
59   end
60 end
expression_value_pairs() click to toggle source
   # File lib/given/natural_assertion.rb
69 def expression_value_pairs
70   assertion_subexpressions.map { |exp|
71     [exp, @evaluator.eval_string(exp)]
72   }
73 end
extract_brace_block(sexp) click to toggle source
    # File lib/given/natural_assertion.rb
 97 def extract_brace_block(sexp)
 98   unless then_block?(sexp)
 99     source = Sorcerer.source(sexp)
100     fail InvalidThenError, "Unexpected code at #{source_line}\n#{source}"
101   end
102   sexp[1][2][2]
103 end
extract_first_statement(block_sexp) click to toggle source
    # File lib/given/natural_assertion.rb
122 def extract_first_statement(block_sexp)
123   if contains_multiple_statements?(block_sexp)
124     source = Sorcerer.source(block_sexp)
125     fail InvalidThenError, "Multiple statements in Then block at #{source_line}\n#{source}"
126   end
127   extract_statement_from_block(block_sexp)
128 end
extract_statement_from_block(block_sexp) click to toggle source
    # File lib/given/natural_assertion.rb
135 def extract_statement_from_block(block_sexp)
136   delve(block_sexp,2,2)
137 end
extract_test_expression(sexp) click to toggle source
   # File lib/given/natural_assertion.rb
92 def extract_test_expression(sexp)
93   brace_block = extract_brace_block(sexp)
94   extract_first_statement(brace_block)
95 end
has_block_sexp?(sexp) click to toggle source
    # File lib/given/natural_assertion.rb
118 def has_block_sexp?(sexp)
119   delve(sexp,1,2,2,0) == :brace_block || delve(sexp,1,2,2,0) == :do_block
120 end
max_line_length(string) click to toggle source
    # File lib/given/natural_assertion.rb
184 def max_line_length(string)
185   string.to_s.split(/\n/).map { |s| s.size }.max
186 end
method_with_block?(sexp) click to toggle source
    # File lib/given/natural_assertion.rb
113 def method_with_block?(sexp)
114   delve(sexp,1,0) == :stmts_add &&
115     delve(sexp,1,2,0) == :method_add_block
116 end
multi_line?(string) click to toggle source
    # File lib/given/natural_assertion.rb
174 def multi_line?(string)
175   (string.size > WRAP_WIDTH) || (string =~ /\n/)
176 end
program_sexp?(sexp) click to toggle source
    # File lib/given/natural_assertion.rb
109 def program_sexp?(sexp)
110   delve(sexp,0) == :program
111 end
set_file_and_line(block) click to toggle source
   # File lib/given/natural_assertion.rb
87 def set_file_and_line(block)
88   @code_file, @code_line = @evaluator.location
89   @code_line = @code_line.to_i
90 end
source() click to toggle source
   # File lib/given/natural_assertion.rb
83 def source
84   @source ||= @line_extractor.line(@code_file, @code_line)
85 end
source_line() click to toggle source
    # File lib/given/natural_assertion.rb
188 def source_line
189   "#{@code_file}:#{@code_line}"
190 end
suggest_width(pairs) click to toggle source
    # File lib/given/natural_assertion.rb
178 def suggest_width(pairs)
179   pairs.map { |x,v|
180     max_line_length(v)
181   }.select { |n| n < WRAP_WIDTH }.max || 10
182 end
then_block?(sexp) click to toggle source
    # File lib/given/natural_assertion.rb
105 def then_block?(sexp)
106   program_sexp?(sexp) && method_with_block?(sexp) && has_block_sexp?(sexp)
107 end