rspec 0.6.3 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. data/CHANGES +28 -3
  2. data/EXAMPLES.rd +2 -16
  3. data/README +5 -2
  4. data/Rakefile +8 -4
  5. data/bin/spec +1 -0
  6. data/examples/custom_formatter.rb +2 -1
  7. data/examples/helper_method_spec.rb +12 -0
  8. data/examples/{mocking_spec.rb → mocking_example.rb} +0 -0
  9. data/examples/{bdd_framework_spec.rb → predicate_example.rb} +0 -0
  10. data/examples/stubbing_example.rb +28 -0
  11. data/lib/spec.rb +2 -1
  12. data/lib/spec/expectations.rb +7 -0
  13. data/lib/spec/expectations/diff.rb +56 -0
  14. data/lib/spec/expectations/exceptions.rb +6 -0
  15. data/lib/spec/expectations/expectations.rb +19 -0
  16. data/lib/spec/expectations/have_helper.rb +41 -0
  17. data/lib/spec/expectations/helper.rb +4 -0
  18. data/lib/spec/expectations/should_base.rb +52 -0
  19. data/lib/spec/expectations/should_helper.rb +93 -0
  20. data/lib/spec/expectations/should_negator.rb +71 -0
  21. data/lib/spec/{api → expectations}/sugar.rb +8 -8
  22. data/lib/spec/mocks.rb +5 -0
  23. data/lib/spec/{api/mocks → mocks}/argument_expectation.rb +1 -1
  24. data/lib/spec/{api → mocks}/exceptions.rb +3 -5
  25. data/lib/spec/{api/mocks → mocks}/message_expectation.rb +15 -9
  26. data/lib/spec/{api/mocks → mocks}/mock.rb +44 -26
  27. data/lib/spec/{api/mocks → mocks}/order_group.rb +1 -1
  28. data/lib/spec/runner/backtrace_tweaker.rb +4 -1
  29. data/lib/spec/runner/execution_context.rb +13 -4
  30. data/lib/spec/runner/formatter/base_text_formatter.rb +26 -13
  31. data/lib/spec/runner/formatter/html_formatter.rb +1 -1
  32. data/lib/spec/runner/option_parser.rb +6 -2
  33. data/lib/spec/runner/specification.rb +2 -2
  34. data/lib/spec/test_to_spec/ruby2ruby.rb +1 -1
  35. data/lib/spec/version.rb +1 -1
  36. data/test/spec/expectations/arbitrary_operator_test.rb +55 -0
  37. data/test/spec/expectations/arbitrary_predicate_test.rb +163 -0
  38. data/test/spec/{api/helper → expectations}/containment_test.rb +2 -2
  39. data/test/spec/expectations/diff_test.rb +62 -0
  40. data/test/spec/{api/helper → expectations}/identity_test.rb +2 -2
  41. data/test/spec/{api/helper → expectations}/object_equality_test.rb +2 -2
  42. data/test/spec/{api/helper → expectations}/raising_test.rb +5 -5
  43. data/test/spec/{api/helper → expectations}/regex_matching_test.rb +6 -6
  44. data/test/spec/{api/helper → expectations}/should_have_test.rb +11 -2
  45. data/test/spec/{api/helper → expectations}/should_satisfy_test.rb +2 -4
  46. data/test/spec/{api → expectations}/sugar_test.rb +8 -8
  47. data/test/spec/expectations/supported_symbols_test.rb +33 -0
  48. data/test/spec/{api/helper → expectations}/throwing_test.rb +2 -2
  49. data/test/spec/{api/helper → expectations}/true_false_special_case_test.rb +2 -2
  50. data/test/spec/{api/helper → expectations}/typing_test.rb +2 -2
  51. data/test/spec/{api/mocks → mocks}/mock_arg_constraints_test.rb +4 -4
  52. data/test/spec/{api/mocks → mocks}/mock_counts_test.rb +2 -2
  53. data/test/spec/{api/mocks → mocks}/mock_ordering_test.rb +2 -2
  54. data/test/spec/{api/mocks → mocks}/mock_test.rb +22 -7
  55. data/test/spec/{api/mocks → mocks}/null_object_test.rb +8 -2
  56. data/test/spec/runner/backtrace_tweaker_test.rb +21 -19
  57. data/test/spec/runner/context_matching_test.rb +2 -2
  58. data/test/spec/runner/context_runner_test.rb +6 -6
  59. data/test/spec/runner/context_test.rb +1 -1
  60. data/test/spec/runner/execution_context_test.rb +22 -5
  61. data/test/spec/runner/formatter/failure_dump_test.rb +7 -7
  62. data/test/spec/runner/option_parser_test.rb +20 -0
  63. data/test/spec/runner/reporter_test.rb +3 -3
  64. data/test/spec/runner/specification_test.rb +3 -3
  65. data/test/spec/test_to_spec/sexp_transformer_assertion_test.rb +4 -4
  66. data/test/spec/test_to_spec/sexp_transformer_test.rb +1 -1
  67. data/test/spec/test_to_spec/testfiles/test_unit_api_test.rb +2 -2
  68. data/test/test_classes.rb +21 -1
  69. data/test/test_helper.rb +1 -1
  70. data/vendor/selenium/README.txt +23 -0
  71. data/vendor/selenium/find_rspecs_home_page.rb +23 -0
  72. data/vendor/selenium/rspec_selenium.rb +33 -0
  73. data/vendor/watir/README.txt +32 -0
  74. data/vendor/watir/find_rspecs_home_page.rb +21 -0
  75. data/vendor/watir/find_rspecs_home_page.txt +15 -0
  76. data/vendor/watir/rspec_watir.rb +45 -0
  77. metadata +52 -41
  78. data/examples/airport_spec.rb +0 -33
  79. data/examples/custom_method_spec.rb +0 -24
  80. data/examples/sugar_spec.rb +0 -14
  81. data/lib/spec/api.rb +0 -8
  82. data/lib/spec/api/expectations.rb +0 -17
  83. data/lib/spec/api/helper.rb +0 -4
  84. data/lib/spec/api/helper/diff.rb +0 -54
  85. data/lib/spec/api/helper/have_helper.rb +0 -40
  86. data/lib/spec/api/helper/should_base.rb +0 -31
  87. data/lib/spec/api/helper/should_helper.rb +0 -93
  88. data/lib/spec/api/helper/should_negator.rb +0 -72
  89. data/test/spec/api/helper/arbitrary_predicate_test.rb +0 -112
  90. data/test/spec/api/helper/diff_test.rb +0 -60
