activesupport 4.1.15 → 4.2.11.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (111) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +395 -574
  3. data/README.rdoc +7 -2
  4. data/lib/active_support.rb +19 -0
  5. data/lib/active_support/backtrace_cleaner.rb +4 -4
  6. data/lib/active_support/cache.rb +17 -19
  7. data/lib/active_support/cache/file_store.rb +5 -0
  8. data/lib/active_support/cache/mem_cache_store.rb +1 -1
  9. data/lib/active_support/cache/strategy/local_cache.rb +5 -4
  10. data/lib/active_support/cache/strategy/local_cache_middleware.rb +5 -0
  11. data/lib/active_support/callbacks.rb +41 -33
  12. data/lib/active_support/concern.rb +10 -2
  13. data/lib/active_support/core_ext/array/access.rb +9 -1
  14. data/lib/active_support/core_ext/array/grouping.rb +5 -0
  15. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +2 -0
  16. data/lib/active_support/core_ext/class/delegating_attributes.rb +4 -0
  17. data/lib/active_support/core_ext/class/subclasses.rb +0 -2
  18. data/lib/active_support/core_ext/date/conversions.rb +6 -0
  19. data/lib/active_support/core_ext/date_and_time/calculations.rb +11 -0
  20. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  21. data/lib/active_support/core_ext/date_time.rb +1 -0
  22. data/lib/active_support/core_ext/date_time/calculations.rb +34 -4
  23. data/lib/active_support/core_ext/date_time/compatibility.rb +16 -0
  24. data/lib/active_support/core_ext/date_time/conversions.rb +2 -2
  25. data/lib/active_support/core_ext/digest/uuid.rb +51 -0
  26. data/lib/active_support/core_ext/enumerable.rb +16 -0
  27. data/lib/active_support/core_ext/file/atomic.rb +1 -1
  28. data/lib/active_support/core_ext/hash.rb +1 -0
  29. data/lib/active_support/core_ext/hash/compact.rb +20 -16
  30. data/lib/active_support/core_ext/hash/conversions.rb +3 -5
  31. data/lib/active_support/core_ext/hash/except.rb +8 -2
  32. data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -1
  33. data/lib/active_support/core_ext/hash/keys.rb +10 -6
  34. data/lib/active_support/core_ext/hash/slice.rb +8 -2
  35. data/lib/active_support/core_ext/hash/transform_values.rb +23 -0
  36. data/lib/active_support/core_ext/integer/time.rb +0 -15
  37. data/lib/active_support/core_ext/kernel.rb +3 -2
  38. data/lib/active_support/core_ext/kernel/concern.rb +10 -0
  39. data/lib/active_support/core_ext/kernel/debugger.rb +1 -1
  40. data/lib/active_support/core_ext/kernel/reporting.rb +15 -0
  41. data/lib/active_support/core_ext/load_error.rb +4 -1
  42. data/lib/active_support/core_ext/marshal.rb +8 -5
  43. data/lib/active_support/core_ext/module/aliasing.rb +2 -2
  44. data/lib/active_support/core_ext/module/delegation.rb +34 -18
  45. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -1
  46. data/lib/active_support/core_ext/numeric/conversions.rb +11 -3
  47. data/lib/active_support/core_ext/numeric/time.rb +1 -34
  48. data/lib/active_support/core_ext/object.rb +1 -0
  49. data/lib/active_support/core_ext/object/blank.rb +2 -2
  50. data/lib/active_support/core_ext/object/duplicable.rb +62 -33
  51. data/lib/active_support/core_ext/object/itself.rb +15 -0
  52. data/lib/active_support/core_ext/object/json.rb +2 -2
  53. data/lib/active_support/core_ext/object/to_query.rb +2 -1
  54. data/lib/active_support/core_ext/object/try.rb +35 -13
  55. data/lib/active_support/core_ext/object/with_options.rb +30 -3
  56. data/lib/active_support/core_ext/string/access.rb +5 -5
  57. data/lib/active_support/core_ext/string/conversions.rb +1 -1
  58. data/lib/active_support/core_ext/string/filters.rb +44 -6
  59. data/lib/active_support/core_ext/string/inflections.rb +4 -1
  60. data/lib/active_support/core_ext/string/output_safety.rb +33 -14
  61. data/lib/active_support/core_ext/thread.rb +7 -0
  62. data/lib/active_support/core_ext/time.rb +1 -0
  63. data/lib/active_support/core_ext/time/calculations.rb +31 -7
  64. data/lib/active_support/core_ext/time/compatibility.rb +14 -0
  65. data/lib/active_support/core_ext/time/conversions.rb +1 -1
  66. data/lib/active_support/dependencies.rb +32 -18
  67. data/lib/active_support/dependencies/autoload.rb +1 -1
  68. data/lib/active_support/deprecation.rb +1 -1
  69. data/lib/active_support/deprecation/behaviors.rb +1 -1
  70. data/lib/active_support/duration.rb +47 -5
  71. data/lib/active_support/gem_version.rb +4 -4
  72. data/lib/active_support/hash_with_indifferent_access.rb +35 -7
  73. data/lib/active_support/i18n_railtie.rb +1 -7
  74. data/lib/active_support/inflector/inflections.rb +2 -2
  75. data/lib/active_support/inflector/methods.rb +43 -19
  76. data/lib/active_support/json/decoding.rb +1 -1
  77. data/lib/active_support/json/encoding.rb +3 -2
  78. data/lib/active_support/logger.rb +36 -0
  79. data/lib/active_support/logger_silence.rb +4 -22
  80. data/lib/active_support/logger_thread_safe_level.rb +32 -0
  81. data/lib/active_support/message_encryptor.rb +10 -2
  82. data/lib/active_support/message_verifier.rb +11 -12
  83. data/lib/active_support/multibyte/chars.rb +1 -1
  84. data/lib/active_support/multibyte/unicode.rb +5 -4
  85. data/lib/active_support/notifications.rb +8 -3
  86. data/lib/active_support/notifications/fanout.rb +12 -7
  87. data/lib/active_support/number_helper.rb +12 -13
  88. data/lib/active_support/number_helper/number_to_currency_converter.rb +1 -1
  89. data/lib/active_support/number_helper/number_to_percentage_converter.rb +1 -1
  90. data/lib/active_support/number_helper/number_to_rounded_converter.rb +1 -1
  91. data/lib/active_support/per_thread_registry.rb +5 -3
  92. data/lib/active_support/test_case.rb +46 -12
  93. data/lib/active_support/testing/assertions.rb +1 -1
  94. data/lib/active_support/testing/constant_lookup.rb +1 -5
  95. data/lib/active_support/testing/declarative.rb +1 -25
  96. data/lib/active_support/testing/isolation.rb +16 -6
  97. data/lib/active_support/testing/tagged_logging.rb +1 -1
  98. data/lib/active_support/testing/time_helpers.rb +23 -16
  99. data/lib/active_support/time.rb +0 -2
  100. data/lib/active_support/time_with_zone.rb +48 -29
  101. data/lib/active_support/values/time_zone.rb +81 -75
  102. data/lib/active_support/values/unicode_tables.dat +0 -0
  103. data/lib/active_support/xml_mini.rb +30 -15
  104. data/lib/active_support/xml_mini/libxml.rb +1 -3
  105. data/lib/active_support/xml_mini/libxmlsax.rb +1 -4
  106. data/lib/active_support/xml_mini/nokogiri.rb +1 -3
  107. data/lib/active_support/xml_mini/nokogirisax.rb +1 -3
  108. data/lib/active_support/xml_mini/rexml.rb +1 -3
  109. metadata +21 -36
  110. data/lib/active_support/core_ext/object/to_json.rb +0 -5
  111. data/lib/active_support/file_watcher.rb +0 -36
