activesupport 5.0.0 → 6.1.0

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 (268) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +343 -590
  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 +5 -3
  7. data/lib/active_support/array_inquirer.rb +11 -5
  8. data/lib/active_support/backtrace_cleaner.rb +33 -5
  9. data/lib/active_support/benchmarkable.rb +5 -3
  10. data/lib/active_support/builder.rb +3 -1
  11. data/lib/active_support/cache/file_store.rb +45 -53
  12. data/lib/active_support/cache/mem_cache_store.rb +81 -79
  13. data/lib/active_support/cache/memory_store.rb +69 -41
  14. data/lib/active_support/cache/null_store.rb +11 -4
  15. data/lib/active_support/cache/redis_cache_store.rb +493 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +74 -37
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
  18. data/lib/active_support/cache.rb +332 -161
  19. data/lib/active_support/callbacks.rb +657 -586
  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 +59 -19
  23. data/lib/active_support/configurable.rb +15 -17
  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 +20 -18
  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 +3 -1
  30. data/lib/active_support/core_ext/array/inquiry.rb +3 -1
  31. data/lib/active_support/core_ext/array/wrap.rb +2 -0
  32. data/lib/active_support/core_ext/array.rb +9 -7
  33. data/lib/active_support/core_ext/benchmark.rb +5 -3
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +6 -6
  35. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  36. data/lib/active_support/core_ext/class/attribute.rb +52 -49
  37. data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
  38. data/lib/active_support/core_ext/class/subclasses.rb +18 -26
  39. data/lib/active_support/core_ext/class.rb +4 -2
  40. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  41. data/lib/active_support/core_ext/date/blank.rb +3 -1
  42. data/lib/active_support/core_ext/date/calculations.rb +16 -13
  43. data/lib/active_support/core_ext/date/conversions.rb +23 -21
  44. data/lib/active_support/core_ext/date/zones.rb +4 -2
  45. data/lib/active_support/core_ext/date.rb +7 -5
  46. data/lib/active_support/core_ext/date_and_time/calculations.rb +82 -53
  47. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -5
  48. data/lib/active_support/core_ext/date_and_time/zones.rb +9 -9
  49. data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
  50. data/lib/active_support/core_ext/date_time/blank.rb +3 -1
  51. data/lib/active_support/core_ext/date_time/calculations.rb +23 -11
  52. data/lib/active_support/core_ext/date_time/compatibility.rb +15 -2
  53. data/lib/active_support/core_ext/date_time/conversions.rb +14 -13
  54. data/lib/active_support/core_ext/date_time.rb +7 -5
  55. data/lib/active_support/core_ext/digest/uuid.rb +7 -5
  56. data/lib/active_support/core_ext/digest.rb +3 -0
  57. data/lib/active_support/core_ext/enumerable.rb +165 -29
  58. data/lib/active_support/core_ext/file/atomic.rb +7 -5
  59. data/lib/active_support/core_ext/file.rb +3 -1
  60. data/lib/active_support/core_ext/hash/conversions.rb +40 -39
  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 +3 -2
  65. data/lib/active_support/core_ext/hash/keys.rb +9 -36
  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 +10 -9
  69. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  70. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  71. data/lib/active_support/core_ext/integer/time.rb +11 -18
  72. data/lib/active_support/core_ext/integer.rb +5 -3
  73. data/lib/active_support/core_ext/kernel/concern.rb +3 -1
  74. data/lib/active_support/core_ext/kernel/reporting.rb +3 -1
  75. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  76. data/lib/active_support/core_ext/kernel.rb +5 -4
  77. data/lib/active_support/core_ext/load_error.rb +2 -23
  78. data/lib/active_support/core_ext/marshal.rb +6 -2
  79. data/lib/active_support/core_ext/module/aliasing.rb +5 -48
  80. data/lib/active_support/core_ext/module/anonymous.rb +2 -0
  81. data/lib/active_support/core_ext/module/attr_internal.rb +7 -5
  82. data/lib/active_support/core_ext/module/attribute_accessors.rb +53 -59
  83. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +31 -24
  84. data/lib/active_support/core_ext/module/concerning.rb +16 -11
  85. data/lib/active_support/core_ext/module/delegation.rb +159 -44
  86. data/lib/active_support/core_ext/module/deprecation.rb +2 -0
  87. data/lib/active_support/core_ext/module/introspection.rb +23 -26
  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 +13 -12
  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 +129 -134
  94. data/lib/active_support/core_ext/numeric/time.rb +18 -26
  95. data/lib/active_support/core_ext/numeric.rb +5 -4
  96. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  97. data/lib/active_support/core_ext/object/blank.rb +14 -2
  98. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  99. data/lib/active_support/core_ext/object/deep_dup.rb +4 -2
  100. data/lib/active_support/core_ext/object/duplicable.rb +13 -62
  101. data/lib/active_support/core_ext/object/inclusion.rb +3 -1
  102. data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
  103. data/lib/active_support/core_ext/object/json.rb +42 -15
  104. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  105. data/lib/active_support/core_ext/object/to_query.rb +10 -5
  106. data/lib/active_support/core_ext/object/try.rb +20 -8
  107. data/lib/active_support/core_ext/object/with_options.rb +15 -2
  108. data/lib/active_support/core_ext/object.rb +14 -12
  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 +7 -4
  115. data/lib/active_support/core_ext/regexp.rb +10 -1
  116. data/lib/active_support/core_ext/securerandom.rb +28 -6
  117. data/lib/active_support/core_ext/string/access.rb +9 -18
  118. data/lib/active_support/core_ext/string/behavior.rb +2 -0
  119. data/lib/active_support/core_ext/string/conversions.rb +5 -2
  120. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  121. data/lib/active_support/core_ext/string/filters.rb +47 -4
  122. data/lib/active_support/core_ext/string/indent.rb +6 -4
  123. data/lib/active_support/core_ext/string/inflections.rb +78 -29
  124. data/lib/active_support/core_ext/string/inquiry.rb +4 -1
  125. data/lib/active_support/core_ext/string/multibyte.rb +10 -5
  126. data/lib/active_support/core_ext/string/output_safety.rb +86 -31
  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 +4 -2
  130. data/lib/active_support/core_ext/string.rb +15 -13
  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 +3 -1
  134. data/lib/active_support/core_ext/time/calculations.rb +117 -45
  135. data/lib/active_support/core_ext/time/compatibility.rb +13 -2
  136. data/lib/active_support/core_ext/time/conversions.rb +18 -12
  137. data/lib/active_support/core_ext/time/zones.rb +9 -7
  138. data/lib/active_support/core_ext/time.rb +7 -5
  139. data/lib/active_support/core_ext/uri.rb +12 -7
  140. data/lib/active_support/core_ext.rb +3 -2
  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 +7 -1
  145. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  146. data/lib/active_support/dependencies.rb +172 -98
  147. data/lib/active_support/deprecation/behaviors.rb +45 -13
  148. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  149. data/lib/active_support/deprecation/disallowed.rb +56 -0
  150. data/lib/active_support/deprecation/instance_delegator.rb +16 -2
  151. data/lib/active_support/deprecation/method_wrappers.rb +32 -17
  152. data/lib/active_support/deprecation/proxy_wrappers.rb +35 -7
  153. data/lib/active_support/deprecation/reporting.rb +61 -16
  154. data/lib/active_support/deprecation.rb +17 -9
  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 +67 -66
  158. data/lib/active_support/duration/iso8601_serializer.rb +25 -17
  159. data/lib/active_support/duration.rb +349 -46
  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 +88 -112
  164. data/lib/active_support/execution_wrapper.rb +25 -13
  165. data/lib/active_support/executor.rb +3 -1
  166. data/lib/active_support/file_update_checker.rb +56 -51
  167. data/lib/active_support/fork_tracker.rb +62 -0
  168. data/lib/active_support/gem_version.rb +4 -2
  169. data/lib/active_support/gzip.rb +7 -5
  170. data/lib/active_support/hash_with_indifferent_access.rb +153 -49
  171. data/lib/active_support/i18n.rb +9 -6
  172. data/lib/active_support/i18n_railtie.rb +30 -20
  173. data/lib/active_support/inflections.rb +13 -11
  174. data/lib/active_support/inflector/inflections.rb +28 -15
  175. data/lib/active_support/inflector/methods.rb +120 -109
  176. data/lib/active_support/inflector/transliterate.rb +60 -25
  177. data/lib/active_support/inflector.rb +7 -5
  178. data/lib/active_support/json/decoding.rb +30 -29
  179. data/lib/active_support/json/encoding.rb +22 -11
  180. data/lib/active_support/json.rb +4 -2
  181. data/lib/active_support/key_generator.rb +6 -36
  182. data/lib/active_support/lazy_load_hooks.rb +53 -20
  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 +11 -9
  186. data/lib/active_support/log_subscriber.rb +51 -18
  187. data/lib/active_support/logger.rb +9 -22
  188. data/lib/active_support/logger_silence.rb +14 -21
  189. data/lib/active_support/logger_thread_safe_level.rb +55 -8
  190. data/lib/active_support/message_encryptor.rb +170 -53
  191. data/lib/active_support/message_verifier.rb +91 -20
  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 +24 -78
  196. data/lib/active_support/multibyte/unicode.rb +21 -352
  197. data/lib/active_support/multibyte.rb +4 -2
  198. data/lib/active_support/notifications/fanout.rb +121 -19
  199. data/lib/active_support/notifications/instrumenter.rb +78 -14
  200. data/lib/active_support/notifications.rb +80 -12
  201. data/lib/active_support/number_helper/number_converter.rb +17 -16
  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 -3
  204. data/lib/active_support/number_helper/number_to_human_converter.rb +13 -12
  205. data/lib/active_support/number_helper/number_to_human_size_converter.rb +11 -13
  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 -4
  208. data/lib/active_support/number_helper/number_to_rounded_converter.rb +18 -55
  209. data/lib/active_support/number_helper/rounding_helper.rb +50 -0
  210. data/lib/active_support/number_helper.rb +45 -16
  211. data/lib/active_support/option_merger.rb +25 -4
  212. data/lib/active_support/ordered_hash.rb +6 -4
  213. data/lib/active_support/ordered_options.rb +23 -9
  214. data/lib/active_support/parameter_filter.rb +133 -0
  215. data/lib/active_support/per_thread_registry.rb +7 -5
  216. data/lib/active_support/proxy_object.rb +2 -0
  217. data/lib/active_support/rails.rb +8 -9
  218. data/lib/active_support/railtie.rb +62 -11
  219. data/lib/active_support/reloader.rb +12 -11
  220. data/lib/active_support/rescuable.rb +20 -11
  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 +12 -3
  224. data/lib/active_support/subscriber.rb +77 -23
  225. data/lib/active_support/tagged_logging.rb +52 -17
  226. data/lib/active_support/test_case.rb +106 -29
  227. data/lib/active_support/testing/assertions.rb +144 -8
  228. data/lib/active_support/testing/autorun.rb +5 -10
  229. data/lib/active_support/testing/constant_lookup.rb +2 -1
  230. data/lib/active_support/testing/declarative.rb +3 -1
  231. data/lib/active_support/testing/deprecation.rb +4 -2
  232. data/lib/active_support/testing/file_fixtures.rb +4 -0
  233. data/lib/active_support/testing/isolation.rb +19 -24
  234. data/lib/active_support/testing/method_call_assertions.rb +31 -2
  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 +13 -8
  239. data/lib/active_support/testing/stream.rb +30 -29
  240. data/lib/active_support/testing/tagged_logging.rb +3 -1
  241. data/lib/active_support/testing/time_helpers.rb +125 -24
  242. data/lib/active_support/time.rb +14 -12
  243. data/lib/active_support/time_with_zone.rb +142 -55
  244. data/lib/active_support/values/time_zone.rb +160 -53
  245. data/lib/active_support/version.rb +3 -1
  246. data/lib/active_support/xml_mini/jdom.rb +115 -114
  247. data/lib/active_support/xml_mini/libxml.rb +15 -14
  248. data/lib/active_support/xml_mini/libxmlsax.rb +16 -18
  249. data/lib/active_support/xml_mini/nokogiri.rb +13 -13
  250. data/lib/active_support/xml_mini/nokogirisax.rb +15 -16
  251. data/lib/active_support/xml_mini/rexml.rb +18 -9
  252. data/lib/active_support/xml_mini.rb +44 -42
  253. data/lib/active_support.rb +19 -10
  254. metadata +79 -37
  255. data/lib/active_support/concurrency/latch.rb +0 -19
  256. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
  257. data/lib/active_support/core_ext/hash/compact.rb +0 -20
  258. data/lib/active_support/core_ext/hash/transform_values.rb +0 -29
  259. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  260. data/lib/active_support/core_ext/kernel/debugger.rb +0 -3
  261. data/lib/active_support/core_ext/module/method_transplanting.rb +0 -3
  262. data/lib/active_support/core_ext/module/qualified_const.rb +0 -70
  263. data/lib/active_support/core_ext/module/reachable.rb +0 -8
  264. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
  265. data/lib/active_support/core_ext/range/include_range.rb +0 -23
  266. data/lib/active_support/core_ext/struct.rb +0 -3
  267. data/lib/active_support/core_ext/time/marshal.rb +0 -3
  268. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,4 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerable
4
+ INDEX_WITH_DEFAULT = Object.new
5
+ private_constant :INDEX_WITH_DEFAULT
6
+
7
+ # Enumerable#sum was added in Ruby 2.4, but it only works with Numeric elements
8
+ # when we omit an identity.
9
+
10
+ # :stopdoc:
11
+
12
+ # We can't use Refinements here because Refinements with Module which will be prepended
13
+ # doesn't work well https://bugs.ruby-lang.org/issues/13446
14
+ alias :_original_sum_with_required_identity :sum
15
+ private :_original_sum_with_required_identity
16
+
17
+ # :startdoc:
18
+
2
19
  # Calculates a sum from the elements.
3
20
  #
4
21
  # payments.sum { |p| p.price * p.tax_rate }
@@ -12,34 +29,66 @@ module Enumerable
12
29
  #
13
30
  # [5, 15, 10].sum # => 30
14
31
  # ['foo', 'bar'].sum # => "foobar"
15
- # [[1, 2], [3, 1, 5]].sum => [1, 2, 3, 1, 5]
32
+ # [[1, 2], [3, 1, 5]].sum # => [1, 2, 3, 1, 5]
16
33
  #
17
34
  # The default sum of an empty list is zero. You can override this default:
18
35
  #
19
36
  # [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
