activesupport 4.2.8 → 5.2.6

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 (256) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +424 -373
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +4 -5
  5. data/lib/active_support/all.rb +5 -3
  6. data/lib/active_support/array_inquirer.rb +48 -0
  7. data/lib/active_support/backtrace_cleaner.rb +7 -5
  8. data/lib/active_support/benchmarkable.rb +6 -4
  9. data/lib/active_support/builder.rb +3 -1
  10. data/lib/active_support/cache/file_store.rb +41 -35
  11. data/lib/active_support/cache/mem_cache_store.rb +91 -91
  12. data/lib/active_support/cache/memory_store.rb +27 -30
  13. data/lib/active_support/cache/null_store.rb +7 -8
  14. data/lib/active_support/cache/redis_cache_store.rb +466 -0
  15. data/lib/active_support/cache/strategy/local_cache.rb +67 -34
  16. data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
  17. data/lib/active_support/cache.rb +287 -196
  18. data/lib/active_support/callbacks.rb +640 -590
  19. data/lib/active_support/concern.rb +11 -5
  20. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +17 -0
  21. data/lib/active_support/concurrency/share_lock.rb +227 -0
  22. data/lib/active_support/configurable.rb +8 -5
  23. data/lib/active_support/core_ext/array/access.rb +29 -1
  24. data/lib/active_support/core_ext/array/conversions.rb +22 -18
  25. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  26. data/lib/active_support/core_ext/array/grouping.rb +11 -18
  27. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  28. data/lib/active_support/core_ext/array/prepend_and_append.rb +5 -3
  29. data/lib/active_support/core_ext/array/wrap.rb +7 -4
  30. data/lib/active_support/core_ext/array.rb +9 -6
  31. data/lib/active_support/core_ext/benchmark.rb +3 -1
  32. data/lib/active_support/core_ext/big_decimal/conversions.rb +10 -12
  33. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  34. data/lib/active_support/core_ext/class/attribute.rb +41 -22
  35. data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
  36. data/lib/active_support/core_ext/class/subclasses.rb +20 -6
  37. data/lib/active_support/core_ext/class.rb +4 -3
  38. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  39. data/lib/active_support/core_ext/date/blank.rb +14 -0
  40. data/lib/active_support/core_ext/date/calculations.rb +11 -9
  41. data/lib/active_support/core_ext/date/conversions.rb +25 -23
  42. data/lib/active_support/core_ext/date/zones.rb +4 -2
  43. data/lib/active_support/core_ext/date.rb +6 -4
  44. data/lib/active_support/core_ext/date_and_time/calculations.rb +170 -58
  45. data/lib/active_support/core_ext/date_and_time/compatibility.rb +4 -17
  46. data/lib/active_support/core_ext/date_and_time/zones.rb +12 -12
  47. data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
  48. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  49. data/lib/active_support/core_ext/date_time/calculations.rb +29 -16
  50. data/lib/active_support/core_ext/date_time/compatibility.rb +14 -1
  51. data/lib/active_support/core_ext/date_time/conversions.rb +16 -12
  52. data/lib/active_support/core_ext/date_time.rb +7 -5
  53. data/lib/active_support/core_ext/digest/uuid.rb +7 -5
  54. data/lib/active_support/core_ext/digest.rb +3 -0
  55. data/lib/active_support/core_ext/enumerable.rb +101 -33
  56. data/lib/active_support/core_ext/file/atomic.rb +38 -31
  57. data/lib/active_support/core_ext/file.rb +3 -1
  58. data/lib/active_support/core_ext/hash/compact.rb +14 -9
  59. data/lib/active_support/core_ext/hash/conversions.rb +62 -41
  60. data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
  61. data/lib/active_support/core_ext/hash/except.rb +11 -8
  62. data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -3
  63. data/lib/active_support/core_ext/hash/keys.rb +33 -27
  64. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  65. data/lib/active_support/core_ext/hash/slice.rb +8 -8
  66. data/lib/active_support/core_ext/hash/transform_values.rb +14 -5
  67. data/lib/active_support/core_ext/hash.rb +11 -9
  68. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  69. data/lib/active_support/core_ext/integer/multiple.rb +2 -0
  70. data/lib/active_support/core_ext/integer/time.rb +11 -18
  71. data/lib/active_support/core_ext/integer.rb +5 -3
  72. data/lib/active_support/core_ext/kernel/agnostics.rb +2 -0
  73. data/lib/active_support/core_ext/kernel/concern.rb +5 -1
  74. data/lib/active_support/core_ext/kernel/reporting.rb +4 -84
  75. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  76. data/lib/active_support/core_ext/kernel.rb +6 -5
  77. data/lib/active_support/core_ext/load_error.rb +3 -22
  78. data/lib/active_support/core_ext/marshal.rb +8 -8
  79. data/lib/active_support/core_ext/module/aliasing.rb +6 -44
  80. data/lib/active_support/core_ext/module/anonymous.rb +12 -1
  81. data/lib/active_support/core_ext/module/attr_internal.rb +8 -9
  82. data/lib/active_support/core_ext/module/attribute_accessors.rb +43 -40
  83. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +150 -0
  84. data/lib/active_support/core_ext/module/concerning.rb +11 -12
  85. data/lib/active_support/core_ext/module/delegation.rb +99 -29
  86. data/lib/active_support/core_ext/module/deprecation.rb +4 -2
  87. data/lib/active_support/core_ext/module/introspection.rb +9 -9
  88. data/lib/active_support/core_ext/module/reachable.rb +5 -2
  89. data/lib/active_support/core_ext/module/redefine_method.rb +49 -0
  90. data/lib/active_support/core_ext/module/remove_method.rb +8 -3
  91. data/lib/active_support/core_ext/module.rb +14 -11
  92. data/lib/active_support/core_ext/name_error.rb +22 -2
  93. data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
  94. data/lib/active_support/core_ext/numeric/conversions.rb +78 -81
  95. data/lib/active_support/core_ext/numeric/inquiry.rb +28 -0
  96. data/lib/active_support/core_ext/numeric/time.rb +35 -23
  97. data/lib/active_support/core_ext/numeric.rb +6 -3
  98. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  99. data/lib/active_support/core_ext/object/blank.rb +27 -2
  100. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  101. data/lib/active_support/core_ext/object/deep_dup.rb +13 -4
  102. data/lib/active_support/core_ext/object/duplicable.rb +41 -14
  103. data/lib/active_support/core_ext/object/inclusion.rb +5 -3
  104. data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
  105. data/lib/active_support/core_ext/object/json.rb +49 -19
  106. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  107. data/lib/active_support/core_ext/object/to_query.rb +10 -5
  108. data/lib/active_support/core_ext/object/try.rb +69 -21
  109. data/lib/active_support/core_ext/object/with_options.rb +16 -3
  110. data/lib/active_support/core_ext/object.rb +14 -13
  111. data/lib/active_support/core_ext/range/compare_range.rb +61 -0
  112. data/lib/active_support/core_ext/range/conversions.rb +27 -7
  113. data/lib/active_support/core_ext/range/each.rb +19 -17
  114. data/lib/active_support/core_ext/range/include_range.rb +2 -22
  115. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  116. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  117. data/lib/active_support/core_ext/range.rb +7 -4
  118. data/lib/active_support/core_ext/regexp.rb +6 -0
  119. data/lib/active_support/core_ext/securerandom.rb +25 -0
  120. data/lib/active_support/core_ext/string/access.rb +8 -6
  121. data/lib/active_support/core_ext/string/behavior.rb +3 -1
  122. data/lib/active_support/core_ext/string/conversions.rb +7 -4
  123. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  124. data/lib/active_support/core_ext/string/filters.rb +6 -5
  125. data/lib/active_support/core_ext/string/indent.rb +6 -4
  126. data/lib/active_support/core_ext/string/inflections.rb +61 -24
  127. data/lib/active_support/core_ext/string/inquiry.rb +3 -1
  128. data/lib/active_support/core_ext/string/multibyte.rb +15 -7
  129. data/lib/active_support/core_ext/string/output_safety.rb +34 -38
  130. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -0
  131. data/lib/active_support/core_ext/string/strip.rb +4 -5
  132. data/lib/active_support/core_ext/string/zones.rb +4 -2
  133. data/lib/active_support/core_ext/string.rb +15 -13
  134. data/lib/active_support/core_ext/time/acts_like.rb +3 -1
  135. data/lib/active_support/core_ext/time/calculations.rb +88 -52
  136. data/lib/active_support/core_ext/time/compatibility.rb +12 -1
  137. data/lib/active_support/core_ext/time/conversions.rb +20 -13
  138. data/lib/active_support/core_ext/time/zones.rb +41 -7
  139. data/lib/active_support/core_ext/time.rb +7 -6
  140. data/lib/active_support/core_ext/uri.rb +6 -8
  141. data/lib/active_support/core_ext.rb +3 -1
  142. data/lib/active_support/current_attributes.rb +195 -0
  143. data/lib/active_support/dependencies/autoload.rb +2 -0
  144. data/lib/active_support/dependencies/interlock.rb +57 -0
  145. data/lib/active_support/dependencies.rb +152 -161
  146. data/lib/active_support/deprecation/behaviors.rb +44 -11
  147. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  148. data/lib/active_support/deprecation/instance_delegator.rb +17 -2
  149. data/lib/active_support/deprecation/method_wrappers.rb +66 -20
  150. data/lib/active_support/deprecation/proxy_wrappers.rb +56 -28
  151. data/lib/active_support/deprecation/reporting.rb +32 -12
  152. data/lib/active_support/deprecation.rb +12 -9
  153. data/lib/active_support/descendants_tracker.rb +2 -0
  154. data/lib/active_support/digest.rb +20 -0
  155. data/lib/active_support/duration/iso8601_parser.rb +125 -0
  156. data/lib/active_support/duration/iso8601_serializer.rb +55 -0
  157. data/lib/active_support/duration.rb +314 -38
  158. data/lib/active_support/encrypted_configuration.rb +49 -0
  159. data/lib/active_support/encrypted_file.rb +99 -0
  160. data/lib/active_support/evented_file_update_checker.rb +205 -0
  161. data/lib/active_support/execution_wrapper.rb +128 -0
  162. data/lib/active_support/executor.rb +8 -0
  163. data/lib/active_support/file_update_checker.rb +63 -37
  164. data/lib/active_support/gem_version.rb +5 -3
  165. data/lib/active_support/gzip.rb +7 -5
  166. data/lib/active_support/hash_with_indifferent_access.rb +127 -28
  167. data/lib/active_support/i18n.rb +8 -6
  168. data/lib/active_support/i18n_railtie.rb +37 -13
  169. data/lib/active_support/inflections.rb +13 -11
  170. data/lib/active_support/inflector/inflections.rb +61 -12
  171. data/lib/active_support/inflector/methods.rb +163 -136
  172. data/lib/active_support/inflector/transliterate.rb +48 -27
  173. data/lib/active_support/inflector.rb +7 -5
  174. data/lib/active_support/json/decoding.rb +16 -13
  175. data/lib/active_support/json/encoding.rb +11 -58
  176. data/lib/active_support/json.rb +4 -2
  177. data/lib/active_support/key_generator.rb +25 -25
  178. data/lib/active_support/lazy_load_hooks.rb +50 -20
  179. data/lib/active_support/locale/en.yml +2 -0
  180. data/lib/active_support/log_subscriber/test_helper.rb +14 -12
  181. data/lib/active_support/log_subscriber.rb +13 -10
  182. data/lib/active_support/logger.rb +19 -7
  183. data/lib/active_support/logger_silence.rb +6 -4
  184. data/lib/active_support/logger_thread_safe_level.rb +7 -5
  185. data/lib/active_support/message_encryptor.rb +168 -53
  186. data/lib/active_support/message_verifier.rb +150 -17
  187. data/lib/active_support/messages/metadata.rb +71 -0
  188. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  189. data/lib/active_support/messages/rotator.rb +56 -0
  190. data/lib/active_support/multibyte/chars.rb +36 -23
  191. data/lib/active_support/multibyte/unicode.rb +100 -96
  192. data/lib/active_support/multibyte.rb +4 -2
  193. data/lib/active_support/notifications/fanout.rb +11 -9
  194. data/lib/active_support/notifications/instrumenter.rb +27 -7
  195. data/lib/active_support/notifications.rb +11 -7
  196. data/lib/active_support/number_helper/number_converter.rb +13 -11
  197. data/lib/active_support/number_helper/number_to_currency_converter.rb +9 -9
  198. data/lib/active_support/number_helper/number_to_delimited_converter.rb +9 -3
  199. data/lib/active_support/number_helper/number_to_human_converter.rb +11 -9
  200. data/lib/active_support/number_helper/number_to_human_size_converter.rb +9 -8
  201. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  202. data/lib/active_support/number_helper/number_to_phone_converter.rb +13 -4
  203. data/lib/active_support/number_helper/number_to_rounded_converter.rb +23 -56
  204. data/lib/active_support/number_helper/rounding_helper.rb +66 -0
  205. data/lib/active_support/number_helper.rb +94 -68
  206. data/lib/active_support/option_merger.rb +3 -1
  207. data/lib/active_support/ordered_hash.rb +6 -4
  208. data/lib/active_support/ordered_options.rb +23 -5
  209. data/lib/active_support/per_thread_registry.rb +9 -4
  210. data/lib/active_support/proxy_object.rb +2 -0
  211. data/lib/active_support/rails.rb +16 -8
  212. data/lib/active_support/railtie.rb +43 -9
  213. data/lib/active_support/reloader.rb +131 -0
  214. data/lib/active_support/rescuable.rb +108 -53
  215. data/lib/active_support/security_utils.rb +15 -11
  216. data/lib/active_support/string_inquirer.rb +11 -3
  217. data/lib/active_support/subscriber.rb +21 -16
  218. data/lib/active_support/tagged_logging.rb +14 -11
  219. data/lib/active_support/test_case.rb +19 -47
  220. data/lib/active_support/testing/assertions.rb +137 -20
  221. data/lib/active_support/testing/autorun.rb +4 -2
  222. data/lib/active_support/testing/constant_lookup.rb +2 -1
  223. data/lib/active_support/testing/declarative.rb +3 -1
  224. data/lib/active_support/testing/deprecation.rb +14 -10
  225. data/lib/active_support/testing/file_fixtures.rb +36 -0
  226. data/lib/active_support/testing/isolation.rb +34 -25
  227. data/lib/active_support/testing/method_call_assertions.rb +43 -0
  228. data/lib/active_support/testing/setup_and_teardown.rb +13 -8
  229. data/lib/active_support/testing/stream.rb +44 -0
  230. data/lib/active_support/testing/tagged_logging.rb +3 -1
  231. data/lib/active_support/testing/time_helpers.rb +91 -23
  232. data/lib/active_support/time.rb +14 -12
  233. data/lib/active_support/time_with_zone.rb +182 -40
  234. data/lib/active_support/values/time_zone.rb +196 -61
  235. data/lib/active_support/values/unicode_tables.dat +0 -0
  236. data/lib/active_support/version.rb +3 -1
  237. data/lib/active_support/xml_mini/jdom.rb +116 -114
  238. data/lib/active_support/xml_mini/libxml.rb +17 -16
  239. data/lib/active_support/xml_mini/libxmlsax.rb +16 -18
  240. data/lib/active_support/xml_mini/nokogiri.rb +15 -15
  241. data/lib/active_support/xml_mini/nokogirisax.rb +15 -16
  242. data/lib/active_support/xml_mini/rexml.rb +11 -9
  243. data/lib/active_support/xml_mini.rb +37 -37
  244. data/lib/active_support.rb +12 -11
  245. metadata +54 -25
  246. data/lib/active_support/concurrency/latch.rb +0 -27
  247. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
  248. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  249. data/lib/active_support/core_ext/date_time/zones.rb +0 -6
  250. data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
  251. data/lib/active_support/core_ext/module/method_transplanting.rb +0 -13
  252. data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
  253. data/lib/active_support/core_ext/object/itself.rb +0 -15
  254. data/lib/active_support/core_ext/struct.rb +0 -6
  255. data/lib/active_support/core_ext/thread.rb +0 -86
  256. data/lib/active_support/core_ext/time/marshal.rb +0 -30
