activesupport 4.2.11.1 → 6.0.3.1

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 (263) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +399 -411
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -7
  5. data/lib/active_support/actionable_error.rb +48 -0
  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 +34 -6
  9. data/lib/active_support/benchmarkable.rb +6 -4
  10. data/lib/active_support/builder.rb +3 -1
  11. data/lib/active_support/cache/file_store.rb +58 -53
  12. data/lib/active_support/cache/mem_cache_store.rb +95 -91
  13. data/lib/active_support/cache/memory_store.rb +39 -36
  14. data/lib/active_support/cache/null_store.rb +11 -7
  15. data/lib/active_support/cache/redis_cache_store.rb +493 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +75 -42
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
  18. data/lib/active_support/cache.rb +331 -217
  19. data/lib/active_support/callbacks.rb +650 -592
  20. data/lib/active_support/concern.rb +35 -6
  21. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
  22. data/lib/active_support/concurrency/share_lock.rb +226 -0
  23. data/lib/active_support/configurable.rb +13 -14
  24. data/lib/active_support/core_ext/array/access.rb +41 -1
  25. data/lib/active_support/core_ext/array/conversions.rb +24 -20
  26. data/lib/active_support/core_ext/array/extract.rb +21 -0
  27. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  28. data/lib/active_support/core_ext/array/grouping.rb +11 -18
  29. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  30. data/lib/active_support/core_ext/array/prepend_and_append.rb +4 -6
  31. data/lib/active_support/core_ext/array/wrap.rb +7 -4
  32. data/lib/active_support/core_ext/array.rb +9 -6
  33. data/lib/active_support/core_ext/benchmark.rb +3 -1
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +10 -12
  35. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  36. data/lib/active_support/core_ext/class/attribute.rb +45 -31
  37. data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
  38. data/lib/active_support/core_ext/class/subclasses.rb +20 -6
  39. data/lib/active_support/core_ext/class.rb +4 -3
  40. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  41. data/lib/active_support/core_ext/date/blank.rb +14 -0
  42. data/lib/active_support/core_ext/date/calculations.rb +17 -14
  43. data/lib/active_support/core_ext/date/conversions.rb +25 -23
  44. data/lib/active_support/core_ext/date/zones.rb +4 -2
  45. data/lib/active_support/core_ext/date.rb +6 -4
  46. data/lib/active_support/core_ext/date_and_time/calculations.rb +154 -65
  47. data/lib/active_support/core_ext/date_and_time/compatibility.rb +4 -3
  48. data/lib/active_support/core_ext/date_and_time/zones.rb +12 -13
  49. data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
  50. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  51. data/lib/active_support/core_ext/date_time/calculations.rb +37 -19
  52. data/lib/active_support/core_ext/date_time/compatibility.rb +8 -6
  53. data/lib/active_support/core_ext/date_time/conversions.rb +16 -13
  54. data/lib/active_support/core_ext/date_time.rb +7 -5
  55. data/lib/active_support/core_ext/digest/uuid.rb +7 -5
  56. data/lib/active_support/core_ext/digest.rb +3 -0
  57. data/lib/active_support/core_ext/enumerable.rb +114 -22
  58. data/lib/active_support/core_ext/file/atomic.rb +38 -31
  59. data/lib/active_support/core_ext/file.rb +3 -1
  60. data/lib/active_support/core_ext/hash/compact.rb +4 -23
  61. data/lib/active_support/core_ext/hash/conversions.rb +62 -41
  62. data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
  63. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  64. data/lib/active_support/core_ext/hash/except.rb +12 -9
  65. data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -3
  66. data/lib/active_support/core_ext/hash/keys.rb +19 -42
  67. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  68. data/lib/active_support/core_ext/hash/slice.rb +5 -27
  69. data/lib/active_support/core_ext/hash/transform_values.rb +4 -22
  70. data/lib/active_support/core_ext/hash.rb +10 -9
  71. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  72. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  73. data/lib/active_support/core_ext/integer/time.rb +11 -18
  74. data/lib/active_support/core_ext/integer.rb +5 -3
  75. data/lib/active_support/core_ext/kernel/concern.rb +5 -1
  76. data/lib/active_support/core_ext/kernel/reporting.rb +4 -84
  77. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  78. data/lib/active_support/core_ext/kernel.rb +5 -5
  79. data/lib/active_support/core_ext/load_error.rb +3 -22
  80. data/lib/active_support/core_ext/marshal.rb +8 -8
  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 +46 -46
  85. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +144 -0
  86. data/lib/active_support/core_ext/module/concerning.rb +11 -12
  87. data/lib/active_support/core_ext/module/delegation.rb +133 -30
  88. data/lib/active_support/core_ext/module/deprecation.rb +4 -2
  89. data/lib/active_support/core_ext/module/introspection.rb +44 -19
  90. data/lib/active_support/core_ext/module/reachable.rb +5 -7
  91. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  92. data/lib/active_support/core_ext/module/remove_method.rb +8 -3
  93. data/lib/active_support/core_ext/module.rb +13 -11
  94. data/lib/active_support/core_ext/name_error.rb +22 -2
  95. data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
  96. data/lib/active_support/core_ext/numeric/conversions.rb +129 -136
  97. data/lib/active_support/core_ext/numeric/inquiry.rb +5 -0
  98. data/lib/active_support/core_ext/numeric/time.rb +35 -23
  99. data/lib/active_support/core_ext/numeric.rb +5 -3
  100. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  101. data/lib/active_support/core_ext/object/blank.rb +27 -3
  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 +13 -93
  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 +51 -20
  108. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  109. data/lib/active_support/core_ext/object/to_query.rb +10 -5
  110. data/lib/active_support/core_ext/object/try.rb +81 -23
  111. data/lib/active_support/core_ext/object/with_options.rb +16 -3
  112. data/lib/active_support/core_ext/object.rb +14 -13
  113. data/lib/active_support/core_ext/range/compare_range.rb +76 -0
  114. data/lib/active_support/core_ext/range/conversions.rb +37 -15
  115. data/lib/active_support/core_ext/range/each.rb +18 -17
  116. data/lib/active_support/core_ext/range/include_range.rb +7 -21
  117. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  118. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  119. data/lib/active_support/core_ext/range.rb +7 -4
  120. data/lib/active_support/core_ext/regexp.rb +2 -0
  121. data/lib/active_support/core_ext/securerandom.rb +45 -0
  122. data/lib/active_support/core_ext/string/access.rb +16 -6
  123. data/lib/active_support/core_ext/string/behavior.rb +3 -1
  124. data/lib/active_support/core_ext/string/conversions.rb +7 -4
  125. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  126. data/lib/active_support/core_ext/string/filters.rb +48 -6
  127. data/lib/active_support/core_ext/string/indent.rb +6 -4
  128. data/lib/active_support/core_ext/string/inflections.rb +66 -24
  129. data/lib/active_support/core_ext/string/inquiry.rb +3 -1
  130. data/lib/active_support/core_ext/string/multibyte.rb +16 -7
  131. data/lib/active_support/core_ext/string/output_safety.rb +93 -40
  132. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -0
  133. data/lib/active_support/core_ext/string/strip.rb +6 -5
  134. data/lib/active_support/core_ext/string/zones.rb +4 -2
  135. data/lib/active_support/core_ext/string.rb +15 -13
  136. data/lib/active_support/core_ext/time/acts_like.rb +3 -1
  137. data/lib/active_support/core_ext/time/calculations.rb +115 -52
  138. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  139. data/lib/active_support/core_ext/time/conversions.rb +20 -13
  140. data/lib/active_support/core_ext/time/zones.rb +41 -7
  141. data/lib/active_support/core_ext/time.rb +7 -6
  142. data/lib/active_support/core_ext/uri.rb +6 -7
  143. data/lib/active_support/core_ext.rb +3 -1
  144. data/lib/active_support/current_attributes.rb +203 -0
  145. data/lib/active_support/dependencies/autoload.rb +2 -0
  146. data/lib/active_support/dependencies/interlock.rb +57 -0
  147. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  148. data/lib/active_support/dependencies.rb +208 -166
  149. data/lib/active_support/deprecation/behaviors.rb +44 -11
  150. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  151. data/lib/active_support/deprecation/instance_delegator.rb +17 -2
  152. data/lib/active_support/deprecation/method_wrappers.rb +61 -21
  153. data/lib/active_support/deprecation/proxy_wrappers.rb +81 -30
  154. data/lib/active_support/deprecation/reporting.rb +32 -12
  155. data/lib/active_support/deprecation.rb +12 -9
  156. data/lib/active_support/descendants_tracker.rb +57 -9
  157. data/lib/active_support/digest.rb +20 -0
  158. data/lib/active_support/duration/iso8601_parser.rb +123 -0
  159. data/lib/active_support/duration/iso8601_serializer.rb +53 -0
  160. data/lib/active_support/duration.rb +315 -40
  161. data/lib/active_support/encrypted_configuration.rb +45 -0
  162. data/lib/active_support/encrypted_file.rb +100 -0
  163. data/lib/active_support/evented_file_update_checker.rb +234 -0
  164. data/lib/active_support/execution_wrapper.rb +129 -0
  165. data/lib/active_support/executor.rb +8 -0
  166. data/lib/active_support/file_update_checker.rb +62 -37
  167. data/lib/active_support/gem_version.rb +6 -4
  168. data/lib/active_support/gzip.rb +7 -5
  169. data/lib/active_support/hash_with_indifferent_access.rb +129 -30
  170. data/lib/active_support/i18n.rb +9 -6
  171. data/lib/active_support/i18n_railtie.rb +50 -14
  172. data/lib/active_support/inflections.rb +13 -11
  173. data/lib/active_support/inflector/inflections.rb +58 -13
  174. data/lib/active_support/inflector/methods.rb +159 -145
  175. data/lib/active_support/inflector/transliterate.rb +84 -34
  176. data/lib/active_support/inflector.rb +7 -5
  177. data/lib/active_support/json/decoding.rb +32 -30
  178. data/lib/active_support/json/encoding.rb +17 -60
  179. data/lib/active_support/json.rb +4 -2
  180. data/lib/active_support/key_generator.rb +11 -43
  181. data/lib/active_support/lazy_load_hooks.rb +53 -20
  182. data/lib/active_support/locale/en.rb +33 -0
  183. data/lib/active_support/locale/en.yml +2 -0
  184. data/lib/active_support/log_subscriber/test_helper.rb +14 -12
  185. data/lib/active_support/log_subscriber.rb +44 -19
  186. data/lib/active_support/logger.rb +9 -23
  187. data/lib/active_support/logger_silence.rb +32 -14
  188. data/lib/active_support/logger_thread_safe_level.rb +32 -8
  189. data/lib/active_support/message_encryptor.rb +166 -53
  190. data/lib/active_support/message_verifier.rb +149 -16
  191. data/lib/active_support/messages/metadata.rb +72 -0
  192. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  193. data/lib/active_support/messages/rotator.rb +56 -0
  194. data/lib/active_support/multibyte/chars.rb +56 -63
  195. data/lib/active_support/multibyte/unicode.rb +56 -290
  196. data/lib/active_support/multibyte.rb +4 -2
  197. data/lib/active_support/notifications/fanout.rb +109 -22
  198. data/lib/active_support/notifications/instrumenter.rb +107 -16
  199. data/lib/active_support/notifications.rb +51 -10
  200. data/lib/active_support/number_helper/number_converter.rb +16 -15
  201. data/lib/active_support/number_helper/number_to_currency_converter.rb +14 -15
  202. data/lib/active_support/number_helper/number_to_delimited_converter.rb +11 -4
  203. data/lib/active_support/number_helper/number_to_human_converter.rb +13 -10
  204. data/lib/active_support/number_helper/number_to_human_size_converter.rb +11 -9
  205. data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
  206. data/lib/active_support/number_helper/number_to_phone_converter.rb +15 -5
  207. data/lib/active_support/number_helper/number_to_rounded_converter.rb +25 -57
  208. data/lib/active_support/number_helper/rounding_helper.rb +66 -0
  209. data/lib/active_support/number_helper.rb +105 -68
  210. data/lib/active_support/option_merger.rb +24 -4
  211. data/lib/active_support/ordered_hash.rb +7 -5
  212. data/lib/active_support/ordered_options.rb +27 -5
  213. data/lib/active_support/parameter_filter.rb +128 -0
  214. data/lib/active_support/per_thread_registry.rb +9 -4
  215. data/lib/active_support/proxy_object.rb +2 -0
  216. data/lib/active_support/rails.rb +10 -8
  217. data/lib/active_support/railtie.rb +43 -9
  218. data/lib/active_support/reloader.rb +130 -0
  219. data/lib/active_support/rescuable.rb +108 -53
  220. data/lib/active_support/security_utils.rb +15 -11
  221. data/lib/active_support/string_inquirer.rb +11 -4
  222. data/lib/active_support/subscriber.rb +74 -30
  223. data/lib/active_support/tagged_logging.rb +25 -13
  224. data/lib/active_support/test_case.rb +107 -44
  225. data/lib/active_support/testing/assertions.rb +151 -20
  226. data/lib/active_support/testing/autorun.rb +4 -2
  227. data/lib/active_support/testing/constant_lookup.rb +2 -1
  228. data/lib/active_support/testing/declarative.rb +3 -1
  229. data/lib/active_support/testing/deprecation.rb +13 -10
  230. data/lib/active_support/testing/file_fixtures.rb +38 -0
  231. data/lib/active_support/testing/isolation.rb +35 -26
  232. data/lib/active_support/testing/method_call_assertions.rb +70 -0
  233. data/lib/active_support/testing/parallelization.rb +134 -0
  234. data/lib/active_support/testing/setup_and_teardown.rb +13 -8
  235. data/lib/active_support/testing/stream.rb +43 -0
  236. data/lib/active_support/testing/tagged_logging.rb +3 -1
  237. data/lib/active_support/testing/time_helpers.rb +84 -20
  238. data/lib/active_support/time.rb +14 -12
  239. data/lib/active_support/time_with_zone.rb +179 -39
  240. data/lib/active_support/values/time_zone.rb +203 -63
  241. data/lib/active_support/version.rb +3 -1
  242. data/lib/active_support/xml_mini/jdom.rb +116 -115
  243. data/lib/active_support/xml_mini/libxml.rb +16 -13
  244. data/lib/active_support/xml_mini/libxmlsax.rb +15 -14
  245. data/lib/active_support/xml_mini/nokogiri.rb +14 -12
  246. data/lib/active_support/xml_mini/nokogirisax.rb +14 -13
  247. data/lib/active_support/xml_mini/rexml.rb +11 -9
  248. data/lib/active_support/xml_mini.rb +38 -46
  249. data/lib/active_support.rb +13 -11
  250. metadata +84 -26
  251. data/lib/active_support/concurrency/latch.rb +0 -27
  252. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
  253. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  254. data/lib/active_support/core_ext/date_time/zones.rb +0 -6
  255. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  256. data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
  257. data/lib/active_support/core_ext/module/method_transplanting.rb +0 -13
  258. data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
  259. data/lib/active_support/core_ext/object/itself.rb +0 -15
  260. data/lib/active_support/core_ext/struct.rb +0 -6
  261. data/lib/active_support/core_ext/thread.rb +0 -86
  262. data/lib/active_support/core_ext/time/marshal.rb +0 -30
  263. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,49 +1,8 @@
