activesupport 5.1.7 → 6.1.7

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (262) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +434 -490
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -5
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/all.rb +2 -0
  7. data/lib/active_support/array_inquirer.rb +6 -2
  8. data/lib/active_support/backtrace_cleaner.rb +31 -3
  9. data/lib/active_support/benchmarkable.rb +3 -1
  10. data/lib/active_support/builder.rb +2 -0
  11. data/lib/active_support/cache/file_store.rb +37 -36
  12. data/lib/active_support/cache/mem_cache_store.rb +72 -56
  13. data/lib/active_support/cache/memory_store.rb +61 -33
  14. data/lib/active_support/cache/null_store.rb +10 -3
  15. data/lib/active_support/cache/redis_cache_store.rb +493 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +67 -21
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +2 -0
  18. data/lib/active_support/cache.rb +310 -126
  19. data/lib/active_support/callbacks.rb +106 -100
  20. data/lib/active_support/concern.rb +79 -6
  21. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  22. data/lib/active_support/concurrency/share_lock.rb +2 -1
  23. data/lib/active_support/configurable.rb +12 -14
  24. data/lib/active_support/configuration_file.rb +51 -0
  25. data/lib/active_support/core_ext/array/access.rb +21 -7
  26. data/lib/active_support/core_ext/array/conversions.rb +7 -5
  27. data/lib/active_support/core_ext/array/extract.rb +21 -0
  28. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  29. data/lib/active_support/core_ext/array/grouping.rb +2 -0
  30. data/lib/active_support/core_ext/array/inquiry.rb +2 -0
  31. data/lib/active_support/core_ext/array/wrap.rb +2 -0
  32. data/lib/active_support/core_ext/array.rb +3 -1
  33. data/lib/active_support/core_ext/benchmark.rb +4 -2
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +2 -0
  35. data/lib/active_support/core_ext/big_decimal.rb +2 -0
  36. data/lib/active_support/core_ext/class/attribute.rb +50 -47
  37. data/lib/active_support/core_ext/class/attribute_accessors.rb +2 -0
  38. data/lib/active_support/core_ext/class/subclasses.rb +18 -40
  39. data/lib/active_support/core_ext/class.rb +2 -0
  40. data/lib/active_support/core_ext/date/acts_like.rb +2 -0
  41. data/lib/active_support/core_ext/date/blank.rb +2 -0
  42. data/lib/active_support/core_ext/date/calculations.rb +8 -5
  43. data/lib/active_support/core_ext/date/conversions.rb +12 -10
  44. data/lib/active_support/core_ext/date/zones.rb +2 -0
  45. data/lib/active_support/core_ext/date.rb +2 -0
  46. data/lib/active_support/core_ext/date_and_time/calculations.rb +61 -37
  47. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -1
  48. data/lib/active_support/core_ext/date_and_time/zones.rb +2 -1
  49. data/lib/active_support/core_ext/date_time/acts_like.rb +2 -0
  50. data/lib/active_support/core_ext/date_time/blank.rb +2 -0
  51. data/lib/active_support/core_ext/date_time/calculations.rb +3 -1
  52. data/lib/active_support/core_ext/date_time/compatibility.rb +7 -5
  53. data/lib/active_support/core_ext/date_time/conversions.rb +2 -1
  54. data/lib/active_support/core_ext/date_time.rb +2 -0
  55. data/lib/active_support/core_ext/digest/uuid.rb +4 -1
  56. data/lib/active_support/core_ext/digest.rb +3 -0
  57. data/lib/active_support/core_ext/enumerable.rb +174 -71
  58. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  59. data/lib/active_support/core_ext/file.rb +2 -0
  60. data/lib/active_support/core_ext/hash/conversions.rb +7 -5
  61. data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
  62. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  63. data/lib/active_support/core_ext/hash/except.rb +4 -2
  64. data/lib/active_support/core_ext/hash/indifferent_access.rb +2 -0
  65. data/lib/active_support/core_ext/hash/keys.rb +3 -30
  66. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  67. data/lib/active_support/core_ext/hash/slice.rb +8 -29
  68. data/lib/active_support/core_ext/hash.rb +3 -2
  69. data/lib/active_support/core_ext/integer/inflections.rb +2 -0
  70. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  71. data/lib/active_support/core_ext/integer/time.rb +7 -14
  72. data/lib/active_support/core_ext/integer.rb +2 -0
  73. data/lib/active_support/core_ext/kernel/concern.rb +2 -0
  74. data/lib/active_support/core_ext/kernel/reporting.rb +2 -0
  75. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  76. data/lib/active_support/core_ext/kernel.rb +2 -1
  77. data/lib/active_support/core_ext/load_error.rb +3 -8
  78. data/lib/active_support/core_ext/marshal.rb +4 -0
  79. data/lib/active_support/core_ext/module/aliasing.rb +2 -0
  80. data/lib/active_support/core_ext/module/anonymous.rb +2 -0
  81. data/lib/active_support/core_ext/module/attr_internal.rb +4 -2
  82. data/lib/active_support/core_ext/module/attribute_accessors.rb +44 -56
  83. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +18 -18
  84. data/lib/active_support/core_ext/module/concerning.rb +15 -10
  85. data/lib/active_support/core_ext/module/delegation.rb +103 -58
  86. data/lib/active_support/core_ext/module/deprecation.rb +2 -0
  87. data/lib/active_support/core_ext/module/introspection.rb +18 -15
  88. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  89. data/lib/active_support/core_ext/module/remove_method.rb +5 -23
  90. data/lib/active_support/core_ext/module.rb +3 -1
  91. data/lib/active_support/core_ext/name_error.rb +36 -2
  92. data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
  93. data/lib/active_support/core_ext/numeric/conversions.rb +131 -129
  94. data/lib/active_support/core_ext/numeric/time.rb +7 -15
  95. data/lib/active_support/core_ext/numeric.rb +2 -1
  96. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  97. data/lib/active_support/core_ext/object/blank.rb +13 -3
  98. data/lib/active_support/core_ext/object/conversions.rb +2 -0
  99. data/lib/active_support/core_ext/object/deep_dup.rb +3 -1
  100. data/lib/active_support/core_ext/object/duplicable.rb +9 -114
  101. data/lib/active_support/core_ext/object/inclusion.rb +2 -0
  102. data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
  103. data/lib/active_support/core_ext/object/json.rb +22 -2
  104. data/lib/active_support/core_ext/object/to_param.rb +2 -0
  105. data/lib/active_support/core_ext/object/to_query.rb +2 -0
  106. data/lib/active_support/core_ext/object/try.rb +19 -7
  107. data/lib/active_support/core_ext/object/with_options.rb +4 -2
  108. data/lib/active_support/core_ext/object.rb +2 -0
  109. data/lib/active_support/core_ext/range/compare_range.rb +82 -0
  110. data/lib/active_support/core_ext/range/conversions.rb +35 -25
  111. data/lib/active_support/core_ext/range/each.rb +5 -2
  112. data/lib/active_support/core_ext/range/include_time_with_zone.rb +28 -0
  113. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  114. data/lib/active_support/core_ext/range.rb +4 -1
  115. data/lib/active_support/core_ext/regexp.rb +10 -5
  116. data/lib/active_support/core_ext/securerandom.rb +25 -3
  117. data/lib/active_support/core_ext/string/access.rb +7 -16
  118. data/lib/active_support/core_ext/string/behavior.rb +2 -0
  119. data/lib/active_support/core_ext/string/conversions.rb +3 -0
  120. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  121. data/lib/active_support/core_ext/string/filters.rb +44 -1
  122. data/lib/active_support/core_ext/string/indent.rb +2 -0
  123. data/lib/active_support/core_ext/string/inflections.rb +69 -16
  124. data/lib/active_support/core_ext/string/inquiry.rb +3 -0
  125. data/lib/active_support/core_ext/string/multibyte.rb +9 -4
  126. data/lib/active_support/core_ext/string/output_safety.rb +104 -20
  127. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
  128. data/lib/active_support/core_ext/string/strip.rb +5 -1
  129. data/lib/active_support/core_ext/string/zones.rb +2 -0
  130. data/lib/active_support/core_ext/string.rb +2 -0
  131. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  132. data/lib/active_support/core_ext/symbol.rb +3 -0
  133. data/lib/active_support/core_ext/time/acts_like.rb +2 -0
  134. data/lib/active_support/core_ext/time/calculations.rb +76 -18
  135. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  136. data/lib/active_support/core_ext/time/conversions.rb +4 -0
  137. data/lib/active_support/core_ext/time/zones.rb +6 -4
  138. data/lib/active_support/core_ext/time.rb +2 -0
  139. data/lib/active_support/core_ext/uri.rb +11 -6
  140. data/lib/active_support/core_ext.rb +3 -1
  141. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  142. data/lib/active_support/current_attributes.rb +210 -0
  143. data/lib/active_support/dependencies/autoload.rb +2 -0
  144. data/lib/active_support/dependencies/interlock.rb +2 -0
  145. data/lib/active_support/dependencies/zeitwerk_integration.rb +120 -0
  146. data/lib/active_support/dependencies.rb +134 -60
  147. data/lib/active_support/deprecation/behaviors.rb +43 -11
  148. data/lib/active_support/deprecation/constant_accessor.rb +4 -2
  149. data/lib/active_support/deprecation/disallowed.rb +56 -0
  150. data/lib/active_support/deprecation/instance_delegator.rb +2 -1
  151. data/lib/active_support/deprecation/method_wrappers.rb +29 -21
  152. data/lib/active_support/deprecation/proxy_wrappers.rb +32 -6
  153. data/lib/active_support/deprecation/reporting.rb +54 -9
  154. data/lib/active_support/deprecation.rb +9 -2
  155. data/lib/active_support/descendants_tracker.rb +61 -9
  156. data/lib/active_support/digest.rb +22 -0
  157. data/lib/active_support/duration/iso8601_parser.rb +6 -6
  158. data/lib/active_support/duration/iso8601_serializer.rb +20 -14
  159. data/lib/active_support/duration.rb +102 -45
  160. data/lib/active_support/encrypted_configuration.rb +45 -0
  161. data/lib/active_support/encrypted_file.rb +117 -0
  162. data/lib/active_support/environment_inquirer.rb +20 -0
  163. data/lib/active_support/evented_file_update_checker.rb +84 -117
  164. data/lib/active_support/execution_wrapper.rb +19 -13
  165. data/lib/active_support/executor.rb +2 -0
  166. data/lib/active_support/file_update_checker.rb +2 -1
  167. data/lib/active_support/fork_tracker.rb +64 -0
  168. data/lib/active_support/gem_version.rb +3 -1
  169. data/lib/active_support/gzip.rb +2 -0
  170. data/lib/active_support/hash_with_indifferent_access.rb +123 -41
  171. data/lib/active_support/i18n.rb +4 -1
  172. data/lib/active_support/i18n_railtie.rb +19 -14
  173. data/lib/active_support/inflections.rb +2 -0
  174. data/lib/active_support/inflector/inflections.rb +19 -8
  175. data/lib/active_support/inflector/methods.rb +87 -77
  176. data/lib/active_support/inflector/transliterate.rb +56 -18
  177. data/lib/active_support/inflector.rb +2 -0
  178. data/lib/active_support/json/decoding.rb +27 -26
  179. data/lib/active_support/json/encoding.rb +13 -3
  180. data/lib/active_support/json.rb +2 -0
  181. data/lib/active_support/key_generator.rb +3 -33
  182. data/lib/active_support/lazy_load_hooks.rb +7 -2
  183. data/lib/active_support/locale/en.rb +33 -0
  184. data/lib/active_support/locale/en.yml +7 -3
  185. data/lib/active_support/log_subscriber/test_helper.rb +2 -0
  186. data/lib/active_support/log_subscriber.rb +42 -11
  187. data/lib/active_support/logger.rb +4 -17
  188. data/lib/active_support/logger_silence.rb +13 -20
  189. data/lib/active_support/logger_thread_safe_level.rb +54 -7
  190. data/lib/active_support/message_encryptor.rb +100 -32
  191. data/lib/active_support/message_verifier.rb +85 -14
  192. data/lib/active_support/messages/metadata.rb +80 -0
  193. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  194. data/lib/active_support/messages/rotator.rb +57 -0
  195. data/lib/active_support/multibyte/chars.rb +12 -68
  196. data/lib/active_support/multibyte/unicode.rb +17 -327
  197. data/lib/active_support/multibyte.rb +2 -0
  198. data/lib/active_support/notifications/fanout.rb +118 -16
  199. data/lib/active_support/notifications/instrumenter.rb +73 -9
  200. data/lib/active_support/notifications.rb +74 -8
  201. data/lib/active_support/number_helper/number_converter.rb +7 -6
  202. data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -9
  203. data/lib/active_support/number_helper/number_to_delimited_converter.rb +5 -2
  204. data/lib/active_support/number_helper/number_to_human_converter.rb +6 -3
  205. data/lib/active_support/number_helper/number_to_human_size_converter.rb +6 -3
  206. data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
  207. data/lib/active_support/number_helper/number_to_phone_converter.rb +5 -2
  208. data/lib/active_support/number_helper/number_to_rounded_converter.rb +14 -27
  209. data/lib/active_support/number_helper/rounding_helper.rb +16 -30
  210. data/lib/active_support/number_helper.rb +40 -12
  211. data/lib/active_support/option_merger.rb +24 -3
  212. data/lib/active_support/ordered_hash.rb +3 -1
  213. data/lib/active_support/ordered_options.rb +17 -5
  214. data/lib/active_support/parameter_filter.rb +133 -0
  215. data/lib/active_support/per_thread_registry.rb +4 -1
  216. data/lib/active_support/proxy_object.rb +2 -0
  217. data/lib/active_support/rails.rb +3 -10
  218. data/lib/active_support/railtie.rb +60 -9
  219. data/lib/active_support/reloader.rb +12 -11
  220. data/lib/active_support/rescuable.rb +7 -6
  221. data/lib/active_support/secure_compare_rotator.rb +51 -0
  222. data/lib/active_support/security_utils.rb +26 -15
  223. data/lib/active_support/string_inquirer.rb +6 -3
  224. data/lib/active_support/subscriber.rb +74 -24
  225. data/lib/active_support/tagged_logging.rb +44 -8
  226. data/lib/active_support/test_case.rb +94 -2
  227. data/lib/active_support/testing/assertions.rb +58 -20
  228. data/lib/active_support/testing/autorun.rb +2 -0
  229. data/lib/active_support/testing/constant_lookup.rb +2 -0
  230. data/lib/active_support/testing/declarative.rb +2 -0
  231. data/lib/active_support/testing/deprecation.rb +2 -1
  232. data/lib/active_support/testing/file_fixtures.rb +4 -0
  233. data/lib/active_support/testing/isolation.rb +4 -2
  234. data/lib/active_support/testing/method_call_assertions.rb +30 -1
  235. data/lib/active_support/testing/parallelization/server.rb +78 -0
  236. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  237. data/lib/active_support/testing/parallelization.rb +51 -0
  238. data/lib/active_support/testing/setup_and_teardown.rb +12 -7
  239. data/lib/active_support/testing/stream.rb +3 -2
  240. data/lib/active_support/testing/tagged_logging.rb +2 -0
  241. data/lib/active_support/testing/time_helpers.rb +78 -13
  242. data/lib/active_support/time.rb +2 -0
  243. data/lib/active_support/time_with_zone.rb +113 -41
  244. data/lib/active_support/values/time_zone.rb +54 -25
  245. data/lib/active_support/version.rb +2 -0
  246. data/lib/active_support/xml_mini/jdom.rb +5 -4
  247. data/lib/active_support/xml_mini/libxml.rb +4 -2
  248. data/lib/active_support/xml_mini/libxmlsax.rb +6 -4
  249. data/lib/active_support/xml_mini/nokogiri.rb +4 -2
  250. data/lib/active_support/xml_mini/nokogirisax.rb +5 -3
  251. data/lib/active_support/xml_mini/rexml.rb +12 -3
  252. data/lib/active_support/xml_mini.rb +5 -11
  253. data/lib/active_support.rb +18 -13
  254. metadata +71 -32
  255. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
  256. data/lib/active_support/core_ext/hash/compact.rb +0 -27
  257. data/lib/active_support/core_ext/hash/transform_values.rb +0 -30
  258. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  259. data/lib/active_support/core_ext/module/reachable.rb +0 -8
  260. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
  261. data/lib/active_support/core_ext/range/include_range.rb +0 -23
  262. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,5 +1,4 @@