@@ -1,5 +1,6 @@
1
1
  require 'base64'
2
2
  require 'active_support/core_ext/object/blank'
3
+ require 'active_support/security_utils'
3
4
 
4
5
  module ActiveSupport
5
6
  # +MessageVerifier+ makes it easy to generate and verify messages which are
@@ -27,18 +28,19 @@ module ActiveSupport
27
28
  class InvalidSignature < StandardError; end
28
29
 
29
30
  def initialize(secret, options = {})
31
+ raise ArgumentError, 'Secret should not be nil.' unless secret
30
32
  @secret = secret
31
33
  @digest = options[:digest] || 'SHA1'
32
34
  @serializer = options[:serializer] || Marshal
33
35
  end
34
36
 
35
37
  def verify(signed_message)
36
- raise InvalidSignature if signed_message.blank?
38
+ raise InvalidSignature if signed_message.nil? || !signed_message.valid_encoding? || signed_message.blank?
37
39
 
38
40
  data, digest = signed_message.split("--")
39
- if data.present? && digest.present? && secure_compare(digest, generate_digest(data))
41
+ if data.present? && digest.present? && ActiveSupport::SecurityUtils.secure_compare(digest, generate_digest(data))
40
42
  begin
41
- @serializer.load(::Base64.strict_decode64(data))
43
+ @serializer.load(decode(data))
42
44
  rescue ArgumentError => argument_error
