activesupport 5.1.1 → 6.1.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 (262) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +360 -442
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -4
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/all.rb +2 -0
  7. data/lib/active_support/array_inquirer.rb +6 -2
  8. data/lib/active_support/backtrace_cleaner.rb +31 -3
  9. data/lib/active_support/benchmarkable.rb +3 -1
  10. data/lib/active_support/builder.rb +2 -0
  11. data/lib/active_support/cache/file_store.rb +37 -36
  12. data/lib/active_support/cache/mem_cache_store.rb +65 -53
  13. data/lib/active_support/cache/memory_store.rb +61 -33
  14. data/lib/active_support/cache/null_store.rb +10 -3
  15. data/lib/active_support/cache/redis_cache_store.rb +493 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +68 -22
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +2 -0
  18. data/lib/active_support/cache.rb +305 -127
  19. data/lib/active_support/callbacks.rb +106 -98
  20. data/lib/active_support/concern.rb +79 -6
  21. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
  22. data/lib/active_support/concurrency/share_lock.rb +2 -1
  23. data/lib/active_support/configurable.rb +12 -14
  24. data/lib/active_support/configuration_file.rb +46 -0
  25. data/lib/active_support/core_ext/array/access.rb +21 -7
  26. data/lib/active_support/core_ext/array/conversions.rb +7 -5
  27. data/lib/active_support/core_ext/array/extract.rb +21 -0
  28. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  29. data/lib/active_support/core_ext/array/grouping.rb +2 -0
  30. data/lib/active_support/core_ext/array/inquiry.rb +2 -0
  31. data/lib/active_support/core_ext/array/wrap.rb +2 -0
  32. data/lib/active_support/core_ext/array.rb +3 -1
  33. data/lib/active_support/core_ext/benchmark.rb +4 -2
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +2 -0
  35. data/lib/active_support/core_ext/big_decimal.rb +2 -0
  36. data/lib/active_support/core_ext/class/attribute.rb +50 -47
  37. data/lib/active_support/core_ext/class/attribute_accessors.rb +2 -0
  38. data/lib/active_support/core_ext/class/subclasses.rb +18 -40
  39. data/lib/active_support/core_ext/class.rb +2 -0
  40. data/lib/active_support/core_ext/date/acts_like.rb +2 -0
  41. data/lib/active_support/core_ext/date/blank.rb +2 -0
  42. data/lib/active_support/core_ext/date/calculations.rb +8 -5
  43. data/lib/active_support/core_ext/date/conversions.rb +12 -10
  44. data/lib/active_support/core_ext/date/zones.rb +2 -0
  45. data/lib/active_support/core_ext/date.rb +2 -0
  46. data/lib/active_support/core_ext/date_and_time/calculations.rb +61 -37
  47. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -1
  48. data/lib/active_support/core_ext/date_and_time/zones.rb +2 -1
  49. data/lib/active_support/core_ext/date_time/acts_like.rb +2 -0
  50. data/lib/active_support/core_ext/date_time/blank.rb +2 -0
  51. data/lib/active_support/core_ext/date_time/calculations.rb +3 -1
  52. data/lib/active_support/core_ext/date_time/compatibility.rb +7 -5
  53. data/lib/active_support/core_ext/date_time/conversions.rb +2 -1
  54. data/lib/active_support/core_ext/date_time.rb +2 -0
  55. data/lib/active_support/core_ext/digest/uuid.rb +3 -1
  56. data/lib/active_support/core_ext/digest.rb +3 -0
  57. data/lib/active_support/core_ext/enumerable.rb +174 -71
  58. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  59. data/lib/active_support/core_ext/file.rb +2 -0
  60. data/lib/active_support/core_ext/hash/conversions.rb +7 -5
  61. data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
  62. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  63. data/lib/active_support/core_ext/hash/except.rb +4 -2
  64. data/lib/active_support/core_ext/hash/indifferent_access.rb +2 -0
  65. data/lib/active_support/core_ext/hash/keys.rb +3 -30
  66. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  67. data/lib/active_support/core_ext/hash/slice.rb +8 -29
  68. data/lib/active_support/core_ext/hash.rb +3 -2
  69. data/lib/active_support/core_ext/integer/inflections.rb +2 -0
  70. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  71. data/lib/active_support/core_ext/integer/time.rb +7 -14
  72. data/lib/active_support/core_ext/integer.rb +2 -0
  73. data/lib/active_support/core_ext/kernel/concern.rb +2 -0
  74. data/lib/active_support/core_ext/kernel/reporting.rb +2 -0
  75. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  76. data/lib/active_support/core_ext/kernel.rb +2 -1
  77. data/lib/active_support/core_ext/load_error.rb +3 -8
  78. data/lib/active_support/core_ext/marshal.rb +4 -0
  79. data/lib/active_support/core_ext/module/aliasing.rb +2 -0
  80. data/lib/active_support/core_ext/module/anonymous.rb +2 -0
  81. data/lib/active_support/core_ext/module/attr_internal.rb +4 -2
  82. data/lib/active_support/core_ext/module/attribute_accessors.rb +44 -56
  83. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +18 -18
  84. data/lib/active_support/core_ext/module/concerning.rb +15 -10
  85. data/lib/active_support/core_ext/module/delegation.rb +103 -58
  86. data/lib/active_support/core_ext/module/deprecation.rb +2 -0
  87. data/lib/active_support/core_ext/module/introspection.rb +18 -15
  88. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  89. data/lib/active_support/core_ext/module/remove_method.rb +5 -23
  90. data/lib/active_support/core_ext/module.rb +3 -1
  91. data/lib/active_support/core_ext/name_error.rb +36 -2
  92. data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
  93. data/lib/active_support/core_ext/numeric/conversions.rb +131 -129
  94. data/lib/active_support/core_ext/numeric/time.rb +7 -15
  95. data/lib/active_support/core_ext/numeric.rb +2 -1
  96. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  97. data/lib/active_support/core_ext/object/blank.rb +13 -3
  98. data/lib/active_support/core_ext/object/conversions.rb +2 -0
  99. data/lib/active_support/core_ext/object/deep_dup.rb +3 -1
  100. data/lib/active_support/core_ext/object/duplicable.rb +6 -101
  101. data/lib/active_support/core_ext/object/inclusion.rb +2 -0
  102. data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
  103. data/lib/active_support/core_ext/object/json.rb +22 -2
  104. data/lib/active_support/core_ext/object/to_param.rb +2 -0
  105. data/lib/active_support/core_ext/object/to_query.rb +7 -2
  106. data/lib/active_support/core_ext/object/try.rb +19 -7
  107. data/lib/active_support/core_ext/object/with_options.rb +4 -2
  108. data/lib/active_support/core_ext/object.rb +2 -0
  109. data/lib/active_support/core_ext/range/compare_range.rb +82 -0
  110. data/lib/active_support/core_ext/range/conversions.rb +35 -25
  111. data/lib/active_support/core_ext/range/each.rb +5 -2
  112. data/lib/active_support/core_ext/range/include_time_with_zone.rb +28 -0
  113. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  114. data/lib/active_support/core_ext/range.rb +4 -1
  115. data/lib/active_support/core_ext/regexp.rb +10 -5
  116. data/lib/active_support/core_ext/securerandom.rb +25 -3
  117. data/lib/active_support/core_ext/string/access.rb +7 -16
  118. data/lib/active_support/core_ext/string/behavior.rb +2 -0
  119. data/lib/active_support/core_ext/string/conversions.rb +3 -0
  120. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  121. data/lib/active_support/core_ext/string/filters.rb +44 -1
  122. data/lib/active_support/core_ext/string/indent.rb +2 -0
  123. data/lib/active_support/core_ext/string/inflections.rb +69 -16
  124. data/lib/active_support/core_ext/string/inquiry.rb +3 -0
  125. data/lib/active_support/core_ext/string/multibyte.rb +9 -4
  126. data/lib/active_support/core_ext/string/output_safety.rb +76 -20
  127. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
  128. data/lib/active_support/core_ext/string/strip.rb +5 -1
  129. data/lib/active_support/core_ext/string/zones.rb +2 -0
  130. data/lib/active_support/core_ext/string.rb +2 -0
  131. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  132. data/lib/active_support/core_ext/symbol.rb +3 -0
  133. data/lib/active_support/core_ext/time/acts_like.rb +2 -0
  134. data/lib/active_support/core_ext/time/calculations.rb +73 -18
  135. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  136. data/lib/active_support/core_ext/time/conversions.rb +4 -0
  137. data/lib/active_support/core_ext/time/zones.rb +6 -4
  138. data/lib/active_support/core_ext/time.rb +2 -0
  139. data/lib/active_support/core_ext/uri.rb +11 -6
  140. data/lib/active_support/core_ext.rb +3 -1
  141. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  142. data/lib/active_support/current_attributes.rb +208 -0
  143. data/lib/active_support/dependencies/autoload.rb +2 -0
  144. data/lib/active_support/dependencies/interlock.rb +2 -0
  145. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  146. data/lib/active_support/dependencies.rb +135 -60
  147. data/lib/active_support/deprecation/behaviors.rb +43 -11
  148. data/lib/active_support/deprecation/constant_accessor.rb +4 -2
  149. data/lib/active_support/deprecation/disallowed.rb +56 -0
  150. data/lib/active_support/deprecation/instance_delegator.rb +2 -1
  151. data/lib/active_support/deprecation/method_wrappers.rb +30 -15
  152. data/lib/active_support/deprecation/proxy_wrappers.rb +32 -6
  153. data/lib/active_support/deprecation/reporting.rb +54 -9
  154. data/lib/active_support/deprecation.rb +9 -2
  155. data/lib/active_support/descendants_tracker.rb +61 -9
  156. data/lib/active_support/digest.rb +20 -0
  157. data/lib/active_support/duration/iso8601_parser.rb +6 -6
  158. data/lib/active_support/duration/iso8601_serializer.rb +20 -14
  159. data/lib/active_support/duration.rb +179 -41
  160. data/lib/active_support/encrypted_configuration.rb +45 -0
  161. data/lib/active_support/encrypted_file.rb +117 -0
  162. data/lib/active_support/environment_inquirer.rb +20 -0
  163. data/lib/active_support/evented_file_update_checker.rb +84 -117
  164. data/lib/active_support/execution_wrapper.rb +3 -0
  165. data/lib/active_support/executor.rb +2 -0
  166. data/lib/active_support/file_update_checker.rb +2 -1
  167. data/lib/active_support/fork_tracker.rb +62 -0
  168. data/lib/active_support/gem_version.rb +3 -1
  169. data/lib/active_support/gzip.rb +2 -0
  170. data/lib/active_support/hash_with_indifferent_access.rb +134 -37
  171. data/lib/active_support/i18n.rb +4 -1
  172. data/lib/active_support/i18n_railtie.rb +20 -11
  173. data/lib/active_support/inflections.rb +2 -0
  174. data/lib/active_support/inflector/inflections.rb +19 -8
  175. data/lib/active_support/inflector/methods.rb +87 -77
  176. data/lib/active_support/inflector/transliterate.rb +56 -18
  177. data/lib/active_support/inflector.rb +2 -0
  178. data/lib/active_support/json/decoding.rb +27 -26
  179. data/lib/active_support/json/encoding.rb +13 -3
  180. data/lib/active_support/json.rb +2 -0
  181. data/lib/active_support/key_generator.rb +3 -33
  182. data/lib/active_support/lazy_load_hooks.rb +33 -10
  183. data/lib/active_support/locale/en.rb +33 -0
  184. data/lib/active_support/locale/en.yml +7 -3
  185. data/lib/active_support/log_subscriber/test_helper.rb +2 -0
  186. data/lib/active_support/log_subscriber.rb +46 -13
  187. data/lib/active_support/logger.rb +4 -17
  188. data/lib/active_support/logger_silence.rb +13 -20
  189. data/lib/active_support/logger_thread_safe_level.rb +54 -7
  190. data/lib/active_support/message_encryptor.rb +101 -33
  191. data/lib/active_support/message_verifier.rb +85 -14
  192. data/lib/active_support/messages/metadata.rb +80 -0
  193. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  194. data/lib/active_support/messages/rotator.rb +57 -0
  195. data/lib/active_support/multibyte/chars.rb +12 -68
  196. data/lib/active_support/multibyte/unicode.rb +17 -327
  197. data/lib/active_support/multibyte.rb +2 -0
  198. data/lib/active_support/notifications/fanout.rb +118 -16
  199. data/lib/active_support/notifications/instrumenter.rb +73 -9
  200. data/lib/active_support/notifications.rb +74 -8
  201. data/lib/active_support/number_helper/number_converter.rb +7 -6
  202. data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -9
  203. data/lib/active_support/number_helper/number_to_delimited_converter.rb +5 -2
  204. data/lib/active_support/number_helper/number_to_human_converter.rb +8 -7
  205. data/lib/active_support/number_helper/number_to_human_size_converter.rb +6 -3
  206. data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
  207. data/lib/active_support/number_helper/number_to_phone_converter.rb +5 -2
  208. data/lib/active_support/number_helper/number_to_rounded_converter.rb +16 -53
  209. data/lib/active_support/number_helper/rounding_helper.rb +50 -0
  210. data/lib/active_support/number_helper.rb +41 -12
  211. data/lib/active_support/option_merger.rb +24 -3
  212. data/lib/active_support/ordered_hash.rb +3 -1
  213. data/lib/active_support/ordered_options.rb +17 -5
  214. data/lib/active_support/parameter_filter.rb +133 -0
  215. data/lib/active_support/per_thread_registry.rb +3 -1
  216. data/lib/active_support/proxy_object.rb +2 -0
  217. data/lib/active_support/rails.rb +3 -10
  218. data/lib/active_support/railtie.rb +60 -9
  219. data/lib/active_support/reloader.rb +11 -10
  220. data/lib/active_support/rescuable.rb +7 -6
  221. data/lib/active_support/secure_compare_rotator.rb +51 -0
  222. data/lib/active_support/security_utils.rb +26 -15
  223. data/lib/active_support/string_inquirer.rb +6 -3
  224. data/lib/active_support/subscriber.rb +74 -24
  225. data/lib/active_support/tagged_logging.rb +44 -8
  226. data/lib/active_support/test_case.rb +94 -2
  227. data/lib/active_support/testing/assertions.rb +58 -20
  228. data/lib/active_support/testing/autorun.rb +2 -4
  229. data/lib/active_support/testing/constant_lookup.rb +2 -0
  230. data/lib/active_support/testing/declarative.rb +2 -0
  231. data/lib/active_support/testing/deprecation.rb +2 -1
  232. data/lib/active_support/testing/file_fixtures.rb +4 -0
  233. data/lib/active_support/testing/isolation.rb +8 -4
  234. data/lib/active_support/testing/method_call_assertions.rb +30 -1
  235. data/lib/active_support/testing/parallelization/server.rb +78 -0
  236. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  237. data/lib/active_support/testing/parallelization.rb +51 -0
  238. data/lib/active_support/testing/setup_and_teardown.rb +12 -7
  239. data/lib/active_support/testing/stream.rb +3 -2
  240. data/lib/active_support/testing/tagged_logging.rb +2 -0
  241. data/lib/active_support/testing/time_helpers.rb +78 -13
  242. data/lib/active_support/time.rb +2 -0
  243. data/lib/active_support/time_with_zone.rb +113 -41
  244. data/lib/active_support/values/time_zone.rb +55 -25
  245. data/lib/active_support/version.rb +2 -0
  246. data/lib/active_support/xml_mini/jdom.rb +5 -4
  247. data/lib/active_support/xml_mini/libxml.rb +4 -2
  248. data/lib/active_support/xml_mini/libxmlsax.rb +6 -4
  249. data/lib/active_support/xml_mini/nokogiri.rb +4 -2
  250. data/lib/active_support/xml_mini/nokogirisax.rb +5 -3
  251. data/lib/active_support/xml_mini/rexml.rb +12 -3
  252. data/lib/active_support/xml_mini.rb +5 -11
  253. data/lib/active_support.rb +18 -13
  254. metadata +81 -35
  255. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
  256. data/lib/active_support/core_ext/hash/compact.rb +0 -27
  257. data/lib/active_support/core_ext/hash/transform_values.rb +0 -30
  258. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  259. data/lib/active_support/core_ext/module/reachable.rb +0 -8
  260. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
  261. data/lib/active_support/core_ext/range/include_range.rb +0 -23
  262. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/inflector/methods"