@@ -0,0 +1,71 @@
1
+ module Spec
2
+ module Expectations
3
+ class ShouldNegator < ShouldBase
4
+
5
+ def initialize(target)
6
+ @target = target
7
+ @be_seen = false
8
+ end
9
+
10
+ def satisfy
11
+ fail_with_message "Supplied expectation was satisfied, but should not have been" if (yield @target)
12
+ end
13
+
14
+ def equal(expected)
15
+ fail_with_message(default_message("should not equal", expected)) if (@target == expected)
16
+ end
17
+
18
+ def be(expected = :no_arg)
19
+ @be_seen = true
20
+ return self if (expected == :no_arg)
21
+ fail_with_message(default_message("should not be", expected)) if (@target.equal?(expected))
22
+ end
23
+
24
+ def an_instance_of expected_class
25
+ fail_with_message(default_message("should not be an instance of", expected_class)) if @target.instance_of? expected_class
26
+ end
27
+
28
+ def a_kind_of expected_class
29
+ fail_with_message(default_message("should not be a kind of", expected_class)) if @target.kind_of? expected_class
30
+ end
31
+
32
+ def respond_to message
33
+ fail_with_message(default_message("should not respond to", message)) if @target.respond_to? message
34
+ end
35
+
36
+ def match(expected)
37
+ fail_with_message(default_message("should not match", expected)) if (@target =~ expected)
38
+ end
39
+
40
+ def raise(exception=Exception, message=nil)
41
+ begin
42
+ @target.call
43
+ rescue exception => e
44
+ return unless message.nil? || e.message == message
45
+ fail_with_message("#{default_message("should not raise", exception)}") if e.instance_of? exception
46
+ fail_with_message("#{default_message("should not raise", exception)} but raised #{e.inspect}") unless e.instance_of? exception
47
+ rescue
48
+ true
49
+ end
50
+ end
51
+
52
+ def throw(symbol=:___this_is_a_symbol_that_will_likely_never_occur___)
53
+ begin
54
+ catch symbol do
55
+ @target.call
56
+ return true
57
+ end
58
+ fail_with_message(default_message("should not throw", symbol.inspect))
59
+ rescue NameError
60
+ true
61
+ end
62
+ end
63
+
64
+ def method_missing(original_sym, *args)
65
+ actual_sym = find_supported_sym(original_sym)
66
+ return unless @target.__send__(actual_sym, *args)
67
+ fail_with_message(default_message("should not#{@be_seen ? ' be' : ''} #{original_sym}" + (args.empty? ? '' : (' ' + args.join(', ')))))
68
+ end
69
+ end
70
+ end
71
+ end
@@ -1,19 +1,19 @@
1
1
  module Spec