1
- class Module
2
- # Encapsulates the common pattern of:
3
- #
4
- # alias_method :foo_without_feature, :foo
5
- # alias_method :foo, :foo_with_feature
6
- #
7
- # With this, you simply do:
8
- #
9
- # alias_method_chain :foo, :feature
10
- #
11
- # And both aliases are set up for you.
12
- #
13
- # Query and bang methods (foo?, foo!) keep the same punctuation:
14
- #
15
- # alias_method_chain :foo?, :feature
16
- #
17
- # is equivalent to
18
- #
19
- # alias_method :foo_without_feature?, :foo?
20
- # alias_method :foo?, :foo_with_feature?
21
- #
22
- # so you can safely chain foo, foo?, foo! and/or foo= with the same feature.
23
- def alias_method_chain(target, feature)
24
- # Strip out punctuation on predicates, bang or writer methods since
25
- # e.g. target?_without_feature is not a valid method name.
26
- aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
27
- yield(aliased_target, punctuation) if block_given?
28
-
29
- with_method = "#{aliased_target}_with_#{feature}#{punctuation}"
30
- without_method = "#{aliased_target}_without_#{feature}#{punctuation}"
31
-
32
- alias_method without_method, target
33
- alias_method target, with_method
34
-
35
- case
36
- when public_method_defined?(without_method)
37
- public target
38
- when protected_method_defined?(without_method)
39
- protected target
40
- when private_method_defined?(without_method)
41
- private target
42
- end
43
- end
1
+ # frozen_string_literal: true
44
2
 