1
- require "active_support/core_ext/array/extract_options"
2
- require "active_support/core_ext/regexp"
1
+ # frozen_string_literal: true
3
2
 
4
3
  # Extends the module object with class/module and instance accessors for
5
4
  # class/module attributes, just like the native attr* accessors for instance
@@ -26,7 +25,7 @@ class Module
26
25
  # end
27
26
  # # => NameError: invalid attribute name: 1_Badname
28
27
  #
29
- # If you want to opt out of the creation of the instance reader method, pass
28
+ # To omit the instance reader method, pass
30
29
  # <tt>instance_reader: false</tt> or <tt>instance_accessor: false</tt>.
31
30
  #
32
31
  # class Current
@@ -34,9 +33,7 @@ class Module
34
33
  # end
35
34
  #
36
35
  # Current.new.user # => NoMethodError
37
- def thread_mattr_reader(*syms) # :nodoc:
38
- options = syms.extract_options!
39
-
36
+ def thread_mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil) # :nodoc:
40
37
  syms.each do |sym|
41
38
  raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
42
39
 
@@ -48,13 +45,15 @@ class Module
48
45
  end
49
46
  EOS
50
47
 
51
- unless options[:instance_reader] == false || options[:instance_accessor] == false
48
+ if instance_reader && instance_accessor
52
49
  class_eval(<<-EOS, __FILE__, __LINE__ + 1)