2
- module Api
2
+ module Expectations
3
3
  # This module adds syntactic sugar that allows usage of should_* instead of should.*
4
4
  module UnderscoreSugar
5
- module SugarizeForRspec; end
5
+ module SweetTooth; end
6
6
 
7
- def sugarize_for_rspec!
7
+ def handle_underscores_for_rspec!
8
8
  original_method_missing = instance_method(:method_missing)
9
9
  class_eval do
10
- include SugarizeForRspec # This is meant to add a signature to the object that sugarization occurred.
10
+ include SweetTooth # This is meant to add a signature to the object that sugarization occurred.
11
11
  def method_missing(sym, *args, &block)
12
12
  _method_missing(sym, args, block)
13
13
  end
14
14
 
15
15
  define_method :_method_missing do |sym, args, block|
16
- return original_method_missing.bind(self).call(sym, *args, &block) unless __is_sweetened?(sym)
16
+ return original_method_missing.bind(self).call(sym, *args, &block) unless __sweetened?(sym)
17
17
 
18
18
  object = self
19
19
  calls = sym.to_s.split("_")
@@ -27,7 +27,7 @@ module Spec
27
27
  return object.__send__(calls.join("_"), *args, &block)
28
28
  end
29
29
 
30
- def __is_sweetened?(sym) #:nodoc:
30
+ def __sweetened?(sym) #:nodoc:
31
31
  return true if sym.to_s =~ /^should_/
32
32
  end
33
33
  end
@@ -37,7 +37,7 @@ module Spec
37
37
  end
38
38
 
39
39
  class Module
40
- include Spec::Api::UnderscoreSugar
40
+ include Spec::Expectations::UnderscoreSugar
41
41
  end
42
42
 
43
- Object.sugarize_for_rspec!
43
+ Object.handle_underscores_for_rspec!
@@ -0,0 +1,5 @@
1
+ require 'spec/mocks/mock'
2
+ require 'spec/mocks/argument_expectation'
3
+ require 'spec/mocks/message_expectation'
4
+ require 'spec/mocks/order_group'
5
+ require 'spec/mocks/exceptions'
@@ -1,5 +1,5 @@
1
1
  module Spec
2
- module Api
2
+ module Mocks
3
3
 
4
4
  class LiteralArgConstraint
5
5
  def initialize(literal)
@@ -1,12 +1,10 @@
1
1
  module Spec
2
- module Api
3
- class ExpectationNotMetError < StandardError
4
- end
5
-
2
+ module Mocks
6
3
  class MockExpectationError < StandardError
7
4
  end
8
-
5
+
9
6
  class AmbiguousReturnError < StandardError
10
7
  end
11
8
  end
12
9
  end
10
+
@@ -1,17 +1,17 @@
1
1
  module Spec
2
- module Api
2
+ module Mocks
3
3
 
4
4
  # Represents the expection of the reception of a message
5
5
  class MessageExpectation
6
6
 
7
- def initialize(mock_name, expectation_ordering, expected_from, sym, method_block)
7
+ def initialize(mock_name, expectation_ordering, expected_from, sym, method_block, expected_received_count=1)
8
8
  @mock_name = mock_name
9
9
  @expected_from = expected_from
10
10
  @sym = sym
11
11
  @method_block = method_block
12
12
  @return_block = lambda {}
13
13
  @received_count = 0
14
- @expected_received_count = 1
14
+ @expected_received_count = expected_received_count
15
15
  @args_expectation = ArgumentExpectation.new([:any_args])
16
16
  @consecutive = false
17
17
  @exception_to_raise = nil
