activesupport 4.2.0 → 5.0.0.1

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 (185) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +630 -220
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +2 -3
  5. data/lib/active_support/array_inquirer.rb +44 -0
  6. data/lib/active_support/backtrace_cleaner.rb +1 -1
  7. data/lib/active_support/benchmarkable.rb +1 -1
  8. data/lib/active_support/cache/file_store.rb +36 -22
  9. data/lib/active_support/cache/mem_cache_store.rb +63 -54
  10. data/lib/active_support/cache/memory_store.rb +16 -21
  11. data/lib/active_support/cache/null_store.rb +1 -4
  12. data/lib/active_support/cache/strategy/local_cache.rb +31 -20
  13. data/lib/active_support/cache.rb +73 -89
  14. data/lib/active_support/callbacks.rb +195 -155
  15. data/lib/active_support/concern.rb +2 -2
  16. data/lib/active_support/concurrency/latch.rb +7 -15
  17. data/lib/active_support/concurrency/share_lock.rb +186 -0
  18. data/lib/active_support/configurable.rb +1 -0
  19. data/lib/active_support/core_ext/array/access.rb +27 -1
  20. data/lib/active_support/core_ext/array/conversions.rb +6 -4
  21. data/lib/active_support/core_ext/array/grouping.rb +9 -18
  22. data/lib/active_support/core_ext/array/inquiry.rb +17 -0
  23. data/lib/active_support/core_ext/array/wrap.rb +5 -4
  24. data/lib/active_support/core_ext/array.rb +1 -0
  25. data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -10
  26. data/lib/active_support/core_ext/class/attribute.rb +10 -9
  27. data/lib/active_support/core_ext/class/subclasses.rb +3 -4
  28. data/lib/active_support/core_ext/class.rb +0 -1
  29. data/lib/active_support/core_ext/date/blank.rb +12 -0
  30. data/lib/active_support/core_ext/date/calculations.rb +1 -1
  31. data/lib/active_support/core_ext/date/conversions.rb +13 -6
  32. data/lib/active_support/core_ext/date.rb +1 -1
  33. data/lib/active_support/core_ext/date_and_time/calculations.rb +109 -25
  34. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -0
  35. data/lib/active_support/core_ext/date_and_time/zones.rb +3 -4
  36. data/lib/active_support/core_ext/date_time/blank.rb +12 -0
  37. data/lib/active_support/core_ext/date_time/calculations.rb +36 -10
  38. data/lib/active_support/core_ext/date_time/compatibility.rb +5 -0
  39. data/lib/active_support/core_ext/date_time/conversions.rb +2 -0
  40. data/lib/active_support/core_ext/date_time.rb +2 -1
  41. data/lib/active_support/core_ext/enumerable.rb +49 -5
  42. data/lib/active_support/core_ext/file/atomic.rb +30 -25
  43. data/lib/active_support/core_ext/hash/conversions.rb +23 -4
  44. data/lib/active_support/core_ext/hash/deep_merge.rb +1 -1
  45. data/lib/active_support/core_ext/hash/except.rb +9 -8
  46. data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -1
  47. data/lib/active_support/core_ext/hash/keys.rb +23 -19
  48. data/lib/active_support/core_ext/hash/slice.rb +1 -1
  49. data/lib/active_support/core_ext/hash/transform_values.rb +11 -5
  50. data/lib/active_support/core_ext/integer/time.rb +1 -16
  51. data/lib/active_support/core_ext/kernel/concern.rb +2 -0
  52. data/lib/active_support/core_ext/kernel/debugger.rb +3 -10
  53. data/lib/active_support/core_ext/kernel/reporting.rb +2 -83
  54. data/lib/active_support/core_ext/kernel.rb +0 -1
  55. data/lib/active_support/core_ext/load_error.rb +4 -2
  56. data/lib/active_support/core_ext/marshal.rb +12 -11
  57. data/lib/active_support/core_ext/module/aliasing.rb +6 -1
  58. data/lib/active_support/core_ext/module/anonymous.rb +10 -1
  59. data/lib/active_support/core_ext/module/attr_internal.rb +2 -5
  60. data/lib/active_support/core_ext/module/attribute_accessors.rb +15 -15
  61. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
  62. data/lib/active_support/core_ext/module/concerning.rb +4 -4
  63. data/lib/active_support/core_ext/module/delegation.rb +35 -25
  64. data/lib/active_support/core_ext/module/deprecation.rb +2 -2
  65. data/lib/active_support/core_ext/module/introspection.rb +4 -0
  66. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -11
  67. data/lib/active_support/core_ext/module/qualified_const.rb +30 -12
  68. data/lib/active_support/core_ext/module/remove_method.rb +23 -0
  69. data/lib/active_support/core_ext/module.rb +1 -0
  70. data/lib/active_support/core_ext/name_error.rb +15 -2
  71. data/lib/active_support/core_ext/numeric/bytes.rb +20 -0
  72. data/lib/active_support/core_ext/numeric/conversions.rb +74 -64
  73. data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
  74. data/lib/active_support/core_ext/numeric/time.rb +24 -19
  75. data/lib/active_support/core_ext/numeric.rb +1 -0
  76. data/lib/active_support/core_ext/object/blank.rb +17 -5
  77. data/lib/active_support/core_ext/object/deep_dup.rb +10 -3
  78. data/lib/active_support/core_ext/object/duplicable.rb +8 -13
  79. data/lib/active_support/core_ext/object/inclusion.rb +2 -2
  80. data/lib/active_support/core_ext/object/instance_variables.rb +1 -1
  81. data/lib/active_support/core_ext/object/json.rb +15 -7
  82. data/lib/active_support/core_ext/object/to_query.rb +1 -1
  83. data/lib/active_support/core_ext/object/try.rb +68 -22
  84. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  85. data/lib/active_support/core_ext/object.rb +0 -1
  86. data/lib/active_support/core_ext/range/conversions.rb +18 -6
  87. data/lib/active_support/core_ext/range/each.rb +16 -18
  88. data/lib/active_support/core_ext/range/include_range.rb +20 -20
  89. data/lib/active_support/core_ext/securerandom.rb +23 -0
  90. data/lib/active_support/core_ext/string/access.rb +1 -1
  91. data/lib/active_support/core_ext/string/behavior.rb +1 -1
  92. data/lib/active_support/core_ext/string/conversions.rb +4 -3
  93. data/lib/active_support/core_ext/string/filters.rb +5 -5
  94. data/lib/active_support/core_ext/string/inflections.rb +32 -5
  95. data/lib/active_support/core_ext/string/multibyte.rb +11 -7
  96. data/lib/active_support/core_ext/string/output_safety.rb +18 -16
  97. data/lib/active_support/core_ext/string/strip.rb +3 -6
  98. data/lib/active_support/core_ext/struct.rb +3 -6
  99. data/lib/active_support/core_ext/time/calculations.rb +36 -11
  100. data/lib/active_support/core_ext/time/compatibility.rb +5 -0
  101. data/lib/active_support/core_ext/time/conversions.rb +4 -2
  102. data/lib/active_support/core_ext/time/marshal.rb +2 -29
  103. data/lib/active_support/core_ext/time/zones.rb +36 -4
  104. data/lib/active_support/core_ext/time.rb +1 -1
  105. data/lib/active_support/core_ext/uri.rb +1 -3
  106. data/lib/active_support/core_ext.rb +2 -1
  107. data/lib/active_support/dependencies/interlock.rb +51 -0
  108. data/lib/active_support/dependencies.rb +87 -95
  109. data/lib/active_support/deprecation/behaviors.rb +16 -2
  110. data/lib/active_support/deprecation/method_wrappers.rb +42 -16
  111. data/lib/active_support/deprecation/proxy_wrappers.rb +47 -24
  112. data/lib/active_support/deprecation/reporting.rb +23 -5
  113. data/lib/active_support/deprecation.rb +1 -1
  114. data/lib/active_support/duration/iso8601_parser.rb +122 -0
  115. data/lib/active_support/duration/iso8601_serializer.rb +51 -0
  116. data/lib/active_support/duration.rb +55 -10
  117. data/lib/active_support/evented_file_update_checker.rb +194 -0
  118. data/lib/active_support/execution_wrapper.rb +117 -0
  119. data/lib/active_support/executor.rb +6 -0
  120. data/lib/active_support/file_update_checker.rb +23 -3
  121. data/lib/active_support/gem_version.rb +4 -4
  122. data/lib/active_support/hash_with_indifferent_access.rb +46 -13
  123. data/lib/active_support/i18n_railtie.rb +25 -4
  124. data/lib/active_support/inflector/inflections.rb +36 -5
  125. data/lib/active_support/inflector/methods.rb +97 -90
  126. data/lib/active_support/inflector/transliterate.rb +36 -21
  127. data/lib/active_support/json/decoding.rb +11 -10
  128. data/lib/active_support/json/encoding.rb +4 -49
  129. data/lib/active_support/key_generator.rb +7 -9
  130. data/lib/active_support/locale/en.yml +2 -0
  131. data/lib/active_support/log_subscriber/test_helper.rb +3 -3
  132. data/lib/active_support/log_subscriber.rb +1 -1
  133. data/lib/active_support/logger.rb +50 -1
  134. data/lib/active_support/logger_silence.rb +8 -4
  135. data/lib/active_support/logger_thread_safe_level.rb +31 -0
  136. data/lib/active_support/message_encryptor.rb +4 -4
  137. data/lib/active_support/message_verifier.rb +70 -8
  138. data/lib/active_support/multibyte/chars.rb +13 -4
  139. data/lib/active_support/multibyte/unicode.rb +44 -21
  140. data/lib/active_support/notifications/fanout.rb +6 -6
  141. data/lib/active_support/notifications/instrumenter.rb +20 -2
  142. data/lib/active_support/notifications.rb +2 -2
  143. data/lib/active_support/number_helper/number_to_currency_converter.rb +7 -9
  144. data/lib/active_support/number_helper/number_to_delimited_converter.rb +8 -3
  145. data/lib/active_support/number_helper/number_to_human_converter.rb +6 -4
  146. data/lib/active_support/number_helper/number_to_human_size_converter.rb +6 -2
  147. data/lib/active_support/number_helper/number_to_percentage_converter.rb +1 -1
  148. data/lib/active_support/number_helper/number_to_phone_converter.rb +11 -2
  149. data/lib/active_support/number_helper/number_to_rounded_converter.rb +30 -25
  150. data/lib/active_support/number_helper.rb +90 -67
  151. data/lib/active_support/ordered_hash.rb +1 -1
  152. data/lib/active_support/ordered_options.rb +15 -1
  153. data/lib/active_support/per_thread_registry.rb +8 -3
  154. data/lib/active_support/rails.rb +2 -2
  155. data/lib/active_support/railtie.rb +6 -1
  156. data/lib/active_support/reloader.rb +129 -0
  157. data/lib/active_support/rescuable.rb +93 -47
  158. data/lib/active_support/security_utils.rb +7 -0
  159. data/lib/active_support/string_inquirer.rb +1 -1
  160. data/lib/active_support/subscriber.rb +5 -10
  161. data/lib/active_support/tagged_logging.rb +3 -1
  162. data/lib/active_support/test_case.rb +15 -29
  163. data/lib/active_support/testing/assertions.rb +15 -13
  164. data/lib/active_support/testing/autorun.rb +8 -1
  165. data/lib/active_support/testing/deprecation.rb +9 -8
  166. data/lib/active_support/testing/file_fixtures.rb +34 -0
  167. data/lib/active_support/testing/isolation.rb +22 -8
  168. data/lib/active_support/testing/method_call_assertions.rb +41 -0
  169. data/lib/active_support/testing/stream.rb +42 -0
  170. data/lib/active_support/testing/time_helpers.rb +13 -10
  171. data/lib/active_support/time_with_zone.rb +135 -46
  172. data/lib/active_support/values/time_zone.rb +95 -47
  173. data/lib/active_support/values/unicode_tables.dat +0 -0
  174. data/lib/active_support/xml_mini/jdom.rb +7 -6
  175. data/lib/active_support/xml_mini/libxml.rb +2 -2
  176. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  177. data/lib/active_support/xml_mini/rexml.rb +7 -8
  178. data/lib/active_support/xml_mini.rb +22 -14
  179. data/lib/active_support.rb +20 -6
  180. metadata +33 -35
  181. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -14
  182. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  183. data/lib/active_support/core_ext/date_time/zones.rb +0 -6
  184. data/lib/active_support/core_ext/object/itself.rb +0 -15
  185. data/lib/active_support/core_ext/thread.rb +0 -86