53
50
  def #{sym}
54
51
  self.class.#{sym}
55
52
  end
56
53
  EOS
57
54
  end
55
+
56
+ Thread.current["attr_" + name + "_#{sym}"] = default unless default.nil?
58
57
  end
59
58
  end
60
59
  alias :thread_cattr_reader :thread_mattr_reader
@@ -69,7 +68,7 @@ class Module
69
68
  # Current.user = "DHH"
70
69
  # Thread.current[:attr_Current_user] # => "DHH"
71
70
  #
72
- # If you want to opt out of the creation of the instance writer method, pass
71
+ # To omit the instance writer method, pass
73
72
  # <tt>instance_writer: false</tt> or <tt>instance_accessor: false</tt>.
74
73
  #
75
74
  # class Current
@@ -77,8 +76,7 @@ class Module
77
76
  # end
78
77
  #
79
78
  # Current.new.user = "DHH" # => NoMethodError
80
- def thread_mattr_writer(*syms) # :nodoc:
81
- options = syms.extract_options!
79
+ def thread_mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil) # :nodoc:
82
80
  syms.each do |sym|
83
81
  raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
84
82
 
@@ -90,13 +88,15 @@ class Module
90
88
  end
91
89
  EOS
92
90
 
93
- unless options[:instance_writer] == false || options[:instance_accessor] == false
91
+ if instance_writer && instance_accessor
94
92
  class_eval(<<-EOS, __FILE__, __LINE__ + 1)
