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,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/object/acts_like"
4
+ require "active_support/core_ext/object/blank"
5
+ require "active_support/core_ext/object/duplicable"
6
+ require "active_support/core_ext/object/deep_dup"
7
+ require "active_support/core_ext/object/try"
8
+ require "active_support/core_ext/object/inclusion"
9
+
10
+ require "active_support/core_ext/object/conversions"
11
+ require "active_support/core_ext/object/instance_variables"
12
+
13
+ require "active_support/core_ext/object/json"
14
+ require "active_support/core_ext/object/to_param"
15
+ require "active_support/core_ext/object/to_query"
16
+ require "active_support/core_ext/object/with_options"
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Object
4
+ # A duck-type assistant method. For example, Active Support extends Date
5
+ # to define an <tt>acts_like_date?</tt> method, and extends Time to define
6
+ # <tt>acts_like_time?</tt>. As a result, we can do <tt>x.acts_like?(:time)</tt> and
7
+ # <tt>x.acts_like?(:date)</tt> to do duck-type-safe comparisons, since classes that
8
+ # we want to act like Time simply need to define an <tt>acts_like_time?</tt> method.
9
+ def acts_like?(duck)
10
+ case duck
11
+ when :time
12
+ respond_to? :acts_like_time?
13
+ when :date
14
+ respond_to? :acts_like_date?
15
+ when :string
16
+ respond_to? :acts_like_string?
17
+ else
18
+ respond_to? :"acts_like_#{duck}?"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,155 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "concurrent/map"
4
+
5
+ class Object
6
+ # An object is blank if it's false, empty, or a whitespace string.
7
+ # For example, +nil+, '', ' ', [], {}, and +false+ are all blank.
8
+ #
9
+ # This simplifies
10
+ #
11
+ # !address || address.empty?
12
+ #
13
+ # to
14
+ #
15
+ # address.blank?
16
+ #
17
+ # @return [true, false]
18
+ def blank?
19
+ respond_to?(:empty?) ? !!empty? : !self
20
+ end
21
+
22
+ # An object is present if it's not blank.
23
+ #
24
+ # @return [true, false]
25
+ def present?
26
+ !blank?
27
+ end
28
+
29
+ # Returns the receiver if it's present otherwise returns +nil+.
30
+ # <tt>object.presence</tt> is equivalent to
31
+ #
32
+ # object.present? ? object : nil
33
+ #
34
+ # For example, something like
35
+ #
36
+ # state = params[:state] if params[:state].present?
37
+ # country = params[:country] if params[:country].present?
38
+ # region = state || country || 'US'
39
+ #
40
+ # becomes
41
+ #
42
+ # region = params[:state].presence || params[:country].presence || 'US'
43
+ #
44
+ # @return [Object]
45
+ def presence
46
+ self if present?
47
+ end
48
+ end
49
+
50
+ class NilClass
51
+ # +nil+ is blank:
52
+ #
53
+ # nil.blank? # => true
54
+ #
55
+ # @return [true]
56
+ def blank?
57
+ true
58
+ end
59
+ end
60
+
61
+ class FalseClass
62
+ # +false+ is blank:
63
+ #
64
+ # false.blank? # => true
65
+ #
66
+ # @return [true]
67
+ def blank?
68
+ true
69
+ end
70
+ end
71
+
72
+ class TrueClass
73
+ # +true+ is not blank:
74
+ #
75
+ # true.blank? # => false
76
+ #
77
+ # @return [false]
78
+ def blank?
79
+ false
80
+ end
81
+ end
82
+
83
+ class Array
84
+ # An array is blank if it's empty:
85
+ #
86
+ # [].blank? # => true
87
+ # [1,2,3].blank? # => false
88
+ #
89
+ # @return [true, false]
90
+ alias_method :blank?, :empty?
91
+ end
92
+
93
+ class Hash
94
+ # A hash is blank if it's empty:
95
+ #
96
+ # {}.blank? # => true
97
+ # { key: 'value' }.blank? # => false
98
+ #
99
+ # @return [true, false]
100
+ alias_method :blank?, :empty?
101
+ end
102
+
103
+ class String
104
+ BLANK_RE = /\A[[:space:]]*\z/
105
+ ENCODED_BLANKS = Concurrent::Map.new do |h, enc|
106
+ h[enc] = Regexp.new(BLANK_RE.source.encode(enc), BLANK_RE.options | Regexp::FIXEDENCODING)
107
+ end
108
+
109
+ # A string is blank if it's empty or contains whitespaces only:
110
+ #
111
+ # ''.blank? # => true
112
+ # ' '.blank? # => true
113
+ # "\t\n\r".blank? # => true
114
+ # ' blah '.blank? # => false
115
+ #
116
+ # Unicode whitespace is supported:
117
+ #
118
+ # "\u00a0".blank? # => true
119
+ #
120
+ # @return [true, false]
121
+ def blank?
122
+ # The regexp that matches blank strings is expensive. For the case of empty
123
+ # strings we can speed up this method (~3.5x) with an empty? call. The
124
+ # penalty for the rest of strings is marginal.
125
+ empty? ||
126
+ begin
127
+ BLANK_RE.match?(self)
128
+ rescue Encoding::CompatibilityError
129
+ ENCODED_BLANKS[self.encoding].match?(self)
130
+ end
131
+ end
132
+ end
133
+
134
+ class Numeric #:nodoc:
135
+ # No number is blank:
136
+ #
137
+ # 1.blank? # => false
138
+ # 0.blank? # => false
139
+ #
140
+ # @return [false]
141
+ def blank?
142
+ false
143
+ end
144
+ end
145
+
146
+ class Time #:nodoc:
147
+ # No Time is blank:
148
+ #
149
+ # Time.now.blank? # => false
150
+ #
151
+ # @return [false]
152
+ def blank?
153
+ false
154
+ end
155
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/object/to_param"
4
+ require "active_support/core_ext/object/to_query"
5
+ require "active_support/core_ext/array/conversions"
6
+ require "active_support/core_ext/hash/conversions"
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/object/duplicable"
4
+
5
+ class Object
6
+ # Returns a deep copy of object if it's duplicable. If it's
7
+ # not duplicable, returns +self+.
8
+ #
9
+ # object = Object.new
10
+ # dup = object.deep_dup
11
+ # dup.instance_variable_set(:@a, 1)
12
+ #
13
+ # object.instance_variable_defined?(:@a) # => false
14
+ # dup.instance_variable_defined?(:@a) # => true
15
+ def deep_dup
16
+ duplicable? ? dup : self
17
+ end
18
+ end
19
+
20
+ class Array
21
+ # Returns a deep copy of array.
22
+ #
23
+ # array = [1, [2, 3]]
24
+ # dup = array.deep_dup
25
+ # dup[1][2] = 4
26
+ #
27
+ # array[1][2] # => nil
28
+ # dup[1][2] # => 4
29
+ def deep_dup
30
+ map(&:deep_dup)
31
+ end
32
+ end
33
+
34
+ class Hash
35
+ # Returns a deep copy of hash.
36
+ #
37
+ # hash = { a: { b: 'b' } }
38
+ # dup = hash.deep_dup
39
+ # dup[:a][:c] = 'c'
40
+ #
41
+ # hash[:a][:c] # => nil
42
+ # dup[:a][:c] # => "c"
43
+ def deep_dup
44
+ hash = dup
45
+ each_pair do |key, value|
46
+ if key.frozen? && ::String === key
47
+ hash[key] = value.deep_dup
48
+ else
49
+ hash.delete(key)
50
+ hash[key.deep_dup] = value.deep_dup
51
+ end
52
+ end
53
+ hash
54
+ end
55
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # Most objects are cloneable, but not all. For example you can't dup methods:
5
+ #
6
+ # method(:puts).dup # => TypeError: allocator undefined for Method
7
+ #
8
+ # Classes may signal their instances are not duplicable removing +dup+/+clone+
9
+ # or raising exceptions from them. So, to dup an arbitrary object you normally
10
+ # use an optimistic approach and are ready to catch an exception, say:
11
+ #
12
+ # arbitrary_object.dup rescue object
13
+ #
14
+ # Rails dups objects in a few critical spots where they are not that arbitrary.
15
+ # That rescue is very expensive (like 40 times slower than a predicate), and it
16
+ # is often triggered.
17
+ #
18
+ # That's why we hardcode the following cases and check duplicable? instead of
19
+ # using that rescue idiom.
20
+ #++
21
+ class Object
22
+ # Can you safely dup this object?
23
+ #
24
+ # False for method objects;
25
+ # true otherwise.
26
+ def duplicable?
27
+ true
28
+ end
29
+ end
30
+
31
+ class Method
32
+ # Methods are not duplicable:
33
+ #
34
+ # method(:puts).duplicable? # => false
35
+ # method(:puts).dup # => TypeError: allocator undefined for Method
36
+ def duplicable?
37
+ false
38
+ end
39
+ end
40
+
41
+ class UnboundMethod
42
+ # Unbound methods are not duplicable:
43
+ #
44
+ # method(:puts).unbind.duplicable? # => false
45
+ # method(:puts).unbind.dup # => TypeError: allocator undefined for UnboundMethod
46
+ def duplicable?
47
+ false
48
+ end
49
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Object
4
+ # Returns true if this object is included in the argument. Argument must be
5
+ # any object which responds to +#include?+. Usage:
6
+ #
7
+ # characters = ["Konata", "Kagami", "Tsukasa"]
8
+ # "Konata".in?(characters) # => true
9
+ #
10
+ # This will throw an +ArgumentError+ if the argument doesn't respond
11
+ # to +#include?+.
12
+ def in?(another_object)
13
+ another_object.include?(self)
14
+ rescue NoMethodError
15
+ raise ArgumentError.new("The parameter passed to #in? must respond to #include?")
16
+ end
17
+
18
+ # Returns the receiver if it's included in the argument otherwise returns +nil+.
19
+ # Argument must be any object which responds to +#include?+. Usage:
20
+ #
21
+ # params[:bucket_type].presence_in %w( project calendar )
22
+ #
23
+ # This will throw an +ArgumentError+ if the argument doesn't respond to +#include?+.
24
+ #
25
+ # @return [Object]
26
+ def presence_in(another_object)
27
+ in?(another_object) ? self : nil
28
+ end
29
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Object
4
+ # Returns a hash with string keys that maps instance variable names without "@" to their
5
+ # corresponding values.
6
+ #
7
+ # class C
8
+ # def initialize(x, y)
9
+ # @x, @y = x, y
10
+ # end
11
+ # end
12
+ #
13
+ # C.new(0, 1).instance_values # => {"x" => 0, "y" => 1}
14
+ def instance_values
15
+ Hash[instance_variables.map { |name| [name[1..-1], instance_variable_get(name)] }]
16
+ end
17
+
18
+ # Returns an array of instance variable names as strings including "@".
19
+ #
20
+ # class C
21
+ # def initialize(x, y)
22
+ # @x, @y = x, y
23
+ # end
24
+ # end
25
+ #
26
+ # C.new(0, 1).instance_variable_names # => ["@y", "@x"]
27
+ def instance_variable_names
28
+ instance_variables.map(&:to_s)
29
+ end
30
+ end
@@ -0,0 +1,228 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Hack to load json gem first so we can overwrite its to_json.
4
+ require "json"
5
+ require "bigdecimal"
6
+ require "uri/generic"
7
+ require "pathname"
8
+ require "active_support/core_ext/big_decimal/conversions" # for #to_s
9
+ require "active_support/core_ext/hash/except"
10
+ require "active_support/core_ext/hash/slice"
11
+ require "active_support/core_ext/object/instance_variables"
12
+ require "time"
13
+ require "active_support/core_ext/time/conversions"
14
+ require "active_support/core_ext/date_time/conversions"
15
+ require "active_support/core_ext/date/conversions"
16
+
17
+ #--
18
+ # The JSON gem adds a few modules to Ruby core classes containing :to_json definition, overwriting
19
+ # their default behavior. That said, we need to define the basic to_json method in all of them,
20
+ # otherwise they will always use to_json gem implementation, which is backwards incompatible in
21
+ # several cases (for instance, the JSON implementation for Hash does not work) with inheritance
22
+ # and consequently classes as ActiveSupport::OrderedHash cannot be serialized to json.
23
+ #
24
+ # On the other hand, we should avoid conflict with ::JSON.{generate,dump}(obj). Unfortunately, the
25
+ # JSON gem's encoder relies on its own to_json implementation to encode objects. Since it always
26
+ # passes a ::JSON::State object as the only argument to to_json, we can detect that and forward the
27
+ # calls to the original to_json method.
28
+ #
29
+ # It should be noted that when using ::JSON.{generate,dump} directly, ActiveSupport's encoder is
30
+ # bypassed completely. This means that as_json won't be invoked and the JSON gem will simply
31
+ # ignore any options it does not natively understand. This also means that ::JSON.{generate,dump}
32
+ # should give exactly the same results with or without active support.
33
+
34
+ module ActiveSupport
35
+ module ToJsonWithActiveSupportEncoder # :nodoc:
36
+ def to_json(options = nil)
37
+ if options.is_a?(::JSON::State)
38
+ # Called from JSON.{generate,dump}, forward it to JSON gem's to_json
39
+ super(options)
40
+ else
41
+ # to_json is being invoked directly, use ActiveSupport's encoder
42
+ ActiveSupport::JSON.encode(self, options)
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ [Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass, Enumerable].reverse_each do |klass|
49
+ klass.prepend(ActiveSupport::ToJsonWithActiveSupportEncoder)
50
+ end
51
+
52
+ class Object
53
+ def as_json(options = nil) #:nodoc:
54
+ if respond_to?(:to_hash)
55
+ to_hash.as_json(options)
56
+ else
57
+ instance_values.as_json(options)
58
+ end
59
+ end
60
+ end
61
+
62
+ class Struct #:nodoc:
63
+ def as_json(options = nil)
64
+ Hash[members.zip(values)].as_json(options)
65
+ end
66
+ end
67
+
68
+ class TrueClass
69
+ def as_json(options = nil) #:nodoc:
70
+ self
71
+ end
72
+ end
73
+
74
+ class FalseClass
75
+ def as_json(options = nil) #:nodoc:
76
+ self
77
+ end
78
+ end
79
+
80
+ class NilClass
81
+ def as_json(options = nil) #:nodoc:
82
+ self
83
+ end
84
+ end
85
+
86
+ class String
87
+ def as_json(options = nil) #:nodoc:
88
+ self
89
+ end
90
+ end
91
+
92
+ class Symbol
93
+ def as_json(options = nil) #:nodoc:
94
+ to_s
95
+ end
96
+ end
97
+
98
+ class Numeric
99
+ def as_json(options = nil) #:nodoc:
100
+ self
101
+ end
102
+ end
103
+
104
+ class Float
105
+ # Encoding Infinity or NaN to JSON should return "null". The default returns
106
+ # "Infinity" or "NaN" which are not valid JSON.
107
+ def as_json(options = nil) #:nodoc:
108
+ finite? ? self : nil
109
+ end
110
+ end
111
+
112
+ class BigDecimal
113
+ # A BigDecimal would be naturally represented as a JSON number. Most libraries,
114
+ # however, parse non-integer JSON numbers directly as floats. Clients using
115
+ # those libraries would get in general a wrong number and no way to recover
116
+ # other than manually inspecting the string with the JSON code itself.
117
+ #
118
+ # That's why a JSON string is returned. The JSON literal is not numeric, but
119
+ # if the other end knows by contract that the data is supposed to be a
120
+ # BigDecimal, it still has the chance to post-process the string and get the
121
+ # real value.
122
+ def as_json(options = nil) #:nodoc:
123
+ finite? ? to_s : nil
124
+ end
125
+ end
126
+
127
+ class Regexp
128
+ def as_json(options = nil) #:nodoc:
129
+ to_s
130
+ end
131
+ end
132
+
133
+ module Enumerable
134
+ def as_json(options = nil) #:nodoc:
135
+ to_a.as_json(options)
136
+ end
137
+ end
138
+
139
+ class IO
140
+ def as_json(options = nil) #:nodoc:
141
+ to_s
142
+ end
143
+ end
144
+
145
+ class Range
146
+ def as_json(options = nil) #:nodoc:
147
+ to_s
148
+ end
149
+ end
150
+
151
+ class Array
152
+ def as_json(options = nil) #:nodoc:
153
+ map { |v| options ? v.as_json(options.dup) : v.as_json }
154
+ end
155
+ end
156
+
157
+ class Hash
158
+ def as_json(options = nil) #:nodoc:
159
+ # create a subset of the hash by applying :only or :except
160
+ subset = if options
161
+ if attrs = options[:only]
162
+ slice(*Array(attrs))
163
+ elsif attrs = options[:except]
164
+ except(*Array(attrs))
165
+ else
166
+ self
167
+ end
168
+ else
169
+ self
170
+ end
171
+
172
+ Hash[subset.map { |k, v| [k.to_s, options ? v.as_json(options.dup) : v.as_json] }]
173
+ end
174
+ end
175
+
176
+ class Time
177
+ def as_json(options = nil) #:nodoc:
178
+ if ActiveSupport::JSON::Encoding.use_standard_json_time_format
179
+ xmlschema(ActiveSupport::JSON::Encoding.time_precision)
180
+ else
181
+ %(#{strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)})
182
+ end
183
+ end
184
+ end
185
+
186
+ class Date
187
+ def as_json(options = nil) #:nodoc:
188
+ if ActiveSupport::JSON::Encoding.use_standard_json_time_format
189
+ strftime("%Y-%m-%d")
190
+ else
191
+ strftime("%Y/%m/%d")
192
+ end
193
+ end
194
+ end
195
+
196
+ class DateTime
197
+ def as_json(options = nil) #:nodoc:
198
+ if ActiveSupport::JSON::Encoding.use_standard_json_time_format
199
+ xmlschema(ActiveSupport::JSON::Encoding.time_precision)
200
+ else
201
+ strftime("%Y/%m/%d %H:%M:%S %z")
202
+ end
203
+ end
204
+ end
205
+
206
+ class URI::Generic #:nodoc:
207
+ def as_json(options = nil)
208
+ to_s
209
+ end
210
+ end
211
+
212
+ class Pathname #:nodoc:
213
+ def as_json(options = nil)
214
+ to_s
215
+ end
216
+ end
217
+
218
+ class Process::Status #:nodoc:
219
+ def as_json(options = nil)
220
+ { exitstatus: exitstatus, pid: pid }
221
+ end
222
+ end
223
+
224
+ class Exception
225
+ def as_json(options = nil)
226
+ to_s
227
+ end
228
+ end