@@ -53,7 +53,7 @@ module Spec
53
53
 
54
54
  message = "Mock '#{@mock_name}' expected '#{@sym}' #{count_message}, but received it #{@received_count} times"
55
55
  begin
56
- Kernel::raise(Spec::Api::MockExpectationError, message)
56
+ Kernel::raise(Spec::Mocks::MockExpectationError, message)
57
57
  rescue => error
58
58
  error.backtrace.insert(0, @expected_from)
59
59
  Kernel::raise error
@@ -64,7 +64,7 @@ module Spec
64
64
  return unless @ordered
65
65
  return @ordering.consume(self) if @ordering.ready_for?(self)
66
66
  message = "Mock '#{@mock_name}' received '#{@sym}' out of order"
67
- Kernel::raise(Spec::Api::MockExpectationError, message)
67
+ Kernel::raise(Spec::Mocks::MockExpectationError, message)
68
68
  end
69
69
 
70
70
  # This method is called when a method is invoked on a mock
@@ -91,17 +91,17 @@ module Spec
91
91
  def invoke_method_block(args)
92
92
  begin
93
93
  @method_block.call(*args)
94
- rescue Spec::Api::ExpectationNotMetError => detail
95
- Kernel::raise Spec::Api::MockExpectationError, "Call expectation violated with: " + detail
94
+ rescue Spec::Expectations::ExpectationNotMetError => detail
95
+ Kernel::raise Spec::Mocks::MockExpectationError, "Call expectation violated with: " + detail
96
96
  end
97
97
  end
98
98
 
99
99
  def invoke_with_yield(block)
100
100
  if block.nil?
101
- Kernel::raise Spec::Api::MockExpectationError, "Expected block to be passed"
101
+ Kernel::raise Spec::Mocks::MockExpectationError, "Expected block to be passed"
102
102
  end
103
103
  if @args_to_yield.length != block.arity
104
- Kernel::raise Spec::Api::MockExpectationError, "Wrong arity of passed block. Expected #{@args_to_yield.size}"
104
+ Kernel::raise Spec::Mocks::MockExpectationError, "Wrong arity of passed block. Expected #{@args_to_yield.size}"
105
105
  end
106
106
  block.call(*@args_to_yield)
107
107
  end
@@ -196,5 +196,11 @@ module Spec
196
196
  self
197
197
  end
198
198
  end
199
+
200
+ class NegativeMessageExpectation < MessageExpectation
201
+ def initialize(mock_name, expectation_ordering, expected_from, sym, method_block)
202
+ super mock_name, expectation_ordering, expected_from, sym, method_block, 0
203
+ end
204
+ end
199
205
  end
200
206
  end
@@ -1,11 +1,6 @@
1
1
  module Spec
2
- module Api
3
- class Mock
4
- # Remove all methods so they can be mocked too
5
- (public_instance_methods - ['__id__', '__send__', 'nil?']).each do |m|
6
- undef_method m
7
- end
8
-
2
+ module Mocks
3
+ module MockInstanceMethods
9
4
  # Creates a new mock with a +name+ (that will be used in error messages only)
10
5
  # Options:
11
6
  # * <tt>:null_object</tt> - if true, the mock object acts as a forgiving null object allowing any message to be sent to it.
@@ -15,17 +10,15 @@ module Spec
15
10
  @expectations = []
16
11
  @expectation_ordering = OrderGroup.new
17
12
  end
18
-
13
+
19
14
  def should_receive(sym, &block)
20
- expected_from = caller(1)[0]
21
- expectation = MessageExpectation.new(@name, @expectation_ordering, expected_from, sym, block_given? ? block : nil)
22
- @expectations << expectation
23
- expectation
15
+ add MessageExpectation, caller(1)[0], sym, &block
24
16
  end
25
17
 
26
18
  def should_not_receive(sym, &block)
19
+ add NegativeMessageExpectation, caller(1)[0], sym, &block
27
20
  end
28
-
21
+
29
22
  def __verify #:nodoc:
30
23
  @expectations.each do |expectation|
31
24
  expectation.verify_messages_received
@@ -33,30 +26,55 @@ module Spec
33
26
  end
34
27
 
35
28
  def method_missing(sym, *args, &block)