95
93
  def #{sym}=(obj)
96
94
  self.class.#{sym} = obj
97
95
  end
98
96
  EOS
99
97
  end
98
+
99
+ public_send("#{sym}=", default) unless default.nil?
100
100
  end
101
101
  end
102
102
  alias :thread_cattr_writer :thread_mattr_writer
@@ -122,8 +122,8 @@ class Module
122
122
  # Customer.user # => "Rafael"
123
123
  # Account.user # => "DHH"
124
124
  #
125
- # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
126
- # To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
125
+ # To omit the instance writer method, pass <tt>instance_writer: false</tt>.
126
+ # To omit the instance reader method, pass <tt>instance_reader: false</tt>.
127
127
  #
128
128
  # class Current
129
129
  # thread_mattr_accessor :user, instance_writer: false, instance_reader: false
@@ -132,17 +132,17 @@ class Module
132
132
  # Current.new.user = "DHH" # => NoMethodError
133
133
  # Current.new.user # => NoMethodError
134
134
  #
135
- # Or pass <tt>instance_accessor: false</tt>, to opt out both instance methods.
135
+ # Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
136
136
  #
137
137
  # class Current
138
- # mattr_accessor :user, instance_accessor: false
138
+ # thread_mattr_accessor :user, instance_accessor: false
139
139
  # end