3
+ class Module
45
4
  # Allows you to make aliases for attributes, which includes
46
- # getter, setter, and query methods.
5
+ # getter, setter, and a predicate.
47
6
  #
48
7
  # class Content < ActiveRecord::Base
49
8
  # # has a title attribute
@@ -60,6 +19,9 @@ class Module
60
19
  # e.subject = "Megastars"
61
20
  # e.title # => "Megastars"
62
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.
63
25
  module_eval <<-STR, __FILE__, __LINE__ + 1
64
26
  def #{new_name}; self.#{old_name}; end # def subject; self.title; end
65
27
  def #{new_name}?; self.#{old_name}?; end # def subject?; self.title?; end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Module
2
4
  # A module may or may not have a name.
3
5
  #
@@ -7,12 +9,21 @@ class Module
7
9
  # m = Module.new
8
10
  # m.name # => nil
9
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
+ #
10
19
  # A module gets a name when it is first assigned to a constant. Either
11
20
  # via the +module+ or +class+ keyword or by an explicit assignment:
12
21
  #
13
22
  # m = Module.new # creates an anonymous module
14
- # M = m # => m gets a name here as a side-effect
23
+ # m.anonymous? # => true
24
+ # M = m # m gets a name here as a side-effect
15
25
  # m.name # => "M"
