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,7 +1,9 @@
1
- require 'active_support/core_ext/marshal'
2
- require 'active_support/core_ext/file/atomic'
3
- require 'active_support/core_ext/string/conversions'
4
- require 'uri/common'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/marshal"
4
+ require "active_support/core_ext/file/atomic"
5
+ require "active_support/core_ext/string/conversions"
6
+ require "uri/common"
5
7
 
6
8
  module ActiveSupport
7
9
  module Cache
@@ -10,34 +12,35 @@ module ActiveSupport
10
12
  # FileStore implements the Strategy::LocalCache strategy which implements
11
13
  # an in-memory cache inside of a block.
12
14
  class FileStore < Store
15
+ prepend Strategy::LocalCache
13
16
  attr_reader :cache_path
14
17
 
15
18
  DIR_FORMATTER = "%03X"
16
19
  FILENAME_MAX_SIZE = 228 # max filename size on file system is 255, minus room for timestamp and random characters appended by Tempfile (used by atomic write)
17
20
  FILEPATH_MAX_SIZE = 900 # max is 1024, plus some room
18
- EXCLUDED_DIRS = ['.', '..'].freeze
21
+ EXCLUDED_DIRS = [".", ".."].freeze
22
+ GITKEEP_FILES = [".gitkeep", ".keep"].freeze
19
23
 
20
24
  def initialize(cache_path, options = nil)
21
25
  super(options)
22
26
  @cache_path = cache_path.to_s
23
- extend Strategy::LocalCache
24
27
  end
25
28
 
26
29
  # Deletes all items from the cache. In this case it deletes all the entries in the specified
27
- # file store directory except for .gitkeep. Be careful which directory is specified in your
30
+ # file store directory except for .keep or .gitkeep. Be careful which directory is specified in your
28
31
  # config file when using +FileStore+ because everything in that directory will be deleted.
29
32
  def clear(options = nil)
30
- root_dirs = Dir.entries(cache_path).reject {|f| (EXCLUDED_DIRS + [".gitkeep"]).include?(f)}
31
- FileUtils.rm_r(root_dirs.collect{|f| File.join(cache_path, f)})
33
+ root_dirs = exclude_from(cache_path, EXCLUDED_DIRS + GITKEEP_FILES)
34
+ FileUtils.rm_r(root_dirs.collect { |f| File.join(cache_path, f) })
35
+ rescue Errno::ENOENT
32
36
  end
33
37
 
34
38
  # Preemptively iterates through all stored keys and removes the ones which have expired.
35
39
  def cleanup(options = nil)
36
40
  options = merged_options(options)
37
41
  search_dir(cache_path) do |fname|
38
- key = file_path_key(fname)
39
- entry = read_entry(key, options)
40
- delete_entry(key, options) if entry && entry.expired?
42
+ entry = read_entry(fname, options)
43
+ delete_entry(fname, options) if entry && entry.expired?
41
44
  end
42
45
  end
43
46
 
@@ -59,17 +62,16 @@ module ActiveSupport
59
62
  matcher = key_matcher(matcher, options)
60
63
  search_dir(cache_path) do |path|
61
64
  key = file_path_key(path)
62
- delete_entry(key, options) if key.match(matcher)
65
+ delete_entry(path, options) if key.match(matcher)
63
66
  end
64
67
  end
65
68
  end
66
69
 
67
- protected
70
+ private
68
71
 
69
72
  def read_entry(key, options)
70
- file_name = key_file_path(key)
71
- if File.exist?(file_name)
72
- File.open(file_name) { |f| Marshal.load(f) }
73
+ if File.exist?(key)
74
+ File.open(key) { |f| Marshal.load(f) }
73
75
  end
74
76
  rescue => e
75
77
  logger.error("FileStoreError (#{e}): #{e.message}") if logger
@@ -77,33 +79,30 @@ module ActiveSupport
77
79
  end
78
80
 
79
81
  def write_entry(key, entry, options)