43
45
  raise InvalidSignature if argument_error.message =~ %r{invalid base64}
44
46
  raise
@@ -49,20 +51,17 @@ module ActiveSupport
49
51
  end
50
52
 
51
53
  def generate(value)
52
- data = ::Base64.strict_encode64(@serializer.dump(value))
54
+ data = encode(@serializer.dump(value))
53
55
  "#{data}--#{generate_digest(data)}"
54
56
  end
55
57
 
56
58
  private
57
- # constant-time comparison algorithm to prevent timing attacks
58
- def secure_compare(a, b)
59
- return false unless a.bytesize == b.bytesize
60
-
61
- l = a.unpack "C#{a.bytesize}"
59
+ def encode(data)
60
+ ::Base64.strict_encode64(data)
61
+ end
62
62
 
63
- res = 0
64
- b.each_byte { |byte| res |= byte ^ l.shift }
65
- res == 0
63
+ def decode(data)
64
+ ::Base64.strict_decode64(data)
66
65
  end
67
66
 
68
67
  def generate_digest(data)
@@ -86,7 +86,7 @@ module ActiveSupport #:nodoc:
86
86
  @wrapped_string.split(*args).map { |i| self.class.new(i) }
87
87
  end
88
88
 
89
- # Works like like <tt>String#slice!</tt>, but returns an instance of
89
+ # Works like <tt>String#slice!</tt>, but returns an instance of
90
90
  # Chars, or nil if the string was not modified.
91
91
  def slice!(*args)
92
92
  chars(@wrapped_string.slice!(*args))
@@ -11,7 +11,7 @@ module ActiveSupport
11
11
  NORMALIZATION_FORMS = [:c, :kc, :d, :kd]
12
12
 
13
13
  # The Unicode version that is supported by the implementation
14
- UNICODE_VERSION = '6.3.0'
14
+ UNICODE_VERSION = '7.0.0'
15
15
 
16
16
  # The default normalization used for operations that require
17
17
  # normalization. It can be set to any of the normalizations
@@ -212,7 +212,8 @@ module ActiveSupport
212
212
  end
213
213
 
214
214
  # Ruby >= 2.1 has String#scrub, which is faster than the workaround used for < 2.1.
215
- if '<3'.respond_to?(:scrub)
215
+ # Rubinius' String#scrub, however, doesn't support ASCII-incompatible chars.
216
+ if '<3'.respond_to?(:scrub) && !defined?(Rubinius)
216
217
  # Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
217
218
  # resulting in a valid UTF-8 string.
218
219
  #
@@ -334,7 +335,7 @@ module ActiveSupport
334
335
  begin