140
140
  #
141
141
  # Current.new.user = "DHH" # => NoMethodError
142
142
  # Current.new.user # => NoMethodError
143
- def thread_mattr_accessor(*syms)
144
- thread_mattr_reader(*syms)
145
- thread_mattr_writer(*syms)
143
+ def thread_mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil)
144
+ thread_mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor, default: default)
145
+ thread_mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor)
146
146
  end
147
147
  alias :thread_cattr_accessor :thread_mattr_accessor
148
148
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/concern"
2
4
 
3
5
  class Module
@@ -20,7 +22,7 @@ class Module
20
22
  #
21
23
  # == Using comments:
22
24
  #
23
- # class Todo
25
+ # class Todo < ApplicationRecord
24
26
  # # Other todo implementation
25
27
  # # ...
26
28
  #
@@ -28,7 +30,6 @@ class Module
28
30
  # has_many :events
29
31
  #
30
32
  # before_create :track_creation
31
- # after_destroy :track_deletion
32
33
  #
33
34
  # private
34
35
  # def track_creation
@@ -40,7 +41,7 @@ class Module
40
41
  #
41
42
  # Noisy syntax.
42
43
  #
43
- # class Todo
44
+ # class Todo < ApplicationRecord
44
45
  # # Other todo implementation
45
46
  # # ...
46
47
  #
@@ -50,7 +51,6 @@ class Module
50
51
  # included do
51
52
  # has_many :events
52
53
  # before_create :track_creation
53
- # after_destroy :track_deletion
54
54
  # end
55
55
  #
56
56
  # private
@@ -68,7 +68,7 @@ class Module
68
68
  # increased overhead can be a reasonable tradeoff even if it reduces our
69
69
  # at-a-glance perception of how things work.
70
70
  #
71
- # class Todo
71
+ # class Todo < ApplicationRecord
72
72
  # # Other todo implementation
73
73
  # # ...
74
74
  #
@@ -80,7 +80,7 @@ class Module
80
80
  # By quieting the mix-in noise, we arrive at a natural, low-ceremony way to
81
81
  # separate bite-sized concerns.
82
82
  #
83
- # class Todo
83
+ # class Todo < ApplicationRecord
84
84
  # # Other todo implementation
85
85
  # # ...
86
86
  #
@@ -88,7 +88,6 @@ class Module
88
88
  # included do
89
89
  # has_many :events
90
90
  # before_create :track_creation
91
- # after_destroy :track_deletion
92
91
  # end
93
92
  #
94
93
  # private
@@ -99,16 +98,22 @@ class Module
99
98
  # end
100
99
  #
101
100
  # Todo.ancestors
102
- # # => [Todo, Todo::EventTracking, Object]
101
+ # # => [Todo, Todo::EventTracking, ApplicationRecord, Object]
103
102
  #
104
103
  # This small step has some wonderful ripple effects. We can
105
104
  # * grok the behavior of our class in one glance,
106
105
  # * clean up monolithic junk-drawer classes by separating their concerns, and
107
106
  # * stop leaning on protected/private for crude "this is internal stuff" modularity.
107
+ #
108
+ # === Prepending concerning
109
+ #
110
+ # <tt>concerning</tt> supports a <tt>prepend: true</tt> argument which will <tt>prepend</tt> the
111
+ # concern instead of using <tt>include</tt> for it.
108
112
  module Concerning
109
113
  # Define a new concern and mix it in.
110
- def concerning(topic, &block)
111
- include concern(topic, &block)
114
+ def concerning(topic, prepend: false, &block)
115
+ method = prepend ? :prepend : :include
116
+ __send__(method, concern(topic, &block))
112
117
  end
113
118
 
114
119
  # A low-cruft shortcut to define a concern.
@@ -1,5 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "set"
2
- require "active_support/core_ext/regexp"
3
4
 
4
5
  class Module
5
6
  # Error generated by +delegate+ when a method is called on +nil+ and +allow_nil+
@@ -18,10 +19,11 @@ class Module
18
19
  # public methods as your own.
19
20
  #
20
21
  # ==== Options
21
- # * <tt>:to</tt> - Specifies the target object
22
+ # * <tt>:to</tt> - Specifies the target object name as a symbol or string
22
23
  # * <tt>:prefix</tt> - Prefixes the new method with the target name or a custom prefix
23
- # * <tt>:allow_nil</tt> - if set to true, prevents a +Module::DelegationError+
24
+ # * <tt>:allow_nil</tt> - If set to true, prevents a +Module::DelegationError+
24
25
  # from being raised
26
+ # * <tt>:private</tt> - If set to true, changes method visibility to private
25
27
  #
26
28
  # The macro receives one or more method names (specified as symbols or
27
29
  # strings) and the name of the target object via the <tt>:to</tt> option
@@ -112,12 +114,26 @@ class Module
112
114
  # invoice.customer_name # => 'John Doe'
113
115
  # invoice.customer_address # => 'Vimmersvej 13'
114
116
  #