@@ -1,34 +1,32 @@
1
- require 'erb'
2
- require 'active_support/core_ext/kernel/singleton_class'
3
- require 'active_support/deprecation'
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "active_support/core_ext/kernel/singleton_class"
5
+ require "active_support/core_ext/module/redefine_method"
6
+ require "active_support/multibyte/unicode"
4
7
 
5
8
  class ERB
6
9
  module Util
7
- HTML_ESCAPE = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;', "'" => '&#39;' }
8
- JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003e', '<' => '\u003c', "\u2028" => '\u2028', "\u2029" => '\u2029' }
9
- HTML_ESCAPE_REGEXP = /[&"'><]/
10
+ HTML_ESCAPE = { "&" => "&amp;", ">" => "&gt;", "<" => "&lt;", '"' => "&quot;", "'" => "&#39;" }
11
+ JSON_ESCAPE = { "&" => '\u0026', ">" => '\u003e', "<" => '\u003c', "\u2028" => '\u2028', "\u2029" => '\u2029' }
10
12
  HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
11
13
  JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u
12
14
 
13
15
  # A utility method for escaping HTML tag characters.
14
16
  # This method is also aliased as <tt>h</tt>.
15
17
  #
16
- # In your ERB templates, use this method to escape any unsafe content. For example:
17
- # <%=h @person.name %>
18
- #
19
18
  # puts html_escape('is a > 0 & a < 10?')
20
19
  # # => is a &gt; 0 &amp; a &lt; 10?
21
20
  def html_escape(s)
22
21
  unwrapped_html_escape(s).html_safe
23
22
  end
24
23
 
25
- # Aliasing twice issues a warning "discarding old...". Remove first to avoid it.
26
- remove_method(:h)
24
+ silence_redefinition_of_method :h
27
25
  alias h html_escape
28
26
 
29
27
  module_function :h
30
28
 
31
- singleton_class.send(:remove_method, :html_escape)
29
+ singleton_class.silence_redefinition_of_method :html_escape
32
30
  module_function :html_escape
33
31
 
34
32
  # HTML escapes strings but doesn't wrap them with an ActiveSupport::SafeBuffer.
@@ -38,7 +36,7 @@ class ERB
38
36
  if s.html_safe?
39
37
  s
40
38
  else
41
- s.gsub(HTML_ESCAPE_REGEXP, HTML_ESCAPE)
39
+ CGI.escapeHTML(ActiveSupport::Multibyte::Unicode.tidy_bytes(s))
42
40
  end
43
41
  end
44
42
  module_function :unwrapped_html_escape
@@ -51,7 +49,7 @@ class ERB
51
49
  # html_escape_once('&lt;&lt; Accept & Checkout')
52
50
  # # => "&lt;&lt; Accept &amp; Checkout"
53
51
  def html_escape_once(s)
54
- result = s.to_s.gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE)
52
+ result = ActiveSupport::Multibyte::Unicode.tidy_bytes(s.to_s).gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE)
55
53
  s.html_safe? ? result.html_safe : result