20
37
  def sum(identity = nil, &block)
21
- if block_given?
38
+ if identity
39
+ _original_sum_with_required_identity(identity, &block)
40
+ elsif block_given?
22
41
  map(&block).sum(identity)
23
42
  else
24
- sum = identity ? inject(identity, :+) : inject(:+)
25
- sum || identity || 0
43
+ inject(:+) || 0
26
44
  end
27
45
  end
28
46
 
29
- # Convert an enumerable to a hash.
47
+ # Convert an enumerable to a hash, using the block result as the key and the
48
+ # element as the value.
30
49
  #
31
50
  # people.index_by(&:login)
32
- # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
51
+ # # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
52
+ #
33
53
  # people.index_by { |person| "#{person.first_name} #{person.last_name}" }
34
- # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
54
+ # # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
35
55
  def index_by
36
56
  if block_given?
37
- Hash[map { |elem| [yield(elem), elem] }]
57
+ result = {}
58
+ each { |elem| result[yield(elem)] = elem }
59
+ result
38
60
  else
39
61
  to_enum(:index_by) { size if respond_to?(:size) }
40
62
  end
41
63
  end
42
64
 
65
+ # Convert an enumerable to a hash, using the element as the key and the block
66
+ # result as the value.
67
+ #
68
+ # post = Post.new(title: "hey there", body: "what's up?")
69
+ #
70
+ # %i( title body ).index_with { |attr_name| post.public_send(attr_name) }
71
+ # # => { title: "hey there", body: "what's up?" }
72
+ #
73
+ # If an argument is passed instead of a block, it will be used as the value
74
+ # for all elements:
75
+ #
76
+ # %i( created_at updated_at ).index_with(Time.now)
77
+ # # => { created_at: 2020-03-09 22:31:47, updated_at: 2020-03-09 22:31:47 }
78
+ def index_with(default = INDEX_WITH_DEFAULT)
79
+ if block_given?
80
+ result = {}
81
+ each { |elem| result[elem] = yield(elem) }
82
+ result
83
+ elsif default != INDEX_WITH_DEFAULT
84
+ result = {}
85
+ each { |elem| result[elem] = default }
86
+ result
87
+ else
88
+ to_enum(:index_with) { size if respond_to?(:size) }
89
+ end
90
+ end
91
+
43
92
  # Returns +true+ if the enumerable has more than 1 element. Functionally