36
- if expectation = find_matching_expectation(sym, *args)
37
- expectation.invoke(args, block)
38
- else
39
- begin
40
- # act as null object if method is missing and we ignore them. return value too!
41
- @options[:null_object] ? self : super(sym, *args, &block)
42
- rescue NoMethodError
43
- arg_message = args.collect{|arg| "<#{arg}:#{arg.class.name}>"}.join(", ")
44
- Kernel::raise Spec::Api::MockExpectationError, "Mock '#{@name}' received unexpected message '#{sym}' with [#{arg_message}]"
45
- end
29
+ begin
30
+ return self if @options[:null_object]
31
+ super(sym, *args, &block)
32
+ rescue NoMethodError
33
+ arg_message = args.collect{|arg| "<#{arg}:#{arg.class.name}>"}.join(", ")
34
+ Kernel::raise Spec::Mocks::MockExpectationError, "Mock '#{@name}' received unexpected message '#{sym}' with [#{arg_message}]"
46
35
  end
47
36
  end
48
-
37
+
49
38
  private
50
39
 
51
40
  DEFAULT_OPTIONS = {
52
41
  :null_object => false
53
42
  }
43
+
44
+ def add(expectation_class, expected_from, sym, &block)
45
+ define_expected_method(sym)
46
+ expectation = expectation_class.send(:new, @name, @expectation_ordering, expected_from, sym, block_given? ? block : nil)
47
+ @expectations << expectation
48
+ expectation
49
+ end
50
+
51
+ def metaclass
52
+ class << self; self; end
53
+ end
54
+
55
+ def define_expected_method(sym)
56
+ metaclass.__send__ :class_eval, %{
57
+ def #{sym}(*args, &block)
58
+ message_received :#{sym}, *args, &block # ?
59
+ end
60
+ }
61
+ end
62
+
63
+ def message_received(sym, *args, &block)
64
+ if expectation = find_matching_expectation(sym, *args)
65
+ expectation.invoke(args, block)
66
+ else
67
+ method_missing(sym, *args, &block)
68
+ end
69
+ end
54
70
 
55
71
  def find_matching_expectation(sym, *args)
56
72
  expectation = @expectations.find {|expectation| expectation.matches(sym, args)}
57
73
  end
58
-
59
74
  end
60
-
75
+
76
+ class Mock
77
+ include MockInstanceMethods
78
+ end
61
79
  end
62
80
  end
@@ -1,5 +1,5 @@
1
1
  module Spec
2
- module Api
2
+ module Mocks
3
3
  class OrderGroup
4
4
  def initialize
5
5
  @ordering = Array.new
@@ -25,8 +25,11 @@ module Spec
25
25
  error.backtrace.collect! do |line|
26
26
  line = tweak_instance_exec_line line, spec_name
27
27
  line = nil if line =~ /\/lib\/ruby\//
28
- line = nil if line =~ /\/lib\/spec\/api\//
28
+ line = nil if line =~ /\/lib\/spec\/expectations\//
29
+ line = nil if line =~ /\/lib\/spec\/mocks\//
30
+ line = nil if line =~ /\/lib\/spec\/rake\//
29
31
  line = nil if line =~ /\/lib\/spec\/runner\//
32
+ line = nil if line =~ /\/lib\/spec\/stubs\//
30
33
  line = nil if line =~ /bin\/spec:/
31
34
  line = nil if line =~ /lib\/rspec_on_rails/
32
35
  line = nil if line =~ /script\/rails_spec/
@@ -5,19 +5,28 @@ module Spec
5
5
  def initialize(spec)
6
6
  @spec = spec
7
7
  end
8
-
8
+
9
9
  def mock(name, options={})
10
- mock = Api::Mock.new(name, options)
10
+ mock = Spec::Mocks::Mock.new(name, options)
11
11
  @spec.add_mock(mock)
12
12
  mock
13
13
  end
14
14
 
15
+ def stub(object, name="")
16
+ stub_space.create_stub(object, name)
17
+ end
18
+
15
19
  def duck_type(*args)
16
- return Api::DuckTypeArgConstraint.new(*args)
20
+ return Spec::Mocks::DuckTypeArgConstraint.new(*args)
17
21
  end
18
22
 
19
23
  def violated(message="")
20
- raise Spec::Api::ExpectationNotMetError.new(message)
24
+ raise Spec::Expectations::ExpectationNotMetError.new(message)
25
+ end
26
+
27
+ private
28
+ def stub_space
29
+ @spec.stub_space
21
30
  end