2
4
  require "active_support/inflector/transliterate"
3
5
 
@@ -28,6 +30,8 @@ class String
28
30
  # 'apple'.pluralize(2) # => "apples"
29
31
  # 'ley'.pluralize(:es) # => "leyes"
30
32
  # 'ley'.pluralize(1, :es) # => "ley"
33
+ #
34
+ # See ActiveSupport::Inflector.pluralize.
31
35
  def pluralize(count = nil, locale = :en)
32
36
  locale = count if count.is_a?(Symbol)
33
37
  if count == 1
@@ -51,28 +55,34 @@ class String
51
55
  # 'the blue mailmen'.singularize # => "the blue mailman"
52
56
  # 'CamelOctopi'.singularize # => "CamelOctopus"
53
57
  # 'leyes'.singularize(:es) # => "ley"
58
+ #
59
+ # See ActiveSupport::Inflector.singularize.
54
60
  def singularize(locale = :en)
55
61
  ActiveSupport::Inflector.singularize(self, locale)
56
62
  end
57
63
 
58
64
  # +constantize+ tries to find a declared constant with the name specified
59
65
  # in the string. It raises a NameError when the name is not in CamelCase
60
- # or is not initialized. See ActiveSupport::Inflector.constantize
66
+ # or is not initialized.
61
67
  #
