activesupport 3.1.0 → 5.0.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 (276) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +798 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +13 -7
  5. data/lib/active_support/array_inquirer.rb +44 -0
  6. data/lib/active_support/backtrace_cleaner.rb +38 -34
  7. data/lib/active_support/benchmarkable.rb +17 -28
  8. data/lib/active_support/cache/file_store.rb +85 -70
  9. data/lib/active_support/cache/mem_cache_store.rb +75 -66
  10. data/lib/active_support/cache/memory_store.rb +31 -23
  11. data/lib/active_support/cache/null_store.rb +41 -0
  12. data/lib/active_support/cache/strategy/local_cache.rb +73 -70
  13. data/lib/active_support/cache/strategy/local_cache_middleware.rb +44 -0
  14. data/lib/active_support/cache.rb +360 -294
  15. data/lib/active_support/callbacks.rb +563 -393
  16. data/lib/active_support/concern.rb +42 -34
  17. data/lib/active_support/concurrency/latch.rb +19 -0
  18. data/lib/active_support/concurrency/share_lock.rb +186 -0
  19. data/lib/active_support/configurable.rb +70 -12
  20. data/lib/active_support/core_ext/array/access.rb +53 -9
  21. data/lib/active_support/core_ext/array/conversions.rb +109 -62
  22. data/lib/active_support/core_ext/array/extract_options.rb +2 -2
  23. data/lib/active_support/core_ext/array/grouping.rb +39 -32
  24. data/lib/active_support/core_ext/array/inquiry.rb +17 -0
  25. data/lib/active_support/core_ext/array/prepend_and_append.rb +7 -0
  26. data/lib/active_support/core_ext/array/wrap.rb +16 -18
  27. data/lib/active_support/core_ext/array.rb +2 -2
  28. data/lib/active_support/core_ext/benchmark.rb +7 -0
  29. data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -36
  30. data/lib/active_support/core_ext/class/attribute.rb +47 -34
  31. data/lib/active_support/core_ext/class/attribute_accessors.rb +4 -79
  32. data/lib/active_support/core_ext/class/subclasses.rb +12 -7
  33. data/lib/active_support/core_ext/class.rb +0 -3
  34. data/lib/active_support/core_ext/date/blank.rb +12 -0
  35. data/lib/active_support/core_ext/date/calculations.rb +57 -167
  36. data/lib/active_support/core_ext/date/conversions.rb +31 -42
  37. data/lib/active_support/core_ext/date/zones.rb +2 -10
  38. data/lib/active_support/core_ext/date.rb +5 -0
  39. data/lib/active_support/core_ext/date_and_time/calculations.rb +335 -0
  40. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -0
  41. data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
  42. data/lib/active_support/core_ext/date_time/acts_like.rb +1 -0
  43. data/lib/active_support/core_ext/date_time/blank.rb +12 -0
  44. data/lib/active_support/core_ext/date_time/calculations.rb +132 -65
  45. data/lib/active_support/core_ext/date_time/compatibility.rb +5 -0
  46. data/lib/active_support/core_ext/date_time/conversions.rb +36 -34
  47. data/lib/active_support/core_ext/date_time.rb +5 -0
  48. data/lib/active_support/core_ext/digest/uuid.rb +51 -0
  49. data/lib/active_support/core_ext/enumerable.rb +81 -74
  50. data/lib/active_support/core_ext/file/atomic.rb +53 -26
  51. data/lib/active_support/core_ext/file.rb +0 -1
  52. data/lib/active_support/core_ext/hash/compact.rb +20 -0
  53. data/lib/active_support/core_ext/hash/conversions.rb +175 -70
  54. data/lib/active_support/core_ext/hash/deep_merge.rb +30 -8
  55. data/lib/active_support/core_ext/hash/except.rb +11 -12
  56. data/lib/active_support/core_ext/hash/indifferent_access.rb +7 -8
  57. data/lib/active_support/core_ext/hash/keys.rb +147 -24
  58. data/lib/active_support/core_ext/hash/reverse_merge.rb +2 -3
  59. data/lib/active_support/core_ext/hash/slice.rb +22 -14
  60. data/lib/active_support/core_ext/hash/transform_values.rb +29 -0
  61. data/lib/active_support/core_ext/hash.rb +2 -2
  62. data/lib/active_support/core_ext/integer/inflections.rb +13 -1
  63. data/lib/active_support/core_ext/integer/multiple.rb +4 -0
  64. data/lib/active_support/core_ext/integer/time.rb +12 -22
  65. data/lib/active_support/core_ext/kernel/agnostics.rb +2 -2
  66. data/lib/active_support/core_ext/kernel/concern.rb +12 -0
  67. data/lib/active_support/core_ext/kernel/debugger.rb +2 -15
  68. data/lib/active_support/core_ext/kernel/reporting.rb +12 -62
  69. data/lib/active_support/core_ext/kernel/singleton_class.rb +0 -7
  70. data/lib/active_support/core_ext/kernel.rb +2 -3
  71. data/lib/active_support/core_ext/load_error.rb +14 -7
  72. data/lib/active_support/core_ext/marshal.rb +22 -0
  73. data/lib/active_support/core_ext/module/aliasing.rb +16 -12
  74. data/lib/active_support/core_ext/module/anonymous.rb +12 -8
  75. data/lib/active_support/core_ext/module/attr_internal.rb +2 -5
  76. data/lib/active_support/core_ext/module/attribute_accessors.rb +165 -13
  77. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
  78. data/lib/active_support/core_ext/module/concerning.rb +135 -0
  79. data/lib/active_support/core_ext/module/delegation.rb +141 -68
  80. data/lib/active_support/core_ext/module/deprecation.rb +17 -3
  81. data/lib/active_support/core_ext/module/introspection.rb +9 -31
  82. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -0
  83. data/lib/active_support/core_ext/module/qualified_const.rb +70 -0
  84. data/lib/active_support/core_ext/module/reachable.rb +1 -3
  85. data/lib/active_support/core_ext/module/remove_method.rb +24 -5
  86. data/lib/active_support/core_ext/module.rb +3 -3
  87. data/lib/active_support/core_ext/name_error.rb +15 -2
  88. data/lib/active_support/core_ext/numeric/bytes.rb +20 -0
  89. data/lib/active_support/core_ext/numeric/conversions.rb +145 -0
  90. data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
  91. data/lib/active_support/core_ext/numeric/time.rb +31 -36
  92. data/lib/active_support/core_ext/numeric.rb +2 -0
  93. data/lib/active_support/core_ext/object/acts_like.rb +4 -4
  94. data/lib/active_support/core_ext/object/blank.rb +52 -18
  95. data/lib/active_support/core_ext/object/deep_dup.rb +53 -0
  96. data/lib/active_support/core_ext/object/duplicable.rb +12 -20
  97. data/lib/active_support/core_ext/object/inclusion.rb +13 -1
  98. data/lib/active_support/core_ext/object/instance_variables.rb +7 -12
  99. data/lib/active_support/core_ext/object/json.rb +205 -0
  100. data/lib/active_support/core_ext/object/to_param.rb +1 -55
  101. data/lib/active_support/core_ext/object/to_query.rb +66 -9
  102. data/lib/active_support/core_ext/object/try.rb +124 -33
  103. data/lib/active_support/core_ext/object/with_options.rb +37 -11
  104. data/lib/active_support/core_ext/object.rb +2 -1
  105. data/lib/active_support/core_ext/range/conversions.rb +17 -7
  106. data/lib/active_support/core_ext/range/each.rb +21 -0
  107. data/lib/active_support/core_ext/range/include_range.rb +20 -18
  108. data/lib/active_support/core_ext/range/overlaps.rb +1 -1
  109. data/lib/active_support/core_ext/range.rb +1 -2
  110. data/lib/active_support/core_ext/securerandom.rb +23 -0
  111. data/lib/active_support/core_ext/string/access.rb +95 -90
  112. data/lib/active_support/core_ext/string/behavior.rb +1 -1
  113. data/lib/active_support/core_ext/string/conversions.rb +41 -38
  114. data/lib/active_support/core_ext/string/exclude.rb +6 -1
  115. data/lib/active_support/core_ext/string/filters.rb +70 -17
  116. data/lib/active_support/core_ext/string/indent.rb +43 -0
  117. data/lib/active_support/core_ext/string/inflections.rb +139 -59
  118. data/lib/active_support/core_ext/string/inquiry.rb +2 -2
  119. data/lib/active_support/core_ext/string/multibyte.rb +46 -65
  120. data/lib/active_support/core_ext/string/output_safety.rb +153 -56
  121. data/lib/active_support/core_ext/string/strip.rb +3 -6
  122. data/lib/active_support/core_ext/string/zones.rb +14 -0
  123. data/lib/active_support/core_ext/string.rb +2 -3
  124. data/lib/active_support/core_ext/struct.rb +3 -0
  125. data/lib/active_support/core_ext/time/calculations.rb +173 -173
  126. data/lib/active_support/core_ext/time/compatibility.rb +5 -0
  127. data/lib/active_support/core_ext/time/conversions.rb +33 -29
  128. data/lib/active_support/core_ext/time/marshal.rb +2 -56
  129. data/lib/active_support/core_ext/time/zones.rb +57 -32
  130. data/lib/active_support/core_ext/time.rb +5 -0
  131. data/lib/active_support/core_ext/uri.rb +13 -19
  132. data/lib/active_support/core_ext.rb +3 -2
  133. data/lib/active_support/dependencies/autoload.rb +47 -20
  134. data/lib/active_support/dependencies/interlock.rb +51 -0
  135. data/lib/active_support/dependencies.rb +315 -265
  136. data/lib/active_support/deprecation/behaviors.rb +71 -30
  137. data/lib/active_support/deprecation/instance_delegator.rb +24 -0
  138. data/lib/active_support/deprecation/method_wrappers.rb +59 -18
  139. data/lib/active_support/deprecation/proxy_wrappers.rb +82 -14
  140. data/lib/active_support/deprecation/reporting.rb +61 -14
  141. data/lib/active_support/deprecation.rb +38 -13
  142. data/lib/active_support/descendants_tracker.rb +34 -19
  143. data/lib/active_support/duration/iso8601_parser.rb +122 -0
  144. data/lib/active_support/duration/iso8601_serializer.rb +51 -0
  145. data/lib/active_support/duration.rb +85 -14
  146. data/lib/active_support/evented_file_update_checker.rb +194 -0
  147. data/lib/active_support/execution_wrapper.rb +117 -0
  148. data/lib/active_support/executor.rb +6 -0
  149. data/lib/active_support/file_update_checker.rb +138 -17
  150. data/lib/active_support/gem_version.rb +15 -0
  151. data/lib/active_support/gzip.rb +11 -5
  152. data/lib/active_support/hash_with_indifferent_access.rb +199 -49
  153. data/lib/active_support/i18n.rb +6 -2
  154. data/lib/active_support/i18n_railtie.rb +40 -21
  155. data/lib/active_support/inflections.rb +22 -13
  156. data/lib/active_support/inflector/inflections.rb +175 -144
  157. data/lib/active_support/inflector/methods.rb +328 -91
  158. data/lib/active_support/inflector/transliterate.rb +51 -37
  159. data/lib/active_support/json/decoding.rb +31 -22
  160. data/lib/active_support/json/encoding.rb +88 -248
  161. data/lib/active_support/key_generator.rb +71 -0
  162. data/lib/active_support/lazy_load_hooks.rb +27 -25
  163. data/lib/active_support/locale/en.yml +102 -3
  164. data/lib/active_support/log_subscriber/test_helper.rb +24 -21
  165. data/lib/active_support/log_subscriber.rb +36 -49
  166. data/lib/active_support/logger.rb +106 -0
  167. data/lib/active_support/logger_silence.rb +28 -0
  168. data/lib/active_support/logger_thread_safe_level.rb +31 -0
  169. data/lib/active_support/message_encryptor.rb +72 -36
  170. data/lib/active_support/message_verifier.rb +96 -24
  171. data/lib/active_support/multibyte/chars.rb +88 -333
  172. data/lib/active_support/multibyte/unicode.rb +156 -136
  173. data/lib/active_support/multibyte.rb +5 -28
  174. data/lib/active_support/notifications/fanout.rb +115 -19
  175. data/lib/active_support/notifications/instrumenter.rb +52 -15
  176. data/lib/active_support/notifications.rb +168 -33
  177. data/lib/active_support/number_helper/number_converter.rb +182 -0
  178. data/lib/active_support/number_helper/number_to_currency_converter.rb +44 -0
  179. data/lib/active_support/number_helper/number_to_delimited_converter.rb +28 -0
  180. data/lib/active_support/number_helper/number_to_human_converter.rb +68 -0
  181. data/lib/active_support/number_helper/number_to_human_size_converter.rb +62 -0
  182. data/lib/active_support/number_helper/number_to_percentage_converter.rb +12 -0
  183. data/lib/active_support/number_helper/number_to_phone_converter.rb +58 -0
  184. data/lib/active_support/number_helper/number_to_rounded_converter.rb +92 -0
  185. data/lib/active_support/number_helper.rb +368 -0
  186. data/lib/active_support/option_merger.rb +1 -1
  187. data/lib/active_support/ordered_hash.rb +18 -183
  188. data/lib/active_support/ordered_options.rb +44 -24
  189. data/lib/active_support/per_thread_registry.rb +58 -0
  190. data/lib/active_support/proxy_object.rb +13 -0
  191. data/lib/active_support/rails.rb +27 -0
  192. data/lib/active_support/railtie.rb +25 -34
  193. data/lib/active_support/reloader.rb +129 -0
  194. data/lib/active_support/rescuable.rb +98 -48
  195. data/lib/active_support/security_utils.rb +27 -0
  196. data/lib/active_support/string_inquirer.rb +14 -9
  197. data/lib/active_support/subscriber.rb +120 -0
  198. data/lib/active_support/tagged_logging.rb +78 -0
  199. data/lib/active_support/test_case.rb +69 -17
  200. data/lib/active_support/testing/assertions.rb +43 -41
  201. data/lib/active_support/testing/autorun.rb +12 -0
  202. data/lib/active_support/testing/constant_lookup.rb +50 -0
  203. data/lib/active_support/testing/declarative.rb +7 -21
  204. data/lib/active_support/testing/deprecation.rb +14 -33
  205. data/lib/active_support/testing/file_fixtures.rb +34 -0
  206. data/lib/active_support/testing/isolation.rb +53 -95
  207. data/lib/active_support/testing/method_call_assertions.rb +41 -0
  208. data/lib/active_support/testing/setup_and_teardown.rb +21 -82
  209. data/lib/active_support/testing/stream.rb +42 -0
  210. data/lib/active_support/testing/tagged_logging.rb +25 -0
  211. data/lib/active_support/testing/time_helpers.rb +134 -0
  212. data/lib/active_support/time.rb +6 -23
  213. data/lib/active_support/time_with_zone.rb +239 -92
  214. data/lib/active_support/values/time_zone.rb +236 -160
  215. data/lib/active_support/values/unicode_tables.dat +0 -0
  216. data/lib/active_support/version.rb +5 -7
  217. data/lib/active_support/xml_mini/jdom.rb +19 -13
  218. data/lib/active_support/xml_mini/libxml.rb +3 -4
  219. data/lib/active_support/xml_mini/libxmlsax.rb +2 -3
  220. data/lib/active_support/xml_mini/nokogiri.rb +3 -4
  221. data/lib/active_support/xml_mini/nokogirisax.rb +2 -3
  222. data/lib/active_support/xml_mini/rexml.rb +8 -10
  223. data/lib/active_support/xml_mini.rb +66 -34
  224. data/lib/active_support.rb +40 -23
  225. metadata +185 -134
  226. data/CHANGELOG +0 -1534
  227. data/lib/active_support/base64.rb +0 -42
  228. data/lib/active_support/basic_object.rb +0 -21
  229. data/lib/active_support/buffered_logger.rb +0 -137
  230. data/lib/active_support/cache/compressed_mem_cache_store.rb +0 -13
  231. data/lib/active_support/cache/synchronized_memory_store.rb +0 -11
  232. data/lib/active_support/core_ext/array/random_access.rb +0 -30
  233. data/lib/active_support/core_ext/array/uniq_by.rb +0 -16
  234. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -44
  235. data/lib/active_support/core_ext/class/inheritable_attributes.rb +0 -178
  236. data/lib/active_support/core_ext/date/freeze.rb +0 -31
  237. data/lib/active_support/core_ext/date_time/zones.rb +0 -21
  238. data/lib/active_support/core_ext/exception.rb +0 -3
  239. data/lib/active_support/core_ext/file/path.rb +0 -5
  240. data/lib/active_support/core_ext/float/rounding.rb +0 -19
  241. data/lib/active_support/core_ext/float.rb +0 -1
  242. data/lib/active_support/core_ext/hash/deep_dup.rb +0 -11
  243. data/lib/active_support/core_ext/hash/diff.rb +0 -13
  244. data/lib/active_support/core_ext/kernel/requires.rb +0 -28
  245. data/lib/active_support/core_ext/logger.rb +0 -81
  246. data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +0 -31
  247. data/lib/active_support/core_ext/module/method_names.rb +0 -14
  248. data/lib/active_support/core_ext/module/synchronization.rb +0 -43
  249. data/lib/active_support/core_ext/object/to_json.rb +0 -19
  250. data/lib/active_support/core_ext/proc.rb +0 -14
  251. data/lib/active_support/core_ext/process/daemon.rb +0 -23
  252. data/lib/active_support/core_ext/process.rb +0 -1
  253. data/lib/active_support/core_ext/range/blockless_step.rb +0 -29
  254. data/lib/active_support/core_ext/range/cover.rb +0 -3
  255. data/lib/active_support/core_ext/rexml.rb +0 -46
  256. data/lib/active_support/core_ext/string/encoding.rb +0 -11
  257. data/lib/active_support/core_ext/string/interpolation.rb +0 -2
  258. data/lib/active_support/core_ext/string/xchar.rb +0 -18
  259. data/lib/active_support/core_ext/time/publicize_conversion_methods.rb +0 -10
  260. data/lib/active_support/file_watcher.rb +0 -36
  261. data/lib/active_support/json/variable.rb +0 -9
  262. data/lib/active_support/memoizable.rb +0 -105
  263. data/lib/active_support/multibyte/exceptions.rb +0 -8
  264. data/lib/active_support/multibyte/utils.rb +0 -60
  265. data/lib/active_support/ruby/shim.rb +0 -22
  266. data/lib/active_support/secure_random.rb +0 -6
  267. data/lib/active_support/testing/mochaing.rb +0 -7
  268. data/lib/active_support/testing/pending.rb +0 -52
  269. data/lib/active_support/testing/performance/jruby.rb +0 -115
  270. data/lib/active_support/testing/performance/rubinius.rb +0 -113
  271. data/lib/active_support/testing/performance/ruby/mri.rb +0 -57
  272. data/lib/active_support/testing/performance/ruby/yarv.rb +0 -57
  273. data/lib/active_support/testing/performance/ruby.rb +0 -152
  274. data/lib/active_support/testing/performance.rb +0 -317
  275. data/lib/active_support/time/autoload.rb +0 -5
  276. data/lib/active_support/whiny_nil.rb +0 -60