@@ -1,7 +1,6 @@
1
1
  require 'active_support/concern'
2
2
  require 'active_support/core_ext/class/attribute'
3
3
  require 'active_support/core_ext/string/inflections'
4
- require 'active_support/core_ext/array/extract_options'
5
4
 
6
5
  module ActiveSupport
7
6
  # Rescuable module adds support for easier exception handling.
@@ -48,72 +47,119 @@ module ActiveSupport
48
47
  # end
49
48
  #
50
49
  # Exceptions raised inside exception handlers are not propagated up.
51
- def rescue_from(*klasses, &block)
52
- options = klasses.extract_options!
53
-
54
- unless options.has_key?(:with)
50
+ def rescue_from(*klasses, with: nil, &block)
51
+ unless with
55
52
  if block_given?
56
- options[:with] = block
53
+ with = block
57
54
  else
58
- raise ArgumentError, "Need a handler. Supply an options hash that has a :with key as the last argument."
55
+ raise ArgumentError, 'Need a handler. Pass the with: keyword argument or provide a block.'
59
56
  end
60
57
  end
61
58
 
62
59
  klasses.each do |klass|
63
- key = if klass.is_a?(Class) && klass <= Exception
60
+ key = if klass.is_a?(Module) && klass.respond_to?(:===)
64
61
  klass.name
