rspec-core 2.11.1 → 2.12.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|