@@ -1,17 +1,18 @@
1
1
  begin
2
- require 'memcache'
2
+ require 'dalli'
3
3
  rescue LoadError => e
4
- $stderr.puts "You don't have memcache-client installed in your application. Please add it to your Gemfile and run bundle install"
4
+ $stderr.puts "You don't have dalli installed in your application. Please add it to your Gemfile and run bundle install"
5
5
  raise e
6
6
  end
7
7
 
8
8
  require 'digest/md5'
9
- require 'active_support/core_ext/string/encoding'
9
+ require 'active_support/core_ext/marshal'
10
+ require 'active_support/core_ext/array/extract_options'
10
11
 
11
12
  module ActiveSupport
12
13
  module Cache
13
14
  # A cache store implementation which stores data in Memcached:
14
- # http://www.danga.com/memcached/
15
+ # http://memcached.org/
15
16
  #
16
17
  # This is currently the most popular cache store for production websites.
17
18
  #
@@ -21,23 +22,47 @@ module ActiveSupport
21
22
  # server goes down, then MemCacheStore will ignore it until it comes back up.
22
23
  #
23
24
  # MemCacheStore implements the Strategy::LocalCache strategy which implements
24
- # an in memory cache inside of a block.
25
+ # an in-memory cache inside of a block.
25
26
  class MemCacheStore < Store