65
62
  elsif klass.is_a?(String)
66
63
  klass
67
64
  else
68
- raise ArgumentError, "#{klass} is neither an Exception nor a String"
65
+ raise ArgumentError, "#{klass.inspect} must be an Exception class or a String referencing an Exception class"
69
66
  end
70
67
 
71
- # put the new handler at the end because the list is read in reverse
72
- self.rescue_handlers += [[key, options[:with]]]
68
+ # Put the new handler at the end because the list is read in reverse.
69
+ self.rescue_handlers += [[key, with]]
73
70
  end
74
71
  end
75
- end
76
72
 
77
- # Tries to rescue the exception by looking up and calling a registered handler.
78
- def rescue_with_handler(exception)
79
- if handler = handler_for_rescue(exception)
80
- handler.arity != 0 ? handler.call(exception) : handler.call
81
- true # don't rely on the return value of the handler
73
+ # Matches an exception to a handler based on the exception class.
74
+ #
75
+ # If no handler matches the exception, check for a handler matching the
76
+ # (optional) exception.cause. If no handler matches the exception or its
77
+ # cause, this returns nil so you can deal with unhandled exceptions.
78
+ # Be sure to re-raise unhandled exceptions if this is what you expect.
79
+ #
80
+ # begin
81
+ # …
82
+ # rescue => exception
83
+ # rescue_with_handler(exception) || raise
84
+ # end
85
+ #
86
+ # Returns the exception if it was handled and nil if it was not.
87
+ def rescue_with_handler(exception, object: self)
88
+ if handler = handler_for_rescue(exception, object: object)
89
+ handler.call exception
90
+ exception
91
+ end
82
92
  end
