activesupport 4.1.16 → 4.2.0.beta1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +140 -714
- data/README.rdoc +7 -2
- data/lib/active_support/backtrace_cleaner.rb +4 -4
- data/lib/active_support/cache.rb +18 -20
- data/lib/active_support/cache/file_store.rb +5 -0
- data/lib/active_support/cache/strategy/local_cache.rb +5 -4
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +5 -0
- data/lib/active_support/callbacks.rb +92 -140
- data/lib/active_support/concern.rb +9 -1
- data/lib/active_support/core_ext/array/access.rb +5 -1
- data/lib/active_support/core_ext/array/grouping.rb +5 -0
- data/lib/active_support/core_ext/class/delegating_attributes.rb +4 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +11 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +2 -2
- data/lib/active_support/core_ext/digest/uuid.rb +51 -0
- data/lib/active_support/core_ext/hash.rb +1 -0
- data/lib/active_support/core_ext/hash/conversions.rb +2 -3
- data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -1
- data/lib/active_support/core_ext/hash/keys.rb +10 -6
- data/lib/active_support/core_ext/hash/transform_values.rb +23 -0
- data/lib/active_support/core_ext/kernel.rb +3 -2
- data/lib/active_support/core_ext/kernel/concern.rb +10 -0
- data/lib/active_support/core_ext/kernel/reporting.rb +14 -0
- data/lib/active_support/core_ext/load_error.rb +4 -1
- data/lib/active_support/core_ext/module/delegation.rb +13 -25
- data/lib/active_support/core_ext/numeric/time.rb +1 -19
- data/lib/active_support/core_ext/object.rb +1 -0
- data/lib/active_support/core_ext/object/duplicable.rb +4 -11
- data/lib/active_support/core_ext/object/itself.rb +12 -0
- data/lib/active_support/core_ext/object/json.rb +1 -1
- data/lib/active_support/core_ext/object/to_query.rb +2 -1
- data/lib/active_support/core_ext/object/with_options.rb +15 -2
- data/lib/active_support/core_ext/string/access.rb +4 -4
- data/lib/active_support/core_ext/string/filters.rb +25 -1
- data/lib/active_support/core_ext/string/inflections.rb +3 -1
- data/lib/active_support/core_ext/string/output_safety.rb +29 -19
- data/lib/active_support/core_ext/thread.rb +7 -0
- data/lib/active_support/core_ext/time/conversions.rb +1 -1
- data/lib/active_support/core_ext/time/zones.rb +0 -1
- data/lib/active_support/dependencies.rb +5 -4
- data/lib/active_support/duration.rb +2 -3
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/hash_with_indifferent_access.rb +13 -5
- data/lib/active_support/i18n_railtie.rb +1 -7
- data/lib/active_support/inflector/inflections.rb +1 -1
- data/lib/active_support/inflector/methods.rb +39 -15
- data/lib/active_support/json/encoding.rb +0 -4
- data/lib/active_support/logger.rb +0 -14
- data/lib/active_support/logger_silence.rb +3 -24
- data/lib/active_support/message_encryptor.rb +2 -1
- data/lib/active_support/multibyte/unicode.rb +5 -3
- data/lib/active_support/notifications.rb +7 -2
- data/lib/active_support/notifications/fanout.rb +11 -6
- data/lib/active_support/number_helper.rb +7 -8
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +2 -2
- data/lib/active_support/test_case.rb +3 -13
- data/lib/active_support/testing/assertions.rb +1 -1
- data/lib/active_support/testing/declarative.rb +1 -25
- data/lib/active_support/testing/isolation.rb +16 -6
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +5 -1
- data/lib/active_support/time.rb +0 -2
- data/lib/active_support/time_with_zone.rb +14 -3
- data/lib/active_support/values/time_zone.rb +76 -75
- data/lib/active_support/xml_mini.rb +0 -3
- data/lib/active_support/xml_mini/jdom.rb +5 -6
- data/lib/active_support/xml_mini/rexml.rb +5 -6
- metadata +17 -16
- data/lib/active_support/core_ext/object/to_json.rb +0 -5
- data/lib/active_support/file_watcher.rb +0 -36
- data/lib/active_support/security_utils.rb +0 -27
@@ -89,6 +89,7 @@ module ActiveSupport
|
|
89
89
|
#
|
90
90
|
# 'SSLError'.underscore.camelize # => "SslError"
|
91
91
|
def underscore(camel_cased_word)
|
92
|
+
return camel_cased_word unless camel_cased_word =~ /[A-Z-]|::/
|
92
93
|
word = camel_cased_word.to_s.gsub('::', '/')
|
93
94
|
word.gsub!(/(?:([A-Za-z\d])|^)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$1}#{$1 && '_'}#{$2.downcase}" }
|
94
95
|
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
|
@@ -98,26 +99,46 @@ module ActiveSupport
|
|
98
99
|
word
|
99
100
|
end
|
100
101
|
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
102
|
+
# Tweaks an attribute name for display to end users.
|
103
|
+
#
|
104
|
+
# Specifically, +humanize+ performs these transformations:
|
105
|
+
#
|
106
|
+
# * Applies human inflection rules to the argument.
|
107
|
+
# * Deletes leading underscores, if any.
|
108
|
+
# * Removes a "_id" suffix if present.
|
109
|
+
# * Replaces underscores with spaces, if any.
|
110
|
+
# * Downcases all words except acronyms.
|
111
|
+
# * Capitalizes the first word.
|
104
112
|
#
|
105
113
|
# The capitalization of the first word can be turned off by setting the
|
106
|
-
#
|
107
|
-
# By default, this parameter is true.
|
114
|
+
# +:capitalize+ option to false (default is true).
|
108
115
|
#
|
109
116
|
# humanize('employee_salary') # => "Employee salary"
|
110
117
|
# humanize('author_id') # => "Author"
|
111
118
|
# humanize('author_id', capitalize: false) # => "author"
|
119
|
+
# humanize('_id') # => "Id"
|
120
|
+
#
|
121
|
+
# If "SSL" was defined to be an acronym:
|
122
|
+
#
|
123
|
+
# humanize('ssl_error') # => "SSL error"
|
124
|
+
#
|
112
125
|
def humanize(lower_case_and_underscored_word, options = {})
|
113
126
|
result = lower_case_and_underscored_word.to_s.dup
|
127
|
+
|
114
128
|
inflections.humans.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
|
115
|
-
|
129
|
+
|
130
|
+
result.sub!(/\A_+/, '')
|
131
|
+
result.sub!(/_id\z/, '')
|
116
132
|
result.tr!('_', ' ')
|
117
|
-
|
133
|
+
|
134
|
+
result.gsub!(/([a-z\d]*)/i) do |match|
|
118
135
|
"#{inflections.acronyms[match] || match.downcase}"
|
119
|
-
|
120
|
-
|
136
|
+
end
|
137
|
+
|
138
|
+
if options.fetch(:capitalize, true)
|
139
|
+
result.sub!(/\A\w/) { |match| match.upcase }
|
140
|
+
end
|
141
|
+
|
121
142
|
result
|
122
143
|
end
|
123
144
|
|
@@ -171,6 +192,8 @@ module ActiveSupport
|
|
171
192
|
#
|
172
193
|
# 'ActiveRecord::CoreExtensions::String::Inflections'.demodulize # => "Inflections"
|
173
194
|
# 'Inflections'.demodulize # => "Inflections"
|
195
|
+
# '::Inflections'.demodulize # => "Inflections"
|
196
|
+
# ''.demodulize # => ""
|
174
197
|
#
|
175
198
|
# See also +deconstantize+.
|
176
199
|
def demodulize(path)
|
@@ -227,7 +250,7 @@ module ActiveSupport
|
|
227
250
|
def constantize(camel_cased_word)
|
228
251
|
names = camel_cased_word.split('::')
|
229
252
|
|
230
|
-
# Trigger a
|
253
|
+
# Trigger a built-in NameError exception including the ill-formed constant in the message.
|
231
254
|
Object.const_get(camel_cased_word) if names.empty?
|
232
255
|
|
233
256
|
# Remove the first blank element in case of '::ClassName' notation.
|
@@ -241,8 +264,8 @@ module ActiveSupport
|
|
241
264
|
next candidate if constant.const_defined?(name, false)
|
242
265
|
next candidate unless Object.const_defined?(name)
|
243
266
|
|
244
|
-
# Go down the ancestors to check
|
245
|
-
#
|
267
|
+
# Go down the ancestors to check if it is owned directly. The check
|
268
|
+
# stops when we reach Object or the end of ancestors tree.
|
246
269
|
constant = constant.ancestors.inject do |const, ancestor|
|
247
270
|
break const if ancestor == Object
|
248
271
|
break ancestor if ancestor.const_defined?(name, false)
|
@@ -325,10 +348,11 @@ module ActiveSupport
|
|
325
348
|
|
326
349
|
private
|
327
350
|
|
328
|
-
#
|
351
|
+
# Mounts a regular expression, returned as a string to ease interpolation,
|
352
|
+
# that will match part by part the given constant.
|
329
353
|
#
|
330
|
-
# const_regexp("Foo::Bar::Baz") # =>
|
331
|
-
# const_regexp("::") # =>
|
354
|
+
# const_regexp("Foo::Bar::Baz") # => "Foo(::Bar(::Baz)?)?"
|
355
|
+
# const_regexp("::") # => "::"
|
332
356
|
def const_regexp(camel_cased_word) #:nodoc:
|
333
357
|
parts = camel_cased_word.split("::")
|
334
358
|
|
@@ -44,20 +44,6 @@ module ActiveSupport
|
|
44
44
|
def initialize(*args)
|
45
45
|
super
|
46
46
|
@formatter = SimpleFormatter.new
|
47
|
-
after_initialize if respond_to? :after_initialize
|
48
|
-
end
|
49
|
-
|
50
|
-
def add(severity, message = nil, progname = nil, &block)
|
51
|
-
return true if @logdev.nil? || (severity || UNKNOWN) < level
|
52
|
-
super
|
53
|
-
end
|
54
|
-
|
55
|
-
Logger::Severity.constants.each do |severity|
|
56
|
-
class_eval(<<-EOT, __FILE__, __LINE__ + 1)
|
57
|
-
def #{severity.downcase}? # def debug?
|
58
|
-
Logger::#{severity} >= level # DEBUG >= level
|
59
|
-
end # end
|
60
|
-
EOT
|
61
47
|
end
|
62
48
|
|
63
49
|
# Simple formatter which only displays the message.
|
@@ -1,45 +1,24 @@
|
|
1
1
|
require 'active_support/concern'
|
2
|
-
require 'thread_safe'
|
3
2
|
|
4
3
|
module LoggerSilence
|
5
4
|
extend ActiveSupport::Concern
|
6
5
|
|
7
6
|
included do
|
8
7
|
cattr_accessor :silencer
|
9
|
-
attr_reader :local_levels
|
10
8
|
self.silencer = true
|
11
9
|
end
|
12
10
|
|
13
|
-
|
14
|
-
def after_initialize
|
15
|
-
@local_levels = ThreadSafe::Cache.new(:initial_capacity => 2)
|
16
|
-
end
|
17
|
-
|
18
|
-
def local_log_id
|
19
|
-
Thread.current.__id__
|
20
|
-
end
|
21
|
-
|
22
|
-
def level
|
23
|
-
local_levels[local_log_id] || super
|
24
|
-
end
|
25
|
-
|
26
11
|
# Silences the logger for the duration of the block.
|
27
12
|
def silence(temporary_level = Logger::ERROR)
|
28
13
|
if silencer
|
29
14
|
begin
|
30
|
-
|
31
|
-
local_levels[local_log_id] = temporary_level
|
32
|
-
|
15
|
+
old_logger_level, self.level = level, temporary_level
|
33
16
|
yield self
|
34
17
|
ensure
|
35
|
-
|
36
|
-
local_levels[local_log_id] = old_local_level
|
37
|
-
else
|
38
|
-
local_levels.delete(local_log_id)
|
39
|
-
end
|
18
|
+
self.level = old_logger_level
|
40
19
|
end
|
41
20
|
else
|
42
21
|
yield self
|
43
22
|
end
|
44
23
|
end
|
45
|
-
end
|
24
|
+
end
|
@@ -40,6 +40,7 @@ module ActiveSupport
|
|
40
40
|
# Options:
|
41
41
|
# * <tt>:cipher</tt> - Cipher to use. Can be any cipher returned by
|
42
42
|
# <tt>OpenSSL::Cipher.ciphers</tt>. Default is 'aes-256-cbc'.
|
43
|
+
# * <tt>:digest</tt> - String of digest to use for signing. Default is +SHA1+.
|
43
44
|
# * <tt>:serializer</tt> - Object serializer to use. Default is +Marshal+.
|
44
45
|
def initialize(secret, *signature_key_or_options)
|
45
46
|
options = signature_key_or_options.extract_options!
|
@@ -47,7 +48,7 @@ module ActiveSupport
|
|
47
48
|
@secret = secret
|
48
49
|
@sign_secret = sign_secret
|
49
50
|
@cipher = options[:cipher] || 'aes-256-cbc'
|
50
|
-
@verifier = MessageVerifier.new(@sign_secret || @secret, :serializer
|
51
|
+
@verifier = MessageVerifier.new(@sign_secret || @secret, digest: options[:digest] || 'SHA1', serializer: NullSerializer)
|
51
52
|
@serializer = options[:serializer] || Marshal
|
52
53
|
end
|
53
54
|
|
@@ -42,6 +42,7 @@ module ActiveSupport
|
|
42
42
|
0x0085, # White_Space # Cc <control-0085>
|
43
43
|
0x00A0, # White_Space # Zs NO-BREAK SPACE
|
44
44
|
0x1680, # White_Space # Zs OGHAM SPACE MARK
|
45
|
+
0x180E, # White_Space # Zs MONGOLIAN VOWEL SEPARATOR
|
45
46
|
(0x2000..0x200A).to_a, # White_Space # Zs [11] EN QUAD..HAIR SPACE
|
46
47
|
0x2028, # White_Space # Zl LINE SEPARATOR
|
47
48
|
0x2029, # White_Space # Zp PARAGRAPH SEPARATOR
|
@@ -212,7 +213,8 @@ module ActiveSupport
|
|
212
213
|
end
|
213
214
|
|
214
215
|
# Ruby >= 2.1 has String#scrub, which is faster than the workaround used for < 2.1.
|
215
|
-
|
216
|
+
# Rubinius' String#scrub, however, doesn't support ASCII-incompatible chars.
|
217
|
+
if '<3'.respond_to?(:scrub) && !defined?(Rubinius)
|
216
218
|
# Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
|
217
219
|
# resulting in a valid UTF-8 string.
|
218
220
|
#
|
@@ -334,7 +336,7 @@ module ActiveSupport
|
|
334
336
|
begin
|
335
337
|
@codepoints, @composition_exclusion, @composition_map, @boundary, @cp1252 = File.open(self.class.filename, 'rb') { |f| Marshal.load f.read }
|
336
338
|
rescue => e
|
337
|
-
|
339
|
+
raise IOError.new("Couldn't load the Unicode tables for UTF8Handler (#{e.message}), ActiveSupport::Multibyte is unusable")
|
338
340
|
end
|
339
341
|
|
340
342
|
# Redefine the === method so we can write shorter rules for grapheme cluster breaks
|
@@ -366,6 +368,7 @@ module ActiveSupport
|
|
366
368
|
private
|
367
369
|
|
368
370
|
def apply_mapping(string, mapping) #:nodoc:
|
371
|
+
database.codepoints
|
369
372
|
string.each_codepoint.map do |codepoint|
|
370
373
|
cp = database.codepoints[codepoint]
|
371
374
|
if cp and (ncp = cp.send(mapping)) and ncp > 0
|
@@ -383,7 +386,6 @@ module ActiveSupport
|
|
383
386
|
def database
|
384
387
|
@database ||= UnicodeDatabase.new
|
385
388
|
end
|
386
|
-
|
387
389
|
end
|
388
390
|
end
|
389
391
|
end
|
@@ -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(
|
177
|
-
notifier.unsubscribe(
|
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(
|
28
|
+
def unsubscribe(subscriber_or_name)
|
29
29
|
synchronize do
|
30
|
-
|
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,12 +103,11 @@ module ActiveSupport
|
|
97
103
|
end
|
98
104
|
|
99
105
|
def subscribed_to?(name)
|
100
|
-
@pattern === name
|
106
|
+
@pattern === name
|
101
107
|
end
|
102
108
|
|
103
|
-
def matches?(
|
104
|
-
|
105
|
-
@pattern && @pattern === subscriber_or_name
|
109
|
+
def matches?(name)
|
110
|
+
@pattern && @pattern === name
|
106
111
|
end
|
107
112
|
end
|
108
113
|
|
@@ -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
|
-
#
|
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
|
@@ -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
|
-
#
|
313
|
-
#
|
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
|
#
|
@@ -23,7 +23,7 @@ module ActiveSupport
|
|
23
23
|
precision = 0 if precision < 0 # don't let it be negative
|
24
24
|
else
|
25
25
|
rounded_number = number.round(precision)
|
26
|
-
rounded_number = rounded_number.to_i if precision == 0
|
26
|
+
rounded_number = rounded_number.to_i if precision == 0
|
27
27
|
rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros
|
28
28
|
end
|
29
29
|
|
@@ -59,7 +59,7 @@ module ActiveSupport
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def digit_count(number)
|
62
|
-
|
62
|
+
(Math.log10(absolute_number(number)) + 1).floor
|
63
63
|
end
|
64
64
|
|
65
65
|
def strip_insignificant_zeros
|
@@ -11,25 +11,15 @@ 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
|
-
|
24
|
-
|
25
|
-
$tags = {}
|
26
|
-
def self.for_tag(tag)
|
27
|
-
yield if $tags[tag]
|
18
|
+
class << self
|
19
|
+
alias :my_tests_are_order_dependent! :i_suck_and_my_tests_are_order_dependent!
|
28
20
|
end
|
29
21
|
|
30
|
-
|
31
|
-
# remove this method call.
|
32
|
-
self.i_suck_and_my_tests_are_order_dependent!
|
22
|
+
alias_method :method_name, :name
|
33
23
|
|
34
24
|
include ActiveSupport::Testing::TaggedLogging
|
35
25
|
include ActiveSupport::Testing::SetupAndTeardown
|
@@ -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 =
|
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
|
-
|
74
|
-
|
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
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|