22
31
  end
23
32
  include InstanceMethods
@@ -5,10 +5,16 @@ module Spec
5
5
  # non-text based ones too - just ignore the +output+ constructor
6
6
  # argument.
7
7
  class BaseTextFormatter
8
- def initialize(output, dry_run=false)
9
- @dry_run = dry_run
8
+ def initialize(output, dry_run=false, colour=false)
10
9
  @output = output
11
- end
10
+ @dry_run = dry_run
11
+ @colour = colour
12
+ begin
13
+ require 'Win32/Console/ANSI' if @colour && PLATFORM =~ /win32/
14
+ rescue LoadError
15
+ raise "You must gem install win32console to use --color on Windows"
16
+ end
17
+ end
12
18
 
13
19
  # This method is invoked before any specs are run, right after
14
20
  # they have all been collected. This can be useful for special
@@ -55,22 +61,29 @@ module Spec
55
61
  # of the associated spec. +failure+ is a Failure object, which contains detailed
56
62
  # information about the failure.
57
63
  def dump_failure(counter, failure)
58
- @output << "\n"
59
- @output << counter.to_s << ")\n"
60
- @output << "#{failure.header}\n"
61
- @output << "#{failure.message}\n"
62
- @output << "#{failure.backtrace}\n"
64
+ @output.puts
65
+ @output.puts "#{counter.to_s})"
66
+ @output.puts failure.header
67
+ @output.puts failure.message
68
+ @output.puts failure.backtrace
63
69
  @output.flush
64
70
  end
65
71
 
66
72
  # This method is invoked at the very end.
67
73
  def dump_summary(duration, spec_count, failure_count)
68
74
  return if @dry_run
69
- @output << "\n"
70
- @output << "Finished in " << (duration).to_s << " seconds\n\n"
71
- @output << "#{spec_count} specification#{'s' unless spec_count == 1}, "
72
- @output << "#{failure_count} failure#{'s' unless failure_count == 1}"
73
- @output << "\n"
75
+ if @colour && @output == STDOUT
76
+ colour_prefix = (failure_count == 0 ? "\e[32m" : "\e[31m")
77
+ colour_postfix = "\e[0m"
78
+ summary_output = Kernel
79
+ else
80
+ colour_prefix = colour_postfix = ""
81
+ summary_output = @output
82
+ end
83
+ @output.puts
84
+ @output.puts "Finished in #{duration} seconds"
85
+ @output.puts
86
+ summary_output.puts "#{colour_prefix}#{spec_count} specification#{'s' unless spec_count == 1}, #{failure_count} failure#{'s' unless failure_count == 1}#{colour_postfix}"
74
87
  @output.flush
75
88
  end
76
89
  end
@@ -2,7 +2,7 @@ module Spec
2
2
  module Runner
3
3
  module Formatter
4
4
  class HtmlFormatter < BaseTextFormatter
5
- def initialize(output, dry_run=false)
5
+ def initialize(output, dry_run=false, colour=false)
6
6
  super
7
7
  @current_count = 0
8
8
  end
@@ -8,7 +8,7 @@ module Spec
8
8
  def self.create_context_runner(args, standalone, err, out=STDOUT)
9
9
  options = parse(args, standalone, err, out)
10
10
 
11
- formatter = options.formatter_type.new(options.out, options.dry_run)
11
+ formatter = options.formatter_type.new(options.out, options.dry_run, options.colour)
12
12
  reporter = Reporter.new(formatter, options.backtrace_tweaker)
13
13
  ContextRunner.new(reporter, standalone, options.dry_run, options.spec_name)
14
14
  end
@@ -25,7 +25,11 @@ module Spec
25
25
  opts.separator ""
26
26
 
27
27
  opts.on("--diff", "Show unified diff of Strings that are expected to be equal when they are not") do
28
- require 'spec/api/helper/diff'
28
+ require 'spec/expectations/diff'
29
+ end
30
+
31
+ opts.on("-c", "--colour", "--color", "Show coloured (red/green) output") do
32
+ options.colour = true
29
33
  end
30
34
 
31
35
  opts.on("-s", "--spec SPECIFICATION_NAME", "Execute a single specification") do |spec_name|