83
- end
84
93
 
85
- def handler_for_rescue(exception)
86
- # We go from right to left because pairs are pushed onto rescue_handlers
87
- # as rescue_from declarations are found.
88
- _, rescuer = self.class.rescue_handlers.reverse.detect do |klass_name, handler|
89
- # The purpose of allowing strings in rescue_from is to support the
90
- # declaration of handler associations for exception classes whose
91
- # definition is yet unknown.
92
- #
93
- # Since this loop needs the constants it would be inconsistent to
94
- # assume they should exist at this point. An early raised exception
95
- # could trigger some other handler and the array could include
96
- # precisely a string whose corresponding constant has not yet been
97
- # seen. This is why we are tolerant to unknown constants.
98
- #
99
- # Note that this tolerance only matters if the exception was given as
100
- # a string, otherwise a NameError will be raised by the interpreter
101
- # itself when rescue_from CONSTANT is executed.
102
- klass = self.class.const_get(klass_name) rescue nil
103
- klass ||= klass_name.constantize rescue nil
104
- exception.is_a?(klass) if klass
94
+ def handler_for_rescue(exception, object: self) #:nodoc:
95
+ case rescuer = find_rescue_handler(exception)
96
+ when Symbol
97
+ method = object.method(rescuer)
98
+ if method.arity == 0
99
+ -> e { method.call }
100
+ else
101
+ method
102
+ end
103
+ when Proc
104
+ if rescuer.arity == 0
105
+ -> e { object.instance_exec(&rescuer) }
106
+ else
107
+ -> e { object.instance_exec(e, &rescuer) }
108
+ end
109
+ end
105
110
  end
106
111
 
107
- case rescuer
108
- when Symbol
109
- method(rescuer)
110
- when Proc
111
- if rescuer.arity == 0
112
- Proc.new { instance_exec(&rescuer) }
113
- else
114
- Proc.new { |_exception| instance_exec(_exception, &rescuer) }
112
+ private
113
+ def find_rescue_handler(exception)
114
+ if exception
115
+ # Handlers are in order of declaration but the most recently declared
116
+ # is the highest priority match, so we search for matching handlers
117
+ # in reverse.
118
+ _, handler = rescue_handlers.reverse_each.detect do |class_or_name, _|
119
+ if klass = constantize_rescue_handler_class(class_or_name)
120
+ klass === exception
121
+ end
122
+ end
123
+
124
+ handler || find_rescue_handler(exception.cause)
125
+ end
115
126
  end
116
- end
127
+
128
+ def constantize_rescue_handler_class(class_or_name)
129
+ case class_or_name
130
+ when String, Symbol
131
+ begin
132
+ # Try a lexical lookup first since we support
133
+ #
134
+ # class Super
135
+ # rescue_from 'Error', with: …
136
+ # end
137
+ #
138
+ # class Sub
139
+ # class Error < StandardError; end
140
+ # end
141
+ #
142
+ # so an Error raised in Sub will hit the 'Error' handler.
143
+ const_get class_or_name
144
+ rescue NameError
145
+ class_or_name.safe_constantize
146
+ end
147
+ else
148
+ class_or_name
149
+ end
150
+ end
151
+ end
152
+
153
+ # Delegates to the class method, but uses the instance as the subject for
154
+ # rescue_from handlers (method calls, instance_exec blocks).
155
+ def rescue_with_handler(exception)
156
+ self.class.rescue_with_handler exception, object: self
157
+ end
158
+
159
+ # Internal handler lookup. Delegates to class method. Some libraries call
160
+ # this directly, so keeping it around for compatibility.
161
+ def handler_for_rescue(exception) #:nodoc:
162
+ self.class.handler_for_rescue exception, object: self
117
163
  end
