ruptr 0.1.3

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.
@@ -0,0 +1,191 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require 'set'
5
+
6
+ module Ruptr
7
+ class Compat
8
+ class RSpec < self
9
+ class Adapter < Module
10
+ class Configuration
11
+ extend Forwardable
12
+
13
+ def initialize(adapter)
14
+ @adapter_module = adapter
15
+ @delayed_example_group_alterations = []
16
+ @delayed_example_alterations = []
17
+ @inclusion_filter = []
18
+ @exclusion_filter = []
19
+ @run_all_when_everything_filtered = false
20
+ @expectation_frameworks = Set.new
21
+ @mock_frameworks = Set.new
22
+ end
23
+
24
+ attr_reader :adapter_module
25
+
26
+ def disable_monkey_patching! = nil # TODO
27
+
28
+ def color_enabled? = false # used in RSpec::Expectations::Configuration
29
+
30
+ def full_backtrace=(v)
31
+ raise ArgumentError, "unsupported" if v
32
+ end
33
+
34
+ def full_backtrace? = true
35
+
36
+ def order=(v)
37
+ raise ArgumentError, "unsupported" if v.to_sym != :random
38
+ end
39
+
40
+ def threadsafe = false
41
+
42
+ def threadsafe=(v)
43
+ # NOTE: The framework supports running the examples in multiple threads, but the example
44
+ # blocks themselves should not call the framework from multiple threads. This can be a
45
+ # problem with memoized "let" helpers for example (but using "let!" helpers is fine).
46
+ raise ArgumentError, "unsupported" if v
47
+ end
48
+
49
+ private def delayed_example_group_alteration(filter)
50
+ @delayed_example_group_alterations << lambda do |example_group|
51
+ next unless ExampleGroup.filter_matches?(filter, example_group.metadata)
52
+ yield example_group
53
+ end
54
+ end
55
+
56
+ def apply_to_example_group(example_group = nil)
57
+ @delayed_example_group_alterations.each { |p| p.call(example_group ||= yield) }
58
+ end
59
+
60
+ private def delayed_example_alteration(filter)
61
+ @delayed_example_alterations << lambda do |example|
62
+ next unless ExampleGroup.filter_matches?(filter, example.metadata)
63
+ yield example
64
+ end
65
+ end
66
+
67
+ def apply_to_example(example = nil)
68
+ @delayed_example_alterations.each { |p| p.call(example ||= yield) }
69
+ end
70
+
71
+ %i[include prepend extend].each do |name|
72
+ define_method(name) do |m, *args, **opts|
73
+ delayed_example_group_alteration(ExampleGroup.get_args_filter(args, opts)) do |example_group|
74
+ example_group.send(name, m)
75
+ end
76
+ end
77
+ end
78
+
79
+ def include_context(include_name, *args, **opts)
80
+ delayed_example_group_alteration(ExampleGroup.get_args_filter(args, opts)) do |example_group|
81
+ example_group.include_context(include_name)
82
+ end
83
+ end
84
+
85
+ def on_example_group_definition(&)
86
+ delayed_example_group_alteration({}, &)
87
+ end
88
+
89
+ def when_first_matching_example_defined(*args, **opts)
90
+ first = true
91
+ delayed_example_alteration(ExampleGroup.get_args_filter(args, opts)) do |example|
92
+ next unless first
93
+ yield example
94
+ first = false
95
+ end
96
+ end
97
+
98
+ attr_accessor :inclusion_filter, :exclusion_filter,
99
+ :run_all_when_everything_filtered
100
+
101
+ def filter_run_including(*args, **opts)
102
+ inclusion_filter << ExampleGroup.get_args_filter(args, opts)
103
+ end
104
+
105
+ alias filter_run filter_run_including
106
+
107
+ def filter_run_excluding(*args, **opts)
108
+ exclusion_filter << ExampleGroup.get_args_filter(args, opts)
109
+ end
110
+
111
+ def filter_run_when_matching(*args, **opts)
112
+ when_first_matching_example_defined(*args, **opts) { filter_run_including(*args, **opts) }
113
+ end
114
+
115
+ def silence_filter_announcements = true
116
+
117
+ def silence_filter_announcements=(v)
118
+ raise ArgumentError, "unsupported" if v
119
+ end
120
+
121
+ attr_reader :expectation_frameworks
122
+
123
+ private def expect_with_1(handler)
124
+ case handler
125
+ when Module
126
+ root_example_group.include(handler)
127
+ when :test_unit, :minitest
128
+ require 'ruptr/adapters/assertions'
129
+ root_example_group.include(Adapters::RuptrAssertions)
130
+ when :rspec
131
+ require 'ruptr/adapters/rspec_expect'
132
+ root_example_group.include(Adapters::RSpecExpect)
133
+ root_example_group.include(Adapters::RSpecExpect::Helpers)
134
+ else
135
+ raise ArgumentError, "#{handler} not supported"
136
+ end
137
+ @expectation_frameworks << handler
138
+ end
139
+
140
+ def expect_with(*handlers)
141
+ handlers.each { |handler| expect_with_1(handler) }
142
+ end
143
+
144
+ attr_reader :mock_frameworks
145
+
146
+ private def mock_with_1(handler)
147
+ case handler
148
+ when :rspec
149
+ require 'ruptr/adapters/rspec_mocks'
150
+ root_example_group.include(Adapters::RSpecMocks)
151
+ root_example_group.include(Adapters::RSpecMocks::Helpers)
152
+ else
153
+ raise ArgumentError, "#{handler} not supported"
154
+ end
155
+ @mock_frameworks << handler
156
+ end
157
+
158
+ def mock_with(*handlers)
159
+ handlers.each { |handler| mock_with_1(handler) }
160
+ end
161
+
162
+ def alias_example_group_to(name, *args, **opts)
163
+ metadata = ExampleGroup.get_args_filter(args, opts)
164
+ root_example_group.singleton_class.def_example_group_shortcut(name, metadata)
165
+ adapter_module.singleton_class.def_delegators(:root_example_group, name)
166
+ end
167
+
168
+ def alias_example_to(name, *args, **opts)
169
+ metadata = ExampleGroup.get_args_filter(args, opts)
170
+ root_example_group.singleton_class.def_example_shortcut(name, metadata)
171
+ adapter_module.singleton_class.def_delegators(:root_example_group, name)
172
+ end
173
+
174
+ def alias_it_behaves_like_to(name, label_prefix)
175
+ root_example_group.singleton_class.def_it_behaves_like_shortcut(
176
+ name, ->(example_group_name) { "#{label_prefix} #{example_group_name}" }
177
+ )
178
+ adapter_module.singleton_class.def_delegators(:root_example_group, name)
179
+ end
180
+
181
+ alias alias_it_should_behave_like_to alias_it_behaves_like_to
182
+
183
+ def_delegators :adapter_module,
184
+ :root_example_group
185
+ def_delegators :root_example_group,
186
+ :before, :prepend_before, :after, :append_after, :around
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,498 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../adapters'
4
+
5
+ module Ruptr
6
+ class Compat
7
+ class RSpec < self
8
+ # Passed to example and hook blocks.
9
+ class Handle
10
+ def initialize(element, exception = nil, &run)
11
+ @element = element
12
+ @exception = exception
13
+ @run = run
14
+ end
15
+
16
+ def metadata = @element.metadata
17
+ def exception = @exception
18
+ def run = @run.call(chain)
19
+ def to_proc = @run ? proc { run } : nil
20
+ def chain(&) = self.class.new(@element, @exception, &)
21
+ def caught(exception) = exception ? self.class.new(@element, exception) : self
22
+ end
23
+
24
+ # Common for both Examples and ExampleGroups.
25
+ module Element
26
+ DEFAULT_METADATA = {}.freeze
27
+ def metadata = DEFAULT_METADATA
28
+ def label = nil
29
+ end
30
+
31
+ class Example
32
+ include Element
33
+
34
+ def initialize(label:, metadata:, block:)
35
+ @label = label
36
+ @metadata = metadata
37
+ @block = block
38
+ end
39
+
40
+ attr_reader :label, :metadata, :block
41
+ end
42
+
43
+ module ExampleGroupInstanceUserMethods
44
+ def skip(reason = nil) = raise SkippedException, reason
45
+
46
+ def pending? = @rspec_example_pending
47
+ def pending_reason = @rspec_example_pending_reason
48
+
49
+ def pending(reason = nil)
50
+ @rspec_example_pending = true
51
+ @rspec_example_pending_reason = reason
52
+ end
53
+ end
54
+
55
+ module ExampleGroupInstanceInternal
56
+ def wrap_context_handle(h) = yield h
57
+ def wrap_context(&) = wrap_context_handle(Handle.new(self.class), &)
58
+
59
+ def wrap_example_handle(h) = yield h
60
+
61
+ def run_example(example)
62
+ ran = false
63
+ wrap_example_handle(Handle.new(example)) do |h|
64
+ instance_exec(h, &example.block)
65
+ ran = true
66
+ end
67
+ skip unless ran # may happen if an "around" hook didn't call its handle's #run method
68
+ end
69
+ end
70
+
71
+ module ExampleGroupInternal
72
+ def carryover_instance_variables(from, to)
73
+ from.instance_variables.each do |name|
74
+ next if from.ruptr_internal_variable?(name)
75
+ to.instance_variable_set(name, from.instance_variable_get(name))
76
+ end
77
+ end
78
+
79
+ def my_examples = @my_examples ||= []
80
+ def my_example_groups = @my_example_groups ||= []
81
+
82
+ def each_example(&) = my_examples.each(&)
83
+ def each_example_group(&) = my_example_groups.each(&)
84
+
85
+ def need_wrap_context? = false
86
+ end
87
+
88
+ module ExampleGroupHooks
89
+ def self.def_hook(name, setup_method_name)
90
+ iv_name = :"@#{name}"
91
+ attr_reader name
92
+ define_method(:"#{name}=") do |new|
93
+ instance_variable_set(iv_name, new)
94
+ send(setup_method_name)
95
+ new
96
+ end
97
+ end
98
+
99
+ # Context-level hooks are invoked by the runner. It will recursively call #wrap_context as
100
+ # it traverses the hierarchy of test groups.
101
+
102
+ def_hook :context_around_layer_hook, :setup_context_hooks
103
+ def_hook :context_before_hook, :setup_context_hooks
104
+ def_hook :context_after_hook, :setup_context_hooks
105
+
106
+ # For example-level hooks, "around" hooks are run in a separate phase that precedes all of
107
+ # the nested "before" and "after" hooks. This is not supported for context-level hooks, so
108
+ # use "around_layer" semantics for those instead. The behavior may not be exactly correct
109
+ # (though it seems to be deprecated in RSpec and I'm not sure what the correct behavior
110
+ # actually should be). This at least makes :suite "around" hooks work as expected (as they
111
+ # are added to the root example group, they will necessarily be run before all of the
112
+ # "before" and "after" hooks without needing a separate phase).
113
+
114
+ alias context_around_hook context_around_layer_hook
115
+ alias context_around_hook= context_around_layer_hook=
116
+
117
+ def need_wrap_context? = context_around_layer_hook || context_before_hook || context_after_hook
118
+
119
+ module ContextHooksInstanceMethods
120
+ def wrap_context_handle(h)
121
+ eg = self.class
122
+ # NOTE: Hooks for the parent example groups will already have been called by the runner.
123
+ k = lambda do |h|
124
+ instance_exec(h, &eg.context_before_hook) if eg.context_before_hook
125
+ yield h
126
+ ensure
127
+ instance_exec(h, &eg.context_after_hook) if eg.context_after_hook
128
+ end
129
+ if eg.context_around_layer_hook
130
+ instance_exec(h.chain(&k), &eg.context_around_layer_hook)
131
+ else
132
+ k.call(h)
133
+ end
134
+ end
135
+ end
136
+
137
+ def setup_context_hooks
138
+ include ContextHooksInstanceMethods
139
+ end
140
+
141
+ # Example-level hooks are invoked by the test case instance before each example is run.
142
+ # Method inheritance is used to call the hooks of the parent example groups (if any).
143
+ #
144
+ # Two phases are used: the "around" hooks are run in phase 1, the "before", "after" and
145
+ # "around_layer" hooks in phase 2.
146
+ #
147
+ # The "around_layer" hooks behave similarly to "around" but they only wrap around the
148
+ # "before" and "after" hooks of their own (and nested) example groups.
149
+
150
+ def_hook :example_around_hook, :setup_example_phase1_hooks
151
+ def_hook :example_around_layer_hook, :setup_example_phase2_hooks
152
+ def_hook :example_before_hook, :setup_example_phase2_hooks
153
+ def_hook :example_after_hook, :setup_example_phase2_hooks
154
+
155
+ module ExampleHooksBaseInstanceMethods
156
+ def wrap_example_phase1_hooks(h) = yield h
157
+ def wrap_example_phase2_hooks(h) = yield h
158
+ def wrap_example_handle(h, &) = wrap_example_phase1_hooks(h) { |h| wrap_example_phase2_hooks(h, &) }
159
+ end
160
+
161
+ def setup_example_phase1_hooks
162
+ return if method_defined?(:wrap_example_phase1_hooks, false)
163
+ include ExampleHooksBaseInstanceMethods
164
+ eg = self
165
+ define_method(:wrap_example_phase1_hooks) do |down_h, &up|
166
+ super(down_h) { |h| instance_exec(h.chain(&up), &eg.example_around_hook) }
167
+ end
168
+ end
169
+
170
+ def setup_example_phase2_hooks
171
+ return if method_defined?(:wrap_example_phase2_hooks, false)
172
+ include ExampleHooksBaseInstanceMethods
173
+ eg = self
174
+ define_method(:wrap_example_phase2_hooks) do |down_h, &up|
175
+ super(down_h) do |h|
176
+ k = if eg.example_before_hook || eg.example_after_hook
177
+ lambda do |h|
178
+ instance_exec(h, &eg.example_before_hook) if eg.example_before_hook
179
+ up.call(h)
180
+ ensure
181
+ instance_exec(h.caught($!), &eg.example_after_hook) if eg.example_after_hook
182
+ end
183
+ else
184
+ up
185
+ end
186
+ if eg.example_around_layer_hook
187
+ instance_exec(h.chain(&k), &eg.example_around_layer_hook)
188
+ else
189
+ k.call(h)
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
195
+
196
+ module SharedContext
197
+ # This is almost identical to the implementation in RSpec 3 rspec-core's
198
+ # lib/rspec/core/shared_context.rb. This makes SharedContext modules behave very similarly
199
+ # to named #shared_examples/#shared_context blocks.
200
+ def included(from)
201
+ super
202
+ ruptr_shared_context_recordings.each do |method_name, args, opts, blk|
203
+ from.__send__(method_name, *args, **opts, &blk)
204
+ end
205
+ end
206
+
207
+ def ruptr_shared_context_recordings = @ruptr_shared_context_recordings ||= []
208
+
209
+ def self.record(method_name)
210
+ define_method(method_name) do |*args, **opts, &blk|
211
+ ruptr_shared_context_recordings << [method_name, args, opts, blk]
212
+ end
213
+ end
214
+ end
215
+
216
+ module ExampleGroupDSL
217
+ module Meta; end
218
+ extend Meta
219
+
220
+ def self.extended(from)
221
+ super
222
+ from.singleton_class.extend(Meta)
223
+ end
224
+
225
+ def get_args_filter(args, opts)
226
+ args.each { |key| opts[key] = true }
227
+ opts
228
+ end
229
+
230
+ def filter_matches?(filter, metadata)
231
+ filter.all? { |k, v| metadata[k] == v }
232
+ end
233
+
234
+ def get_args_metadata(extra, args, opts)
235
+ return metadata if (extra.nil? || extra.empty?) && args.empty? && opts.empty?
236
+ new_metadata = metadata.dup
237
+ new_metadata.merge!(extra) if extra
238
+ new_metadata.merge!(opts)
239
+ args.each { |key| new_metadata[key] = true }
240
+ new_metadata
241
+ end
242
+
243
+ def example_with_metadata_1(label, metadata, &blk)
244
+ Example.new(
245
+ label: label&.to_s,
246
+ metadata:,
247
+ block: if (reason = metadata[:skip]) || !blk
248
+ reason = nil if reason == true
249
+ ->(_h) { raise SkippedException, reason }
250
+ elsif (reason = metadata[:pending])
251
+ reason = nil if reason == true
252
+ ->(h) { pending(reason); instance_exec(h, &blk) }
253
+ else
254
+ blk
255
+ end
256
+ ).tap do |example|
257
+ configuration.apply_to_example(example)
258
+ my_examples << example
259
+ end
260
+ end
261
+
262
+ def example_with_metadata(label, metadata, &)
263
+ unless metadata == self.metadata
264
+ done = false
265
+ configuration.apply_to_example_group do
266
+ example_group_with_metadata(nil, metadata, apply_configuration: false) do
267
+ example_with_metadata_1(label, metadata, &)
268
+ done = true
269
+ end
270
+ end
271
+ end
272
+ example_with_metadata_1(label, metadata, &) unless done
273
+ end
274
+
275
+ # FIXME: This won't necessarily be unique with examples included from SharedContext modules.
276
+ def default_example_name = "example ##{my_examples.size + 1}"
277
+
278
+ module Meta
279
+ def recordable(method_name) = SharedContext.record(method_name)
280
+ end
281
+
282
+ recordable def example(label = default_example_name, *args, **opts, &)
283
+ example_with_metadata(label, get_args_metadata(nil, args, opts).freeze, &)
284
+ end
285
+
286
+ recordable alias_method :specify, :example
287
+ recordable alias_method :it, :example
288
+
289
+ module Meta
290
+ def def_example_shortcut(name, extra_metadata)
291
+ recordable name
292
+ define_method(name) do |label = default_example_name, *args, **opts, &blk|
293
+ example_with_metadata(label, get_args_metadata(extra_metadata, args, opts).freeze, &blk)
294
+ end
295
+ end
296
+ end
297
+
298
+ def_example_shortcut :focus, { focus: true }
299
+ def_example_shortcut :fexample, { focus: true }
300
+ def_example_shortcut :fspecify, { focus: true }
301
+ def_example_shortcut :fit, { focus: true }
302
+
303
+ def_example_shortcut :skip, { skip: true }
304
+ def_example_shortcut :xexample, { skip: "Temporarily skipped with xexample" }
305
+ def_example_shortcut :xspecify, { skip: "Temporarily skipped with xspecify" }
306
+ def_example_shortcut :xit, { skip: "Temporarily skipped with xit" }
307
+
308
+ def_example_shortcut :pending, { pending: true }
309
+
310
+ def example_group_with_metadata(label, metadata, apply_configuration: true, &)
311
+ Class.new(self) do
312
+ define_singleton_method(:metadata) { metadata }
313
+ define_singleton_method(:label) { label&.to_s }
314
+ if label.is_a?(Module)
315
+ define_singleton_method(:described_class) { label }
316
+ define_method(:described_class) { label }
317
+ if label.is_a?(Class)
318
+ let(:subject) { label.new }
319
+ else
320
+ let(:subject) { label }
321
+ end
322
+ end
323
+ configuration.apply_to_example_group(self) if apply_configuration
324
+ class_exec(&) if block_given?
325
+ end.tap { |example_group| my_example_groups << example_group }
326
+ end
327
+
328
+ recordable def example_group(label = nil, *args, **opts, &)
329
+ example_group_with_metadata(label, get_args_metadata(nil, args, opts).freeze, &)
330
+ end
331
+
332
+ recordable alias_method :describe, :example_group
333
+ recordable alias_method :context, :example_group
334
+
335
+ module Meta
336
+ def def_example_group_shortcut(name, extra_metadata)
337
+ recordable name
338
+ define_method(name) do |label, *args, **opts, &blk|
339
+ example_group_with_metadata(label, get_args_metadata(extra_metadata, args, opts).freeze, &blk)
340
+ end
341
+ end
342
+ end
343
+
344
+ def_example_group_shortcut :fdescribe, { focus: true }
345
+ def_example_group_shortcut :fcontext, { focus: true }
346
+ def_example_group_shortcut :xdescribe, { skip: "Temporarily skipped with xdescribe" }
347
+ def_example_group_shortcut :xcontext, { skip: "Temporarily skipped with xcontext" }
348
+
349
+ def lookup_shared_examples(_name) = nil
350
+ def shared_examples_stash = nil
351
+
352
+ recordable def shared_examples(name, *args, **opts, &body)
353
+ _child_metadata = get_args_metadata(nil, args, opts).freeze # TODO
354
+ unless singleton_class.method_defined?(:shared_examples_stash, false)
355
+ stash = {}
356
+ define_singleton_method(:shared_examples_stash) { stash }
357
+ define_singleton_method(:lookup_shared_examples) { |name| stash[name] || super(name) }
358
+ end
359
+ shared_examples_stash[name] = body
360
+ end
361
+
362
+ recordable alias_method :shared_examples_for, :shared_examples
363
+ recordable alias_method :shared_context, :shared_examples
364
+
365
+ def examples_included?(_name) = false
366
+ def included_examples = nil
367
+
368
+ recordable def include_examples(name, *args, **opts, &)
369
+ return if examples_included?(name)
370
+ unless singleton_class.method_defined?(:included_examples, false)
371
+ included = []
372
+ define_singleton_method(:examples_included?) { |name| included.include?(name) || super(name) }
373
+ define_singleton_method(:included_examples) { included }
374
+ end
375
+ class_exec(*args, **opts, &lookup_shared_examples(name))
376
+ included_examples << name
377
+ class_exec(&) if block_given?
378
+ end
379
+
380
+ recordable alias_method :include_context, :include_examples
381
+
382
+ recordable def it_behaves_like_with_label(name, label, *args, **opts, &)
383
+ context(label) do
384
+ include_examples(name, *args, **opts)
385
+ class_exec(&) if block_given?
386
+ end
387
+ end
388
+
389
+ module Meta
390
+ def def_it_behaves_like_shortcut(shortcut_name, make_label = ->(name) { "it behaves like #{name}" })
391
+ recordable shortcut_name
392
+ define_method(shortcut_name) do |name, *args, **opts, &blk|
393
+ it_behaves_like_with_label(name, make_label.call(name), *args, **opts, &blk)
394
+ end
395
+ end
396
+ end
397
+
398
+ def_it_behaves_like_shortcut :it_behaves_like
399
+ recordable alias_method :it_should_behave_like, :it_behaves_like
400
+
401
+ recordable def let(method_name, &)
402
+ name = case
403
+ when method_name.end_with?('?') then :"rspec__#{method_name.name.chop}__p"
404
+ when method_name.end_with?('!') then :"rspec__#{method_name.name.chop}__d"
405
+ else :"rspec__#{method_name.name}"
406
+ end
407
+ define_method(:"#{name}__uncached", &)
408
+ module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
409
+ def #{method_name} = defined?(@#{name}) ? @#{name} : (@#{name} = #{name}__uncached)
410
+ RUBY
411
+ end
412
+
413
+ recordable def let!(name, &)
414
+ let(name, &)
415
+ before { public_send(name) }
416
+ end
417
+
418
+ recordable def subject(name = :subject, &)
419
+ let(name, &)
420
+ alias_method(:subject, name) if name != :subject
421
+ end
422
+
423
+ recordable def subject!(name = :subject, &)
424
+ subject(name, &)
425
+ before { public_send(name) }
426
+ end
427
+
428
+ def wrap_hook_block_with_metadata_test(args, opts, blk, around: false)
429
+ filter = get_args_filter(args, opts)
430
+ return blk if filter.empty?
431
+ if around
432
+ ->(h) { ExampleGroup.filter_matches?(filter, h.metadata) ? instance_exec(h, &blk) : h.run }
433
+ else
434
+ ->(h) { instance_exec(h, &blk) if ExampleGroup.filter_matches?(filter, h.metadata) }
435
+ end
436
+ end
437
+
438
+ def self.def_hook_adder(method_name, hook_name, around: false)
439
+ example_get_name = :"example_#{hook_name}"
440
+ example_set_name = :"example_#{hook_name}="
441
+ context_get_name = :"context_#{hook_name}"
442
+ context_set_name = :"context_#{hook_name}="
443
+ recordable method_name
444
+ define_method(method_name) do |scope = :example, *args, **opts, &new|
445
+ new = wrap_hook_block_with_metadata_test(args, opts, new, around:)
446
+ eg = self
447
+ case scope
448
+ when :example, :each
449
+ get_name, set_name = example_get_name, example_set_name
450
+ when :context, :all
451
+ get_name, set_name = context_get_name, context_set_name
452
+ when :suite
453
+ get_name, set_name = context_get_name, context_set_name
454
+ eg = superclass while eg >= ExampleGroup
455
+ else
456
+ raise ArgumentError, "unsupported scope: #{scope}"
457
+ end
458
+ eg.public_send(set_name, (old = public_send(get_name)) ? yield(new, old) : new)
459
+ end
460
+ end
461
+
462
+ def_hook_adder(:around, :around_hook, around: true) do |new, old|
463
+ ->(h) { instance_exec(h.chain { instance_exec(h, &new) }, &old) }
464
+ end
465
+
466
+ def_hook_adder(:around_layer, :around_layer_hook, around: true) do |new, old|
467
+ ->(h) { instance_exec(h.chain { instance_exec(h, &new) }, &old) }
468
+ end
469
+
470
+ def_hook_adder(:before, :before_hook) do |new, old|
471
+ ->(h) { instance_exec(h, &old); instance_exec(h, &new) }
472
+ end
473
+
474
+ def_hook_adder(:prepend_before, :before_hook) do |new, old|
475
+ ->(h) { instance_exec(h, &new); instance_exec(h, &old) }
476
+ end
477
+
478
+ def_hook_adder(:after, :after_hook) do |new, old|
479
+ ->(h) { begin instance_exec(h, &new) ensure instance_exec(h.caught($!), &old) end }
480
+ end
481
+
482
+ def_hook_adder(:append_after, :after_hook) do |new, old|
483
+ ->(h) { begin instance_exec(h, &old) ensure instance_exec(h.caught($!), &new) end }
484
+ end
485
+ end
486
+
487
+ class ExampleGroup
488
+ extend Element
489
+ extend ExampleGroupInternal
490
+ extend ExampleGroupHooks
491
+ extend ExampleGroupDSL
492
+ include ExampleGroupInstanceInternal
493
+ include Ruptr::TestInstance
494
+ include ExampleGroupInstanceUserMethods
495
+ end
496
+ end
497
+ end
498
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../rspec'
4
+ Ruptr::Compat::RSpec.new.prepare_autorun!