80
- file_name = key_file_path(key)
81
- return false if options[:unless_exist] && File.exist?(file_name)
82
- ensure_cache_path(File.dirname(file_name))
83
- File.atomic_write(file_name, cache_path) {|f| Marshal.dump(entry, f)}
82
+ return false if options[:unless_exist] && File.exist?(key)
83
+ ensure_cache_path(File.dirname(key))
84
+ File.atomic_write(key, cache_path) { |f| Marshal.dump(entry, f) }
84
85
  true
85
86
  end
86
87
 
87
88
  def delete_entry(key, options)
88
- file_name = key_file_path(key)
89
- if File.exist?(file_name)
89
+ if File.exist?(key)
90
90
  begin
91
- File.delete(file_name)
92
- delete_empty_directories(File.dirname(file_name))
91
+ File.delete(key)
92
+ delete_empty_directories(File.dirname(key))
93
93
  true
94
94
  rescue => e
95
95
  # Just in case the error was caused by another process deleting the file first.
96
- raise e if File.exist?(file_name)
96
+ raise e if File.exist?(key)
97
97
  false
98
98
  end
99
99
  end
100
100
  end
101
101
 
102
- private
103
102
  # Lock a file for a block so only one process can modify it at a time.
104
- def lock_file(file_name, &block) # :nodoc:
103
+ def lock_file(file_name, &block)
105
104
  if File.exist?(file_name)
106
- File.open(file_name, 'r+') do |f|
105
+ File.open(file_name, "r+") do |f|
107
106
  begin
108
107
  f.flock File::LOCK_EX
109
108
  yield
@@ -117,12 +116,14 @@ module ActiveSupport
117
116
  end
118
117
 
119
118
  # Translate a key into a file path.
120
- def key_file_path(key)
121
- if key.size > FILEPATH_MAX_SIZE
122
- key = Digest::MD5.hexdigest(key)
119
+ def normalize_key(key, options)
120
+ key = super
121
+ fname = URI.encode_www_form_component(key)
122
+
123
+ if fname.size > FILEPATH_MAX_SIZE
124
+ fname = ActiveSupport::Digest.hexdigest(key)
123
125
  end
124
126
 
125
- fname = URI.encode_www_form_component(key)
126
127
  hash = Zlib.adler32(fname)
127
128
  hash, dir_1 = hash.divmod(0x1000)
128
129
  dir_2 = hash.modulo(0x1000)
@@ -146,7 +147,7 @@ module ActiveSupport
146
147
  # Delete empty directories in the cache.
147
148
  def delete_empty_directories(dir)
148
149
  return if File.realpath(dir) == File.realpath(cache_path)
149
- if Dir.entries(dir).reject {|f| EXCLUDED_DIRS.include?(f)}.empty?
150
+ if exclude_from(dir, EXCLUDED_DIRS).empty?
150
151
  Dir.delete(dir) rescue nil
151
152
  delete_empty_directories(File.dirname(dir))
152
153
  end
@@ -173,7 +174,7 @@ module ActiveSupport
173
174
  # Modifies the amount of an already existing integer value that is stored in the cache.
174
175
  # If the key is not found nothing is done.
175
176
  def modify_value(name, amount, options)
176
- file_name = key_file_path(namespaced_key(name, options))
177
+ file_name = normalize_key(name, options)
177
178
 
178
179
  lock_file(file_name) do
179
180
  options = merged_options(options)
@@ -185,6 +186,11 @@ module ActiveSupport
185
186
  end
186
187
  end
187
188
  end
189
+
190
+ # Exclude entries from source directory
191
+ def exclude_from(source, excludes)
192
+ Dir.entries(source).reject { |f| excludes.include?(f) }
193
+ end
188
194
  end
189
195
  end
190
196
  end
@@ -1,18 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
- require 'dalli'
4
+ require "dalli"
3
5
  rescue LoadError => e
4
6
  $stderr.puts "You don't have dalli installed in your application. Please add it to your Gemfile and run bundle install"
5
7
  raise e
6
8
  end
7
9
 
