activesupport 4.2.0 → 5.2.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 (254) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +366 -232
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +4 -5
  5. data/lib/active_support.rb +17 -7
  6. data/lib/active_support/all.rb +5 -3
  7. data/lib/active_support/array_inquirer.rb +48 -0
  8. data/lib/active_support/backtrace_cleaner.rb +7 -5
  9. data/lib/active_support/benchmarkable.rb +6 -4
  10. data/lib/active_support/builder.rb +3 -1
  11. data/lib/active_support/cache.rb +271 -177
  12. data/lib/active_support/cache/file_store.rb +41 -35
  13. data/lib/active_support/cache/mem_cache_store.rb +97 -88
  14. data/lib/active_support/cache/memory_store.rb +27 -30
  15. data/lib/active_support/cache/null_store.rb +7 -8
  16. data/lib/active_support/cache/redis_cache_store.rb +454 -0
  17. data/lib/active_support/cache/strategy/local_cache.rb +67 -34
  18. data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
  19. data/lib/active_support/callbacks.rb +654 -560
  20. data/lib/active_support/concern.rb +5 -3
  21. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +17 -0
  22. data/lib/active_support/concurrency/share_lock.rb +227 -0
  23. data/lib/active_support/configurable.rb +8 -5
  24. data/lib/active_support/core_ext.rb +3 -1
  25. data/lib/active_support/core_ext/array.rb +9 -6
  26. data/lib/active_support/core_ext/array/access.rb +29 -1
  27. data/lib/active_support/core_ext/array/conversions.rb +22 -18
  28. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  29. data/lib/active_support/core_ext/array/grouping.rb +11 -18
  30. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  31. data/lib/active_support/core_ext/array/prepend_and_append.rb +5 -3
  32. data/lib/active_support/core_ext/array/wrap.rb +7 -4
  33. data/lib/active_support/core_ext/benchmark.rb +3 -1
  34. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  35. data/lib/active_support/core_ext/big_decimal/conversions.rb +10 -12
  36. data/lib/active_support/core_ext/class.rb +4 -3
  37. data/lib/active_support/core_ext/class/attribute.rb +41 -22
  38. data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
  39. data/lib/active_support/core_ext/class/subclasses.rb +20 -8
  40. data/lib/active_support/core_ext/date.rb +6 -4
  41. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  42. data/lib/active_support/core_ext/date/blank.rb +14 -0
  43. data/lib/active_support/core_ext/date/calculations.rb +11 -9
  44. data/lib/active_support/core_ext/date/conversions.rb +31 -23
  45. data/lib/active_support/core_ext/date/zones.rb +4 -2
  46. data/lib/active_support/core_ext/date_and_time/calculations.rb +179 -56
  47. data/lib/active_support/core_ext/date_and_time/compatibility.rb +16 -0
  48. data/lib/active_support/core_ext/date_and_time/zones.rb +12 -12
  49. data/lib/active_support/core_ext/date_time.rb +7 -4
  50. data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
  51. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  52. data/lib/active_support/core_ext/date_time/calculations.rb +58 -20
  53. data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
  54. data/lib/active_support/core_ext/date_time/conversions.rb +16 -12
  55. data/lib/active_support/core_ext/digest/uuid.rb +7 -5
  56. data/lib/active_support/core_ext/enumerable.rb +107 -28
  57. data/lib/active_support/core_ext/file.rb +3 -1
  58. data/lib/active_support/core_ext/file/atomic.rb +38 -31
  59. data/lib/active_support/core_ext/hash.rb +11 -9
  60. data/lib/active_support/core_ext/hash/compact.rb +24 -15
  61. data/lib/active_support/core_ext/hash/conversions.rb +63 -43
  62. data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
  63. data/lib/active_support/core_ext/hash/except.rb +11 -8
  64. data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -3
  65. data/lib/active_support/core_ext/hash/keys.rb +33 -27
  66. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  67. data/lib/active_support/core_ext/hash/slice.rb +8 -8
  68. data/lib/active_support/core_ext/hash/transform_values.rb +16 -7
  69. data/lib/active_support/core_ext/integer.rb +5 -3
  70. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  71. data/lib/active_support/core_ext/integer/multiple.rb +2 -0
  72. data/lib/active_support/core_ext/integer/time.rb +11 -33
  73. data/lib/active_support/core_ext/kernel.rb +6 -5
  74. data/lib/active_support/core_ext/kernel/agnostics.rb +2 -0
  75. data/lib/active_support/core_ext/kernel/concern.rb +5 -1
  76. data/lib/active_support/core_ext/kernel/reporting.rb +4 -83
  77. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  78. data/lib/active_support/core_ext/load_error.rb +3 -22
  79. data/lib/active_support/core_ext/marshal.rb +13 -10
  80. data/lib/active_support/core_ext/module.rb +14 -11
  81. data/lib/active_support/core_ext/module/aliasing.rb +6 -44
  82. data/lib/active_support/core_ext/module/anonymous.rb +12 -1
  83. data/lib/active_support/core_ext/module/attr_internal.rb +8 -9
  84. data/lib/active_support/core_ext/module/attribute_accessors.rb +43 -40
  85. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +150 -0
  86. data/lib/active_support/core_ext/module/concerning.rb +11 -12
  87. data/lib/active_support/core_ext/module/delegation.rb +121 -39
  88. data/lib/active_support/core_ext/module/deprecation.rb +4 -2
  89. data/lib/active_support/core_ext/module/introspection.rb +9 -9
  90. data/lib/active_support/core_ext/module/reachable.rb +5 -2
  91. data/lib/active_support/core_ext/module/redefine_method.rb +49 -0
  92. data/lib/active_support/core_ext/module/remove_method.rb +8 -3
  93. data/lib/active_support/core_ext/name_error.rb +22 -2
  94. data/lib/active_support/core_ext/numeric.rb +6 -3
  95. data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
  96. data/lib/active_support/core_ext/numeric/conversions.rb +79 -74
  97. data/lib/active_support/core_ext/numeric/inquiry.rb +28 -0
  98. data/lib/active_support/core_ext/numeric/time.rb +35 -38
  99. data/lib/active_support/core_ext/object.rb +14 -13
  100. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  101. data/lib/active_support/core_ext/object/blank.rb +29 -4
  102. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  103. data/lib/active_support/core_ext/object/deep_dup.rb +13 -4
  104. data/lib/active_support/core_ext/object/duplicable.rb +98 -45
  105. data/lib/active_support/core_ext/object/inclusion.rb +5 -3
  106. data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
  107. data/lib/active_support/core_ext/object/json.rb +49 -19
  108. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  109. data/lib/active_support/core_ext/object/to_query.rb +6 -4
  110. data/lib/active_support/core_ext/object/try.rb +70 -22
  111. data/lib/active_support/core_ext/object/with_options.rb +16 -3
  112. data/lib/active_support/core_ext/range.rb +7 -4
  113. data/lib/active_support/core_ext/range/conversions.rb +27 -7
  114. data/lib/active_support/core_ext/range/each.rb +19 -17
  115. data/lib/active_support/core_ext/range/include_range.rb +21 -19
  116. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  117. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  118. data/lib/active_support/core_ext/regexp.rb +6 -0
  119. data/lib/active_support/core_ext/securerandom.rb +25 -0
  120. data/lib/active_support/core_ext/string.rb +15 -13
  121. data/lib/active_support/core_ext/string/access.rb +9 -7
  122. data/lib/active_support/core_ext/string/behavior.rb +3 -1
  123. data/lib/active_support/core_ext/string/conversions.rb +8 -5
  124. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  125. data/lib/active_support/core_ext/string/filters.rb +10 -8
  126. data/lib/active_support/core_ext/string/indent.rb +6 -4
  127. data/lib/active_support/core_ext/string/inflections.rb +61 -24
  128. data/lib/active_support/core_ext/string/inquiry.rb +3 -1
  129. data/lib/active_support/core_ext/string/multibyte.rb +15 -7
  130. data/lib/active_support/core_ext/string/output_safety.rb +35 -35
  131. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -0
  132. data/lib/active_support/core_ext/string/strip.rb +4 -5
  133. data/lib/active_support/core_ext/string/zones.rb +4 -2
  134. data/lib/active_support/core_ext/time.rb +7 -5
  135. data/lib/active_support/core_ext/time/acts_like.rb +3 -1
  136. data/lib/active_support/core_ext/time/calculations.rb +101 -51
  137. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  138. data/lib/active_support/core_ext/time/conversions.rb +20 -13
  139. data/lib/active_support/core_ext/time/zones.rb +41 -7
  140. data/lib/active_support/core_ext/uri.rb +5 -4
  141. data/lib/active_support/current_attributes.rb +195 -0
  142. data/lib/active_support/dependencies.rb +143 -160
  143. data/lib/active_support/dependencies/autoload.rb +2 -0
  144. data/lib/active_support/dependencies/interlock.rb +57 -0
  145. data/lib/active_support/deprecation.rb +12 -9
  146. data/lib/active_support/deprecation/behaviors.rb +41 -12
  147. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  148. data/lib/active_support/deprecation/instance_delegator.rb +17 -2
  149. data/lib/active_support/deprecation/method_wrappers.rb +54 -21
  150. data/lib/active_support/deprecation/proxy_wrappers.rb +56 -28
  151. data/lib/active_support/deprecation/reporting.rb +32 -12
  152. data/lib/active_support/descendants_tracker.rb +2 -0
  153. data/lib/active_support/digest.rb +20 -0
  154. data/lib/active_support/duration.rb +326 -30
  155. data/lib/active_support/duration/iso8601_parser.rb +125 -0
  156. data/lib/active_support/duration/iso8601_serializer.rb +55 -0
  157. data/lib/active_support/encrypted_configuration.rb +49 -0
  158. data/lib/active_support/encrypted_file.rb +99 -0
  159. data/lib/active_support/evented_file_update_checker.rb +205 -0
  160. data/lib/active_support/execution_wrapper.rb +128 -0
  161. data/lib/active_support/executor.rb +8 -0
  162. data/lib/active_support/file_update_checker.rb +63 -37
  163. data/lib/active_support/gem_version.rb +4 -2
  164. data/lib/active_support/gzip.rb +7 -5
  165. data/lib/active_support/hash_with_indifferent_access.rb +130 -30
  166. data/lib/active_support/i18n.rb +8 -6
  167. data/lib/active_support/i18n_railtie.rb +34 -14
  168. data/lib/active_support/inflections.rb +13 -11
  169. data/lib/active_support/inflector.rb +7 -5
  170. data/lib/active_support/inflector/inflections.rb +61 -12
  171. data/lib/active_support/inflector/methods.rb +161 -136
  172. data/lib/active_support/inflector/transliterate.rb +48 -27
  173. data/lib/active_support/json.rb +4 -2
  174. data/lib/active_support/json/decoding.rb +16 -13
  175. data/lib/active_support/json/encoding.rb +15 -57
  176. data/lib/active_support/key_generator.rb +25 -25
  177. data/lib/active_support/lazy_load_hooks.rb +50 -20
  178. data/lib/active_support/locale/en.yml +2 -0
  179. data/lib/active_support/log_subscriber.rb +13 -10
  180. data/lib/active_support/log_subscriber/test_helper.rb +14 -12
  181. data/lib/active_support/logger.rb +54 -3
  182. data/lib/active_support/logger_silence.rb +12 -7
  183. data/lib/active_support/logger_thread_safe_level.rb +33 -0
  184. data/lib/active_support/message_encryptor.rb +173 -51
  185. data/lib/active_support/message_verifier.rb +150 -17
  186. data/lib/active_support/messages/metadata.rb +71 -0
  187. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  188. data/lib/active_support/messages/rotator.rb +56 -0
  189. data/lib/active_support/multibyte.rb +4 -2
  190. data/lib/active_support/multibyte/chars.rb +37 -24
  191. data/lib/active_support/multibyte/unicode.rb +100 -96
  192. data/lib/active_support/notifications.rb +11 -7
  193. data/lib/active_support/notifications/fanout.rb +10 -8
  194. data/lib/active_support/notifications/instrumenter.rb +27 -7
  195. data/lib/active_support/number_helper.rb +94 -68
  196. data/lib/active_support/number_helper/number_converter.rb +13 -11
  197. data/lib/active_support/number_helper/number_to_currency_converter.rb +9 -9
  198. data/lib/active_support/number_helper/number_to_delimited_converter.rb +9 -3
  199. data/lib/active_support/number_helper/number_to_human_converter.rb +11 -9
  200. data/lib/active_support/number_helper/number_to_human_size_converter.rb +9 -8
  201. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  202. data/lib/active_support/number_helper/number_to_phone_converter.rb +13 -4
  203. data/lib/active_support/number_helper/number_to_rounded_converter.rb +23 -56
  204. data/lib/active_support/number_helper/rounding_helper.rb +66 -0
  205. data/lib/active_support/option_merger.rb +3 -1
  206. data/lib/active_support/ordered_hash.rb +6 -4
  207. data/lib/active_support/ordered_options.rb +22 -4
  208. data/lib/active_support/per_thread_registry.rb +13 -6
  209. data/lib/active_support/proxy_object.rb +2 -0
  210. data/lib/active_support/rails.rb +16 -8
  211. data/lib/active_support/railtie.rb +43 -9
  212. data/lib/active_support/reloader.rb +131 -0
  213. data/lib/active_support/rescuable.rb +108 -53
  214. data/lib/active_support/security_utils.rb +17 -6
  215. data/lib/active_support/string_inquirer.rb +11 -3
  216. data/lib/active_support/subscriber.rb +15 -14
  217. data/lib/active_support/tagged_logging.rb +14 -11
  218. data/lib/active_support/test_case.rb +18 -46
  219. data/lib/active_support/testing/assertions.rb +137 -20
  220. data/lib/active_support/testing/autorun.rb +4 -2
  221. data/lib/active_support/testing/constant_lookup.rb +2 -1
  222. data/lib/active_support/testing/declarative.rb +3 -1
  223. data/lib/active_support/testing/deprecation.rb +14 -10
  224. data/lib/active_support/testing/file_fixtures.rb +36 -0
  225. data/lib/active_support/testing/isolation.rb +34 -25
  226. data/lib/active_support/testing/method_call_assertions.rb +43 -0
  227. data/lib/active_support/testing/setup_and_teardown.rb +12 -3
  228. data/lib/active_support/testing/stream.rb +44 -0
  229. data/lib/active_support/testing/tagged_logging.rb +3 -1
  230. data/lib/active_support/testing/time_helpers.rb +96 -27
  231. data/lib/active_support/time.rb +14 -12
  232. data/lib/active_support/time_with_zone.rb +195 -53
  233. data/lib/active_support/values/time_zone.rb +200 -61
  234. data/lib/active_support/values/unicode_tables.dat +0 -0
  235. data/lib/active_support/version.rb +3 -1
  236. data/lib/active_support/xml_mini.rb +69 -51
  237. data/lib/active_support/xml_mini/jdom.rb +116 -113
  238. data/lib/active_support/xml_mini/libxml.rb +17 -16
  239. data/lib/active_support/xml_mini/libxmlsax.rb +16 -18
  240. data/lib/active_support/xml_mini/nokogiri.rb +15 -15
  241. data/lib/active_support/xml_mini/nokogirisax.rb +15 -16
  242. data/lib/active_support/xml_mini/rexml.rb +17 -16
  243. metadata +55 -43
  244. data/lib/active_support/concurrency/latch.rb +0 -27
  245. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -14
  246. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  247. data/lib/active_support/core_ext/date_time/zones.rb +0 -6
  248. data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
  249. data/lib/active_support/core_ext/module/method_transplanting.rb +0 -11
  250. data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
  251. data/lib/active_support/core_ext/object/itself.rb +0 -15
  252. data/lib/active_support/core_ext/struct.rb +0 -6
  253. data/lib/active_support/core_ext/thread.rb +0 -86
  254. data/lib/active_support/core_ext/time/marshal.rb +0 -30