62
68
  # 'Module'.constantize # => Module
63
69
  # 'Class'.constantize # => Class
64
70
  # 'blargle'.constantize # => NameError: wrong constant name blargle
71
+ #
72
+ # See ActiveSupport::Inflector.constantize.
65
73
  def constantize
66
74
  ActiveSupport::Inflector.constantize(self)
67
75
  end
68
76
 
69
77
  # +safe_constantize+ tries to find a declared constant with the name specified
70
78
  # in the string. It returns +nil+ when the name is not in CamelCase
71
- # or is not initialized. See ActiveSupport::Inflector.safe_constantize
79
+ # or is not initialized.
72
80
  #
73
81
  # 'Module'.safe_constantize # => Module
74
82
  # 'Class'.safe_constantize # => Class
75
83
  # 'blargle'.safe_constantize # => nil
84
+ #
85
+ # See ActiveSupport::Inflector.safe_constantize.
76
86
  def safe_constantize
77
87
  ActiveSupport::Inflector.safe_constantize(self)
78
88
  end
@@ -86,12 +96,18 @@ class String
86
96
  # 'active_record'.camelize(:lower) # => "activeRecord"
87
97
  # 'active_record/errors'.camelize # => "ActiveRecord::Errors"
88
98
  # 'active_record/errors'.camelize(:lower) # => "activeRecord::Errors"