56
54
  end
57
55
 
@@ -86,6 +84,11 @@ class ERB
86
84
  # automatically flag the result as HTML safe, since the raw value is unsafe to
87
85
  # use inside HTML attributes.
88
86
  #
87
+ # If your JSON is being used downstream for insertion into the DOM, be aware of
88
+ # whether or not it is being inserted via +html()+. Most jQuery plugins do this.
89
+ # If that is the case, be sure to +html_escape+ or +sanitize+ any user-generated
90
+ # content returned by your JSON.
91
+ #
89
92
  # If you need to output JSON elsewhere in your HTML, you can just do something
90
93
  # like this, as any unsafe characters (including quotation marks) will be
91
94
  # automatically escaped for you:
@@ -138,27 +141,26 @@ module ActiveSupport #:nodoc:
138
141
  alias_method :original_concat, :concat
139
142
  private :original_concat
140
143
 
144
+ # Raised when <tt>ActiveSupport::SafeBuffer#safe_concat</tt> is called on unsafe buffers.
141
145
  class SafeConcatError < StandardError
142
146
  def initialize
143
- super 'Could not concatenate to the buffer because it is not html safe.'
147
+ super "Could not concatenate to the buffer because it is not html safe."
144
148
  end
145
149
  end
146
150
 
147
151
  def [](*args)