@@ -1,4 +1,6 @@
1
- require 'active_support/concern'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
2
4
 
3
5
  class Module
4
6
  # = Bite-sized separation of concerns
@@ -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
@@ -63,12 +63,12 @@ class Module
63
63
  #
64
64
  # == Mix-in noise exiled to its own file:
65
65
  #
66
- # Once our chunk of behavior starts pushing the scroll-to-understand it's
66
+ # Once our chunk of behavior starts pushing the scroll-to-understand-it
67
67
  # boundary, we give in and move it to a separate file. At this size, the
68
- # overhead feels in good proportion to the size of our extraction, despite
69
- # diluting our at-a-glance sense of how things really work.
68
+ # increased overhead can be a reasonable tradeoff even if it reduces our
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,7 +98,7 @@ 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,
@@ -1,14 +1,19 @@
1
- require 'set'
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+ require "active_support/core_ext/regexp"
2
5
 
3
6
  class Module
4
7
  # Error generated by +delegate+ when a method is called on +nil+ and +allow_nil+
5
8
  # option is not used.
6
9
  class DelegationError < NoMethodError; end
7
10
 
8
- RUBY_RESERVED_WORDS = Set.new(
9
- %w(alias and BEGIN begin break case class def defined? do else elsif END
10
- end ensure false for if in module next nil not or redo rescue retry
11
- return self super then true undef unless until when while yield)
11
+ RUBY_RESERVED_KEYWORDS = %w(alias and BEGIN begin break case class def defined? do
12
+ else elsif END end ensure false for if in module next nil not or redo rescue retry
13
+ return self super then true undef unless until when while yield)
14
+ DELEGATION_RESERVED_KEYWORDS = %w(_ arg args block)
15
+ DELEGATION_RESERVED_METHOD_NAMES = Set.new(
16
+ RUBY_RESERVED_KEYWORDS + DELEGATION_RESERVED_KEYWORDS
12
17
  ).freeze
13
18
 
14
19
  # Provides a +delegate+ class method to easily expose contained objects'
@@ -17,7 +22,8 @@ class Module
17
22
  # ==== Options
18
23
  # * <tt>:to</tt> - Specifies the target object
19
24
  # * <tt>:prefix</tt> - Prefixes the new method with the target name or a custom prefix
20
- # * <tt>:allow_nil</tt> - if set to true, prevents a +NoMethodError+ to be raised
25
+ # * <tt>:allow_nil</tt> - if set to true, prevents a +Module::DelegationError+
26
+ # from being raised
21
27
  #
22
28
  # The macro receives one or more method names (specified as symbols or
23
29
  # strings) and the name of the target object via the <tt>:to</tt> option
@@ -109,18 +115,16 @@ class Module
109
115
  # invoice.customer_address # => 'Vimmersvej 13'
110
116
  #
111
117
  # If the target is +nil+ and does not respond to the delegated method a
112
- # +NoMethodError+ is raised, as with any other value. Sometimes, however, it
113
- # makes sense to be robust to that situation and that is the purpose of the
114
- # <tt>:allow_nil</tt> option: If the target is not +nil+, or it is and
115
- # responds to the method, everything works as usual. But if it is +nil+ and
116
- # does not respond to the delegated method, +nil+ is returned.
118
+ # +Module::DelegationError+ is raised. If you wish to instead return +nil+,
119
+ # use the <tt>:allow_nil</tt> option.
117
120
  #
118
121
  # class User < ActiveRecord::Base
119
122
  # has_one :profile
120
123
  # delegate :age, to: :profile
121
124
  # end
122
125
  #
123
- # User.new.age # raises NoMethodError: undefined method `age'
126
+ # User.new.age
127
+ # # => Module::DelegationError: User#age delegated to profile.age, but profile is nil
124
128
  #
125
129
  # But if not having a profile yet is fine and should not be an error
126
130
  # condition:
@@ -147,36 +151,32 @@ class Module
147
151
  # Foo.new("Bar").name # raises NoMethodError: undefined method `name'
148
152
  #
149
153
  # The target method must be public, otherwise it will raise +NoMethodError+.
150
- #
151
- def delegate(*methods)
152
- options = methods.pop
153
- unless options.is_a?(Hash) && to = options[:to]
154
- raise ArgumentError, 'Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter).'
154
+ def delegate(*methods, to: nil, prefix: nil, allow_nil: nil)
155
+ unless to
156
+ raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter)."
155
157
  end