99
+ #
100
+ # +camelize+ is also aliased as +camelcase+.
101
+ #
102
+ # See ActiveSupport::Inflector.camelize.
89
103
  def camelize(first_letter = :upper)
90
104
  case first_letter
91
105
  when :upper
92
106
  ActiveSupport::Inflector.camelize(self, true)
93
107
  when :lower
94
108
  ActiveSupport::Inflector.camelize(self, false)
109
+ else
110
+ raise ArgumentError, "Invalid option, use either :upper or :lower."
95
111
  end
96
112
  end
97
113
  alias_method :camelcase, :camelize
@@ -100,12 +116,19 @@ class String
100
116
  # a nicer looking title. +titleize+ is meant for creating pretty output. It is not
101
117
  # used in the Rails internals.
102
118
  #
119
+ # The trailing '_id','Id'.. can be kept and capitalized by setting the
120
+ # optional parameter +keep_id_suffix+ to true.
121
+ # By default, this parameter is false.
122
+ #
123
+ # 'man from the boondocks'.titleize # => "Man From The Boondocks"
124
+ # 'x-men: the last stand'.titleize # => "X Men: The Last Stand"
125
+ # 'string_ending_with_id'.titleize(keep_id_suffix: true) # => "String Ending With Id"
126
+ #
103
127
  # +titleize+ is also aliased as +titlecase+.
104
128
  #
105
- # 'man from the boondocks'.titleize # => "Man From The Boondocks"
106
- # 'x-men: the last stand'.titleize # => "X Men: The Last Stand"
107
- def titleize
108
- ActiveSupport::Inflector.titleize(self)
129
+ # See ActiveSupport::Inflector.titleize.
130
+ def titleize(keep_id_suffix: false)
131
+ ActiveSupport::Inflector.titleize(self, keep_id_suffix: keep_id_suffix)
109
132
  end
110
133
  alias_method :titlecase, :titleize
111
134
 
@@ -115,6 +138,8 @@ class String
115
138
  #
116
139
  # 'ActiveModel'.underscore # => "active_model"
117
140
  # 'ActiveModel::Errors'.underscore # => "active_model/errors"
141
+ #
142
+ # See ActiveSupport::Inflector.underscore.
118
143
  def underscore
119
144
  ActiveSupport::Inflector.underscore(self)
120
145
  end
@@ -122,6 +147,8 @@ class String
122
147
  # Replaces underscores with dashes in the string.
123
148
  #
124
149
  # 'puni_puni'.dasherize # => "puni-puni"
150
+ #
151
+ # See ActiveSupport::Inflector.dasherize.
125
152
  def dasherize
126
153
  ActiveSupport::Inflector.dasherize(self)
127
154
  end
@@ -133,6 +160,8 @@ class String
133
160
  # '::Inflections'.demodulize # => "Inflections"
134
161
  # ''.demodulize # => ''
135
162
  #
163
+ # See ActiveSupport::Inflector.demodulize.
164
+ #
136
165
  # See also +deconstantize+.
137
166
  def demodulize
138
167
  ActiveSupport::Inflector.demodulize(self)
@@ -146,6 +175,8 @@ class String
146
175
  # '::String'.deconstantize # => ""