148
152
  if args.size < 2
149
153
  super
150
- else
151
- if html_safe?
152
- new_safe_buffer = super
153
-
154
- if new_safe_buffer
155
- new_safe_buffer.instance_variable_set :@html_safe, true
156
- end
154
+ elsif html_safe?
155
+ new_safe_buffer = super
157
156
 
158
- new_safe_buffer
159
- else
160
- to_str[*args]
157
+ if new_safe_buffer
158
+ new_safe_buffer.instance_variable_set :@html_safe, true
161
159
  end
160
+
161
+ new_safe_buffer
162
+ else
163
+ to_str[*args]
162
164
  end
163
165
  end
164
166
 
@@ -167,7 +169,7 @@ module ActiveSupport #:nodoc:
167
169
  original_concat(value)
168
170
  end
169
171
 
170
- def initialize(*)
172
+ def initialize(str = "")
171
173
  @html_safe = true
172
174
  super
173
175
  end
@@ -190,11 +192,6 @@ module ActiveSupport #:nodoc:
190
192
  super(html_escape_interpolated_argument(value))
191
193
  end
192
194
 
193
- def prepend!(value)
194
- ActiveSupport::Deprecation.deprecation_warning "ActiveSupport::SafeBuffer#prepend!", :prepend
195
- prepend value
196
- end
197
-
198
195
  def +(other)
199
196
  dup.concat(other)
200
197
  end
@@ -202,7 +199,7 @@ module ActiveSupport #:nodoc:
202
199
  def %(args)
203
200
  case args
204
201
  when Hash
205
- escaped_args = Hash[args.map { |k,arg| [k, html_escape_interpolated_argument(arg)] }]
202
+ escaped_args = Hash[args.map { |k, arg| [k, html_escape_interpolated_argument(arg)] }]
206
203
  else
207
204
  escaped_args = Array(args).map { |arg| html_escape_interpolated_argument(arg) }
208
205
  end
@@ -243,18 +240,17 @@ module ActiveSupport #:nodoc:
243
240
 
244
241
  private
245
242
 
