activesupport 3.2.22.5 → 4.0.0.beta1

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 (214) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +325 -136
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -2
  5. data/lib/active_support.rb +8 -21
  6. data/lib/active_support/backtrace_cleaner.rb +33 -25
  7. data/lib/active_support/basic_object.rb +7 -17
  8. data/lib/active_support/benchmarkable.rb +19 -15
  9. data/lib/active_support/buffered_logger.rb +9 -113
  10. data/lib/active_support/cache.rb +203 -171
  11. data/lib/active_support/cache/file_store.rb +12 -12
  12. data/lib/active_support/cache/mem_cache_store.rb +24 -30
  13. data/lib/active_support/cache/memory_store.rb +2 -0
  14. data/lib/active_support/callbacks.rb +195 -247
  15. data/lib/active_support/concern.rb +16 -23
  16. data/lib/active_support/concurrency/latch.rb +27 -0
  17. data/lib/active_support/configurable.rb +69 -12
  18. data/lib/active_support/core_ext.rb +1 -0
  19. data/lib/active_support/core_ext/array.rb +0 -1
  20. data/lib/active_support/core_ext/array/access.rb +17 -9
  21. data/lib/active_support/core_ext/array/conversions.rb +113 -55
  22. data/lib/active_support/core_ext/array/extract_options.rb +2 -2
  23. data/lib/active_support/core_ext/array/grouping.rb +21 -22
  24. data/lib/active_support/core_ext/array/uniq_by.rb +12 -9
  25. data/lib/active_support/core_ext/array/wrap.rb +11 -14
  26. data/lib/active_support/core_ext/big_decimal/conversions.rb +7 -24
  27. data/lib/active_support/core_ext/class/attribute.rb +12 -8
  28. data/lib/active_support/core_ext/class/attribute_accessors.rb +14 -12
  29. data/lib/active_support/core_ext/class/delegating_attributes.rb +15 -19
  30. data/lib/active_support/core_ext/class/subclasses.rb +11 -5
  31. data/lib/active_support/core_ext/date.rb +6 -0
  32. data/lib/active_support/core_ext/date/calculations.rb +34 -188
  33. data/lib/active_support/core_ext/date/conversions.rb +16 -38
  34. data/lib/active_support/core_ext/date/infinite_comparable.rb +5 -0
  35. data/lib/active_support/core_ext/date/zones.rb +25 -2
  36. data/lib/active_support/core_ext/date_and_time/calculations.rb +232 -0
  37. data/lib/active_support/core_ext/date_time.rb +5 -0
  38. data/lib/active_support/core_ext/date_time/acts_like.rb +0 -1
  39. data/lib/active_support/core_ext/date_time/calculations.rb +73 -65
  40. data/lib/active_support/core_ext/date_time/conversions.rb +21 -33
  41. data/lib/active_support/core_ext/date_time/infinite_comparable.rb +5 -0
  42. data/lib/active_support/core_ext/date_time/zones.rb +11 -8
  43. data/lib/active_support/core_ext/enumerable.rb +26 -73
  44. data/lib/active_support/core_ext/file.rb +0 -1
  45. data/lib/active_support/core_ext/file/atomic.rb +27 -11
  46. data/lib/active_support/core_ext/hash.rb +0 -1
  47. data/lib/active_support/core_ext/hash/conversions.rb +145 -79
  48. data/lib/active_support/core_ext/hash/deep_merge.rb +14 -8
  49. data/lib/active_support/core_ext/hash/diff.rb +5 -4
  50. data/lib/active_support/core_ext/hash/except.rb +1 -9
  51. data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -5
  52. data/lib/active_support/core_ext/hash/keys.rb +108 -24
  53. data/lib/active_support/core_ext/hash/reverse_merge.rb +2 -3
  54. data/lib/active_support/core_ext/hash/slice.rb +12 -12
  55. data/lib/active_support/core_ext/infinite_comparable.rb +35 -0
  56. data/lib/active_support/core_ext/integer/inflections.rb +13 -1
  57. data/lib/active_support/core_ext/integer/time.rb +17 -12
  58. data/lib/active_support/core_ext/kernel/debugger.rb +2 -2
  59. data/lib/active_support/core_ext/kernel/reporting.rb +36 -22
  60. data/lib/active_support/core_ext/kernel/singleton_class.rb +0 -7
  61. data/lib/active_support/core_ext/load_error.rb +7 -5
  62. data/lib/active_support/core_ext/logger.rb +7 -23
  63. data/lib/active_support/core_ext/marshal.rb +19 -0
  64. data/lib/active_support/core_ext/module.rb +1 -3
  65. data/lib/active_support/core_ext/module/aliasing.rb +8 -9
  66. data/lib/active_support/core_ext/module/anonymous.rb +2 -7
  67. data/lib/active_support/core_ext/module/attr_internal.rb +0 -1
  68. data/lib/active_support/core_ext/module/attribute_accessors.rb +12 -10
  69. data/lib/active_support/core_ext/module/delegation.rb +57 -40
  70. data/lib/active_support/core_ext/module/deprecation.rb +19 -3
  71. data/lib/active_support/core_ext/module/introspection.rb +17 -27
  72. data/lib/active_support/core_ext/module/qualified_const.rb +8 -20
  73. data/lib/active_support/core_ext/module/remove_method.rb +1 -5
  74. data/lib/active_support/core_ext/numeric.rb +2 -0
  75. data/lib/active_support/core_ext/numeric/conversions.rb +135 -0
  76. data/lib/active_support/core_ext/numeric/infinite_comparable.rb +9 -0
  77. data/lib/active_support/core_ext/numeric/time.rb +6 -6
  78. data/lib/active_support/core_ext/object.rb +1 -0
  79. data/lib/active_support/core_ext/object/acts_like.rb +4 -4
  80. data/lib/active_support/core_ext/object/blank.rb +7 -23
  81. data/lib/active_support/core_ext/object/deep_dup.rb +46 -0
  82. data/lib/active_support/core_ext/object/duplicable.rb +1 -30
  83. data/lib/active_support/core_ext/object/inclusion.rb +6 -6
  84. data/lib/active_support/core_ext/object/instance_variables.rb +7 -12
  85. data/lib/active_support/core_ext/object/to_json.rb +8 -0
  86. data/lib/active_support/core_ext/object/to_param.rb +5 -2
  87. data/lib/active_support/core_ext/object/try.rb +46 -25
  88. data/lib/active_support/core_ext/object/with_options.rb +7 -8
  89. data/lib/active_support/core_ext/proc.rb +3 -0
  90. data/lib/active_support/core_ext/range.rb +0 -2
  91. data/lib/active_support/core_ext/range/conversions.rb +0 -2
  92. data/lib/active_support/core_ext/range/include_range.rb +1 -1
  93. data/lib/active_support/core_ext/range/overlaps.rb +1 -1
  94. data/lib/active_support/core_ext/string.rb +2 -2
  95. data/lib/active_support/core_ext/string/access.rb +95 -90
  96. data/lib/active_support/core_ext/string/conversions.rb +29 -38
  97. data/lib/active_support/core_ext/string/encoding.rb +6 -9
  98. data/lib/active_support/core_ext/string/filters.rb +24 -18
  99. data/lib/active_support/core_ext/string/indent.rb +43 -0
  100. data/lib/active_support/core_ext/string/inflections.rb +70 -60
  101. data/lib/active_support/core_ext/string/inquiry.rb +2 -2
  102. data/lib/active_support/core_ext/string/multibyte.rb +41 -64
  103. data/lib/active_support/core_ext/string/output_safety.rb +59 -51
  104. data/lib/active_support/core_ext/string/zones.rb +13 -0
  105. data/lib/active_support/core_ext/struct.rb +6 -0
  106. data/lib/active_support/core_ext/thread.rb +74 -0
  107. data/lib/active_support/core_ext/time.rb +6 -0
  108. data/lib/active_support/core_ext/time/calculations.rb +105 -193
  109. data/lib/active_support/core_ext/time/conversions.rb +27 -51
  110. data/lib/active_support/core_ext/time/infinite_comparable.rb +5 -0
  111. data/lib/active_support/core_ext/time/marshal.rb +0 -27
  112. data/lib/active_support/core_ext/time/zones.rb +27 -17
  113. data/lib/active_support/core_ext/uri.rb +13 -17
  114. data/lib/active_support/dependencies.rb +160 -141
  115. data/lib/active_support/dependencies/autoload.rb +47 -20
  116. data/lib/active_support/deprecation.rb +39 -14
  117. data/lib/active_support/deprecation/behaviors.rb +44 -30
  118. data/lib/active_support/deprecation/instance_delegator.rb +24 -0
  119. data/lib/active_support/deprecation/method_wrappers.rb +33 -18
  120. data/lib/active_support/deprecation/proxy_wrappers.rb +58 -13
  121. data/lib/active_support/deprecation/reporting.rb +40 -11
  122. data/lib/active_support/descendants_tracker.rb +34 -19
  123. data/lib/active_support/duration.rb +6 -8
  124. data/lib/active_support/file_update_checker.rb +63 -47
  125. data/lib/active_support/gzip.rb +11 -5
  126. data/lib/active_support/hash_with_indifferent_access.rb +112 -37
  127. data/lib/active_support/i18n.rb +4 -0
  128. data/lib/active_support/i18n_railtie.rb +5 -22
  129. data/lib/active_support/inflections.rb +14 -12
  130. data/lib/active_support/inflector/inflections.rb +108 -71
  131. data/lib/active_support/inflector/methods.rb +181 -160
  132. data/lib/active_support/inflector/transliterate.rb +16 -17
  133. data/lib/active_support/json/decoding.rb +18 -17
  134. data/lib/active_support/json/encoding.rb +93 -39
  135. data/lib/active_support/json/variable.rb +10 -1
  136. data/lib/active_support/key_generator.rb +75 -0
  137. data/lib/active_support/lazy_load_hooks.rb +21 -19
  138. data/lib/active_support/locale/en.yml +100 -3
  139. data/lib/active_support/log_subscriber.rb +56 -36
  140. data/lib/active_support/log_subscriber/test_helper.rb +18 -15
  141. data/lib/active_support/logger.rb +57 -0
  142. data/lib/active_support/logger_silence.rb +24 -0
  143. data/lib/active_support/message_encryptor.rb +32 -29
  144. data/lib/active_support/message_verifier.rb +8 -14
  145. data/lib/active_support/multibyte.rb +5 -28
  146. data/lib/active_support/multibyte/chars.rb +80 -333
  147. data/lib/active_support/multibyte/unicode.rb +74 -64
  148. data/lib/active_support/notifications.rb +57 -25
  149. data/lib/active_support/notifications/fanout.rb +105 -18
  150. data/lib/active_support/notifications/instrumenter.rb +32 -13
  151. data/lib/active_support/number_helper.rb +636 -0
  152. data/lib/active_support/ordered_hash.rb +8 -190
  153. data/lib/active_support/ordered_options.rb +21 -23
  154. data/lib/active_support/proxy_object.rb +13 -0
  155. data/lib/active_support/rails.rb +27 -0
  156. data/lib/active_support/railtie.rb +12 -32
  157. data/lib/active_support/rescuable.rb +9 -4
  158. data/lib/active_support/string_inquirer.rb +13 -8
  159. data/lib/active_support/tagged_logging.rb +51 -73
  160. data/lib/active_support/test_case.rb +46 -17
  161. data/lib/active_support/testing/assertions.rb +56 -26
  162. data/lib/active_support/testing/autorun.rb +5 -0
  163. data/lib/active_support/testing/constant_lookup.rb +52 -0
  164. data/lib/active_support/testing/declarative.rb +1 -1
  165. data/lib/active_support/testing/deprecation.rb +0 -19
  166. data/lib/active_support/testing/isolation.rb +25 -58
  167. data/lib/active_support/testing/pending.rb +5 -43
  168. data/lib/active_support/testing/setup_and_teardown.rb +6 -92
  169. data/lib/active_support/testing/tagged_logging.rb +25 -0
  170. data/lib/active_support/time.rb +6 -21
  171. data/lib/active_support/time_with_zone.rb +78 -43
  172. data/lib/active_support/values/time_zone.rb +77 -58
  173. data/lib/active_support/values/unicode_tables.dat +0 -0
  174. data/lib/active_support/version.rb +4 -4
  175. data/lib/active_support/xml_mini.rb +35 -17
  176. data/lib/active_support/xml_mini/jdom.rb +9 -17
  177. data/lib/active_support/xml_mini/libxml.rb +1 -2
  178. data/lib/active_support/xml_mini/libxmlsax.rb +1 -2
  179. data/lib/active_support/xml_mini/nokogiri.rb +1 -2
  180. data/lib/active_support/xml_mini/nokogirisax.rb +1 -2
  181. data/lib/active_support/xml_mini/rexml.rb +6 -8
  182. metadata +107 -77
  183. data/lib/active_support/base64.rb +0 -54
  184. data/lib/active_support/core_ext/array/random_access.rb +0 -30
  185. data/lib/active_support/core_ext/date/freeze.rb +0 -33
  186. data/lib/active_support/core_ext/exception.rb +0 -3
  187. data/lib/active_support/core_ext/file/path.rb +0 -5
  188. data/lib/active_support/core_ext/float.rb +0 -1
  189. data/lib/active_support/core_ext/float/rounding.rb +0 -19
  190. data/lib/active_support/core_ext/hash/deep_dup.rb +0 -18
  191. data/lib/active_support/core_ext/io.rb +0 -15
  192. data/lib/active_support/core_ext/module/method_names.rb +0 -14
  193. data/lib/active_support/core_ext/module/synchronization.rb +0 -45
  194. data/lib/active_support/core_ext/process.rb +0 -1
  195. data/lib/active_support/core_ext/process/daemon.rb +0 -23
  196. data/lib/active_support/core_ext/range/blockless_step.rb +0 -29
  197. data/lib/active_support/core_ext/range/cover.rb +0 -3
  198. data/lib/active_support/core_ext/rexml.rb +0 -46
  199. data/lib/active_support/core_ext/string/interpolation.rb +0 -2
  200. data/lib/active_support/core_ext/time/publicize_conversion_methods.rb +0 -10
  201. data/lib/active_support/memoizable.rb +0 -116
  202. data/lib/active_support/multibyte/exceptions.rb +0 -8
  203. data/lib/active_support/multibyte/utils.rb +0 -60
  204. data/lib/active_support/ruby/shim.rb +0 -22
  205. data/lib/active_support/security_utils.rb +0 -27
  206. data/lib/active_support/testing/mochaing.rb +0 -7
  207. data/lib/active_support/testing/performance.rb +0 -317
  208. data/lib/active_support/testing/performance/jruby.rb +0 -115
  209. data/lib/active_support/testing/performance/rubinius.rb +0 -113
  210. data/lib/active_support/testing/performance/ruby.rb +0 -152
  211. data/lib/active_support/testing/performance/ruby/mri.rb +0 -57
  212. data/lib/active_support/testing/performance/ruby/yarv.rb +0 -57
  213. data/lib/active_support/time/autoload.rb +0 -5
  214. data/lib/active_support/whiny_nil.rb +0 -24