44
93
  # equivalent to <tt>enum.to_a.size > 1</tt>. Can be called with a block too,
45
94
  # much like any?, so <tt>people.many? { |p| p.age > 26 }</tt> returns +true+
@@ -56,37 +105,110 @@ module Enumerable
56
105
  end
57
106
  end
58
107
 
108
+ # Returns a new array that includes the passed elements.
109
+ #
110
+ # [ 1, 2, 3 ].including(4, 5)
111
+ # # => [ 1, 2, 3, 4, 5 ]
112
+ #
113
+ # ["David", "Rafael"].including %w[ Aaron Todd ]
114
+ # # => ["David", "Rafael", "Aaron", "Todd"]
115
+ def including(*elements)
116
+ to_a.including(*elements)
117
+ end
118
+
59
119
  # The negative of the <tt>Enumerable#include?</tt>. Returns +true+ if the
60
120
  # collection does not include the object.
61
121
  def exclude?(object)
62
122
  !include?(object)
63
123
  end
64
124
 
65
- # Returns a copy of the enumerable without the specified elements.
125
+ # Returns a copy of the enumerable excluding the specified elements.
66
126
  #
67
- # ["David", "Rafael", "Aaron", "Todd"].without "Aaron", "Todd"
68
- # => ["David", "Rafael"]
127
+ # ["David", "Rafael", "Aaron", "Todd"].excluding "Aaron", "Todd"
128
+ # # => ["David", "Rafael"]
69
129
  #
70
- # {foo: 1, bar: 2, baz: 3}.without :bar
71
- # => {foo: 1, baz: 3}
72
- def without(*elements)
130
+ # ["David", "Rafael", "Aaron", "Todd"].excluding %w[ Aaron Todd ]
131
+ # # => ["David", "Rafael"]
132
+ #
133
+ # {foo: 1, bar: 2, baz: 3}.excluding :bar
134
+ # # => {foo: 1, baz: 3}
135
+ def excluding(*elements)
136
+ elements.flatten!(1)
73
137
  reject { |element| elements.include?(element) }
74
138
  end
75
139
 
76
- # Convert an enumerable to an array based on the given key.
140
+ # Alias for #excluding.
141
+ def without(*elements)
142
+ excluding(*elements)
143
+ end
144
+
145
+ # Extract the given key from each element in the enumerable.
77
146
  #
78
147
  # [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)
79
- # => ["David", "Rafael", "Aaron"]
148
+ # # => ["David", "Rafael", "Aaron"]
80
149
  #
81
150
  # [{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pluck(:id, :name)
82
- # => [[1, "David"], [2, "Rafael"]]
151
+ # # => [[1, "David"], [2, "Rafael"]]
83
152
  def pluck(*keys)