26
- module Response # :nodoc:
27
- STORED = "STORED\r\n"
28
- NOT_STORED = "NOT_STORED\r\n"
29
- EXISTS = "EXISTS\r\n"
30
- NOT_FOUND = "NOT_FOUND\r\n"
31
- DELETED = "DELETED\r\n"
27
+ # Provide support for raw values in the local cache strategy.
28
+ module LocalCacheWithRaw # :nodoc:
29
+ protected
30
+ def read_entry(key, options)
31
+ entry = super
32
+ if options[:raw] && local_cache && entry
33
+ entry = deserialize_entry(entry.value)
34
+ end
35
+ entry
36
+ end
37
+
38
+ def write_entry(key, entry, options) # :nodoc:
39
+ if options[:raw] && local_cache
40
+ raw_entry = Entry.new(entry.value.to_s)
41
+ raw_entry.expires_at = entry.expires_at
42
+ super(key, raw_entry, options)
43
+ else
44
+ super
45
+ end
46
+ end
32
47
  end
33
48
 
49
+ prepend Strategy::LocalCache
50
+ prepend LocalCacheWithRaw
51
+
34
52
  ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
35
53
 
36
- def self.build_mem_cache(*addresses)
54
+ # Creates a new Dalli::Client instance with specified addresses and options.
55
+ # By default address is equal localhost:11211.
56
+ #
57
+ # ActiveSupport::Cache::MemCacheStore.build_mem_cache
58
+ # # => #<Dalli::Client:0x007f98a47d2028 @servers=["localhost:11211"], @options={}, @ring=nil>
59
+ # ActiveSupport::Cache::MemCacheStore.build_mem_cache('localhost:10290')
60
+ # # => #<Dalli::Client:0x007f98a47b3a60 @servers=["localhost:10290"], @options={}, @ring=nil>
61
+ def self.build_mem_cache(*addresses) # :nodoc:
37
62
  addresses = addresses.flatten