117
+ # The delegated methods are public by default.
118
+ # Pass <tt>private: true</tt> to change that.
119
+ #
120
+ # class User < ActiveRecord::Base
121
+ # has_one :profile
122
+ # delegate :first_name, to: :profile
123
+ # delegate :date_of_birth, to: :profile, private: true
124
+ #
125
+ # def age
126
+ # Date.today.year - date_of_birth.year
127
+ # end
128
+ # end
129
+ #
130
+ # User.new.first_name # => "Tomas"
131
+ # User.new.date_of_birth # => NoMethodError: private method `date_of_birth' called for #<User:0x00000008221340>
132
+ # User.new.age # => 2
133
+ #
115
134
  # If the target is +nil+ and does not respond to the delegated method a
116
- # +Module::DelegationError+ is raised, as with any other value. Sometimes,
117
- # however, it makes sense to be robust to that situation and that is the
118
- # purpose of the <tt>:allow_nil</tt> option: If the target is not +nil+, or it
119
- # is and responds to the method, everything works as usual. But if it is +nil+
120
- # and does not respond to the delegated method, +nil+ is returned.
135
+ # +Module::DelegationError+ is raised. If you wish to instead return +nil+,
136
+ # use the <tt>:allow_nil</tt> option.
121
137
  #
122
138
  # class User < ActiveRecord::Base
123
139
  # has_one :profile
@@ -152,9 +168,9 @@ class Module
152
168
  # Foo.new("Bar").name # raises NoMethodError: undefined method `name'
153
169
  #
154
170
  # The target method must be public, otherwise it will raise +NoMethodError+.
155
- def delegate(*methods, to: nil, prefix: nil, allow_nil: nil)
171
+ def delegate(*methods, to: nil, prefix: nil, allow_nil: nil, private: nil)
156
172
  unless to
157
- raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter)."
173
+ raise ArgumentError, "Delegation needs a target. Supply a keyword argument 'to' (e.g. delegate :hello, to: :greeter)."
158
174
  end
159
175
 
160
176
  if prefix == true && /^[^a-z_]/.match?(to)
@@ -174,10 +190,22 @@ class Module
174
190
  to = to.to_s
175
191
  to = "self.#{to}" if DELEGATION_RESERVED_METHOD_NAMES.include?(to)
176
192
 
177
- methods.each do |method|
193
+ method_def = []
194
+ method_names = []
195
+
196
+ methods.map do |method|
197
+ method_name = prefix ? "#{method_prefix}#{method}" : method
198
+ method_names << method_name.to_sym
199
+
178
200
  # Attribute writer methods only accept one argument. Makes sure []=
179
201
  # methods still accept two arguments.
180
- definition = /[^\]]=$/.match?(method) ? "arg" : "*args, &block"
202
+ definition = if /[^\]]=$/.match?(method)
203
+ "arg"
204
+ elsif RUBY_VERSION >= "2.7"
205
+ "..."
206
+ else
207
+ "*args, &block"
208
+ end
181
209
 
182
210
  # The following generated method calls the target exactly once, storing
183
211
  # the returned value in a dummy variable.
@@ -187,81 +215,84 @@ class Module
187
215
  # whereas conceptually, from the user point of view, the delegator should
188
216
  # be doing one call.
189
217
  if allow_nil
190
- method_def = [
191
- "def #{method_prefix}#{method}(#{definition})",
192
- "_ = #{to}",
193
- "if !_.nil? || nil.respond_to?(:#{method})",
194
- " _.#{method}(#{definition})",
195
- "end",
196
- "end"
197
- ].join ";"
218
+ method = method.to_s
219
+
220
+ method_def <<
221
+ "def #{method_name}(#{definition})" <<
222
+ " _ = #{to}" <<
223
+ " if !_.nil? || nil.respond_to?(:#{method})" <<
224
+ " _.#{method}(#{definition})" <<
225
+ " end" <<
226
+ "end"
198
227
  else