84
153
  if keys.many?
85
154
  map { |element| keys.map { |key| element[key] } }
86
155
  else
87
- map { |element| element[keys.first] }
156
+ key = keys.first
157
+ map { |element| element[key] }
88
158
  end
89
159
  end
160
+
161
+ # Extract the given key from the first element in the enumerable.
162
+ #
163
+ # [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pick(:name)
164
+ # # => "David"
165
+ #
166
+ # [{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pick(:id, :name)
167
+ # # => [1, "David"]
168
+ def pick(*keys)
169
+ return if none?
170
+
171
+ if keys.many?
172
+ keys.map { |key| first[key] }
173
+ else
174
+ first[keys.first]
175
+ end
176
+ end
177
+
178
+ # Returns a new +Array+ without the blank items.
179
+ # Uses Object#blank? for determining if an item is blank.
180
+ #
181
+ # [1, "", nil, 2, " ", [], {}, false, true].compact_blank
182
+ # # => [1, 2, true]
183
+ #
184
+ # Set.new([nil, "", 1, 2])
185
+ # # => [2, 1] (or [1, 2])
186
+ #
187
+ # When called on a +Hash+, returns a new +Hash+ without the blank values.
188
+ #
189
+ # { a: "", b: 1, c: nil, d: [], e: false, f: true }.compact_blank
190
+ # #=> { b: 1, f: true }
191
+ def compact_blank
192
+ reject(&:blank?)
193
+ end
194
+ end
195
+
196
+ class Hash
197
+ # Hash#reject has its own definition, so this needs one too.
198
+ def compact_blank #:nodoc:
199
+ reject { |_k, v| v.blank? }
200
+ end
201
+
202
+ # Removes all blank values from the +Hash+ in place and returns self.
203
+ # Uses Object#blank? for determining if a value is blank.
204
+ #
205
+ # h = { a: "", b: 1, c: nil, d: [], e: false, f: true }
206
+ # h.compact_blank!
207
+ # # => { b: 1, f: true }
208
+ def compact_blank!
209
+ # use delete_if rather than reject! because it always returns self even if nothing changed
210
+ delete_if { |_k, v| v.blank? }
211
+ end
90
212
  end
91
213
 
92
214
  class Range #:nodoc:
@@ -107,18 +229,32 @@ class Range #:nodoc:
107
229
  end
108
230
  end
109
231
 
110
- # Array#sum was added in Ruby 2.4 but it only works with Numeric elements.
111
- #
112
- # We tried shimming it to attempt the fast native method, rescue TypeError,
113
- # and fall back to the compatible implementation, but that's much slower than
114
- # just calling the compat method in the first place.
115
- if Array.instance_methods(false).include?(:sum) && !(%w[a].sum rescue false)
116
- class Array
117
- remove_method :sum
118
-
119
- def sum(*args) #:nodoc:
120
- # Use Enumerable#sum instead.
232
+ # Using Refinements here in order not to expose our internal method
233
+ using Module.new {
234
+ refine Array do
235
+ alias :orig_sum :sum
236
+ end
237
+ }
238
+
239
+ class Array #:nodoc:
240
+ # Array#sum was added in Ruby 2.4 but it only works with Numeric elements.
241
+ def sum(init = nil, &block)
242
+ if init.is_a?(Numeric) || first.is_a?(Numeric)
243
+ init ||= 0
244
+ orig_sum(init, &block)
245
+ else
121
246
  super
122
247
  end
123
248
  end
249
+
250
+ # Removes all blank elements from the +Array+ in place and returns self.
251
+ # Uses Object#blank? for determining if an item is blank.
252
+ #
253
+ # a = [1, "", nil, 2, " ", [], {}, false, true]
254
+ # a.compact_blank!
255
+ # # => [1, 2, true]
256
+ def compact_blank!
257
+ # use delete_if rather than reject! because it always returns self even if nothing changed
258
+ delete_if(&:blank?)
259
+ end
124
260
  end
@@ -1,4 +1,6 @@
1
- require 'fileutils'
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
2
4
 
3
5
  class File
4
6
  # Write to a file atomically. Useful for situations where you don't
@@ -17,7 +19,7 @@ class File
17
19
  # file.write('hello')
18
20
  # end
19
21
  def self.atomic_write(file_name, temp_dir = dirname(file_name))
20
- require 'tempfile' unless defined?(Tempfile)
22
+ require "tempfile" unless defined?(Tempfile)
21
23
 
22
24
  Tempfile.open(".#{basename(file_name)}", temp_dir) do |temp_file|
23
25
  temp_file.binmode
@@ -27,7 +29,7 @@ class File
27
29
  old_stat = if exist?(file_name)
28
30
  # Get original file permissions
29
31
  stat(file_name)
30
- elsif temp_dir != dirname(file_name)
32
+ else
31
33
  # If not possible, probe which are the default permissions in the
32
34
  # destination directory.
33
35
  probe_stat_in(dirname(file_name))