38
63
  options = addresses.extract_options!
39
64
  addresses = ["localhost:11211"] if addresses.empty?
40
- MemCache.new(addresses, options)
65
+ Dalli::Client.new(addresses, options)
41
66
  end
42
67
 
43
68
  # Creates a new MemCacheStore object, with the given memcached server
@@ -48,26 +73,21 @@ module ActiveSupport
48
73
  #
49
74
  # If no addresses are specified, then MemCacheStore will connect to
50
75
  # localhost port 11211 (the default memcached port).
51
- #
52
- # Instead of addresses one can pass in a MemCache-like object. For example:
53
- #
54
- # require 'memcached' # gem install memcached; uses C bindings to libmemcached
55
- # ActiveSupport::Cache::MemCacheStore.new(Memcached::Rails.new("localhost:11211"))
56
76
  def initialize(*addresses)
57
77
  addresses = addresses.flatten
58
78
  options = addresses.extract_options!
59
79
  super(options)
60
80
 
61
- if addresses.first.respond_to?(:get)
81
+ unless [String, Dalli::Client, NilClass].include?(addresses.first.class)
82
+ raise ArgumentError, "First argument must be an empty array, an array of hosts or a Dalli::Client instance."
83
+ end
84
+ if addresses.first.is_a?(Dalli::Client)
62
85
  @data = addresses.first
