activesupport 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/object/to_query"
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cgi"
4
+
5
+ class Object
6
+ # Alias of <tt>to_s</tt>.
7
+ def to_param
8
+ to_s
9
+ end
10
+
11
+ # Converts an object into a string suitable for use as a URL query string,
12
+ # using the given <tt>key</tt> as the param name.
13
+ def to_query(key)
14
+ "#{CGI.escape(key.to_param)}=#{CGI.escape(to_param.to_s)}"
15
+ end
16
+ end
17
+
18
+ class NilClass
19
+ # Returns +self+.
20
+ def to_param
21
+ self
22
+ end
23
+ end
24
+
25
+ class TrueClass
26
+ # Returns +self+.
27
+ def to_param
28
+ self
29
+ end
30
+ end
31
+
32
+ class FalseClass
33
+ # Returns +self+.
34
+ def to_param
35
+ self
36
+ end
37
+ end
38
+
39
+ class Array
40
+ # Calls <tt>to_param</tt> on all its elements and joins the result with
41
+ # slashes. This is used by <tt>url_for</tt> in Action Pack.
42
+ def to_param
43
+ collect(&:to_param).join "/"
44
+ end
45
+
46
+ # Converts an array into a string suitable for use as a URL query string,
47
+ # using the given +key+ as the param name.
48
+ #
49
+ # ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"
50
+ def to_query(key)
51
+ prefix = "#{key}[]"
52
+
53
+ if empty?
54
+ nil.to_query(prefix)
55
+ else
56
+ collect { |value| value.to_query(prefix) }.join "&"
57
+ end
58
+ end
59
+ end
60
+
61
+ class Hash
62
+ # Returns a string representation of the receiver suitable for use as a URL
63
+ # query string:
64
+ #
65
+ # {name: 'David', nationality: 'Danish'}.to_query
66
+ # # => "name=David&nationality=Danish"
67
+ #
68
+ # An optional namespace can be passed to enclose key names:
69
+ #
70
+ # {name: 'David', nationality: 'Danish'}.to_query('user')
71
+ # # => "user%5Bname%5D=David&user%5Bnationality%5D=Danish"
72
+ #
73
+ # The string pairs "key=value" that conform the query string
74
+ # are sorted lexicographically in ascending order.
75
+ #
76
+ # This method is also aliased as +to_param+.
77
+ def to_query(namespace = nil)
78
+ query = collect do |key, value|
79
+ unless (value.is_a?(Hash) || value.is_a?(Array)) && value.empty?
80
+ value.to_query(namespace ? "#{namespace}[#{key}]" : key)
81
+ end
82
+ end.compact
83
+
84
+ query.sort! unless namespace.to_s.include?("[]")
85
+ query.join("&")
86
+ end
87
+
88
+ alias_method :to_param, :to_query
89
+ end
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "delegate"
4
+
5
+ module ActiveSupport
6
+ module Tryable #:nodoc:
7
+ def try(method_name = nil, *args, &b)
8
+ if method_name.nil? && block_given?
9
+ if b.arity == 0
10
+ instance_eval(&b)
11
+ else
12
+ yield self
13
+ end
14
+ elsif respond_to?(method_name)
15
+ public_send(method_name, *args, &b)
16
+ end
17
+ end
18
+
19
+ def try!(method_name = nil, *args, &b)
20
+ if method_name.nil? && block_given?
21
+ if b.arity == 0
22
+ instance_eval(&b)
23
+ else
24
+ yield self
25
+ end
26
+ else
27
+ public_send(method_name, *args, &b)
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ class Object
34
+ include ActiveSupport::Tryable
35
+
36
+ ##
37
+ # :method: try
38
+ #
39
+ # :call-seq:
40
+ # try(*a, &b)
41
+ #
42
+ # Invokes the public method whose name goes as first argument just like
43
+ # +public_send+ does, except that if the receiver does not respond to it the
44
+ # call returns +nil+ rather than raising an exception.
45
+ #
46
+ # This method is defined to be able to write
47
+ #
48
+ # @person.try(:name)
49
+ #
50
+ # instead of
51
+ #
52
+ # @person.name if @person
53
+ #
54
+ # +try+ calls can be chained:
55
+ #
56
+ # @person.try(:spouse).try(:name)
57
+ #
58
+ # instead of
59
+ #
60
+ # @person.spouse.name if @person && @person.spouse
61
+ #
62
+ # +try+ will also return +nil+ if the receiver does not respond to the method:
63
+ #
64
+ # @person.try(:non_existing_method) # => nil
65
+ #
66
+ # instead of
67
+ #
68
+ # @person.non_existing_method if @person.respond_to?(:non_existing_method) # => nil
69
+ #
70
+ # +try+ returns +nil+ when called on +nil+ regardless of whether it responds
71
+ # to the method:
72
+ #
73
+ # nil.try(:to_i) # => nil, rather than 0
74
+ #
75
+ # Arguments and blocks are forwarded to the method if invoked:
76
+ #
77
+ # @posts.try(:each_slice, 2) do |a, b|
78
+ # ...
79
+ # end
80
+ #
81
+ # The number of arguments in the signature must match. If the object responds
82
+ # to the method the call is attempted and +ArgumentError+ is still raised
83
+ # in case of argument mismatch.
84
+ #
85
+ # If +try+ is called without arguments it yields the receiver to a given
86
+ # block unless it is +nil+:
87
+ #
88
+ # @person.try do |p|
89
+ # ...
90
+ # end
91
+ #
92
+ # You can also call try with a block without accepting an argument, and the block
93
+ # will be instance_eval'ed instead:
94
+ #
95
+ # @person.try { upcase.truncate(50) }
96
+ #
97
+ # Please also note that +try+ is defined on +Object+. Therefore, it won't work
98
+ # with instances of classes that do not have +Object+ among their ancestors,
99
+ # like direct subclasses of +BasicObject+.
100
+
101
+ ##
102
+ # :method: try!
103
+ #
104
+ # :call-seq:
105
+ # try!(*a, &b)
106
+ #
107
+ # Same as #try, but raises a +NoMethodError+ exception if the receiver is
108
+ # not +nil+ and does not implement the tried method.
109
+ #
110
+ # "a".try!(:upcase) # => "A"
111
+ # nil.try!(:upcase) # => nil
112
+ # 123.try!(:upcase) # => NoMethodError: undefined method `upcase' for 123:Integer
113
+ end
114
+
115
+ class Delegator
116
+ include ActiveSupport::Tryable
117
+
118
+ ##
119
+ # :method: try
120
+ #
121
+ # :call-seq:
122
+ # try(a*, &b)
123
+ #
124
+ # See Object#try
125
+
126
+ ##
127
+ # :method: try!
128
+ #
129
+ # :call-seq:
130
+ # try!(a*, &b)
131
+ #
132
+ # See Object#try!
133
+ end
134
+
135
+ class NilClass
136
+ # Calling +try+ on +nil+ always returns +nil+.
137
+ # It becomes especially helpful when navigating through associations that may return +nil+.
138
+ #
139
+ # nil.try(:name) # => nil
140
+ #
141
+ # Without +try+
142
+ # @person && @person.children.any? && @person.children.first.name
143
+ #
144
+ # With +try+
145
+ # @person.try(:children).try(:first).try(:name)
146
+ def try(method_name = nil, *args)
147
+ nil
148
+ end
149
+
150
+ # Calling +try!+ on +nil+ always returns +nil+.
151
+ #
152
+ # nil.try!(:name) # => nil
153
+ def try!(method_name = nil, *args)
154
+ nil
155
+ end
156
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/option_merger"
4
+
5
+ class Object
6
+ # An elegant way to factor duplication out of options passed to a series of
7
+ # method calls. Each method called in the block, with the block variable as
8
+ # the receiver, will have its options merged with the default +options+ hash
9
+ # provided. Each method called on the block variable must take an options
10
+ # hash as its final argument.
11
+ #
12
+ # Without <tt>with_options</tt>, this code contains duplication:
13
+ #
14
+ # class Account < ActiveRecord::Base
15
+ # has_many :customers, dependent: :destroy
16
+ # has_many :products, dependent: :destroy
17
+ # has_many :invoices, dependent: :destroy
18
+ # has_many :expenses, dependent: :destroy
19
+ # end
20
+ #
21
+ # Using <tt>with_options</tt>, we can remove the duplication:
22
+ #
23
+ # class Account < ActiveRecord::Base
24
+ # with_options dependent: :destroy do |assoc|
25
+ # assoc.has_many :customers
26
+ # assoc.has_many :products
27
+ # assoc.has_many :invoices
28
+ # assoc.has_many :expenses
29
+ # end
30
+ # end
31
+ #
32
+ # It can also be used with an explicit receiver:
33
+ #
34
+ # I18n.with_options locale: user.locale, scope: 'newsletter' do |i18n|
35
+ # subject i18n.t :subject
36
+ # body i18n.t :body, user_name: user.name
37
+ # end
38
+ #
39
+ # When you don't pass an explicit receiver, it executes the whole block
40
+ # in merging options context:
41
+ #
42
+ # class Account < ActiveRecord::Base
43
+ # with_options dependent: :destroy do
44
+ # has_many :customers
45
+ # has_many :products
46
+ # has_many :invoices
47
+ # has_many :expenses
48
+ # end
49
+ # end
50
+ #
51
+ # <tt>with_options</tt> can also be nested since the call is forwarded to its receiver.
52
+ #
53
+ # NOTE: Each nesting level will merge inherited defaults in addition to their own.
54
+ #
55
+ # class Post < ActiveRecord::Base
56
+ # with_options if: :persisted?, length: { minimum: 50 } do
57
+ # validates :content, if: -> { content.present? }
58
+ # end
59
+ # end
60
+ #
61
+ # The code is equivalent to:
62
+ #
63
+ # validates :content, length: { minimum: 50 }, if: -> { content.present? }
64
+ #
65
+ # Hence the inherited default for +if+ key is ignored.
66
+ #
67
+ # NOTE: You cannot call class methods implicitly inside of with_options.
68
+ # You can access these methods using the class name instead:
69
+ #
70
+ # class Phone < ActiveRecord::Base
71
+ # enum phone_number_type: { home: 0, office: 1, mobile: 2 }
72
+ #
73
+ # with_options presence: true do
74
+ # validates :phone_number_type, inclusion: { in: Phone.phone_number_types.keys }
75
+ # end
76
+ # end
77
+ #
78
+ def with_options(options, &block)
79
+ option_merger = ActiveSupport::OptionMerger.new(self, options)
80
+ block.arity.zero? ? option_merger.instance_eval(&block) : block.call(option_merger)
81
+ end
82
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/range/conversions"
4
+ require "active_support/core_ext/range/compare_range"
5
+ require "active_support/core_ext/range/include_time_with_zone"
6
+ require "active_support/core_ext/range/overlaps"
7
+ require "active_support/core_ext/range/each"
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module CompareWithRange
5
+ # Extends the default Range#=== to support range comparisons.
6
+ # (1..5) === (1..5) # => true
7
+ # (1..5) === (2..3) # => true
8
+ # (1..5) === (1...6) # => true
9
+ # (1..5) === (2..6) # => false
10
+ #
11
+ # The native Range#=== behavior is untouched.
12
+ # ('a'..'f') === ('c') # => true
13
+ # (5..9) === (11) # => false
14
+ def ===(value)
15
+ if value.is_a?(::Range)
16
+ # 1...10 includes 1..9 but it does not include 1..10.
17
+ # 1..10 includes 1...11 but it does not include 1...12.
18
+ operator = exclude_end? && !value.exclude_end? ? :< : :<=
19
+ value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
20
+ super(value.first) && value_max.send(operator, last)
21
+ else
22
+ super
23
+ end
24
+ end
25
+
26
+ # Extends the default Range#include? to support range comparisons.
27
+ # (1..5).include?(1..5) # => true
28
+ # (1..5).include?(2..3) # => true
29
+ # (1..5).include?(1...6) # => true
30
+ # (1..5).include?(2..6) # => false
31
+ #
32
+ # The native Range#include? behavior is untouched.
33
+ # ('a'..'f').include?('c') # => true
34
+ # (5..9).include?(11) # => false
35
+ def include?(value)
36
+ if value.is_a?(::Range)
37
+ # 1...10 includes 1..9 but it does not include 1..10.
38
+ # 1..10 includes 1...11 but it does not include 1...12.
39
+ operator = exclude_end? && !value.exclude_end? ? :< : :<=
40
+ value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
41
+ super(value.first) && value_max.send(operator, last)
42
+ else
43
+ super
44
+ end
45
+ end
46
+
47
+ # Extends the default Range#cover? to support range comparisons.
48
+ # (1..5).cover?(1..5) # => true
49
+ # (1..5).cover?(2..3) # => true
50
+ # (1..5).cover?(1...6) # => true
51
+ # (1..5).cover?(2..6) # => false
52
+ #
53
+ # The native Range#cover? behavior is untouched.
54
+ # ('a'..'f').cover?('c') # => true
55
+ # (5..9).cover?(11) # => false
56
+ def cover?(value)
57
+ if value.is_a?(::Range)
58
+ # 1...10 covers 1..9 but it does not cover 1..10.
59
+ # 1..10 covers 1...11 but it does not cover 1...12.
60
+ operator = exclude_end? && !value.exclude_end? ? :< : :<=
61
+ value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
62
+ super(value.first) && value_max.send(operator, last)
63
+ else
64
+ super
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ Range.prepend(ActiveSupport::CompareWithRange)
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module RangeWithFormat
5
+ RANGE_FORMATS = {
6
+ db: -> (start, stop) do
7
+ case start
8
+ when String then "BETWEEN '#{start}' AND '#{stop}'"
9
+ else
10
+ "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'"
11
+ end
12
+ end
13
+ }
14
+
15
+ # Convert range to a formatted string. See RANGE_FORMATS for predefined formats.
16
+ #
17
+ # range = (1..100) # => 1..100
18
+ #
19
+ # range.to_s # => "1..100"
20
+ # range.to_s(:db) # => "BETWEEN '1' AND '100'"
21
+ #
22
+ # == Adding your own range formats to to_s
23
+ # You can add your own formats to the Range::RANGE_FORMATS hash.
24
+ # Use the format name as the hash key and a Proc instance.
25
+ #
26
+ # # config/initializers/range_formats.rb
27
+ # Range::RANGE_FORMATS[:short] = ->(start, stop) { "Between #{start.to_s(:db)} and #{stop.to_s(:db)}" }
28
+ def to_s(format = :default)
29
+ if formatter = RANGE_FORMATS[format]
30
+ formatter.call(first, last)
31
+ else
32
+ super()
33
+ end
34
+ end
35
+
36
+ alias_method :to_default_s, :to_s
37
+ alias_method :to_formatted_s, :to_s
38
+ end
39
+ end
40
+
41
+ Range.prepend(ActiveSupport::RangeWithFormat)