@@ -1,4 +1,4 @@
1
- Copyright (c) 2005-2011 David Heinemeier Hansson
1
+ Copyright (c) 2005-2013 David Heinemeier Hansson
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -14,12 +14,14 @@ The latest version of Active Support can be installed with RubyGems:
14
14
 
15
15
  Source code can be downloaded as part of the Rails project on GitHub
16
16
 
17
- * https://github.com/rails/rails/tree/3-2-stable/activesupport
17
+ * https://github.com/rails/rails/tree/master/activesupport
18
18
 
19
19
 
20
20
  == License
21
21
 
22
- Active Support is released under the MIT license.
22
+ Active Support is released under the MIT license:
23
+
24
+ * http://www.opensource.org/licenses/MIT
23
25
 
24
26
 
25
27
  == Support
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2011 David Heinemeier Hansson
2
+ # Copyright (c) 2005-2013 David Heinemeier Hansson
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -22,59 +22,46 @@
22
22
  #++
23
23
 
24
24
  require 'securerandom'
25
-
26
- module ActiveSupport
27
- class << self
28
- attr_accessor :load_all_hooks
29
- def on_load_all(&hook) load_all_hooks << hook end
30
- def load_all!; load_all_hooks.each { |hook| hook.call } end
31
- end
32
- self.load_all_hooks = []
33
-
34
- on_load_all do
35
- [Dependencies, Deprecation, Gzip, MessageVerifier, Multibyte]
36
- end
37
- end
38
-
39
25
  require "active_support/dependencies/autoload"