335
336
  @codepoints, @composition_exclusion, @composition_map, @boundary, @cp1252 = File.open(self.class.filename, 'rb') { |f| Marshal.load f.read }
336
337
  rescue => e
337
- raise IOError.new("Couldn't load the Unicode tables for UTF8Handler (#{e.message}), ActiveSupport::Multibyte is unusable")
338
+ raise IOError.new("Couldn't load the Unicode tables for UTF8Handler (#{e.message}), ActiveSupport::Multibyte is unusable")
338
339
  end
339
340
 
340
341
  # Redefine the === method so we can write shorter rules for grapheme cluster breaks
@@ -366,6 +367,7 @@ module ActiveSupport
366
367
  private
367
368
 
368
369
  def apply_mapping(string, mapping) #:nodoc:
370
+ database.codepoints
369
371
  string.each_codepoint.map do |codepoint|
370
372
  cp = database.codepoints[codepoint]
371
373
  if cp and (ncp = cp.send(mapping)) and ncp > 0
@@ -383,7 +385,6 @@ module ActiveSupport
383
385
  def database
384
386
  @database ||= UnicodeDatabase.new
385
387
  end
386
-
387
388
  end
388
389
  end
389
390
  end
@@ -16,7 +16,7 @@ module ActiveSupport
16
16
  # render text: 'Foo'
17
17
  # end
18
18
  #
19
- # That executes the block first and notifies all subscribers once done.
19
+ # That first executes the block and then notifies all subscribers once done.
20
20
  #
21
21
  # In the example above +render+ is the name of the event, and the rest is called
22
22
  # the _payload_. The payload is a mechanism that allows instrumenters to pass
@@ -141,6 +141,11 @@ module ActiveSupport
141
141
  #
142
142
  # ActiveSupport::Notifications.unsubscribe(subscriber)
143
143
  #
144
+ # You can also unsubscribe by passing the name of the subscriber object. Note
145
+ # that this will unsubscribe all subscriptions with the given name:
146
+ #
147
+ # ActiveSupport::Notifications.unsubscribe("render")
148
+ #
144
149
  # == Default Queue
145
150
  #
146
151
  # Notifications ships with a queue implementation that consumes and publishes events
@@ -173,8 +178,8 @@ module ActiveSupport
173
178
  unsubscribe(subscriber)
174
179
  end
175
180
 
176
- def unsubscribe(args)
177
- notifier.unsubscribe(args)
181
+ def unsubscribe(subscriber_or_name)
182
+ notifier.unsubscribe(subscriber_or_name)
178
183
  end
179
184
 
180
185
  def instrumenter
@@ -25,9 +25,15 @@ module ActiveSupport
25
25
  subscriber
26
26
  end
27
27
 
28
- def unsubscribe(subscriber)
28
+ def unsubscribe(subscriber_or_name)
29
29
  synchronize do
30
- @subscribers.reject! { |s| s.matches?(subscriber) }
30
+ case subscriber_or_name
31
+ when String
32
+ @subscribers.reject! { |s| s.matches?(subscriber_or_name) }
33
+ else
34
+ @subscribers.delete(subscriber_or_name)
35
+ end
36
+
31
37
  @listeners_for.clear
32
38
  end
33
39
  end
@@ -97,16 +103,15 @@ module ActiveSupport
97
103
  end
98
104
 
99
105
  def subscribed_to?(name)
100
- @pattern === name.to_s
106
+ @pattern === name
101
107
  end
102
108
 
103
- def matches?(subscriber_or_name)
104
- self === subscriber_or_name ||
105
- @pattern && @pattern === subscriber_or_name
109
+ def matches?(name)
110
+ @pattern && @pattern === name
106
111
  end
107
112
  end
108
113
 
109
- class Timed < Evented
114
+ class Timed < Evented # :nodoc:
110
115
  def publish(name, *args)
111
116
  @delegate.call name, *args
112
117
  end
@@ -232,12 +232,8 @@ module ActiveSupport
232
232
  # number_to_human_size(1234567, precision: 2) # => 1.2 MB