63
86
  else
64
87
  mem_cache_options = options.dup
65
88
  UNIVERSAL_OPTIONS.each{|name| mem_cache_options.delete(name)}
66
89
  @data = self.class.build_mem_cache(*(addresses + [mem_cache_options]))
67
90
  end
68
-
69
- extend Strategy::LocalCache
70
- extend LocalCacheWithRaw
71
91
  end
72
92
 
73
93
  # Reads multiple values from the cache using a single call to the
@@ -75,7 +95,8 @@ module ActiveSupport
75
95
  def read_multi(*names)
76
96
  options = names.extract_options!
77
97
  options = merged_options(options)
78
- keys_to_names = Hash[names.map{|name| [escape_key(namespaced_key(name, options)), name]}]
98
+
99
+ keys_to_names = Hash[names.map{|name| [normalize_key(name, options), name]}]
79
100
  raw_values = @data.get_multi(keys_to_names.keys, :raw => true)
80
101
  values = {}
81
102
  raw_values.each do |key, value|
@@ -91,12 +112,11 @@ module ActiveSupport
91
112
  # to zero.
92
113
  def increment(name, amount = 1, options = nil) # :nodoc:
93
114
  options = merged_options(options)
94
- response = instrument(:increment, name, :amount => amount) do
95
- @data.incr(escape_key(namespaced_key(name, options)), amount)
115
+ instrument(:increment, name, :amount => amount) do
116
+ rescue_error_with nil do
117
+ @data.incr(normalize_key(name, options), amount)
118
+ end
96
119
  end
97
- response == Response::NOT_FOUND ? nil : response.to_i
98
- rescue MemCache::MemCacheError
99
- nil
100
120
  end
101
121
 
102
122
  # Decrement a cached value. This method uses the memcached decr atomic
@@ -105,18 +125,17 @@ module ActiveSupport
105
125
  # to zero.
106
126
  def decrement(name, amount = 1, options = nil) # :nodoc:
107
127
  options = merged_options(options)
108
- response = instrument(:decrement, name, :amount => amount) do
109
- @data.decr(escape_key(namespaced_key(name, options)), amount)
128
+ instrument(:decrement, name, :amount => amount) do
129
+ rescue_error_with nil do
130
+ @data.decr(normalize_key(name, options), amount)
131
+ end
110
132
  end
111
- response == Response::NOT_FOUND ? nil : response.to_i
112
- rescue MemCache::MemCacheError
113
- nil
114
133
  end
115
134
 
116
135
  # Clear the entire cache on all memcached servers. This method should
117
136
  # be used with care when shared cache is being used.
118
137
  def clear(options = nil)
119
- @data.flush_all
138
+ rescue_error_with(nil) { @data.flush_all }
120
139
  end
121
140
 
122
141
  # Get the statistics from the memcached servers.
@@ -127,10 +146,7 @@ module ActiveSupport
127
146
  protected