118
164
  end
119
165
  end
@@ -1,3 +1,5 @@
1
+ require 'digest'
2
+
1
3
  module ActiveSupport
2
4
  module SecurityUtils
3
5
  # Constant time string comparison.
@@ -16,5 +18,10 @@ module ActiveSupport
16
18
  res == 0
17
19
  end
18
20
  module_function :secure_compare
21
+
22
+ def variable_size_secure_compare(a, b) # :nodoc:
23
+ secure_compare(::Digest::SHA256.hexdigest(a), ::Digest::SHA256.hexdigest(b))
24
+ end
25
+ module_function :variable_size_secure_compare
19
26
  end
20
27
  end
@@ -1,7 +1,7 @@
1
1
  module ActiveSupport
2
2
  # Wrapping a string in this class gives you a prettier way to test
3
3
  # for equality. The value returned by <tt>Rails.env</tt> is wrapped
4
- # in a StringInquirer object so instead of calling this:
4
+ # in a StringInquirer object, so instead of calling this:
5
5
  #
6
6
  # Rails.env == 'production'
7
7
  #
@@ -5,24 +5,19 @@ module ActiveSupport
5
5
  # ActiveSupport::Notifications. The subscriber dispatches notifications to
6
6
  # a registered object based on its given namespace.
7
7
  #
8
- # An example would be Active Record subscriber responsible for collecting
8
+ # An example would be an Active Record subscriber responsible for collecting
9
9
  # statistics about queries:
10
10
  #
11
11
  # module ActiveRecord
12
12
  # class StatsSubscriber < ActiveSupport::Subscriber
13
+ # attach_to :active_record
14
+ #
13
15
  # def sql(event)
14
16
  # Statsd.timing("sql.#{event.payload[:name]}", event.duration)
15
17
  # end
16
18
  # end
17
19
  # end
18
20
  #
19
- # And it's finally registered as:
20
- #
21
- # ActiveRecord::StatsSubscriber.attach_to :active_record
22
- #
23
- # Since we need to know all instance methods before attaching the log
24
- # subscriber, the line above should be called after your subscriber definition.
25
- #
26
21
  # After configured, whenever a "sql.active_record" notification is published,
27
22
  # it will properly dispatch the event (ActiveSupport::Notifications::Event) to
28
23
  # the +sql+ method.
@@ -66,7 +61,7 @@ module ActiveSupport
66
61
 
67
62
  pattern = "#{event}.#{namespace}"
68
63
 
69
- # don't add multiple subscribers (eg. if methods are redefined)
64
+ # Don't add multiple subscribers (eg. if methods are redefined).
70
65
  return if subscriber.patterns.include?(pattern)
71
66
 
72
67
  subscriber.patterns << pattern
@@ -96,7 +91,7 @@ module ActiveSupport
96
91
  event.end = finished
97
92
  event.payload.merge!(payload)
98
93
 
99
- method = name.split('.').first
94
+ method = name.split('.'.freeze).first
100
95
  send(method, event)
101
96
  end
102
97
 
@@ -43,7 +43,9 @@ module ActiveSupport
43
43
  end
44
44
 
45
45
  def current_tags
46
- Thread.current[:activesupport_tagged_logging_tags] ||= []
46
+ # We use our object ID here to avoid conflicting with other instances
47
+ thread_key = @thread_key ||= "activesupport_tagged_logging_tags:#{object_id}".freeze
48
+ Thread.current[thread_key] ||= []
47
49
  end
48
50
 
49
51
  private
@@ -8,8 +8,8 @@ require 'active_support/testing/declarative'
8
8
  require 'active_support/testing/isolation'
9
9
  require 'active_support/testing/constant_lookup'
10
10
  require 'active_support/testing/time_helpers'
11
+ require 'active_support/testing/file_fixtures'
11
12
  require 'active_support/core_ext/kernel/reporting'
12
- require 'active_support/deprecation'
13
13
 
14
14
  module ActiveSupport
15
15
  class TestCase < ::Minitest::Test
@@ -31,36 +31,13 @@ module ActiveSupport
31
31
 
32
32
  # Returns the order in which test cases are run.
33
33
  #
34
- # ActiveSupport::TestCase.test_order # => :sorted
34
+ # ActiveSupport::TestCase.test_order # => :random
35
35
  #
36
36
  # Possible values are +:random+, +:parallel+, +:alpha+, +:sorted+.
37
- # Defaults to +:sorted+.
37
+ # Defaults to +:random+.
38
38
  def test_order