40
26
  require "active_support/version"
27
+ require "active_support/logger"
28
+ require "active_support/lazy_load_hooks"
41
29
 
42
30
  module ActiveSupport
43
31
  extend ActiveSupport::Autoload
44
32
 
33
+ autoload :Concern
34
+ autoload :Dependencies
45
35
  autoload :DescendantsTracker
46
36
  autoload :FileUpdateChecker
47
37
  autoload :LogSubscriber
48
38
  autoload :Notifications
49
39
 
50
- # TODO: Narrow this list down
51
40
  eager_autoload do
52
41
  autoload :BacktraceCleaner
53
- autoload :Base64
54
42
  autoload :BasicObject
43
+ autoload :ProxyObject
55
44
  autoload :Benchmarkable
56
- autoload :BufferedLogger
57
45
  autoload :Cache
58
46
  autoload :Callbacks
59
- autoload :Concern
60
47
  autoload :Configurable
61
48
  autoload :Deprecation
62
49
  autoload :Gzip
63
50
  autoload :Inflector
64
51
  autoload :JSON
65
- autoload :Memoizable
52
+ autoload :KeyGenerator
66
53
  autoload :MessageEncryptor
67
54
  autoload :MessageVerifier
68
55
  autoload :Multibyte
69
56
  autoload :OptionMerger
70
57
  autoload :OrderedHash
71
58
  autoload :OrderedOptions
72
- autoload :Rescuable
73
59
  autoload :StringInquirer
74
60
  autoload :TaggedLogging
75
61
  autoload :XmlMini
76
62
  end
77
63
 
64
+ autoload :Rescuable
78
65
  autoload :SafeBuffer, "active_support/core_ext/string/output_safety"
79
66
  autoload :TestCase
80
67
  end
@@ -1,24 +1,29 @@
1
1
  module ActiveSupport
2
- # Backtraces often include many lines that are not relevant for the context under review. This makes it hard to find the
3
- # signal amongst the backtrace noise, and adds debugging time. With a BacktraceCleaner, filters and silencers are used to
4
- # remove the noisy lines, so that only the most relevant lines remain.
2
+ # Backtraces often include many lines that are not relevant for the context
3
+ # under review. This makes it hard to find the signal amongst the backtrace
4
+ # noise, and adds debugging time. With a BacktraceCleaner, filters and
5
+ # silencers are used to remove the noisy lines, so that only the most relevant
6
+ # lines remain.
5
7
  #
6
- # Filters are used to modify lines of data, while silencers are used to remove lines entirely. The typical filter use case
7
- # is to remove lengthy path information from the start of each line, and view file paths relevant to the app directory
8
- # instead of the file system root. The typical silencer use case is to exclude the output of a noisy library from the
9
- # backtrace, so that you can focus on the rest.
10
- #
11
- # ==== Example:
8
+ # Filters are used to modify lines of data, while silencers are used to remove
9
+ # lines entirely. The typical filter use case is to remove lengthy path
10
+ # information from the start of each line, and view file paths relevant to the
11
+ # app directory instead of the file system root. The typical silencer use case
12
+ # is to exclude the output of a noisy library from the backtrace, so that you
13
+ # can focus on the rest.
12
14
  #
13
15
  # bc = BacktraceCleaner.new
14
16
  # bc.add_filter { |line| line.gsub(Rails.root, '') }
15
17
  # bc.add_silencer { |line| line =~ /mongrel|rubygems/ }
16
18
  # bc.clean(exception.backtrace) # will strip the Rails.root prefix and skip any lines from mongrel or rubygems
17
19
  #
18
- # To reconfigure an existing BacktraceCleaner (like the default one in Rails) and show as much data as possible, you can
19
- # always call <tt>BacktraceCleaner#remove_silencers!</tt>, which will restore the backtrace to a pristine state. If you
20
- # need to reconfigure an existing BacktraceCleaner so that it does not filter or modify the paths of any lines of the
21
- # backtrace, you can call BacktraceCleaner#remove_filters! These two methods will give you a completely untouched backtrace.
20
+ # To reconfigure an existing BacktraceCleaner (like the default one in Rails)
21
+ # and show as much data as possible, you can always call
22
+ # <tt>BacktraceCleaner#remove_silencers!</tt>, which will restore the
23
+ # backtrace to a pristine state. If you need to reconfigure an existing
24
+ # BacktraceCleaner so that it does not filter or modify the paths of any lines
25
+ # of the backtrace, you can call BacktraceCleaner#remove_filters! These two
26
+ # methods will give you a completely untouched backtrace.
22
27
  #
23
28
  # Inspired by the Quiet Backtrace gem by Thoughtbot.
24
29
  class BacktraceCleaner
@@ -26,9 +31,10 @@ module ActiveSupport
26
31
  @filters, @silencers = [], []
27
32
  end
28
33
 
29
- # Returns the backtrace after all filters and silencers have been run against it. Filters run first, then silencers.
34
+ # Returns the backtrace after all filters and silencers have been run
35
+ # against it. Filters run first, then silencers.
30
36
  def clean(backtrace, kind = :silent)
31
- filtered = filter(backtrace)
37
+ filtered = filter_backtrace(backtrace)
32
38
 
33
39
  case kind
34
40
  when :silent