246
- def html_escape_interpolated_argument(arg)
247
- (!html_safe? || arg.html_safe?) ? arg :
248
- arg.to_s.gsub(ERB::Util::HTML_ESCAPE_REGEXP, ERB::Util::HTML_ESCAPE)
249
- end
243
+ def html_escape_interpolated_argument(arg)
244
+ (!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
245
+ end
250
246
  end
251
247
  end
252
248
 
253
249
  class String
254
250
  # Marks a string as trusted safe. It will be inserted into HTML with no
255
- # additional escaping performed. It is your responsibilty to ensure that the
251
+ # additional escaping performed. It is your responsibility to ensure that the
256
252
  # string contains no malicious content. This method is equivalent to the
257
- # `raw` helper in views. It is recommended that you use `sanitize` instead of
253
+ # +raw+ helper in views. It is recommended that you use +sanitize+ instead of
258
254
  # this method. It should never be called on user input.
259
255
  def html_safe
260
256
  ActiveSupport::SafeBuffer.new(self)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class String
2
4
  alias_method :starts_with?, :start_with?
3
5
  alias_method :ends_with?, :end_with?
@@ -1,4 +1,4 @@
1
- require 'active_support/core_ext/object/try'
1
+ # frozen_string_literal: true
2
2
 
3
3
  class String
4
4
  # Strips indentation in heredocs.
@@ -17,10 +17,9 @@ class String
17
17
  #
18
18
  # the user would see the usage message aligned against the left margin.
19
19
  #
20
- # Technically, it looks for the least indented line in the whole string, and removes
21
- # that amount of leading whitespace.
20
+ # Technically, it looks for the least indented non-empty line
21
+ # in the whole string, and removes that amount of leading whitespace.
22
22
  def strip_heredoc
23
- indent = scan(/^[ \t]*(?=\S)/).min.try(:size) || 0
24
- gsub(/^[ \t]{#{indent}}/, '')
23
+ gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, "".freeze)
25
24
  end
26
25
  end
@@ -1,5 +1,7 @@
1
- require 'active_support/core_ext/string/conversions'
2
- require 'active_support/core_ext/time/zones'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/conversions"
4
+ require "active_support/core_ext/time/zones"
3
5
 
4
6
  class String
5
7
  # Converts String to a TimeWithZone in the current zone if Time.zone or Time.zone_default
@@ -1,13 +1,15 @@
1
- require 'active_support/core_ext/string/conversions'
2
- require 'active_support/core_ext/string/filters'
3
- require 'active_support/core_ext/string/multibyte'
4
- require 'active_support/core_ext/string/starts_ends_with'
5
- require 'active_support/core_ext/string/inflections'
6
- require 'active_support/core_ext/string/access'
7
- require 'active_support/core_ext/string/behavior'
8
- require 'active_support/core_ext/string/output_safety'
9
- require 'active_support/core_ext/string/exclude'
10
- require 'active_support/core_ext/string/strip'
11
- require 'active_support/core_ext/string/inquiry'
12
- require 'active_support/core_ext/string/indent'
13
- require 'active_support/core_ext/string/zones'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/conversions"
4
+ require "active_support/core_ext/string/filters"
5
+ require "active_support/core_ext/string/multibyte"
6
+ require "active_support/core_ext/string/starts_ends_with"
7
+ require "active_support/core_ext/string/inflections"
8
+ require "active_support/core_ext/string/access"
9
+ require "active_support/core_ext/string/behavior"
10
+ require "active_support/core_ext/string/output_safety"
11
+ require "active_support/core_ext/string/exclude"
12
+ require "active_support/core_ext/string/strip"
13
+ require "active_support/core_ext/string/inquiry"
14
+ require "active_support/core_ext/string/indent"
15
+ require "active_support/core_ext/string/zones"
@@ -1,4 +1,6 @@
1
- require 'active_support/core_ext/object/acts_like'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/object/acts_like"
2
4
 
3
5
  class Time
4
6
  # Duck-types as a Time-like class. See Object#acts_like?.
@@ -1,9 +1,11 @@
1
- require 'active_support/duration'
2
- require 'active_support/core_ext/time/conversions'
3
- require 'active_support/time_with_zone'
4
- require 'active_support/core_ext/time/zones'
5
- require 'active_support/core_ext/date_and_time/calculations'
6
- require 'active_support/core_ext/date/calculations'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/duration"
4
+ require "active_support/core_ext/time/conversions"
5
+ require "active_support/time_with_zone"
6
+ require "active_support/core_ext/time/zones"
7
+ require "active_support/core_ext/date_and_time/calculations"
8
+ require "active_support/core_ext/date/calculations"
7
9
 
8
10
  class Time
9
11
  include DateAndTime::Calculations
@@ -16,9 +18,9 @@ class Time
16
18
  super || (self == Time && other.is_a?(ActiveSupport::TimeWithZone))
17
19
  end
18
20
 
19
- # Return the number of days in the given month.
21
+ # Returns the number of days in the given month.
20
22
  # If no year is specified, it will use the current year.
21
- def days_in_month(month, year = now.year)
23
+ def days_in_month(month, year = current.year)
22
24
  if month == 2 && ::Date.gregorian_leap?(year)
23
25
  29
24
26
  else
@@ -26,6 +28,12 @@ class Time
26
28
  end
27
29
  end
28
30
 
31
+ # Returns the number of days in the given year.
32
+ # If no year is specified, it will use the current year.
33
+ def days_in_year(year = current.year)
34
+ days_in_month(2, year) + 337
35
+ end
36
+
29
37
  # Returns <tt>Time.zone.now</tt> when <tt>Time.zone</tt> or <tt>config.time_zone</tt> are set, otherwise just returns <tt>Time.now</tt>.
30
38
  def current
31
39
  ::Time.zone ? ::Time.zone.now : ::Time.now
@@ -47,11 +55,38 @@ class Time
47
55
  end
48
56
  alias_method :at_without_coercion, :at
49
57
  alias_method :at, :at_with_coercion
58
+
59
+ # Creates a +Time+ instance from an RFC 3339 string.
60
+ #
61
+ # Time.rfc3339('1999-12-31T14:00:00-10:00') # => 2000-01-01 00:00:00 -1000
62
+ #
63
+ # If the time or offset components are missing then an +ArgumentError+ will be raised.
64
+ #
65
+ # Time.rfc3339('1999-12-31') # => ArgumentError: invalid date
66
+ def rfc3339(str)
67
+ parts = Date._rfc3339(str)
68
+
69
+ raise ArgumentError, "invalid date" if parts.empty?
70
+
71
+ Time.new(
72
+ parts.fetch(:year),
73
+ parts.fetch(:mon),
74
+ parts.fetch(:mday),
75
+ parts.fetch(:hour),
76
+ parts.fetch(:min),
77
+ parts.fetch(:sec) + parts.fetch(:sec_fraction, 0),
78
+ parts.fetch(:offset)
79
+ )
80
+ end
50
81
  end
51
82
 
52
- # Seconds since midnight: Time.now.seconds_since_midnight
83
+ # Returns the number of seconds since 00:00:00.
84
+ #
85
+ # Time.new(2012, 8, 29, 0, 0, 0).seconds_since_midnight # => 0.0
86
+ # Time.new(2012, 8, 29, 12, 34, 56).seconds_since_midnight # => 45296.0
87
+ # Time.new(2012, 8, 29, 23, 59, 59).seconds_since_midnight # => 86399.0
53
88
  def seconds_since_midnight
54
- to_i - change(:hour => 0).to_i + (usec / 1.0e+6)
89
+ to_i - change(hour: 0).to_i + (usec / 1.0e+6)
55
90
  end
56
91
 
57
92
  # Returns the number of seconds until 23:59:59.
@@ -74,36 +109,42 @@ class Time
74
109
  # to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>,
75
110
  # <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly, so if only
76
111
  # the hour is passed, then minute, sec, usec and nsec is set to 0. If the hour
77
- # and minute is passed, then sec, usec and nsec is set to 0. The +options+
78
- # parameter takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>,
79
- # <tt>:day</tt>, <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>
80
- # <tt>:nsec</tt>. Path either <tt>:usec</tt> or <tt>:nsec</tt>, not both.
112
+ # and minute is passed, then sec, usec and nsec is set to 0. The +options+ parameter
113
+ # takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>,
114
+ # <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>,
115
+ # <tt>:offset</tt>. Pass either <tt>:usec</tt> or <tt>:nsec</tt>, not both.
81
116
  #
82
117
  # Time.new(2012, 8, 29, 22, 35, 0).change(day: 1) # => Time.new(2012, 8, 1, 22, 35, 0)
83
118
  # Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, day: 1) # => Time.new(1981, 8, 1, 22, 35, 0)
84
119
  # Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, hour: 0) # => Time.new(1981, 8, 29, 0, 0, 0)
85
120
  def change(options)
86
- new_year = options.fetch(:year, year)
87
- new_month = options.fetch(:month, month)
88
- new_day = options.fetch(:day, day)
89
- new_hour = options.fetch(:hour, hour)
90
- new_min = options.fetch(:min, options[:hour] ? 0 : min)
91
- new_sec = options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec)
121
+ new_year = options.fetch(:year, year)
122
+ new_month = options.fetch(:month, month)
123
+ new_day = options.fetch(:day, day)
124
+ new_hour = options.fetch(:hour, hour)
125
+ new_min = options.fetch(:min, options[:hour] ? 0 : min)
126
+ new_sec = options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec)
127
+ new_offset = options.fetch(:offset, nil)
92
128
 