199
- exception = %(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
228
+ method = method.to_s
229
+ method_name = method_name.to_s
200
230
 
201
- method_def = [
202
- "def #{method_prefix}#{method}(#{definition})",
203
- " _ = #{to}",
204
- " _.#{method}(#{definition})",
205
- "rescue NoMethodError => e",
206
- " if _.nil? && e.name == :#{method}",
207
- " #{exception}",
208
- " else",
209
- " raise",
210
- " end",
231
+ method_def <<
232
+ "def #{method_name}(#{definition})" <<
233
+ " _ = #{to}" <<
234
+ " _.#{method}(#{definition})" <<
235
+ "rescue NoMethodError => e" <<
236
+ " if _.nil? && e.name == :#{method}" <<
237
+ %( raise DelegationError, "#{self}##{method_name} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}") <<
238
+ " else" <<
239
+ " raise" <<
240
+ " end" <<
211
241
  "end"
212
- ].join ";"
213
242
  end
214
-
215
- module_eval(method_def, file, line)
216
243
  end
244
+ module_eval(method_def.join(";"), file, line)
245
+ private(*method_names) if private
246
+ method_names
217
247
  end
218
248
 
219
249
  # When building decorators, a common pattern may emerge:
220
250
  #
221
251
  # class Partition
222
- # def initialize(first_event)
223
- # @events = [ first_event ]
252
+ # def initialize(event)
253
+ # @event = event
224
254
  # end
225
255
  #
226
- # def people
227
- # if @events.first.detail.people.any?
228
- # @events.collect { |e| Array(e.detail.people) }.flatten.uniq
229
- # else
230
- # @events.collect(&:creator).uniq
231
- # end
256
+ # def person
257
+ # detail.person || creator
232
258
  # end
233
259
  #
234
260
  # private
235
261
  # def respond_to_missing?(name, include_private = false)
236
- # @events.respond_to?(name, include_private)
262
+ # @event.respond_to?(name, include_private)
237
263
  # end
238
264
  #
239
265
  # def method_missing(method, *args, &block)
240
- # @events.send(method, *args, &block)
266
+ # @event.send(method, *args, &block)
241
267
  # end
242
268
  # end
243
269
  #
244
- # With `Module#delegate_missing_to`, the above is condensed to:
270
+ # With <tt>Module#delegate_missing_to</tt>, the above is condensed to:
245
271
  #
246
272
  # class Partition
247
- # delegate_missing_to :@events
273
+ # delegate_missing_to :@event
248
274
  #
249
- # def initialize(first_event)
250
- # @events = [ first_event ]
275
+ # def initialize(event)
276
+ # @event = event
251
277
  # end
252
278
  #
253
- # def people
254
- # if @events.first.detail.people.any?
255
- # @events.collect { |e| Array(e.detail.people) }.flatten.uniq
256
- # else
257
- # @events.collect(&:creator).uniq
258
- # end
279
+ # def person
280
+ # detail.person || creator
259
281
  # end
260
282
  # end
261
283
  #
262
- # The target can be anything callable within the object. E.g. instance
263
- # variables, methods, constants and the likes.
264
- def delegate_missing_to(target)
284
+ # The target can be anything callable within the object, e.g. instance
285
+ # variables, methods, constants, etc.
286
+ #
287
+ # The delegated method must be public on the target, otherwise it will
288
+ # raise +DelegationError+. If you wish to instead return +nil+,
289
+ # use the <tt>:allow_nil</tt> option.
290
+ #
291
+ # The <tt>marshal_dump</tt> and <tt>_dump</tt> methods are exempt from
292
+ # delegation due to possible interference when calling
293
+ # <tt>Marshal.dump(object)</tt>, should the delegation target method
294
+ # of <tt>object</tt> add or remove instance variables.
295
+ def delegate_missing_to(target, allow_nil: nil)
265
296
  target = target.to_s
266
297
  target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target)
267
298
 
@@ -270,6 +301,7 @@ class Module
270
301
  # It may look like an oversight, but we deliberately do not pass
271
302
  # +include_private+, because they do not get delegated.
272
303
 
304
+ return false if name == :marshal_dump || name == :_dump
273
305
  #{target}.respond_to?(name) || super
274
306
  end
275
307
 
@@ -277,9 +309,22 @@ class Module
277
309
  if #{target}.respond_to?(method)
278
310
  #{target}.public_send(method, *args, &block)
279
311
  else
280
- super
312
+ begin
313
+ super
314
+ rescue NoMethodError
315
+ if #{target}.nil?
316
+ if #{allow_nil == true}
317
+ nil
318
+ else
319
+ raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
320
+ end
321
+ else
322
+ raise
323
+ end
324
+ end
281
325
  end
282
326
  end
327
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
283
328
  RUBY
284
329
  end
285
330
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Module
2
4
  # deprecate :foo
3
5
  # deprecate bar: 'message'
@@ -1,14 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/filters"
1
4
  require "active_support/inflector"
2
5
 
3
6
  class Module
4
7
  # Returns the name of the module containing this one.
5
8
  #
6
- # M::N.parent_name # => "M"
7
- def parent_name
9
+ # M::N.module_parent_name # => "M"
10
+ def module_parent_name
8
11
  if defined?(@parent_name)
9
12
  @parent_name
10
13
  else