128
147
  # Read an entry from the cache.
129
148
  def read_entry(key, options) # :nodoc:
130
- deserialize_entry(@data.get(escape_key(key), true))
131
- rescue MemCache::MemCacheError => e
132
- logger.error("MemCacheError (#{e}): #{e.message}") if logger
133
- nil
149
+ rescue_error_with(nil) { deserialize_entry(@data.get(key, options)) }
134
150
  end
135
151
 
136
152
  # Write an entry to the cache.
@@ -142,20 +158,14 @@ module ActiveSupport
142
158
  # Set the memcache expire a few minutes in the future to support race condition ttls on read
143
159
  expires_in += 5.minutes
144
160
  end
145
- response = @data.send(method, escape_key(key), value, expires_in, options[:raw])
146
- response == Response::STORED
147
- rescue MemCache::MemCacheError => e
148
- logger.error("MemCacheError (#{e}): #{e.message}") if logger
149
- false
161
+ rescue_error_with false do
162
+ @data.send(method, key, value, expires_in, options)
163
+ end
150
164
  end
151
165
 
152
166
  # Delete an entry from the cache.
153
167
  def delete_entry(key, options) # :nodoc:
154
- response = @data.delete(escape_key(key))
155
- response == Response::DELETED
156
- rescue MemCache::MemCacheError => e
157
- logger.error("MemCacheError (#{e}): #{e.message}") if logger
158
- false
168
+ rescue_error_with(false) { @data.delete(key) }
159
169
  end
160
170
 
161
171
  private
@@ -163,36 +173,35 @@ module ActiveSupport
163
173
  # Memcache keys are binaries. So we need to force their encoding to binary
164
174
  # before applying the regular expression to ensure we are escaping all
165
175
  # characters properly.
166
- def escape_key(key)
167
- key = key.to_s.dup
168
- key = key.force_encoding("BINARY") if key.encoding_aware?
176
+ def normalize_key(key, options)
177
+ key = super.dup
178
+ key = key.force_encoding(Encoding::ASCII_8BIT)
169
179
  key = key.gsub(ESCAPE_KEY_CHARS){ |match| "%#{match.getbyte(0).to_s(16).upcase}" }
170
180
  key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250
171
181
  key
172
182
  end
173
183
 
184
+ def escape_key(key)
185
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
186
+ `escape_key` is deprecated and will be removed from Rails 5.1.
187
+ Please use `normalize_key` which will return a fully resolved key or nothing.
188
+ MESSAGE
189
+ key
190
+ end
191
+
174
192
  def deserialize_entry(raw_value)
175
193
  if raw_value
176
194
  entry = Marshal.load(raw_value) rescue raw_value
177
195
  entry.is_a?(Entry) ? entry : Entry.new(entry)
178
- else
179
- nil
180
196
  end
181
197
  end
182
198
 
183
- # Provide support for raw values in the local cache strategy.
184
- module LocalCacheWithRaw # :nodoc:
185
- protected
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
@@ -36,6 +36,7 @@ module ActiveSupport
36
36
  end
37
37
  end
38
38
 
39
+ # Preemptively iterates through all stored keys and removes the ones which have expired.
39
40
  def cleanup(options = nil)
40
41
  options = merged_options(options)
41
42
  instrument(:cleanup, :size => @data.size) do
@@ -74,30 +75,12 @@ module ActiveSupport
74
75
 
75
76
  # Increment an integer value in the cache.
76
77
  def increment(name, amount = 1, options = nil)
77
- synchronize do
78
- options = merged_options(options)
79
- if num = read(name, options)
80
- num = num.to_i + amount
81
- write(name, num, options)
82
- num
83
- else
84
- nil
85
- end
86
- end
78
+ modify_value(name, amount, options)
87
79
  end
88
80
 
89
81
  # Decrement an integer value in the cache.
90
82
  def decrement(name, amount = 1, options = nil)
91
- synchronize do
92
- options = merged_options(options)
93
- if num = read(name, options)
94
- num = num.to_i - amount
95
- write(name, num, options)
96
- num
97
- else
98
- nil
99
- end
100
- end
83
+ modify_value(name, -amount, options)
101
84
  end
102
85
 
103
86
  def delete_matched(matcher, options = nil)
@@ -122,6 +105,13 @@ module ActiveSupport
122
105
  end
123
106
 
124
107
  protected
108
+
109
+ PER_ENTRY_OVERHEAD = 240
110
+
111
+ def cached_size(key, entry) # :nodoc:
112
+ key.to_s.bytesize + entry.size + PER_ENTRY_OVERHEAD
113
+ end
114
+
125
115
  def read_entry(key, options) # :nodoc:
126
116
  entry = @data[key]
127
117
  synchronize do
@@ -135,10 +125,15 @@ module ActiveSupport
135
125
  end
136
126
 
137
127
  def write_entry(key, entry, options) # :nodoc:
128
+ entry.dup_value!
138
129
  synchronize do
139
130
  old_entry = @data[key]
140
- @cache_size -= old_entry.size if old_entry
141
- @cache_size += entry.size
131
+ return false if @data.key?(key) && options[:unless_exist]
132
+ if old_entry
133
+ @cache_size -= (old_entry.size - entry.size)
134
+ else
135
+ @cache_size += cached_size(key, entry)
136
+ end
142
137
  @key_access[key] = Time.now.to_f
143
138
  @data[key] = entry
144
139
  prune(@max_size * 0.75, @max_prune_time) if @cache_size > @max_size