147
176
  # ''.deconstantize # => ""
148
177
  #
178
+ # See ActiveSupport::Inflector.deconstantize.
179
+ #
149
180
  # See also +demodulize+.
150
181
  def deconstantize
151
182
  ActiveSupport::Inflector.deconstantize(self)
@@ -153,6 +184,11 @@ class String
153
184
 
154
185
  # Replaces special characters in a string so that it may be used as part of a 'pretty' URL.
155
186
  #
187
+ # If the optional parameter +locale+ is specified,
188
+ # the word will be parameterized as a word of that language.
189
+ # By default, this parameter is set to <tt>nil</tt> and it will use
190
+ # the configured <tt>I18n.locale</tt>.
191
+ #
156
192
  # class Person
157
193
  # def to_param
158
194
  # "#{id}-#{name.parameterize}"
@@ -165,7 +201,7 @@ class String
165
201
  # <%= link_to(@person.name, person_path) %>
166
202
  # # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a>
167
203
  #
168
- # To preserve the case of the characters in a string, use the `preserve_case` argument.
204
+ # To preserve the case of the characters in a string, use the +preserve_case+ argument.
169
205
  #
170
206
  # class Person
171
207
  # def to_param
@@ -178,8 +214,10 @@ class String
178
214
  #
179
215
  # <%= link_to(@person.name, person_path) %>
180
216
  # # => <a href="/person/1-Donald-E-Knuth">Donald E. Knuth</a>
181
- def parameterize(separator: "-", preserve_case: false)
182
- ActiveSupport::Inflector.parameterize(self, separator: separator, preserve_case: preserve_case)
217
+ #
218
+ # See ActiveSupport::Inflector.parameterize.
219
+ def parameterize(separator: "-", preserve_case: false, locale: nil)
220
+ ActiveSupport::Inflector.parameterize(self, separator: separator, preserve_case: preserve_case, locale: locale)
183
221
  end
184
222
 
185
223
  # Creates the name of a table like Rails does for models to table names. This method
@@ -188,6 +226,8 @@ class String
188
226
  # 'RawScaledScorer'.tableize # => "raw_scaled_scorers"
189
227
  # 'ham_and_egg'.tableize # => "ham_and_eggs"
190
228
  # 'fancyCategory'.tableize # => "fancy_categories"
229
+ #
230
+ # See ActiveSupport::Inflector.tableize.
191
231
  def tableize
192
232
  ActiveSupport::Inflector.tableize(self)
193
233
  end
@@ -198,11 +238,13 @@ class String
198
238
  #
199
239
  # 'ham_and_eggs'.classify # => "HamAndEgg"
200
240
  # 'posts'.classify # => "Post"
241
+ #
242
+ # See ActiveSupport::Inflector.classify.
201
243
  def classify
202
244
  ActiveSupport::Inflector.classify(self)
203
245
  end
204
246
 
205
- # Capitalizes the first word, turns underscores into spaces, and strips a
247
+ # Capitalizes the first word, turns underscores into spaces, and (by default)strips a
206
248
  # trailing '_id' if present.
207
249
  # Like +titleize+, this is meant for creating pretty output.
208
250
  #
@@ -210,12 +252,19 @@ class String
210
252
  # optional parameter +capitalize+ to false.
211
253
  # By default, this parameter is true.
212
254
  #
213
- # 'employee_salary'.humanize # => "Employee salary"
214
- # 'author_id'.humanize # => "Author"
215
- # 'author_id'.humanize(capitalize: false) # => "author"
216
- # '_id'.humanize # => "Id"
217
- def humanize(options = {})
218
- ActiveSupport::Inflector.humanize(self, options)
255
+ # The trailing '_id' can be kept and capitalized by setting the
256
+ # optional parameter +keep_id_suffix+ to true.
257
+ # By default, this parameter is false.
258
+ #
259
+ # 'employee_salary'.humanize # => "Employee salary"
260
+ # 'author_id'.humanize # => "Author"
261
+ # 'author_id'.humanize(capitalize: false) # => "author"
262
+ # '_id'.humanize # => "Id"
263
+ # 'author_id'.humanize(keep_id_suffix: true) # => "Author Id"
264
+ #
265
+ # See ActiveSupport::Inflector.humanize.
266
+ def humanize(capitalize: true, keep_id_suffix: false)
267
+ ActiveSupport::Inflector.humanize(self, capitalize: capitalize, keep_id_suffix: keep_id_suffix)
219
268
  end
220
269
 
221
270
  # Converts just the first character to uppercase.
@@ -223,6 +272,8 @@ class String
223
272
  # 'what a Lovely Day'.upcase_first # => "What a Lovely Day"
224
273
  # 'w'.upcase_first # => "W"
225
274
  # ''.upcase_first # => ""
275
+ #
276
+ # See ActiveSupport::Inflector.upcase_first.
226
277
  def upcase_first
227
278
  ActiveSupport::Inflector.upcase_first(self)
228
279
  end
@@ -234,6 +285,8 @@ class String
234
285
  # 'Message'.foreign_key # => "message_id"
235
286
  # 'Message'.foreign_key(false) # => "messageid"
236
287
  # 'Admin::Post'.foreign_key # => "post_id"
288
+ #
289
+ # See ActiveSupport::Inflector.foreign_key.
237
290
  def foreign_key(separate_class_name_and_id_with_underscore = true)
238
291
  ActiveSupport::Inflector.foreign_key(self, separate_class_name_and_id_with_underscore)
239
292
  end
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/string_inquirer"
4
+ require "active_support/environment_inquirer"
2
5
 
3
6
  class String