93
129
  if new_nsec = options[:nsec]
94
130
  raise ArgumentError, "Can't change both :nsec and :usec at the same time: #{options.inspect}" if options[:usec]
95
131
  new_usec = Rational(new_nsec, 1000)
96
132
  else
97
- new_usec = options.fetch(:usec, (options[:hour] || options[:min] || options[:sec]) ? 0 : Rational(nsec, 1000))
133
+ new_usec = options.fetch(:usec, (options[:hour] || options[:min] || options[:sec]) ? 0 : Rational(nsec, 1000))
98
134
  end
99
135
 
100
- if utc?
101
- ::Time.utc(new_year, new_month, new_day, new_hour, new_min, new_sec, new_usec)
136
+ raise ArgumentError, "argument out of range" if new_usec >= 1000000
137
+
138
+ new_sec += Rational(new_usec, 1000000)
139
+
140
+ if new_offset
141
+ ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, new_offset)
142
+ elsif utc?
143
+ ::Time.utc(new_year, new_month, new_day, new_hour, new_min, new_sec)
102
144
  elsif zone
103
- ::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec, new_usec)
145
+ ::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec)
104
146
  else
105
- raise ArgumentError, 'argument out of range' if new_usec >= 1000000
106
- ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec + (new_usec.to_r / 1000000), utc_offset)
147
+ ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, utc_offset)
107
148
  end
108
149
  end
109
150
 
@@ -131,7 +172,7 @@ class Time
131
172
 
132
173
  d = to_date.advance(options)
133
174
  d = d.gregorian if d.julian?
134
- time_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
175
+ time_advanced_by_date = change(year: d.year, month: d.month, day: d.day)
135
176
  seconds_to_advance = \
136
177
  options.fetch(:seconds, 0) +
137
178
  options.fetch(:minutes, 0) * 60 +
@@ -159,8 +200,7 @@ class Time
159
200
 
160
201
  # Returns a new Time representing the start of the day (0:00)
161
202
  def beginning_of_day
162
- #(self - seconds_since_midnight).change(usec: 0)
163
- change(:hour => 0)
203
+ change(hour: 0)
164
204
  end
165
205
  alias :midnight :beginning_of_day
166
206
  alias :at_midnight :beginning_of_day
@@ -168,7 +208,7 @@ class Time
168
208
 
169
209
  # Returns a new Time representing the middle of the day (12:00)