@@ -150,10 +145,23 @@ module ActiveSupport
150
145
  synchronize do
151
146
  @key_access.delete(key)
152
147
  entry = @data.delete(key)
153
- @cache_size -= entry.size if entry
148
+ @cache_size -= cached_size(key, entry) if entry
154
149
  !!entry
155
150
  end
156
151
  end
152
+
153
+ private
154
+
155
+ def modify_value(name, amount, options)
156
+ synchronize do
157
+ options = merged_options(options)
158
+ if num = read(name, options)
159
+ num = num.to_i + amount
160
+ write(name, num, options)
161
+ num
162
+ end
163
+ end
164
+ end
157
165
  end
158
166
  end
159
167
  end
@@ -0,0 +1,41 @@
1
+ module ActiveSupport
2
+ module Cache
3
+ # A cache store implementation which doesn't actually store anything. Useful in
4
+ # development and test environments where you don't want caching turned on but
5
+ # need to go through the caching interface.
6
+ #
7
+ # This cache does implement the local cache strategy, so values will actually
8
+ # be cached inside blocks that utilize this strategy. See
9
+ # ActiveSupport::Cache::Strategy::LocalCache for more details.
10
+ class NullStore < Store
11
+ prepend Strategy::LocalCache
12
+
13
+ def clear(options = nil)
14
+ end
15
+
16
+ def cleanup(options = nil)
17
+ end
18
+
19
+ def increment(name, amount = 1, options = nil)
20
+ end
21
+
22
+ def decrement(name, amount = 1, options = nil)
23
+ end
24
+
25
+ def delete_matched(matcher, options = nil)
26
+ end
27
+
28
+ protected
29
+ def read_entry(key, options) # :nodoc:
30
+ end
31
+
32
+ def write_entry(key, entry, options) # :nodoc:
33
+ true
34
+ end
35
+
36
+ def delete_entry(key, options) # :nodoc:
37
+ false
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,13 +1,36 @@
1
1
  require 'active_support/core_ext/object/duplicable'
2
2
  require 'active_support/core_ext/string/inflections'
3
+ require 'active_support/per_thread_registry'
3
4
 
4
5
  module ActiveSupport
5
6
  module Cache
6
7
  module Strategy
7
- # Caches that implement LocalCache will be backed by an in memory cache for the
8
+ # Caches that implement LocalCache will be backed by an in-memory cache for the
8
9
  # duration of a block. Repeated calls to the cache for the same key will hit the
9
- # in memory cache for faster access.
10
+ # in-memory cache for faster access.
10
11
  module LocalCache
12
+ autoload :Middleware, 'active_support/cache/strategy/local_cache_middleware'
13
+
14
+ # Class for storing and registering the local caches.
15
+ class LocalCacheRegistry # :nodoc:
16
+ extend ActiveSupport::PerThreadRegistry
17
+
18
+ def initialize
19
+ @registry = {}
20
+ end
21
+
22
+ def cache_for(local_cache_key)
23
+ @registry[local_cache_key]
24
+ end
25
+
26
+ def set_cache_for(local_cache_key, value)
27
+ @registry[local_cache_key] = value
28
+ end
29
+
30
+ def self.set_cache_for(l, v); instance.set_cache_for l, v; end
31
+ def self.cache_for(l); instance.cache_for l; end
32
+ end
33
+
11
34
  # Simple memory backed cache. This cache is not thread safe and is intended only
12
35
  # for serving as a temporary memory cache for a single thread.
13
36
  class LocalStore < Store
@@ -16,7 +39,7 @@ module ActiveSupport
16
39
  @data = {}
17
40
  end
18
41
 
19
- # Don't allow synchronizing since it isn't thread safe,
42
+ # Don't allow synchronizing since it isn't thread safe.
20
43
  def synchronize # :nodoc:
21
44
  yield
22
45
  end
@@ -37,99 +60,54 @@ module ActiveSupport
37
60
  def delete_entry(key, options)
38
61
  !!@data.delete(key)
39
62
  end
40
- end
41
63
 
42
- # Use a local cache for the duration of block.
43
- def with_local_cache
44
- save_val = Thread.current[thread_local_key]
45
- begin
46
- Thread.current[thread_local_key] = LocalStore.new
47
- yield
48
- ensure
49
- Thread.current[thread_local_key] = save_val
64
+ def fetch_entry(key, options = nil) # :nodoc:
65
+ @data.fetch(key) { @data[key] = yield }
50
66
  end
51
67
  end
52
68
 
53
- #--
54
- # This class wraps up local storage for middlewares. Only the middleware method should
55
- # construct them.
56
- class Middleware # :nodoc:
57
- attr_reader :name, :thread_local_key
58
-
59
- def initialize(name, thread_local_key)
60
- @name = name
61
- @thread_local_key = thread_local_key
62
- @app = nil
63
- end
64
-
65
- def new(app)
66
- @app = app
67
- self
68
- end
69
-
70
- def call(env)
71
- Thread.current[thread_local_key] = LocalStore.new
72
- @app.call(env)
73
- ensure
74
- Thread.current[thread_local_key] = nil
75
- end
69
+ # Use a local cache for the duration of block.
70
+ def with_local_cache
71
+ use_temporary_local_cache(LocalStore.new) { yield }
76
72
  end
77
-
78
73
  # Middleware class can be inserted as a Rack handler to be local cache for the
79
74
  # duration of request.