11
- parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil
14
+ parent_name = name =~ /::[^:]+\z/ ? -$` : nil
12
15
  @parent_name = parent_name unless frozen?
13
16
  parent_name
14
17
  end
@@ -22,15 +25,15 @@ class Module
22
25
  # end
23
26
  # X = M::N
24
27
  #
25
- # M::N.parent # => M
26
- # X.parent # => M
28
+ # M::N.module_parent # => M
29
+ # X.module_parent # => M
27
30
  #
28
31
  # The parent of top-level and anonymous modules is Object.
29
32
  #
30
- # M.parent # => Object
31
- # Module.new.parent # => Object
32
- def parent
33
- parent_name ? ActiveSupport::Inflector.constantize(parent_name) : Object
33
+ # M.module_parent # => Object
34
+ # Module.new.module_parent # => Object
35
+ def module_parent
36
+ module_parent_name ? ActiveSupport::Inflector.constantize(module_parent_name) : Object
34
37
  end
35
38
 
36
39
  # Returns all the parents of this module according to its name, ordered from
@@ -42,13 +45,13 @@ class Module
42
45
  # end
43
46
  # X = M::N
44
47
  #
45
- # M.parents # => [Object]
46
- # M::N.parents # => [M, Object]
47
- # X.parents # => [M, Object]
48
- def parents
48
+ # M.module_parents # => [Object]
49
+ # M::N.module_parents # => [M, Object]
50
+ # X.module_parents # => [M, Object]
51
+ def module_parents
49
52
  parents = []
50
- if parent_name
51
- parts = parent_name.split("::")
53
+ if module_parent_name
54
+ parts = module_parent_name.split("::")
52
55
  until parts.empty?
53
56
  parents << ActiveSupport::Inflector.constantize(parts * "::")
54
57
  parts.pop
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Module
4
+ # Marks the named method as intended to be redefined, if it exists.
5
+ # Suppresses the Ruby method redefinition warning. Prefer
6
+ # #redefine_method where possible.
7
+ def silence_redefinition_of_method(method)
8
+ if method_defined?(method) || private_method_defined?(method)
9
+ # This suppresses the "method redefined" warning; the self-alias
10
+ # looks odd, but means we don't need to generate a unique name
11
+ alias_method method, method
12
+ end
13
+ end
14
+
15
+ # Replaces the existing method definition, if there is one, with the passed
16
+ # block as its body.
17
+ def redefine_method(method, &block)
18
+ visibility = method_visibility(method)
19
+ silence_redefinition_of_method(method)
20
+ define_method(method, &block)
21
+ send(visibility, method)
22
+ end
23
+
24
+ # Replaces the existing singleton method definition, if there is one, with
25
+ # the passed block as its body.
26
+ def redefine_singleton_method(method, &block)
27
+ singleton_class.redefine_method(method, &block)
28
+ end
29
+
30
+ def method_visibility(method) # :nodoc:
31
+ case
32
+ when private_method_defined?(method)
33
+ :private
34
+ when protected_method_defined?(method)
35
+ :protected
36
+ else
37
+ :public
38
+ end
39
+ end
40
+ end
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/redefine_method"
4
+
1
5
  class Module
2
6
  # Removes the named method, if it exists.
3
7
  def remove_possible_method(method)
@@ -8,28 +12,6 @@ class Module
8
12
 
9
13
  # Removes the named singleton method, if it exists.
10
14
  def remove_possible_singleton_method(method)
11
- singleton_class.instance_eval do
12
- remove_possible_method(method)
13
- end
14
- end
15
-
16
- # Replaces the existing method definition, if there is one, with the passed
17
- # block as its body.
18
- def redefine_method(method, &block)
19
- visibility = method_visibility(method)
20
- remove_possible_method(method)
21
- define_method(method, &block)
22
- send(visibility, method)
23
- end
24
-
25
- def method_visibility(method) # :nodoc:
26
- case
27
- when private_method_defined?(method)
28
- :private
29
- when protected_method_defined?(method)
30
- :protected
31
- else
32
- :public
33
- end
15
+ singleton_class.remove_possible_method(method)
34
16
  end
35
17
  end
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/module/aliasing"
2
4
  require "active_support/core_ext/module/introspection"
3
5
  require "active_support/core_ext/module/anonymous"
4
- require "active_support/core_ext/module/reachable"
5
6
  require "active_support/core_ext/module/attribute_accessors"
6
7
  require "active_support/core_ext/module/attribute_accessors_per_thread"
7
8
  require "active_support/core_ext/module/attr_internal"
8
9
  require "active_support/core_ext/module/concerning"
9
10
  require "active_support/core_ext/module/delegation"
10
11
  require "active_support/core_ext/module/deprecation"
12
+ require "active_support/core_ext/module/redefine_method"
11
13
  require "active_support/core_ext/module/remove_method"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class NameError
2
4
  # Extract the name of the missing constant from the exception message.
3
5
  #
@@ -8,8 +10,26 @@ class NameError
8
10
  # end
9
11
  # # => "HelloWorld"
10
12
  def missing_name
11
- if /undefined local variable or method/ !~ message
12
- $1 if /((::)?([A-Z]\w*)(::[A-Z]\w*)*)$/ =~ message
13
+ # Since ruby v2.3.0 `did_you_mean` gem is loaded by default.
14
+ # It extends NameError#message with spell corrections which are SLOW.
15
+ # We should use original_message message instead.
16
+ message = respond_to?(:original_message) ? original_message : self.message
17
+ return unless message.start_with?("uninitialized constant ")
18
+
19
+ receiver = begin
20
+ self.receiver
21
+ rescue ArgumentError
22
+ nil
23
+ end
24
+
25
+ if receiver == Object
26
+ name.to_s
27
+ elsif receiver
28
+ "#{real_mod_name(receiver)}::#{self.name}"
29
+ else
30
+ if match = message.match(/((::)?([A-Z]\w*)(::[A-Z]\w*)*)$/)
31
+ match[1]
32
+ end
13
33
  end
14
34
  end
15
35
 
@@ -28,4 +48,18 @@ class NameError
28
48
  missing_name == name.to_s
29
49
  end
30
50
  end
51
+
52
+ private
53
+ UNBOUND_METHOD_MODULE_NAME = Module.instance_method(:name)
54
+ private_constant :UNBOUND_METHOD_MODULE_NAME
55
+
56
+ if UnboundMethod.method_defined?(:bind_call)
57
+ def real_mod_name(mod)
58
+ UNBOUND_METHOD_MODULE_NAME.bind_call(mod)
59
+ end
60
+ else
61
+ def real_mod_name(mod)
62
+ UNBOUND_METHOD_MODULE_NAME.bind(mod).call
63
+ end
64
+ end
31
65
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Numeric
2
4
  KILOBYTE = 1024
3
5
  MEGABYTE = KILOBYTE * 1024