micronaut 0.2.9
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +15 -0
- data/LICENSE +45 -0
- data/README.markdown +66 -0
- data/RSPEC-LICENSE +23 -0
- data/Rakefile +78 -0
- data/VERSION.yml +4 -0
- data/bin/micronaut +4 -0
- data/examples/example_helper.rb +54 -0
- data/examples/lib/micronaut/behaviour_example.rb +351 -0
- data/examples/lib/micronaut/configuration_example.rb +133 -0
- data/examples/lib/micronaut/example_example.rb +67 -0
- data/examples/lib/micronaut/expectations/extensions/object_example.rb +146 -0
- data/examples/lib/micronaut/expectations/fail_with_example.rb +17 -0
- data/examples/lib/micronaut/expectations/wrap_expectation_example.rb +27 -0
- data/examples/lib/micronaut/formatters/base_formatter_example.rb +117 -0
- data/examples/lib/micronaut/formatters/documentation_formatter_example.rb +5 -0
- data/examples/lib/micronaut/formatters/progress_formatter_example.rb +29 -0
- data/examples/lib/micronaut/kernel_extensions_example.rb +13 -0
- data/examples/lib/micronaut/matchers/be_close_example.rb +52 -0
- data/examples/lib/micronaut/matchers/be_example.rb +298 -0
- data/examples/lib/micronaut/matchers/change_example.rb +360 -0
- data/examples/lib/micronaut/matchers/description_generation_example.rb +175 -0
- data/examples/lib/micronaut/matchers/eql_example.rb +35 -0
- data/examples/lib/micronaut/matchers/equal_example.rb +35 -0
- data/examples/lib/micronaut/matchers/has_example.rb +69 -0
- data/examples/lib/micronaut/matchers/have_example.rb +392 -0
- data/examples/lib/micronaut/matchers/include_example.rb +103 -0
- data/examples/lib/micronaut/matchers/match_example.rb +43 -0
- data/examples/lib/micronaut/matchers/matcher_methods_example.rb +78 -0
- data/examples/lib/micronaut/matchers/operator_matcher_example.rb +193 -0
- data/examples/lib/micronaut/matchers/raise_error_example.rb +348 -0
- data/examples/lib/micronaut/matchers/respond_to_example.rb +54 -0
- data/examples/lib/micronaut/matchers/satisfy_example.rb +36 -0
- data/examples/lib/micronaut/matchers/simple_matcher_example.rb +93 -0
- data/examples/lib/micronaut/matchers/throw_symbol_example.rb +125 -0
- data/examples/lib/micronaut/mocha_example.rb +29 -0
- data/examples/lib/micronaut/runner_example.rb +41 -0
- data/examples/lib/micronaut/world_example.rb +98 -0
- data/examples/lib/micronaut_example.rb +43 -0
- data/examples/resources/example_classes.rb +67 -0
- data/lib/micronaut.rb +40 -0
- data/lib/micronaut/behaviour.rb +217 -0
- data/lib/micronaut/configuration.rb +162 -0
- data/lib/micronaut/example.rb +112 -0
- data/lib/micronaut/expectations.rb +45 -0
- data/lib/micronaut/expectations/extensions/object.rb +92 -0
- data/lib/micronaut/expectations/handler.rb +51 -0
- data/lib/micronaut/expectations/wrap_expectation.rb +52 -0
- data/lib/micronaut/formatters.rb +12 -0
- data/lib/micronaut/formatters/base_formatter.rb +127 -0
- data/lib/micronaut/formatters/base_text_formatter.rb +139 -0
- data/lib/micronaut/formatters/documentation_formatter.rb +78 -0
- data/lib/micronaut/formatters/progress_formatter.rb +30 -0
- data/lib/micronaut/kernel_extensions.rb +11 -0
- data/lib/micronaut/matchers.rb +141 -0
- data/lib/micronaut/matchers/be.rb +204 -0
- data/lib/micronaut/matchers/be_close.rb +37 -0
- data/lib/micronaut/matchers/change.rb +148 -0
- data/lib/micronaut/matchers/eql.rb +26 -0
- data/lib/micronaut/matchers/equal.rb +26 -0
- data/lib/micronaut/matchers/generated_descriptions.rb +36 -0
- data/lib/micronaut/matchers/has.rb +19 -0
- data/lib/micronaut/matchers/have.rb +153 -0
- data/lib/micronaut/matchers/include.rb +80 -0
- data/lib/micronaut/matchers/match.rb +22 -0
- data/lib/micronaut/matchers/method_missing.rb +9 -0
- data/lib/micronaut/matchers/operator_matcher.rb +50 -0
- data/lib/micronaut/matchers/raise_error.rb +128 -0
- data/lib/micronaut/matchers/respond_to.rb +50 -0
- data/lib/micronaut/matchers/satisfy.rb +50 -0
- data/lib/micronaut/matchers/simple_matcher.rb +135 -0
- data/lib/micronaut/matchers/throw_symbol.rb +108 -0
- data/lib/micronaut/mocking/with_absolutely_nothing.rb +11 -0
- data/lib/micronaut/mocking/with_mocha.rb +15 -0
- data/lib/micronaut/mocking/with_rr.rb +24 -0
- data/lib/micronaut/rake_task.rb +84 -0
- data/lib/micronaut/runner.rb +60 -0
- data/lib/micronaut/world.rb +75 -0
- metadata +165 -0
@@ -0,0 +1,139 @@
|
|
1
|
+
module Micronaut
|
2
|
+
|
3
|
+
module Formatters
|
4
|
+
|
5
|
+
class BaseTextFormatter < BaseFormatter
|
6
|
+
|
7
|
+
def dump_failures
|
8
|
+
output.puts
|
9
|
+
failed_examples.each_with_index do |failed_example, index|
|
10
|
+
exception = failed_example.execution_result[:exception_encountered]
|
11
|
+
padding = ' '
|
12
|
+
|
13
|
+
output.puts "#{index.next}) #{failed_example}"
|
14
|
+
output.puts "#{padding}Failure/Error: #{read_failed_line(exception, failed_example).strip}"
|
15
|
+
|
16
|
+
exception.message.split("\n").each do |line|
|
17
|
+
output.puts "#{padding}#{colorise(line, exception).strip}"
|
18
|
+
end
|
19
|
+
|
20
|
+
format_backtrace(exception.backtrace, failed_example).each do |backtrace_info|
|
21
|
+
output.puts grey("#{padding}# #{backtrace_info}")
|
22
|
+
end
|
23
|
+
|
24
|
+
output.puts
|
25
|
+
output.flush
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def colorise(s, failure)
|
30
|
+
if failure.is_a?(Micronaut::Expectations::ExpectationNotMetError)
|
31
|
+
red(s)
|
32
|
+
else
|
33
|
+
magenta(s)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def dump_summary
|
38
|
+
failure_count = failed_examples.size
|
39
|
+
pending_count = pending_examples.size
|
40
|
+
|
41
|
+
output.puts "\nFinished in #{duration} seconds\n"
|
42
|
+
|
43
|
+
summary = "#{example_count} example#{'s' unless example_count == 1}, #{failure_count} failures"
|
44
|
+
summary << ", #{pending_count} pending" if pending_count > 0
|
45
|
+
|
46
|
+
if failure_count == 0
|
47
|
+
if pending_count > 0
|
48
|
+
output.puts yellow(summary)
|
49
|
+
else
|
50
|
+
output.puts green(summary)
|
51
|
+
end
|
52
|
+
else
|
53
|
+
output.puts red(summary)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Don't print out profiled info if there are failures, it just clutters the output
|
57
|
+
if profile_examples? && failure_count == 0
|
58
|
+
sorted_examples = examples.sort_by { |example| example.execution_result[:run_time] }.reverse.first(10)
|
59
|
+
output.puts "\nTop #{sorted_examples.size} slowest examples:\n"
|
60
|
+
sorted_examples.each do |example|
|
61
|
+
output.puts " (#{sprintf("%.7f", example.execution_result[:run_time])} seconds) #{example}"
|
62
|
+
output.puts grey(" # #{format_caller(example.metadata[:caller])}")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
output.flush
|
67
|
+
end
|
68
|
+
|
69
|
+
# def textmate_link_backtrace(path)
|
70
|
+
# file, line = path.split(':')
|
71
|
+
# "txmt://open/?url=file://#{File.expand_path(file)}&line=#{line}"
|
72
|
+
# end
|
73
|
+
|
74
|
+
def format_caller(caller_info)
|
75
|
+
caller_info.to_s.split(':in `block').first
|
76
|
+
end
|
77
|
+
|
78
|
+
def dump_pending
|
79
|
+
unless pending_examples.empty?
|
80
|
+
output.puts
|
81
|
+
output.puts "Pending:"
|
82
|
+
pending_examples.each do |pending_example, message|
|
83
|
+
output.puts " #{pending_example}"
|
84
|
+
output.puts grey(" # #{format_caller(pending_example.metadata[:caller])}")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
output.flush
|
88
|
+
end
|
89
|
+
|
90
|
+
def close
|
91
|
+
if IO === output && output != $stdout
|
92
|
+
output.close
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
protected
|
97
|
+
|
98
|
+
def color(text, color_code)
|
99
|
+
return text unless color_enabled?
|
100
|
+
"#{color_code}#{text}\e[0m"
|
101
|
+
end
|
102
|
+
|
103
|
+
def bold(text)
|
104
|
+
color(text, "\e[1m")
|
105
|
+
end
|
106
|
+
|
107
|
+
def white(text)
|
108
|
+
color(text, "\e[37m")
|
109
|
+
end
|
110
|
+
|
111
|
+
def green(text)
|
112
|
+
color(text, "\e[32m")
|
113
|
+
end
|
114
|
+
|
115
|
+
def red(text)
|
116
|
+
color(text, "\e[31m")
|
117
|
+
end
|
118
|
+
|
119
|
+
def magenta(text)
|
120
|
+
color(text, "\e[35m")
|
121
|
+
end
|
122
|
+
|
123
|
+
def yellow(text)
|
124
|
+
color(text, "\e[33m")
|
125
|
+
end
|
126
|
+
|
127
|
+
def blue(text)
|
128
|
+
color(text, "\e[34m")
|
129
|
+
end
|
130
|
+
|
131
|
+
def grey(text)
|
132
|
+
color(text, "\e[90m")
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Micronaut
|
2
|
+
module Formatters
|
3
|
+
|
4
|
+
class DocumentationFormatter < BaseTextFormatter
|
5
|
+
|
6
|
+
attr_reader :previous_nested_behaviours
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
super
|
10
|
+
@previous_nested_behaviours = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_behaviour(behaviour)
|
14
|
+
super
|
15
|
+
|
16
|
+
described_behaviour_chain.each_with_index do |nested_behaviour, i|
|
17
|
+
unless nested_behaviour == previous_nested_behaviours[i]
|
18
|
+
at_root_level = (i == 0)
|
19
|
+
desc_or_name = at_root_level ? nested_behaviour.name : nested_behaviour.description
|
20
|
+
output.puts if at_root_level
|
21
|
+
output.puts "#{' ' * i}#{desc_or_name}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
@previous_nested_behaviours = described_behaviour_chain
|
26
|
+
end
|
27
|
+
|
28
|
+
def output_for(example)
|
29
|
+
case example.execution_result[:status]
|
30
|
+
when 'failed'
|
31
|
+
failure_output(example, example.execution_result[:exception_encountered])
|
32
|
+
when 'pending'
|
33
|
+
pending_output(example, example.execution_result[:pending_message])
|
34
|
+
when 'passed'
|
35
|
+
passed_output(example)
|
36
|
+
else
|
37
|
+
red(example.execution_result[:status])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def example_finished(example)
|
42
|
+
super
|
43
|
+
output.puts output_for(example)
|
44
|
+
output.flush
|
45
|
+
end
|
46
|
+
|
47
|
+
def failure_output(example, exception)
|
48
|
+
expectation_not_met = exception.is_a?(::Micronaut::Expectations::ExpectationNotMetError)
|
49
|
+
|
50
|
+
message = if expectation_not_met
|
51
|
+
"#{current_indentation}#{example.description} (FAILED)"
|
52
|
+
else
|
53
|
+
"#{current_indentation}#{example.description} (ERROR)"
|
54
|
+
end
|
55
|
+
|
56
|
+
expectation_not_met ? red(message) : magenta(message)
|
57
|
+
end
|
58
|
+
|
59
|
+
def passed_output(example)
|
60
|
+
green("#{current_indentation}#{example.description}")
|
61
|
+
end
|
62
|
+
|
63
|
+
def pending_output(example, message)
|
64
|
+
yellow("#{current_indentation}#{example.description} (PENDING: #{message})")
|
65
|
+
end
|
66
|
+
|
67
|
+
def current_indentation
|
68
|
+
' ' * previous_nested_behaviours.size
|
69
|
+
end
|
70
|
+
|
71
|
+
def described_behaviour_chain
|
72
|
+
behaviour.ancestors
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Micronaut
|
2
|
+
module Formatters
|
3
|
+
|
4
|
+
class ProgressFormatter < BaseTextFormatter
|
5
|
+
|
6
|
+
def output_for(example)
|
7
|
+
case example.execution_result[:status]
|
8
|
+
when 'failed' then colorise('F', example.execution_result[:exception_encountered])
|
9
|
+
when 'pending' then yellow('*')
|
10
|
+
when 'passed' then green('.')
|
11
|
+
else
|
12
|
+
red(example.execution_result[:status])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def example_finished(example)
|
17
|
+
super
|
18
|
+
output.print output_for(example)
|
19
|
+
end
|
20
|
+
|
21
|
+
def start_dump(duration)
|
22
|
+
super
|
23
|
+
output.puts
|
24
|
+
output.flush
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'micronaut/matchers/generated_descriptions'
|
2
|
+
require 'micronaut/matchers/simple_matcher'
|
3
|
+
require 'micronaut/matchers/be'
|
4
|
+
require 'micronaut/matchers/be_close'
|
5
|
+
require 'micronaut/matchers/change'
|
6
|
+
require 'micronaut/matchers/eql'
|
7
|
+
require 'micronaut/matchers/equal'
|
8
|
+
require 'micronaut/matchers/has'
|
9
|
+
require 'micronaut/matchers/have'
|
10
|
+
require 'micronaut/matchers/include'
|
11
|
+
require 'micronaut/matchers/match'
|
12
|
+
require 'micronaut/matchers/raise_error'
|
13
|
+
require 'micronaut/matchers/respond_to'
|
14
|
+
require 'micronaut/matchers/satisfy'
|
15
|
+
require 'micronaut/matchers/throw_symbol'
|
16
|
+
require 'micronaut/matchers/operator_matcher'
|
17
|
+
|
18
|
+
module Micronaut
|
19
|
+
|
20
|
+
# We ship (courtesy of RSpec and Micronaut) with a number of useful Expression Matchers. An Expression Matcher
|
21
|
+
# is any object that responds to the following methods:
|
22
|
+
#
|
23
|
+
# matches?(actual)
|
24
|
+
# failure_message
|
25
|
+
# negative_failure_message #optional
|
26
|
+
# description #optional
|
27
|
+
#
|
28
|
+
# See Micronaut::Expectations to learn how to use these as Expectation Matchers.
|
29
|
+
# See Micronaut::Mocks to learn how to use them as Mock Argument Constraints.
|
30
|
+
#
|
31
|
+
# == Predicates
|
32
|
+
#
|
33
|
+
# In addition to those Expression Matchers that are defined explicitly, we will
|
34
|
+
# create custom Matchers on the fly for any arbitrary predicate, giving your specs
|
35
|
+
# a much more natural language feel.
|
36
|
+
#
|
37
|
+
# A Ruby predicate is a method that ends with a "?" and returns true or false.
|
38
|
+
# Common examples are +empty?+, +nil?+, and +instance_of?+.
|
39
|
+
#
|
40
|
+
# All you need to do is write +should be_+ followed by the predicate without
|
41
|
+
# the question mark, and we will figure it out from there. For example:
|
42
|
+
#
|
43
|
+
# [].should be_empty => [].empty? #passes
|
44
|
+
# [].should_not be_empty => [].empty? #fails
|
45
|
+
#
|
46
|
+
# In addtion to prefixing the predicate matchers with "be_", you can also use "be_a_"
|
47
|
+
# and "be_an_", making your specs read much more naturally:
|
48
|
+
#
|
49
|
+
# "a string".should be_an_instance_of(String) =>"a string".instance_of?(String) #passes
|
50
|
+
#
|
51
|
+
# 3.should be_a_kind_of(Fixnum) => 3.kind_of?(Numeric) #passes
|
52
|
+
# 3.should be_a_kind_of(Numeric) => 3.kind_of?(Numeric) #passes
|
53
|
+
# 3.should be_an_instance_of(Fixnum) => 3.instance_of?(Fixnum) #passes
|
54
|
+
# 3.should_not be_instance_of(Numeric) => 3.instance_of?(Numeric) #fails
|
55
|
+
#
|
56
|
+
# We will also create custom matchers for predicates like +has_key?+. To
|
57
|
+
# use this feature, just state that the object should have_key(:key) and we will
|
58
|
+
# call has_key?(:key) on the target. For example:
|
59
|
+
#
|
60
|
+
# {:a => "A"}.should have_key(:a) => {:a => "A"}.has_key?(:a) #passes
|
61
|
+
# {:a => "A"}.should have_key(:b) => {:a => "A"}.has_key?(:b) #fails
|
62
|
+
#
|
63
|
+
# You can use this feature to invoke any predicate that begins with "has_", whether it is
|
64
|
+
# part of the Ruby libraries (like +Hash#has_key?+) or a method you wrote on your own class.
|
65
|
+
#
|
66
|
+
# == Custom Expectation Matchers
|
67
|
+
#
|
68
|
+
# When you find that none of the stock Expectation Matchers provide a natural
|
69
|
+
# feeling expectation, you can very easily write your own.
|
70
|
+
#
|
71
|
+
# For example, imagine that you are writing a game in which players can
|
72
|
+
# be in various zones on a virtual board. To specify that bob should
|
73
|
+
# be in zone 4, you could say:
|
74
|
+
#
|
75
|
+
# bob.current_zone.should eql(Zone.new("4"))
|
76
|
+
#
|
77
|
+
# But you might find it more expressive to say:
|
78
|
+
#
|
79
|
+
# bob.should be_in_zone("4")
|
80
|
+
#
|
81
|
+
# and/or
|
82
|
+
#
|
83
|
+
# bob.should_not be_in_zone("3")
|
84
|
+
#
|
85
|
+
# To do this, you would need to write a class like this:
|
86
|
+
#
|
87
|
+
# class BeInZone
|
88
|
+
# def initialize(expected)
|
89
|
+
# @expected = expected
|
90
|
+
# end
|
91
|
+
# def matches?(target)
|
92
|
+
# @target = target
|
93
|
+
# @target.current_zone.eql?(Zone.new(@expected))
|
94
|
+
# end
|
95
|
+
# def failure_message
|
96
|
+
# "expected #{@target.inspect} to be in Zone #{@expected}"
|
97
|
+
# end
|
98
|
+
# def negative_failure_message
|
99
|
+
# "expected #{@target.inspect} not to be in Zone #{@expected}"
|
100
|
+
# end
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# ... and a method like this:
|
104
|
+
#
|
105
|
+
# def be_in_zone(expected)
|
106
|
+
# BeInZone.new(expected)
|
107
|
+
# end
|
108
|
+
#
|
109
|
+
# And then expose the method to your specs. This is normally done
|
110
|
+
# by including the method and the class in a module, which is then
|
111
|
+
# included in your spec:
|
112
|
+
#
|
113
|
+
# module CustomGameMatchers
|
114
|
+
# class BeInZone
|
115
|
+
# ...
|
116
|
+
# end
|
117
|
+
#
|
118
|
+
# def be_in_zone(expected)
|
119
|
+
# ...
|
120
|
+
# end
|
121
|
+
# end
|
122
|
+
#
|
123
|
+
# describe "Player behaviour" do
|
124
|
+
# include CustomGameMatchers
|
125
|
+
# ...
|
126
|
+
# end
|
127
|
+
|
128
|
+
module Matchers
|
129
|
+
|
130
|
+
class MatcherError < StandardError; end
|
131
|
+
|
132
|
+
private
|
133
|
+
def method_missing(sym, *args, &block) # :nodoc:
|
134
|
+
return Matchers::Be.new(sym, *args) if sym.to_s =~ /^be_/
|
135
|
+
return has(sym, *args) if sym.to_s =~ /^have_/
|
136
|
+
super
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
module Micronaut
|
2
|
+
module Matchers
|
3
|
+
|
4
|
+
class Be #:nodoc:
|
5
|
+
def initialize(*args)
|
6
|
+
@expected = args.empty? ? true : set_expected(args.shift)
|
7
|
+
@args = args
|
8
|
+
end
|
9
|
+
|
10
|
+
def matches?(actual)
|
11
|
+
@actual = actual
|
12
|
+
handling_predicate? ? run_predicate_on(actual) : match_or_compare(actual)
|
13
|
+
end
|
14
|
+
|
15
|
+
def run_predicate_on(actual)
|
16
|
+
begin
|
17
|
+
return @result = actual.__send__(predicate, *@args)
|
18
|
+
rescue NameError => predicate_missing_error
|
19
|
+
"this needs to be here or rcov will not count this branch even though it's executed in a code example"
|
20
|
+
end
|
21
|
+
|
22
|
+
begin
|
23
|
+
return @result = actual.__send__(present_tense_predicate, *@args)
|
24
|
+
rescue NameError
|
25
|
+
raise predicate_missing_error
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def failure_message
|
30
|
+
handling_predicate? ?
|
31
|
+
"expected #{predicate}#{args_to_s} to return true, got #{@result.inspect}" :
|
32
|
+
"expected #{@comparison_method} #{expected}, got #{@actual.inspect}".gsub(' ',' ')
|
33
|
+
end
|
34
|
+
|
35
|
+
def negative_failure_message
|
36
|
+
if handling_predicate?
|
37
|
+
"expected #{predicate}#{args_to_s} to return false, got #{@result.inspect}"
|
38
|
+
else
|
39
|
+
message = <<-MESSAGE
|
40
|
+
'should_not be #{@comparison_method} #{expected}' not only FAILED,
|
41
|
+
it reads really poorly.
|
42
|
+
MESSAGE
|
43
|
+
|
44
|
+
raise message << ([:===,:==].include?(@comparison_method) ?
|
45
|
+
"Why don't you try expressing it without the \"be\"?" :
|
46
|
+
"Why don't you try expressing it in the positive?")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def description
|
51
|
+
"#{prefix_to_sentence}#{comparison} #{expected_to_sentence}#{args_to_sentence}".gsub(/\s+/,' ')
|
52
|
+
end
|
53
|
+
|
54
|
+
[:==, :<, :<=, :>=, :>, :===].each do |method|
|
55
|
+
define_method method do |expected|
|
56
|
+
compare_to(expected, :using => method)
|
57
|
+
self
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
def match_or_compare(actual)
|
63
|
+
case @expected
|
64
|
+
when TrueClass
|
65
|
+
@actual
|
66
|
+
else
|
67
|
+
@actual.__send__(comparison_method, @expected)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def comparison_method
|
72
|
+
@comparison_method || :equal?
|
73
|
+
end
|
74
|
+
|
75
|
+
def expected
|
76
|
+
@expected
|
77
|
+
end
|
78
|
+
|
79
|
+
def compare_to(expected, opts)
|
80
|
+
@expected, @comparison_method = expected, opts[:using]
|
81
|
+
end
|
82
|
+
|
83
|
+
def set_expected(expected)
|
84
|
+
Symbol === expected ? parse_expected(expected) : expected
|
85
|
+
end
|
86
|
+
|
87
|
+
def parse_expected(expected)
|
88
|
+
["be_an_","be_a_","be_"].each do |prefix|
|
89
|
+
handling_predicate!
|
90
|
+
if expected.to_s =~ /^#{prefix}/
|
91
|
+
set_prefix(prefix)
|
92
|
+
expected = expected.to_s.sub(prefix,"")
|
93
|
+
[true, false, nil].each do |val|
|
94
|
+
return val if val.to_s == expected
|
95
|
+
end
|
96
|
+
return expected.to_sym
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def set_prefix(prefix)
|
102
|
+
@prefix = prefix
|
103
|
+
end
|
104
|
+
|
105
|
+
def prefix
|
106
|
+
@prefix
|
107
|
+
end
|
108
|
+
|
109
|
+
def handling_predicate!
|
110
|
+
@handling_predicate = true
|
111
|
+
end
|
112
|
+
|
113
|
+
def handling_predicate?
|
114
|
+
return false if [true, false, nil].include?(expected)
|
115
|
+
return @handling_predicate
|
116
|
+
end
|
117
|
+
|
118
|
+
def predicate
|
119
|
+
"#{@expected.to_s}?".to_sym
|
120
|
+
end
|
121
|
+
|
122
|
+
def present_tense_predicate
|
123
|
+
"#{@expected.to_s}s?".to_sym
|
124
|
+
end
|
125
|
+
|
126
|
+
def args_to_s
|
127
|
+
@args.empty? ? "" : parenthesize(inspected_args.join(', '))
|
128
|
+
end
|
129
|
+
|
130
|
+
def parenthesize(string)
|
131
|
+
return "(#{string})"
|
132
|
+
end
|
133
|
+
|
134
|
+
def inspected_args
|
135
|
+
@args.collect{|a| a.inspect}
|
136
|
+
end
|
137
|
+
|
138
|
+
def comparison
|
139
|
+
@comparison_method.nil? ? " " : "be #{@comparison_method.to_s} "
|
140
|
+
end
|
141
|
+
|
142
|
+
def expected_to_sentence
|
143
|
+
split_words(expected)
|
144
|
+
end
|
145
|
+
|
146
|
+
def prefix_to_sentence
|
147
|
+
split_words(prefix)
|
148
|
+
end
|
149
|
+
|
150
|
+
def split_words(sym)
|
151
|
+
sym.to_s.gsub(/_/,' ')
|
152
|
+
end
|
153
|
+
|
154
|
+
def args_to_sentence
|
155
|
+
case @args.length
|
156
|
+
when 0
|
157
|
+
""
|
158
|
+
when 1
|
159
|
+
" #{@args[0]}"
|
160
|
+
else
|
161
|
+
" #{@args[0...-1].join(', ')} and #{@args[-1]}"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
# :call-seq:
|
168
|
+
# should be_true
|
169
|
+
# should be_false
|
170
|
+
# should be_nil
|
171
|
+
# should be_arbitrary_predicate(*args)
|
172
|
+
# should_not be_nil
|
173
|
+
# should_not be_arbitrary_predicate(*args)
|
174
|
+
#
|
175
|
+
# Given true, false, or nil, will pass if actual value is
|
176
|
+
# true, false or nil (respectively). Given no args means
|
177
|
+
# the caller should satisfy an if condition (to be or not to be).
|
178
|
+
#
|
179
|
+
# Predicates are any Ruby method that ends in a "?" and returns true or false.
|
180
|
+
# Given be_ followed by arbitrary_predicate (without the "?"), we will match
|
181
|
+
# convert that into a query against the target object.
|
182
|
+
#
|
183
|
+
# The arbitrary_predicate feature will handle any predicate
|
184
|
+
# prefixed with "be_an_" (e.g. be_an_instance_of), "be_a_" (e.g. be_a_kind_of)
|
185
|
+
# or "be_" (e.g. be_empty), letting you choose the prefix that best suits the predicate.
|
186
|
+
#
|
187
|
+
# == Examples
|
188
|
+
#
|
189
|
+
# target.should be_true
|
190
|
+
# target.should be_false
|
191
|
+
# target.should be_nil
|
192
|
+
# target.should_not be_nil
|
193
|
+
#
|
194
|
+
# collection.should be_empty #passes if target.empty?
|
195
|
+
# "this string".should be_an_intance_of(String)
|
196
|
+
#
|
197
|
+
# target.should_not be_empty #passes unless target.empty?
|
198
|
+
# target.should_not be_old_enough(16) #passes unless target.old_enough?(16)
|
199
|
+
def be(*args)
|
200
|
+
Matchers::Be.new(*args)
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
end
|