39
- test_order = ActiveSupport.test_order
40
-
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
39
+ ActiveSupport.test_order ||= :random
61
40
  end
62
-
63
- alias :my_tests_are_order_dependent! :i_suck_and_my_tests_are_order_dependent!
64
41
  end
65
42
 
66
43
  alias_method :method_name, :name
@@ -70,6 +47,7 @@ module ActiveSupport
70
47
  include ActiveSupport::Testing::Assertions
71
48
  include ActiveSupport::Testing::Deprecation
72
49
  include ActiveSupport::Testing::TimeHelpers
50
+ include ActiveSupport::Testing::FileFixtures
73
51
  extend ActiveSupport::Testing::Declarative
74
52
 
75
53
  # test/unit backwards compatibility methods
@@ -88,12 +66,20 @@ module ActiveSupport
88
66
  alias :assert_not_respond_to :refute_respond_to
89
67
  alias :assert_not_same :refute_same
90
68
 
91
- # Fails if the block raises an exception.
69
+
70
+ # Assertion that the block should not raise an exception.
71
+ #
72
+ # Passes if evaluated code in the yielded block raises no exception.
92
73
  #
93
74
  # assert_nothing_raised do
94
- # ...
75
+ # perform_service(param: 'no_exception')
95
76
  # end
96
77
  def assert_nothing_raised(*args)
78
+ if args.present?
79
+ ActiveSupport::Deprecation.warn(
80
+ "Passing arguments to assert_nothing_raised " \
81
+ "is deprecated and will be removed in Rails 5.1.")
82
+ end
97
83
  yield
98
84
  end
99
85
  end
@@ -3,7 +3,7 @@ require 'active_support/core_ext/object/blank'
3
3
  module ActiveSupport
4
4
  module Testing
5
5
  module Assertions
6
- # Assert that an expression is not truthy. Passes if <tt>object</tt> is
6
+ # Asserts that an expression is not truthy. Passes if <tt>object</tt> is
7
7
  # +nil+ or +false+. "Truthy" means "considered true in a conditional"
8
8
  # like <tt>if foo</tt>.
9
9
  #
@@ -23,42 +23,42 @@ module ActiveSupport
23
23
  # result of what is evaluated in the yielded block.
24
24
  #
25
25
  # assert_difference 'Article.count' do
26
- # post :create, article: {...}
26
+ # post :create, params: { article: {...} }
27
27
  # end
28
28
  #
29
29
  # An arbitrary expression is passed in and evaluated.
30
30
  #
31
- # assert_difference 'assigns(:article).comments(:reload).size' do
32
- # post :create, comment: {...}
31
+ # assert_difference 'Article.last.comments(:reload).size' do
32
+ # post :create, params: { comment: {...} }
33
33
  # end
34
34
  #
35
35
  # An arbitrary positive or negative difference can be specified.
36
36
  # The default is <tt>1</tt>.
37
37
  #
38
38
  # assert_difference 'Article.count', -1 do
39
- # post :delete, id: ...
39
+ # post :delete, params: { id: ... }
40
40
  # end
41
41
  #
42
42
  # An array of expressions can also be passed in and evaluated.
43
43
  #
44
44
  # assert_difference [ 'Article.count', 'Post.count' ], 2 do
45
- # post :create, article: {...}
45
+ # post :create, params: { article: {...} }
46
46
  # end
47
47
  #
48
48
  # A lambda or a list of lambdas can be passed in and evaluated:
49
49
  #
50
50
  # assert_difference ->{ Article.count }, 2 do
51
- # post :create, article: {...}
51
+ # post :create, params: { article: {...} }
52
52
  # end
53
53
  #
54
54
  # assert_difference [->{ Article.count }, ->{ Post.count }], 2 do
55
- # post :create, article: {...}
55
+ # post :create, params: { article: {...} }
56
56
  # end
57
57
  #
58
58
  # An error message can be specified.
59
59
  #
60
60
  # assert_difference 'Article.count', -1, 'An Article should be destroyed' do
61
- # post :delete, id: ...
61
+ # post :delete, params: { id: ... }
62
62
  # end
63
63
  def assert_difference(expression, difference = 1, message = nil, &block)
64
64
  expressions = Array(expression)
@@ -66,28 +66,30 @@ module ActiveSupport
66
66
  exps = expressions.map { |e|
67
67
  e.respond_to?(:call) ? e : lambda { eval(e, block.binding) }
68
68
  }
69
- before = exps.map { |e| e.call }
69
+ before = exps.map(&:call)
70
70
 
71
- yield
71
+ retval = yield
72
72
 
73
73
  expressions.zip(exps).each_with_index do |(code, e), i|
74
74
  error = "#{code.inspect} didn't change by #{difference}"
75
75
  error = "#{message}.\n#{error}" if message