4
7
  # Wraps the current string in the <tt>ActiveSupport::StringInquirer</tt> class,
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/multibyte"
2
4
 
3
5
  class String
@@ -9,11 +11,14 @@ class String
9
11
  # encapsulates the original string. A Unicode safe version of all the String methods are defined on this proxy
10
12
  # class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsulated string.
11
13
  #
12
- # >> "lj".upcase
13
- # => "lj"
14
14
  # >> "lj".mb_chars.upcase.to_s
15
15
  # => "LJ"
16
16
  #
17
+ # NOTE: Ruby 2.4 and later support native Unicode case mappings:
18
+ #
19
+ # >> "lj".upcase
20
+ # => "LJ"
21
+ #
17
22
  # == Method chaining
18
23
  #
19
24
  # All the methods on the Chars proxy which normally return a string will return a Chars object. This allows
@@ -42,9 +47,9 @@ class String
42
47
  # iso_str.is_utf8? # => false
43
48
  def is_utf8?
44
49
  case encoding
45
- when Encoding::UTF_8
50
+ when Encoding::UTF_8, Encoding::US_ASCII
46
51
  valid_encoding?
47
- when Encoding::ASCII_8BIT, Encoding::US_ASCII
52
+ when Encoding::ASCII_8BIT
48
53
  dup.force_encoding(Encoding::UTF_8).valid_encoding?
49
54
  else
50
55
  false
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "erb"
2
- require "active_support/core_ext/kernel/singleton_class"
4
+ require "active_support/core_ext/module/redefine_method"
3
5
  require "active_support/multibyte/unicode"
4
6
 
5
7
  class ERB
@@ -12,22 +14,18 @@ class ERB
12
14
  # A utility method for escaping HTML tag characters.
13
15
  # This method is also aliased as <tt>h</tt>.
14
16
  #
15
- # In your ERB templates, use this method to escape any unsafe content. For example:
16
- # <%= h @person.name %>
17
- #
18
17
  # puts html_escape('is a > 0 & a < 10?')
19
18
  # # => is a &gt; 0 &amp; a &lt; 10?
20
19
  def html_escape(s)
21
20
  unwrapped_html_escape(s).html_safe
22
21
  end
23
22
 
24
- # Aliasing twice issues a warning "discarding old...". Remove first to avoid it.
25
- remove_method(:h)
23
+ silence_redefinition_of_method :h
26
24
  alias h html_escape
27
25
 
28
26
  module_function :h
29
27
 
30
- singleton_class.send(:remove_method, :html_escape)
28
+ singleton_class.silence_redefinition_of_method :html_escape
31
29
  module_function :html_escape
32
30
 
33
31
  # HTML escapes strings but doesn't wrap them with an ActiveSupport::SafeBuffer.
@@ -86,7 +84,7 @@ class ERB
86
84
  # use inside HTML attributes.
87
85
  #
88
86
  # If your JSON is being used downstream for insertion into the DOM, be aware of
89
- # whether or not it is being inserted via +html()+. Most jQuery plugins do this.
87
+ # whether or not it is being inserted via <tt>html()</tt>. Most jQuery plugins do this.
90
88
  # If that is the case, be sure to +html_escape+ or +sanitize+ any user-generated
91
89
  # content returned by your JSON.
92
90
  #
@@ -135,10 +133,13 @@ end
135
133
  module ActiveSupport #:nodoc:
136
134
  class SafeBuffer < String
137
135
  UNSAFE_STRING_METHODS = %w(
138
- capitalize chomp chop delete downcase gsub lstrip next reverse rstrip
139
- slice squeeze strip sub succ swapcase tr tr_s upcase
136
+ capitalize chomp chop delete delete_prefix delete_suffix
137
+ downcase lstrip next reverse rstrip scrub slice squeeze strip
138
+ succ swapcase tr tr_s unicode_normalize upcase
140
139
  )
141
140
 
141
+ UNSAFE_STRING_METHODS_WITH_BACKREF = %w(gsub sub)
142
+
142
143
  alias_method :original_concat, :concat
143
144
  private :original_concat
144
145
 
@@ -150,15 +151,13 @@ module ActiveSupport #:nodoc:
150
151
  end
151
152
 
152
153
  def [](*args)
153
- if args.size < 2
154
- super
155
- elsif html_safe?
156
- new_safe_buffer = super
154
+ if html_safe?
155
+ new_string = super
157
156
 
158
- if new_safe_buffer
159
- new_safe_buffer.instance_variable_set :@html_safe, true
160
- end
157
+ return unless new_string
161
158
 
159
+ new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
160
+ new_safe_buffer.instance_variable_set :@html_safe, true
162
161
  new_safe_buffer
163
162
  else
164
163
  to_str[*args]
@@ -189,18 +188,41 @@ module ActiveSupport #:nodoc:
189
188
  end
190
189
  alias << concat
191
190
 
191
+ def insert(index, value)
192
+ super(index, html_escape_interpolated_argument(value))
193
+ end
194
+
192
195
  def prepend(value)
193
196
  super(html_escape_interpolated_argument(value))
194
197
  end
195
198
 
199
+ def replace(value)
200
+ super(html_escape_interpolated_argument(value))
201
+ end
202
+
203
+ def []=(*args)
204
+ if args.length == 3
205
+ super(args[0], args[1], html_escape_interpolated_argument(args[2]))
206
+ else
207
+ super(args[0], html_escape_interpolated_argument(args[1]))
208
+ end
209
+ end
210
+
196
211
  def +(other)
197
212
  dup.concat(other)
198
213
  end
199
214
 