8
- require 'digest/md5'
9
- require 'active_support/core_ext/marshal'
10
- require 'active_support/core_ext/array/extract_options'
10
+ require "active_support/core_ext/marshal"
11
+ require "active_support/core_ext/array/extract_options"
11
12
 
12
13
  module ActiveSupport
13
14
  module Cache
14
15
  # A cache store implementation which stores data in Memcached:
15
- # http://memcached.org/
16
+ # https://memcached.org
16
17
  #
17
18
  # This is currently the most popular cache store for production websites.
18
19
  #
@@ -24,13 +25,52 @@ module ActiveSupport
24
25
  # MemCacheStore implements the Strategy::LocalCache strategy which implements
25
26
  # an in-memory cache inside of a block.
26
27
  class MemCacheStore < Store
28
+ # Provide support for raw values in the local cache strategy.
29
+ module LocalCacheWithRaw # :nodoc:
30
+ private
31
+ def read_entry(key, options)
32
+ entry = super
33
+ if options[:raw] && local_cache && entry
34
+ entry = deserialize_entry(entry.value)
35
+ end
36
+ entry
37
+ end
38
+
39
+ def write_entry(key, entry, options)
40
+ if options[:raw] && local_cache
41
+ raw_entry = Entry.new(entry.value.to_s)
42
+ raw_entry.expires_at = entry.expires_at
43
+ super(key, raw_entry, options)
44
+ else
45
+ super
46
+ end
47
+ end
48
+ end
49
+
50
+ prepend Strategy::LocalCache
51
+ prepend LocalCacheWithRaw
52
+
27
53
  ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
28
54
 
29
- def self.build_mem_cache(*addresses)
55
+ # Creates a new Dalli::Client instance with specified addresses and options.
56
+ # By default address is equal localhost:11211.
57
+ #
58
+ # ActiveSupport::Cache::MemCacheStore.build_mem_cache
59
+ # # => #<Dalli::Client:0x007f98a47d2028 @servers=["localhost:11211"], @options={}, @ring=nil>
60
+ # ActiveSupport::Cache::MemCacheStore.build_mem_cache('localhost:10290')
61
+ # # => #<Dalli::Client:0x007f98a47b3a60 @servers=["localhost:10290"], @options={}, @ring=nil>
62
+ def self.build_mem_cache(*addresses) # :nodoc:
30
63
  addresses = addresses.flatten
31
64
  options = addresses.extract_options!
32
65
  addresses = ["localhost:11211"] if addresses.empty?
33
- Dalli::Client.new(addresses, options)
66
+ pool_options = retrieve_pool_options(options)
67
+
68
+ if pool_options.empty?
69
+ Dalli::Client.new(addresses, options)
70
+ else
71
+ ensure_connection_pool_added!
72
+ ConnectionPool.new(pool_options) { Dalli::Client.new(addresses, options.merge(threadsafe: false)) }
73
+ end
34
74
  end
35
75
 
36
76
  # Creates a new MemCacheStore object, with the given memcached server
@@ -53,82 +93,56 @@ module ActiveSupport
53
93
  @data = addresses.first
54
94
  else
55
95
  mem_cache_options = options.dup
56
- UNIVERSAL_OPTIONS.each{|name| mem_cache_options.delete(name)}
96
+ UNIVERSAL_OPTIONS.each { |name| mem_cache_options.delete(name) }
57
97
  @data = self.class.build_mem_cache(*(addresses + [mem_cache_options]))
58
98
  end
59
-
60
- extend Strategy::LocalCache
61
- extend LocalCacheWithRaw
62
- end
63
-
64
- # Reads multiple values from the cache using a single call to the
65
- # servers for all keys. Options can be passed in the last argument.
66
- def read_multi(*names)
67
- options = names.extract_options!
68
- options = merged_options(options)
69
- keys_to_names = Hash[names.map{|name| [escape_key(namespaced_key(name, options)), name]}]
70
- raw_values = @data.get_multi(keys_to_names.keys, :raw => true)
71
- values = {}
72
- raw_values.each do |key, value|
73
- entry = deserialize_entry(value)
74
- values[keys_to_names[key]] = entry.value unless entry.expired?
75
- end
76
- values
77
99
  end
