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,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kernel
2
4
  # class_eval on an object acts like singleton_class.class_eval.
3
5
  def class_eval(*args, &block)
@@ -1,28 +1,9 @@
1
- class LoadError
2
- REGEXPS = [
3
- /^no such file to load -- (.+)$/i,
4
- /^Missing \w+ (?:file\s*)?([^\s]+.rb)$/i,
5
- /^Missing API definition file in (.+)$/i,
6
- /^cannot load such file -- (.+)$/i,
7
- ]
8
-
9
- unless method_defined?(:path)
10
- # Returns the path which was unable to be loaded.
11
- def path
12
- @path ||= begin
13
- REGEXPS.find do |regex|
14
- message =~ regex
15
- end
16
- $1
17
- end
18
- end
19
- end
1
+ # frozen_string_literal: true
20
2
 
3
+ class LoadError
21
4
  # Returns true if the given path name (except perhaps for the ".rb"
22
5
  # extension) is the missing file which caused the exception to be raised.
23
6
  def is_missing?(location)
24
- location.sub(/\.rb$/, '') == path.sub(/\.rb$/, '')
7
+ location.sub(/\.rb$/, "".freeze) == path.sub(/\.rb$/, "".freeze)
25
8
  end
26
9
  end
27
-
28
- MissingSourceFile = LoadError
@@ -1,21 +1,24 @@
1
- require 'active_support/core_ext/module/aliasing'
1
+ # frozen_string_literal: true
2
2
 
3
- module Marshal
4
- class << self
5
- def load_with_autoloading(source)
6
- load_without_autoloading(source)
3
+ module ActiveSupport
4
+ module MarshalWithAutoloading # :nodoc:
5
+ def load(source, proc = nil)
6
+ super(source, proc)
7
7
  rescue ArgumentError, NameError => exc
8
- if exc.message.match(%r|undefined class/module (.+)|)
8
+ if exc.message.match(%r|undefined class/module (.+?)(?:::)?\z|)
9
9
  # try loading the class/module
10
- $1.constantize
11
- # if it is a IO we need to go back to read the object
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
12
15
  source.rewind if source.respond_to?(:rewind)
13
16
  retry
14
17
  else
15
18
  raise exc
16
19
  end
17
20
  end
18
-
19
- alias_method_chain :load, :autoloading
20
21
  end
21
22
  end
23
+
24
+ Marshal.singleton_class.prepend(ActiveSupport::MarshalWithAutoloading)
@@ -1,11 +1,14 @@
1
- require 'active_support/core_ext/module/aliasing'
2
- require 'active_support/core_ext/module/introspection'
3
- require 'active_support/core_ext/module/anonymous'
4
- require 'active_support/core_ext/module/reachable'
5
- require 'active_support/core_ext/module/attribute_accessors'
6
- require 'active_support/core_ext/module/attr_internal'
7
- require 'active_support/core_ext/module/concerning'
8
- require 'active_support/core_ext/module/delegation'
9
- require 'active_support/core_ext/module/deprecation'
10
- require 'active_support/core_ext/module/remove_method'
11
- require 'active_support/core_ext/module/qualified_const'
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/reachable"
7
+ require "active_support/core_ext/module/attribute_accessors"
8
+ require "active_support/core_ext/module/attribute_accessors_per_thread"
9
+ require "active_support/core_ext/module/attr_internal"
10
+ require "active_support/core_ext/module/concerning"
11
+ require "active_support/core_ext/module/delegation"
12
+ require "active_support/core_ext/module/deprecation"
13
+ require "active_support/core_ext/module/redefine_method"
14
+ require "active_support/core_ext/module/remove_method"
@@ -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,16 @@
1
- require 'active_support/core_ext/array/extract_options'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/array/extract_options"
4
+ require "active_support/core_ext/regexp"
2
5
 
3
6
  # Extends the module object with class/module and instance accessors for
4
7
  # class/module attributes, just like the native attr* accessors for instance
5
8
  # attributes.
6
9
  class Module
7
10
  # 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.
11
+ # The underlying class variable is set to +nil+, if it is not previously
12
+ # defined. All class and instance methods created will be public, even if
13
+ # this method is called with a private or protected access modifier.
10
14
  #
11
15
  # module HairColors
12
16
  # mattr_reader :hair_colors