233
233
  # number_to_human_size(483989, precision: 2) # => 470 KB
234
234
  # number_to_human_size(1234567, precision: 2, separator: ',') # => 1,2 MB
235
- #
236
- # Non-significant zeros after the fractional separator are stripped out by
237
- # default (set <tt>:strip_insignificant_zeros</tt> to +false+ to change that):
238
- #
239
- # number_to_human_size(1234567890123, precision: 5) # => "1.1229 TB"
240
- # number_to_human_size(524288000, precision: 5) # => "500 MB"
235
+ # number_to_human_size(1234567890123, precision: 5) # => "1.1228 TB"
236
+ # number_to_human_size(524288000, precision: 5) # => "500 MB"
241
237
  def number_to_human_size(number, options = {})
242
238
  NumberToHumanSizeConverter.convert(number, options)
243
239
  end
@@ -276,12 +272,12 @@ module ActiveSupport
276
272
  # string containing an i18n scope where to find this hash. It
277
273
  # might have the following keys:
278
274
  # * *integers*: <tt>:unit</tt>, <tt>:ten</tt>,
279
- # *<tt>:hundred</tt>, <tt>:thousand</tt>, <tt>:million</tt>,
280
- # *<tt>:billion</tt>, <tt>:trillion</tt>,
281
- # *<tt>:quadrillion</tt>
275
+ # <tt>:hundred</tt>, <tt>:thousand</tt>, <tt>:million</tt>,
276
+ # <tt>:billion</tt>, <tt>:trillion</tt>,
277
+ # <tt>:quadrillion</tt>
282
278
  # * *fractionals*: <tt>:deci</tt>, <tt>:centi</tt>,
283
- # *<tt>:mili</tt>, <tt>:micro</tt>, <tt>:nano</tt>,
284
- # *<tt>:pico</tt>, <tt>:femto</tt>
279
+ # <tt>:mili</tt>, <tt>:micro</tt>, <tt>:nano</tt>,
280
+ # <tt>:pico</tt>, <tt>:femto</tt>
285
281
  # * <tt>:format</tt> - Sets the format of the output string
286
282
  # (defaults to "%n %u"). The field types are:
287
283
  # * %u - The quantifier (ex.: 'thousand')
@@ -305,12 +301,15 @@ module ActiveSupport
305
301
  # separator: ',',
306
302
  # significant: false) # => "1,2 Million"
307
303
  #
304
+ # number_to_human(500000000, precision: 5) # => "500 Million"
305
+ # number_to_human(12345012345, significant: false) # => "12.345 Billion"
306
+ #
308
307
  # Non-significant zeros after the decimal separator are stripped
309
308
  # out by default (set <tt>:strip_insignificant_zeros</tt> to
310
309
  # +false+ to change that):
311
310
  #
312
- # number_to_human(12345012345, significant_digits: 6) # => "12.345 Billion"
313
- # number_to_human(500000000, precision: 5) # => "500 Million"
311
+ # number_to_human(12.00001) # => "12"
312
+ # number_to_human(12.00001, strip_insignificant_zeros: false) # => "12.0"
314
313
  #
315
314
  # ==== Custom Unit Quantifiers
316
315
  #
@@ -13,7 +13,7 @@ module ActiveSupport
13
13
  end
14
14
 
15
15
  rounded_number = NumberToRoundedConverter.convert(number, options)
16
- format.gsub('%n', rounded_number).gsub('%u', options[:unit])
16
+ format.gsub(/%n/, rounded_number).gsub(/%u/, options[:unit])
17
17
  end
18
18
 
19
19
  private
@@ -5,7 +5,7 @@ module ActiveSupport
5
5
 
6
6
  def convert
7
7
  rounded_number = NumberToRoundedConverter.convert(number, options)
8
- options[:format].gsub('%n', rounded_number)
8
+ options[:format].gsub(/%n/, rounded_number)
9
9
  end
10
10
  end
11
11
  end