78
100
 
79
101
  # Increment a cached value. This method uses the memcached incr atomic
80
102
  # operator and can only be used on values written with the :raw option.
81
103
  # Calling it on a value not stored with :raw will initialize that value
82
104
  # to zero.
83
- def increment(name, amount = 1, options = nil) # :nodoc:
105
+ def increment(name, amount = 1, options = nil)
84
106
  options = merged_options(options)
85
- instrument(:increment, name, :amount => amount) do
86
- @data.incr(escape_key(namespaced_key(name, options)), amount)
107
+ instrument(:increment, name, amount: amount) do
108
+ rescue_error_with nil do
109
+ @data.with { |c| c.incr(normalize_key(name, options), amount, options[:expires_in]) }
110
+ end
87
111
  end
88
- rescue Dalli::DalliError => e
89
- logger.error("DalliError (#{e}): #{e.message}") if logger
90
- nil
91
112
  end
92
113
 
93
114
  # Decrement a cached value. This method uses the memcached decr atomic
94
115
  # operator and can only be used on values written with the :raw option.
95
116
  # Calling it on a value not stored with :raw will initialize that value
96
117
  # to zero.
97
- def decrement(name, amount = 1, options = nil) # :nodoc:
118
+ def decrement(name, amount = 1, options = nil)
98
119
  options = merged_options(options)
99
- instrument(:decrement, name, :amount => amount) do
100
- @data.decr(escape_key(namespaced_key(name, options)), amount)
120
+ instrument(:decrement, name, amount: amount) do
121
+ rescue_error_with nil do
122
+ @data.with { |c| c.decr(normalize_key(name, options), amount, options[:expires_in]) }
123
+ end
101
124
  end
102
- rescue Dalli::DalliError => e
103
- logger.error("DalliError (#{e}): #{e.message}") if logger
104
- nil
105
125
  end
106
126
 
107
127
  # Clear the entire cache on all memcached servers. This method should
108
128
  # be used with care when shared cache is being used.
109
129
  def clear(options = nil)
110
- @data.flush_all
111
- rescue Dalli::DalliError => e
112
- logger.error("DalliError (#{e}): #{e.message}") if logger
113
- nil
130
+ rescue_error_with(nil) { @data.with { |c| c.flush_all } }
114
131
  end
115
132
 
116
133
  # Get the statistics from the memcached servers.
117
134
  def stats
118
- @data.stats
135
+ @data.with { |c| c.stats }
119
136
  end
120
137
 
121
- protected
138
+ private
122
139
  # Read an entry from the cache.
123
- def read_entry(key, options) # :nodoc:
124
- deserialize_entry(@data.get(escape_key(key), options))
125
- rescue Dalli::DalliError => e
126
- logger.error("DalliError (#{e}): #{e.message}") if logger
127
- nil
140
+ def read_entry(key, options)
141
+ rescue_error_with(nil) { deserialize_entry(@data.with { |c| c.get(key, options) }) }
128
142
  end
129
143
 
130
144
  # Write an entry to the cache.
131
- def write_entry(key, entry, options) # :nodoc:
145
+ def write_entry(key, entry, options)
132
146
  method = options && options[:unless_exist] ? :add : :set
133
147
  value = options[:raw] ? entry.value.to_s : entry
134
148
  expires_in = options[:expires_in].to_i
@@ -136,30 +150,42 @@ module ActiveSupport
136
150
  # Set the memcache expire a few minutes in the future to support race condition ttls on read
137
151
  expires_in += 5.minutes
138
152
  end
139
- @data.send(method, escape_key(key), value, expires_in, options)
140
- rescue Dalli::DalliError => e
141
- logger.error("DalliError (#{e}): #{e.message}") if logger
142
- false
153
+ rescue_error_with false do
154
+ @data.with { |c| c.send(method, key, value, expires_in, options) }
155
+ end
143
156
  end
144
157
 