@@ -19,15 +23,15 @@ class Module
19
23
  # The attribute name must be a valid method name in Ruby.
20
24
  #
21
25
  # module Foo
22
- # mattr_reader :"1_Badname "
26
+ # mattr_reader :"1_Badname"
23
27
  # end
24
- # # => NameError: invalid attribute name
28
+ # # => NameError: invalid attribute name: 1_Badname
25
29
  #
26
30
  # If you want to opt out the creation on the instance reader method, pass
27
31
  # <tt>instance_reader: false</tt> or <tt>instance_accessor: false</tt>.
28
32
  #
29
33
  # module HairColors
30
- # mattr_writer :hair_colors, instance_reader: false
34
+ # mattr_reader :hair_colors, instance_reader: false
31
35
  # end
32
36
  #
33
37
  # class Person
@@ -36,24 +40,20 @@ class Module
36
40
  #
37
41
  # Person.new.hair_colors # => NoMethodError
38
42
  #
39
- #
40
- # Also, you can pass a block to set up the attribute with a default value.
43
+ # You can set a default value for the attribute.
41
44
  #
42
45
  # module HairColors
43
- # cattr_reader :hair_colors do
44
- # [:brown, :black, :blonde, :red]
45
- # end
46
+ # mattr_reader :hair_colors, default: [:brown, :black, :blonde, :red]
46
47
  # end
47
48
  #
48
49
  # class Person
49
50
  # include HairColors
50
51
  # end
51
52
  #
52
- # Person.hair_colors # => [:brown, :black, :blonde, :red]
53
- def mattr_reader(*syms)
54
- options = syms.extract_options!
53
+ # Person.new.hair_colors # => [:brown, :black, :blonde, :red]
54
+ def mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil)
55
55
  syms.each do |sym|
56
- raise NameError.new("invalid attribute name: #{sym}") unless sym =~ /^[_A-Za-z]\w*$/
56
+ raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
57
57
  class_eval(<<-EOS, __FILE__, __LINE__ + 1)
58
58
  @@#{sym} = nil unless defined? @@#{sym}
59
59
 
@@ -62,20 +62,24 @@ class Module
62
62
  end
63
63
  EOS
64
64
 
65
- unless options[:instance_reader] == false || options[:instance_accessor] == false
65
+ if instance_reader && instance_accessor
66
66
  class_eval(<<-EOS, __FILE__, __LINE__ + 1)
67
67
  def #{sym}
68
68
  @@#{sym}
69
69
  end
70
70
  EOS
71
71
  end
72
- class_variable_set("@@#{sym}", yield) if block_given?
72
+
73
+ sym_default_value = (block_given? && default.nil?) ? yield : default
74
+ class_variable_set("@@#{sym}", sym_default_value) unless sym_default_value.nil?
73
75
  end
74
76
  end
75
77
  alias :cattr_reader :mattr_reader
76
78
 
77
79
  # Defines a class attribute and creates a class and instance writer methods to
78
- # allow assignment to the attribute.
80
+ # allow assignment to the attribute. All class and instance methods created
81
+ # will be public, even if this method is called with a private or protected
82
+ # access modifier.
79
83
  #
80
84
  # module HairColors
81
85
  # mattr_writer :hair_colors
@@ -103,12 +107,10 @@ class Module
103
107
  #
104
108
  # Person.new.hair_colors = [:blonde, :red] # => NoMethodError
105
109
  #
106
- # Also, you can pass a block to set up the attribute with a default value.
110
+ # You can set a default value for the attribute.
107
111
  #
108
- # class HairColors
109
- # mattr_writer :hair_colors do
110
- # [:brown, :black, :blonde, :red]
111
- # end
112
+ # module HairColors
113
+ # mattr_writer :hair_colors, default: [:brown, :black, :blonde, :red]
112
114
  # end
113
115
  #
114
116
  # class Person
@@ -116,10 +118,9 @@ class Module
116
118
  # end
117
119
  #
118
120
  # Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
119
- def mattr_writer(*syms)
120
- options = syms.extract_options!
121
+ def mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil)
121
122
  syms.each do |sym|
122
- raise NameError.new("invalid attribute name: #{sym}") unless sym =~ /^[_A-Za-z]\w*$/
123
+ raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
123
124
  class_eval(<<-EOS, __FILE__, __LINE__ + 1)