@@ -53,11 +55,11 @@ class File
53
55
  # Private utility method.
54
56
  def self.probe_stat_in(dir) #:nodoc:
55
57
  basename = [
56
- '.permissions_check',
58
+ ".permissions_check",
57
59
  Thread.current.object_id,
58
60
  Process.pid,
59
61
  rand(1000000)
60
- ].join('.')
62
+ ].join(".")
61
63
 
62
64
  file_name = join(dir, basename)
63
65
  FileUtils.touch(file_name)
@@ -1 +1,3 @@
1
- require 'active_support/core_ext/file/atomic'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/file/atomic"
@@ -1,11 +1,13 @@
1
- require 'active_support/xml_mini'
2
- require 'active_support/time'
3
- require 'active_support/core_ext/object/blank'
4
- require 'active_support/core_ext/object/to_param'
5
- require 'active_support/core_ext/object/to_query'
6
- require 'active_support/core_ext/array/wrap'
7
- require 'active_support/core_ext/hash/reverse_merge'
8
- require 'active_support/core_ext/string/inflections'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/xml_mini"
4
+ require "active_support/core_ext/object/blank"
5
+ require "active_support/core_ext/object/to_param"
6
+ require "active_support/core_ext/object/to_query"
7
+ require "active_support/core_ext/object/try"
8
+ require "active_support/core_ext/array/wrap"
9
+ require "active_support/core_ext/hash/reverse_merge"
10
+ require "active_support/core_ext/string/inflections"
9
11
 
10
12
  class Hash
11
13
  # Returns a string containing an XML representation of its receiver:
@@ -71,11 +73,11 @@ class Hash
71
73
  # configure your own builder with the <tt>:builder</tt> option. The method also accepts
72
74
  # options like <tt>:dasherize</tt> and friends, they are forwarded to the builder.
73
75
  def to_xml(options = {})
74
- require 'active_support/builder' unless defined?(Builder)
76
+ require "active_support/builder" unless defined?(Builder::XmlMarkup)
75
77
 
76
78
  options = options.dup
77
79
  options[:indent] ||= 2
78
- options[:root] ||= 'hash'
80
+ options[:root] ||= "hash"
79
81
  options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent])
80
82
 
81
83
  builder = options[:builder]
@@ -159,36 +161,36 @@ module ActiveSupport
159
161
  private
160
162
  def normalize_keys(params)
161
163
  case params
162
- when Hash
163
- Hash[params.map { |k,v| [k.to_s.tr('-', '_'), normalize_keys(v)] } ]
164
- when Array
165
- params.map { |v| normalize_keys(v) }
166
- else
167
- params
164
+ when Hash
165
+ Hash[params.map { |k, v| [k.to_s.tr("-", "_"), normalize_keys(v)] } ]
166
+ when Array
167
+ params.map { |v| normalize_keys(v) }
168
+ else
169
+ params
168
170
  end
169
171
  end
170
172
 
171
173
  def deep_to_h(value)
172
174
  case value
173
- when Hash
174
- process_hash(value)
175
- when Array
176
- process_array(value)
177
- when String
178
- value
179
- else
180
- raise "can't typecast #{value.class.name} - #{value.inspect}"
175
+ when Hash
176
+ process_hash(value)
177
+ when Array
178
+ process_array(value)
179
+ when String
180
+ value
181
+ else
182
+ raise "can't typecast #{value.class.name} - #{value.inspect}"
181
183
  end
182
184
  end
183
185
 
184
186
  def process_hash(value)
185
- if value.include?('type') && !value['type'].is_a?(Hash) && @disallowed_types.include?(value['type'])
186
- raise DisallowedType, value['type']
187
+ if value.include?("type") && !value["type"].is_a?(Hash) && @disallowed_types.include?(value["type"])
188
+ raise DisallowedType, value["type"]
187
189
  end
188
190
 
189
191
  if become_array?(value)
190
- _, entries = Array.wrap(value.detect { |k,v| not v.is_a?(String) })
191
- if entries.nil? || value['__content__'].try(:empty?)
192
+ _, entries = Array.wrap(value.detect { |k, v| not v.is_a?(String) })
193
+ if entries.nil? || value["__content__"].try(:empty?)
192
194
  []
193
195
  else
194
196
  case entries
@@ -204,28 +206,28 @@ module ActiveSupport
204
206
  process_content(value)
205
207
 
206
208
  elsif become_empty_string?(value)
207
- ''
209
+ ""
208
210
  elsif become_hash?(value)
209
- xml_value = Hash[value.map { |k,v| [k, deep_to_h(v)] }]
211
+ xml_value = value.transform_values { |v| deep_to_h(v) }
210
212
 
211
213
  # Turn { files: { file: #<StringIO> } } into { files: #<StringIO> } so it is compatible with
212
214
  # how multipart uploaded files from HTML appear
213
- xml_value['file'].is_a?(StringIO) ? xml_value['file'] : xml_value
215
+ xml_value["file"].is_a?(StringIO) ? xml_value["file"] : xml_value
214
216
  end