76
76
  assert_equal(before[i] + difference, e.call, error)
77
77
  end
78
+
79
+ retval
78
80
  end
79
81
 
80
82
  # Assertion that the numeric result of evaluating an expression is not
81
83
  # changed before and after invoking the passed in block.
82
84
  #
83
85
  # assert_no_difference 'Article.count' do
84
- # post :create, article: invalid_attributes
86
+ # post :create, params: { article: invalid_attributes }
85
87
  # end
86
88
  #
87
89
  # An error message can be specified.
88
90
  #
89
91
  # assert_no_difference 'Article.count', 'An Article should not be created' do
90
- # post :create, article: invalid_attributes
92
+ # post :create, params: { article: invalid_attributes }
91
93
  # end
92
94
  def assert_no_difference(expression, message = nil, &block)
93
95
  assert_difference expression, 0, message, &block
@@ -2,4 +2,11 @@ gem 'minitest'
2
2
 
3
3
  require 'minitest'
4
4
 
5
- Minitest.autorun
5
+ if Minitest.respond_to?(:run_with_rails_extension)
6
+ unless Minitest.run_with_rails_extension
7
+ Minitest.run_with_autorun = true
8
+ Minitest.autorun
9
+ end
10
+ else
11
+ Minitest.autorun
12
+ end
@@ -3,8 +3,8 @@ require 'active_support/deprecation'
3
3
  module ActiveSupport
4
4
  module Testing
5
5
  module Deprecation #:nodoc:
6
- def assert_deprecated(match = nil, &block)
7
- result, warnings = collect_deprecations(&block)
6
+ def assert_deprecated(match = nil, deprecator = nil, &block)
7
+ result, warnings = collect_deprecations(deprecator, &block)
8
8
  assert !warnings.empty?, "Expected a deprecation warning within the block but received none"
9
9
  if match
10
10
  match = Regexp.new(Regexp.escape(match)) unless match.is_a?(Regexp)
@@ -13,22 +13,23 @@ module ActiveSupport
13
13
  result
14
14
  end
15
15
 
16
- def assert_not_deprecated(&block)
17
- result, deprecations = collect_deprecations(&block)
16
+ def assert_not_deprecated(deprecator = nil, &block)
17
+ result, deprecations = collect_deprecations(deprecator, &block)
18
18
  assert deprecations.empty?, "Expected no deprecation warning within the block but received #{deprecations.size}: \n #{deprecations * "\n "}"
19
19
  result
20
20
  end
21
21
 
22
- def collect_deprecations
23
- old_behavior = ActiveSupport::Deprecation.behavior
22
+ def collect_deprecations(deprecator = nil)
23
+ deprecator ||= ActiveSupport::Deprecation
24
+ old_behavior = deprecator.behavior
24
25
  deprecations = []
25
- ActiveSupport::Deprecation.behavior = Proc.new do |message, callstack|
26
+ deprecator.behavior = Proc.new do |message, callstack|
26
27
  deprecations << message
27
28
  end
28
29
  result = yield
29
30
  [result, deprecations]
30
31
  ensure
31
- ActiveSupport::Deprecation.behavior = old_behavior
32
+ deprecator.behavior = old_behavior
32
33
  end
33
34
  end
34
35
  end
@@ -0,0 +1,34 @@
1
+ module ActiveSupport
2
+ module Testing
3
+ # Adds simple access to sample files called file fixtures.
4
+ # File fixtures are normal files stored in
5
+ # <tt>ActiveSupport::TestCase.file_fixture_path</tt>.
6
+ #
7
+ # File fixtures are represented as +Pathname+ objects.
8
+ # This makes it easy to extract specific information:
9
+ #
10
+ # file_fixture("example.txt").read # get the file's content
11
+ # file_fixture("example.mp3").size # get the file size
12
+ module FileFixtures
13
+ extend ActiveSupport::Concern
14
+
15
+ included do
16
+ class_attribute :file_fixture_path, instance_writer: false
17
+ end
18
+
19
+ # Returns a +Pathname+ to the fixture file named +fixture_name+.
20
+ #
21
+ # Raises +ArgumentError+ if +fixture_name+ can't be found.
22
+ def file_fixture(fixture_name)
23
+ path = Pathname.new(File.join(file_fixture_path, fixture_name))
24
+
25
+ if path.exist?
26
+ path
27
+ else
28
+ msg = "the directory '%s' does not contain a file named '%s'"
29
+ raise ArgumentError, msg % [file_fixture_path, fixture_name]
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1,5 +1,3 @@
1
- require 'rbconfig'
2
-
3
1
  module ActiveSupport
4
2
  module Testing
5
3
  module Isolation
@@ -12,7 +10,7 @@ module ActiveSupport
12
10
  end
13
11
 
14
12
  def self.forking_env?
