rspec-core 2.11.1 → 2.12.0
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.
- data/Changelog.md +59 -0
- data/README.md +22 -0
- data/features/command_line/example_name_option.feature +5 -5
- data/features/command_line/exit_status.feature +6 -6
- data/features/command_line/format_option.feature +2 -2
- data/features/command_line/line_number_appended_to_path.feature +2 -2
- data/features/command_line/line_number_option.feature +2 -2
- data/features/command_line/pattern_option.feature +2 -2
- data/features/command_line/rake_task.feature +62 -8
- data/features/command_line/ruby.feature +1 -1
- data/features/command_line/tag.feature +1 -1
- data/features/configuration/alias_example_to.feature +2 -2
- data/features/configuration/custom_settings.feature +3 -3
- data/features/configuration/default_path.feature +3 -3
- data/features/configuration/fail_fast.feature +5 -5
- data/features/configuration/read_options_from_file.feature +4 -4
- data/features/example_groups/basic_structure.feature +2 -2
- data/features/example_groups/shared_context.feature +3 -3
- data/features/example_groups/shared_examples.feature +25 -7
- data/features/expectation_framework_integration/configure_expectation_framework.feature +6 -6
- data/features/filtering/exclusion_filters.feature +5 -5
- data/features/filtering/if_and_unless.feature +5 -5
- data/features/filtering/inclusion_filters.feature +5 -5
- data/features/filtering/run_all_when_everything_filtered.feature +3 -3
- data/features/formatters/custom_formatter.feature +2 -2
- data/features/formatters/json_formatter.feature +30 -0
- data/features/formatters/text_formatter.feature +5 -5
- data/features/helper_methods/arbitrary_methods.feature +2 -2
- data/features/helper_methods/let.feature +2 -2
- data/features/helper_methods/modules.feature +6 -6
- data/features/hooks/around_hooks.feature +11 -11
- data/features/hooks/before_and_after_hooks.feature +15 -11
- data/features/hooks/filtering.feature +6 -6
- data/features/metadata/current_example.feature +1 -1
- data/features/metadata/described_class.feature +1 -1
- data/features/metadata/user_defined.feature +4 -4
- data/features/mock_framework_integration/use_any_framework.feature +6 -6
- data/features/mock_framework_integration/use_flexmock.feature +5 -5
- data/features/mock_framework_integration/use_mocha.feature +5 -5
- data/features/mock_framework_integration/use_rr.feature +5 -5
- data/features/mock_framework_integration/use_rspec.feature +5 -5
- data/features/pending/pending_examples.feature +11 -11
- data/features/spec_files/arbitrary_file_suffix.feature +1 -1
- data/features/step_definitions/additional_cli_steps.rb +2 -0
- data/features/subject/attribute_of_subject.feature +5 -5
- data/features/subject/explicit_subject.feature +5 -5
- data/features/subject/implicit_receiver.feature +2 -2
- data/features/subject/implicit_subject.feature +3 -3
- data/lib/autotest/rspec2.rb +1 -1
- data/lib/rspec/core.rb +53 -32
- data/lib/rspec/core/configuration.rb +123 -15
- data/lib/rspec/core/configuration_options.rb +17 -2
- data/lib/rspec/core/example.rb +5 -4
- data/lib/rspec/core/example_group.rb +19 -9
- data/lib/rspec/core/extensions/ordered.rb +12 -6
- data/lib/rspec/core/formatters.rb +55 -0
- data/lib/rspec/core/formatters/base_formatter.rb +43 -38
- data/lib/rspec/core/formatters/base_text_formatter.rb +9 -5
- data/lib/rspec/core/formatters/documentation_formatter.rb +1 -1
- data/lib/rspec/core/formatters/helpers.rb +30 -5
- data/lib/rspec/core/formatters/html_formatter.rb +58 -368
- data/lib/rspec/core/formatters/html_printer.rb +407 -0
- data/lib/rspec/core/formatters/json_formatter.rb +73 -0
- data/lib/rspec/core/formatters/snippet_extractor.rb +3 -1
- data/lib/rspec/core/hooks.rb +4 -4
- data/lib/rspec/core/metadata.rb +14 -6
- data/lib/rspec/core/mocking/with_mocha.rb +25 -2
- data/lib/rspec/core/mocking/with_rspec.rb +6 -2
- data/lib/rspec/core/option_parser.rb +28 -7
- data/lib/rspec/core/project_initializer.rb +0 -1
- data/lib/rspec/core/rake_task.rb +49 -38
- data/lib/rspec/core/reporter.rb +2 -2
- data/lib/rspec/core/shared_example_group.rb +89 -41
- data/lib/rspec/core/subject.rb +6 -2
- data/lib/rspec/core/version.rb +1 -1
- data/lib/rspec/core/world.rb +2 -2
- data/spec/autotest/rspec_spec.rb +6 -1
- data/spec/command_line/order_spec.rb +67 -0
- data/spec/rspec/core/configuration_options_spec.rb +45 -38
- data/spec/rspec/core/configuration_spec.rb +219 -44
- data/spec/rspec/core/deprecations_spec.rb +9 -0
- data/spec/rspec/core/drb_command_line_spec.rb +1 -7
- data/spec/rspec/core/drb_options_spec.rb +1 -1
- data/spec/rspec/core/dsl_spec.rb +17 -9
- data/spec/rspec/core/example_group_spec.rb +51 -5
- data/spec/rspec/core/example_spec.rb +39 -7
- data/spec/rspec/core/filter_manager_spec.rb +20 -30
- data/spec/rspec/core/formatters/base_formatter_spec.rb +29 -1
- data/spec/rspec/core/formatters/base_text_formatter_spec.rb +6 -2
- data/spec/rspec/core/formatters/helpers_spec.rb +12 -0
- data/spec/rspec/core/formatters/html_formatted-1.8.7-rbx.html +462 -0
- data/spec/rspec/core/formatters/html_formatted-1.9.2-jruby.html +410 -0
- data/spec/rspec/core/formatters/html_formatted-1.9.3-rbx.html +462 -0
- data/spec/rspec/core/formatters/html_formatter_spec.rb +11 -3
- data/spec/rspec/core/formatters/json_formatter_spec.rb +110 -0
- data/spec/rspec/core/formatters/snippet_extractor_spec.rb +8 -0
- data/spec/rspec/core/formatters/text_mate_formatted-1.8.7-rbx.html +462 -0
- data/spec/rspec/core/formatters/text_mate_formatted-1.9.2-jruby.html +410 -0
- data/spec/rspec/core/formatters/text_mate_formatted-1.9.3-rbx.html +462 -0
- data/spec/rspec/core/formatters/text_mate_formatter_spec.rb +11 -3
- data/spec/rspec/core/hooks_filtering_spec.rb +6 -6
- data/spec/rspec/core/metadata_spec.rb +29 -0
- data/spec/rspec/core/option_parser_spec.rb +42 -0
- data/spec/rspec/core/project_initializer_spec.rb +2 -2
- data/spec/rspec/core/rake_task_spec.rb +60 -17
- data/spec/rspec/core/reporter_spec.rb +17 -0
- data/spec/rspec/core/runner_spec.rb +1 -0
- data/spec/rspec/core/shared_example_group_spec.rb +17 -5
- data/spec/rspec/core/subject_spec.rb +11 -0
- data/spec/spec_helper.rb +32 -2
- data/spec/support/config_options_helper.rb +1 -10
- data/spec/support/helper_methods.rb +13 -0
- data/spec/support/isolated_directory.rb +10 -0
- data/spec/support/isolated_home_directory.rb +16 -0
- metadata +145 -148
- data/lib/rspec/core/extensions.rb +0 -4
@@ -4,7 +4,7 @@ module RSpec
|
|
4
4
|
# This class extracts code snippets by looking at the backtrace of the passed error
|
5
5
|
class SnippetExtractor
|
6
6
|
class NullConverter; def convert(code, pre); code; end; end
|
7
|
-
|
7
|
+
|
8
8
|
begin
|
9
9
|
require 'syntax/convertors/html'
|
10
10
|
@@converter = Syntax::Convertors::HTML.for_syntax "ruby"
|
@@ -40,6 +40,8 @@ module RSpec
|
|
40
40
|
else
|
41
41
|
"# Couldn't get snippet for #{file}"
|
42
42
|
end
|
43
|
+
rescue SecurityError
|
44
|
+
"# Couldn't get snippet for #{file}"
|
43
45
|
end
|
44
46
|
|
45
47
|
def post_process(highlighted, offending_line)
|
data/lib/rspec/core/hooks.rb
CHANGED
@@ -119,7 +119,7 @@ module RSpec
|
|
119
119
|
private
|
120
120
|
def process host, globals, position, scope
|
121
121
|
globals[position][scope].each do |hook|
|
122
|
-
unless host.
|
122
|
+
unless host.parent_groups.any? { |a| a.hooks[position][scope].include? hook }
|
123
123
|
self[position][scope] << hook if scope == :each || hook.options_apply?(host)
|
124
124
|
end
|
125
125
|
end
|
@@ -426,7 +426,7 @@ module RSpec
|
|
426
426
|
|
427
427
|
# @private
|
428
428
|
def around_each_hooks_for(example, initial_procsy=nil)
|
429
|
-
AroundHookCollection.new(
|
429
|
+
AroundHookCollection.new(parent_groups.map {|a| a.hooks[:around][:each]}.flatten).for(example, initial_procsy)
|
430
430
|
end
|
431
431
|
|
432
432
|
private
|
@@ -448,11 +448,11 @@ module RSpec
|
|
448
448
|
end
|
449
449
|
|
450
450
|
def before_each_hooks_for(example)
|
451
|
-
HookCollection.new(
|
451
|
+
HookCollection.new(parent_groups.reverse.map {|a| a.hooks[:before][:each]}.flatten).for(example)
|
452
452
|
end
|
453
453
|
|
454
454
|
def after_each_hooks_for(example)
|
455
|
-
HookCollection.new(
|
455
|
+
HookCollection.new(parent_groups.map {|a| a.hooks[:after][:each]}.flatten).for(example)
|
456
456
|
end
|
457
457
|
|
458
458
|
def register_hook prepend_or_append, hook, *args, &block
|
data/lib/rspec/core/metadata.rb
CHANGED
@@ -31,6 +31,8 @@ module RSpec
|
|
31
31
|
line = line.sub(/\A([^:]+:\d+)$/, '\\1')
|
32
32
|
return nil if line == '-e:1'
|
33
33
|
line
|
34
|
+
rescue SecurityError
|
35
|
+
nil
|
34
36
|
end
|
35
37
|
|
36
38
|
# @private
|
@@ -41,7 +43,18 @@ module RSpec
|
|
41
43
|
# ExampleMetadataHash and GroupMetadataHash, which get mixed in to
|
42
44
|
# Metadata for ExampleGroups and Examples (respectively).
|
43
45
|
def [](key)
|
44
|
-
|
46
|
+
store_computed(key) unless has_key?(key)
|
47
|
+
super
|
48
|
+
end
|
49
|
+
|
50
|
+
def fetch(key, *args)
|
51
|
+
store_computed(key) unless has_key?(key)
|
52
|
+
super
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def store_computed(key)
|
45
58
|
case key
|
46
59
|
when :location
|
47
60
|
store(:location, location)
|
@@ -49,7 +62,6 @@ module RSpec
|
|
49
62
|
file_path, line_number = file_and_line_number
|
50
63
|
store(:file_path, file_path)
|
51
64
|
store(:line_number, line_number)
|
52
|
-
super
|
53
65
|
when :execution_result
|
54
66
|
store(:execution_result, {})
|
55
67
|
when :describes, :described_class
|
@@ -61,13 +73,9 @@ module RSpec
|
|
61
73
|
store(:full_description, full_description)
|
62
74
|
when :description
|
63
75
|
store(:description, build_description_from(*self[:description_args]))
|
64
|
-
else
|
65
|
-
super
|
66
76
|
end
|
67
77
|
end
|
68
78
|
|
69
|
-
private
|
70
|
-
|
71
79
|
def location
|
72
80
|
"#{self[:file_path]}:#{self[:line_number]}"
|
73
81
|
end
|
@@ -1,5 +1,28 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# In order to support all versions of mocha, we have to jump through some
|
2
|
+
# hoops here.
|
3
|
+
#
|
4
|
+
# mocha >= '0.13.0':
|
5
|
+
# require 'mocha/api' is required
|
6
|
+
# require 'mocha/object' raises a LoadError b/c the file no longer exists
|
7
|
+
# mocha < '0.13.0', >= '0.9.7'
|
8
|
+
# require 'mocha/api' is required
|
9
|
+
# require 'mocha/object' is required
|
10
|
+
# mocha < '0.9.7':
|
11
|
+
# require 'mocha/api' raises a LoadError b/c the file does not yet exist
|
12
|
+
# require 'mocha/standalone' is required
|
13
|
+
# require 'mocha/object' is required
|
14
|
+
begin
|
15
|
+
require 'mocha/api'
|
16
|
+
|
17
|
+
begin
|
18
|
+
require 'mocha/object'
|
19
|
+
rescue LoadError
|
20
|
+
# Mocha >= 0.13.0 no longer contains this file nor needs it to be loaded
|
21
|
+
end
|
22
|
+
rescue LoadError
|
23
|
+
require 'mocha/standalone'
|
24
|
+
require 'mocha/object'
|
25
|
+
end
|
3
26
|
|
4
27
|
module RSpec
|
5
28
|
module Core
|
@@ -3,9 +3,13 @@ require 'rspec/mocks'
|
|
3
3
|
module RSpec
|
4
4
|
module Core
|
5
5
|
module MockFrameworkAdapter
|
6
|
-
|
6
|
+
|
7
7
|
def self.framework_name; :rspec end
|
8
|
-
|
8
|
+
|
9
|
+
def self.configuration
|
10
|
+
RSpec::Mocks.configuration
|
11
|
+
end
|
12
|
+
|
9
13
|
def setup_mocks_for_rspec
|
10
14
|
RSpec::Mocks::setup(self)
|
11
15
|
end
|
@@ -13,15 +13,35 @@ module RSpec::Core
|
|
13
13
|
|
14
14
|
def parse!(args)
|
15
15
|
return {} if args.empty?
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
16
|
+
|
17
|
+
convert_deprecated_args(args)
|
18
|
+
|
20
19
|
options = args.delete('--tty') ? {:tty => true} : {}
|
21
|
-
|
20
|
+
begin
|
21
|
+
parser(options).parse!(args)
|
22
|
+
rescue OptionParser::InvalidOption => e
|
23
|
+
abort "#{e.message}\n\nPlease use --help for a listing of valid options"
|
24
|
+
end
|
25
|
+
|
22
26
|
options
|
23
27
|
end
|
24
28
|
|
29
|
+
def convert_deprecated_args(args)
|
30
|
+
args.map! { |arg|
|
31
|
+
case arg
|
32
|
+
when "--formatter"
|
33
|
+
RSpec.deprecate("the --formatter option", "-f or --format")
|
34
|
+
"--format"
|
35
|
+
when "--default_path"
|
36
|
+
"--default-path"
|
37
|
+
when "--line_number"
|
38
|
+
"--line-number"
|
39
|
+
else
|
40
|
+
arg
|
41
|
+
end
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
25
45
|
alias_method :parse, :parse!
|
26
46
|
|
27
47
|
def parser(options)
|
@@ -92,6 +112,7 @@ module RSpec::Core
|
|
92
112
|
' [d]ocumentation (group and example names)',
|
93
113
|
' [h]tml',
|
94
114
|
' [t]extmate',
|
115
|
+
' [j]son',
|
95
116
|
' custom formatter class name') do |o|
|
96
117
|
options[:formatters] ||= []
|
97
118
|
options[:formatters] << [o]
|
@@ -139,7 +160,7 @@ FILTERING
|
|
139
160
|
(options[:full_description] ||= []) << Regexp.compile(Regexp.escape(o))
|
140
161
|
end
|
141
162
|
|
142
|
-
parser.on('-l', '--
|
163
|
+
parser.on('-l', '--line-number LINE', 'Specify line number of an example or group (may be',
|
143
164
|
' used more than once).') do |o|
|
144
165
|
(options[:line_numbers] ||= []) << o
|
145
166
|
end
|
@@ -158,7 +179,7 @@ FILTERING
|
|
158
179
|
options[filter_type][name] = value.nil? ? true : eval(value) rescue value
|
159
180
|
end
|
160
181
|
|
161
|
-
parser.on('--
|
182
|
+
parser.on('--default-path PATH', 'Set the default path where RSpec looks for examples (can',
|
162
183
|
' be a path to a file or a directory).') do |path|
|
163
184
|
options[:default_path] = path
|
164
185
|
end
|
data/lib/rspec/core/rake_task.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'rspec/core'
|
2
1
|
require 'rspec/core/deprecation'
|
3
2
|
require 'rake'
|
4
3
|
require 'rake/tasklib'
|
@@ -63,6 +62,9 @@ module RSpec
|
|
63
62
|
|
64
63
|
# Use rcov for code coverage?
|
65
64
|
#
|
65
|
+
# Due to the many ways `rcov` can run, if this option is enabled, it is
|
66
|
+
# required that `require 'rspec/autorun'` appears in `spec_helper`.rb
|
67
|
+
#
|
66
68
|
# default:
|
67
69
|
# false
|
68
70
|
attr_accessor :rcov
|
@@ -109,34 +111,47 @@ module RSpec
|
|
109
111
|
@rspec_opts = opts
|
110
112
|
end
|
111
113
|
|
112
|
-
def initialize(*args)
|
114
|
+
def initialize(*args, &task_block)
|
115
|
+
setup_ivars(args)
|
116
|
+
|
117
|
+
desc "Run RSpec code examples" unless ::Rake.application.last_comment
|
118
|
+
|
119
|
+
task name, *args do |_, task_args|
|
120
|
+
RakeFileUtils.send(:verbose, verbose) do
|
121
|
+
task_block.call(*[self, task_args].slice(0, task_block.arity)) if task_block
|
122
|
+
run_task verbose
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def setup_ivars(args)
|
113
128
|
@name = args.shift || :spec
|
114
|
-
@
|
129
|
+
@rcov_opts, @ruby_opts, @rspec_opts = nil, nil, nil
|
115
130
|
@warning, @rcov = false, false
|
116
131
|
@verbose, @fail_on_error = true, true
|
117
132
|
|
118
|
-
|
119
|
-
|
120
|
-
@
|
121
|
-
|
122
|
-
@pattern ||= './spec{,/*/**}/*_spec.rb'
|
133
|
+
@rcov_path = 'rcov'
|
134
|
+
@rspec_path = 'rspec'
|
135
|
+
@pattern = './spec{,/*/**}/*_spec.rb'
|
136
|
+
end
|
123
137
|
|
124
|
-
|
138
|
+
def has_files?
|
139
|
+
empty = files_to_run.empty?
|
140
|
+
puts "No examples matching #{pattern} could be found" if empty
|
141
|
+
not empty
|
142
|
+
end
|
125
143
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
puts failure_message if failure_message
|
136
|
-
end
|
137
|
-
raise("#{spec_command} failed") if fail_on_error unless success
|
138
|
-
end
|
144
|
+
def run_task(verbose)
|
145
|
+
files = has_files?
|
146
|
+
if files
|
147
|
+
command = spec_command
|
148
|
+
begin
|
149
|
+
puts command if verbose
|
150
|
+
success = system(command)
|
151
|
+
rescue
|
152
|
+
puts failure_message if failure_message
|
139
153
|
end
|
154
|
+
raise("#{command} failed") if fail_on_error unless success
|
140
155
|
end
|
141
156
|
end
|
142
157
|
|
@@ -144,29 +159,25 @@ module RSpec
|
|
144
159
|
|
145
160
|
def files_to_run
|
146
161
|
if ENV['SPEC']
|
147
|
-
FileList[ ENV['SPEC'] ]
|
162
|
+
FileList[ ENV['SPEC'] ].sort
|
148
163
|
else
|
149
|
-
FileList[ pattern ].map { |f| f.
|
164
|
+
FileList[ pattern ].sort.map { |f| f.shellescape }
|
150
165
|
end
|
151
166
|
end
|
152
167
|
|
153
168
|
def spec_command
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
cmd_parts.flatten.reject(&blank).join(" ")
|
165
|
-
end
|
169
|
+
cmd_parts = []
|
170
|
+
cmd_parts << RUBY
|
171
|
+
cmd_parts << ruby_opts
|
172
|
+
cmd_parts << "-w" if @warning
|
173
|
+
cmd_parts << "-S" << runner
|
174
|
+
cmd_parts << "-Ispec:lib" << rcov_opts if rcov
|
175
|
+
cmd_parts << files_to_run
|
176
|
+
cmd_parts << "--" if rcov && rspec_opts
|
177
|
+
cmd_parts << rspec_opts
|
178
|
+
cmd_parts.flatten.reject(&blank).join(" ")
|
166
179
|
end
|
167
180
|
|
168
|
-
private
|
169
|
-
|
170
181
|
def runner
|
171
182
|
rcov ? rcov_path : rspec_path
|
172
183
|
end
|
data/lib/rspec/core/reporter.rb
CHANGED
@@ -38,7 +38,7 @@ module RSpec::Core
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def start(expected_example_count)
|
41
|
-
@start = Time.now
|
41
|
+
@start = RSpec::Core::Time.now
|
42
42
|
notify :start, expected_example_count
|
43
43
|
end
|
44
44
|
|
@@ -89,7 +89,7 @@ module RSpec::Core
|
|
89
89
|
alias_method :abort, :finish
|
90
90
|
|
91
91
|
def stop
|
92
|
-
@duration = Time.now - @start if @start
|
92
|
+
@duration = (RSpec::Core::Time.now - @start).to_f if @start
|
93
93
|
notify :stop
|
94
94
|
end
|
95
95
|
|
@@ -29,68 +29,116 @@ module RSpec
|
|
29
29
|
# @see ExampleGroup.include_examples
|
30
30
|
# @see ExampleGroup.include_context
|
31
31
|
def shared_examples *args, &block
|
32
|
-
|
33
|
-
key = args.shift
|
34
|
-
raise_key_taken key if key_taken? key
|
35
|
-
RSpec.world.shared_example_groups[key] = block
|
36
|
-
end
|
37
|
-
|
38
|
-
unless args.empty?
|
39
|
-
mod = Module.new
|
40
|
-
(class << mod; self; end).send :define_method, :extended do |host|
|
41
|
-
host.class_eval(&block)
|
42
|
-
end
|
43
|
-
RSpec.configuration.extend mod, *args
|
44
|
-
end
|
32
|
+
Registry.add_group(*args, &block)
|
45
33
|
end
|
46
34
|
|
47
35
|
alias_method :shared_context, :shared_examples
|
48
36
|
alias_method :share_examples_for, :shared_examples
|
49
37
|
alias_method :shared_examples_for, :shared_examples
|
50
38
|
|
39
|
+
# @deprecated
|
51
40
|
def share_as(name, &block)
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
41
|
+
RSpec.deprecate("Rspec::Core::SharedExampleGroup#share_as",
|
42
|
+
"RSpec::SharedContext or shared_examples")
|
43
|
+
Registry.add_const(name, &block)
|
44
|
+
end
|
45
|
+
|
46
|
+
# @private
|
47
|
+
#
|
48
|
+
# Used internally to manage the shared example groups and
|
49
|
+
# constants. We want to limit the number of methods we add
|
50
|
+
# to objects we don't own (main and Module) so this allows
|
51
|
+
# us to have helper methods that don't get added to those
|
52
|
+
# objects.
|
53
|
+
module Registry
|
54
|
+
extend self
|
56
55
|
|
57
|
-
|
58
|
-
|
59
|
-
@caller_line = caller.last
|
56
|
+
def add_group(*args, &block)
|
57
|
+
ensure_block_has_source_location(block, caller[1])
|
60
58
|
|
61
|
-
|
62
|
-
|
59
|
+
if key? args.first
|
60
|
+
key = args.shift
|
61
|
+
warn_if_key_taken key, block
|
62
|
+
RSpec.world.shared_example_groups[key] = block
|
63
63
|
end
|
64
64
|
|
65
|
-
|
66
|
-
|
67
|
-
|
65
|
+
unless args.empty?
|
66
|
+
mod = Module.new
|
67
|
+
(class << mod; self; end).send :define_method, :extended do |host|
|
68
|
+
host.class_eval(&block)
|
69
|
+
end
|
70
|
+
RSpec.configuration.extend mod, *args
|
68
71
|
end
|
69
72
|
end
|
70
73
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
+
def add_const(name, &block)
|
75
|
+
if Object.const_defined?(name)
|
76
|
+
mod = Object.const_get(name)
|
77
|
+
raise_name_error unless mod.created_from_caller(caller)
|
78
|
+
end
|
74
79
|
|
75
|
-
|
80
|
+
mod = Module.new do
|
81
|
+
@shared_block = block
|
82
|
+
@caller_line = caller.last
|
76
83
|
|
77
|
-
|
78
|
-
|
79
|
-
|
84
|
+
def self.created_from_caller(other_caller)
|
85
|
+
@caller_line == other_caller.last
|
86
|
+
end
|
80
87
|
|
81
|
-
|
82
|
-
|
83
|
-
|
88
|
+
def self.included(kls)
|
89
|
+
kls.describe(&@shared_block)
|
90
|
+
kls.children.first.metadata[:shared_group_name] = name
|
91
|
+
end
|
92
|
+
end
|
84
93
|
|
85
|
-
|
86
|
-
|
87
|
-
|
94
|
+
shared_const = Object.const_set(name, mod)
|
95
|
+
RSpec.world.shared_example_groups[shared_const] = block
|
96
|
+
end
|
88
97
|
|
89
|
-
|
90
|
-
|
98
|
+
private
|
99
|
+
|
100
|
+
def key? candidate
|
101
|
+
[String, Symbol, Module].any? { |cls| cls === candidate }
|
102
|
+
end
|
103
|
+
|
104
|
+
def raise_name_error
|
105
|
+
raise NameError, "The first argument (#{name}) to share_as must be a legal name for a constant not already in use."
|
106
|
+
end
|
107
|
+
|
108
|
+
def warn_if_key_taken key, new_block
|
109
|
+
return unless existing_block = example_block_for(key)
|
110
|
+
|
111
|
+
Kernel.warn <<-WARNING.gsub(/^ +\|/, '')
|
112
|
+
|WARNING: Shared example group '#{key}' has been previously defined at:
|
113
|
+
| #{formatted_location existing_block}
|
114
|
+
|...and you are now defining it at:
|
115
|
+
| #{formatted_location new_block}
|
116
|
+
|The new definition will overwrite the original one.
|
117
|
+
WARNING
|
118
|
+
end
|
119
|
+
|
120
|
+
def formatted_location block
|
121
|
+
block.source_location.join ":"
|
122
|
+
end
|
123
|
+
|
124
|
+
def example_block_for key
|
125
|
+
RSpec.world.shared_example_groups[key]
|
126
|
+
end
|
127
|
+
|
128
|
+
def ensure_block_has_source_location(block, caller_line)
|
129
|
+
return if block.respond_to?(:source_location)
|
130
|
+
|
131
|
+
block.extend Module.new {
|
132
|
+
define_method :source_location do
|
133
|
+
caller_line.split(':')
|
134
|
+
end
|
135
|
+
}
|
136
|
+
end
|
91
137
|
end
|
92
138
|
end
|
93
139
|
end
|
94
140
|
end
|
95
141
|
|
96
|
-
|
142
|
+
extend RSpec::Core::SharedExampleGroup
|
143
|
+
Module.send(:include, RSpec::Core::SharedExampleGroup)
|
144
|
+
|