@@ -33,7 +33,7 @@ module ActiveSupport
33
33
  a, b = s.split('.', 2)
34
34
  a + '.' + b[0, precision]
35
35
  else
36
- "%01.#{precision}f" % rounded_number
36
+ "%00.#{precision}f" % rounded_number
37
37
  end
38
38
 
39
39
  delimited_number = NumberToDelimitedConverter.convert(formatted_string, options)
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/module/delegation'
2
+
1
3
  module ActiveSupport
2
4
  # This module is used to encapsulate access to thread local variables.
3
5
  #
@@ -43,9 +45,9 @@ module ActiveSupport
43
45
  protected
44
46
  def method_missing(name, *args, &block) # :nodoc:
45
47
  # Caches the method definition as a singleton method of the receiver.
46
- define_singleton_method(name) do |*a, &b|
47
- instance.public_send(name, *a, &b)
48
- end
48
+ #
49
+ # By letting #delegate handle it, we avoid an enclosure that'll capture args.
50
+ singleton_class.delegate name, to: :instance
49
51
 
50
52
  send(name, *args, &block)
51
53
  end
@@ -11,25 +11,59 @@ require 'active_support/testing/time_helpers'
11
11
  require 'active_support/core_ext/kernel/reporting'
12
12
  require 'active_support/deprecation'
13
13
 
14
- begin
15
- silence_warnings { require 'mocha/setup' }
16
- rescue LoadError
17
- end
18
-
19
14
  module ActiveSupport
20
15
  class TestCase < ::Minitest::Test
21
16
  Assertion = Minitest::Assertion
22
17
 
23
- alias_method :method_name, :name
18
+ class << self
19
+ # Sets the order in which test cases are run.
20
+ #
21
+ # ActiveSupport::TestCase.test_order = :random # => :random
22
+ #
23
+ # Valid values are:
24
+ # * +:random+ (to run tests in random order)
25
+ # * +:parallel+ (to run tests in parallel)
26
+ # * +:sorted+ (to run tests alphabetically by method name)
27
+ # * +:alpha+ (equivalent to +:sorted+)
28
+ def test_order=(new_order)
29
+ ActiveSupport.test_order = new_order
30
+ end
31
+
32
+ # Returns the order in which test cases are run.
33
+ #
34
+ # ActiveSupport::TestCase.test_order # => :sorted
35
+ #
36
+ # Possible values are +:random+, +:parallel+, +:alpha+, +:sorted+.
37
+ # Defaults to +:sorted+.
38
+ def test_order
39
+ test_order = ActiveSupport.test_order
24
40
 
25
- $tags = {}
26
- def self.for_tag(tag)
27
- yield if $tags[tag]
41
+ if test_order.nil?
42
+ ActiveSupport::Deprecation.warn "You did not specify a value for the " \
43
+ "configuration option `active_support.test_order`. In Rails 5, " \
44
+ "the default value of this option will change from `:sorted` to " \
45
+ "`:random`.\n" \
46
+ "To disable this warning and keep the current behavior, you can add " \
47
+ "the following line to your `config/environments/test.rb`:\n" \
48
+ "\n" \
49
+ " Rails.application.configure do\n" \
50
+ " config.active_support.test_order = :sorted\n" \
51
+ " end\n" \
52
+ "\n" \
53
+ "Alternatively, you can opt into the future behavior by setting this " \
54
+ "option to `:random`."
55
+
56
+ test_order = :sorted
57
+ self.test_order = test_order
58
+ end
59
+
60
+ test_order
61
+ end
62
+
63
+ alias :my_tests_are_order_dependent! :i_suck_and_my_tests_are_order_dependent!
28
64
  end
29
65
 
30
- # FIXME: we have tests that depend on run order, we should fix that and
31
- # remove this method call.
32
- self.i_suck_and_my_tests_are_order_dependent!
66
+ alias_method :method_name, :name
33
67
 
34
68
  include ActiveSupport::Testing::TaggedLogging
35
69
  include ActiveSupport::Testing::SetupAndTeardown
