activesupport 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +572 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +40 -0
  5. data/lib/active_support.rb +96 -0
  6. data/lib/active_support/actionable_error.rb +48 -0
  7. data/lib/active_support/all.rb +5 -0
  8. data/lib/active_support/array_inquirer.rb +48 -0
  9. data/lib/active_support/backtrace_cleaner.rb +132 -0
  10. data/lib/active_support/benchmarkable.rb +51 -0
  11. data/lib/active_support/builder.rb +8 -0
  12. data/lib/active_support/cache.rb +830 -0
  13. data/lib/active_support/cache/file_store.rb +196 -0
  14. data/lib/active_support/cache/mem_cache_store.rb +212 -0
  15. data/lib/active_support/cache/memory_store.rb +174 -0
  16. data/lib/active_support/cache/null_store.rb +48 -0
  17. data/lib/active_support/cache/redis_cache_store.rb +488 -0
  18. data/lib/active_support/cache/strategy/local_cache.rb +194 -0
  19. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  20. data/lib/active_support/callbacks.rb +856 -0
  21. data/lib/active_support/concern.rb +171 -0
  22. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +17 -0
  23. data/lib/active_support/concurrency/share_lock.rb +227 -0
  24. data/lib/active_support/configurable.rb +146 -0
  25. data/lib/active_support/core_ext.rb +5 -0
  26. data/lib/active_support/core_ext/array.rb +9 -0
  27. data/lib/active_support/core_ext/array/access.rb +104 -0
  28. data/lib/active_support/core_ext/array/conversions.rb +213 -0
  29. data/lib/active_support/core_ext/array/extract.rb +21 -0
  30. data/lib/active_support/core_ext/array/extract_options.rb +31 -0
  31. data/lib/active_support/core_ext/array/grouping.rb +109 -0
  32. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  33. data/lib/active_support/core_ext/array/prepend_and_append.rb +5 -0
  34. data/lib/active_support/core_ext/array/wrap.rb +48 -0
  35. data/lib/active_support/core_ext/benchmark.rb +16 -0
  36. data/lib/active_support/core_ext/big_decimal.rb +3 -0
  37. data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
  38. data/lib/active_support/core_ext/class.rb +4 -0
  39. data/lib/active_support/core_ext/class/attribute.rb +141 -0
  40. data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
  41. data/lib/active_support/core_ext/class/subclasses.rb +54 -0
  42. data/lib/active_support/core_ext/date.rb +7 -0
  43. data/lib/active_support/core_ext/date/acts_like.rb +10 -0
  44. data/lib/active_support/core_ext/date/blank.rb +14 -0
  45. data/lib/active_support/core_ext/date/calculations.rb +146 -0
  46. data/lib/active_support/core_ext/date/conversions.rb +96 -0
  47. data/lib/active_support/core_ext/date/zones.rb +8 -0
  48. data/lib/active_support/core_ext/date_and_time/calculations.rb +351 -0
  49. data/lib/active_support/core_ext/date_and_time/compatibility.rb +16 -0
  50. data/lib/active_support/core_ext/date_and_time/zones.rb +41 -0
  51. data/lib/active_support/core_ext/date_time.rb +7 -0
  52. data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
  53. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  54. data/lib/active_support/core_ext/date_time/calculations.rb +211 -0
  55. data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
  56. data/lib/active_support/core_ext/date_time/conversions.rb +107 -0
  57. data/lib/active_support/core_ext/digest.rb +3 -0
  58. data/lib/active_support/core_ext/digest/uuid.rb +53 -0
  59. data/lib/active_support/core_ext/enumerable.rb +188 -0
  60. data/lib/active_support/core_ext/file.rb +3 -0
  61. data/lib/active_support/core_ext/file/atomic.rb +70 -0
  62. data/lib/active_support/core_ext/hash.rb +10 -0
  63. data/lib/active_support/core_ext/hash/compact.rb +5 -0
  64. data/lib/active_support/core_ext/hash/conversions.rb +263 -0
  65. data/lib/active_support/core_ext/hash/deep_merge.rb +34 -0
  66. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  67. data/lib/active_support/core_ext/hash/except.rb +24 -0
  68. data/lib/active_support/core_ext/hash/indifferent_access.rb +24 -0
  69. data/lib/active_support/core_ext/hash/keys.rb +143 -0
  70. data/lib/active_support/core_ext/hash/reverse_merge.rb +25 -0
  71. data/lib/active_support/core_ext/hash/slice.rb +26 -0
  72. data/lib/active_support/core_ext/hash/transform_values.rb +5 -0
  73. data/lib/active_support/core_ext/integer.rb +5 -0
  74. data/lib/active_support/core_ext/integer/inflections.rb +31 -0
  75. data/lib/active_support/core_ext/integer/multiple.rb +12 -0
  76. data/lib/active_support/core_ext/integer/time.rb +22 -0
  77. data/lib/active_support/core_ext/kernel.rb +5 -0
  78. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  79. data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
  80. data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
  81. data/lib/active_support/core_ext/load_error.rb +9 -0
  82. data/lib/active_support/core_ext/marshal.rb +24 -0
  83. data/lib/active_support/core_ext/module.rb +13 -0
  84. data/lib/active_support/core_ext/module/aliasing.rb +31 -0
  85. data/lib/active_support/core_ext/module/anonymous.rb +30 -0
  86. data/lib/active_support/core_ext/module/attr_internal.rb +38 -0
  87. data/lib/active_support/core_ext/module/attribute_accessors.rb +212 -0
  88. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +144 -0
  89. data/lib/active_support/core_ext/module/concerning.rb +134 -0
  90. data/lib/active_support/core_ext/module/delegation.rb +313 -0
  91. data/lib/active_support/core_ext/module/deprecation.rb +25 -0
  92. data/lib/active_support/core_ext/module/introspection.rb +86 -0
  93. data/lib/active_support/core_ext/module/reachable.rb +6 -0
  94. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  95. data/lib/active_support/core_ext/module/remove_method.rb +17 -0
  96. data/lib/active_support/core_ext/name_error.rb +38 -0
  97. data/lib/active_support/core_ext/numeric.rb +5 -0
  98. data/lib/active_support/core_ext/numeric/bytes.rb +66 -0
  99. data/lib/active_support/core_ext/numeric/conversions.rb +136 -0
  100. data/lib/active_support/core_ext/numeric/inquiry.rb +5 -0
  101. data/lib/active_support/core_ext/numeric/time.rb +66 -0
  102. data/lib/active_support/core_ext/object.rb +16 -0
  103. data/lib/active_support/core_ext/object/acts_like.rb +21 -0
  104. data/lib/active_support/core_ext/object/blank.rb +155 -0
  105. data/lib/active_support/core_ext/object/conversions.rb +6 -0
  106. data/lib/active_support/core_ext/object/deep_dup.rb +55 -0
  107. data/lib/active_support/core_ext/object/duplicable.rb +49 -0
  108. data/lib/active_support/core_ext/object/inclusion.rb +29 -0
  109. data/lib/active_support/core_ext/object/instance_variables.rb +30 -0
  110. data/lib/active_support/core_ext/object/json.rb +228 -0
  111. data/lib/active_support/core_ext/object/to_param.rb +3 -0
  112. data/lib/active_support/core_ext/object/to_query.rb +89 -0
  113. data/lib/active_support/core_ext/object/try.rb +156 -0
  114. data/lib/active_support/core_ext/object/with_options.rb +82 -0
  115. data/lib/active_support/core_ext/range.rb +7 -0
  116. data/lib/active_support/core_ext/range/compare_range.rb +70 -0
  117. data/lib/active_support/core_ext/range/conversions.rb +41 -0
  118. data/lib/active_support/core_ext/range/each.rb +25 -0
  119. data/lib/active_support/core_ext/range/include_range.rb +9 -0
  120. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  121. data/lib/active_support/core_ext/range/overlaps.rb +10 -0
  122. data/lib/active_support/core_ext/regexp.rb +7 -0
  123. data/lib/active_support/core_ext/securerandom.rb +45 -0
  124. data/lib/active_support/core_ext/string.rb +15 -0
  125. data/lib/active_support/core_ext/string/access.rb +114 -0
  126. data/lib/active_support/core_ext/string/behavior.rb +8 -0
  127. data/lib/active_support/core_ext/string/conversions.rb +59 -0
  128. data/lib/active_support/core_ext/string/exclude.rb +13 -0
  129. data/lib/active_support/core_ext/string/filters.rb +145 -0
  130. data/lib/active_support/core_ext/string/indent.rb +45 -0
  131. data/lib/active_support/core_ext/string/inflections.rb +259 -0
  132. data/lib/active_support/core_ext/string/inquiry.rb +15 -0
  133. data/lib/active_support/core_ext/string/multibyte.rb +58 -0
  134. data/lib/active_support/core_ext/string/output_safety.rb +314 -0
  135. data/lib/active_support/core_ext/string/starts_ends_with.rb +6 -0
  136. data/lib/active_support/core_ext/string/strip.rb +27 -0
  137. data/lib/active_support/core_ext/string/zones.rb +16 -0
  138. data/lib/active_support/core_ext/time.rb +7 -0
  139. data/lib/active_support/core_ext/time/acts_like.rb +10 -0
  140. data/lib/active_support/core_ext/time/calculations.rb +344 -0
  141. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  142. data/lib/active_support/core_ext/time/conversions.rb +72 -0
  143. data/lib/active_support/core_ext/time/zones.rb +113 -0
  144. data/lib/active_support/core_ext/uri.rb +25 -0
  145. data/lib/active_support/current_attributes.rb +203 -0
  146. data/lib/active_support/dependencies.rb +806 -0
  147. data/lib/active_support/dependencies/autoload.rb +79 -0
  148. data/lib/active_support/dependencies/interlock.rb +57 -0
  149. data/lib/active_support/dependencies/zeitwerk_integration.rb +110 -0
  150. data/lib/active_support/deprecation.rb +46 -0
  151. data/lib/active_support/deprecation/behaviors.rb +109 -0
  152. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  153. data/lib/active_support/deprecation/instance_delegator.rb +39 -0
  154. data/lib/active_support/deprecation/method_wrappers.rb +78 -0
  155. data/lib/active_support/deprecation/proxy_wrappers.rb +173 -0
  156. data/lib/active_support/deprecation/reporting.rb +114 -0
  157. data/lib/active_support/descendants_tracker.rb +109 -0
  158. data/lib/active_support/digest.rb +20 -0
  159. data/lib/active_support/duration.rb +433 -0
  160. data/lib/active_support/duration/iso8601_parser.rb +124 -0
  161. data/lib/active_support/duration/iso8601_serializer.rb +54 -0
  162. data/lib/active_support/encrypted_configuration.rb +45 -0
  163. data/lib/active_support/encrypted_file.rb +100 -0
  164. data/lib/active_support/evented_file_update_checker.rb +235 -0
  165. data/lib/active_support/execution_wrapper.rb +129 -0
  166. data/lib/active_support/executor.rb +8 -0
  167. data/lib/active_support/file_update_checker.rb +163 -0
  168. data/lib/active_support/gem_version.rb +17 -0
  169. data/lib/active_support/gzip.rb +38 -0
  170. data/lib/active_support/hash_with_indifferent_access.rb +399 -0
  171. data/lib/active_support/i18n.rb +16 -0
  172. data/lib/active_support/i18n_railtie.rb +126 -0
  173. data/lib/active_support/inflections.rb +72 -0
  174. data/lib/active_support/inflector.rb +9 -0
  175. data/lib/active_support/inflector/inflections.rb +257 -0
  176. data/lib/active_support/inflector/methods.rb +398 -0
  177. data/lib/active_support/inflector/transliterate.rb +147 -0
  178. data/lib/active_support/json.rb +4 -0
  179. data/lib/active_support/json/decoding.rb +76 -0
  180. data/lib/active_support/json/encoding.rb +134 -0
  181. data/lib/active_support/key_generator.rb +41 -0
  182. data/lib/active_support/lazy_load_hooks.rb +82 -0
  183. data/lib/active_support/locale/en.rb +31 -0
  184. data/lib/active_support/locale/en.yml +135 -0
  185. data/lib/active_support/log_subscriber.rb +135 -0
  186. data/lib/active_support/log_subscriber/test_helper.rb +106 -0
  187. data/lib/active_support/logger.rb +93 -0
  188. data/lib/active_support/logger_silence.rb +45 -0
  189. data/lib/active_support/logger_thread_safe_level.rb +56 -0
  190. data/lib/active_support/message_encryptor.rb +227 -0
  191. data/lib/active_support/message_verifier.rb +205 -0
  192. data/lib/active_support/messages/metadata.rb +71 -0
  193. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  194. data/lib/active_support/messages/rotator.rb +56 -0
  195. data/lib/active_support/multibyte.rb +23 -0
  196. data/lib/active_support/multibyte/chars.rb +216 -0
  197. data/lib/active_support/multibyte/unicode.rb +157 -0
  198. data/lib/active_support/notifications.rb +253 -0
  199. data/lib/active_support/notifications/fanout.rb +244 -0
  200. data/lib/active_support/notifications/instrumenter.rb +164 -0
  201. data/lib/active_support/number_helper.rb +378 -0
  202. data/lib/active_support/number_helper/number_converter.rb +184 -0
  203. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  204. data/lib/active_support/number_helper/number_to_delimited_converter.rb +31 -0
  205. data/lib/active_support/number_helper/number_to_human_converter.rb +70 -0
  206. data/lib/active_support/number_helper/number_to_human_size_converter.rb +61 -0
  207. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  208. data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
  209. data/lib/active_support/number_helper/number_to_rounded_converter.rb +56 -0
  210. data/lib/active_support/number_helper/rounding_helper.rb +66 -0
  211. data/lib/active_support/option_merger.rb +27 -0
  212. data/lib/active_support/ordered_hash.rb +50 -0
  213. data/lib/active_support/ordered_options.rb +85 -0
  214. data/lib/active_support/parameter_filter.rb +129 -0
  215. data/lib/active_support/per_thread_registry.rb +60 -0
  216. data/lib/active_support/proxy_object.rb +15 -0
  217. data/lib/active_support/rails.rb +29 -0
  218. data/lib/active_support/railtie.rb +80 -0
  219. data/lib/active_support/reloader.rb +130 -0
  220. data/lib/active_support/rescuable.rb +174 -0
  221. data/lib/active_support/security_utils.rb +31 -0
  222. data/lib/active_support/string_inquirer.rb +34 -0
  223. data/lib/active_support/subscriber.rb +169 -0
  224. data/lib/active_support/tagged_logging.rb +88 -0
  225. data/lib/active_support/test_case.rb +163 -0
  226. data/lib/active_support/testing/assertions.rb +228 -0
  227. data/lib/active_support/testing/autorun.rb +7 -0
  228. data/lib/active_support/testing/constant_lookup.rb +51 -0
  229. data/lib/active_support/testing/declarative.rb +28 -0
  230. data/lib/active_support/testing/deprecation.rb +38 -0
  231. data/lib/active_support/testing/file_fixtures.rb +38 -0
  232. data/lib/active_support/testing/isolation.rb +110 -0
  233. data/lib/active_support/testing/method_call_assertions.rb +70 -0
  234. data/lib/active_support/testing/parallelization.rb +128 -0
  235. data/lib/active_support/testing/setup_and_teardown.rb +55 -0
  236. data/lib/active_support/testing/stream.rb +44 -0
  237. data/lib/active_support/testing/tagged_logging.rb +27 -0
  238. data/lib/active_support/testing/time_helpers.rb +200 -0
  239. data/lib/active_support/time.rb +20 -0
  240. data/lib/active_support/time_with_zone.rb +561 -0
  241. data/lib/active_support/values/time_zone.rb +570 -0
  242. data/lib/active_support/version.rb +10 -0
  243. data/lib/active_support/xml_mini.rb +202 -0
  244. data/lib/active_support/xml_mini/jdom.rb +183 -0
  245. data/lib/active_support/xml_mini/libxml.rb +80 -0
  246. data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
  247. data/lib/active_support/xml_mini/nokogiri.rb +83 -0
  248. data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
  249. data/lib/active_support/xml_mini/rexml.rb +130 -0
  250. metadata +385 -0
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kernel
4
+ # class_eval on an object acts like singleton_class.class_eval.
5
+ def class_eval(*args, &block)
6
+ singleton_class.class_eval(*args, &block)
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LoadError
4
+ # Returns true if the given path name (except perhaps for the ".rb"
5
+ # extension) is the missing file which caused the exception to be raised.
6
+ def is_missing?(location)
7
+ location.sub(/\.rb$/, "") == path.to_s.sub(/\.rb$/, "")
8
+ end
9
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module MarshalWithAutoloading # :nodoc:
5
+ def load(source, proc = nil)
6
+ super(source, proc)
7
+ rescue ArgumentError, NameError => exc
8
+ if exc.message.match(%r|undefined class/module (.+?)(?:::)?\z|)
9
+ # try loading the class/module
10
+ loaded = $1.constantize
11
+
12
+ raise unless $1 == loaded.name
13
+
14
+ # if it is an IO we need to go back to read the object
15
+ source.rewind if source.respond_to?(:rewind)
16
+ retry
17
+ else
18
+ raise exc
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ Marshal.singleton_class.prepend(ActiveSupport::MarshalWithAutoloading)
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/aliasing"
4
+ require "active_support/core_ext/module/introspection"
5
+ require "active_support/core_ext/module/anonymous"
6
+ require "active_support/core_ext/module/attribute_accessors"
7
+ require "active_support/core_ext/module/attribute_accessors_per_thread"
8
+ require "active_support/core_ext/module/attr_internal"
9
+ require "active_support/core_ext/module/concerning"
10
+ require "active_support/core_ext/module/delegation"
11
+ require "active_support/core_ext/module/deprecation"
12
+ require "active_support/core_ext/module/redefine_method"
13
+ require "active_support/core_ext/module/remove_method"
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Module
4
+ # Allows you to make aliases for attributes, which includes
5
+ # getter, setter, and a predicate.
6
+ #
7
+ # class Content < ActiveRecord::Base
8
+ # # has a title attribute
9
+ # end
10
+ #
11
+ # class Email < Content
12
+ # alias_attribute :subject, :title
13
+ # end
14
+ #
15
+ # e = Email.find(1)
16
+ # e.title # => "Superstars"
17
+ # e.subject # => "Superstars"
18
+ # e.subject? # => true
19
+ # e.subject = "Megastars"
20
+ # e.title # => "Megastars"
21
+ def alias_attribute(new_name, old_name)
22
+ # The following reader methods use an explicit `self` receiver in order to
23
+ # support aliases that start with an uppercase letter. Otherwise, they would
24
+ # be resolved as constants instead.
25
+ module_eval <<-STR, __FILE__, __LINE__ + 1
26
+ def #{new_name}; self.#{old_name}; end # def subject; self.title; end
27
+ def #{new_name}?; self.#{old_name}?; end # def subject?; self.title?; end
28
+ def #{new_name}=(v); self.#{old_name} = v; end # def subject=(v); self.title = v; end
29
+ STR
30
+ end
31
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Module
4
+ # A module may or may not have a name.
5
+ #
6
+ # module M; end
7
+ # M.name # => "M"
8
+ #
9
+ # m = Module.new
10
+ # m.name # => nil
11
+ #
12
+ # +anonymous?+ method returns true if module does not have a name, false otherwise:
13
+ #
14
+ # Module.new.anonymous? # => true
15
+ #
16
+ # module M; end
17
+ # M.anonymous? # => false
18
+ #
19
+ # A module gets a name when it is first assigned to a constant. Either
20
+ # via the +module+ or +class+ keyword or by an explicit assignment:
21
+ #
22
+ # m = Module.new # creates an anonymous module
23
+ # m.anonymous? # => true
24
+ # M = m # m gets a name here as a side-effect
25
+ # m.name # => "M"
26
+ # m.anonymous? # => false
27
+ def anonymous?
28
+ name.nil?
29
+ end
30
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Module
4
+ # Declares an attribute reader backed by an internally-named instance variable.
5
+ def attr_internal_reader(*attrs)
6
+ attrs.each { |attr_name| attr_internal_define(attr_name, :reader) }
7
+ end
8
+
9
+ # Declares an attribute writer backed by an internally-named instance variable.
10
+ def attr_internal_writer(*attrs)
11
+ attrs.each { |attr_name| attr_internal_define(attr_name, :writer) }
12
+ end
13
+
14
+ # Declares an attribute reader and writer backed by an internally-named instance
15
+ # variable.
16
+ def attr_internal_accessor(*attrs)
17
+ attr_internal_reader(*attrs)
18
+ attr_internal_writer(*attrs)
19
+ end
20
+ alias_method :attr_internal, :attr_internal_accessor
21
+
22
+ class << self; attr_accessor :attr_internal_naming_format end
23
+ self.attr_internal_naming_format = "@_%s"
24
+
25
+ private
26
+ def attr_internal_ivar_name(attr)
27
+ Module.attr_internal_naming_format % attr
28
+ end
29
+
30
+ def attr_internal_define(attr_name, type)
31
+ internal_name = attr_internal_ivar_name(attr_name).sub(/\A@/, "")
32
+ # use native attr_* methods as they are faster on some Ruby implementations
33
+ send("attr_#{type}", internal_name)
34
+ attr_name, internal_name = "#{attr_name}=", "#{internal_name}=" if type == :writer
35
+ alias_method attr_name, internal_name
36
+ remove_method internal_name
37
+ end
38
+ end
@@ -0,0 +1,212 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Extends the module object with class/module and instance accessors for
4
+ # class/module attributes, just like the native attr* accessors for instance
5
+ # attributes.
6
+ class Module
7
+ # Defines a class attribute and creates a class and instance reader methods.
8
+ # The underlying class variable is set to +nil+, if it is not previously
9
+ # defined. All class and instance methods created will be public, even if
10
+ # this method is called with a private or protected access modifier.
11
+ #
12
+ # module HairColors
13
+ # mattr_reader :hair_colors
14
+ # end
15
+ #
16
+ # HairColors.hair_colors # => nil
17
+ # HairColors.class_variable_set("@@hair_colors", [:brown, :black])
18
+ # HairColors.hair_colors # => [:brown, :black]
19
+ #
20
+ # The attribute name must be a valid method name in Ruby.
21
+ #
22
+ # module Foo
23
+ # mattr_reader :"1_Badname"
24
+ # end
25
+ # # => NameError: invalid attribute name: 1_Badname
26
+ #
27
+ # To omit the instance reader method, pass
28
+ # <tt>instance_reader: false</tt> or <tt>instance_accessor: false</tt>.
29
+ #
30
+ # module HairColors
31
+ # mattr_reader :hair_colors, instance_reader: false
32
+ # end
33
+ #
34
+ # class Person
35
+ # include HairColors
36
+ # end
37
+ #
38
+ # Person.new.hair_colors # => NoMethodError
39
+ #
40
+ # You can set a default value for the attribute.
41
+ #
42
+ # module HairColors
43
+ # mattr_reader :hair_colors, default: [:brown, :black, :blonde, :red]
44
+ # end
45
+ #
46
+ # class Person
47
+ # include HairColors
48
+ # end
49
+ #
50
+ # Person.new.hair_colors # => [:brown, :black, :blonde, :red]
51
+ def mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil)
52
+ syms.each do |sym|
53
+ raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
54
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
55
+ @@#{sym} = nil unless defined? @@#{sym}
56
+
57
+ def self.#{sym}
58
+ @@#{sym}
59
+ end
60
+ EOS
61
+
62
+ if instance_reader && instance_accessor
63
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
64
+ def #{sym}
65
+ @@#{sym}
66
+ end
67
+ EOS
68
+ end
69
+
70
+ sym_default_value = (block_given? && default.nil?) ? yield : default
71
+ class_variable_set("@@#{sym}", sym_default_value) unless sym_default_value.nil?
72
+ end
73
+ end
74
+ alias :cattr_reader :mattr_reader
75
+
76
+ # Defines a class attribute and creates a class and instance writer methods to
77
+ # allow assignment to the attribute. All class and instance methods created
78
+ # will be public, even if this method is called with a private or protected
79
+ # access modifier.
80
+ #
81
+ # module HairColors
82
+ # mattr_writer :hair_colors
83
+ # end
84
+ #
85
+ # class Person
86
+ # include HairColors
87
+ # end
88
+ #
89
+ # HairColors.hair_colors = [:brown, :black]
90
+ # Person.class_variable_get("@@hair_colors") # => [:brown, :black]
91
+ # Person.new.hair_colors = [:blonde, :red]
92
+ # HairColors.class_variable_get("@@hair_colors") # => [:blonde, :red]
93
+ #
94
+ # To omit the instance writer method, pass
95
+ # <tt>instance_writer: false</tt> or <tt>instance_accessor: false</tt>.
96
+ #
97
+ # module HairColors
98
+ # mattr_writer :hair_colors, instance_writer: false
99
+ # end
100
+ #
101
+ # class Person
102
+ # include HairColors
103
+ # end
104
+ #
105
+ # Person.new.hair_colors = [:blonde, :red] # => NoMethodError
106
+ #
107
+ # You can set a default value for the attribute.
108
+ #
109
+ # module HairColors
110
+ # mattr_writer :hair_colors, default: [:brown, :black, :blonde, :red]
111
+ # end
112
+ #
113
+ # class Person
114
+ # include HairColors
115
+ # end
116
+ #
117
+ # Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
118
+ def mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil)
119
+ syms.each do |sym|
120
+ raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
121
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
122
+ @@#{sym} = nil unless defined? @@#{sym}
123
+
124
+ def self.#{sym}=(obj)
125
+ @@#{sym} = obj
126
+ end
127
+ EOS
128
+
129
+ if instance_writer && instance_accessor
130
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
131
+ def #{sym}=(obj)
132
+ @@#{sym} = obj
133
+ end
134
+ EOS
135
+ end
136
+
137
+ sym_default_value = (block_given? && default.nil?) ? yield : default
138
+ send("#{sym}=", sym_default_value) unless sym_default_value.nil?
139
+ end
140
+ end
141
+ alias :cattr_writer :mattr_writer
142
+
143
+ # Defines both class and instance accessors for class attributes.
144
+ # All class and instance methods created will be public, even if
145
+ # this method is called with a private or protected access modifier.
146
+ #
147
+ # module HairColors
148
+ # mattr_accessor :hair_colors
149
+ # end
150
+ #
151
+ # class Person
152
+ # include HairColors
153
+ # end
154
+ #
155
+ # HairColors.hair_colors = [:brown, :black, :blonde, :red]
156
+ # HairColors.hair_colors # => [:brown, :black, :blonde, :red]
157
+ # Person.new.hair_colors # => [:brown, :black, :blonde, :red]
158
+ #
159
+ # If a subclass changes the value then that would also change the value for
160
+ # parent class. Similarly if parent class changes the value then that would
161
+ # change the value of subclasses too.
162
+ #
163
+ # class Citizen < Person
164
+ # end
165
+ #
166
+ # Citizen.new.hair_colors << :blue
167
+ # Person.new.hair_colors # => [:brown, :black, :blonde, :red, :blue]
168
+ #
169
+ # To omit the instance writer method, pass <tt>instance_writer: false</tt>.
170
+ # To omit the instance reader method, pass <tt>instance_reader: false</tt>.
171
+ #
172
+ # module HairColors
173
+ # mattr_accessor :hair_colors, instance_writer: false, instance_reader: false
174
+ # end
175
+ #
176
+ # class Person
177
+ # include HairColors
178
+ # end
179
+ #
180
+ # Person.new.hair_colors = [:brown] # => NoMethodError
181
+ # Person.new.hair_colors # => NoMethodError
182
+ #
183
+ # Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
184
+ #
185
+ # module HairColors
186
+ # mattr_accessor :hair_colors, instance_accessor: false
187
+ # end
188
+ #
189
+ # class Person
190
+ # include HairColors
191
+ # end
192
+ #
193
+ # Person.new.hair_colors = [:brown] # => NoMethodError
194
+ # Person.new.hair_colors # => NoMethodError
195
+ #
196
+ # You can set a default value for the attribute.
197
+ #
198
+ # module HairColors
199
+ # mattr_accessor :hair_colors, default: [:brown, :black, :blonde, :red]
200
+ # end
201
+ #
202
+ # class Person
203
+ # include HairColors
204
+ # end
205
+ #
206
+ # Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
207
+ def mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil, &blk)
208
+ mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor, default: default, &blk)
209
+ mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor, default: default)
210
+ end
211
+ alias :cattr_accessor :mattr_accessor
212
+ end
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Extends the module object with class/module and instance accessors for
4
+ # class/module attributes, just like the native attr* accessors for instance
5
+ # attributes, but does so on a per-thread basis.
6
+ #
7
+ # So the values are scoped within the Thread.current space under the class name
8
+ # of the module.
9
+ class Module
10
+ # Defines a per-thread class attribute and creates class and instance reader methods.
11
+ # The underlying per-thread class variable is set to +nil+, if it is not previously defined.
12
+ #
13
+ # module Current
14
+ # thread_mattr_reader :user
15
+ # end
16
+ #
17
+ # Current.user # => nil
18
+ # Thread.current[:attr_Current_user] = "DHH"
19
+ # Current.user # => "DHH"
20
+ #
21
+ # The attribute name must be a valid method name in Ruby.
22
+ #
23
+ # module Foo
24
+ # thread_mattr_reader :"1_Badname"
25
+ # end
26
+ # # => NameError: invalid attribute name: 1_Badname
27
+ #
28
+ # To omit the instance reader method, pass
29
+ # <tt>instance_reader: false</tt> or <tt>instance_accessor: false</tt>.
30
+ #
31
+ # class Current
32
+ # thread_mattr_reader :user, instance_reader: false
33
+ # end
34
+ #
35
+ # Current.new.user # => NoMethodError
36
+ def thread_mattr_reader(*syms, instance_reader: true, instance_accessor: true) # :nodoc:
37
+ syms.each do |sym|
38
+ raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
39
+
40
+ # The following generated method concatenates `name` because we want it
41
+ # to work with inheritance via polymorphism.
42
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
43
+ def self.#{sym}
44
+ Thread.current["attr_" + name + "_#{sym}"]
45
+ end
46
+ EOS
47
+
48
+ if instance_reader && instance_accessor
49
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
50
+ def #{sym}
51
+ self.class.#{sym}
52
+ end
53
+ EOS
54
+ end
55
+ end
56
+ end
57
+ alias :thread_cattr_reader :thread_mattr_reader
58
+
59
+ # Defines a per-thread class attribute and creates a class and instance writer methods to
60
+ # allow assignment to the attribute.
61
+ #
62
+ # module Current
63
+ # thread_mattr_writer :user
64
+ # end
65
+ #
66
+ # Current.user = "DHH"
67
+ # Thread.current[:attr_Current_user] # => "DHH"
68
+ #
69
+ # To omit the instance writer method, pass
70
+ # <tt>instance_writer: false</tt> or <tt>instance_accessor: false</tt>.
71
+ #
72
+ # class Current
73
+ # thread_mattr_writer :user, instance_writer: false
74
+ # end
75
+ #
76
+ # Current.new.user = "DHH" # => NoMethodError
77
+ def thread_mattr_writer(*syms, instance_writer: true, instance_accessor: true) # :nodoc:
78
+ syms.each do |sym|
79
+ raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
80
+
81
+ # The following generated method concatenates `name` because we want it
82
+ # to work with inheritance via polymorphism.
83
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
84
+ def self.#{sym}=(obj)
85
+ Thread.current["attr_" + name + "_#{sym}"] = obj
86
+ end
87
+ EOS
88
+
89
+ if instance_writer && instance_accessor
90
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
91
+ def #{sym}=(obj)
92
+ self.class.#{sym} = obj
93
+ end
94
+ EOS
95
+ end
96
+ end
97
+ end
98
+ alias :thread_cattr_writer :thread_mattr_writer
99
+
100
+ # Defines both class and instance accessors for class attributes.
101
+ #
102
+ # class Account
103
+ # thread_mattr_accessor :user
104
+ # end
105
+ #
106
+ # Account.user = "DHH"
107
+ # Account.user # => "DHH"
108
+ # Account.new.user # => "DHH"
109
+ #
110
+ # If a subclass changes the value, the parent class' value is not changed.
111
+ # Similarly, if the parent class changes the value, the value of subclasses
112
+ # is not changed.
113
+ #
114
+ # class Customer < Account
115
+ # end
116
+ #
117
+ # Customer.user = "Rafael"
118
+ # Customer.user # => "Rafael"
119
+ # Account.user # => "DHH"
120
+ #
121
+ # To omit the instance writer method, pass <tt>instance_writer: false</tt>.
122
+ # To omit the instance reader method, pass <tt>instance_reader: false</tt>.
123
+ #
124
+ # class Current
125
+ # thread_mattr_accessor :user, instance_writer: false, instance_reader: false
126
+ # end
127
+ #
128
+ # Current.new.user = "DHH" # => NoMethodError
129
+ # Current.new.user # => NoMethodError
130
+ #
131
+ # Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
132
+ #
133
+ # class Current
134
+ # thread_mattr_accessor :user, instance_accessor: false
135
+ # end
136
+ #
137
+ # Current.new.user = "DHH" # => NoMethodError
138
+ # Current.new.user # => NoMethodError
139
+ def thread_mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true)
140
+ thread_mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor)
141
+ thread_mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor)
142
+ end
143
+ alias :thread_cattr_accessor :thread_mattr_accessor
144
+ end