145
- # Delete an entry from the cache.
146
- def delete_entry(key, options) # :nodoc:
147
- @data.delete(escape_key(key))
148
- rescue Dalli::DalliError => e
149
- logger.error("DalliError (#{e}): #{e.message}") if logger
150
- false
158
+ # Reads multiple entries from the cache implementation.
159
+ def read_multi_entries(names, options)
160
+ keys_to_names = Hash[names.map { |name| [normalize_key(name, options), name] }]
161
+
162
+ raw_values = @data.with { |c| c.get_multi(keys_to_names.keys) }
163
+ values = {}
164
+
165
+ raw_values.each do |key, value|
166
+ entry = deserialize_entry(value)
167
+
168
+ unless entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options))
169
+ values[keys_to_names[key]] = entry.value
170
+ end
171
+ end
172
+
173
+ values
151
174
  end
152
175
 
153
- private
176
+ # Delete an entry from the cache.
177
+ def delete_entry(key, options)
178
+ rescue_error_with(false) { @data.with { |c| c.delete(key) } }
179
+ end
154
180
 
155
181
  # Memcache keys are binaries. So we need to force their encoding to binary
156
182
  # before applying the regular expression to ensure we are escaping all
157
183
  # characters properly.
158
- def escape_key(key)
159
- key = key.to_s.dup
184
+ def normalize_key(key, options)
185
+ key = super.dup
160
186
  key = key.force_encoding(Encoding::ASCII_8BIT)
161
- key = key.gsub(ESCAPE_KEY_CHARS){ |match| "%#{match.getbyte(0).to_s(16).upcase}" }
162
- key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250
187
+ key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" }
188
+ key = "#{key[0, 213]}:md5:#{ActiveSupport::Digest.hexdigest(key)}" if key.size > 250
163
189
  key
164
190
  end
165
191
 
@@ -167,32 +193,15 @@ module ActiveSupport
167
193
  if raw_value
168
194
  entry = Marshal.load(raw_value) rescue raw_value
169
195
  entry.is_a?(Entry) ? entry : Entry.new(entry)
170
- else
171
- nil
172
196
  end
173
197
  end
174
198
 
175
- # Provide support for raw values in the local cache strategy.
176
- module LocalCacheWithRaw # :nodoc:
177
- protected
178
- def read_entry(key, options)
179
- entry = super
180
- if options[:raw] && local_cache && entry
181
- entry = deserialize_entry(entry.value)
182
- end
183
- entry
184
- end
185
-
186
- def write_entry(key, entry, options) # :nodoc:
187
- retval = super
188
- if options[:raw] && local_cache && retval
189
- raw_entry = Entry.new(entry.value.to_s)
190
- raw_entry.expires_at = entry.expires_at
191
- local_cache.write_entry(key, raw_entry, options)
192
- end
193
- retval
194
- end
195
- end
199
+ def rescue_error_with(fallback)
200
+ yield
201
+ rescue Dalli::DalliError => e
202
+ logger.error("DalliError (#{e}): #{e.message}") if logger
203
+ fallback
204
+ end
196
205
  end
197
206
  end
198
207
  end
@@ -1,10 +1,12 @@
1
- require 'monitor'
1
+ # frozen_string_literal: true
2
+
3
+ require "monitor"
2
4
 
3
5
  module ActiveSupport
4
6
  module Cache
5
7
  # A cache store implementation which stores everything into memory in the
6
8
  # same process. If you're running multiple Ruby on Rails server processes
7
- # (which is the case if you're using mongrel_cluster or Phusion Passenger),
9
+ # (which is the case if you're using Phusion Passenger or puma clustered mode),
8
10
  # then this means that Rails server process instances won't be able
9
11
  # to share cache data with each other and this may not be the most
10
12
  # appropriate cache in that scenario.
@@ -28,6 +30,7 @@ module ActiveSupport
28
30
  @pruning = false
29
31
  end
30
32
 
33
+ # Delete all data stored in a given cache store.
31
34
  def clear(options = nil)
32
35
  synchronize do
33
36
  @data.clear
@@ -39,8 +42,8 @@ module ActiveSupport
39
42
  # Preemptively iterates through all stored keys and removes the ones which have expired.