@@ -9,7 +9,7 @@ module ActiveSupport
9
9
  #
10
10
  # assert_not nil # => true
11
11
  # assert_not false # => true
12
- # assert_not 'foo' # => 'foo' is not nil or false
12
+ # assert_not 'foo' # => Expected "foo" to be nil or false
13
13
  #
14
14
  # An error message can be specified.
15
15
  #
@@ -36,12 +36,8 @@ module ActiveSupport
36
36
  while names.size > 0 do
37
37
  names.last.sub!(/Test$/, "")
38
38
  begin
39
- constant = names.join("::").constantize
39
+ constant = names.join("::").safe_constantize
40
40
  break(constant) if yield(constant)
41
- rescue NoMethodError # subclass of NameError
42
- raise
43
- rescue NameError
44
- # Constant wasn't found, move on
45
41
  ensure
46
42
  names.pop
47
43
  end
@@ -1,30 +1,6 @@
1
1
  module ActiveSupport
2
2
  module Testing
3
3
  module Declarative
4
-
5
- def self.extended(klass) #:nodoc:
6
- klass.class_eval do
7
-
8
- unless method_defined?(:describe)
9
- def self.describe(text)
10
- if block_given?
11
- super
12
- else
13
- message = "`describe` without a block is deprecated, please switch to: `def self.name; #{text.inspect}; end`\n"
14
- ActiveSupport::Deprecation.warn message
15
-
16
- class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
17
- def self.name
18
- "#{text}"
19
- end
20
- RUBY_EVAL
21
- end
22
- end
23
- end
24
-
25
- end
26
- end
27
-
28
4
  unless defined?(Spec)
29
5
  # Helper to define a test method using a String. Under the hood, it replaces
30
6
  # spaces with underscores and defines the test method.
@@ -34,7 +10,7 @@ module ActiveSupport
34
10
  # end
35
11
  def test(name, &block)
36
12
  test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
37
- defined = instance_method(test_name) rescue false
13
+ defined = method_defined? test_name
38
14
  raise "#{test_name} is already defined in #{self}" if defined
39
15
  if block_given?
40
16
  define_method(test_name, &block)
@@ -70,14 +70,24 @@ module ActiveSupport
70
70
  exit!
71
71
  else
72
72
  Tempfile.open("isolation") do |tmpfile|
73
- ENV["ISOLATION_TEST"] = self.class.name
74
- ENV["ISOLATION_OUTPUT"] = tmpfile.path
73
+ env = {
74
+ ISOLATION_TEST: self.class.name,
75
+ ISOLATION_OUTPUT: tmpfile.path
76
+ }
75
77
 
76
78
  load_paths = $-I.map {|p| "-I\"#{File.expand_path(p)}\"" }.join(" ")
77
- `#{Gem.ruby} #{load_paths} #{$0} #{ORIG_ARGV.join(" ")}`
78
-
79
- ENV.delete("ISOLATION_TEST")
80
- ENV.delete("ISOLATION_OUTPUT")
79
+ orig_args = ORIG_ARGV.join(" ")
80
+ test_opts = "-n#{self.class.name}##{self.name}"
81
+ command = "#{Gem.ruby} #{load_paths} #{$0} #{orig_args} #{test_opts}"
82
+
83
+ # IO.popen lets us pass env in a cross-platform way
84
+ child = IO.popen([env, command])
85
+
86
+ begin
87
+ Process.wait(child.pid)
88
+ rescue Errno::ECHILD # The child process may exit before we wait
89
+ nil
90
+ end
81
91
 
82
92
  return tmpfile.read.unpack("m")[0]
83
93
  end
@@ -6,7 +6,7 @@ module ActiveSupport
6
6
  attr_writer :tagged_logger
7
7
 
8
8
  def before_setup
9
- if tagged_logger
9
+ if tagged_logger && tagged_logger.info?
10
10
  heading = "#{self.class}: #{name}"
11
11
  divider = '-' * heading.size
12
12
  tagged_logger.info divider