rspec 1.0.5 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/CHANGES +78 -1
  2. data/EXAMPLES.rd +8 -5
  3. data/README +1 -0
  4. data/Rakefile +1 -1
  5. data/examples/pending_example.rb +20 -0
  6. data/lib/autotest/rspec.rb +46 -18
  7. data/lib/spec/dsl.rb +1 -0
  8. data/lib/spec/dsl/behaviour.rb +37 -27
  9. data/lib/spec/dsl/behaviour_callbacks.rb +4 -0
  10. data/lib/spec/dsl/behaviour_eval.rb +27 -16
  11. data/lib/spec/dsl/behaviour_factory.rb +2 -2
  12. data/lib/spec/dsl/composite_proc_builder.rb +9 -4
  13. data/lib/spec/dsl/configuration.rb +20 -4
  14. data/lib/spec/dsl/description.rb +7 -0
  15. data/lib/spec/dsl/errors.rb +9 -0
  16. data/lib/spec/dsl/example.rb +18 -10
  17. data/lib/spec/matchers/have.rb +10 -13
  18. data/lib/spec/matchers/operator_matcher.rb +3 -3
  19. data/lib/spec/matchers/raise_error.rb +8 -3
  20. data/lib/spec/mocks/error_generator.rb +1 -1
  21. data/lib/spec/mocks/message_expectation.rb +11 -0
  22. data/lib/spec/mocks/methods.rb +9 -5
  23. data/lib/spec/mocks/proxy.rb +13 -9
  24. data/lib/spec/rake/spectask.rb +80 -38
  25. data/lib/spec/runner/backtrace_tweaker.rb +2 -1
  26. data/lib/spec/runner/behaviour_runner.rb +37 -16
  27. data/lib/spec/runner/formatter/base_formatter.rb +23 -15
  28. data/lib/spec/runner/formatter/base_text_formatter.rb +39 -11
  29. data/lib/spec/runner/formatter/failing_behaviours_formatter.rb +7 -3
  30. data/lib/spec/runner/formatter/failing_examples_formatter.rb +3 -3
  31. data/lib/spec/runner/formatter/html_formatter.rb +32 -25
  32. data/lib/spec/runner/formatter/progress_bar_formatter.rb +6 -5
  33. data/lib/spec/runner/formatter/rdoc_formatter.rb +6 -6
  34. data/lib/spec/runner/formatter/specdoc_formatter.rb +7 -6
  35. data/lib/spec/runner/option_parser.rb +6 -5
  36. data/lib/spec/runner/options.rb +60 -43
  37. data/lib/spec/runner/reporter.rb +17 -6
  38. data/lib/spec/runner/spec_parser.rb +1 -1
  39. data/lib/spec/translator.rb +8 -0
  40. data/lib/spec/version.rb +3 -3
  41. data/plugins/mock_frameworks/flexmock.rb +14 -18
  42. data/plugins/mock_frameworks/mocha.rb +0 -2
  43. data/plugins/mock_frameworks/rr.rb +21 -0
  44. data/spec/autotest/discover_spec.rb +19 -0
  45. data/spec/autotest/rspec_spec.rb +257 -0
  46. data/spec/autotest_helper.rb +4 -0
  47. data/spec/spec/dsl/behaviour_eval_spec.rb +30 -0
  48. data/spec/spec/dsl/behaviour_factory_spec.rb +18 -0
  49. data/spec/spec/dsl/behaviour_spec.rb +95 -58
  50. data/spec/spec/dsl/composite_proc_builder_spec.rb +0 -13
  51. data/spec/spec/dsl/configuration_spec.rb +6 -1
  52. data/spec/spec/dsl/description_spec.rb +9 -1
  53. data/spec/spec/dsl/example_class_spec.rb +3 -3
  54. data/spec/spec/dsl/example_instance_spec.rb +26 -28
  55. data/spec/spec/dsl/example_matcher_spec.rb +91 -0
  56. data/spec/spec/dsl/shared_behaviour_spec.rb +24 -0
  57. data/spec/spec/expectations/extensions/object_spec.rb +2 -2
  58. data/spec/spec/expectations/fail_with_spec.rb +2 -2
  59. data/spec/spec/matchers/have_spec.rb +1 -1
  60. data/spec/spec/matchers/operator_matcher_spec.rb +10 -10
  61. data/spec/spec/matchers/raise_error_spec.rb +38 -0
  62. data/spec/spec/mocks/argument_expectation_spec.rb +18 -14
  63. data/spec/spec/mocks/at_most_spec.rb +1 -1
  64. data/spec/spec/mocks/bug_report_11545_spec.rb +31 -0
  65. data/spec/spec/mocks/partial_mock_spec.rb +33 -1
  66. data/spec/spec/runner/behaviour_runner_spec.rb +72 -49
  67. data/spec/spec/runner/command_line_spec.rb +1 -1
  68. data/spec/spec/runner/context_matching_spec.rb +10 -10
  69. data/spec/spec/runner/drb_command_line_spec.rb +62 -59
  70. data/spec/spec/runner/extensions/bug_report_10577_spec.rb +35 -0
  71. data/spec/spec/runner/formatter/failing_behaviours_formatter_spec.rb +15 -2
  72. data/spec/spec/runner/formatter/failing_examples_formatter_spec.rb +3 -3
  73. data/spec/spec/runner/formatter/html_formatter_spec.rb +1 -1
  74. data/spec/spec/runner/formatter/progress_bar_formatter_dry_run_spec.rb +14 -15
  75. data/spec/spec/runner/formatter/progress_bar_formatter_failure_dump_spec.rb +1 -1
  76. data/spec/spec/runner/formatter/progress_bar_formatter_spec.rb +42 -9
  77. data/spec/spec/runner/formatter/rdoc_formatter_spec.rb +40 -40
  78. data/spec/spec/runner/formatter/specdoc_formatter_spec.rb +55 -49
  79. data/spec/spec/runner/option_parser_spec.rb +16 -15
  80. data/spec/spec/runner/options_spec.rb +64 -31
  81. data/spec/spec/runner/reporter_spec.rb +67 -15
  82. data/spec/spec/spec_classes.rb +9 -1
  83. data/spec/spec/translator_spec.rb +48 -0
  84. data/spec/spec_helper.rb +5 -2
  85. metadata +13 -6
  86. data/examples/not_yet_implemented_spec.rb +0 -12
  87. data/spec/spec/runner/example_matcher_spec.rb +0 -127