80
75
  def middleware
81
76
  @middleware ||= Middleware.new(
82
77
  "ActiveSupport::Cache::Strategy::LocalCache",
83
- thread_local_key)
78
+ local_cache_key)
84
79
  end
85
80
 
86
81
  def clear(options = nil) # :nodoc:
87
- local_cache.clear(options) if local_cache
82
+ return super unless cache = local_cache
83
+ cache.clear(options)
88
84
  super
89
85
  end
90
86
 
91
87
  def cleanup(options = nil) # :nodoc:
92
- local_cache.clear(options) if local_cache
88
+ return super unless cache = local_cache
89
+ cache.clear(options)
93
90
  super
94
91
  end
95
92
 
96
93
  def increment(name, amount = 1, options = nil) # :nodoc:
94
+ return super unless local_cache
97
95
  value = bypass_local_cache{super}
98
- if local_cache
99
- local_cache.mute do
100
- if value
101
- local_cache.write(name, value, options)
102
- else
103
- local_cache.delete(name, options)
104
- end
105
- end
106
- end
96
+ write_cache_value(name, value, options)
107
97
  value
108
98
  end
109
99
 
110
100
  def decrement(name, amount = 1, options = nil) # :nodoc:
101
+ return super unless local_cache
111
102
  value = bypass_local_cache{super}
112
- if local_cache
113
- local_cache.mute do
114
- if value
115
- local_cache.write(name, value, options)
116
- else
117
- local_cache.delete(name, options)
118
- end
119
- end
120
- end
103
+ write_cache_value(name, value, options)
121
104
  value
122
105
  end
123
106
 
124
107
  protected
125
108
  def read_entry(key, options) # :nodoc:
126
- if local_cache
127
- entry = local_cache.read_entry(key, options)
128
- unless entry
129
- entry = super
130
- local_cache.write_entry(key, entry, options)
131
- end
132
- entry
109
+ if cache = local_cache
110
+ cache.fetch_entry(key) { super }
133
111
  else
134
112
  super
135
113
  end
@@ -145,22 +123,47 @@ module ActiveSupport
145
123
  super
146
124
  end
147
125
 
126
+ def set_cache_value(value, name, amount, options) # :nodoc:
127
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
128
+ `set_cache_value` is deprecated and will be removed from Rails 5.1.
129
+ Please use `write_cache_value` instead.
130
+ MESSAGE
131
+ write_cache_value name, value, options
132
+ end
133
+
134
+ def write_cache_value(name, value, options) # :nodoc:
135
+ name = normalize_key(name, options)
136
+ cache = local_cache
137
+ cache.mute do
138
+ if value
139
+ cache.write(name, value, options)
140
+ else
141
+ cache.delete(name, options)
142
+ end
143
+ end
144
+ end
145
+
148
146
  private
149
- def thread_local_key
150
- @thread_local_key ||= "#{self.class.name.underscore}_local_cache_#{object_id}".gsub(/[\/-]/, '_').to_sym
147
+
148
+ def local_cache_key
149
+ @local_cache_key ||= "#{self.class.name.underscore}_local_cache_#{object_id}".gsub(/[\/-]/, '_').to_sym
151
150
  end
152
151
 
153
152
  def local_cache
154
- Thread.current[thread_local_key]
153
+ LocalCacheRegistry.cache_for(local_cache_key)
155
154
  end
156
155
 
157
156
  def bypass_local_cache
158
- save_cache = Thread.current[thread_local_key]
157
+ use_temporary_local_cache(nil) { yield }
158
+ end
159
+
160
+ def use_temporary_local_cache(temporary_cache)
161
+ save_cache = LocalCacheRegistry.cache_for(local_cache_key)
159
162
  begin
160
- Thread.current[thread_local_key] = nil
163
+ LocalCacheRegistry.set_cache_for(local_cache_key, temporary_cache)
161
164
  yield
162
165
  ensure
163
- Thread.current[thread_local_key] = save_cache
166
+ LocalCacheRegistry.set_cache_for(local_cache_key, save_cache)
164
167
  end
165
168
  end
166
169
  end
@@ -0,0 +1,44 @@
1
+ require 'rack/body_proxy'
2
+ require 'rack/utils'
3
+
4
+ module ActiveSupport
5
+ module Cache
6
+ module Strategy
7
+ module LocalCache
8
+
9
+ #--
10
+ # This class wraps up local storage for middlewares. Only the middleware method should
11
+ # construct them.
12
+ class Middleware # :nodoc:
13
+ attr_reader :name, :local_cache_key
14
+
15
+ def initialize(name, local_cache_key)
16
+ @name = name
17
+ @local_cache_key = local_cache_key
18
+ @app = nil
19
+ end
20
+
21
+ def new(app)
22
+ @app = app
23
+ self
24
+ end
25
+
26
+ def call(env)
27
+ LocalCacheRegistry.set_cache_for(local_cache_key, LocalStore.new)
28
+ response = @app.call(env)
29
+ response[2] = ::Rack::BodyProxy.new(response[2]) do
30
+ LocalCacheRegistry.set_cache_for(local_cache_key, nil)
31
+ end
32
+ response
33
+ rescue Rack::Utils::InvalidParameterError
34
+ LocalCacheRegistry.set_cache_for(local_cache_key, nil)
35
+ [400, {}, []]
36
+ rescue Exception
37
+ LocalCacheRegistry.set_cache_for(local_cache_key, nil)
38
+ raise
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end