rspec 1.0.5 → 1.0.6

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 (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