156
158
 
157
- prefix, allow_nil = options.values_at(:prefix, :allow_nil)
158
-
159
- if prefix == true && to =~ /^[^a-z_]/
160
- raise ArgumentError, 'Can only automatically set the delegation prefix when delegating to a method.'
159
+ if prefix == true && /^[^a-z_]/.match?(to)
160
+ raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
161
161
  end
162
162
 
163
163
  method_prefix = \
164
164
  if prefix
165
165
  "#{prefix == true ? to : prefix}_"
166
166
  else
167
- ''
167
+ ""
168
168
  end
169
169
 
170
- file, line = caller.first.split(':', 2)
171
- line = line.to_i
170
+ location = caller_locations(1, 1).first
171
+ file, line = location.path, location.lineno
172
172
 
173
173
  to = to.to_s
174
- to = "self.#{to}" if RUBY_RESERVED_WORDS.include?(to)
174
+ to = "self.#{to}" if DELEGATION_RESERVED_METHOD_NAMES.include?(to)
175
175
 
176
- methods.each do |method|
176
+ methods.map do |method|
177
177
  # Attribute writer methods only accept one argument. Makes sure []=
178
178
  # methods still accept two arguments.
179
- definition = (method =~ /[^\]]=$/) ? 'arg' : '*args, &block'
179
+ definition = /[^\]]=$/.match?(method) ? "arg" : "*args, &block"
180
180
 