@@ -39,10 +45,10 @@ module ActiveSupport
39
45
  filtered
40
46
  end
41
47
  end
48
+ alias :filter :clean
42
49
 
43
- # Adds a filter from the block provided. Each line in the backtrace will be mapped against this filter.
44
- #
45
- # Example:
50
+ # Adds a filter from the block provided. Each line in the backtrace will be
51
+ # mapped against this filter.
46
52
  #
47
53
  # # Will turn "/my/rails/root/app/models/person.rb" into "/app/models/person.rb"
48
54
  # backtrace_cleaner.add_filter { |line| line.gsub(Rails.root, '') }
@@ -50,10 +56,8 @@ module ActiveSupport
50
56
  @filters << block
51
57
  end
52
58
 
53
- # Adds a silencer from the block provided. If the silencer returns true for a given line, it will be excluded from
54
- # the clean backtrace.
55
- #
56
- # Example:
59
+ # Adds a silencer from the block provided. If the silencer returns +true+
60
+ # for a given line, it will be excluded from the clean backtrace.
57
61
  #
58
62
  # # Will reject all lines that include the word "mongrel", like "/gems/mongrel/server.rb" or "/app/my_mongrel_server/rb"
59
63
  # backtrace_cleaner.add_silencer { |line| line =~ /mongrel/ }
@@ -61,18 +65,22 @@ module ActiveSupport
61
65
  @silencers << block
62
66
  end
63
67
 
64
- # Will remove all silencers, but leave in the filters. This is useful if your context of debugging suddenly expands as
65
- # you suspect a bug in one of the libraries you use.
68
+ # Will remove all silencers, but leave in the filters. This is useful if
69
+ # your context of debugging suddenly expands as you suspect a bug in one of
70
+ # the libraries you use.
66
71
  def remove_silencers!
67
72
  @silencers = []
68
73
  end
69
74
 
75
+ # Removes all filters, but leaves in silencers. Useful if you suddenly
76
+ # need to see entire filepaths in the backtrace that you had already
77
+ # filtered out.
70
78
  def remove_filters!
71
79
  @filters = []
72
80
  end
73
81
 
74
82
  private
75
- def filter(backtrace)
83
+ def filter_backtrace(backtrace)
76
84
  @filters.each do |f|
77
85
  backtrace = backtrace.map { |line| f.call(line) }
78
86
  end
@@ -1,21 +1,11 @@
1
- module ActiveSupport
2
- if defined? ::BasicObject
3
- # A class with no predefined methods that behaves similarly to Builder's
4
- # BlankSlate. Used for proxy classes.
5
- class BasicObject < ::BasicObject
6
- undef_method :==
7
- undef_method :equal?
1
+ require 'active_support/deprecation'
2
+ require 'active_support/proxy_object'
8
3
 
9
- # Let ActiveSupport::BasicObject at least raise exceptions.
10
- def raise(*args)
11
- ::Object.send(:raise, *args)
12
- end
13
- end
14
- else
15
- class BasicObject #:nodoc:
16
- instance_methods.each do |m|
17
- undef_method(m) if m.to_s !~ /(?:^__|^nil\?$|^send$|^object_id$)/
18
- end
4
+ module ActiveSupport
5
+ class BasicObject < ProxyObject # :nodoc:
6
+ def self.inherited(*)
7
+ ::ActiveSupport::Deprecation.warn 'ActiveSupport::BasicObject is deprecated! Use ActiveSupport::ProxyObject instead.'
8
+ super
19
9
  end
20
10
  end
21
11
  end
@@ -3,30 +3,33 @@ require 'active_support/core_ext/hash/keys'
3
3
 
4
4
  module ActiveSupport
5
5
  module Benchmarkable
6
- # Allows you to measure the execution time of a block in a template and records the result to
7
- # the log. Wrap this block around expensive operations or possible bottlenecks to get a time
8
- # reading for the operation. For example, let's say you thought your file processing method
9
- # was taking too long; you could wrap it in a benchmark block.
6
+ # Allows you to measure the execution time of a block in a template and
7
+ # records the result to the log. Wrap this block around expensive operations
8
+ # or possible bottlenecks to get a time reading for the operation. For
9
+ # example, let's say you thought your file processing method was taking too
10
+ # long; you could wrap it in a benchmark block.
10
11
  #
11
- # <% benchmark "Process data files" do %>
12
+ # <% benchmark 'Process data files' do %>
12
13
  # <%= expensive_files_operation %>
13
14
  # <% end %>
14
15
  #
15
- # That would add something like "Process data files (345.2ms)" to the log, which you can then
16
- # use to compare timings when optimizing your code.
16
+ # That would add something like "Process data files (345.2ms)" to the log,
17
+ # which you can then use to compare timings when optimizing your code.
17
18
  #
18
- # You may give an optional logger level (:debug, :info, :warn, :error) as the :level option.
19
- # The default logger level value is :info.
19
+ # You may give an optional logger level (<tt>:debug</tt>, <tt>:info</tt>,
20
+ # <tt>:warn</tt>, <tt>:error</tt>) as the <tt>:level</tt> option. The
21
+ # default logger level value is <tt>:info</tt>.
20
22
  #
21
- # <% benchmark "Low-level files", :level => :debug do %>
23
+ # <% benchmark 'Low-level files', level: :debug do %>
22
24
  # <%= lowlevel_files_operation %>
23
25
  # <% end %>
24
26
  #
25
- # Finally, you can pass true as the third argument to silence all log activity (other than the
26
- # timing information) from inside the block. This is great for boiling down a noisy block to
27
- # just a single statement that produces one log line:
27
+ # Finally, you can pass true as the third argument to silence all log
28
+ # activity (other than the timing information) from inside the block. This
29
+ # is great for boiling down a noisy block to just a single statement that
30
+ # produces one log line:
28
31
  #
29
- # <% benchmark "Process data files", :level => :info, :silence => true do %>
32
+ # <% benchmark 'Process data files', level: :info, silence: true do %>
30
33
  # <%= expensive_and_chatty_files_operation %>
31
34
  # <% end %>
32
35
  def benchmark(message = "Benchmarking", options = {})
@@ -44,8 +47,9 @@ module ActiveSupport
44
47
  end
45
48
 
46
49
  # Silence the logger during the execution of the block.
47
- #
48
50
  def silence
51
+ message = "ActiveSupport::Benchmarkable#silence is deprecated. It will be removed from Rails 4.1."
52
+ ActiveSupport::Deprecation.warn message
49
53
  old_logger_level, logger.level = logger.level, ::Logger::ERROR if logger
50
54
  yield
51
55
  ensure
@@ -1,125 +1,21 @@
1
- require 'thread'
2
- require 'logger'
3
- require 'active_support/core_ext/logger'
4
- require 'active_support/core_ext/class/attribute_accessors'
5
1
  require 'active_support/deprecation'
6
- require 'fileutils'
2
+ require 'active_support/logger'
7
3
 
8
4
  module ActiveSupport