215
217
  end
216
218
 
217
219
  def become_content?(value)
218
- value['type'] == 'file' || (value['__content__'] && (value.keys.size == 1 || value['__content__'].present?))
220
+ value["type"] == "file" || (value["__content__"] && (value.keys.size == 1 || value["__content__"].present?))
219
221
  end
220
222
 
221
223
  def become_array?(value)
222
- value['type'] == 'array'
224
+ value["type"] == "array"
223
225
  end
224
226
 
225
227
  def become_empty_string?(value)
226
228
  # { "string" => true }
227
229
  # No tests fail when the second term is removed.
228
- value['type'] == 'string' && value['nil'] != 'true'
230
+ value["type"] == "string" && value["nil"] != "true"
229
231
  end
230
232
 
231
233
  def become_hash?(value)
@@ -234,19 +236,19 @@ module ActiveSupport
234
236
 
235
237
  def nothing?(value)
236
238
  # blank or nil parsed values are represented by nil
237
- value.blank? || value['nil'] == 'true'
239
+ value.blank? || value["nil"] == "true"
238
240
  end
239
241
 
240
242
  def garbage?(value)
241
243
  # If the type is the only element which makes it then
242
244
  # this still makes the value nil, except if type is
243
245
  # an XML node(where type['value'] is a Hash)
244
- value['type'] && !value['type'].is_a?(::Hash) && value.size == 1
246
+ value["type"] && !value["type"].is_a?(::Hash) && value.size == 1
245
247
  end
246
248
 
247
249
  def process_content(value)
248
- content = value['__content__']
249
- if parser = ActiveSupport::XmlMini::PARSING[value['type']]
250
+ content = value["__content__"]
251
+ if parser = ActiveSupport::XmlMini::PARSING[value["type"]]
250
252
  parser.arity == 1 ? parser.call(content) : parser.call(content, value)
251
253
  else
252
254
  content
@@ -257,6 +259,5 @@ module ActiveSupport
257
259
  value.map! { |i| deep_to_h(i) }
258
260
  value.length > 1 ? value : value.first
259
261
  end
260
-
261
262
  end
262
263
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Hash
2
4
  # Returns a new hash with +self+ and +other_hash+ merged recursively.
3
5
  #
@@ -19,20 +21,14 @@ class Hash
19
21
 
20
22
  # Same as +deep_merge+, but modifies +self+.
21
23
  def deep_merge!(other_hash, &block)
22
- other_hash.each_pair do |current_key, other_value|
23
- this_value = self[current_key]
24
-
25
- self[current_key] = if this_value.is_a?(Hash) && other_value.is_a?(Hash)
26
- this_value.deep_merge(other_value, &block)
24
+ merge!(other_hash) do |key, this_val, other_val|
25
+ if this_val.is_a?(Hash) && other_val.is_a?(Hash)
26
+ this_val.deep_merge(other_val, &block)
27
+ elsif block_given?
28
+ block.call(key, this_val, other_val)
27
29
  else
28
- if block_given? && key?(current_key)
29
- block.call(current_key, this_value, other_value)
30
- else
31
- other_value
32
- end
30
+ other_val
33
31
  end
34
32
  end
35
-
36
- self
37
33
  end
38
34
  end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hash
4
+ # Returns a new hash with all values converted by the block operation.
5
+ # This includes the values from the root hash and from all
6
+ # nested hashes and arrays.
7
+ #
8
+ # hash = { person: { name: 'Rob', age: '28' } }
9
+ #
10
+ # hash.deep_transform_values{ |value| value.to_s.upcase }
11
+ # # => {person: {name: "ROB", age: "28"}}
12
+ def deep_transform_values(&block)
13
+ _deep_transform_values_in_object(self, &block)
14
+ end
15
+
16
+ # Destructively converts all values by using the block operation.
17
+ # This includes the values from the root hash and from all
18
+ # nested hashes and arrays.
19
+ def deep_transform_values!(&block)
20
+ _deep_transform_values_in_object!(self, &block)
21
+ end
22
+
23
+ private
24
+ # Support methods for deep transforming nested hashes and arrays.
25
+ def _deep_transform_values_in_object(object, &block)
26
+ case object
27
+ when Hash
28
+ object.transform_values { |value| _deep_transform_values_in_object(value, &block) }
29
+ when Array
30
+ object.map { |e| _deep_transform_values_in_object(e, &block) }
31
+ else
32
+ yield(object)
33
+ end
34
+ end
35
+
36
+ def _deep_transform_values_in_object!(object, &block)
37
+ case object
38
+ when Hash
39
+ object.transform_values! { |value| _deep_transform_values_in_object!(value, &block) }
40
+ when Array
41
+ object.map! { |e| _deep_transform_values_in_object!(e, &block) }
42
+ else
43
+ yield(object)
44
+ end
45
+ end
46
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Hash
2
4
  # Returns a hash that includes everything except given keys.