124
125
  @@#{sym} = nil unless defined? @@#{sym}
125
126
 
@@ -128,19 +129,23 @@ class Module
128
129
  end
129
130
  EOS
130
131
 
131
- unless options[:instance_writer] == false || options[:instance_accessor] == false
132
+ if instance_writer && instance_accessor
132
133
  class_eval(<<-EOS, __FILE__, __LINE__ + 1)
133
134
  def #{sym}=(obj)
134
135
  @@#{sym} = obj
135
136
  end
136
137
  EOS
137
138
  end
138
- send("#{sym}=", yield) if block_given?
139
+
140
+ sym_default_value = (block_given? && default.nil?) ? yield : default
141
+ send("#{sym}=", sym_default_value) unless sym_default_value.nil?
139
142
  end
140
143
  end
141
144
  alias :cattr_writer :mattr_writer
142
145
 
143
146
  # Defines both class and instance accessors for class attributes.
147
+ # All class and instance methods created will be public, even if
148
+ # this method is called with a private or protected access modifier.
144
149
  #
145
150
  # module HairColors
146
151
  # mattr_accessor :hair_colors
@@ -150,8 +155,8 @@ class Module
150
155
  # include HairColors
151
156
  # end
152
157
  #
153
- # Person.hair_colors = [:brown, :black, :blonde, :red]
154
- # Person.hair_colors # => [:brown, :black, :blonde, :red]
158
+ # HairColors.hair_colors = [:brown, :black, :blonde, :red]
159
+ # HairColors.hair_colors # => [:brown, :black, :blonde, :red]
155
160
  # Person.new.hair_colors # => [:brown, :black, :blonde, :red]
156
161
  #
157
162
  # If a subclass changes the value then that would also change the value for
@@ -161,8 +166,8 @@ class Module
161
166
  # class Male < Person
162
167
  # end
163
168
  #
164
- # Male.hair_colors << :blue
165
- # Person.hair_colors # => [:brown, :black, :blonde, :red, :blue]
169
+ # Male.new.hair_colors << :blue
170
+ # Person.new.hair_colors # => [:brown, :black, :blonde, :red, :blue]
166
171
  #
167
172
  # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
168
173
  # To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
@@ -191,22 +196,20 @@ class Module
191
196
  # Person.new.hair_colors = [:brown] # => NoMethodError
192
197
  # Person.new.hair_colors # => NoMethodError
193
198
  #
194
- # Also you can pass a block to set up the attribute with a default value.
199
+ # You can set a default value for the attribute.
195
200
  #
196
201
  # module HairColors
197
- # mattr_accessor :hair_colors do
198
- # [:brown, :black, :blonde, :red]
199
- # end
202
+ # mattr_accessor :hair_colors, default: [:brown, :black, :blonde, :red]
200
203
  # end
201
204
  #
202
205
  # class Person
203
206
  # include HairColors
204
207
  # end
205
208
  #
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)
209
+ # Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
210
+ def mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil, &blk)
211
+ mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor, default: default, &blk)
212
+ mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor, default: default)
210
213
  end
211
214
  alias :cattr_accessor :mattr_accessor
212
215
  end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/array/extract_options"
