activesupport 6.0.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 (250) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +572 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +40 -0
  5. data/lib/active_support.rb +96 -0
  6. data/lib/active_support/actionable_error.rb +48 -0
  7. data/lib/active_support/all.rb +5 -0
  8. data/lib/active_support/array_inquirer.rb +48 -0
  9. data/lib/active_support/backtrace_cleaner.rb +132 -0
  10. data/lib/active_support/benchmarkable.rb +51 -0
  11. data/lib/active_support/builder.rb +8 -0
  12. data/lib/active_support/cache.rb +830 -0
  13. data/lib/active_support/cache/file_store.rb +196 -0
  14. data/lib/active_support/cache/mem_cache_store.rb +212 -0
  15. data/lib/active_support/cache/memory_store.rb +174 -0
  16. data/lib/active_support/cache/null_store.rb +48 -0
  17. data/lib/active_support/cache/redis_cache_store.rb +488 -0
  18. data/lib/active_support/cache/strategy/local_cache.rb +194 -0
  19. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  20. data/lib/active_support/callbacks.rb +856 -0
  21. data/lib/active_support/concern.rb +171 -0
  22. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +17 -0
  23. data/lib/active_support/concurrency/share_lock.rb +227 -0
  24. data/lib/active_support/configurable.rb +146 -0
  25. data/lib/active_support/core_ext.rb +5 -0
  26. data/lib/active_support/core_ext/array.rb +9 -0
  27. data/lib/active_support/core_ext/array/access.rb +104 -0
  28. data/lib/active_support/core_ext/array/conversions.rb +213 -0
  29. data/lib/active_support/core_ext/array/extract.rb +21 -0
  30. data/lib/active_support/core_ext/array/extract_options.rb +31 -0
  31. data/lib/active_support/core_ext/array/grouping.rb +109 -0
  32. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  33. data/lib/active_support/core_ext/array/prepend_and_append.rb +5 -0
  34. data/lib/active_support/core_ext/array/wrap.rb +48 -0
  35. data/lib/active_support/core_ext/benchmark.rb +16 -0
  36. data/lib/active_support/core_ext/big_decimal.rb +3 -0
  37. data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
  38. data/lib/active_support/core_ext/class.rb +4 -0
  39. data/lib/active_support/core_ext/class/attribute.rb +141 -0
  40. data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
  41. data/lib/active_support/core_ext/class/subclasses.rb +54 -0
  42. data/lib/active_support/core_ext/date.rb +7 -0
  43. data/lib/active_support/core_ext/date/acts_like.rb +10 -0
  44. data/lib/active_support/core_ext/date/blank.rb +14 -0
  45. data/lib/active_support/core_ext/date/calculations.rb +146 -0
  46. data/lib/active_support/core_ext/date/conversions.rb +96 -0
  47. data/lib/active_support/core_ext/date/zones.rb +8 -0
  48. data/lib/active_support/core_ext/date_and_time/calculations.rb +351 -0
  49. data/lib/active_support/core_ext/date_and_time/compatibility.rb +16 -0
  50. data/lib/active_support/core_ext/date_and_time/zones.rb +41 -0
  51. data/lib/active_support/core_ext/date_time.rb +7 -0
  52. data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
  53. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  54. data/lib/active_support/core_ext/date_time/calculations.rb +211 -0
  55. data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
  56. data/lib/active_support/core_ext/date_time/conversions.rb +107 -0
  57. data/lib/active_support/core_ext/digest.rb +3 -0
  58. data/lib/active_support/core_ext/digest/uuid.rb +53 -0
  59. data/lib/active_support/core_ext/enumerable.rb +188 -0
  60. data/lib/active_support/core_ext/file.rb +3 -0
  61. data/lib/active_support/core_ext/file/atomic.rb +70 -0
  62. data/lib/active_support/core_ext/hash.rb +10 -0
  63. data/lib/active_support/core_ext/hash/compact.rb +5 -0
  64. data/lib/active_support/core_ext/hash/conversions.rb +263 -0
  65. data/lib/active_support/core_ext/hash/deep_merge.rb +34 -0
  66. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  67. data/lib/active_support/core_ext/hash/except.rb +24 -0
  68. data/lib/active_support/core_ext/hash/indifferent_access.rb +24 -0
  69. data/lib/active_support/core_ext/hash/keys.rb +143 -0
  70. data/lib/active_support/core_ext/hash/reverse_merge.rb +25 -0
  71. data/lib/active_support/core_ext/hash/slice.rb +26 -0
  72. data/lib/active_support/core_ext/hash/transform_values.rb +5 -0
  73. data/lib/active_support/core_ext/integer.rb +5 -0
  74. data/lib/active_support/core_ext/integer/inflections.rb +31 -0
  75. data/lib/active_support/core_ext/integer/multiple.rb +12 -0
  76. data/lib/active_support/core_ext/integer/time.rb +22 -0
  77. data/lib/active_support/core_ext/kernel.rb +5 -0
  78. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  79. data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
  80. data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
  81. data/lib/active_support/core_ext/load_error.rb +9 -0
  82. data/lib/active_support/core_ext/marshal.rb +24 -0
  83. data/lib/active_support/core_ext/module.rb +13 -0
  84. data/lib/active_support/core_ext/module/aliasing.rb +31 -0
  85. data/lib/active_support/core_ext/module/anonymous.rb +30 -0
  86. data/lib/active_support/core_ext/module/attr_internal.rb +38 -0
  87. data/lib/active_support/core_ext/module/attribute_accessors.rb +212 -0
  88. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +144 -0
  89. data/lib/active_support/core_ext/module/concerning.rb +134 -0
  90. data/lib/active_support/core_ext/module/delegation.rb +313 -0
  91. data/lib/active_support/core_ext/module/deprecation.rb +25 -0
  92. data/lib/active_support/core_ext/module/introspection.rb +86 -0
  93. data/lib/active_support/core_ext/module/reachable.rb +6 -0
  94. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  95. data/lib/active_support/core_ext/module/remove_method.rb +17 -0
  96. data/lib/active_support/core_ext/name_error.rb +38 -0
  97. data/lib/active_support/core_ext/numeric.rb +5 -0
  98. data/lib/active_support/core_ext/numeric/bytes.rb +66 -0
  99. data/lib/active_support/core_ext/numeric/conversions.rb +136 -0
  100. data/lib/active_support/core_ext/numeric/inquiry.rb +5 -0
  101. data/lib/active_support/core_ext/numeric/time.rb +66 -0
  102. data/lib/active_support/core_ext/object.rb +16 -0
  103. data/lib/active_support/core_ext/object/acts_like.rb +21 -0
  104. data/lib/active_support/core_ext/object/blank.rb +155 -0
  105. data/lib/active_support/core_ext/object/conversions.rb +6 -0
  106. data/lib/active_support/core_ext/object/deep_dup.rb +55 -0
  107. data/lib/active_support/core_ext/object/duplicable.rb +49 -0
  108. data/lib/active_support/core_ext/object/inclusion.rb +29 -0
  109. data/lib/active_support/core_ext/object/instance_variables.rb +30 -0
  110. data/lib/active_support/core_ext/object/json.rb +228 -0
  111. data/lib/active_support/core_ext/object/to_param.rb +3 -0
  112. data/lib/active_support/core_ext/object/to_query.rb +89 -0
  113. data/lib/active_support/core_ext/object/try.rb +156 -0
  114. data/lib/active_support/core_ext/object/with_options.rb +82 -0
  115. data/lib/active_support/core_ext/range.rb +7 -0
  116. data/lib/active_support/core_ext/range/compare_range.rb +70 -0
  117. data/lib/active_support/core_ext/range/conversions.rb +41 -0
  118. data/lib/active_support/core_ext/range/each.rb +25 -0
  119. data/lib/active_support/core_ext/range/include_range.rb +9 -0
  120. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  121. data/lib/active_support/core_ext/range/overlaps.rb +10 -0
  122. data/lib/active_support/core_ext/regexp.rb +7 -0
  123. data/lib/active_support/core_ext/securerandom.rb +45 -0
  124. data/lib/active_support/core_ext/string.rb +15 -0
  125. data/lib/active_support/core_ext/string/access.rb +114 -0
  126. data/lib/active_support/core_ext/string/behavior.rb +8 -0
  127. data/lib/active_support/core_ext/string/conversions.rb +59 -0
  128. data/lib/active_support/core_ext/string/exclude.rb +13 -0
  129. data/lib/active_support/core_ext/string/filters.rb +145 -0
  130. data/lib/active_support/core_ext/string/indent.rb +45 -0
  131. data/lib/active_support/core_ext/string/inflections.rb +259 -0
  132. data/lib/active_support/core_ext/string/inquiry.rb +15 -0
  133. data/lib/active_support/core_ext/string/multibyte.rb +58 -0
  134. data/lib/active_support/core_ext/string/output_safety.rb +314 -0
  135. data/lib/active_support/core_ext/string/starts_ends_with.rb +6 -0
  136. data/lib/active_support/core_ext/string/strip.rb +27 -0
  137. data/lib/active_support/core_ext/string/zones.rb +16 -0
  138. data/lib/active_support/core_ext/time.rb +7 -0
  139. data/lib/active_support/core_ext/time/acts_like.rb +10 -0
  140. data/lib/active_support/core_ext/time/calculations.rb +344 -0
  141. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  142. data/lib/active_support/core_ext/time/conversions.rb +72 -0
  143. data/lib/active_support/core_ext/time/zones.rb +113 -0
  144. data/lib/active_support/core_ext/uri.rb +25 -0
  145. data/lib/active_support/current_attributes.rb +203 -0
  146. data/lib/active_support/dependencies.rb +806 -0
  147. data/lib/active_support/dependencies/autoload.rb +79 -0
  148. data/lib/active_support/dependencies/interlock.rb +57 -0
  149. data/lib/active_support/dependencies/zeitwerk_integration.rb +110 -0
  150. data/lib/active_support/deprecation.rb +46 -0
  151. data/lib/active_support/deprecation/behaviors.rb +109 -0
  152. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  153. data/lib/active_support/deprecation/instance_delegator.rb +39 -0
  154. data/lib/active_support/deprecation/method_wrappers.rb +78 -0
  155. data/lib/active_support/deprecation/proxy_wrappers.rb +173 -0
  156. data/lib/active_support/deprecation/reporting.rb +114 -0
  157. data/lib/active_support/descendants_tracker.rb +109 -0
  158. data/lib/active_support/digest.rb +20 -0
  159. data/lib/active_support/duration.rb +433 -0
  160. data/lib/active_support/duration/iso8601_parser.rb +124 -0
  161. data/lib/active_support/duration/iso8601_serializer.rb +54 -0
  162. data/lib/active_support/encrypted_configuration.rb +45 -0
  163. data/lib/active_support/encrypted_file.rb +100 -0
  164. data/lib/active_support/evented_file_update_checker.rb +235 -0
  165. data/lib/active_support/execution_wrapper.rb +129 -0
  166. data/lib/active_support/executor.rb +8 -0
  167. data/lib/active_support/file_update_checker.rb +163 -0
  168. data/lib/active_support/gem_version.rb +17 -0
  169. data/lib/active_support/gzip.rb +38 -0
  170. data/lib/active_support/hash_with_indifferent_access.rb +399 -0
  171. data/lib/active_support/i18n.rb +16 -0
  172. data/lib/active_support/i18n_railtie.rb +126 -0
  173. data/lib/active_support/inflections.rb +72 -0
  174. data/lib/active_support/inflector.rb +9 -0
  175. data/lib/active_support/inflector/inflections.rb +257 -0
  176. data/lib/active_support/inflector/methods.rb +398 -0
  177. data/lib/active_support/inflector/transliterate.rb +147 -0
  178. data/lib/active_support/json.rb +4 -0
  179. data/lib/active_support/json/decoding.rb +76 -0
  180. data/lib/active_support/json/encoding.rb +134 -0
  181. data/lib/active_support/key_generator.rb +41 -0
  182. data/lib/active_support/lazy_load_hooks.rb +82 -0
  183. data/lib/active_support/locale/en.rb +31 -0
  184. data/lib/active_support/locale/en.yml +135 -0
  185. data/lib/active_support/log_subscriber.rb +135 -0
  186. data/lib/active_support/log_subscriber/test_helper.rb +106 -0
  187. data/lib/active_support/logger.rb +93 -0
  188. data/lib/active_support/logger_silence.rb +45 -0
  189. data/lib/active_support/logger_thread_safe_level.rb +56 -0
  190. data/lib/active_support/message_encryptor.rb +227 -0
  191. data/lib/active_support/message_verifier.rb +205 -0
  192. data/lib/active_support/messages/metadata.rb +71 -0
  193. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  194. data/lib/active_support/messages/rotator.rb +56 -0
  195. data/lib/active_support/multibyte.rb +23 -0
  196. data/lib/active_support/multibyte/chars.rb +216 -0
  197. data/lib/active_support/multibyte/unicode.rb +157 -0
  198. data/lib/active_support/notifications.rb +253 -0
  199. data/lib/active_support/notifications/fanout.rb +244 -0
  200. data/lib/active_support/notifications/instrumenter.rb +164 -0
  201. data/lib/active_support/number_helper.rb +378 -0
  202. data/lib/active_support/number_helper/number_converter.rb +184 -0
  203. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  204. data/lib/active_support/number_helper/number_to_delimited_converter.rb +31 -0
  205. data/lib/active_support/number_helper/number_to_human_converter.rb +70 -0
  206. data/lib/active_support/number_helper/number_to_human_size_converter.rb +61 -0
  207. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  208. data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
  209. data/lib/active_support/number_helper/number_to_rounded_converter.rb +56 -0
  210. data/lib/active_support/number_helper/rounding_helper.rb +66 -0
  211. data/lib/active_support/option_merger.rb +27 -0
  212. data/lib/active_support/ordered_hash.rb +50 -0
  213. data/lib/active_support/ordered_options.rb +85 -0
  214. data/lib/active_support/parameter_filter.rb +129 -0
  215. data/lib/active_support/per_thread_registry.rb +60 -0
  216. data/lib/active_support/proxy_object.rb +15 -0
  217. data/lib/active_support/rails.rb +29 -0
  218. data/lib/active_support/railtie.rb +80 -0
  219. data/lib/active_support/reloader.rb +130 -0
  220. data/lib/active_support/rescuable.rb +174 -0
  221. data/lib/active_support/security_utils.rb +31 -0
  222. data/lib/active_support/string_inquirer.rb +34 -0
  223. data/lib/active_support/subscriber.rb +169 -0
  224. data/lib/active_support/tagged_logging.rb +88 -0
  225. data/lib/active_support/test_case.rb +163 -0
  226. data/lib/active_support/testing/assertions.rb +228 -0
  227. data/lib/active_support/testing/autorun.rb +7 -0
  228. data/lib/active_support/testing/constant_lookup.rb +51 -0
  229. data/lib/active_support/testing/declarative.rb +28 -0
  230. data/lib/active_support/testing/deprecation.rb +38 -0
  231. data/lib/active_support/testing/file_fixtures.rb +38 -0
  232. data/lib/active_support/testing/isolation.rb +110 -0
  233. data/lib/active_support/testing/method_call_assertions.rb +70 -0
  234. data/lib/active_support/testing/parallelization.rb +128 -0
  235. data/lib/active_support/testing/setup_and_teardown.rb +55 -0
  236. data/lib/active_support/testing/stream.rb +44 -0
  237. data/lib/active_support/testing/tagged_logging.rb +27 -0
  238. data/lib/active_support/testing/time_helpers.rb +200 -0
  239. data/lib/active_support/time.rb +20 -0
  240. data/lib/active_support/time_with_zone.rb +561 -0
  241. data/lib/active_support/values/time_zone.rb +570 -0
  242. data/lib/active_support/version.rb +10 -0
  243. data/lib/active_support/xml_mini.rb +202 -0
  244. data/lib/active_support/xml_mini/jdom.rb +183 -0
  245. data/lib/active_support/xml_mini/libxml.rb +80 -0
  246. data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
  247. data/lib/active_support/xml_mini/nokogiri.rb +83 -0
  248. data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
  249. data/lib/active_support/xml_mini/rexml.rb +130 -0
  250. metadata +385 -0
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ Dir.glob(File.expand_path("core_ext/*.rb", __dir__)).each do |path|
4
+ require path
5
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/array/wrap"
4
+ require "active_support/core_ext/array/access"
5
+ require "active_support/core_ext/array/conversions"
6
+ require "active_support/core_ext/array/extract"
7
+ require "active_support/core_ext/array/extract_options"
8
+ require "active_support/core_ext/array/grouping"
9
+ require "active_support/core_ext/array/inquiry"
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Array
4
+ # Returns the tail of the array from +position+.
5
+ #
6
+ # %w( a b c d ).from(0) # => ["a", "b", "c", "d"]
7
+ # %w( a b c d ).from(2) # => ["c", "d"]
8
+ # %w( a b c d ).from(10) # => []
9
+ # %w().from(0) # => []
10
+ # %w( a b c d ).from(-2) # => ["c", "d"]
11
+ # %w( a b c ).from(-10) # => []
12
+ def from(position)
13
+ self[position, length] || []
14
+ end
15
+
16
+ # Returns the beginning of the array up to +position+.
17
+ #
18
+ # %w( a b c d ).to(0) # => ["a"]
19
+ # %w( a b c d ).to(2) # => ["a", "b", "c"]
20
+ # %w( a b c d ).to(10) # => ["a", "b", "c", "d"]
21
+ # %w().to(0) # => []
22
+ # %w( a b c d ).to(-2) # => ["a", "b", "c"]
23
+ # %w( a b c ).to(-10) # => []
24
+ def to(position)
25
+ if position >= 0
26
+ take position + 1
27
+ else
28
+ self[0..position]
29
+ end
30
+ end
31
+
32
+ # Returns a new array that includes the passed elements.
33
+ #
34
+ # [ 1, 2, 3 ].including(4, 5) # => [ 1, 2, 3, 4, 5 ]
35
+ # [ [ 0, 1 ] ].including([ [ 1, 0 ] ]) # => [ [ 0, 1 ], [ 1, 0 ] ]
36
+ def including(*elements)
37
+ self + elements.flatten(1)
38
+ end
39
+
40
+ # Returns a copy of the Array excluding the specified elements.
41
+ #
42
+ # ["David", "Rafael", "Aaron", "Todd"].excluding("Aaron", "Todd") # => ["David", "Rafael"]
43
+ # [ [ 0, 1 ], [ 1, 0 ] ].excluding([ [ 1, 0 ] ]) # => [ [ 0, 1 ] ]
44
+ #
45
+ # Note: This is an optimization of <tt>Enumerable#excluding</tt> that uses <tt>Array#-</tt>
46
+ # instead of <tt>Array#reject</tt> for performance reasons.
47
+ def excluding(*elements)
48
+ self - elements.flatten(1)
49
+ end
50
+
51
+ # Alias for #excluding.
52
+ def without(*elements)
53
+ excluding(*elements)
54
+ end
55
+
56
+ # Equal to <tt>self[1]</tt>.
57
+ #
58
+ # %w( a b c d e ).second # => "b"
59
+ def second
60
+ self[1]
61
+ end
62
+
63
+ # Equal to <tt>self[2]</tt>.
64
+ #
65
+ # %w( a b c d e ).third # => "c"
66
+ def third
67
+ self[2]
68
+ end
69
+
70
+ # Equal to <tt>self[3]</tt>.
71
+ #
72
+ # %w( a b c d e ).fourth # => "d"
73
+ def fourth
74
+ self[3]
75
+ end
76
+
77
+ # Equal to <tt>self[4]</tt>.
78
+ #
79
+ # %w( a b c d e ).fifth # => "e"
80
+ def fifth
81
+ self[4]
82
+ end
83
+
84
+ # Equal to <tt>self[41]</tt>. Also known as accessing "the reddit".
85
+ #
86
+ # (1..42).to_a.forty_two # => 42
87
+ def forty_two
88
+ self[41]
89
+ end
90
+
91
+ # Equal to <tt>self[-3]</tt>.
92
+ #
93
+ # %w( a b c d e ).third_to_last # => "c"
94
+ def third_to_last
95
+ self[-3]
96
+ end
97
+
98
+ # Equal to <tt>self[-2]</tt>.
99
+ #
100
+ # %w( a b c d e ).second_to_last # => "d"
101
+ def second_to_last
102
+ self[-2]
103
+ end
104
+ end
@@ -0,0 +1,213 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/xml_mini"
4
+ require "active_support/core_ext/hash/keys"
5
+ require "active_support/core_ext/string/inflections"
6
+ require "active_support/core_ext/object/to_param"
7
+ require "active_support/core_ext/object/to_query"
8
+
9
+ class Array
10
+ # Converts the array to a comma-separated sentence where the last element is
11
+ # joined by the connector word.
12
+ #
13
+ # You can pass the following options to change the default behavior. If you
14
+ # pass an option key that doesn't exist in the list below, it will raise an
15
+ # <tt>ArgumentError</tt>.
16
+ #
17
+ # ==== Options
18
+ #
19
+ # * <tt>:words_connector</tt> - The sign or word used to join the elements
20
+ # in arrays with two or more elements (default: ", ").
21
+ # * <tt>:two_words_connector</tt> - The sign or word used to join the elements
22
+ # in arrays with two elements (default: " and ").
23
+ # * <tt>:last_word_connector</tt> - The sign or word used to join the last element
24
+ # in arrays with three or more elements (default: ", and ").
25
+ # * <tt>:locale</tt> - If +i18n+ is available, you can set a locale and use
26
+ # the connector options defined on the 'support.array' namespace in the
27
+ # corresponding dictionary file.
28
+ #
29
+ # ==== Examples
30
+ #
31
+ # [].to_sentence # => ""
32
+ # ['one'].to_sentence # => "one"
33
+ # ['one', 'two'].to_sentence # => "one and two"
34
+ # ['one', 'two', 'three'].to_sentence # => "one, two, and three"
35
+ #
36
+ # ['one', 'two'].to_sentence(passing: 'invalid option')
37
+ # # => ArgumentError: Unknown key: :passing. Valid keys are: :words_connector, :two_words_connector, :last_word_connector, :locale
38
+ #
39
+ # ['one', 'two'].to_sentence(two_words_connector: '-')
40
+ # # => "one-two"
41
+ #
42
+ # ['one', 'two', 'three'].to_sentence(words_connector: ' or ', last_word_connector: ' or at least ')
43
+ # # => "one or two or at least three"
44
+ #
45
+ # Using <tt>:locale</tt> option:
46
+ #
47
+ # # Given this locale dictionary:
48
+ # #
49
+ # # es:
50
+ # # support:
51
+ # # array:
52
+ # # words_connector: " o "
53
+ # # two_words_connector: " y "
54
+ # # last_word_connector: " o al menos "
55
+ #
56
+ # ['uno', 'dos'].to_sentence(locale: :es)
57
+ # # => "uno y dos"
58
+ #
59
+ # ['uno', 'dos', 'tres'].to_sentence(locale: :es)
60
+ # # => "uno o dos o al menos tres"
61
+ def to_sentence(options = {})
62
+ options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale)
63
+
64
+ default_connectors = {
65
+ words_connector: ", ",
66
+ two_words_connector: " and ",
67
+ last_word_connector: ", and "
68
+ }
69
+ if defined?(I18n)
70
+ i18n_connectors = I18n.translate(:'support.array', locale: options[:locale], default: {})
71
+ default_connectors.merge!(i18n_connectors)
72
+ end
73
+ options = default_connectors.merge!(options)
74
+
75
+ case length
76
+ when 0
77
+ ""
78
+ when 1
79
+ "#{self[0]}"
80
+ when 2
81
+ "#{self[0]}#{options[:two_words_connector]}#{self[1]}"
82
+ else
83
+ "#{self[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{self[-1]}"
84
+ end
85
+ end
86
+
87
+ # Extends <tt>Array#to_s</tt> to convert a collection of elements into a
88
+ # comma separated id list if <tt>:db</tt> argument is given as the format.
89
+ #
90
+ # Blog.all.to_formatted_s(:db) # => "1,2,3"
91
+ # Blog.none.to_formatted_s(:db) # => "null"
92
+ # [1,2].to_formatted_s # => "[1, 2]"
93
+ def to_formatted_s(format = :default)
94
+ case format
95
+ when :db
96
+ if empty?
97
+ "null"
98
+ else
99
+ collect(&:id).join(",")
100
+ end
101
+ else
102
+ to_default_s
103
+ end
104
+ end
105
+ alias_method :to_default_s, :to_s
106
+ alias_method :to_s, :to_formatted_s
107
+
108
+ # Returns a string that represents the array in XML by invoking +to_xml+
109
+ # on each element. Active Record collections delegate their representation
110
+ # in XML to this method.
111
+ #
112
+ # All elements are expected to respond to +to_xml+, if any of them does
113
+ # not then an exception is raised.
114
+ #
115
+ # The root node reflects the class name of the first element in plural
116
+ # if all elements belong to the same type and that's not Hash:
117
+ #
118
+ # customer.projects.to_xml
119
+ #
120
+ # <?xml version="1.0" encoding="UTF-8"?>
121
+ # <projects type="array">
122
+ # <project>
123
+ # <amount type="decimal">20000.0</amount>
124
+ # <customer-id type="integer">1567</customer-id>
125
+ # <deal-date type="date">2008-04-09</deal-date>
126
+ # ...
127
+ # </project>
128
+ # <project>
129
+ # <amount type="decimal">57230.0</amount>
130
+ # <customer-id type="integer">1567</customer-id>
131
+ # <deal-date type="date">2008-04-15</deal-date>
132
+ # ...
133
+ # </project>
134
+ # </projects>
135
+ #
136
+ # Otherwise the root element is "objects":
137
+ #
138
+ # [{ foo: 1, bar: 2}, { baz: 3}].to_xml
139
+ #
140
+ # <?xml version="1.0" encoding="UTF-8"?>
141
+ # <objects type="array">
142
+ # <object>
143
+ # <bar type="integer">2</bar>
144
+ # <foo type="integer">1</foo>
145
+ # </object>
146
+ # <object>
147
+ # <baz type="integer">3</baz>
148
+ # </object>
149
+ # </objects>
150
+ #
151
+ # If the collection is empty the root element is "nil-classes" by default:
152
+ #
153
+ # [].to_xml
154
+ #
155
+ # <?xml version="1.0" encoding="UTF-8"?>
156
+ # <nil-classes type="array"/>
157
+ #
158
+ # To ensure a meaningful root element use the <tt>:root</tt> option:
159
+ #
160
+ # customer_with_no_projects.projects.to_xml(root: 'projects')
161
+ #
162
+ # <?xml version="1.0" encoding="UTF-8"?>
163
+ # <projects type="array"/>
164
+ #
165
+ # By default name of the node for the children of root is <tt>root.singularize</tt>.
166
+ # You can change it with the <tt>:children</tt> option.
167
+ #
168
+ # The +options+ hash is passed downwards:
169
+ #
170
+ # Message.all.to_xml(skip_types: true)
171
+ #
172
+ # <?xml version="1.0" encoding="UTF-8"?>
173
+ # <messages>
174
+ # <message>
175
+ # <created-at>2008-03-07T09:58:18+01:00</created-at>
176
+ # <id>1</id>
177
+ # <name>1</name>
178
+ # <updated-at>2008-03-07T09:58:18+01:00</updated-at>
179
+ # <user-id>1</user-id>
180
+ # </message>
181
+ # </messages>
182
+ #
183
+ def to_xml(options = {})
184
+ require "active_support/builder" unless defined?(Builder)
185
+
186
+ options = options.dup
187
+ options[:indent] ||= 2
188
+ options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent])
189
+ options[:root] ||= \
190
+ if first.class != Hash && all? { |e| e.is_a?(first.class) }
191
+ underscored = ActiveSupport::Inflector.underscore(first.class.name)
192
+ ActiveSupport::Inflector.pluralize(underscored).tr("/", "_")
193
+ else
194
+ "objects"
195
+ end
196
+
197
+ builder = options[:builder]
198
+ builder.instruct! unless options.delete(:skip_instruct)
199
+
200
+ root = ActiveSupport::XmlMini.rename_key(options[:root].to_s, options)
201
+ children = options.delete(:children) || root.singularize
202
+ attributes = options[:skip_types] ? {} : { type: "array" }
203
+
204
+ if empty?
205
+ builder.tag!(root, attributes)
206
+ else
207
+ builder.tag!(root, attributes) do
208
+ each { |value| ActiveSupport::XmlMini.to_tag(children, value, options) }
209
+ yield builder if block_given?
210
+ end
211
+ end
212
+ end
213
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Array
4
+ # Removes and returns the elements for which the block returns a true value.
5
+ # If no block is given, an Enumerator is returned instead.
6
+ #
7
+ # numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
8
+ # odd_numbers = numbers.extract! { |number| number.odd? } # => [1, 3, 5, 7, 9]
9
+ # numbers # => [0, 2, 4, 6, 8]
10
+ def extract!
11
+ return to_enum(:extract!) { size } unless block_given?
12
+
13
+ extracted_elements = []
14
+
15
+ reject! do |element|
16
+ extracted_elements << element if yield(element)
17
+ end
18
+
19
+ extracted_elements
20
+ end
21
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hash
4
+ # By default, only instances of Hash itself are extractable.
5
+ # Subclasses of Hash may implement this method and return
6
+ # true to declare themselves as extractable. If a Hash
7
+ # is extractable, Array#extract_options! pops it from
8
+ # the Array when it is the last element of the Array.
9
+ def extractable_options?
10
+ instance_of?(Hash)
11
+ end
12
+ end
13
+
14
+ class Array
15
+ # Extracts options from a set of arguments. Removes and returns the last
16
+ # element in the array if it's a hash, otherwise returns a blank hash.
17
+ #
18
+ # def options(*args)
19
+ # args.extract_options!
20
+ # end
21
+ #
22
+ # options(1, 2) # => {}
23
+ # options(1, 2, a: :b) # => {:a=>:b}
24
+ def extract_options!
25
+ if last.is_a?(Hash) && last.extractable_options?
26
+ pop
27
+ else
28
+ {}
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Array
4
+ # Splits or iterates over the array in groups of size +number+,
5
+ # padding any remaining slots with +fill_with+ unless it is +false+.
6
+ #
7
+ # %w(1 2 3 4 5 6 7 8 9 10).in_groups_of(3) {|group| p group}
8
+ # ["1", "2", "3"]
9
+ # ["4", "5", "6"]
10
+ # ["7", "8", "9"]
11
+ # ["10", nil, nil]
12
+ #
13
+ # %w(1 2 3 4 5).in_groups_of(2, '&nbsp;') {|group| p group}
14
+ # ["1", "2"]
15
+ # ["3", "4"]
16
+ # ["5", "&nbsp;"]
17
+ #
18
+ # %w(1 2 3 4 5).in_groups_of(2, false) {|group| p group}
19
+ # ["1", "2"]
20
+ # ["3", "4"]
21
+ # ["5"]
22
+ def in_groups_of(number, fill_with = nil)
23
+ if number.to_i <= 0
24
+ raise ArgumentError,
25
+ "Group size must be a positive integer, was #{number.inspect}"
26
+ end
27
+
28
+ if fill_with == false
29
+ collection = self
30
+ else
31
+ # size % number gives how many extra we have;
32
+ # subtracting from number gives how many to add;
33
+ # modulo number ensures we don't add group of just fill.
34
+ padding = (number - size % number) % number
35
+ collection = dup.concat(Array.new(padding, fill_with))
36
+ end
37
+
38
+ if block_given?
39
+ collection.each_slice(number) { |slice| yield(slice) }
40
+ else
41
+ collection.each_slice(number).to_a
42
+ end
43
+ end
44
+
45
+ # Splits or iterates over the array in +number+ of groups, padding any
46
+ # remaining slots with +fill_with+ unless it is +false+.
47
+ #
48
+ # %w(1 2 3 4 5 6 7 8 9 10).in_groups(3) {|group| p group}
49
+ # ["1", "2", "3", "4"]
50
+ # ["5", "6", "7", nil]
51
+ # ["8", "9", "10", nil]
52
+ #
53
+ # %w(1 2 3 4 5 6 7 8 9 10).in_groups(3, '&nbsp;') {|group| p group}
54
+ # ["1", "2", "3", "4"]
55
+ # ["5", "6", "7", "&nbsp;"]
56
+ # ["8", "9", "10", "&nbsp;"]
57
+ #
58
+ # %w(1 2 3 4 5 6 7).in_groups(3, false) {|group| p group}
59
+ # ["1", "2", "3"]
60
+ # ["4", "5"]
61
+ # ["6", "7"]
62
+ def in_groups(number, fill_with = nil)
63
+ # size.div number gives minor group size;
64
+ # size % number gives how many objects need extra accommodation;
65
+ # each group hold either division or division + 1 items.
66
+ division = size.div number
67
+ modulo = size % number
68
+
69
+ # create a new array avoiding dup
70
+ groups = []
71
+ start = 0
72
+
73
+ number.times do |index|
74
+ length = division + (modulo > 0 && modulo > index ? 1 : 0)
75
+ groups << last_group = slice(start, length)
76
+ last_group << fill_with if fill_with != false &&
77
+ modulo > 0 && length == division
78
+ start += length
79
+ end
80
+
81
+ if block_given?
82
+ groups.each { |g| yield(g) }
83
+ else
84
+ groups
85
+ end
86
+ end
87
+
88
+ # Divides the array into one or more subarrays based on a delimiting +value+
89
+ # or the result of an optional block.
90
+ #
91
+ # [1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]]
92
+ # (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]]
93
+ def split(value = nil)
94
+ arr = dup
95
+ result = []
96
+ if block_given?
97
+ while (idx = arr.index { |i| yield i })
98
+ result << arr.shift(idx)
99
+ arr.shift
100
+ end
101
+ else
102
+ while (idx = arr.index(value))
103
+ result << arr.shift(idx)
104
+ arr.shift
105
+ end
106
+ end
107
+ result << arr
108
+ end
109
+ end