26
+ # m.anonymous? # => false
16
27
  def anonymous?
17
28
  name.nil?
18
29
  end
@@ -1,12 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Module
2
4
  # Declares an attribute reader backed by an internally-named instance variable.
3
5
  def attr_internal_reader(*attrs)
4
- attrs.each {|attr_name| attr_internal_define(attr_name, :reader)}
6
+ attrs.each { |attr_name| attr_internal_define(attr_name, :reader) }
5
7
  end
6
8
 
7
9
  # Declares an attribute writer backed by an internally-named instance variable.
8
10
  def attr_internal_writer(*attrs)
9
- attrs.each {|attr_name| attr_internal_define(attr_name, :writer)}
11
+ attrs.each { |attr_name| attr_internal_define(attr_name, :writer) }
10
12
  end
11
13
 
12
14
  # Declares an attribute reader and writer backed by an internally-named instance
@@ -18,7 +20,7 @@ class Module
18
20
  alias_method :attr_internal, :attr_internal_accessor
19
21
 
20
22
  class << self; attr_accessor :attr_internal_naming_format end
21
- self.attr_internal_naming_format = '@_%s'
23
+ self.attr_internal_naming_format = "@_%s"
22
24
 
23
25
  private
24
26
  def attr_internal_ivar_name(attr)