4
+ require "active_support/core_ext/regexp"
5
+
6
+ # Extends the module object with class/module and instance accessors for
7
+ # class/module attributes, just like the native attr* accessors for instance
8
+ # attributes, but does so on a per-thread basis.
9
+ #
10
+ # So the values are scoped within the Thread.current space under the class name
11
+ # of the module.
12
+ class Module
13
+ # Defines a per-thread class attribute and creates class and instance reader methods.
14
+ # The underlying per-thread class variable is set to +nil+, if it is not previously defined.
15
+ #
16
+ # module Current
17
+ # thread_mattr_reader :user
18
+ # end
19
+ #
20
+ # Current.user # => nil
21
+ # Thread.current[:attr_Current_user] = "DHH"
22
+ # Current.user # => "DHH"
23
+ #
24
+ # The attribute name must be a valid method name in Ruby.
25
+ #
26
+ # module Foo
27
+ # thread_mattr_reader :"1_Badname"
28
+ # end
29
+ # # => NameError: invalid attribute name: 1_Badname
30
+ #
31
+ # If you want to opt out of the creation of the instance reader method, pass
32
+ # <tt>instance_reader: false</tt> or <tt>instance_accessor: false</tt>.
33
+ #
34
+ # class Current
35
+ # thread_mattr_reader :user, instance_reader: false
36
+ # end
37
+ #
38
+ # Current.new.user # => NoMethodError
39
+ def thread_mattr_reader(*syms) # :nodoc:
40
+ options = syms.extract_options!
41
+
42
+ syms.each do |sym|
43
+ raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
44
+
45
+ # The following generated method concatenates `name` because we want it
46
+ # to work with inheritance via polymorphism.
47
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
48
+ def self.#{sym}
49
+ Thread.current["attr_" + name + "_#{sym}"]
50
+ end
51
+ EOS
52
+
53
+ unless options[:instance_reader] == false || options[:instance_accessor] == false
54
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
55
+ def #{sym}
56
+ self.class.#{sym}
57
+ end
58
+ EOS
59
+ end
60
+ end
61
+ end
62
+ alias :thread_cattr_reader :thread_mattr_reader
63
+
64
+ # Defines a per-thread class attribute and creates a class and instance writer methods to
65
+ # allow assignment to the attribute.
66
+ #
67
+ # module Current
68
+ # thread_mattr_writer :user
69
+ # end
70
+ #
71
+ # Current.user = "DHH"
72
+ # Thread.current[:attr_Current_user] # => "DHH"
73
+ #
74
+ # If you want to opt out of the creation of the instance writer method, pass
75
+ # <tt>instance_writer: false</tt> or <tt>instance_accessor: false</tt>.
76
+ #
77
+ # class Current
78
+ # thread_mattr_writer :user, instance_writer: false
79
+ # end
80
+ #
81
+ # Current.new.user = "DHH" # => NoMethodError
82
+ def thread_mattr_writer(*syms) # :nodoc:
83
+ options = syms.extract_options!
84
+ syms.each do |sym|
85
+ raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
86
+
87
+ # The following generated method concatenates `name` because we want it
88
+ # to work with inheritance via polymorphism.
89
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
90
+ def self.#{sym}=(obj)
91
+ Thread.current["attr_" + name + "_#{sym}"] = obj
92
+ end
93
+ EOS
94
+
95
+ unless options[:instance_writer] == false || options[:instance_accessor] == false
96
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
97
+ def #{sym}=(obj)
98
+ self.class.#{sym} = obj
99
+ end
100
+ EOS
101
+ end
102
+ end
103
+ end
104
+ alias :thread_cattr_writer :thread_mattr_writer
105
+
106
+ # Defines both class and instance accessors for class attributes.
107
+ #
108
+ # class Account
109
+ # thread_mattr_accessor :user
110
+ # end
111
+ #
112
+ # Account.user = "DHH"
113
+ # Account.user # => "DHH"
114
+ # Account.new.user # => "DHH"
115
+ #
116
+ # If a subclass changes the value, the parent class' value is not changed.
117
+ # Similarly, if the parent class changes the value, the value of subclasses
118
+ # is not changed.
119
+ #
120
+ # class Customer < Account
121
+ # end
122
+ #
123
+ # Customer.user = "Rafael"
124
+ # Customer.user # => "Rafael"
125
+ # Account.user # => "DHH"
126
+ #
127
+ # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
128
+ # To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
129
+ #
130
+ # class Current
131
+ # thread_mattr_accessor :user, instance_writer: false, instance_reader: false
132
+ # end
133
+ #
134
+ # Current.new.user = "DHH" # => NoMethodError
135
+ # Current.new.user # => NoMethodError
136
+ #
137
+ # Or pass <tt>instance_accessor: false</tt>, to opt out both instance methods.
138
+ #
139
+ # class Current
140
+ # mattr_accessor :user, instance_accessor: false
141
+ # end
142
+ #
143
+ # Current.new.user = "DHH" # => NoMethodError
144
+ # Current.new.user # => NoMethodError
145
+ def thread_mattr_accessor(*syms)
146
+ thread_mattr_reader(*syms)
147
+ thread_mattr_writer(*syms)
148
+ end
149
+ alias :thread_cattr_accessor :thread_mattr_accessor
150
+ end