rspec-core 3.5.0.beta1 → 3.5.0.beta2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 764d595de1ccd035e52340a849aa668815e8dae7
4
- data.tar.gz: f7e933e063ee39c7813b9a9618f19b74174ab569
3
+ metadata.gz: ae10092df64000bc49a31c63ea1e6fb90f8bed34
4
+ data.tar.gz: 34f6ffdfff90d32dbb96fde2fd9a45e1280bfaeb
5
5
  SHA512:
6
- metadata.gz: e18131d908d6c1ab5329e13005261cc07aaabade69dfd9ccb09078ec6c2f7efb43231f229168b9eab2ea2ccdde573c55f42cf7beca42e9e2f8cf107e58873944
7
- data.tar.gz: 8e38f681409c92781111082573df67e2e138670f1e063a24088eb92102943818eef279e33bef02cac8c38aa73d9228a105f4bcfd39963409ddf51e90ccb4af91
6
+ metadata.gz: d58b487bff47a2a7d54c86a91e50ec8dadd2f4c5a5a842557cdaa6a2a575dd1409f612a41161ef1862eb15a71b8d9c60bfb3acfc5aec471e0a7fec14467b53d9
7
+ data.tar.gz: 7e6f624e87c70244933bc521d67d6bed2b3b455556a57aaca8bda715d07a738920414ae179bf432054222507323f002fc2e30a344c999125606672c6dbdccd4f
@@ -1,4 +1,4 @@
1
- __m�^�=ĽYi��¦���i8����E�F/���Ұ">�獈-�7 �okac�8<�Ȁ�\�niNhr�8̤�*F��I���=
2
- �R_Il��Mb*�63Ou�@~.)�D�Ynv_��,nzV��e�}km[����D��� ɫ<��!�G��[���d|:3.��G�e����>�
3
- �u<u8x��j��;�� O8������ �h�H��R�t��#�U� #�|�'~Q�G^c-gS�� iR;�'��D8Q�8����t{�d��g+�<���A�V��?�V
4
- ����?Gh]vX�間��E���$�8��ņ�C���̍z��<�X��P����vTlI��]��VV��M49^�ĝ��;�c]��?�}��u��tV���L+{��T���^潏�Bķ��Ľv�)7;II,��Z�ɤ�3A��
1
+ CS+�0������>;���{t�>զ�Y�`�$Qh5��-���"�{�C�5h�:��*�m��L��^���&�����]�fR4�҄��������g�J܊��S�;b�$6�����hu�F
2
+ 9t����6)KR�$l4Ƈ�O(��+���-B�* ���bE���n��;U�پJX�r`�7jY�+z%?ϸ�&��)��^��i؏]F�R��e?�_��~� �ݽ6�^lki��cK�U����
3
+ s���*Z
4
+ ��0����@�+��uD-�K(-i4N ,ؚJ�b� �2>���a� d�%%�Mnp�vT�>�"Oo_�ڪ�.'���QP�&^w�p���F/f+�/@��<��DM
data.tar.gz.sig CHANGED
Binary file
@@ -1,8 +1,41 @@
1
1
  ### Development
2
2
  [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.5.0.beta1...master)
3
3
 
4
+ Enhancements:
5
+
6
+ * Remove unneeded `:execution_result` example groups metadata, saving a
7
+ bit of memory. (Myron Marston, #2172)
8
+ * Apply hooks registered with `config` to previously defined groups.
9
+ (Myron Marston, #2189)
10
+ * `RSpec::Core::Configuration#reporter` is now public API under semver.
11
+ (Jon Rowe, #2193)
12
+ * Add new `config.when_first_matching_example_defined` hook. (Myron
13
+ Marston, #2175)
14
+
4
15
  ### 3.5.0.beta1 / 2016-02-06
5
- [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.4.2...v3.5.0.beta1)
16
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.4.3...v3.5.0.beta1)
17
+
18
+ ### 3.4.4 / 2016-03-09
19
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.4.3...v3.4.4)
20
+
21
+ Bug Fixes:
22
+
23
+ * Fix `RSpec::Core::RakeTask` so that it works with Rake 11.
24
+ (Travis Grathwell, #2197)
25
+
26
+ ### 3.4.3 / 2016-02-19
27
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.4.2...v3.4.3)
28
+
29
+ Bug Fixes:
30
+
31
+ * Prevent a `TypeError` from occuring when running via the rake task when
32
+ Ruby crashes. (Patrik Wenger, #2161)
33
+ * Only consider example and group declaration lines from a specific file
34
+ when applying line number filtering, instead of considering all
35
+ declaration lines from all spec files. (Myron Marston, #2170)
36
+ * Fix failure snippet extraction so that snippets that contain `do-end` style
37
+ block and end with `end`-only line can be extracted properly.
38
+ (Yuji Nakayama, #2173)
6
39
 
7
40
  ### 3.4.2 / 2016-01-26
8
41
  [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.4.1...v3.4.2)
@@ -83,7 +83,6 @@ module RSpec
83
83
  def self.configuration
84
84
  @configuration ||= RSpec::Core::Configuration.new
85
85
  end
86
- configuration.expose_dsl_globally = true
87
86
 
88
87
  # Yields the global configuration to a block.
89
88
  # @yield [Configuration] global configuration
@@ -178,4 +177,7 @@ module RSpec
178
177
  require MODULES_TO_AUTOLOAD.fetch(name) { return super }
179
178
  ::RSpec.const_get(name)
180
179
  end
180
+
181
+ Core::DSL.expose_globally!
182
+ Core::SharedExampleGroup::TopLevelDSL.expose_globally!
181
183
  end
@@ -343,12 +343,13 @@ module RSpec
343
343
  # @private
344
344
  attr_writer :files_to_run
345
345
  # @private
346
- attr_accessor :filter_manager
346
+ attr_accessor :filter_manager, :world
347
347
  # @private
348
348
  attr_accessor :static_config_filter_manager
349
349
  # @private
350
350
  attr_reader :backtrace_formatter, :ordering_manager, :loaded_spec_files
351
351
 
352
+ # rubocop:disable Metrics/AbcSize
352
353
  def initialize
353
354
  # rubocop:disable Style/GlobalVars
354
355
  @start_time = $_rspec_core_load_started_at || ::RSpec::Core::Time.now
@@ -394,9 +395,11 @@ module RSpec
394
395
  @derived_metadata_blocks = FilterableItemRepository::QueryOptimized.new(:any?)
395
396
  @threadsafe = true
396
397
  @max_displayed_failure_line_count = 10
398
+ @world = World::Null
397
399
 
398
400
  define_built_in_hooks
399
401
  end
402
+ # rubocop:enable Metrics/AbcSize
400
403
 
401
404
  # @private
402
405
  #
@@ -822,7 +825,7 @@ module RSpec
822
825
  end
823
826
  end
824
827
 
825
- # @private
828
+ # @return [RSpec::Core::Reporter] the currently configured reporter
826
829
  def reporter
827
830
  # @reporter_buffer should only ever be set in this method to cover
828
831
  # initialization of @reporter.
@@ -1158,7 +1161,7 @@ module RSpec
1158
1161
  def include(mod, *filters)
1159
1162
  meta = Metadata.build_hash_from(filters, :warn_about_example_group_filtering)
1160
1163
  @include_modules.append(mod, meta)
1161
- configure_existing_groups(mod, meta, :safe_include)
1164
+ on_existing_matching_groups(meta) { |group| safe_include(mod, group) }
1162
1165
  end
1163
1166
 
1164
1167
  # Tells RSpec to extend example groups with `mod`. Methods defined in
@@ -1194,7 +1197,7 @@ module RSpec
1194
1197
  def extend(mod, *filters)
1195
1198
  meta = Metadata.build_hash_from(filters, :warn_about_example_group_filtering)
1196
1199
  @extend_modules.append(mod, meta)
1197
- configure_existing_groups(mod, meta, :safe_extend)
1200
+ on_existing_matching_groups(meta) { |group| safe_extend(mod, group) }
1198
1201
  end
1199
1202
 
1200
1203
  if RSpec::Support::RubyFeatures.module_prepends_supported?
@@ -1233,7 +1236,7 @@ module RSpec
1233
1236
  def prepend(mod, *filters)
1234
1237
  meta = Metadata.build_hash_from(filters, :warn_about_example_group_filtering)
1235
1238
  @prepend_modules.append(mod, meta)
1236
- configure_existing_groups(mod, meta, :safe_prepend)
1239
+ on_existing_matching_groups(meta) { |group| safe_prepend(mod, group) }
1237
1240
  end
1238
1241
  end
1239
1242
 
@@ -1247,21 +1250,6 @@ module RSpec
1247
1250
  configure_group_with group, @prepend_modules, :safe_prepend
1248
1251
  end
1249
1252
 
1250
- # @private
1251
- def configure_group_with(group, module_list, application_method)
1252
- module_list.items_for(group.metadata).each do |mod|
1253
- __send__(application_method, mod, group)
1254
- end
1255
- end
1256
-
1257
- # @private
1258
- def configure_existing_groups(mod, meta, application_method)
1259
- RSpec.world.all_example_groups.each do |group|
1260
- next unless meta.empty? || MetadataFilter.apply?(:any?, meta, group.metadata)
1261
- __send__(application_method, mod, group)
1262
- end
1263
- end
1264
-
1265
1253
  # @private
1266
1254
  #
1267
1255
  # Used internally to extend the singleton class of a single example's
@@ -1281,13 +1269,6 @@ module RSpec
1281
1269
  end
1282
1270
  end
1283
1271
 
1284
- if RSpec::Support::RubyFeatures.module_prepends_supported?
1285
- # @private
1286
- def safe_prepend(mod, host)
1287
- host.__send__(:prepend, mod) unless host < mod
1288
- end
1289
- end
1290
-
1291
1272
  # @private
1292
1273
  def requires=(paths)
1293
1274
  directories = ['lib', default_path].select { |p| File.directory? p }
@@ -1305,31 +1286,6 @@ module RSpec
1305
1286
  Regexp.union(regexes)
1306
1287
  end
1307
1288
 
1308
- # @private
1309
- if RUBY_VERSION.to_f >= 1.9
1310
- # @private
1311
- def safe_include(mod, host)
1312
- host.__send__(:include, mod) unless host < mod
1313
- end
1314
-
1315
- # @private
1316
- def safe_extend(mod, host)
1317
- host.extend(mod) unless host.singleton_class < mod
1318
- end
1319
- else # for 1.8.7
1320
- # :nocov:
1321
- # @private
1322
- def safe_include(mod, host)
1323
- host.__send__(:include, mod) unless host.included_modules.include?(mod)
1324
- end
1325
-
1326
- # @private
1327
- def safe_extend(mod, host)
1328
- host.extend(mod) unless (class << host; self; end).included_modules.include?(mod)
1329
- end
1330
- # :nocov:
1331
- end
1332
-
1333
1289
  # @private
1334
1290
  def configure_mock_framework
1335
1291
  RSpec::Core::ExampleGroup.__send__(:include, mock_framework)
@@ -1352,7 +1308,7 @@ module RSpec
1352
1308
  # in that case, the spec file was loaded by `ruby` and
1353
1309
  # isn't loaded by us here so we only know about it because
1354
1310
  # of an example group being registered in it.
1355
- RSpec.world.registered_example_group_files.each do |f|
1311
+ world.registered_example_group_files.each do |f|
1356
1312
  loaded_spec_files << f # the registered files are already expended absolute paths
1357
1313
  end
1358
1314
 
@@ -1597,6 +1553,41 @@ module RSpec
1597
1553
  @derived_metadata_blocks.append(block, meta)
1598
1554
  end
1599
1555
 
1556
+ # Defines a callback that runs after the first example with matching
1557
+ # metadata is defined. If no examples are defined with matching metadata,
1558
+ # it will not get called at all.
1559
+ #
1560
+ # This can be used to ensure some setup is performed (such as bootstrapping
1561
+ # a DB or loading a specific file that adds significantly to the boot time)
1562
+ # if needed (as indicated by the presence of an example with matching metadata)
1563
+ # but avoided otherwise.
1564
+ #
1565
+ # @example
1566
+ # RSpec.configure do |config|
1567
+ # config.when_first_matching_example_defined(:db) do
1568
+ # # Load a support file that does some heavyweight setup,
1569
+ # # including bootstrapping the DB, but only if we have loaded
1570
+ # # any examples tagged with `:db`.
1571
+ # require 'support/db'
1572
+ # end
1573
+ # end
1574
+ def when_first_matching_example_defined(*filters, &block)
1575
+ specified_meta = Metadata.build_hash_from(filters, :warn_about_example_group_filtering)
1576
+
1577
+ callback = lambda do |example_or_group_meta|
1578
+ # Example groups do not have `:example_group` metadata
1579
+ # (instead they have `:parent_example_group` metadata).
1580
+ return unless example_or_group_meta.key?(:example_group)
1581
+
1582
+ # Ensure the callback only fires once.
1583
+ @derived_metadata_blocks.items_for(specified_meta).delete(callback)
1584
+
1585
+ block.call
1586
+ end
1587
+
1588
+ @derived_metadata_blocks.append(callback, specified_meta)
1589
+ end
1590
+
1600
1591
  # @private
1601
1592
  def apply_derived_metadata_to(metadata)
1602
1593
  @derived_metadata_blocks.items_for(metadata).each do |block|
@@ -1613,9 +1604,13 @@ module RSpec
1613
1604
  # @see #prepend_before
1614
1605
  # @see #after
1615
1606
  # @see #append_after
1616
- def before(*args, &block)
1617
- handle_suite_hook(args, @before_suite_hooks, :push,
1618
- Hooks::BeforeHook, block) || super(*args, &block)
1607
+ def before(scope=nil, *meta, &block)
1608
+ handle_suite_hook(scope, meta) do
1609
+ @before_suite_hooks << Hooks::BeforeHook.new(block, {})
1610
+ end || begin
1611
+ on_existing_matching_groups({}) { |g| g.before(scope, *meta, &block) }
1612
+ super(scope, *meta, &block)
1613
+ end
1619
1614
  end
1620
1615
  alias_method :append_before, :before
1621
1616
 
@@ -1632,9 +1627,13 @@ module RSpec
1632
1627
  # @see #before
1633
1628
  # @see #after
1634
1629
  # @see #append_after
1635
- def prepend_before(*args, &block)
1636
- handle_suite_hook(args, @before_suite_hooks, :unshift,
1637
- Hooks::BeforeHook, block) || super(*args, &block)
1630
+ def prepend_before(scope=nil, *meta, &block)
1631
+ handle_suite_hook(scope, meta) do
1632
+ @before_suite_hooks.unshift Hooks::BeforeHook.new(block, {})
1633
+ end || begin
1634
+ on_existing_matching_groups({}) { |g| g.prepend_before(scope, *meta, &block) }
1635
+ super(scope, *meta, &block)
1636
+ end
1638
1637
  end
1639
1638
 
1640
1639
  # Defines a `after` hook. See {Hooks#after} for full docs.
@@ -1646,9 +1645,13 @@ module RSpec
1646
1645
  # @see #append_after
1647
1646
  # @see #before
1648
1647
  # @see #prepend_before
1649
- def after(*args, &block)
1650
- handle_suite_hook(args, @after_suite_hooks, :unshift,
1651
- Hooks::AfterHook, block) || super(*args, &block)
1648
+ def after(scope=nil, *meta, &block)
1649
+ handle_suite_hook(scope, meta) do
1650
+ @after_suite_hooks.unshift Hooks::AfterHook.new(block, {})
1651
+ end || begin
1652
+ on_existing_matching_groups({}) { |g| g.after(scope, *meta, &block) }
1653
+ super(scope, *meta, &block)
1654
+ end
1652
1655
  end
1653
1656
  alias_method :prepend_after, :after
1654
1657
 
@@ -1665,9 +1668,22 @@ module RSpec
1665
1668
  # @see #append_after
1666
1669
  # @see #before
1667
1670
  # @see #prepend_before
1668
- def append_after(*args, &block)
1669
- handle_suite_hook(args, @after_suite_hooks, :push,
1670
- Hooks::AfterHook, block) || super(*args, &block)
1671
+ def append_after(scope=nil, *meta, &block)
1672
+ handle_suite_hook(scope, meta) do
1673
+ @after_suite_hooks << Hooks::AfterHook.new(block, {})
1674
+ end || begin
1675
+ on_existing_matching_groups({}) { |g| g.append_after(scope, *meta, &block) }
1676
+ super(scope, *meta, &block)
1677
+ end
1678
+ end
1679
+
1680
+ # Registers `block` as an `around` hook.
1681
+ #
1682
+ # See {Hooks#around} for full `around` hook docs.
1683
+ def around(scope=nil, *meta, &block)
1684
+ on_existing_matching_groups({}) { |g| g.around(scope, *meta, &block) }
1685
+
1686
+ super(scope, *meta, &block)
1671
1687
  end
1672
1688
 
1673
1689
  # @private
@@ -1704,11 +1720,10 @@ module RSpec
1704
1720
 
1705
1721
  private
1706
1722
 
1707
- def handle_suite_hook(args, collection, append_or_prepend, hook_type, block)
1708
- scope, meta = *args
1723
+ def handle_suite_hook(scope, meta)
1709
1724
  return nil unless scope == :suite
1710
1725
 
1711
- if meta
1726
+ unless meta.empty?
1712
1727
  # TODO: in RSpec 4, consider raising an error here.
1713
1728
  # We warn only for backwards compatibility.
1714
1729
  RSpec.warn_with "WARNING: `:suite` hooks do not support metadata since " \
@@ -1717,7 +1732,7 @@ module RSpec
1717
1732
  "The metadata you have provided (#{meta.inspect}) will be ignored."
1718
1733
  end
1719
1734
 
1720
- collection.__send__(append_or_prepend, hook_type.new(block, {}))
1735
+ yield
1721
1736
  end
1722
1737
 
1723
1738
  def run_hooks_with(hooks, hook_context)
@@ -1814,7 +1829,7 @@ module RSpec
1814
1829
  end
1815
1830
 
1816
1831
  def assert_no_example_groups_defined(config_option)
1817
- return unless RSpec.world.example_groups.any?
1832
+ return unless world.example_groups.any?
1818
1833
 
1819
1834
  raise MustBeConfiguredBeforeExampleGroupsError.new(
1820
1835
  "RSpec's #{config_option} configuration option must be configured before " \
@@ -1863,6 +1878,44 @@ module RSpec
1863
1878
  @last_run_statuses = nil
1864
1879
  @spec_files_with_failures = nil
1865
1880
  end
1881
+
1882
+ def configure_group_with(group, module_list, application_method)
1883
+ module_list.items_for(group.metadata).each do |mod|
1884
+ __send__(application_method, mod, group)
1885
+ end
1886
+ end
1887
+
1888
+ def on_existing_matching_groups(meta)
1889
+ world.all_example_groups.each do |group|
1890
+ yield group if meta.empty? || MetadataFilter.apply?(:any?, meta, group.metadata)
1891
+ end
1892
+ end
1893
+
1894
+ if RSpec::Support::RubyFeatures.module_prepends_supported?
1895
+ def safe_prepend(mod, host)
1896
+ host.__send__(:prepend, mod) unless host < mod
1897
+ end
1898
+ end
1899
+
1900
+ if RUBY_VERSION.to_f >= 1.9
1901
+ def safe_include(mod, host)
1902
+ host.__send__(:include, mod) unless host < mod
1903
+ end
1904
+
1905
+ def safe_extend(mod, host)
1906
+ host.extend(mod) unless host.singleton_class < mod
1907
+ end
1908
+ else # for 1.8.7
1909
+ # :nocov:
1910
+ def safe_include(mod, host)
1911
+ host.__send__(:include, mod) unless host.included_modules.include?(mod)
1912
+ end
1913
+
1914
+ def safe_extend(mod, host)
1915
+ host.extend(mod) unless (class << host; self; end).included_modules.include?(mod)
1916
+ end
1917
+ # :nocov:
1918
+ end
1866
1919
  end
1867
1920
  # rubocop:enable Metrics/ClassLength
1868
1921
  end
@@ -40,7 +40,9 @@ module RSpec
40
40
  example_group_aliases << name
41
41
 
42
42
  (class << RSpec; self; end).__send__(:define_method, name) do |*args, &example_group_block|
43
- RSpec.world.register RSpec::Core::ExampleGroup.__send__(name, *args, &example_group_block)
43
+ group = RSpec::Core::ExampleGroup.__send__(name, *args, &example_group_block)
44
+ RSpec.world.record(group)
45
+ group
44
46
  end
45
47
 
46
48
  expose_example_group_alias_globally(name) if exposed_globally?
@@ -178,6 +178,16 @@ module RSpec
178
178
  @example_group_class = example_group_class
179
179
  @example_block = example_block
180
180
 
181
+ # Register the example with the group before creating the metadata hash.
182
+ # This is necessary since creating the metadata hash triggers
183
+ # `when_first_matching_example_defined` callbacks, in which users can
184
+ # load RSpec support code which defines hooks. For that to work, the
185
+ # examples and example groups must be registered at the time the
186
+ # support code is called or be defined afterwards.
187
+ # Begin defined beforehand but registered afterwards causes hooks to
188
+ # not be applied where they should.
189
+ example_group_class.examples << self
190
+
181
191
  @metadata = Metadata::ExampleHash.create(
182
192
  @example_group_class.metadata, user_metadata,
183
193
  example_group_class.method(:next_runnable_index_for),
@@ -143,9 +143,7 @@ module RSpec
143
143
  options.update(:skip => RSpec::Core::Pending::NOT_YET_IMPLEMENTED) unless block
144
144
  options.update(extra_options)
145
145
 
146
- example = RSpec::Core::Example.new(self, desc, options, block)
147
- examples << example
148
- example
146
+ RSpec::Core::Example.new(self, desc, options, block)
149
147
  end
150
148
  end
151
149
 
@@ -235,27 +233,27 @@ module RSpec
235
233
  thread_data = RSpec::Support.thread_local_data
236
234
  top_level = self == ExampleGroup
237
235
 
238
- if top_level
239
- if thread_data[:in_example_group]
240
- raise "Creating an isolated context from within a context is " \
241
- "not allowed. Change `RSpec.#{name}` to `#{name}` or " \
242
- "move this to a top-level scope."
236
+ registration_collection =
237
+ if top_level
238
+ if thread_data[:in_example_group]
239
+ raise "Creating an isolated context from within a context is " \
240
+ "not allowed. Change `RSpec.#{name}` to `#{name}` or " \
241
+ "move this to a top-level scope."
242
+ end
243
+
244
+ thread_data[:in_example_group] = true
245
+ RSpec.world.example_groups
246
+ else
247
+ children
243
248
  end
244
249
 
245
- thread_data[:in_example_group] = true
246
- end
247
-
248
250
  begin
249
-
250
251
  description = args.shift
251
252
  combined_metadata = metadata.dup
252
253
  combined_metadata.merge!(args.pop) if args.last.is_a? Hash
253
254
  args << combined_metadata
254
255
 
255
- subclass(self, description, args, &example_group_block).tap do |child|
256
- children << child
257
- end
258
-
256
+ subclass(self, description, args, registration_collection, &example_group_block)
259
257
  ensure
260
258
  thread_data.delete(:in_example_group) if top_level
261
259
  end
@@ -347,7 +345,7 @@ module RSpec
347
345
  @descendant_filtered_examples = nil
348
346
  @_descendants = nil
349
347
  @parent_groups = nil
350
- @declaration_line_numbers = nil
348
+ @declaration_locations = nil
351
349
  end
352
350
 
353
351
  # Adds an example to the example group
@@ -379,9 +377,9 @@ module RSpec
379
377
  # @!endgroup
380
378
 
381
379
  # @private
382
- def self.subclass(parent, description, args, &example_group_block)
380
+ def self.subclass(parent, description, args, registration_collection, &example_group_block)
383
381
  subclass = Class.new(parent)
384
- subclass.set_it_up(description, *args, &example_group_block)
382
+ subclass.set_it_up(description, args, registration_collection, &example_group_block)
385
383
  subclass.module_exec(&example_group_block) if example_group_block
386
384
 
387
385
  # The LetDefinitions module must be included _after_ other modules
@@ -394,7 +392,7 @@ module RSpec
394
392
  end
395
393
 
396
394
  # @private
397
- def self.set_it_up(description, *args, &example_group_block)
395
+ def self.set_it_up(description, args, registration_collection, &example_group_block)
398
396
  # Ruby 1.9 has a bug that can lead to infinite recursion and a
399
397
  # SystemStackError if you include a module in a superclass after
400
398
  # including it in a subclass: https://gist.github.com/845896
@@ -405,6 +403,16 @@ module RSpec
405
403
  # here.
406
404
  ensure_example_groups_are_configured
407
405
 
406
+ # Register the example with the group before creating the metadata hash.
407
+ # This is necessary since creating the metadata hash triggers
408
+ # `when_first_matching_example_defined` callbacks, in which users can
409
+ # load RSpec support code which defines hooks. For that to work, the
410
+ # examples and example groups must be registered at the time the
411
+ # support code is called or be defined afterwards.
412
+ # Begin defined beforehand but registered afterwards causes hooks to
413
+ # not be applied where they should.
414
+ registration_collection << self
415
+
408
416
  user_metadata = Metadata.build_hash_from(args)
409
417
 
410
418
  @metadata = Metadata::ExampleGroupHash.create(
@@ -444,10 +452,19 @@ module RSpec
444
452
  # @private
445
453
  def self.next_runnable_index_for(file)
446
454
  if self == ExampleGroup
447
- RSpec.world.num_example_groups_defined_in(file)
455
+ # We add 1 so the ids start at 1 instead of 0. This is
456
+ # necessary for this branch (but not for the other one)
457
+ # because we register examples and groups with the
458
+ # `children` and `examples` collection BEFORE this
459
+ # method is called as part of metadata hash creation,
460
+ # but the example group is recorded with
461
+ # `RSpec.world.example_group_counts_by_spec_file` AFTER
462
+ # the metadata hash is created and the group is returned
463
+ # to the caller.
464
+ RSpec.world.num_example_groups_defined_in(file) + 1
448
465
  else
449
466
  children.count + examples.count
450
- end + 1
467
+ end
451
468
  end
452
469
 
453
470
  # @private
@@ -613,10 +630,10 @@ module RSpec
613
630
  end
614
631
 
615
632
  # @private
616
- def self.declaration_line_numbers
617
- @declaration_line_numbers ||= [metadata[:line_number]] +
618
- examples.map { |e| e.metadata[:line_number] } +
619
- FlatMap.flat_map(children, &:declaration_line_numbers)
633
+ def self.declaration_locations
634
+ @declaration_locations ||= [Metadata.location_tuple_from(metadata)] +
635
+ examples.map { |e| Metadata.location_tuple_from(e.metadata) } +
636
+ FlatMap.flat_map(children, &:declaration_locations)
620
637
  end
621
638
 
622
639
  # @return [String] the unique id of this example group. Pass
@@ -23,13 +23,6 @@ module RSpec
23
23
  if RSpec::Support::RubyFeatures.ripper_supported?
24
24
  NoExpressionAtLineError = Class.new(StandardError)
25
25
 
26
- PAREN_TOKEN_TYPE_PAIRS = {
27
- :on_lbracket => :on_rbracket,
28
- :on_lparen => :on_rparen,
29
- :on_lbrace => :on_rbrace,
30
- :on_heredoc_beg => :on_heredoc_end
31
- }
32
-
33
26
  attr_reader :source, :beginning_line_number, :max_line_count
34
27
 
35
28
  def self.extract_expression_lines_at(file_path, beginning_line_number, max_line_count=nil)
@@ -64,29 +57,29 @@ module RSpec
64
57
  def line_range_of_expression
65
58
  @line_range_of_expression ||= begin
66
59
  line_range = line_range_of_location_nodes_in_expression
67
- initial_unclosed_parens = unclosed_paren_tokens_in_line_range(line_range)
68
- unclosed_parens = initial_unclosed_parens
60
+ initial_unclosed_tokens = unclosed_tokens_in_line_range(line_range)
61
+ unclosed_tokens = initial_unclosed_tokens
69
62
 
70
- until (initial_unclosed_parens & unclosed_parens).empty?
63
+ until (initial_unclosed_tokens & unclosed_tokens).empty?
71
64
  line_range = (line_range.begin)..(line_range.end + 1)
72
- unclosed_parens = unclosed_paren_tokens_in_line_range(line_range)
65
+ unclosed_tokens = unclosed_tokens_in_line_range(line_range)
73
66
  end
74
67
 
75
68
  line_range
76
69
  end
77
70
  end
78
71
 
79
- def unclosed_paren_tokens_in_line_range(line_range)
72
+ def unclosed_tokens_in_line_range(line_range)
80
73
  tokens = FlatMap.flat_map(line_range) do |line_number|
81
74
  source.tokens_by_line_number[line_number]
82
75
  end
83
76
 
84
77
  tokens.each_with_object([]) do |token, unclosed_tokens|
85
- if PAREN_TOKEN_TYPE_PAIRS.keys.include?(token.type)
78
+ if token.opening?
86
79
  unclosed_tokens << token
87
80
  else
88
81
  index = unclosed_tokens.rindex do |unclosed_token|
89
- PAREN_TOKEN_TYPE_PAIRS[unclosed_token.type] == token.type
82
+ unclosed_token.closed_by?(token)
90
83
  end
91
84
  unclosed_tokens.delete_at(index) if index
92
85
  end
@@ -342,14 +342,7 @@ module RSpec
342
342
  private
343
343
 
344
344
  # @private
345
- class Hook
346
- attr_reader :block, :options
347
-
348
- def initialize(block, options)
349
- @block = block
350
- @options = options
351
- end
352
- end
345
+ Hook = Struct.new(:block, :options)
353
346
 
354
347
  # @private
355
348
  class BeforeHook < Hook
@@ -106,6 +106,11 @@ module RSpec
106
106
  "#{metadata[:rerun_file_path]}[#{metadata[:scoped_id]}]"
107
107
  end
108
108
 
109
+ # @private
110
+ def self.location_tuple_from(metadata)
111
+ [metadata[:absolute_file_path], metadata[:line_number]]
112
+ end
113
+
109
114
  # @private
110
115
  # Used internally to populate metadata hashes with computed keys
111
116
  # managed by RSpec.
@@ -123,7 +128,6 @@ module RSpec
123
128
  def populate
124
129
  ensure_valid_user_keys
125
130
 
126
- metadata[:execution_result] = Example::ExecutionResult.new
127
131
  metadata[:block] = block
128
132
  metadata[:description_args] = description_args
129
133
  metadata[:description] = build_description_from(*metadata[:description_args])
@@ -214,6 +218,7 @@ module RSpec
214
218
  end)
215
219
  group_metadata.update(example_metadata)
216
220
 
221
+ example_metadata[:execution_result] = Example::ExecutionResult.new
217
222
  example_metadata[:example_group] = group_metadata
218
223
  example_metadata[:shared_group_inclusion_backtrace] = SharedExampleGroupInclusionStackFrame.current_backtrace
219
224
  example_metadata.delete(:parent_example_group)
@@ -15,9 +15,9 @@ module RSpec
15
15
  # @private
16
16
  def filter_applies?(key, value, metadata)
17
17
  silence_metadata_example_group_deprecations do
18
- return location_filter_applies?(value, metadata) if key == :locations
19
- return id_filter_applies?(value, metadata) if key == :ids
20
- return filters_apply?(key, value, metadata) if Hash === value
18
+ return location_filter_applies?(value, metadata) if key == :locations
19
+ return id_filter_applies?(value, metadata) if key == :ids
20
+ return filters_apply?(key, value, metadata) if Hash === value
21
21
 
22
22
  return false unless metadata.key?(key)
23
23
  return true if TrueClass === value && !!metadata[key]
@@ -49,13 +49,14 @@ module RSpec
49
49
  end
50
50
 
51
51
  def location_filter_applies?(locations, metadata)
52
- line_numbers = example_group_declaration_lines(locations, metadata)
53
- line_number_filter_applies?(line_numbers, metadata)
54
- end
52
+ Metadata.ascend(metadata).any? do |meta|
53
+ file_path = meta[:absolute_file_path]
54
+ line_num = meta[:line_number]
55
55
 
56
- def line_number_filter_applies?(line_numbers, metadata)
57
- preceding_declaration_lines = line_numbers.map { |n| RSpec.world.preceding_declaration_line(n) }
58
- !(relevant_line_numbers(metadata) & preceding_declaration_lines).empty?
56
+ locations[file_path].any? do |filter_line_num|
57
+ line_num == RSpec.world.preceding_declaration_line(file_path, filter_line_num)
58
+ end
59
+ end
59
60
  end
60
61
 
61
62
  def proc_filter_applies?(key, proc, metadata)
@@ -66,16 +67,6 @@ module RSpec
66
67
  end
67
68
  end
68
69
 
69
- def relevant_line_numbers(metadata)
70
- Metadata.ascend(metadata).map { |meta| meta[:line_number] }
71
- end
72
-
73
- def example_group_declaration_lines(locations, metadata)
74
- FlatMap.flat_map(Metadata.ascend(metadata)) do |meta|
75
- locations[meta[:absolute_file_path]]
76
- end.uniq
77
- end
78
-
79
70
  def filters_apply?(key, value, metadata)
80
71
  subhash = metadata[key]
81
72
  return false unless Hash === subhash || HashImitatable === subhash
@@ -81,14 +81,14 @@ module RSpec
81
81
 
82
82
  return unless fail_on_error
83
83
  $stderr.puts "#{command} failed" if verbose
84
- exit $?.exitstatus
84
+ exit $?.exitstatus || 1
85
85
  end
86
86
 
87
87
  private
88
88
 
89
89
  # @private
90
90
  def define(args, &task_block)
91
- desc "Run RSpec code examples" unless ::Rake.application.last_comment
91
+ desc "Run RSpec code examples" unless ::Rake.application.last_description
92
92
 
93
93
  task name, *args do |_, task_args|
94
94
  RakeFileUtils.__send__(:verbose, verbose) do
@@ -150,19 +150,28 @@ module RSpec
150
150
  end
151
151
 
152
152
  # @private
153
- # rubocop:disable Lint/EnsureReturn
154
153
  def self.running_in_drb?
155
- if defined?(DRb) && DRb.current_server && DRb.current_server.alive?
156
- require 'socket'
157
- require 'uri'
158
- local_ipv4 = IPSocket.getaddress(Socket.gethostname)
159
- local_drb = ["127.0.0.1", "localhost", local_ipv4].any? { |addr| addr == URI(DRb.current_server.uri).host }
160
- end
161
- rescue DRb::DRbServerNotFound
162
- ensure
163
- return local_drb || false
154
+ return false unless defined?(DRb)
155
+
156
+ server = begin
157
+ DRb.current_server
158
+ rescue DRb::DRbServerNotFound
159
+ return false
160
+ end
161
+
162
+ return false unless server && server.alive?
163
+
164
+ require 'socket'
165
+ require 'uri'
166
+
167
+ local_ipv4 = begin
168
+ IPSocket.getaddress(Socket.gethostname)
169
+ rescue SocketError
170
+ return false
171
+ end
172
+
173
+ ["127.0.0.1", "localhost", local_ipv4].any? { |addr| addr == URI(DRb.current_server.uri).host }
164
174
  end
165
- # rubocop:enable Lint/EnsureReturn
166
175
 
167
176
  # @private
168
177
  def self.trap_interrupt
@@ -175,7 +184,7 @@ module RSpec
175
184
  exit!(1)
176
185
  else
177
186
  RSpec.world.wants_to_quit = true
178
- STDERR.puts "\nRSpec is shutting down and will print the summary report... Interrupt again to force quit."
187
+ $stderr.puts "\nRSpec is shutting down and will print the summary report... Interrupt again to force quit."
179
188
  end
180
189
  end
181
190
  end
@@ -6,6 +6,17 @@ module RSpec
6
6
  # @private
7
7
  # A wrapper for Ripper token which is generated with `Ripper.lex`.
8
8
  class Token
9
+ CLOSING_TYPES_BY_OPENING_TYPE = {
10
+ :on_lbracket => :on_rbracket,
11
+ :on_lparen => :on_rparen,
12
+ :on_lbrace => :on_rbrace,
13
+ :on_heredoc_beg => :on_heredoc_end
14
+ }.freeze
15
+
16
+ CLOSING_KEYWORDS_BY_OPENING_KEYWORD = {
17
+ 'do' => 'end'
18
+ }.freeze
19
+
9
20
  attr_reader :token
10
21
 
11
22
  def self.tokens_from_ripper_tokens(ripper_tokens)
@@ -37,6 +48,38 @@ module RSpec
37
48
  def inspect
38
49
  "#<#{self.class} #{type} #{string.inspect}>"
39
50
  end
51
+
52
+ def keyword?
53
+ type == :on_kw
54
+ end
55
+
56
+ def opening?
57
+ opening_delimiter? || opening_keyword?
58
+ end
59
+
60
+ def closed_by?(other)
61
+ closed_by_delimiter?(other) || closed_by_keyword?(other)
62
+ end
63
+
64
+ private
65
+
66
+ def opening_delimiter?
67
+ CLOSING_TYPES_BY_OPENING_TYPE.key?(type)
68
+ end
69
+
70
+ def opening_keyword?
71
+ return false unless keyword?
72
+ CLOSING_KEYWORDS_BY_OPENING_KEYWORD.key?(string)
73
+ end
74
+
75
+ def closed_by_delimiter?(other)
76
+ other.type == CLOSING_TYPES_BY_OPENING_TYPE[type]
77
+ end
78
+
79
+ def closed_by_keyword?(other)
80
+ return false unless other.keyword?
81
+ other.string == CLOSING_KEYWORDS_BY_OPENING_KEYWORD[string]
82
+ end
40
83
  end
41
84
  end
42
85
  end
@@ -3,7 +3,7 @@ module RSpec
3
3
  # Version information for RSpec Core.
4
4
  module Version
5
5
  # Current version of RSpec Core, in semantic versioning format.
6
- STRING = '3.5.0.beta1'
6
+ STRING = '3.5.0.beta2'
7
7
  end
8
8
  end
9
9
  end
@@ -12,6 +12,7 @@ module RSpec
12
12
 
13
13
  def initialize(configuration=RSpec.configuration)
14
14
  @configuration = configuration
15
+ configuration.world = self
15
16
  @example_groups = []
16
17
  @example_group_counts_by_spec_file = Hash.new(0)
17
18
  @filtered_examples = Hash.new do |hash, group|
@@ -47,12 +48,10 @@ module RSpec
47
48
 
48
49
  # @api private
49
50
  #
50
- # Register an example group.
51
- def register(example_group)
51
+ # Records an example group.
52
+ def record(example_group)
52
53
  @configuration.on_example_group_definition_callbacks.each { |block| block.call(example_group) }
53
- example_groups << example_group
54
54
  @example_group_counts_by_spec_file[example_group.metadata[:absolute_file_path]] += 1
55
- example_group
56
55
  end
57
56
 
58
57
  # @private
@@ -96,10 +95,12 @@ module RSpec
96
95
  # @api private
97
96
  #
98
97
  # Find line number of previous declaration.
99
- def preceding_declaration_line(filter_line)
100
- declaration_line_numbers.sort.inject(nil) do |highest_prior_declaration_line, line|
101
- line <= filter_line ? line : highest_prior_declaration_line
98
+ def preceding_declaration_line(absolute_file_name, filter_line)
99
+ line_numbers = descending_declaration_line_numbers_by_file.fetch(absolute_file_name) do
100
+ return nil
102
101
  end
102
+
103
+ line_numbers.find { |num| num <= filter_line }
103
104
  end
104
105
 
105
106
  # @private
@@ -179,8 +180,22 @@ module RSpec
179
180
 
180
181
  private
181
182
 
182
- def declaration_line_numbers
183
- @declaration_line_numbers ||= FlatMap.flat_map(example_groups, &:declaration_line_numbers)
183
+ def descending_declaration_line_numbers_by_file
184
+ @descending_declaration_line_numbers_by_file ||= begin
185
+ declaration_locations = FlatMap.flat_map(example_groups, &:declaration_locations)
186
+ hash_of_arrays = Hash.new { |h, k| h[k] = [] }
187
+
188
+ # TODO: change `inject` to `each_with_object` when we drop 1.8.7 support.
189
+ line_nums_by_file = declaration_locations.inject(hash_of_arrays) do |hash, (file_name, line_number)|
190
+ hash[file_name] << line_number
191
+ hash
192
+ end
193
+
194
+ line_nums_by_file.each_value do |list|
195
+ list.sort!
196
+ list.reverse!
197
+ end
198
+ end
184
199
  end
185
200
 
186
201
  def fail_if_config_and_cli_options_invalid
@@ -192,6 +207,24 @@ module RSpec
192
207
  1 # exit code
193
208
  )
194
209
  end
210
+
211
+ # @private
212
+ # Provides a null implementation for initial use by configuration.
213
+ module Null
214
+ def self.registered_example_group_files
215
+ []
216
+ end
217
+
218
+ # :nocov:
219
+ def self.example_groups
220
+ []
221
+ end
222
+
223
+ def self.all_example_groups
224
+ []
225
+ end
226
+ # :nocov:
227
+ end
195
228
  end
196
229
  end
197
230
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.5.0.beta1
4
+ version: 3.5.0.beta2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steven Baker
@@ -46,7 +46,7 @@ cert_chain:
46
46
  ZsVDj6a7lH3cNqtWXZxrb2wO38qV5AkYj8SQK7Hj3/Yui9myUX3crr+PdetazSqQ
47
47
  F3MdtaDehhjC
48
48
  -----END CERTIFICATE-----
49
- date: 2016-02-06 00:00:00.000000000 Z
49
+ date: 2016-03-10 00:00:00.000000000 Z
50
50
  dependencies:
51
51
  - !ruby/object:Gem::Dependency
52
52
  name: rspec-support
@@ -54,28 +54,14 @@ dependencies:
54
54
  requirements:
55
55
  - - '='
56
56
  - !ruby/object:Gem::Version
57
- version: 3.5.0.beta1
57
+ version: 3.5.0.beta2
58
58
  type: :runtime
59
59
  prerelease: false
60
60
  version_requirements: !ruby/object:Gem::Requirement
61
61
  requirements:
62
62
  - - '='
63
63
  - !ruby/object:Gem::Version
64
- version: 3.5.0.beta1
65
- - !ruby/object:Gem::Dependency
66
- name: rake
67
- requirement: !ruby/object:Gem::Requirement
68
- requirements:
69
- - - "~>"
70
- - !ruby/object:Gem::Version
71
- version: 10.0.0
72
- type: :development
73
- prerelease: false
74
- version_requirements: !ruby/object:Gem::Requirement
75
- requirements:
76
- - - "~>"
77
- - !ruby/object:Gem::Version
78
- version: 10.0.0
64
+ version: 3.5.0.beta2
79
65
  - !ruby/object:Gem::Dependency
80
66
  name: cucumber
81
67
  requirement: !ruby/object:Gem::Requirement
@@ -293,9 +279,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
293
279
  version: 1.3.1
294
280
  requirements: []
295
281
  rubyforge_project:
296
- rubygems_version: 2.4.5.1
282
+ rubygems_version: 2.5.1
297
283
  signing_key:
298
284
  specification_version: 4
299
- summary: rspec-core-3.5.0.beta1
285
+ summary: rspec-core-3.5.0.beta2
300
286
  test_files: []
301
287
  has_rdoc:
metadata.gz.sig CHANGED
Binary file