@@ -26,12 +28,9 @@ class Module
26
28
  end
27
29
 
28
30
  def attr_internal_define(attr_name, type)
29
- internal_name = attr_internal_ivar_name(attr_name).sub(/\A@/, '')
30
- # class_eval is necessary on 1.9 or else the methods are made private
31
- class_eval do
32
- # use native attr_* methods as they are faster on some Ruby implementations
33
- send("attr_#{type}", internal_name)
34
- end
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)
35
34
  attr_name, internal_name = "#{attr_name}=", "#{internal_name}=" if type == :writer
36
35
  alias_method attr_name, internal_name
37
36
  remove_method internal_name
@@ -1,12 +1,13 @@
1
- require 'active_support/core_ext/array/extract_options'
1
+ # frozen_string_literal: true
2
2
 
3
3
  # Extends the module object with class/module and instance accessors for
4
4
  # class/module attributes, just like the native attr* accessors for instance
5
5
  # attributes.
6
6
  class Module
7
7
  # Defines a class attribute and creates a class and instance reader methods.
8
- # The underlying the class variable is set to +nil+, if it is not previously
9
- # defined.
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.
10
11
  #
11
12
  # module HairColors
12
13
  # mattr_reader :hair_colors
@@ -19,15 +20,15 @@ class Module
19
20
  # The attribute name must be a valid method name in Ruby.