215
+ def *(*)
216
+ new_string = super
217
+ new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
218
+ new_safe_buffer.instance_variable_set(:@html_safe, @html_safe)
219
+ new_safe_buffer
220
+ end
221
+
200
222
  def %(args)
201
223
  case args
202
224
  when Hash
203
- escaped_args = Hash[args.map { |k, arg| [k, html_escape_interpolated_argument(arg)] }]
225
+ escaped_args = args.transform_values { |arg| html_escape_interpolated_argument(arg) }
204
226
  else
205
227
  escaped_args = Array(args).map { |arg| html_escape_interpolated_argument(arg) }
206
228
  end
@@ -239,11 +261,45 @@ module ActiveSupport #:nodoc:
239
261
  end
240
262
  end
241
263
 
242
- private
264
+ UNSAFE_STRING_METHODS_WITH_BACKREF.each do |unsafe_method|
265
+ if unsafe_method.respond_to?(unsafe_method)
266
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
267
+ def #{unsafe_method}(*args, &block) # def gsub(*args, &block)
268
+ if block # if block
269
+ to_str.#{unsafe_method}(*args) { |*params| # to_str.gsub(*args) { |*params|
270
+ set_block_back_references(block, $~) # set_block_back_references(block, $~)
271
+ block.call(*params) # block.call(*params)
272
+ } # }
273
+ else # else
274
+ to_str.#{unsafe_method}(*args) # to_str.gsub(*args)
275
+ end # end
276
+ end # end
277
+
278
+ def #{unsafe_method}!(*args, &block) # def gsub!(*args, &block)
279
+ @html_safe = false # @html_safe = false
280
+ if block # if block
281
+ super(*args) { |*params| # super(*args) { |*params|
282
+ set_block_back_references(block, $~) # set_block_back_references(block, $~)
283
+ block.call(*params) # block.call(*params)
284
+ } # }
285
+ else # else
286
+ super # super
287
+ end # end
288
+ end # end
289
+ EOT
290
+ end
291
+ end
243
292
 
293
+ private
244
294
  def html_escape_interpolated_argument(arg)
245
295
  (!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
246
296
  end
297
+
298
+ def set_block_back_references(block, match_data)
299
+ block.binding.eval("proc { |m| $~ = m }").call(match_data)
300
+ rescue ArgumentError
301
+ # Can't create binding from C level Proc
302
+ end
247
303
  end
248
304
  end
249
305
 
@@ -251,7 +307,7 @@ class String
251
307
  # Marks a string as trusted safe. It will be inserted into HTML with no
252
308
  # additional escaping performed. It is your responsibility to ensure that the
253
309
  # string contains no malicious content. This method is equivalent to the
254
- # `raw` helper in views. It is recommended that you use `sanitize` instead of
310
+ # +raw+ helper in views. It is recommended that you use +sanitize+ instead of
255
311
  # this method. It should never be called on user input.
256
312
  def html_safe
257
313
  ActiveSupport::SafeBuffer.new(self)
@@ -1,4 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class String
2
- alias_method :starts_with?, :start_with?
3
- alias_method :ends_with?, :end_with?
4
+ alias :starts_with? :start_with?
5
+ alias :ends_with? :end_with?
4
6
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class String
2
4
  # Strips indentation in heredocs.
3
5
  #
@@ -18,6 +20,8 @@ class String
18
20
  # Technically, it looks for the least indented non-empty line
19
21
  # in the whole string, and removes that amount of leading whitespace.
20
22
  def strip_heredoc
21
- gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, "".freeze)
23
+ gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, "").tap do |stripped|
24
+ stripped.freeze if frozen?
25
+ end
22
26
  end
23
27
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/string/conversions"
2
4
  require "active_support/core_ext/time/zones"
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/string/conversions"
2
4
  require "active_support/core_ext/string/filters"
3
5
  require "active_support/core_ext/string/multibyte"
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Symbol
4
+ def start_with?(*prefixes)
5
+ to_s.start_with?(*prefixes)
6
+ end unless method_defined?(:start_with?)
7
+
8
+ def end_with?(*suffixes)
9
+ to_s.end_with?(*suffixes)
10
+ end unless method_defined?(:end_with?)
11
+
12
+ alias :starts_with? :start_with?
13
+ alias :ends_with? :end_with?
14
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/symbol/starts_ends_with"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/object/acts_like"
2
4
 
3
5
  class Time
@@ -1,9 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/duration"
2
4
  require "active_support/core_ext/time/conversions"
3
5
  require "active_support/time_with_zone"
4
6
  require "active_support/core_ext/time/zones"
5
7
  require "active_support/core_ext/date_and_time/calculations"
6
8
  require "active_support/core_ext/date/calculations"
9
+ require "active_support/core_ext/module/remove_method"
7
10
 
8
11
  class Time
9
12
  include DateAndTime::Calculations
@@ -45,7 +48,9 @@ class Time
45
48
  # Time.at can be called with a time or numerical value
46
49
  time_or_number = args.first
47
50
 
48
- if time_or_number.is_a?(ActiveSupport::TimeWithZone) || time_or_number.is_a?(DateTime)
51
+ if time_or_number.is_a?(ActiveSupport::TimeWithZone)
52
+ at_without_coercion(time_or_number.to_r).getlocal
53
+ elsif time_or_number.is_a?(DateTime)
49
54
  at_without_coercion(time_or_number.to_f).getlocal
50
55
  else
51
56
  at_without_coercion(time_or_number)
@@ -103,25 +108,41 @@ class Time
103
108
  subsec
104
109
  end
105
110
 