9
- # Inspired by the buffered logger idea by Ezra
10
- class BufferedLogger
11
- module Severity
12
- DEBUG = 0
13
- INFO = 1
14
- WARN = 2
15
- ERROR = 3
16
- FATAL = 4
17
- UNKNOWN = 5
18
- end
19
- include Severity
20
-
21
- MAX_BUFFER_SIZE = 1000
22
-
23
- ##
24
- # :singleton-method:
25
- # Set to false to disable the silencer
26
- cattr_accessor :silencer
27
- self.silencer = true
28
-
29
- # Silences the logger for the duration of the block.
30
- def silence(temporary_level = ERROR)
31
- if silencer
32
- begin
33
- logger = self.class.new @log_dest.dup, temporary_level
34
- yield logger
35
- ensure
36
- logger.close
37
- end
38
- else
39
- yield self
40
- end
41
- end
42
- deprecate :silence
43
-
44
- attr_reader :auto_flushing
45
- deprecate :auto_flushing
46
-
47
- def initialize(log, level = DEBUG)
48
- @log_dest = log
49
-
50
- unless log.respond_to?(:write)
51
- unless File.exist?(File.dirname(log))
52
- ActiveSupport::Deprecation.warn(<<-eowarn)
53
- Automatic directory creation for '#{log}' is deprecated. Please make sure the directory for your log file exists before creating the logger.
54
- eowarn
55
- FileUtils.mkdir_p(File.dirname(log))
56
- end
57
- end
58
-
59
- @log = open_logfile log
60
- self.level = level
61
- end
62
-
63
- def open_log(log, mode)
64
- open(log, mode).tap do |open_log|
65
- open_log.set_encoding(Encoding::BINARY) if open_log.respond_to?(:set_encoding)
66
- open_log.sync = true
67
- end
68
- end
69
- deprecate :open_log
70
-
71
- def level
72
- @log.level
73
- end
74
-
75
- def level=(l)
76
- @log.level = l
77
- end
5
+ class BufferedLogger < Logger
78
6
 