20
21
  #
21
22
  # module Foo
22
- # mattr_reader :"1_Badname "
23
+ # mattr_reader :"1_Badname"
23
24
  # end
24
- # # => NameError: invalid attribute name
25
+ # # => NameError: invalid attribute name: 1_Badname
25
26
  #
26
- # If you want to opt out the creation on the instance reader method, pass
27
+ # To omit the instance reader method, pass
27
28
  # <tt>instance_reader: false</tt> or <tt>instance_accessor: false</tt>.
28
29
  #
29
30
  # module HairColors
30
- # mattr_writer :hair_colors, instance_reader: false
31
+ # mattr_reader :hair_colors, instance_reader: false
31
32
  # end
32
33
  #
33
34
  # class Person
@@ -36,24 +37,20 @@ class Module
36
37
  #
37
38
  # Person.new.hair_colors # => NoMethodError
38
39
  #
39
- #
40
- # Also, you can pass a block to set up the attribute with a default value.
40
+ # You can set a default value for the attribute.
41
41
  #
42
42
  # module HairColors
43
- # cattr_reader :hair_colors do
44
- # [:brown, :black, :blonde, :red]
45
- # end
43
+ # mattr_reader :hair_colors, default: [:brown, :black, :blonde, :red]
46
44
  # end
47
45
  #
48
46
  # class Person
49
47
  # include HairColors
50
48
  # end
51
49
  #
52
- # Person.hair_colors # => [:brown, :black, :blonde, :red]
53
- def mattr_reader(*syms)
54
- options = syms.extract_options!
50
+ # Person.new.hair_colors # => [:brown, :black, :blonde, :red]
51
+ def mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil)
55
52
  syms.each do |sym|
56
- raise NameError.new("invalid attribute name: #{sym}") unless sym =~ /^[_A-Za-z]\w*$/
53
+ raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
57
54
  class_eval(<<-EOS, __FILE__, __LINE__ + 1)
58
55
  @@#{sym} = nil unless defined? @@#{sym}
59
56
 
@@ -62,20 +59,24 @@ class Module
62
59
  end
63
60
  EOS
64
61
 
65
- unless options[:instance_reader] == false || options[:instance_accessor] == false
62
+ if instance_reader && instance_accessor
66
63
  class_eval(<<-EOS, __FILE__, __LINE__ + 1)
67
64
  def #{sym}
68
65
  @@#{sym}
69
66
  end
70
67
  EOS
71
68
  end
72
- class_variable_set("@@#{sym}", yield) if block_given?
69
+
70
+ sym_default_value = (block_given? && default.nil?) ? yield : default
71
+ class_variable_set("@@#{sym}", sym_default_value) unless sym_default_value.nil?
73
72
  end
74
73
  end
75
74
  alias :cattr_reader :mattr_reader
76
75
 
77
76
  # Defines a class attribute and creates a class and instance writer methods to
78
- # allow assignment to the attribute.
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.
79
80
  #
80
81
  # module HairColors
81
82
  # mattr_writer :hair_colors
@@ -90,7 +91,7 @@ class Module
90
91
  # Person.new.hair_colors = [:blonde, :red]
91
92
  # HairColors.class_variable_get("@@hair_colors") # => [:blonde, :red]
92
93
  #
93
- # If you want to opt out the instance writer method, pass
94
+ # To omit the instance writer method, pass
94
95
  # <tt>instance_writer: false</tt> or <tt>instance_accessor: false</tt>.
95
96
  #
96
97
  # module HairColors
@@ -103,12 +104,10 @@ class Module
103
104
  #
104
105
  # Person.new.hair_colors = [:blonde, :red] # => NoMethodError
105
106
  #
106
- # Also, you can pass a block to set up the attribute with a default value.
107
+ # You can set a default value for the attribute.
107
108
  #
108
- # class HairColors
109
- # mattr_writer :hair_colors do
110
- # [:brown, :black, :blonde, :red]
111
- # end
109
+ # module HairColors
110
+ # mattr_writer :hair_colors, default: [:brown, :black, :blonde, :red]
112
111
  # end
113
112
  #
114
113
  # class Person
@@ -116,10 +115,9 @@ class Module
116
115
  # end