181
181
  # The following generated method calls the target exactly once, storing
182
182
  # the returned value in a dummy variable.
@@ -185,21 +185,103 @@ class Module
185
185
  # On the other hand it could be that the target has side-effects,
186
186
  # whereas conceptually, from the user point of view, the delegator should
187
187
  # be doing one call.
188
-
189
- exception = %(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
190
-
191
- method_def = [
192
- "def #{method_prefix}#{method}(#{definition})",
193
- " _ = #{to}",
194
- " if !_.nil? || nil.respond_to?(:#{method})",
195
- " _.#{method}(#{definition})",
196
- " else",
197
- " #{exception unless allow_nil}",
198
- " end",
188
+ if allow_nil
189
+ method_def = [
190
+ "def #{method_prefix}#{method}(#{definition})",
191
+ "_ = #{to}",
192
+ "if !_.nil? || nil.respond_to?(:#{method})",
193
+ " _.#{method}(#{definition})",
194
+ "end",
199
195
  "end"
200
- ].join ';'
196
+ ].join ";"
197
+ else
198
+ exception = %(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
199
+
200
+ method_def = [
201
+ "def #{method_prefix}#{method}(#{definition})",
202
+ " _ = #{to}",
203
+ " _.#{method}(#{definition})",
204
+ "rescue NoMethodError => e",
205
+ " if _.nil? && e.name == :#{method}",
206
+ " #{exception}",
207
+ " else",
208
+ " raise",
209
+ " end",
210
+ "end"
211
+ ].join ";"
212
+ end
201
213
 
202
214
  module_eval(method_def, file, line)
203
215
  end
204
216
  end
217
+
218
+ # When building decorators, a common pattern may emerge:
219
+ #
220
+ # class Partition
221
+ # def initialize(event)
222
+ # @event = event
223
+ # end
224
+ #
225
+ # def person
226
+ # @event.detail.person || @event.creator
227
+ # end
228
+ #
229
+ # private
230
+ # def respond_to_missing?(name, include_private = false)
231
+ # @event.respond_to?(name, include_private)
232
+ # end
233
+ #
234
+ # def method_missing(method, *args, &block)
235
+ # @event.send(method, *args, &block)
236
+ # end
237
+ # end
238
+ #
239
+ # With <tt>Module#delegate_missing_to</tt>, the above is condensed to:
240
+ #
241
+ # class Partition
242
+ # delegate_missing_to :@event
243
+ #
244
+ # def initialize(event)
245
+ # @event = event
246
+ # end
247
+ #
248
+ # def person
249
+ # @event.detail.person || @event.creator
250
+ # end
251
+ # end
252
+ #
253
+ # The target can be anything callable within the object, e.g. instance
254
+ # variables, methods, constants, etc.
255
+ #
256
+ # The delegated method must be public on the target, otherwise it will
257
+ # raise +NoMethodError+.
258
+ def delegate_missing_to(target)
259
+ target = target.to_s
260
+ target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target)
261
+
262
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
263
+ def respond_to_missing?(name, include_private = false)
264
+ # It may look like an oversight, but we deliberately do not pass
265
+ # +include_private+, because they do not get delegated.
266
+
267
+ #{target}.respond_to?(name) || super
268
+ end
269
+
270
+ def method_missing(method, *args, &block)
271
+ if #{target}.respond_to?(method)
272
+ #{target}.public_send(method, *args, &block)
273
+ else
274
+ begin
275
+ super
276
+ rescue NoMethodError
277
+ if #{target}.nil?
278
+ raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
279
+ else
280
+ raise
281
+ end
282
+ end
283
+ end
284
+ end
285
+ RUBY
286
+ end
205
287
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Module
2
4
  # deprecate :foo
3
5
  # deprecate bar: 'message'
@@ -13,8 +15,8 @@ class Module
13
15
  #
14
16
  # class MyLib::Deprecator
15
17
  # def deprecation_warning(deprecated_method_name, message, caller_backtrace = nil)
16
- # message = "#{deprecated_method_name} is deprecated and will be removed from MyLibrary | #{message}"
17
- # Kernel.warn message
18
+ # message = "#{deprecated_method_name} is deprecated and will be removed from MyLibrary | #{message}"
19
+ # Kernel.warn message
18
20
  # end
19
21
  # end
20
22
  def deprecate(*method_names)
@@ -1,14 +1,18 @@
1
- require 'active_support/inflector'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/inflector"
2
4
 
3
5
  class Module
4
6
  # Returns the name of the module containing this one.
5
7
  #
6
8
  # M::N.parent_name # => "M"
7
9
  def parent_name
8
- if defined? @parent_name
10
+ if defined?(@parent_name)
9
11
  @parent_name
10
12
  else
11
- @parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil
13
+ parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil
14
+ @parent_name = parent_name unless frozen?
15
+ parent_name
12
16
  end
13
17
  end
14
18
 
@@ -46,17 +50,13 @@ class Module
46
50
  def parents
47
51
  parents = []
48
52
  if parent_name
49
- parts = parent_name.split('::')
53
+ parts = parent_name.split("::")
50
54
  until parts.empty?
51
- parents << ActiveSupport::Inflector.constantize(parts * '::')
55
+ parents << ActiveSupport::Inflector.constantize(parts * "::")
52
56
  parts.pop
53
57
  end
54
58
  end
55
59
  parents << Object unless parents.include? Object
56
60
  parents
57
61
  end
58
-
59
- def local_constants #:nodoc:
60
- constants(false)
61
- end
62
62
  end
@@ -1,8 +1,11 @@
1
- require 'active_support/core_ext/module/anonymous'
2
- require 'active_support/core_ext/string/inflections'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/anonymous"
4
+ require "active_support/core_ext/string/inflections"
3
5
 
4
6
  class Module
5
7
  def reachable? #:nodoc:
6
8
  !anonymous? && name.safe_constantize.equal?(self)
7
9
  end
10
+ deprecate :reachable?
8
11
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Module
4
+ if RUBY_VERSION >= "2.3"
5
+ # Marks the named method as intended to be redefined, if it exists.
6
+ # Suppresses the Ruby method redefinition warning. Prefer
7
+ # #redefine_method where possible.
8
+ def silence_redefinition_of_method(method)
9
+ if method_defined?(method) || private_method_defined?(method)
10
+ # This suppresses the "method redefined" warning; the self-alias
11
+ # looks odd, but means we don't need to generate a unique name
12
+ alias_method method, method
13
+ end
14
+ end
15
+ else
16
+ def silence_redefinition_of_method(method)
17
+ if method_defined?(method) || private_method_defined?(method)
18
+ alias_method :__rails_redefine, method
19
+ remove_method :__rails_redefine
20
+ end
21
+ end
22
+ end
23
+
24
+ # Replaces the existing method definition, if there is one, with the passed
25
+ # block as its body.
26
+ def redefine_method(method, &block)
27
+ visibility = method_visibility(method)
28
+ silence_redefinition_of_method(method)
29
+ define_method(method, &block)
30
+ send(visibility, method)
31
+ end
32
+
33
+ # Replaces the existing singleton method definition, if there is one, with
34
+ # the passed block as its body.
35
+ def redefine_singleton_method(method, &block)
36
+ singleton_class.redefine_method(method, &block)
37
+ end
38
+
39
+ def method_visibility(method) # :nodoc:
40
+ case
41
+ when private_method_defined?(method)
42
+ :private
43
+ when protected_method_defined?(method)
44
+ :protected
45
+ else
46
+ :public
47
+ end
48
+ end
49
+ end
@@ -1,12 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/redefine_method"
4
+
1
5
  class Module
6
+ # Removes the named method, if it exists.
2
7
  def remove_possible_method(method)
3
8
  if method_defined?(method) || private_method_defined?(method)
4
9
  undef_method(method)
5
10
  end
6
11
  end
7
12
 
8
- def redefine_method(method, &block)
9
- remove_possible_method(method)
10
- define_method(method, &block)
13
+ # Removes the named singleton method, if it exists.
14
+ def remove_possible_singleton_method(method)
15
+ singleton_class.remove_possible_method(method)
11
16
  end
12
17
  end