79
- def add(severity, message = nil, progname = nil, &block)
80
- @log.add(severity, message, progname, &block)
81
- end
82
-
83
- # Dynamically add methods such as:
84
- # def info
85
- # def warn
86
- # def debug
87
- Severity.constants.each do |severity|
88
- class_eval <<-EOT, __FILE__, __LINE__ + 1
89
- def #{severity.downcase}(message = nil, progname = nil, &block) # def debug(message = nil, progname = nil, &block)
90
- add(#{severity}, message, progname, &block) # add(DEBUG, message, progname, &block)
91
- end # end
92
-
93
- def #{severity.downcase}? # def debug?
94
- #{severity} >= level # DEBUG >= level
95
- end # end
96
- EOT
97
- end
98
-
99
- # Set the auto-flush period. Set to true to flush after every log message,
100
- # to an integer to flush every N messages, or to false, nil, or zero to
101
- # never auto-flush. If you turn auto-flushing off, be sure to regularly
102
- # flush the log yourself -- it will eat up memory until you do.
103
- def auto_flushing=(period)
104
- end
105
- deprecate :auto_flushing=
106
-
107
- def flush
108
- end
109
- deprecate :flush
110
-
111
- def respond_to?(method, include_private = false)
112
- return false if method.to_s == "flush"
7
+ def initialize(*args)
8
+ self.class._deprecation_warning
113
9
  super
114
10
  end
115
11
 
116
- def close
117
- @log.close
12
+ def self.inherited(*)
13
+ _deprecation_warning
14
+ super
118
15
  end
119
16
 
120
- private
121
- def open_logfile(log)
122
- Logger.new log
17
+ def self._deprecation_warning
18
+ ::ActiveSupport::Deprecation.warn 'ActiveSupport::BufferedLogger is deprecated! Use ActiveSupport::Logger instead.'
123
19
  end
124
20
  end
125
21
  end
@@ -3,7 +3,6 @@ require 'zlib'
3
3
  require 'active_support/core_ext/array/extract_options'
4
4
  require 'active_support/core_ext/array/wrap'
5
5
  require 'active_support/core_ext/benchmark'
6
- require 'active_support/core_ext/exception'
7
6
  require 'active_support/core_ext/class/attribute_accessors'
8
7
  require 'active_support/core_ext/numeric/bytes'
9
8
  require 'active_support/core_ext/numeric/time'
@@ -45,8 +44,8 @@ module ActiveSupport
45
44
  # Any additional arguments will be passed to the corresponding cache store
46
45
  # class's constructor:
47
46
  #
48
- # ActiveSupport::Cache.lookup_store(:file_store, "/tmp/cache")
49
- # # => same as: ActiveSupport::Cache::FileStore.new("/tmp/cache")
47
+ # ActiveSupport::Cache.lookup_store(:file_store, '/tmp/cache')
48
+ # # => same as: ActiveSupport::Cache::FileStore.new('/tmp/cache')
50
49
  #
51
50
  # If the first argument is not a Symbol, then it will simply be returned:
52
51
  #
@@ -91,6 +90,7 @@ module ActiveSupport
91
90
  case
92
91
  when key.respond_to?(:cache_key) then key.cache_key
93
92
  when key.is_a?(Array) then key.map { |element| retrieve_cache_key(element) }.to_param
93
+ when key.respond_to?(:to_a) then retrieve_cache_key(key.to_a)
94
94
  else key.to_param
95
95
  end.to_s
96
96
  end
@@ -109,9 +109,9 @@ module ActiveSupport
109
109
  #
110
110
  # cache = ActiveSupport::Cache::MemoryStore.new
111
111
  #
112
- # cache.read("city") # => nil
113
- # cache.write("city", "Duckburgh")
114
- # cache.read("city") # => "Duckburgh"
112
+ # cache.read('city') # => nil
113
+ # cache.write('city', "Duckburgh")
114
+ # cache.read('city') # => "Duckburgh"
115
115
  #
116
116
  # Keys are always translated into Strings and are case sensitive. When an
117
117
  # object is specified as a key and has a +cache_key+ method defined, this
@@ -120,7 +120,7 @@ module ActiveSupport
120
120
  # elements will be delimited by slashes, and the elements within a Hash
121
121
  # will be sorted by key so they are consistent.
122
122
  #
123
- # cache.read("city") == cache.read(:city) # => true
123
+ # cache.read('city') == cache.read(:city) # => true
124
124
  #
125
125
  # Nil values can be cached.
126
126
  #
@@ -130,14 +130,13 @@ module ActiveSupport
130
130
  # is a Proc, it will be invoked when each key is evaluated so that you can
131
131
  # use application logic to invalidate keys.
132
132
  #
133
- # cache.namespace = lambda { @last_mod_time } # Set the namespace to a variable
133
+ # cache.namespace = -> { @last_mod_time } # Set the namespace to a variable
134
134
  # @last_mod_time = Time.now # Invalidate the entire cache by changing namespace
135
135
  #
136
- #
137
136
  # Caches can also store values in a compressed format to save space and
138
137
  # reduce time spent sending data. Since there is overhead, values must be
139
138
  # large enough to warrant compression. To turn on compression either pass
140
- # <tt>:compress => true</tt> in the initializer or as an option to +fetch+
139
+ # <tt>compress: true</tt> in the initializer or as an option to +fetch+
141
140
  # or +write+. To specify the threshold at which to compress values, set the
142
141
  # <tt>:compress_threshold</tt> option. The default threshold is 16K.
143
142
  class Store
@@ -147,8 +146,9 @@ module ActiveSupport
147
146
  attr_reader :silence, :options
148
147
  alias :silence? :silence
149
148
 
150
- # Create a new cache. The options will be passed to any write method calls except
151
- # for :namespace which can be used to set the global namespace for the cache.
149
+ # Create a new cache. The options will be passed to any write method calls
150
+ # except for <tt>:namespace</tt> which can be used to set the global
151
+ # namespace for the cache.
152
152
  def initialize(options = nil)
153
153
  @options = options ? options.dup : {}
154
154
  end
@@ -167,7 +167,8 @@ module ActiveSupport
167
167
  @silence = previous_silence
168
168
  end
169
169
 
170
- # Set to true if cache stores should be instrumented. Default is false.
170
+ # Set to +true+ if cache stores should be instrumented.
171
+ # Default is +false+.
171
172
  def self.instrument=(boolean)
172
173
  Thread.current[:instrument_cache_store] = boolean
173
174
  end
@@ -179,125 +180,109 @@ module ActiveSupport
179
180
  # Fetches data from the cache, using the given key. If there is data in
180
181
  # the cache with the given key, then that data is returned.
181
182
  #
182
- # If there is no such data in the cache (a cache miss), then nil will be
183
- # returned. However, if a block has been passed, that block will be run
184
- # in the event of a cache miss. The return value of the block will be
185
- # written to the cache under the given cache key, and that return value
186
- # will be returned.
183
+ # If there is no such data in the cache (a cache miss), then +nil+ will be
184
+ # returned. However, if a block has been passed, that block will be passed
185
+ # the key and executed in the event of a cache miss. The return value of the
186
+ # block will be written to the cache under the given cache key, and that
187
+ # return value will be returned.
187
188
  #
188
- # cache.write("today", "Monday")
189
- # cache.fetch("today") # => "Monday"
189
+ # cache.write('today', 'Monday')
190
+ # cache.fetch('today') # => "Monday"
190
191
  #
191
- # cache.fetch("city") # => nil
192
- # cache.fetch("city") do
193
- # "Duckburgh"
192
+ # cache.fetch('city') # => nil
193
+ # cache.fetch('city') do
194
+ # 'Duckburgh'
194
195
  # end
195
- # cache.fetch("city") # => "Duckburgh"
196
+ # cache.fetch('city') # => "Duckburgh"
196
197
  #
197
198
  # You may also specify additional options via the +options+ argument.
198
- # Setting <tt>:force => true</tt> will force a cache miss:
199
+ # Setting <tt>force: true</tt> will force a cache miss:
199
200
  #
200
- # cache.write("today", "Monday")
201
- # cache.fetch("today", :force => true) # => nil
201
+ # cache.write('today', 'Monday')
202
+ # cache.fetch('today', force: true) # => nil
202
203
  #
203
204
  # Setting <tt>:compress</tt> will store a large cache entry set by the call
204
205
  # in a compressed format.
205
206
  #
206
- #
207
207
  # Setting <tt>:expires_in</tt> will set an expiration time on the cache.
208
208
  # All caches support auto-expiring content after a specified number of
209
209
  # seconds. This value can be specified as an option to the constructor
210
210
  # (in which case all entries will be affected), or it can be supplied to
211
211
  # the +fetch+ or +write+ method to effect just one entry.
212
212
  #
213
- # cache = ActiveSupport::Cache::MemoryStore.new(:expires_in => 5.minutes)
214
- # cache.write(key, value, :expires_in => 1.minute) # Set a lower value for one entry
215
- #
216
- # Setting <tt>:race_condition_ttl</tt> is very useful in situations where a cache entry
217
- # is used very frequently and is under heavy load. If a cache expires and due to heavy load
218
- # seven different processes will try to read data natively and then they all will try to
219
- # write to cache. To avoid that case the first process to find an expired cache entry will
220
- # bump the cache expiration time by the value set in <tt>:race_condition_ttl</tt>. Yes
221
- # this process is extending the time for a stale value by another few seconds. Because
222
- # of extended life of the previous cache, other processes will continue to use slightly
223
- # stale data for a just a big longer. In the meantime that first process will go ahead
224
- # and will write into cache the new value. After that all the processes will start
225
- # getting new value. The key is to keep <tt>:race_condition_ttl</tt> small.
226
- #
227
- # If the process regenerating the entry errors out, the entry will be regenerated
228
- # after the specified number of seconds. Also note that the life of stale cache is
229
- # extended only if it expired recently. Otherwise a new value is generated and
230
- # <tt>:race_condition_ttl</tt> does not play any role.
213
+ # cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 5.minutes)
214
+ # cache.write(key, value, expires_in: 1.minute) # Set a lower value for one entry
215
+ #
216
+ # Setting <tt>:race_condition_ttl</tt> is very useful in situations where
217
+ # a cache entry is used very frequently and is under heavy load. If a
218
+ # cache expires and due to heavy load seven different processes will try
219
+ # to read data natively and then they all will try to write to cache. To
220
+ # avoid that case the first process to find an expired cache entry will
221
+ # bump the cache expiration time by the value set in <tt>:race_condition_ttl</tt>.
222
+ # Yes, this process is extending the time for a stale value by another few
223
+ # seconds. Because of extended life of the previous cache, other processes
224
+ # will continue to use slightly stale data for a just a big longer. In the
225
+ # meantime that first process will go ahead and will write into cache the
226
+ # new value. After that all the processes will start getting new value.
227
+ # The key is to keep <tt>:race_condition_ttl</tt> small.
228
+ #
229
+ # If the process regenerating the entry errors out, the entry will be
230
+ # regenerated after the specified number of seconds. Also note that the
231
+ # life of stale cache is extended only if it expired recently. Otherwise
232
+ # a new value is generated and <tt>:race_condition_ttl</tt> does not play
233
+ # any role.
231
234
  #
232
235
  # # Set all values to expire after one minute.
233
- # cache = ActiveSupport::Cache::MemoryStore.new(:expires_in => 1.minute)
236
+ # cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1.minute)
234
237
  #
235
- # cache.write("foo", "original value")
238
+ # cache.write('foo', 'original value')
236
239
  # val_1 = nil
237
240
  # val_2 = nil
238
241
  # sleep 60
239
242
  #
240
243
  # Thread.new do
241
- # val_1 = cache.fetch("foo", :race_condition_ttl => 10) do
244
+ # val_1 = cache.fetch('foo', race_condition_ttl: 10) do
242
245
  # sleep 1
243
- # "new value 1"
246
+ # 'new value 1'
244
247
  # end
245
248
  # end
246
249
  #
247
250
  # Thread.new do
248
- # val_2 = cache.fetch("foo", :race_condition_ttl => 10) do
249
- # "new value 2"
251
+ # val_2 = cache.fetch('foo', race_condition_ttl: 10) do
252
+ # 'new value 2'
250
253
  # end
251
254
  # end
252
255
  #
253
256
  # # val_1 => "new value 1"
254
257
  # # val_2 => "original value"
255
258
  # # sleep 10 # First thread extend the life of cache by another 10 seconds
256
- # # cache.fetch("foo") => "new value 1"
259
+ # # cache.fetch('foo') => "new value 1"
257
260
  #
258
261
  # Other options will be handled by the specific cache store implementation.
259
- # Internally, #fetch calls #read_entry, and calls #write_entry on a cache miss.
260
- # +options+ will be passed to the #read and #write calls.
262
+ # Internally, #fetch calls #read_entry, and calls #write_entry on a cache
263
+ # miss. +options+ will be passed to the #read and #write calls.
261
264
  #
262
265
  # For example, MemCacheStore's #write method supports the +:raw+
263
266
  # option, which tells the memcached server to store all values as strings.
264
267
  # We can use this option with #fetch too:
265
268
  #
266
269
  # cache = ActiveSupport::Cache::MemCacheStore.new
267
- # cache.fetch("foo", :force => true, :raw => true) do
270
+ # cache.fetch("foo", force: true, raw: true) do
268
271
  # :bar
269
272
  # end
270
- # cache.fetch("foo") # => "bar"
273
+ # cache.fetch('foo') # => "bar"
271
274
  def fetch(name, options = nil)
272
275
  if block_given?
273
276
  options = merged_options(options)
274
277
  key = namespaced_key(name, options)
275
- unless options[:force]
276
- entry = instrument(:read, name, options) do |payload|
277
- payload[:super_operation] = :fetch if payload
278
- read_entry(key, options)
279
- end
280
- end
281
- if entry && entry.expired?
282
- race_ttl = options[:race_condition_ttl].to_f
283
- if race_ttl and Time.now.to_f - entry.expires_at <= race_ttl
284
- entry.expires_at = Time.now + race_ttl
285
- write_entry(key, entry, :expires_in => race_ttl * 2)
286
- else
287
- delete_entry(key, options)
288
- end
289
- entry = nil
290
- end
278
+
279
+ cached_entry = find_cached_entry(key, name, options) unless options[:force]
280
+ entry = handle_expired_entry(cached_entry, key, options)
291
281
 
292
282
  if entry
293
- instrument(:fetch_hit, name, options) { |payload| }
294
- entry.value
283
+ get_entry_value(entry, name, options)
295
284
  else
296
- result = instrument(:generate, name, options) do |payload|
297
- yield
298
- end
299
- write(name, result, options)
300
- result
285
+ save_block_result_to_cache(name, options) { |_name| yield _name }
301
286
  end
302
287
  else
303
288
  read(name, options)
@@ -306,7 +291,7 @@ module ActiveSupport
306
291
 
307
292
  # Fetches data from the cache, using the given key. If there is data in
308
293
  # the cache with the given key, then that data is returned. Otherwise,
309
- # nil is returned.
294
+ # +nil+ is returned.
310
295
  #
311
296
  # Options are passed to the underlying cache implementation.
312
297
  def read(name, options = nil)
@@ -375,18 +360,14 @@ module ActiveSupport
375
360
  end
376
361
  end
377
362
 
378
- # Return true if the cache contains an entry for the given key.
363
+ # Return +true+ if the cache contains an entry for the given key.
379
364
  #
380
365
  # Options are passed to the underlying cache implementation.
381
366
  def exist?(name, options = nil)
382
367
  options = merged_options(options)
383
368
  instrument(:exist?, name) do |payload|
384
369
  entry = read_entry(namespaced_key(name, options), options)
385
- if entry && !entry.expired?
386
- true
387
- else
388
- false
389
- end
370
+ entry && !entry.expired?
390
371
  end
391
372
  end
392
373
 
@@ -408,7 +389,7 @@ module ActiveSupport
408
389
  raise NotImplementedError.new("#{self.class.name} does not support increment")
409
390
  end
410
391
 
411
- # Increment an integer value in the cache.
392
+ # Decrement an integer value in the cache.
412
393
  #
413
394
  # Options are passed to the underlying cache implementation.
414
395
  #
@@ -437,9 +418,10 @@ module ActiveSupport
437
418
  end
438
419
 
439
420
  protected
440
- # Add the namespace defined in the options to a pattern designed to match keys.
441
- # Implementations that support delete_matched should call this method to translate
442
- # a pattern that matches names into one that matches namespaced keys.
421
+ # Add the namespace defined in the options to a pattern designed to
422
+ # match keys. Implementations that support delete_matched should call
423
+ # this method to translate a pattern that matches names into one that
424
+ # matches namespaced keys.
443
425
  def key_matcher(pattern, options)
444
426
  prefix = options[:namespace].is_a?(Proc) ? options[:namespace].call : options[:namespace]
445
427
  if prefix
@@ -455,17 +437,20 @@ module ActiveSupport
455
437
  end
456
438
  end
457
439
 
458
- # Read an entry from the cache implementation. Subclasses must implement this method.
440
+ # Read an entry from the cache implementation. Subclasses must implement
441
+ # this method.
459
442
  def read_entry(key, options) # :nodoc:
460
443
  raise NotImplementedError.new
461
444
  end
462
445
 
463
- # Write an entry to the cache implementation. Subclasses must implement this method.
446
+ # Write an entry to the cache implementation. Subclasses must implement
447
+ # this method.
464
448
  def write_entry(key, entry, options) # :nodoc:
465
449
  raise NotImplementedError.new
466
450
  end
467
451
 
468
- # Delete an entry from the cache implementation. Subclasses must implement this method.
452
+ # Delete an entry from the cache implementation. Subclasses must
453
+ # implement this method.
469
454
  def delete_entry(key, options) # :nodoc:
470
455
  raise NotImplementedError.new
471
456
  end
@@ -481,7 +466,7 @@ module ActiveSupport
481
466
  end
482
467
 
483
468
  # Expand key to be a consistent string value. Invoke +cache_key+ if
484
- # object responds to +cache_key+. Otherwise, to_param method will be
469
+ # object responds to +cache_key+. Otherwise, +to_param+ method will be
485
470
  # called. If the key is a Hash, then keys will be sorted alphabetically.
486
471
  def expanded_key(key) # :nodoc:
487
472
  return key.cache_key.to_s if key.respond_to?(:cache_key)
@@ -500,7 +485,8 @@ module ActiveSupport
500
485
  key.to_param
501
486
  end
502
487
 
503
- # Prefix a key with the namespace. Namespace and key will be delimited with a colon.
488
+ # Prefix a key with the namespace. Namespace and key will be delimited
489
+ # with a colon.
504
490
  def namespaced_key(key, options)
505
491
  key = expanded_key(key)
506
492
  namespace = options[:namespace] if options
@@ -525,114 +511,160 @@ module ActiveSupport
525
511
  return unless logger && logger.debug? && !silence?
526
512
  logger.debug("Cache #{operation}: #{key}#{options.blank? ? "" : " (#{options.inspect})"}")
527
513
  end
528
- end
529
514
 
530
- # Entry that is put into caches. It supports expiration time on entries and can compress values
531
- # to save space in the cache.
532
- class Entry
533
- attr_reader :created_at, :expires_in
534
-
535
- DEFAULT_COMPRESS_LIMIT = 16.kilobytes
515
+ def find_cached_entry(key, name, options)
516
+ instrument(:read, name, options) do |payload|
517
+ payload[:super_operation] = :fetch if payload
518
+ read_entry(key, options)
519
+ end
520
+ end
536
521
 
537
- class << self
538
- # Create an entry with internal attributes set. This method is intended to be
539
- # used by implementations that store cache entries in a native format instead
540
- # of as serialized Ruby objects.
541
- def create(raw_value, created_at, options = {})
542
- entry = new(nil)
543
- entry.instance_variable_set(:@value, raw_value)
544
- entry.instance_variable_set(:@created_at, created_at.to_f)
545
- entry.instance_variable_set(:@compressed, options[:compressed])
546
- entry.instance_variable_set(:@expires_in, options[:expires_in])
522
+ def handle_expired_entry(entry, key, options)
523
+ if entry && entry.expired?
524
+ race_ttl = options[:race_condition_ttl].to_i
525
+ if race_ttl && (Time.now - entry.expires_at <= race_ttl)
526
+ # When an entry has :race_condition_ttl defined, put the stale entry back into the cache
527
+ # for a brief period while the entry is begin recalculated.
528
+ entry.expires_at = Time.now + race_ttl
529
+ write_entry(key, entry, :expires_in => race_ttl * 2)
530
+ else
531
+ delete_entry(key, options)
532
+ end
533
+ entry = nil
534
+ end
547
535
  entry
548
536
  end
549
- end
537
+
538
+ def get_entry_value(entry, name, options)
539
+ instrument(:fetch_hit, name, options) { |payload| }
540
+ entry.value
541
+ end
542
+
543
+ def save_block_result_to_cache(name, options)
544
+ result = instrument(:generate, name, options) do |payload|
545
+ yield(name)
546
+ end
547
+ write(name, result, options)
548
+ result
549
+ end
550
+ end
551
+
552
+ # This class is used to represent cache entries. Cache entries have a value and an optional
553
+ # expiration time. The expiration time is used to support the :race_condition_ttl option
554
+ # on the cache.
555
+ #
556
+ # Since cache entries in most instances will be serialized, the internals of this class are highly optimized
557
+ # using short instance variable names that are lazily defined.
558
+ class Entry # :nodoc:
559
+ DEFAULT_COMPRESS_LIMIT = 16.kilobytes
550
560
 
551
561
  # Create a new cache entry for the specified value. Options supported are
552
562
  # +:compress+, +:compress_threshold+, and +:expires_in+.
553
563
  def initialize(value, options = {})
554
- @compressed = false
555
- @expires_in = options[:expires_in]
556
- @expires_in = @expires_in.to_f if @expires_in
557
- @created_at = Time.now.to_f
558
- if value.nil?
559
- @value = nil
564
+ if should_compress?(value, options)
565
+ @v = compress(value)
566
+ @c = true
560
567
  else
561
- @value = Marshal.dump(value)
562
- if should_compress?(@value, options)
563
- @value = Zlib::Deflate.deflate(@value)
564
- @compressed = true
565
- end
568
+ @v = value
566
569
  end
567
- end
568
-
569
- # Get the raw value. This value may be serialized and compressed.
570
- def raw_value
571
- @value
572
- end
573
-
574
- # Get the value stored in the cache.
575
- def value
576
- # If the original value was exactly false @value is still true because
577
- # it is marshalled and eventually compressed. Both operations yield
578
- # strings.
579
- if @value
580
- # In rails 3.1 and earlier values in entries did not marshaled without
581
- # options[:compress] and if it's Numeric.
582
- # But after commit a263f377978fc07515b42808ebc1f7894fafaa3a
583
- # all values in entries are marshalled. And after that code below expects
584
- # that all values in entries will be marshaled (and will be strings).
585
- # So here we need a check for old ones.
586
- begin
587
- Marshal.load(compressed? ? Zlib::Inflate.inflate(@value) : @value)
588
- rescue TypeError
589
- compressed? ? Zlib::Inflate.inflate(@value) : @value
590
- end
570
+ if expires_in = options[:expires_in]
571
+ @x = (Time.now + expires_in).to_i
591
572
  end
592
573
  end
593
574
 
594
- def compressed?
595
- @compressed
575
+ def value
576
+ convert_version_3_entry! if defined?(@value)
577
+ compressed? ? uncompress(@v) : @v
596
578
  end
597
579
 
598
- # Check if the entry is expired. The +expires_in+ parameter can override the
599
- # value set when the entry was created.
580
+ # Check if the entry is expired. The +expires_in+ parameter can override
581
+ # the value set when the entry was created.
600
582
  def expired?
601
- @expires_in && @created_at + @expires_in <= Time.now.to_f
602
- end
603
-
604
- # Set a new time when the entry will expire.
605
- def expires_at=(time)
606
- if time
607
- @expires_in = time.to_f - @created_at
583
+ convert_version_3_entry! if defined?(@value)
584
+ if defined?(@x)
585
+ @x && @x < Time.now.to_i
608
586
  else
609
- @expires_in = nil
587
+ false
610
588
  end
611
589
  end
612
590
 
613
- # Seconds since the epoch when the entry will expire.
614
591
  def expires_at
615
- @expires_in ? @created_at + @expires_in : nil
592
+ Time.at(@x) if defined?(@x)
593
+ end
594
+
595
+ def expires_at=(value)
596
+ @x = value.to_i
616
597
  end
617
598
 
618
- # Returns the size of the cached value. This could be less than value.size
619
- # if the data is compressed.
599
+ # Returns the size of the cached value. This could be less than
600
+ # <tt>value.size</tt> if the data is compressed.
620
601
  def size
621
- if @value.nil?
622
- 0
602
+ if defined?(@s)
603
+ @s
623
604
  else
624
- @value.bytesize
605
+ case value
606
+ when NilClass
607
+ 0
608
+ when String
609
+ @v.bytesize
610
+ else
611
+ @s = Marshal.dump(@v).bytesize
612
+ end
613
+ end
614
+ end
615
+
616
+ # Duplicate the value in a class. This is used by cache implementations that don't natively
617
+ # serialize entries to protect against accidental cache modifications.
618
+ def dup_value!
619
+ convert_version_3_entry! if defined?(@value)
620
+ if @v && !compressed? && !(@v.is_a?(Numeric) || @v == true || @v == false)
621
+ if @v.is_a?(String)
622
+ @v = @v.dup
623
+ else
624
+ @v = Marshal.load(Marshal.dump(@v))
625
+ end
625
626
  end
626
627
  end
627
628
 
628
629
  private
629
- def should_compress?(serialized_value, options)
630
- if options[:compress]
630
+ def should_compress?(value, options)
631
+ if value && options[:compress]
631
632
  compress_threshold = options[:compress_threshold] || DEFAULT_COMPRESS_LIMIT
632
- return true if serialized_value.size >= compress_threshold
633
+ serialized_value_size = (value.is_a?(String) ? value : Marshal.dump(value)).bytesize
634
+ return true if serialized_value_size >= compress_threshold
633
635
  end
634
636
  false
635
637
  end
638
+
639
+ def compressed?
640
+ defined?(@c) ? @c : false
641
+ end
642
+
643
+ def compress(value)
644
+ Zlib::Deflate.deflate(Marshal.dump(value))
645
+ end
646
+
647
+ def uncompress(value)
648
+ Marshal.load(Zlib::Inflate.inflate(value))
649
+ end
650
+
651
+ # The internals of this method changed between Rails 3.x and 4.0. This method provides the glue
652
+ # to ensure that cache entries created under the old version still work with the new class definition.
653
+ def convert_version_3_entry!
654
+ if defined?(@value)
655
+ @v = @value
656
+ remove_instance_variable(:@value)
657
+ end
658
+ if defined?(@compressed)
659
+ @c = @compressed
660
+ remove_instance_variable(:@compressed)
661
+ end
662
+ if defined?(@expires_in) && defined?(@created_at) && @expires_in && @created_at
663
+ @x = (@created_at + @expires_in).to_i
664
+ remove_instance_variable(:@created_at)
665
+ remove_instance_variable(:@expires_in)
666
+ end
667
+ end
636
668
  end
637
669
  end
638
670
  end