117
116
  #
118
117
  # Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
119
- def mattr_writer(*syms)
120
- options = syms.extract_options!
118
+ def mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil)
121
119
  syms.each do |sym|
122
- raise NameError.new("invalid attribute name: #{sym}") unless sym =~ /^[_A-Za-z]\w*$/
120
+ raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
123
121
  class_eval(<<-EOS, __FILE__, __LINE__ + 1)
124
122
  @@#{sym} = nil unless defined? @@#{sym}
125
123
 
@@ -128,19 +126,23 @@ class Module
128
126
  end
129
127
  EOS
130
128
 
131
- unless options[:instance_writer] == false || options[:instance_accessor] == false
129
+ if instance_writer && instance_accessor
132
130
  class_eval(<<-EOS, __FILE__, __LINE__ + 1)
133
131
  def #{sym}=(obj)
134
132
  @@#{sym} = obj
135
133
  end
136
134
  EOS
137
135
  end
138
- send("#{sym}=", yield) if block_given?
136
+
137
+ sym_default_value = (block_given? && default.nil?) ? yield : default
138
+ send("#{sym}=", sym_default_value) unless sym_default_value.nil?
139
139
  end
140
140
  end
141
141
  alias :cattr_writer :mattr_writer
142
142
 
143
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.
144
146
  #
145
147
  # module HairColors
146
148
  # mattr_accessor :hair_colors
@@ -150,22 +152,22 @@ class Module
150
152
  # include HairColors
151
153
  # end
152
154
  #
153
- # Person.hair_colors = [:brown, :black, :blonde, :red]
154
- # Person.hair_colors # => [:brown, :black, :blonde, :red]
155
+ # HairColors.hair_colors = [:brown, :black, :blonde, :red]
156
+ # HairColors.hair_colors # => [:brown, :black, :blonde, :red]
155
157
  # Person.new.hair_colors # => [:brown, :black, :blonde, :red]
156
158
  #
157
159
  # If a subclass changes the value then that would also change the value for
158
160
  # parent class. Similarly if parent class changes the value then that would
159
161
  # change the value of subclasses too.
160
162
  #
161
- # class Male < Person
163
+ # class Citizen < Person
162
164
  # end
163
165
  #
164
- # Male.hair_colors << :blue
165
- # Person.hair_colors # => [:brown, :black, :blonde, :red, :blue]
166
+ # Citizen.new.hair_colors << :blue
167
+ # Person.new.hair_colors # => [:brown, :black, :blonde, :red, :blue]
166
168
  #
167
- # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
168
- # To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
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>.
169
171
  #
170
172
  # module HairColors
171
173
  # mattr_accessor :hair_colors, instance_writer: false, instance_reader: false
@@ -178,7 +180,7 @@ class Module
178
180
  # Person.new.hair_colors = [:brown] # => NoMethodError
179
181
  # Person.new.hair_colors # => NoMethodError
180
182
  #
181
- # Or pass <tt>instance_accessor: false</tt>, to opt out both instance methods.
183
+ # Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
182
184
  #
183
185
  # module HairColors
184
186
  # mattr_accessor :hair_colors, instance_accessor: false
@@ -191,22 +193,20 @@ class Module
191
193
  # Person.new.hair_colors = [:brown] # => NoMethodError
192
194
  # Person.new.hair_colors # => NoMethodError
193
195
  #
194
- # Also you can pass a block to set up the attribute with a default value.
196
+ # You can set a default value for the attribute.
195
197
  #
196
198
  # module HairColors
197
- # mattr_accessor :hair_colors do
198
- # [:brown, :black, :blonde, :red]
199
- # end
199
+ # mattr_accessor :hair_colors, default: [:brown, :black, :blonde, :red]
200
200
  # end
201
201
  #
202
202
  # class Person
203
203
  # include HairColors
204
204
  # end
205
205
  #
206
- # Person.class_variable_get("@@hair_colors") #=> [:brown, :black, :blonde, :red]
207
- def mattr_accessor(*syms, &blk)
208
- mattr_reader(*syms, &blk)
209
- mattr_writer(*syms, &blk)
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
210
  end
211
211
  alias :cattr_accessor :mattr_accessor
212
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
@@ -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,