170
210
  def middle_of_day
171
- change(:hour => 12)
211
+ change(hour: 12)
172
212
  end
173
213
  alias :midday :middle_of_day
174
214
  alias :noon :middle_of_day
@@ -176,53 +216,48 @@ class Time
176
216
  alias :at_noon :middle_of_day
177
217
  alias :at_middle_of_day :middle_of_day
178
218
 
179
- # Returns a new Time representing the end of the day, 23:59:59.999999 (.999999999 in ruby1.9)
219
+ # Returns a new Time representing the end of the day, 23:59:59.999999
180
220
  def end_of_day
181
221
  change(
182
- :hour => 23,
183
- :min => 59,
184
- :sec => 59,
185
- :usec => Rational(999999999, 1000)
222
+ hour: 23,
223
+ min: 59,
224
+ sec: 59,
225
+ usec: Rational(999999999, 1000)
186
226
  )
187
227
  end
188
228
  alias :at_end_of_day :end_of_day
189
229
 
190
230
  # Returns a new Time representing the start of the hour (x:00)
191
231
  def beginning_of_hour
192
- change(:min => 0)
232
+ change(min: 0)
193
233
  end
194
234
  alias :at_beginning_of_hour :beginning_of_hour
195
235
 
196
- # Returns a new Time representing the end of the hour, x:59:59.999999 (.999999999 in ruby1.9)
236
+ # Returns a new Time representing the end of the hour, x:59:59.999999
197
237
  def end_of_hour
198
238
  change(
199
- :min => 59,
200
- :sec => 59,
201
- :usec => Rational(999999999, 1000)
239
+ min: 59,
240
+ sec: 59,
241
+ usec: Rational(999999999, 1000)
202
242
  )
203
243
  end
204
244
  alias :at_end_of_hour :end_of_hour
205
245
 
206
246
  # Returns a new Time representing the start of the minute (x:xx:00)
207
247
  def beginning_of_minute
208
- change(:sec => 0)
248
+ change(sec: 0)
209
249
  end
210
250
  alias :at_beginning_of_minute :beginning_of_minute
211
251
 
212
- # Returns a new Time representing the end of the minute, x:xx:59.999999 (.999999999 in ruby1.9)
252
+ # Returns a new Time representing the end of the minute, x:xx:59.999999
213
253
  def end_of_minute
214
254
  change(
215
- :sec => 59,
216
- :usec => Rational(999999999, 1000)
255
+ sec: 59,
256
+ usec: Rational(999999999, 1000)
217
257
  )
218
258
  end
219
259
  alias :at_end_of_minute :end_of_minute
220
260
 
221
- # Returns a Range representing the whole day of the current time.
222
- def all_day
223
- beginning_of_day..end_of_day
224
- end
225
-
226
261
  def plus_with_duration(other) #:nodoc:
227
262
  if ActiveSupport::Duration === other
228
263
  other.since(self)
@@ -256,8 +291,10 @@ class Time
256
291
  # Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances
257
292
  # can be chronologically compared with a Time
258
293
  def compare_with_coercion(other)
259
- # we're avoiding Time#to_datetime cause it's expensive
260
- if other.is_a?(Time)
294
+ # we're avoiding Time#to_datetime and Time#to_time because they're expensive
295
+ if other.class == Time
296
+ compare_without_coercion(other)
297
+ elsif other.is_a?(Time)
261
298
  compare_without_coercion(other.to_time)
262
299
  else
263
300
  to_datetime <=> other
@@ -275,5 +312,4 @@ class Time
275
312
  end
276
313
  alias_method :eql_without_coercion, :eql?
277
314
  alias_method :eql?, :eql_with_coercion
278
-
279
315
  end
@@ -1,5 +1,16 @@
1
- require 'active_support/core_ext/date_and_time/compatibility'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/date_and_time/compatibility"
4
+ require "active_support/core_ext/module/redefine_method"
2
5
 
3
6
  class Time
4
7
  include DateAndTime::Compatibility
8
+
9
+ silence_redefinition_of_method :to_time
10
+
11
+ # Either return +self+ or the time in the local system timezone depending
12
+ # on the setting of +ActiveSupport.to_time_preserves_timezone+.
13
+ def to_time
14
+ preserve_timezone ? self : getlocal
15
+ end
5
16
  end
@@ -1,30 +1,33 @@
1
- require 'active_support/inflector/methods'
2
- require 'active_support/values/time_zone'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/inflector/methods"
4
+ require "active_support/values/time_zone"
3
5
 
4
6
  class Time