3
5
  # hash = { a: true, b: false, c: nil }
@@ -8,8 +10,8 @@ class Hash
8
10
  # This is useful for limiting a set of parameters to everything but a few known toggles:
9
11
  # @person.update(params[:person].except(:admin))
10
12
  def except(*keys)
11
- dup.except!(*keys)
12
- end
13
+ slice(*self.keys - keys)
14
+ end unless method_defined?(:except)
13
15
 
14
16
  # Removes the given keys from hash and returns it.
15
17
  # hash = { a: true, b: false, c: nil }
@@ -1,7 +1,8 @@
1
- require 'active_support/hash_with_indifferent_access'
1
+ # frozen_string_literal: true
2
2
 
3
- class Hash
3
+ require "active_support/hash_with_indifferent_access"
4
4
 
5
+ class Hash
5
6
  # Returns an <tt>ActiveSupport::HashWithIndifferentAccess</tt> out of its receiver:
6
7
  #
7
8
  # { a: 1 }.with_indifferent_access['a'] # => 1
@@ -1,33 +1,6 @@
1
- class Hash
2
- # Returns a new hash with all keys converted using the +block+ operation.
3
- #
4
- # hash = { name: 'Rob', age: '28' }
5
- #
6
- # hash.transform_keys { |key| key.to_s.upcase } # => {"NAME"=>"Rob", "AGE"=>"28"}
7
- #
8
- # If you do not provide a +block+, it will return an Enumerator
9
- # for chaining with other methods:
10
- #
11
- # hash.transform_keys.with_index { |k, i| [k, i].join } # => {"name0"=>"Rob", "age1"=>"28"}
12
- def transform_keys
13
- return enum_for(:transform_keys) { size } unless block_given?
14
- result = {}
15
- each_key do |key|
16
- result[yield(key)] = self[key]
17
- end
18
- result
19
- end
20
-
21
- # Destructively converts all keys using the +block+ operations.
22
- # Same as +transform_keys+ but modifies +self+.
23
- def transform_keys!
24
- return enum_for(:transform_keys!) { size } unless block_given?
25
- keys.each do |key|
26
- self[yield(key)] = delete(key)
27
- end
28
- self
29
- end
1
+ # frozen_string_literal: true
30
2
 
3
+ class Hash
31
4
  # Returns a new hash with all keys converted to strings.
32
5
  #
33
6
  # hash = { name: 'Rob', age: '28' }
@@ -52,14 +25,14 @@ class Hash
52
25
  # hash.symbolize_keys
53
26
  # # => {:name=>"Rob", :age=>"28"}
54
27
  def symbolize_keys
55
- transform_keys{ |key| key.to_sym rescue key }
28
+ transform_keys { |key| key.to_sym rescue key }
56
29
  end
57
30
  alias_method :to_options, :symbolize_keys
58
31
 
59
32
  # Destructively converts all keys to symbols, as long as they respond
60
33
  # to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
61
34
  def symbolize_keys!
62
- transform_keys!{ |key| key.to_sym rescue key }
35
+ transform_keys! { |key| key.to_sym rescue key }
63
36
  end
64
37
  alias_method :to_options!, :symbolize_keys!
65
38
 
@@ -128,18 +101,18 @@ class Hash
128
101
  # hash.deep_symbolize_keys
129
102
  # # => {:person=>{:name=>"Rob", :age=>"28"}}
130
103
  def deep_symbolize_keys
131
- deep_transform_keys{ |key| key.to_sym rescue key }
104
+ deep_transform_keys { |key| key.to_sym rescue key }
132
105
  end
133
106
 
134
107
  # Destructively converts all keys to symbols, as long as they respond
135
108
  # to +to_sym+. This includes the keys from the root hash and from all
136
109
  # nested hashes and arrays.
137
110
  def deep_symbolize_keys!
138
- deep_transform_keys!{ |key| key.to_sym rescue key }
111
+ deep_transform_keys! { |key| key.to_sym rescue key }
139
112
  end
140
113
 
141
114
  private
142
- # support methods for deep transforming nested hashes and arrays
115
+ # Support methods for deep transforming nested hashes and arrays.
143
116
  def _deep_transform_keys_in_object(object, &block)
144
117
  case object
145
118
  when Hash
@@ -147,7 +120,7 @@ class Hash
147
120
  result[yield(key)] = _deep_transform_keys_in_object(value, &block)
148
121
  end
149
122
  when Array
150
- object.map {|e| _deep_transform_keys_in_object(e, &block) }
123
+ object.map { |e| _deep_transform_keys_in_object(e, &block) }
151
124
  else
152
125
  object
153
126
  end
@@ -162,7 +135,7 @@ class Hash
162
135
  end
163
136
  object
164
137
  when Array
165
- object.map! {|e| _deep_transform_keys_in_object!(e, &block)}
138
+ object.map! { |e| _deep_transform_keys_in_object!(e, &block) }
166
139
  else
167
140
  object
168
141
  end