111
+ unless Time.method_defined?(:floor)
112
+ def floor(precision = 0)
113
+ change(nsec: 0) + subsec.floor(precision)
114
+ end
115
+ end
116
+
117
+ # Restricted Ruby version due to a bug in `Time#ceil`
118
+ # See https://bugs.ruby-lang.org/issues/17025 for more details
119
+ if RUBY_VERSION <= "2.8"
120
+ remove_possible_method :ceil
121
+ def ceil(precision = 0)
122
+ change(nsec: 0) + subsec.ceil(precision)
123
+ end
124
+ end
125
+
106
126
  # Returns a new Time where one or more of the elements have been changed according
107
127
  # to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>,
108
128
  # <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly, so if only
109
129
  # the hour is passed, then minute, sec, usec and nsec is set to 0. If the hour
110
- # and minute is passed, then sec, usec and nsec is set to 0. The +options+
111
- # parameter takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>,
112
- # <tt>:day</tt>, <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>
113
- # <tt>:nsec</tt>. Pass either <tt>:usec</tt> or <tt>:nsec</tt>, not both.
130
+ # and minute is passed, then sec, usec and nsec is set to 0. The +options+ parameter
131
+ # takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>,
132
+ # <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>,
133
+ # <tt>:offset</tt>. Pass either <tt>:usec</tt> or <tt>:nsec</tt>, not both.
114
134
  #
115
135
  # Time.new(2012, 8, 29, 22, 35, 0).change(day: 1) # => Time.new(2012, 8, 1, 22, 35, 0)
116
136
  # Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, day: 1) # => Time.new(1981, 8, 1, 22, 35, 0)
117
137
  # Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, hour: 0) # => Time.new(1981, 8, 29, 0, 0, 0)
118
138
  def change(options)
119
- new_year = options.fetch(:year, year)
120
- new_month = options.fetch(:month, month)
121
- new_day = options.fetch(:day, day)
122
- new_hour = options.fetch(:hour, hour)
123
- new_min = options.fetch(:min, options[:hour] ? 0 : min)
124
- new_sec = options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec)
139
+ new_year = options.fetch(:year, year)
140
+ new_month = options.fetch(:month, month)
141
+ new_day = options.fetch(:day, day)
142
+ new_hour = options.fetch(:hour, hour)
143
+ new_min = options.fetch(:min, options[:hour] ? 0 : min)
144
+ new_sec = options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec)
145
+ new_offset = options.fetch(:offset, nil)
125
146
 
126
147
  if new_nsec = options[:nsec]
127
148
  raise ArgumentError, "Can't change both :nsec and :usec at the same time: #{options.inspect}" if options[:usec]
@@ -130,13 +151,18 @@ class Time
130
151
  new_usec = options.fetch(:usec, (options[:hour] || options[:min] || options[:sec]) ? 0 : Rational(nsec, 1000))
131
152
  end
132
153
 
133
- if utc?
134
- ::Time.utc(new_year, new_month, new_day, new_hour, new_min, new_sec, new_usec)
154
+ raise ArgumentError, "argument out of range" if new_usec >= 1000000
155
+
156
+ new_sec += Rational(new_usec, 1000000)
157
+
158
+ if new_offset
159
+ ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, new_offset)
160
+ elsif utc?
161
+ ::Time.utc(new_year, new_month, new_day, new_hour, new_min, new_sec)
135
162
  elsif zone
136
- ::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec, new_usec)
163
+ ::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec)
137
164
  else
138
- raise ArgumentError, "argument out of range" if new_usec >= 1000000
139
- ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec + (new_usec.to_r / 1000000), utc_offset)
165
+ ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, utc_offset)
140
166
  end
141
167
  end
142
168
 
@@ -162,8 +188,7 @@ class Time
162
188
  options[:hours] = options.fetch(:hours, 0) + 24 * partial_days
163
189
  end
164
190
 
165
- d = to_date.advance(options)
166
- d = d.gregorian if d.julian?
191
+ d = to_date.gregorian.advance(options)
167
192
  time_advanced_by_date = change(year: d.year, month: d.month, day: d.day)
168
193
  seconds_to_advance = \
169
194
  options.fetch(:seconds, 0) +
@@ -304,4 +329,34 @@ class Time
304
329
  end
305
330
  alias_method :eql_without_coercion, :eql?
306
331
  alias_method :eql?, :eql_with_coercion
332
+
333
+ # Returns a new time the specified number of days ago.
334
+ def prev_day(days = 1)
335
+ advance(days: -days)
336
+ end
337
+
338
+ # Returns a new time the specified number of days in the future.
339
+ def next_day(days = 1)
340
+ advance(days: days)
341
+ end
342
+
343
+ # Returns a new time the specified number of months ago.
344
+ def prev_month(months = 1)
345
+ advance(months: -months)
346
+ end
347
+
348
+ # Returns a new time the specified number of months in the future.
349
+ def next_month(months = 1)
350
+ advance(months: months)
351
+ end
352
+
353
+ # Returns a new time the specified number of years ago.
354
+ def prev_year(years = 1)
355
+ advance(years: -years)
356
+ end
357
+
358
+ # Returns a new time the specified number of years in the future.
359
+ def next_year(years = 1)
360
+ advance(years: years)
361
+ end
307
362
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/date_and_time/compatibility"
2
- require "active_support/core_ext/module/remove_method"
4
+ require "active_support/core_ext/module/redefine_method"
3
5
 
4
6
  class Time
5
7
  include DateAndTime::Compatibility
6
8
 
7
- remove_possible_method :to_time
9
+ silence_redefinition_of_method :to_time
8
10
 
9
11
  # Either return +self+ or the time in the local system timezone depending
10
12
  # on the setting of +ActiveSupport.to_time_preserves_timezone+.