5
7
  DATE_FORMATS = {
6
- :db => '%Y-%m-%d %H:%M:%S',
7
- :number => '%Y%m%d%H%M%S',
8
- :nsec => '%Y%m%d%H%M%S%9N',
9
- :time => '%H:%M',
10
- :short => '%d %b %H:%M',
11
- :long => '%B %d, %Y %H:%M',
12
- :long_ordinal => lambda { |time|
8
+ db: "%Y-%m-%d %H:%M:%S",
9
+ number: "%Y%m%d%H%M%S",
10
+ nsec: "%Y%m%d%H%M%S%9N",
11
+ usec: "%Y%m%d%H%M%S%6N",
12
+ time: "%H:%M",
13
+ short: "%d %b %H:%M",
14
+ long: "%B %d, %Y %H:%M",
15
+ long_ordinal: lambda { |time|
13
16
  day_format = ActiveSupport::Inflector.ordinalize(time.day)
14
17
  time.strftime("%B #{day_format}, %Y %H:%M")
15
18
  },
16
- :rfc822 => lambda { |time|
19
+ rfc822: lambda { |time|
17
20
  offset_format = time.formatted_offset(false)
18
21
  time.strftime("%a, %d %b %Y %H:%M:%S #{offset_format}")
19
22
  },
20
- :iso8601 => lambda { |time| time.iso8601 }
23
+ iso8601: lambda { |time| time.iso8601 }
21
24
  }
22
25
 
23
26
  # Converts to a formatted string. See DATE_FORMATS for built-in formats.
24
27
  #
25
28
  # This method is aliased to <tt>to_s</tt>.
26
29
  #
27
- # time = Time.now # => Thu Jan 18 06:10:17 CST 2007
30
+ # time = Time.now # => 2007-01-18 06:10:17 -06:00
28
31
  #
29
32
  # time.to_formatted_s(:time) # => "06:10"
30
33
  # time.to_s(:time) # => "06:10"
@@ -55,11 +58,15 @@ class Time
55
58
  alias_method :to_default_s, :to_s
56
59
  alias_method :to_s, :to_formatted_s
57
60
 
58
- # Returns the UTC offset as an +HH:MM formatted string.
61
+ # Returns a formatted string of the offset from UTC, or an alternative
62
+ # string if the time zone is already UTC.
59
63
  #
60
64
  # Time.local(2000).formatted_offset # => "-06:00"
61
65
  # Time.local(2000).formatted_offset(false) # => "-0600"
62
66
  def formatted_offset(colon = true, alternate_utc_string = nil)
63
67
  utc? && alternate_utc_string || ActiveSupport::TimeZone.seconds_to_utc_offset(utc_offset, colon)
64
68
  end
69
+
70
+ # Aliased to +xmlschema+ for compatibility with +DateTime+
71
+ alias_method :rfc3339, :xmlschema
65
72
  end
@@ -1,6 +1,8 @@
1
- require 'active_support/time_with_zone'
2
- require 'active_support/core_ext/time/acts_like'
3
- require 'active_support/core_ext/date_and_time/zones'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/time_with_zone"
4
+ require "active_support/core_ext/time/acts_like"
5
+ require "active_support/core_ext/date_and_time/zones"
4
6
 
5
7
  class Time
6
8
  include DateAndTime::Zones
@@ -26,7 +28,7 @@ class Time
26
28
  # <tt>current_user.time_zone</tt> just needs to return a string identifying the user's preferred time zone:
27
29
  #
28
30
  # class ApplicationController < ActionController::Base
29
- # around_filter :set_time_zone
31
+ # around_action :set_time_zone
30
32
  #
31
33
  # def set_time_zone
32
34
  # if logged_in?
@@ -40,7 +42,23 @@ class Time
40
42
  Thread.current[:time_zone] = find_zone!(time_zone)
41
43
  end
42
44
 
43
- # Allows override of <tt>Time.zone</tt> locally inside supplied block; resets <tt>Time.zone</tt> to existing value when done.
45
+ # Allows override of <tt>Time.zone</tt> locally inside supplied block;
46
+ # resets <tt>Time.zone</tt> to existing value when done.
47
+ #
48
+ # class ApplicationController < ActionController::Base
49
+ # around_action :set_time_zone
50
+ #
51
+ # private
52
+ #
53
+ # def set_time_zone
54
+ # Time.use_zone(current_user.timezone) { yield }
55
+ # end
56
+ # end
57
+ #
58
+ # NOTE: This won't affect any <tt>ActiveSupport::TimeWithZone</tt>
59
+ # objects that have already been created, e.g. any model timestamp
60
+ # attributes that have been read before the block will remain in
61
+ # the application's default timezone.
44
62
  def use_zone(time_zone)
45
63
  new_zone = find_zone!(time_zone)
46
64
  begin
@@ -51,12 +69,22 @@ class Time
51
69
  end
52
70
  end
53
71
 
54
- # Returns a TimeZone instance or nil, or raises an ArgumentError for invalid timezones.
72
+ # Returns a TimeZone instance matching the time zone provided.
73
+ # Accepts the time zone in any format supported by <tt>Time.zone=</tt>.
74
+ # Raises an +ArgumentError+ for invalid time zones.
75
+ #
76
+ # Time.find_zone! "America/New_York" # => #<ActiveSupport::TimeZone @name="America/New_York" ...>
77
+ # Time.find_zone! "EST" # => #<ActiveSupport::TimeZone @name="EST" ...>
78
+ # Time.find_zone! -5.hours # => #<ActiveSupport::TimeZone @name="Bogota" ...>
79
+ # Time.find_zone! nil # => nil
80
+ # Time.find_zone! false # => false
81
+ # Time.find_zone! "NOT-A-TIMEZONE" # => ArgumentError: Invalid Timezone: NOT-A-TIMEZONE
55
82
  def find_zone!(time_zone)
56
83
  if !time_zone || time_zone.is_a?(ActiveSupport::TimeZone)
57
84
  time_zone
58
85
  else
59
- # lookup timezone based on identifier (unless we've been passed a TZInfo::Timezone)
86
+ # Look up the timezone based on the identifier (unless we've been
87
+ # passed a TZInfo::Timezone)
60
88
  unless time_zone.respond_to?(:period_for_local)
61
89
  time_zone = ActiveSupport::TimeZone[time_zone] || TZInfo::Timezone.get(time_zone)
62
90
  end
@@ -72,6 +100,12 @@ class Time
72
100
  raise ArgumentError, "Invalid Timezone: #{time_zone}"
73
101
  end
74
102
 
103
+ # Returns a TimeZone instance matching the time zone provided.
104
+ # Accepts the time zone in any format supported by <tt>Time.zone=</tt>.
105
+ # Returns +nil+ for invalid time zones.
106
+ #
107
+ # Time.find_zone "America/New_York" # => #<ActiveSupport::TimeZone @name="America/New_York" ...>
108
+ # Time.find_zone "NOT-A-TIMEZONE" # => nil
75
109
  def find_zone(time_zone)
76
110
  find_zone!(time_zone) rescue nil
77
111
  end