15
- !ENV["NO_FORK"] && ((RbConfig::CONFIG['host_os'] !~ /mswin|mingw/) && (RUBY_PLATFORM !~ /java/))
13
+ !ENV["NO_FORK"] && Process.respond_to?(:fork)
16
14
  end
17
15
 
18
16
  @@class_setup_mutex = Mutex.new
@@ -43,7 +41,23 @@ module ActiveSupport
43
41
  pid = fork do
44
42
  read.close
45
43
  yield
46
- write.puts [Marshal.dump(self.dup)].pack("m")
44
+ begin
45
+ if error?
46
+ failures.map! { |e|
47
+ begin
48
+ Marshal.dump e
49
+ e
50
+ rescue TypeError
51
+ ex = Exception.new e.message
52
+ ex.set_backtrace e.backtrace
53
+ Minitest::UnexpectedError.new ex
54
+ end
55
+ }
56
+ end
57
+ result = Marshal.dump(self.dup)
58
+ end
59
+
60
+ write.puts [result].pack("m")
47
61
  exit!
48
62
  end
49
63
 
@@ -71,17 +85,17 @@ module ActiveSupport
71
85
  else
72
86
  Tempfile.open("isolation") do |tmpfile|
73
87
  env = {
74
- ISOLATION_TEST: self.class.name,
75
- ISOLATION_OUTPUT: tmpfile.path
88
+ 'ISOLATION_TEST' => self.class.name,
89
+ 'ISOLATION_OUTPUT' => tmpfile.path
76
90
  }
77
91
 
78
92
  load_paths = $-I.map {|p| "-I\"#{File.expand_path(p)}\"" }.join(" ")
79
93
  orig_args = ORIG_ARGV.join(" ")
80
94
  test_opts = "-n#{self.class.name}##{self.name}"
81
- command = "#{Gem.ruby} #{load_paths} #{$0} #{orig_args} #{test_opts}"
95
+ command = "#{Gem.ruby} #{load_paths} #{$0} '#{orig_args}' #{test_opts}"
82
96
 
83
97
  # IO.popen lets us pass env in a cross-platform way
84
- child = IO.popen([env, command])
98
+ child = IO.popen(env, command)
85
99
 
86
100
  begin
87
101
  Process.wait(child.pid)
@@ -0,0 +1,41 @@
1
+ require 'minitest/mock'
2
+
3
+ module ActiveSupport
4
+ module Testing
5
+ module MethodCallAssertions # :nodoc:
6
+ private
7
+ def assert_called(object, method_name, message = nil, times: 1, returns: nil)
8
+ times_called = 0
9
+
10
+ object.stub(method_name, proc { times_called += 1; returns }) { yield }
11
+
12
+ error = "Expected #{method_name} to be called #{times} times, " \
13
+ "but was called #{times_called} times"
14
+ error = "#{message}.\n#{error}" if message
15
+ assert_equal times, times_called, error
16
+ end
17
+
18
+ def assert_called_with(object, method_name, args = [], returns: nil)
19
+ mock = Minitest::Mock.new
20
+
21
+ if args.all? { |arg| arg.is_a?(Array) }
22
+ args.each { |arg| mock.expect(:call, returns, arg) }
23
+ else
24
+ mock.expect(:call, returns, args)
25
+ end
26
+
27
+ object.stub(method_name, mock) { yield }
28
+
29
+ mock.verify
30
+ end
31
+
32
+ def assert_not_called(object, method_name, message = nil, &block)
33
+ assert_called(object, method_name, message, times: 0, &block)
34
+ end
35
+
36
+ def stub_any_instance(klass, instance: klass.new)
37
+ klass.stub(:new, instance) { yield instance }
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,42 @@
1
+ module ActiveSupport
2
+ module Testing
3
+ module Stream #:nodoc:
4
+ private
5
+
6
+ def silence_stream(stream)
7
+ old_stream = stream.dup
8
+ stream.reopen(IO::NULL)
9
+ stream.sync = true
10
+ yield
11
+ ensure
12
+ stream.reopen(old_stream)
13
+ old_stream.close
14
+ end
15
+
16
+ def quietly
17
+ silence_stream(STDOUT) do
18
+ silence_stream(STDERR) do
19
+ yield
20
+ end
21
+ end
22
+ end
23
+
24
+ def capture(stream)
25
+ stream = stream.to_s
26
+ captured_stream = Tempfile.new(stream)
27
+ stream_io = eval("$#{stream}")
28
+ origin_stream = stream_io.dup
29
+ stream_io.reopen(captured_stream)
30
+
31
+ yield
32
+
33
+ stream_io.rewind
34
+ return captured_stream.read
35
+ ensure
36
+ captured_stream.close
37
+ captured_stream.unlink
38
+ stream_io.reopen(origin_stream)
39
+ end
40
+ end
41
+ end
42
+ end