@@ -28,8 +28,8 @@ module Spec
28
28
  behaviour_type = :default
29
29
  elsif opts[:behaviour_type]
30
30
  behaviour_type = opts[:behaviour_type]
31
- elsif opts[:spec_path] =~ /spec\/(#{BEHAVIOUR_CLASSES.keys.join('|')})/
32
- behaviour_type = $1.to_sym
31
+ elsif opts[:spec_path] =~ /spec(\\|\/)(#{BEHAVIOUR_CLASSES.keys.join('|')})/
32
+ behaviour_type = $2.to_sym
33
33
  else
34
34
  behaviour_type = :default
35
35
  end
@@ -7,8 +7,9 @@ module Spec
7
7
 
8
8
  def proc(&error_handler)
9
9
  parts = self
10
+ errors = []
10
11
  Proc.new do
11
- parts.collect do |part|
12
+ result = parts.collect do |part|
12
13
  begin
13
14
  if part.is_a?(UnboundMethod)
14
15
  part.bind(self).call
@@ -16,11 +17,15 @@ module Spec
16
17
  instance_eval(&part)
17
18
  end
18
19
  rescue Exception => e
19
- raise e unless error_handler
20
- error_handler.call(e)
21
- e
20
+ if error_handler
21
+ error_handler.call(e)
22
+ else
23
+ errors << e
24
+ end
22
25
  end
23
26
  end
27
+ raise errors.first unless errors.empty?
28
+ result
24
29
  end
25
30
  end
26
31
  end
@@ -5,7 +5,7 @@ module Spec
5
5
  # Chooses what mock framework to use. Example:
6
6
  #
7
7
  # Spec::Runner.configure do |config|
8
- # config.mock_with :rspec # or :mocha, or :flexmock
8
+ # config.mock_with :rspec, :mocha, :flexmock, or :rr
9
9
  # end
10
10
  #
11
11
  # To use any other mock framework, you'll have to provide
@@ -56,11 +56,27 @@ module Spec
56
56
  # end
57
57
  #
58
58
  def include(*args)
59
- included_modules.push(*args)
59
+ args << {} unless Hash === args.last
60
+ modules, options = args_and_options(*args)
61
+ required_behaviour_type = options[:behaviour_type]
62
+ required_behaviour_type = required_behaviour_type.to_sym unless required_behaviour_type.nil?
63
+ @modules ||= {}
64
+ @modules[required_behaviour_type] ||= []
65
+ @modules[required_behaviour_type] += modules
66
+ end
67
+
68
+ def modules_for(required_behaviour_type) #:nodoc:
69
+ @modules ||= {}
70
+ modules = @modules[nil] || [] # general ones
71
+ modules << @modules[required_behaviour_type.to_sym] unless required_behaviour_type.nil?
72
+ modules.uniq.compact
60
73
  end
61
74
 
62
- def included_modules # :nodoc:
63
- @included_modules ||= []
75
+ # This is just for cleanup in RSpec's own examples
76
+ def exclude(*modules) #:nodoc:
77
+ @modules.each do |behaviour_type, mods|
78
+ modules.each{|m| mods.delete(m)}
79
+ end
64
80
  end
65
81
 
66
82
  # Defines global predicate matchers. Example:
@@ -19,6 +19,7 @@ module Spec
19
19
  def initialize(*args)
20
20
  args, @options = args_and_options(*args)
21
21
  init_behaviour_type(@options)
22
+ init_spec_path(@options)
22
23
  init_described_type(args)
23
24
  init_description(*args)
24
25
  end
@@ -52,6 +53,12 @@ module Spec
52
53
  end
53
54
  end
54
55
 
56
+ def init_spec_path(options)
57
+ if options.has_key?(:spec_path)
58
+ options[:spec_path] = File.expand_path(@options[:spec_path])
59
+ end
60
+ end
61
+
55
62
  def init_description(*args)
56
63
  @description = self.class.generate_description(*args)
57
64
  end
@@ -0,0 +1,9 @@
1
+ module Spec
2
+ module DSL
3
+ class ExamplePendingError < StandardError
4
+ end
5
+
6
+ class PendingFixedError < StandardError
7
+ end
8
+ end
9
+ end
@@ -3,6 +3,9 @@ require 'timeout'
3
3
  module Spec
4
4
  module DSL
5
5
  class Example
6
+ # The global sequence number of this example
7
+ attr_accessor :number
8
+
6
9
  def initialize(description, options={}, &example_block)
7
10
  @from = caller(0)[3]
8
11
  @options = options
@@ -13,20 +16,20 @@ module Spec
13
16
 
14
17
  def run(reporter, before_each_block, after_each_block, dry_run, execution_context, timeout=nil)
15
18
  @dry_run = dry_run
16
- reporter.example_started(description)
17
- return reporter.example_finished(description) if dry_run
19
+ reporter.example_started(self)
20
+ return reporter.example_finished(self) if dry_run
18
21
 
19
22
  errors = []
20
23
  location = nil
21
24
  Timeout.timeout(timeout) do
22
- before_each_ok = setup_example(execution_context, errors, &before_each_block)
25
+ before_each_ok = before_example(execution_context, errors, &before_each_block)
23
26
  example_ok = run_example(execution_context, errors) if before_each_ok
24
- after_each_ok = teardown_example(execution_context, errors, &after_each_block)
27
+ after_each_ok = after_example(execution_context, errors, &after_each_block)
25
28
  location = failure_location(before_each_ok, example_ok, after_each_ok)
26
29
  end
27
30
 
28
31
  ExampleShouldRaiseHandler.new(@from, @options).handle(errors)
29
- reporter.example_finished(description, errors.first, location, @example_block.nil?) if reporter
32
+ reporter.example_finished(self, errors.first, location, @example_block.nil?) if reporter
30
33
  end
31
34
 
32
35
  def matches?(matcher, specified_examples)
@@ -34,11 +37,16 @@ module Spec
34
37
  matcher.matches?(specified_examples)
35
38
  end
36
39
 
37
- private
38
40
  def description
39
41
  @description == :__generate_description ? generated_description : @description
40
42
  end
41
43
 
44
+ def to_s
45
+ description
46
+ end
47
+
48
+ private
49
+
42
50
  def generated_description
43
51
  return @generated_description if @generated_description
44
52
  if @dry_run
@@ -52,7 +60,7 @@ module Spec
52
60
  end
53
61
  end
54
62
 
55
- def setup_example(execution_context, errors, &behaviour_before_block)
63
+ def before_example(execution_context, errors, &behaviour_before_block)
56
64
  setup_mocks(execution_context)
57
65
  Spec::Matchers.description_generated(@description_generated_proc)
58
66
 
@@ -62,7 +70,7 @@ module Spec
62
70
 
63
71
  execution_context.instance_eval(&behaviour_before_block) if behaviour_before_block
64
72
  return errors.empty?
65
- rescue => e
73
+ rescue Exception => e
66
74
  @failed = true
67
75
  errors << e
68
76
  return false
@@ -79,7 +87,7 @@ module Spec
79
87
  end
80
88
  end
81
89
 
82
- def teardown_example(execution_context, errors, &behaviour_after_each)
90
+ def after_example(execution_context, errors, &behaviour_after_each)
83
91
  execution_context.instance_eval(&behaviour_after_each) if behaviour_after_each
84
92
 
85
93
  begin
@@ -95,7 +103,7 @@ module Spec
95
103
  execution_context.instance_eval(&after_proc)
96
104
 
97
105
  return errors.empty?
98
- rescue => e
106
+ rescue Exception => e
99
107
  @failed = true
100
108
  errors << e
101
109
  return false
@@ -23,12 +23,12 @@ module Spec
23
23
  end
24
24
 
25
25
  def matches?(collection_owner)
26
- if collection_owner.respond_to?(collection_name)
27
- collection = collection_owner.send(collection_name, *@args, &@block)
26
+ if collection_owner.respond_to?(@collection_name)
27
+ collection = collection_owner.send(@collection_name, *@args, &@block)
28
28
  elsif (collection_owner.respond_to?(:length) || collection_owner.respond_to?(:size))
29
29
  collection = collection_owner
30
30
  else
31
- collection_owner.send(collection_name, *@args, &@block)
31
+ collection_owner.send(@collection_name, *@args, &@block)
32
32
  end
33
33
  @actual = collection.size if collection.respond_to?(:size)
34
34
  @actual = collection.length if collection.respond_to?(:length)
@@ -43,39 +43,36 @@ module Spec
43
43
  end
44
44
 
45
45
  def failure_message
46
- "expected #{relative_expectation} #{collection_name}, got #{@actual}"
46
+ "expected #{relative_expectation} #{@collection_name}, got #{@actual}"
47
47
  end
48
48
 
49
49
  def negative_failure_message
50
50
  if @relativity == :exactly
51
- return "expected target not to have #{@expected} #{collection_name}, got #{@actual}"
51
+ return "expected target not to have #{@expected} #{@collection_name}, got #{@actual}"
52
52
  elsif @relativity == :at_most
53
53
  return <<-EOF
54
54
  Isn't life confusing enough?
55
55
  Instead of having to figure out the meaning of this:
56
- should_not have_at_most(#{@expected}).#{collection_name}
56
+ should_not have_at_most(#{@expected}).#{@collection_name}
57
57
  We recommend that you use this instead:
58
- should have_at_least(#{@expected + 1}).#{collection_name}
58
+ should have_at_least(#{@expected + 1}).#{@collection_name}
59
59
  EOF
60
60
  elsif @relativity == :at_least
61
61
  return <<-EOF
62
62
  Isn't life confusing enough?
63
63
  Instead of having to figure out the meaning of this:
64
- should_not have_at_least(#{@expected}).#{collection_name}
64
+ should_not have_at_least(#{@expected}).#{@collection_name}
65
65
  We recommend that you use this instead:
66
- should have_at_most(#{@expected - 1}).#{collection_name}
66
+ should have_at_most(#{@expected - 1}).#{@collection_name}
67
67
  EOF
68
68
  end
69
69
  end
70
70
 
71
71
  def description
72
- "have #{relative_expectation} #{collection_name}"
72
+ "have #{relative_expectation} #{@collection_name}"
73
73
  end
74
74
 
75
75
  private
76
- def collection_name
77
- @collection_name
78
- end
79
76
 
80
77
  def relative_expectation
81
78
  "#{relativities[@relativity]}#{@expected}"
@@ -52,8 +52,8 @@ module Spec
52
52
  def __delegate_method_missing_to_target(operator, expected)
53
53
  ::Spec::Matchers.generated_description = "should #{operator} #{expected.inspect}"
54
54
  return if @target.send(operator, expected)
55
- return fail_with_message("expected #{expected.inspect}, got #{@target.inspect} (using #{operator})") if ['==','==='].include?(operator)
56
- return fail_with_message("expected #{operator} #{expected.inspect}, got #{@target.inspect}")
55
+ return fail_with_message("expected: #{expected.inspect},\n got: #{@target.inspect} (using #{operator})") if ['==','===', '=~'].include?(operator)
56
+ return fail_with_message("expected: #{operator} #{expected.inspect},\n got: #{operator.gsub(/./, ' ')} #{@target.inspect}")
57
57
  end
58
58
 
59
59
  end
@@ -63,7 +63,7 @@ module Spec
63
63
  def __delegate_method_missing_to_target(operator, expected)
64
64
  ::Spec::Matchers.generated_description = "should not #{operator} #{expected.inspect}"
65
65
  return unless @target.send(operator, expected)
66
- return fail_with_message("expected not #{operator} #{expected.inspect}, got #{@target.inspect}")
66
+ return fail_with_message("expected not: #{operator} #{expected.inspect},\n got: #{operator.gsub(/./, ' ')} #{@target.inspect}")
67
67
  end
68
68
 
69
69
  end
@@ -2,9 +2,14 @@ module Spec
2
2
  module Matchers
3
3
 
4
4
  class RaiseError #:nodoc:
5
- def initialize(exception=Exception, message=nil)
6
- @expected_error = exception
7
- @expected_message = message
5
+ def initialize(error_or_message=Exception, message=nil)
6
+ if String === error_or_message
7
+ @expected_error = Exception
8
+ @expected_message = error_or_message
9
+ else
10
+ @expected_error = error_or_message
11
+ @expected_message = message
12
+ end
8
13
  end
9
14
 
10
15
  def matches?(proc)
@@ -44,7 +44,7 @@ module Spec
44
44
 
45
45
  private
46
46
  def intro
47
- @name ? "Mock '#{@name}'" : @target.to_s
47
+ @name ? "Mock '#{@name}'" : @target.inspect
48
48
  end
49
49
 
50
50
  def __raise(message)
@@ -42,6 +42,17 @@ module Spec
42
42
  @return_block = block_given? ? return_block : lambda { value }
43
43
  end
44
44
 
45
+ # :call-seq:
46
+ # and_raise()
47
+ # and_raise(Exception) #any exception class
48
+ # and_raise(exception) #any exception object
49
+ #
50
+ # == Warning
51
+ #
52
+ # When you pass an exception class, the MessageExpectation will
53
+ # raise an instance of it, creating it with +new+. If the exception
54
+ # class initializer requires any parameters, you must pass in an
55
+ # instance and not the class.
45
56
  def and_raise(exception=Exception)
46
57
  @exception_to_raise = exception
47
58
  end
@@ -2,19 +2,19 @@ module Spec
2
2
  module Mocks
3
3
  module Methods
4
4
  def should_receive(sym, opts={}, &block)
5
- __mock_proxy.add_message_expectation(opts[:expected_from] || caller(1)[0], sym, opts, &block)
5
+ __mock_proxy.add_message_expectation(opts[:expected_from] || caller(1)[0], sym.to_sym, opts, &block)
6
6
  end
7
7
 
8
8
  def should_not_receive(sym, &block)
9
- __mock_proxy.add_negative_message_expectation(caller(1)[0], sym, &block)
9
+ __mock_proxy.add_negative_message_expectation(caller(1)[0], sym.to_sym, &block)
10
10
  end
11
11
 
12
12
  def stub!(sym)
13
- __mock_proxy.add_stub(caller(1)[0], sym)
13
+ __mock_proxy.add_stub(caller(1)[0], sym.to_sym)
14
14
  end
15
15
 
16
16
  def received_message?(sym, *args, &block) #:nodoc:
17
- __mock_proxy.received_message?(sym, *args, &block)
17
+ __mock_proxy.received_message?(sym.to_sym, *args, &block)
18
18
  end
19
19
 
20
20
  def rspec_verify #:nodoc:
@@ -28,7 +28,11 @@ module Spec
28
28
  private
29
29
 
30
30
  def __mock_proxy
31
- @mock_proxy ||= Proxy.new(self, @name, @options)
31
+ if Mock === self
32
+ @mock_proxy ||= Proxy.new(self, @name, @options)
33
+ else
34
+ @mock_proxy ||= Proxy.new(self, self.class.name)
35
+ end
32
36
  end
33
37
  end
34
38
  end
@@ -22,19 +22,19 @@ module Spec
22
22
  end
23
23
 
24
24
  def add_message_expectation(expected_from, sym, opts={}, &block)
25
- __add expected_from, sym, block
25
+ __add sym, block
26
26
  @expectations << MessageExpectation.new(@error_generator, @expectation_ordering, expected_from, sym, block_given? ? block : nil, 1, opts)
27
27
  @expectations.last
28
28
  end
29
29
 
30
30
  def add_negative_message_expectation(expected_from, sym, &block)
31
- __add expected_from, sym, block
31
+ __add sym, block
32
32
  @expectations << NegativeMessageExpectation.new(@error_generator, @expectation_ordering, expected_from, sym, block_given? ? block : nil)
33
33
  @expectations.last
34
34
  end
35
35
 
36
36
  def add_stub(expected_from, sym)
37
- __add expected_from, sym, nil
37
+ __add sym, nil
38
38
  @stubs.unshift MethodStub.new(@error_generator, @expectation_ordering, expected_from, sym, nil)
39
39
  @stubs.first
40
40
  end
@@ -85,17 +85,17 @@ module Spec
85
85
 
86
86
  private
87
87
 
88
- def __add(expected_from, sym, block)
89
- $rspec_mocks.add(@target)
88
+ def __add(sym, block)
89
+ $rspec_mocks.add(@target) unless $rspec_mocks.nil?
90
90
  define_expected_method(sym)
91
91
  end
92
92
 
93
93
  def define_expected_method(sym)
94
94
  if target_responds_to?(sym) && !@proxied_methods.include?(sym)
95
+ metaclass.__send__(:alias_method, munge(sym), sym) if metaclass.instance_methods.include?(sym.to_s)
95
96
  @proxied_methods << sym
96
- metaclass.__send__(:alias_method, munge(sym), sym)
97
97
  end
98
-
98
+
99
99
  metaclass_eval(<<-EOF, __FILE__, __LINE__)
100
100
  def #{sym}(*args, &block)
101
101
  __mock_proxy.message_received :#{sym}, *args, &block
@@ -141,8 +141,12 @@ module Spec
141
141
 
142
142
  def reset_proxied_methods
143
143
  @proxied_methods.each do |sym|
144
- metaclass.__send__(:alias_method, sym, munge(sym))
145
- metaclass.__send__(:undef_method, munge(sym))
144
+ if metaclass.instance_methods.include?(munge(sym).to_s)
145
+ metaclass.__send__(:alias_method, sym, munge(sym))
146
+ metaclass.__send__(:undef_method, munge(sym))
147
+ else
148
+ metaclass.__send__(:undef_method, sym)
149
+ end
146
150
  end
147
151
  end
148
152
 
@@ -21,7 +21,38 @@ module Spec
21
21
  #
22
22
  # rake spec
23
23
  #
24
+ # If rake is invoked with a "SPEC=filename" command line option,
25
+ # then the list of spec files will be overridden to include only the
26
+ # filename specified on the command line. This provides an easy way
27
+ # to run just one spec.
28
+ #
29
+ # If rake is invoked with a "SPEC_OPTS=options" command line option,
30
+ # then the given options will override the value of the +spec_opts+
31
+ # attribute.
32
+ #
33
+ # If rake is invoked with a "RCOV_OPTS=options" command line option,
34
+ # then the given options will override the value of the +rcov_opts+
35
+ # attribute.
36
+ #
37
+ # Examples:
38
+ #
39
+ # rake spec # run specs normally
40
+ # rake spec SPEC=just_one_file.rb # run just one spec file.
41
+ # rake spec SPEC_OPTS="--diff" # enable diffing
42
+ # rake spec RCOV_OPTS="--aggregate myfile.txt" # see rcov --help for details
43
+ #
44
+ # Each attribute of this task may be a proc. This allows for lazy evaluation,
45
+ # which is sometimes handy if you want to defer the evaluation of an attribute value
46
+ # until the task is run (as opposed to when it is defined).
24
47
  class SpecTask < ::Rake::TaskLib
48
+ class << self
49
+ def attr_accessor(*names)
50
+ super(*names)
51
+ names.each do |name|
52
+ module_eval "def #{name}() evaluate(@#{name}) end" # Allows use of procs
53
+ end
54
+ end
55
+ end
25
56
 
26
57
  # Name of spec task. (default is :spec)
27
58
  attr_accessor :name
@@ -35,21 +66,20 @@ module Spec
35
66
  attr_accessor :warning
36
67
 
37
68
  # Glob pattern to match spec files. (default is 'spec/**/*_spec.rb')
69
+ # Setting the SPEC environment variable overrides this.
38
70
  attr_accessor :pattern
39
71
 
40
72
  # Array of commandline options to pass to RSpec. Defaults to [].
73
+ # Setting the SPEC_OPTS environment variable overrides this.
41
74
  attr_accessor :spec_opts
42
75
 
43
- # Where RSpec's output is written. Defaults to STDOUT.
44
- # DEPRECATED. Use --format FORMAT:WHERE in spec_opts.
45
- attr_accessor :out
46
-
47
76
  # Whether or not to use RCov (default is false)
48
77
  # See http://eigenclass.org/hiki.rb?rcov
49
78
  attr_accessor :rcov
50
79
 
51
80
  # Array of commandline options to pass to RCov. Defaults to ['--exclude', 'lib\/spec,bin\/spec'].
52
81
  # Ignored if rcov=false
82
+ # Setting the RCOV_OPTS environment variable overrides this.
53
83
  attr_accessor :rcov_opts
54
84
 
55
85
  # Directory where the RCov report is written. Defaults to "coverage"
@@ -63,18 +93,21 @@ module Spec
63
93
  # Defaults to true.
64
94
  attr_accessor :fail_on_error
65
95
 
66
- # A message to print to stdout when there are failures.
96
+ # A message to print to stderr when there are failures.
67
97
  attr_accessor :failure_message
68
98
 
99
+ # Where RSpec's output is written. Defaults to STDOUT.
100
+ # DEPRECATED. Use --format FORMAT:WHERE in spec_opts.
101
+ attr_accessor :out
102
+
69
103
  # Explicitly define the list of spec files to be included in a
70
- # spec. +list+ is expected to be an array of file names (a
104
+ # spec. +spec_files+ is expected to be an array of file names (a
71
105
  # FileList is acceptable). If both +pattern+ and +spec_files+ are
72
106
  # used, then the list of spec files is the union of the two.
73
- def spec_files=(list)
74
- @spec_files = list
75
- end
107
+ # Setting the SPEC environment variable overrides this.
108
+ attr_accessor :spec_files
76
109
 
77
- # Create a specing task.
110
+ # Defines a new task, using the name +name+.
78
111
  def initialize(name=:spec)
79
112
  @name = name
80
113
  @libs = [File.expand_path(File.dirname(__FILE__) + '/../../../lib')]
@@ -83,62 +116,63 @@ module Spec
83
116
  @spec_opts = []
84
117
  @warning = false
85
118
  @ruby_opts = []
86
- @out = nil
87
119
  @fail_on_error = true
88
120
  @rcov = false
89
121
  @rcov_opts = ['--exclude', 'lib\/spec,bin\/spec,config\/boot.rb']
90
122
  @rcov_dir = "coverage"
91
123
 
92
124
  yield self if block_given?
93
- @pattern = 'spec/**/*_spec.rb' if @pattern.nil? && @spec_files.nil?
125
+ @pattern = 'spec/**/*_spec.rb' if pattern.nil? && spec_files.nil?
94
126
  define
95
127
  end
96
128
 
97
- def define
129
+ def define # :nodoc:
98
130
  spec_script = File.expand_path(File.dirname(__FILE__) + '/../../../bin/spec')
99
131
 
100
- lib_path = @libs.join(File::PATH_SEPARATOR)
132
+ lib_path = libs.join(File::PATH_SEPARATOR)
101
133
  actual_name = Hash === name ? name.keys.first : name
102
134
  unless ::Rake.application.last_comment
103
- desc "Run RSpec for #{actual_name}" + (@rcov ? " using RCov" : "")
135
+ desc "Run specs" + (rcov ? " using RCov" : "")
104
136
  end
105
- task @name do
106
- RakeFileUtils.verbose(@verbose) do
137
+ task name do
138
+ RakeFileUtils.verbose(verbose) do
107
139
  unless spec_file_list.empty?
108
- # ruby [ruby_opts] -Ilib -S rcov [rcov_opts] bin/spec -- [spec_opts] examples
140
+ # ruby [ruby_opts] -Ilib -S rcov [rcov_opts] bin/spec -- examples [spec_opts]
109
141
  # or
110
- # ruby [ruby_opts] -Ilib bin/spec [spec_opts] examples
142
+ # ruby [ruby_opts] -Ilib bin/spec examples [spec_opts]
111
143
  cmd = "ruby "
112
144
 
113
- ruby_opts = @ruby_opts.clone
114
- ruby_opts << "-I\"#{lib_path}\""
115
- ruby_opts << "-S rcov" if @rcov
116
- ruby_opts << "-w" if @warning
117
- cmd << ruby_opts.join(" ")
145
+ rb_opts = ruby_opts.clone
146
+ rb_opts << "-I\"#{lib_path}\""
147
+ rb_opts << "-S rcov" if rcov
148
+ rb_opts << "-w" if warning
149
+ cmd << rb_opts.join(" ")
118
150
  cmd << " "
119
151
  cmd << rcov_option_list
120
- cmd << %[ -o "#{@rcov_dir}" ] if @rcov
152
+ cmd << %[ -o "#{rcov_dir}" ] if rcov
121
153
  cmd << %Q|"#{spec_script}"|
122
154
  cmd << " "
123
- cmd << "-- " if @rcov
155
+ cmd << "-- " if rcov
124
156
  cmd << spec_file_list.collect { |fn| %["#{fn}"] }.join(' ')
125
157
  cmd << " "
126
158
  cmd << spec_option_list
127
- cmd << " "
128
- cmd << %Q| > "#{@out}"| if @out
129
-
159
+ if out
160
+ cmd << " "
161
+ cmd << %Q| > "#{out}"|
162
+ STDERR.puts "The Spec::Rake::SpecTask#out attribute is DEPRECATED and will be removed in a future version. Use --format FORMAT:WHERE instead."
163
+ end
130
164
  unless system(cmd)
131
- puts @failure_message if @failure_message
132
- raise("Command #{cmd} failed") if @fail_on_error
165
+ STDERR.puts failure_message if failure_message
166
+ raise("Command #{cmd} failed") if fail_on_error
133
167
  end
134
168
  end
135
169
  end
136
170
  end
137
171
 
138
- if @rcov
172
+ if rcov
139
173
  desc "Remove rcov products for #{actual_name}"
140
174
  task paste("clobber_", actual_name) do
141
- rm_r @rcov_dir rescue nil
175
+ rm_r rcov_dir rescue nil
142
176
  end
143
177
 
144
178
  clobber_task = paste("clobber_", actual_name)
@@ -150,12 +184,20 @@ module Spec
150
184
  end
151
185
 
152
186
  def rcov_option_list # :nodoc:
153
- return "" unless @rcov
154
- ENV['RCOVOPTS'] || @rcov_opts.join(" ") || ""
187
+ return "" unless rcov
188
+ ENV['RCOV_OPTS'] || rcov_opts.join(" ") || ""
155
189
  end
156
190
 
157
191
  def spec_option_list # :nodoc:
158
- ENV['RSPECOPTS'] || @spec_opts.join(" ") || ""
192
+ STDERR.puts "RSPECOPTS is DEPRECATED and will be removed in a future version. Use SPEC_OPTS instead." if ENV['RSPECOPTS']
193
+ ENV['SPEC_OPTS'] || ENV['RSPECOPTS'] || spec_opts.join(" ") || ""
194
+ end
195
+
196
+ def evaluate(o) # :nodoc:
197
+ case o
198
+ when Proc then o.call
199
+ else o
200
+ end
159
201
  end
160
202
 
161
203
  def spec_file_list # :nodoc:
@@ -163,8 +205,8 @@ module Spec
163
205
  FileList[ ENV['SPEC'] ]
164
206
  else
165
207
  result = []
166
- result += @spec_files.to_a if @spec_files
167
- result += FileList[ @pattern ].to_a if @pattern
208
+ result += spec_files.to_a if spec_files
209
+ result += FileList[ pattern ].to_a if pattern
168
210
  FileList[result]
169
211
  end
170
212
  end