activesupport 6.0.0

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

Potentially problematic release.


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

Files changed (250) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +572 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +40 -0
  5. data/lib/active_support.rb +96 -0
  6. data/lib/active_support/actionable_error.rb +48 -0
  7. data/lib/active_support/all.rb +5 -0
  8. data/lib/active_support/array_inquirer.rb +48 -0
  9. data/lib/active_support/backtrace_cleaner.rb +132 -0
  10. data/lib/active_support/benchmarkable.rb +51 -0
  11. data/lib/active_support/builder.rb +8 -0
  12. data/lib/active_support/cache.rb +830 -0
  13. data/lib/active_support/cache/file_store.rb +196 -0
  14. data/lib/active_support/cache/mem_cache_store.rb +212 -0
  15. data/lib/active_support/cache/memory_store.rb +174 -0
  16. data/lib/active_support/cache/null_store.rb +48 -0
  17. data/lib/active_support/cache/redis_cache_store.rb +488 -0
  18. data/lib/active_support/cache/strategy/local_cache.rb +194 -0
  19. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  20. data/lib/active_support/callbacks.rb +856 -0
  21. data/lib/active_support/concern.rb +171 -0
  22. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +17 -0
  23. data/lib/active_support/concurrency/share_lock.rb +227 -0
  24. data/lib/active_support/configurable.rb +146 -0
  25. data/lib/active_support/core_ext.rb +5 -0
  26. data/lib/active_support/core_ext/array.rb +9 -0
  27. data/lib/active_support/core_ext/array/access.rb +104 -0
  28. data/lib/active_support/core_ext/array/conversions.rb +213 -0
  29. data/lib/active_support/core_ext/array/extract.rb +21 -0
  30. data/lib/active_support/core_ext/array/extract_options.rb +31 -0
  31. data/lib/active_support/core_ext/array/grouping.rb +109 -0
  32. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  33. data/lib/active_support/core_ext/array/prepend_and_append.rb +5 -0
  34. data/lib/active_support/core_ext/array/wrap.rb +48 -0
  35. data/lib/active_support/core_ext/benchmark.rb +16 -0
  36. data/lib/active_support/core_ext/big_decimal.rb +3 -0
  37. data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
  38. data/lib/active_support/core_ext/class.rb +4 -0
  39. data/lib/active_support/core_ext/class/attribute.rb +141 -0
  40. data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
  41. data/lib/active_support/core_ext/class/subclasses.rb +54 -0
  42. data/lib/active_support/core_ext/date.rb +7 -0
  43. data/lib/active_support/core_ext/date/acts_like.rb +10 -0
  44. data/lib/active_support/core_ext/date/blank.rb +14 -0
  45. data/lib/active_support/core_ext/date/calculations.rb +146 -0
  46. data/lib/active_support/core_ext/date/conversions.rb +96 -0
  47. data/lib/active_support/core_ext/date/zones.rb +8 -0
  48. data/lib/active_support/core_ext/date_and_time/calculations.rb +351 -0
  49. data/lib/active_support/core_ext/date_and_time/compatibility.rb +16 -0
  50. data/lib/active_support/core_ext/date_and_time/zones.rb +41 -0
  51. data/lib/active_support/core_ext/date_time.rb +7 -0
  52. data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
  53. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  54. data/lib/active_support/core_ext/date_time/calculations.rb +211 -0
  55. data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
  56. data/lib/active_support/core_ext/date_time/conversions.rb +107 -0
  57. data/lib/active_support/core_ext/digest.rb +3 -0
  58. data/lib/active_support/core_ext/digest/uuid.rb +53 -0
  59. data/lib/active_support/core_ext/enumerable.rb +188 -0
  60. data/lib/active_support/core_ext/file.rb +3 -0
  61. data/lib/active_support/core_ext/file/atomic.rb +70 -0
  62. data/lib/active_support/core_ext/hash.rb +10 -0
  63. data/lib/active_support/core_ext/hash/compact.rb +5 -0
  64. data/lib/active_support/core_ext/hash/conversions.rb +263 -0
  65. data/lib/active_support/core_ext/hash/deep_merge.rb +34 -0
  66. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  67. data/lib/active_support/core_ext/hash/except.rb +24 -0
  68. data/lib/active_support/core_ext/hash/indifferent_access.rb +24 -0
  69. data/lib/active_support/core_ext/hash/keys.rb +143 -0
  70. data/lib/active_support/core_ext/hash/reverse_merge.rb +25 -0
  71. data/lib/active_support/core_ext/hash/slice.rb +26 -0
  72. data/lib/active_support/core_ext/hash/transform_values.rb +5 -0
  73. data/lib/active_support/core_ext/integer.rb +5 -0
  74. data/lib/active_support/core_ext/integer/inflections.rb +31 -0
  75. data/lib/active_support/core_ext/integer/multiple.rb +12 -0
  76. data/lib/active_support/core_ext/integer/time.rb +22 -0
  77. data/lib/active_support/core_ext/kernel.rb +5 -0
  78. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  79. data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
  80. data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
  81. data/lib/active_support/core_ext/load_error.rb +9 -0
  82. data/lib/active_support/core_ext/marshal.rb +24 -0
  83. data/lib/active_support/core_ext/module.rb +13 -0
  84. data/lib/active_support/core_ext/module/aliasing.rb +31 -0
  85. data/lib/active_support/core_ext/module/anonymous.rb +30 -0
  86. data/lib/active_support/core_ext/module/attr_internal.rb +38 -0
  87. data/lib/active_support/core_ext/module/attribute_accessors.rb +212 -0
  88. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +144 -0
  89. data/lib/active_support/core_ext/module/concerning.rb +134 -0
  90. data/lib/active_support/core_ext/module/delegation.rb +313 -0
  91. data/lib/active_support/core_ext/module/deprecation.rb +25 -0
  92. data/lib/active_support/core_ext/module/introspection.rb +86 -0
  93. data/lib/active_support/core_ext/module/reachable.rb +6 -0
  94. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  95. data/lib/active_support/core_ext/module/remove_method.rb +17 -0
  96. data/lib/active_support/core_ext/name_error.rb +38 -0
  97. data/lib/active_support/core_ext/numeric.rb +5 -0
  98. data/lib/active_support/core_ext/numeric/bytes.rb +66 -0
  99. data/lib/active_support/core_ext/numeric/conversions.rb +136 -0
  100. data/lib/active_support/core_ext/numeric/inquiry.rb +5 -0
  101. data/lib/active_support/core_ext/numeric/time.rb +66 -0
  102. data/lib/active_support/core_ext/object.rb +16 -0
  103. data/lib/active_support/core_ext/object/acts_like.rb +21 -0
  104. data/lib/active_support/core_ext/object/blank.rb +155 -0
  105. data/lib/active_support/core_ext/object/conversions.rb +6 -0
  106. data/lib/active_support/core_ext/object/deep_dup.rb +55 -0
  107. data/lib/active_support/core_ext/object/duplicable.rb +49 -0
  108. data/lib/active_support/core_ext/object/inclusion.rb +29 -0
  109. data/lib/active_support/core_ext/object/instance_variables.rb +30 -0
  110. data/lib/active_support/core_ext/object/json.rb +228 -0
  111. data/lib/active_support/core_ext/object/to_param.rb +3 -0
  112. data/lib/active_support/core_ext/object/to_query.rb +89 -0
  113. data/lib/active_support/core_ext/object/try.rb +156 -0
  114. data/lib/active_support/core_ext/object/with_options.rb +82 -0
  115. data/lib/active_support/core_ext/range.rb +7 -0
  116. data/lib/active_support/core_ext/range/compare_range.rb +70 -0
  117. data/lib/active_support/core_ext/range/conversions.rb +41 -0
  118. data/lib/active_support/core_ext/range/each.rb +25 -0
  119. data/lib/active_support/core_ext/range/include_range.rb +9 -0
  120. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  121. data/lib/active_support/core_ext/range/overlaps.rb +10 -0
  122. data/lib/active_support/core_ext/regexp.rb +7 -0
  123. data/lib/active_support/core_ext/securerandom.rb +45 -0
  124. data/lib/active_support/core_ext/string.rb +15 -0
  125. data/lib/active_support/core_ext/string/access.rb +114 -0
  126. data/lib/active_support/core_ext/string/behavior.rb +8 -0
  127. data/lib/active_support/core_ext/string/conversions.rb +59 -0
  128. data/lib/active_support/core_ext/string/exclude.rb +13 -0
  129. data/lib/active_support/core_ext/string/filters.rb +145 -0
  130. data/lib/active_support/core_ext/string/indent.rb +45 -0
  131. data/lib/active_support/core_ext/string/inflections.rb +259 -0
  132. data/lib/active_support/core_ext/string/inquiry.rb +15 -0
  133. data/lib/active_support/core_ext/string/multibyte.rb +58 -0
  134. data/lib/active_support/core_ext/string/output_safety.rb +314 -0
  135. data/lib/active_support/core_ext/string/starts_ends_with.rb +6 -0
  136. data/lib/active_support/core_ext/string/strip.rb +27 -0
  137. data/lib/active_support/core_ext/string/zones.rb +16 -0
  138. data/lib/active_support/core_ext/time.rb +7 -0
  139. data/lib/active_support/core_ext/time/acts_like.rb +10 -0
  140. data/lib/active_support/core_ext/time/calculations.rb +344 -0
  141. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  142. data/lib/active_support/core_ext/time/conversions.rb +72 -0
  143. data/lib/active_support/core_ext/time/zones.rb +113 -0
  144. data/lib/active_support/core_ext/uri.rb +25 -0
  145. data/lib/active_support/current_attributes.rb +203 -0
  146. data/lib/active_support/dependencies.rb +806 -0
  147. data/lib/active_support/dependencies/autoload.rb +79 -0
  148. data/lib/active_support/dependencies/interlock.rb +57 -0
  149. data/lib/active_support/dependencies/zeitwerk_integration.rb +110 -0
  150. data/lib/active_support/deprecation.rb +46 -0
  151. data/lib/active_support/deprecation/behaviors.rb +109 -0
  152. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  153. data/lib/active_support/deprecation/instance_delegator.rb +39 -0
  154. data/lib/active_support/deprecation/method_wrappers.rb +78 -0
  155. data/lib/active_support/deprecation/proxy_wrappers.rb +173 -0
  156. data/lib/active_support/deprecation/reporting.rb +114 -0
  157. data/lib/active_support/descendants_tracker.rb +109 -0
  158. data/lib/active_support/digest.rb +20 -0
  159. data/lib/active_support/duration.rb +433 -0
  160. data/lib/active_support/duration/iso8601_parser.rb +124 -0
  161. data/lib/active_support/duration/iso8601_serializer.rb +54 -0
  162. data/lib/active_support/encrypted_configuration.rb +45 -0
  163. data/lib/active_support/encrypted_file.rb +100 -0
  164. data/lib/active_support/evented_file_update_checker.rb +235 -0
  165. data/lib/active_support/execution_wrapper.rb +129 -0
  166. data/lib/active_support/executor.rb +8 -0
  167. data/lib/active_support/file_update_checker.rb +163 -0
  168. data/lib/active_support/gem_version.rb +17 -0
  169. data/lib/active_support/gzip.rb +38 -0
  170. data/lib/active_support/hash_with_indifferent_access.rb +399 -0
  171. data/lib/active_support/i18n.rb +16 -0
  172. data/lib/active_support/i18n_railtie.rb +126 -0
  173. data/lib/active_support/inflections.rb +72 -0
  174. data/lib/active_support/inflector.rb +9 -0
  175. data/lib/active_support/inflector/inflections.rb +257 -0
  176. data/lib/active_support/inflector/methods.rb +398 -0
  177. data/lib/active_support/inflector/transliterate.rb +147 -0
  178. data/lib/active_support/json.rb +4 -0
  179. data/lib/active_support/json/decoding.rb +76 -0
  180. data/lib/active_support/json/encoding.rb +134 -0
  181. data/lib/active_support/key_generator.rb +41 -0
  182. data/lib/active_support/lazy_load_hooks.rb +82 -0
  183. data/lib/active_support/locale/en.rb +31 -0
  184. data/lib/active_support/locale/en.yml +135 -0
  185. data/lib/active_support/log_subscriber.rb +135 -0
  186. data/lib/active_support/log_subscriber/test_helper.rb +106 -0
  187. data/lib/active_support/logger.rb +93 -0
  188. data/lib/active_support/logger_silence.rb +45 -0
  189. data/lib/active_support/logger_thread_safe_level.rb +56 -0
  190. data/lib/active_support/message_encryptor.rb +227 -0
  191. data/lib/active_support/message_verifier.rb +205 -0
  192. data/lib/active_support/messages/metadata.rb +71 -0
  193. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  194. data/lib/active_support/messages/rotator.rb +56 -0
  195. data/lib/active_support/multibyte.rb +23 -0
  196. data/lib/active_support/multibyte/chars.rb +216 -0
  197. data/lib/active_support/multibyte/unicode.rb +157 -0
  198. data/lib/active_support/notifications.rb +253 -0
  199. data/lib/active_support/notifications/fanout.rb +244 -0
  200. data/lib/active_support/notifications/instrumenter.rb +164 -0
  201. data/lib/active_support/number_helper.rb +378 -0
  202. data/lib/active_support/number_helper/number_converter.rb +184 -0
  203. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  204. data/lib/active_support/number_helper/number_to_delimited_converter.rb +31 -0
  205. data/lib/active_support/number_helper/number_to_human_converter.rb +70 -0
  206. data/lib/active_support/number_helper/number_to_human_size_converter.rb +61 -0
  207. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  208. data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
  209. data/lib/active_support/number_helper/number_to_rounded_converter.rb +56 -0
  210. data/lib/active_support/number_helper/rounding_helper.rb +66 -0
  211. data/lib/active_support/option_merger.rb +27 -0
  212. data/lib/active_support/ordered_hash.rb +50 -0
  213. data/lib/active_support/ordered_options.rb +85 -0
  214. data/lib/active_support/parameter_filter.rb +129 -0
  215. data/lib/active_support/per_thread_registry.rb +60 -0
  216. data/lib/active_support/proxy_object.rb +15 -0
  217. data/lib/active_support/rails.rb +29 -0
  218. data/lib/active_support/railtie.rb +80 -0
  219. data/lib/active_support/reloader.rb +130 -0
  220. data/lib/active_support/rescuable.rb +174 -0
  221. data/lib/active_support/security_utils.rb +31 -0
  222. data/lib/active_support/string_inquirer.rb +34 -0
  223. data/lib/active_support/subscriber.rb +169 -0
  224. data/lib/active_support/tagged_logging.rb +88 -0
  225. data/lib/active_support/test_case.rb +163 -0
  226. data/lib/active_support/testing/assertions.rb +228 -0
  227. data/lib/active_support/testing/autorun.rb +7 -0
  228. data/lib/active_support/testing/constant_lookup.rb +51 -0
  229. data/lib/active_support/testing/declarative.rb +28 -0
  230. data/lib/active_support/testing/deprecation.rb +38 -0
  231. data/lib/active_support/testing/file_fixtures.rb +38 -0
  232. data/lib/active_support/testing/isolation.rb +110 -0
  233. data/lib/active_support/testing/method_call_assertions.rb +70 -0
  234. data/lib/active_support/testing/parallelization.rb +128 -0
  235. data/lib/active_support/testing/setup_and_teardown.rb +55 -0
  236. data/lib/active_support/testing/stream.rb +44 -0
  237. data/lib/active_support/testing/tagged_logging.rb +27 -0
  238. data/lib/active_support/testing/time_helpers.rb +200 -0
  239. data/lib/active_support/time.rb +20 -0
  240. data/lib/active_support/time_with_zone.rb +561 -0
  241. data/lib/active_support/values/time_zone.rb +570 -0
  242. data/lib/active_support/version.rb +10 -0
  243. data/lib/active_support/xml_mini.rb +202 -0
  244. data/lib/active_support/xml_mini/jdom.rb +183 -0
  245. data/lib/active_support/xml_mini/libxml.rb +80 -0
  246. data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
  247. data/lib/active_support/xml_mini/nokogiri.rb +83 -0
  248. data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
  249. data/lib/active_support/xml_mini/rexml.rb +130 -0
  250. metadata +385 -0
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ class Module
6
+ # = Bite-sized separation of concerns
7
+ #
8
+ # We often find ourselves with a medium-sized chunk of behavior that we'd
9
+ # like to extract, but only mix in to a single class.
10
+ #
11
+ # Extracting a plain old Ruby object to encapsulate it and collaborate or
12
+ # delegate to the original object is often a good choice, but when there's
13
+ # no additional state to encapsulate or we're making DSL-style declarations
14
+ # about the parent class, introducing new collaborators can obfuscate rather
15
+ # than simplify.
16
+ #
17
+ # The typical route is to just dump everything in a monolithic class, perhaps
18
+ # with a comment, as a least-bad alternative. Using modules in separate files
19
+ # means tedious sifting to get a big-picture view.
20
+ #
21
+ # = Dissatisfying ways to separate small concerns
22
+ #
23
+ # == Using comments:
24
+ #
25
+ # class Todo < ApplicationRecord
26
+ # # Other todo implementation
27
+ # # ...
28
+ #
29
+ # ## Event tracking
30
+ # has_many :events
31
+ #
32
+ # before_create :track_creation
33
+ #
34
+ # private
35
+ # def track_creation
36
+ # # ...
37
+ # end
38
+ # end
39
+ #
40
+ # == With an inline module:
41
+ #
42
+ # Noisy syntax.
43
+ #
44
+ # class Todo < ApplicationRecord
45
+ # # Other todo implementation
46
+ # # ...
47
+ #
48
+ # module EventTracking
49
+ # extend ActiveSupport::Concern
50
+ #
51
+ # included do
52
+ # has_many :events
53
+ # before_create :track_creation
54
+ # end
55
+ #
56
+ # private
57
+ # def track_creation
58
+ # # ...
59
+ # end
60
+ # end
61
+ # include EventTracking
62
+ # end
63
+ #
64
+ # == Mix-in noise exiled to its own file:
65
+ #
66
+ # Once our chunk of behavior starts pushing the scroll-to-understand-it
67
+ # boundary, we give in and move it to a separate file. At this size, the
68
+ # increased overhead can be a reasonable tradeoff even if it reduces our
69
+ # at-a-glance perception of how things work.
70
+ #
71
+ # class Todo < ApplicationRecord
72
+ # # Other todo implementation
73
+ # # ...
74
+ #
75
+ # include TodoEventTracking
76
+ # end
77
+ #
78
+ # = Introducing Module#concerning
79
+ #
80
+ # By quieting the mix-in noise, we arrive at a natural, low-ceremony way to
81
+ # separate bite-sized concerns.
82
+ #
83
+ # class Todo < ApplicationRecord
84
+ # # Other todo implementation
85
+ # # ...
86
+ #
87
+ # concerning :EventTracking do
88
+ # included do
89
+ # has_many :events
90
+ # before_create :track_creation
91
+ # end
92
+ #
93
+ # private
94
+ # def track_creation
95
+ # # ...
96
+ # end
97
+ # end
98
+ # end
99
+ #
100
+ # Todo.ancestors
101
+ # # => [Todo, Todo::EventTracking, ApplicationRecord, Object]
102
+ #
103
+ # This small step has some wonderful ripple effects. We can
104
+ # * grok the behavior of our class in one glance,
105
+ # * clean up monolithic junk-drawer classes by separating their concerns, and
106
+ # * stop leaning on protected/private for crude "this is internal stuff" modularity.
107
+ module Concerning
108
+ # Define a new concern and mix it in.
109
+ def concerning(topic, &block)
110
+ include concern(topic, &block)
111
+ end
112
+
113
+ # A low-cruft shortcut to define a concern.
114
+ #
115
+ # concern :EventTracking do
116
+ # ...
117
+ # end
118
+ #
119
+ # is equivalent to
120
+ #
121
+ # module EventTracking
122
+ # extend ActiveSupport::Concern
123
+ #
124
+ # ...
125
+ # end
126
+ def concern(topic, &module_definition)
127
+ const_set topic, Module.new {
128
+ extend ::ActiveSupport::Concern
129
+ module_eval(&module_definition)
130
+ }
131
+ end
132
+ end
133
+ include Concerning
134
+ end
@@ -0,0 +1,313 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+
5
+ class Module
6
+ # Error generated by +delegate+ when a method is called on +nil+ and +allow_nil+
7
+ # option is not used.
8
+ class DelegationError < NoMethodError; end
9
+
10
+ RUBY_RESERVED_KEYWORDS = %w(alias and BEGIN begin break case class def defined? do
11
+ else elsif END end ensure false for if in module next nil not or redo rescue retry
12
+ return self super then true undef unless until when while yield)
13
+ DELEGATION_RESERVED_KEYWORDS = %w(_ arg args block)
14
+ DELEGATION_RESERVED_METHOD_NAMES = Set.new(
15
+ RUBY_RESERVED_KEYWORDS + DELEGATION_RESERVED_KEYWORDS
16
+ ).freeze
17
+
18
+ # Provides a +delegate+ class method to easily expose contained objects'
19
+ # public methods as your own.
20
+ #
21
+ # ==== Options
22
+ # * <tt>:to</tt> - Specifies the target object name as a symbol or string
23
+ # * <tt>:prefix</tt> - Prefixes the new method with the target name or a custom prefix
24
+ # * <tt>:allow_nil</tt> - If set to true, prevents a +Module::DelegationError+
25
+ # from being raised
26
+ # * <tt>:private</tt> - If set to true, changes method visibility to private
27
+ #
28
+ # The macro receives one or more method names (specified as symbols or
29
+ # strings) and the name of the target object via the <tt>:to</tt> option
30
+ # (also a symbol or string).
31
+ #
32
+ # Delegation is particularly useful with Active Record associations:
33
+ #
34
+ # class Greeter < ActiveRecord::Base
35
+ # def hello
36
+ # 'hello'
37
+ # end
38
+ #
39
+ # def goodbye
40
+ # 'goodbye'
41
+ # end
42
+ # end
43
+ #
44
+ # class Foo < ActiveRecord::Base
45
+ # belongs_to :greeter
46
+ # delegate :hello, to: :greeter
47
+ # end
48
+ #
49
+ # Foo.new.hello # => "hello"
50
+ # Foo.new.goodbye # => NoMethodError: undefined method `goodbye' for #<Foo:0x1af30c>
51
+ #
52
+ # Multiple delegates to the same target are allowed:
53
+ #
54
+ # class Foo < ActiveRecord::Base
55
+ # belongs_to :greeter
56
+ # delegate :hello, :goodbye, to: :greeter
57
+ # end
58
+ #
59
+ # Foo.new.goodbye # => "goodbye"
60
+ #
61
+ # Methods can be delegated to instance variables, class variables, or constants
62
+ # by providing them as a symbols:
63
+ #
64
+ # class Foo
65
+ # CONSTANT_ARRAY = [0,1,2,3]
66
+ # @@class_array = [4,5,6,7]
67
+ #
68
+ # def initialize
69
+ # @instance_array = [8,9,10,11]
70
+ # end
71
+ # delegate :sum, to: :CONSTANT_ARRAY
72
+ # delegate :min, to: :@@class_array
73
+ # delegate :max, to: :@instance_array
74
+ # end
75
+ #
76
+ # Foo.new.sum # => 6
77
+ # Foo.new.min # => 4
78
+ # Foo.new.max # => 11
79
+ #
80
+ # It's also possible to delegate a method to the class by using +:class+:
81
+ #
82
+ # class Foo
83
+ # def self.hello
84
+ # "world"
85
+ # end
86
+ #
87
+ # delegate :hello, to: :class
88
+ # end
89
+ #
90
+ # Foo.new.hello # => "world"
91
+ #
92
+ # Delegates can optionally be prefixed using the <tt>:prefix</tt> option. If the value
93
+ # is <tt>true</tt>, the delegate methods are prefixed with the name of the object being
94
+ # delegated to.
95
+ #
96
+ # Person = Struct.new(:name, :address)
97
+ #
98
+ # class Invoice < Struct.new(:client)
99
+ # delegate :name, :address, to: :client, prefix: true
100
+ # end
101
+ #
102
+ # john_doe = Person.new('John Doe', 'Vimmersvej 13')
103
+ # invoice = Invoice.new(john_doe)
104
+ # invoice.client_name # => "John Doe"
105
+ # invoice.client_address # => "Vimmersvej 13"
106
+ #
107
+ # It is also possible to supply a custom prefix.
108
+ #
109
+ # class Invoice < Struct.new(:client)
110
+ # delegate :name, :address, to: :client, prefix: :customer
111
+ # end
112
+ #
113
+ # invoice = Invoice.new(john_doe)
114
+ # invoice.customer_name # => 'John Doe'
115
+ # invoice.customer_address # => 'Vimmersvej 13'
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
+ #
134
+ # If the target is +nil+ and does not respond to the delegated method a
135
+ # +Module::DelegationError+ is raised. If you wish to instead return +nil+,
136
+ # use the <tt>:allow_nil</tt> option.
137
+ #
138
+ # class User < ActiveRecord::Base
139
+ # has_one :profile
140
+ # delegate :age, to: :profile
141
+ # end
142
+ #
143
+ # User.new.age
144
+ # # => Module::DelegationError: User#age delegated to profile.age, but profile is nil
145
+ #
146
+ # But if not having a profile yet is fine and should not be an error
147
+ # condition:
148
+ #
149
+ # class User < ActiveRecord::Base
150
+ # has_one :profile
151
+ # delegate :age, to: :profile, allow_nil: true
152
+ # end
153
+ #
154
+ # User.new.age # nil
155
+ #
156
+ # Note that if the target is not +nil+ then the call is attempted regardless of the
157
+ # <tt>:allow_nil</tt> option, and thus an exception is still raised if said object
158
+ # does not respond to the method:
159
+ #
160
+ # class Foo
161
+ # def initialize(bar)
162
+ # @bar = bar
163
+ # end
164
+ #
165
+ # delegate :name, to: :@bar, allow_nil: true
166
+ # end
167
+ #
168
+ # Foo.new("Bar").name # raises NoMethodError: undefined method `name'
169
+ #
170
+ # The target method must be public, otherwise it will raise +NoMethodError+.
171
+ def delegate(*methods, to: nil, prefix: nil, allow_nil: nil, private: nil)
172
+ unless to
173
+ raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter)."
174
+ end
175
+
176
+ if prefix == true && /^[^a-z_]/.match?(to)
177
+ raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
178
+ end
179
+
180
+ method_prefix = \
181
+ if prefix
182
+ "#{prefix == true ? to : prefix}_"
183
+ else
184
+ ""
185
+ end
186
+
187
+ location = caller_locations(1, 1).first
188
+ file, line = location.path, location.lineno
189
+
190
+ to = to.to_s
191
+ to = "self.#{to}" if DELEGATION_RESERVED_METHOD_NAMES.include?(to)
192
+
193
+ method_names = methods.map do |method|
194
+ # Attribute writer methods only accept one argument. Makes sure []=
195
+ # methods still accept two arguments.
196
+ definition = /[^\]]=$/.match?(method) ? "arg" : "*args, &block"
197
+
198
+ # The following generated method calls the target exactly once, storing
199
+ # the returned value in a dummy variable.
200
+ #
201
+ # Reason is twofold: On one hand doing less calls is in general better.
202
+ # On the other hand it could be that the target has side-effects,
203
+ # whereas conceptually, from the user point of view, the delegator should
204
+ # be doing one call.
205
+ if allow_nil
206
+ method_def = [
207
+ "def #{method_prefix}#{method}(#{definition})",
208
+ "_ = #{to}",
209
+ "if !_.nil? || nil.respond_to?(:#{method})",
210
+ " _.#{method}(#{definition})",
211
+ "end",
212
+ "end"
213
+ ].join ";"
214
+ else
215
+ exception = %(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
216
+
217
+ method_def = [
218
+ "def #{method_prefix}#{method}(#{definition})",
219
+ " _ = #{to}",
220
+ " _.#{method}(#{definition})",
221
+ "rescue NoMethodError => e",
222
+ " if _.nil? && e.name == :#{method}",
223
+ " #{exception}",
224
+ " else",
225
+ " raise",
226
+ " end",
227
+ "end"
228
+ ].join ";"
229
+ end
230
+
231
+ module_eval(method_def, file, line)
232
+ end
233
+
234
+ private(*method_names) if private
235
+ method_names
236
+ end
237
+
238
+ # When building decorators, a common pattern may emerge:
239
+ #
240
+ # class Partition
241
+ # def initialize(event)
242
+ # @event = event
243
+ # end
244
+ #
245
+ # def person
246
+ # detail.person || creator
247
+ # end
248
+ #
249
+ # private
250
+ # def respond_to_missing?(name, include_private = false)
251
+ # @event.respond_to?(name, include_private)
252
+ # end
253
+ #
254
+ # def method_missing(method, *args, &block)
255
+ # @event.send(method, *args, &block)
256
+ # end
257
+ # end
258
+ #
259
+ # With <tt>Module#delegate_missing_to</tt>, the above is condensed to:
260
+ #
261
+ # class Partition
262
+ # delegate_missing_to :@event
263
+ #
264
+ # def initialize(event)
265
+ # @event = event
266
+ # end
267
+ #
268
+ # def person
269
+ # detail.person || creator
270
+ # end
271
+ # end
272
+ #
273
+ # The target can be anything callable within the object, e.g. instance
274
+ # variables, methods, constants, etc.
275
+ #
276
+ # The delegated method must be public on the target, otherwise it will
277
+ # raise +NoMethodError+.
278
+ #
279
+ # The <tt>marshal_dump</tt> and <tt>_dump</tt> methods are exempt from
280
+ # delegation due to possible interference when calling
281
+ # <tt>Marshal.dump(object)</tt>, should the delegation target method
282
+ # of <tt>object</tt> add or remove instance variables.
283
+ def delegate_missing_to(target)
284
+ target = target.to_s
285
+ target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target)
286
+
287
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
288
+ def respond_to_missing?(name, include_private = false)
289
+ # It may look like an oversight, but we deliberately do not pass
290
+ # +include_private+, because they do not get delegated.
291
+
292
+ return false if name == :marshal_dump || name == :_dump
293
+ #{target}.respond_to?(name) || super
294
+ end
295
+
296
+ def method_missing(method, *args, &block)
297
+ if #{target}.respond_to?(method)
298
+ #{target}.public_send(method, *args, &block)
299
+ else
300
+ begin
301
+ super
302
+ rescue NoMethodError
303
+ if #{target}.nil?
304
+ raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
305
+ else
306
+ raise
307
+ end
308
+ end
309
+ end
310
+ end
311
+ RUBY
312
+ end
313
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Module
4
+ # deprecate :foo
5
+ # deprecate bar: 'message'
6
+ # deprecate :foo, :bar, baz: 'warning!', qux: 'gone!'
7
+ #
8
+ # You can also use custom deprecator instance:
9
+ #
10
+ # deprecate :foo, deprecator: MyLib::Deprecator.new
11
+ # deprecate :foo, bar: "warning!", deprecator: MyLib::Deprecator.new
12
+ #
13
+ # \Custom deprecators must respond to <tt>deprecation_warning(deprecated_method_name, message, caller_backtrace)</tt>
14
+ # method where you can implement your custom warning behavior.
15
+ #
16
+ # class MyLib::Deprecator
17
+ # def deprecation_warning(deprecated_method_name, message, caller_backtrace = nil)
18
+ # message = "#{deprecated_method_name} is deprecated and will be removed from MyLibrary | #{message}"
19
+ # Kernel.warn message
20
+ # end
21
+ # end
22
+ def deprecate(*method_names)
23
+ ActiveSupport::Deprecation.deprecate_methods(self, *method_names)
24
+ end
25
+ end