40
43
  def cleanup(options = nil)
41
44
  options = merged_options(options)
42
- instrument(:cleanup, :size => @data.size) do
43
- keys = synchronize{ @data.keys }
45
+ instrument(:cleanup, size: @data.size) do
46
+ keys = synchronize { @data.keys }
44
47
  keys.each do |key|
45
48
  entry = @data[key]
46
49
  delete_entry(key, options) if entry && entry.expired?
@@ -56,8 +59,8 @@ module ActiveSupport
56
59
  begin
57
60
  start_time = Time.now
58
61
  cleanup
59
- instrument(:prune, target_size, :from => @cache_size) do
60
- keys = synchronize{ @key_access.keys.sort{|a,b| @key_access[a].to_f <=> @key_access[b].to_f} }
62
+ instrument(:prune, target_size, from: @cache_size) do
63
+ keys = synchronize { @key_access.keys.sort { |a, b| @key_access[a].to_f <=> @key_access[b].to_f } }
61
64
  keys.each do |key|
62
65
  delete_entry(key, options)
63
66
  return if @cache_size <= target_size || (max_time && Time.now - start_time > max_time)
@@ -75,32 +78,15 @@ module ActiveSupport
75
78
 
76
79
  # Increment an integer value in the cache.
77
80
  def increment(name, amount = 1, options = nil)
78
- synchronize do
79
- options = merged_options(options)
80
- if num = read(name, options)
81
- num = num.to_i + amount
82
- write(name, num, options)
83
- num
84
- else
85
- nil
86
- end
87
- end
81
+ modify_value(name, amount, options)
88
82
  end
89
83
 
90
84
  # Decrement an integer value in the cache.
91
85
  def decrement(name, amount = 1, options = nil)
92
- synchronize do
93
- options = merged_options(options)
94
- if num = read(name, options)
95
- num = num.to_i - amount
96
- write(name, num, options)
97
- num
98
- else
99
- nil
100
- end
101
- end
86
+ modify_value(name, -amount, options)
102
87
  end
103
88
 
89
+ # Deletes cache entries if the cache key matches a given pattern.
104
90
  def delete_matched(matcher, options = nil)
105
91
  options = merged_options(options)
106
92
  instrument(:delete_matched, matcher.inspect) do
@@ -122,7 +108,7 @@ module ActiveSupport
122
108
  @monitor.synchronize(&block)
123
109
  end
124
110
 
125
- protected
111
+ private
126
112
 
127
113
  PER_ENTRY_OVERHEAD = 240
128
114
 
@@ -130,7 +116,7 @@ module ActiveSupport
130
116
  key.to_s.bytesize + entry.size + PER_ENTRY_OVERHEAD
131
117
  end
132
118
 
133
- def read_entry(key, options) # :nodoc:
119
+ def read_entry(key, options)
134
120
  entry = @data[key]
135
121
  synchronize do
136
122
  if entry
@@ -142,7 +128,7 @@ module ActiveSupport
142
128
  entry
143
129
  end
144
130
 
145
- def write_entry(key, entry, options) # :nodoc:
131
+ def write_entry(key, entry, options)
146
132
  entry.dup_value!
147
133
  synchronize do
148
134
  old_entry = @data[key]
@@ -159,7 +145,7 @@ module ActiveSupport
159
145
  end
160
146
  end
161
147
 
162
- def delete_entry(key, options) # :nodoc:
148
+ def delete_entry(key, options)
163
149
  synchronize do
164
150
  @key_access.delete(key)
165
151
  entry = @data.delete(key)
@@ -167,6 +153,17 @@ module ActiveSupport
167
153
  !!entry
168
154
  end
169
155
  end
156
+
157
+ def modify_value(name, amount, options)
158
+ synchronize do
159
+ options = merged_options(options)
160
+ if num = read(name, options)
161
+ num = num.to_i + amount
162
+ write(name, num, options)
163
+ num
164
+ end
165
+ end
166
+ end
170
167
  end
171
168
  end
172
169
  end