activesupport 4.2.0 → 5.0.0.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (185) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +630 -220
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +2 -3
  5. data/lib/active_support/array_inquirer.rb +44 -0
  6. data/lib/active_support/backtrace_cleaner.rb +1 -1
  7. data/lib/active_support/benchmarkable.rb +1 -1
  8. data/lib/active_support/cache/file_store.rb +36 -22
  9. data/lib/active_support/cache/mem_cache_store.rb +63 -54
  10. data/lib/active_support/cache/memory_store.rb +16 -21
  11. data/lib/active_support/cache/null_store.rb +1 -4
  12. data/lib/active_support/cache/strategy/local_cache.rb +31 -20
  13. data/lib/active_support/cache.rb +73 -89
  14. data/lib/active_support/callbacks.rb +195 -155
  15. data/lib/active_support/concern.rb +2 -2
  16. data/lib/active_support/concurrency/latch.rb +7 -15
  17. data/lib/active_support/concurrency/share_lock.rb +186 -0
  18. data/lib/active_support/configurable.rb +1 -0
  19. data/lib/active_support/core_ext/array/access.rb +27 -1
  20. data/lib/active_support/core_ext/array/conversions.rb +6 -4
  21. data/lib/active_support/core_ext/array/grouping.rb +9 -18
  22. data/lib/active_support/core_ext/array/inquiry.rb +17 -0
  23. data/lib/active_support/core_ext/array/wrap.rb +5 -4
  24. data/lib/active_support/core_ext/array.rb +1 -0
  25. data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -10
  26. data/lib/active_support/core_ext/class/attribute.rb +10 -9
  27. data/lib/active_support/core_ext/class/subclasses.rb +3 -4
  28. data/lib/active_support/core_ext/class.rb +0 -1
  29. data/lib/active_support/core_ext/date/blank.rb +12 -0
  30. data/lib/active_support/core_ext/date/calculations.rb +1 -1
  31. data/lib/active_support/core_ext/date/conversions.rb +13 -6
  32. data/lib/active_support/core_ext/date.rb +1 -1
  33. data/lib/active_support/core_ext/date_and_time/calculations.rb +109 -25
  34. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -0
  35. data/lib/active_support/core_ext/date_and_time/zones.rb +3 -4
  36. data/lib/active_support/core_ext/date_time/blank.rb +12 -0
  37. data/lib/active_support/core_ext/date_time/calculations.rb +36 -10
  38. data/lib/active_support/core_ext/date_time/compatibility.rb +5 -0
  39. data/lib/active_support/core_ext/date_time/conversions.rb +2 -0
  40. data/lib/active_support/core_ext/date_time.rb +2 -1
  41. data/lib/active_support/core_ext/enumerable.rb +49 -5
  42. data/lib/active_support/core_ext/file/atomic.rb +30 -25
  43. data/lib/active_support/core_ext/hash/conversions.rb +23 -4
  44. data/lib/active_support/core_ext/hash/deep_merge.rb +1 -1
  45. data/lib/active_support/core_ext/hash/except.rb +9 -8
  46. data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -1
  47. data/lib/active_support/core_ext/hash/keys.rb +23 -19
  48. data/lib/active_support/core_ext/hash/slice.rb +1 -1
  49. data/lib/active_support/core_ext/hash/transform_values.rb +11 -5
  50. data/lib/active_support/core_ext/integer/time.rb +1 -16
  51. data/lib/active_support/core_ext/kernel/concern.rb +2 -0
  52. data/lib/active_support/core_ext/kernel/debugger.rb +3 -10
  53. data/lib/active_support/core_ext/kernel/reporting.rb +2 -83
  54. data/lib/active_support/core_ext/kernel.rb +0 -1
  55. data/lib/active_support/core_ext/load_error.rb +4 -2
  56. data/lib/active_support/core_ext/marshal.rb +12 -11
  57. data/lib/active_support/core_ext/module/aliasing.rb +6 -1
  58. data/lib/active_support/core_ext/module/anonymous.rb +10 -1
  59. data/lib/active_support/core_ext/module/attr_internal.rb +2 -5
  60. data/lib/active_support/core_ext/module/attribute_accessors.rb +15 -15
  61. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
  62. data/lib/active_support/core_ext/module/concerning.rb +4 -4
  63. data/lib/active_support/core_ext/module/delegation.rb +35 -25
  64. data/lib/active_support/core_ext/module/deprecation.rb +2 -2
  65. data/lib/active_support/core_ext/module/introspection.rb +4 -0
  66. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -11
  67. data/lib/active_support/core_ext/module/qualified_const.rb +30 -12
  68. data/lib/active_support/core_ext/module/remove_method.rb +23 -0
  69. data/lib/active_support/core_ext/module.rb +1 -0
  70. data/lib/active_support/core_ext/name_error.rb +15 -2
  71. data/lib/active_support/core_ext/numeric/bytes.rb +20 -0
  72. data/lib/active_support/core_ext/numeric/conversions.rb +74 -64
  73. data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
  74. data/lib/active_support/core_ext/numeric/time.rb +24 -19
  75. data/lib/active_support/core_ext/numeric.rb +1 -0
  76. data/lib/active_support/core_ext/object/blank.rb +17 -5
  77. data/lib/active_support/core_ext/object/deep_dup.rb +10 -3
  78. data/lib/active_support/core_ext/object/duplicable.rb +8 -13
  79. data/lib/active_support/core_ext/object/inclusion.rb +2 -2
  80. data/lib/active_support/core_ext/object/instance_variables.rb +1 -1
  81. data/lib/active_support/core_ext/object/json.rb +15 -7
  82. data/lib/active_support/core_ext/object/to_query.rb +1 -1
  83. data/lib/active_support/core_ext/object/try.rb +68 -22
  84. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  85. data/lib/active_support/core_ext/object.rb +0 -1
  86. data/lib/active_support/core_ext/range/conversions.rb +18 -6
  87. data/lib/active_support/core_ext/range/each.rb +16 -18
  88. data/lib/active_support/core_ext/range/include_range.rb +20 -20
  89. data/lib/active_support/core_ext/securerandom.rb +23 -0
  90. data/lib/active_support/core_ext/string/access.rb +1 -1
  91. data/lib/active_support/core_ext/string/behavior.rb +1 -1
  92. data/lib/active_support/core_ext/string/conversions.rb +4 -3
  93. data/lib/active_support/core_ext/string/filters.rb +5 -5
  94. data/lib/active_support/core_ext/string/inflections.rb +32 -5
  95. data/lib/active_support/core_ext/string/multibyte.rb +11 -7
  96. data/lib/active_support/core_ext/string/output_safety.rb +18 -16
  97. data/lib/active_support/core_ext/string/strip.rb +3 -6
  98. data/lib/active_support/core_ext/struct.rb +3 -6
  99. data/lib/active_support/core_ext/time/calculations.rb +36 -11
  100. data/lib/active_support/core_ext/time/compatibility.rb +5 -0
  101. data/lib/active_support/core_ext/time/conversions.rb +4 -2
  102. data/lib/active_support/core_ext/time/marshal.rb +2 -29
  103. data/lib/active_support/core_ext/time/zones.rb +36 -4
  104. data/lib/active_support/core_ext/time.rb +1 -1
  105. data/lib/active_support/core_ext/uri.rb +1 -3
  106. data/lib/active_support/core_ext.rb +2 -1
  107. data/lib/active_support/dependencies/interlock.rb +51 -0
  108. data/lib/active_support/dependencies.rb +87 -95
  109. data/lib/active_support/deprecation/behaviors.rb +16 -2
  110. data/lib/active_support/deprecation/method_wrappers.rb +42 -16
  111. data/lib/active_support/deprecation/proxy_wrappers.rb +47 -24
  112. data/lib/active_support/deprecation/reporting.rb +23 -5
  113. data/lib/active_support/deprecation.rb +1 -1
  114. data/lib/active_support/duration/iso8601_parser.rb +122 -0
  115. data/lib/active_support/duration/iso8601_serializer.rb +51 -0
  116. data/lib/active_support/duration.rb +55 -10
  117. data/lib/active_support/evented_file_update_checker.rb +194 -0
  118. data/lib/active_support/execution_wrapper.rb +117 -0
  119. data/lib/active_support/executor.rb +6 -0
  120. data/lib/active_support/file_update_checker.rb +23 -3
  121. data/lib/active_support/gem_version.rb +4 -4
  122. data/lib/active_support/hash_with_indifferent_access.rb +46 -13
  123. data/lib/active_support/i18n_railtie.rb +25 -4
  124. data/lib/active_support/inflector/inflections.rb +36 -5
  125. data/lib/active_support/inflector/methods.rb +97 -90
  126. data/lib/active_support/inflector/transliterate.rb +36 -21
  127. data/lib/active_support/json/decoding.rb +11 -10
  128. data/lib/active_support/json/encoding.rb +4 -49
  129. data/lib/active_support/key_generator.rb +7 -9
  130. data/lib/active_support/locale/en.yml +2 -0
  131. data/lib/active_support/log_subscriber/test_helper.rb +3 -3
  132. data/lib/active_support/log_subscriber.rb +1 -1
  133. data/lib/active_support/logger.rb +50 -1
  134. data/lib/active_support/logger_silence.rb +8 -4
  135. data/lib/active_support/logger_thread_safe_level.rb +31 -0
  136. data/lib/active_support/message_encryptor.rb +4 -4
  137. data/lib/active_support/message_verifier.rb +70 -8
  138. data/lib/active_support/multibyte/chars.rb +13 -4
  139. data/lib/active_support/multibyte/unicode.rb +44 -21
  140. data/lib/active_support/notifications/fanout.rb +6 -6
  141. data/lib/active_support/notifications/instrumenter.rb +20 -2
  142. data/lib/active_support/notifications.rb +2 -2
  143. data/lib/active_support/number_helper/number_to_currency_converter.rb +7 -9
  144. data/lib/active_support/number_helper/number_to_delimited_converter.rb +8 -3
  145. data/lib/active_support/number_helper/number_to_human_converter.rb +6 -4
  146. data/lib/active_support/number_helper/number_to_human_size_converter.rb +6 -2
  147. data/lib/active_support/number_helper/number_to_percentage_converter.rb +1 -1
  148. data/lib/active_support/number_helper/number_to_phone_converter.rb +11 -2
  149. data/lib/active_support/number_helper/number_to_rounded_converter.rb +30 -25
  150. data/lib/active_support/number_helper.rb +90 -67
  151. data/lib/active_support/ordered_hash.rb +1 -1
  152. data/lib/active_support/ordered_options.rb +15 -1
  153. data/lib/active_support/per_thread_registry.rb +8 -3
  154. data/lib/active_support/rails.rb +2 -2
  155. data/lib/active_support/railtie.rb +6 -1
  156. data/lib/active_support/reloader.rb +129 -0
  157. data/lib/active_support/rescuable.rb +93 -47
  158. data/lib/active_support/security_utils.rb +7 -0
  159. data/lib/active_support/string_inquirer.rb +1 -1
  160. data/lib/active_support/subscriber.rb +5 -10
  161. data/lib/active_support/tagged_logging.rb +3 -1
  162. data/lib/active_support/test_case.rb +15 -29
  163. data/lib/active_support/testing/assertions.rb +15 -13
  164. data/lib/active_support/testing/autorun.rb +8 -1
  165. data/lib/active_support/testing/deprecation.rb +9 -8
  166. data/lib/active_support/testing/file_fixtures.rb +34 -0
  167. data/lib/active_support/testing/isolation.rb +22 -8
  168. data/lib/active_support/testing/method_call_assertions.rb +41 -0
  169. data/lib/active_support/testing/stream.rb +42 -0
  170. data/lib/active_support/testing/time_helpers.rb +13 -10
  171. data/lib/active_support/time_with_zone.rb +135 -46
  172. data/lib/active_support/values/time_zone.rb +95 -47
  173. data/lib/active_support/values/unicode_tables.dat +0 -0
  174. data/lib/active_support/xml_mini/jdom.rb +7 -6
  175. data/lib/active_support/xml_mini/libxml.rb +2 -2
  176. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  177. data/lib/active_support/xml_mini/rexml.rb +7 -8
  178. data/lib/active_support/xml_mini.rb +22 -14
  179. data/lib/active_support.rb +20 -6
  180. metadata +33 -35
  181. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -14
  182. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  183. data/lib/active_support/core_ext/date_time/zones.rb +0 -6
  184. data/lib/active_support/core_ext/object/itself.rb +0 -15
  185. data/lib/active_support/core_ext/thread.rb +0 -86
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2005-2014 David Heinemeier Hansson
1
+ Copyright (c) 2005-2016 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
@@ -17,4 +17,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
17
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
18
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
19
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc CHANGED
@@ -10,11 +10,11 @@ outside of Rails.
10
10
 
11
11
  The latest version of Active Support can be installed with RubyGems:
12
12
 
13
- % [sudo] gem install activesupport
13
+ $ gem install activesupport
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/4-2-stable/activesupport
17
+ * https://github.com/rails/rails/tree/master/activesupport
18
18
 
19
19
 
20
20
  == License
@@ -37,4 +37,3 @@ Bug reports can be filed for the Ruby on Rails project here:
37
37
  Feature requests should be discussed on the rails-core mailing list here:
38
38
 
39
39
  * https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core
40
-
@@ -0,0 +1,44 @@
1
+ module ActiveSupport
2
+ # Wrapping an array in an +ArrayInquirer+ gives a friendlier way to check
3
+ # its string-like contents:
4
+ #
5
+ # variants = ActiveSupport::ArrayInquirer.new([:phone, :tablet])
6
+ #
7
+ # variants.phone? # => true
8
+ # variants.tablet? # => true
9
+ # variants.desktop? # => false
10
+ class ArrayInquirer < Array
11
+ # Passes each element of +candidates+ collection to ArrayInquirer collection.
12
+ # The method returns true if at least one element is the same. If +candidates+
13
+ # collection is not given, method returns true.
14
+ #
15
+ # variants = ActiveSupport::ArrayInquirer.new([:phone, :tablet])
16
+ #
17
+ # variants.any? # => true
18
+ # variants.any?(:phone, :tablet) # => true
19
+ # variants.any?('phone', 'desktop') # => true
20
+ # variants.any?(:desktop, :watch) # => false
21
+ def any?(*candidates, &block)
22
+ if candidates.none?
23
+ super
24
+ else
25
+ candidates.any? do |candidate|
26
+ include?(candidate.to_sym) || include?(candidate.to_s)
27
+ end
28
+ end
29
+ end
30
+
31
+ private
32
+ def respond_to_missing?(name, include_private = false)
33
+ name[-1] == '?'
34
+ end
35
+
36
+ def method_missing(name, *args)
37
+ if name[-1] == '?'
38
+ any?(name[0..-2])
39
+ else
40
+ super
41
+ end
42
+ end
43
+ end
44
+ end
@@ -25,7 +25,7 @@ module ActiveSupport
25
25
  # of the backtrace, you can call <tt>BacktraceCleaner#remove_filters!</tt>
26
26
  # These two methods will give you a completely untouched backtrace.
27
27
  #
28
- # Inspired by the Quiet Backtrace gem by Thoughtbot.
28
+ # Inspired by the Quiet Backtrace gem by thoughtbot.
29
29
  class BacktraceCleaner
30
30
  def initialize
31
31
  @filters, @silencers = [], []
@@ -38,7 +38,7 @@ module ActiveSupport
38
38
  options[:level] ||= :info
39
39
 
40
40
  result = nil
41
- ms = Benchmark.ms { result = options[:silence] ? silence { yield } : yield }
41
+ ms = Benchmark.ms { result = options[:silence] ? logger.silence { yield } : yield }
42
42
  logger.send(options[:level], '%s (%.1fms)' % [ message, ms ])
43
43
  result
44
44
  else
@@ -10,25 +10,27 @@ module ActiveSupport
10
10
  # FileStore implements the Strategy::LocalCache strategy which implements
11
11
  # an in-memory cache inside of a block.
12
12
  class FileStore < Store
13
+ prepend Strategy::LocalCache
13
14
  attr_reader :cache_path
14
15
 
15
16
  DIR_FORMATTER = "%03X"
16
17
  FILENAME_MAX_SIZE = 228 # max filename size on file system is 255, minus room for timestamp and random characters appended by Tempfile (used by atomic write)
17
18
  FILEPATH_MAX_SIZE = 900 # max is 1024, plus some room
18
19
  EXCLUDED_DIRS = ['.', '..'].freeze
20
+ GITKEEP_FILES = ['.gitkeep', '.keep'].freeze
19
21
 
20
22
  def initialize(cache_path, options = nil)
21
23
  super(options)
22
24
  @cache_path = cache_path.to_s
23
- extend Strategy::LocalCache
24
25
  end
25
26
 
26
27
  # Deletes all items from the cache. In this case it deletes all the entries in the specified
27
- # file store directory except for .gitkeep. Be careful which directory is specified in your
28
+ # file store directory except for .keep or .gitkeep. Be careful which directory is specified in your
28
29
  # config file when using +FileStore+ because everything in that directory will be deleted.
29
30
  def clear(options = nil)
30
- root_dirs = Dir.entries(cache_path).reject {|f| (EXCLUDED_DIRS + [".gitkeep"]).include?(f)}
31
+ root_dirs = exclude_from(cache_path, EXCLUDED_DIRS + GITKEEP_FILES)
31
32
  FileUtils.rm_r(root_dirs.collect{|f| File.join(cache_path, f)})
33
+ rescue Errno::ENOENT
32
34
  end
33
35
 
34
36
  # Preemptively iterates through all stored keys and removes the ones which have expired.
@@ -59,7 +61,7 @@ module ActiveSupport
59
61
  matcher = key_matcher(matcher, options)
60
62
  search_dir(cache_path) do |path|
61
63
  key = file_path_key(path)
62
- delete_entry(key, options) if key.match(matcher)
64
+ delete_entry(path, options) if key.match(matcher)
63
65
  end
64
66
  end
65
67
  end
@@ -67,9 +69,8 @@ module ActiveSupport
67
69
  protected
68
70
 
69
71
  def read_entry(key, options)
70
- file_name = key_file_path(key)
71
- if File.exist?(file_name)
72
- File.open(file_name) { |f| Marshal.load(f) }
72
+ if File.exist?(key)
73
+ File.open(key) { |f| Marshal.load(f) }
73
74
  end
74
75
  rescue => e
75
76
  logger.error("FileStoreError (#{e}): #{e.message}") if logger
@@ -77,23 +78,21 @@ module ActiveSupport
77
78
  end
78
79
 
79
80
  def write_entry(key, entry, options)
80
- file_name = key_file_path(key)
81
- return false if options[:unless_exist] && File.exist?(file_name)
82
- ensure_cache_path(File.dirname(file_name))
83
- File.atomic_write(file_name, cache_path) {|f| Marshal.dump(entry, f)}
81
+ return false if options[:unless_exist] && File.exist?(key)
82
+ ensure_cache_path(File.dirname(key))
83
+ File.atomic_write(key, cache_path) {|f| Marshal.dump(entry, f)}
84
84
  true
85
85
  end
86
86
 
87
87
  def delete_entry(key, options)
88
- file_name = key_file_path(key)
89
- if File.exist?(file_name)
88
+ if File.exist?(key)
90
89
  begin
91
- File.delete(file_name)
92
- delete_empty_directories(File.dirname(file_name))
90
+ File.delete(key)
91
+ delete_empty_directories(File.dirname(key))
93
92
  true
94
93
  rescue => e
95
94
  # Just in case the error was caused by another process deleting the file first.
96
- raise e if File.exist?(file_name)
95
+ raise e if File.exist?(key)
97
96
  false
98
97
  end
99
98
  end
@@ -117,12 +116,14 @@ module ActiveSupport
117
116
  end
118
117
 
119
118
  # Translate a key into a file path.
120
- def key_file_path(key)
121
- if key.size > FILEPATH_MAX_SIZE
122
- key = Digest::MD5.hexdigest(key)
119
+ def normalize_key(key, options)
120
+ key = super
121
+ fname = URI.encode_www_form_component(key)
122
+
123
+ if fname.size > FILEPATH_MAX_SIZE
124
+ fname = Digest::MD5.hexdigest(key)
123
125
  end
124
126
 
125
- fname = URI.encode_www_form_component(key)
126
127
  hash = Zlib.adler32(fname)
127
128
  hash, dir_1 = hash.divmod(0x1000)
128
129
  dir_2 = hash.modulo(0x1000)
@@ -137,6 +138,14 @@ module ActiveSupport
137
138
  File.join(cache_path, DIR_FORMATTER % dir_1, DIR_FORMATTER % dir_2, *fname_paths)
138
139
  end
139
140
 
141
+ def key_file_path(key)
142
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
143
+ `key_file_path` is deprecated and will be removed from Rails 5.1.
144
+ Please use `normalize_key` which will return a fully resolved key or nothing.
145
+ MESSAGE
146
+ key
147
+ end
148
+
140
149
  # Translate a file path into a key.
141
150
  def file_path_key(path)
142
151
  fname = path[cache_path.to_s.size..-1].split(File::SEPARATOR, 4).last
@@ -146,7 +155,7 @@ module ActiveSupport
146
155
  # Delete empty directories in the cache.
147
156
  def delete_empty_directories(dir)
148
157
  return if File.realpath(dir) == File.realpath(cache_path)
149
- if Dir.entries(dir).reject {|f| EXCLUDED_DIRS.include?(f)}.empty?
158
+ if exclude_from(dir, EXCLUDED_DIRS).empty?
150
159
  Dir.delete(dir) rescue nil
151
160
  delete_empty_directories(File.dirname(dir))
152
161
  end
@@ -173,7 +182,7 @@ module ActiveSupport
173
182
  # Modifies the amount of an already existing integer value that is stored in the cache.
174
183
  # If the key is not found nothing is done.
175
184
  def modify_value(name, amount, options)
176
- file_name = key_file_path(namespaced_key(name, options))
185
+ file_name = normalize_key(name, options)
177
186
 
178
187
  lock_file(file_name) do
179
188
  options = merged_options(options)
@@ -185,6 +194,11 @@ module ActiveSupport
185
194
  end
186
195
  end
187
196
  end
197
+
198
+ # Exclude entries from source directory
199
+ def exclude_from(source, excludes)
200
+ Dir.entries(source).reject { |f| excludes.include?(f) }
201
+ end
188
202
  end
189
203
  end
190
204
  end
@@ -24,9 +24,41 @@ module ActiveSupport
24
24
  # MemCacheStore implements the Strategy::LocalCache strategy which implements
25
25
  # an in-memory cache inside of a block.
26
26
  class MemCacheStore < Store
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
47
+ end
48
+
49
+ prepend Strategy::LocalCache
50
+ prepend LocalCacheWithRaw
51
+
27
52
  ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
28
53
 
29
- 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:
30
62
  addresses = addresses.flatten
31
63
  options = addresses.extract_options!
32
64
  addresses = ["localhost:11211"] if addresses.empty?
@@ -56,9 +88,6 @@ module ActiveSupport
56
88
  UNIVERSAL_OPTIONS.each{|name| mem_cache_options.delete(name)}
57
89
  @data = self.class.build_mem_cache(*(addresses + [mem_cache_options]))
58
90
  end
59
-
60
- extend Strategy::LocalCache
61
- extend LocalCacheWithRaw
62
91
  end
63
92
 
64
93
  # Reads multiple values from the cache using a single call to the
@@ -66,7 +95,8 @@ module ActiveSupport
66
95
  def read_multi(*names)
67
96
  options = names.extract_options!
68
97
  options = merged_options(options)
69
- 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]}]
70
100
  raw_values = @data.get_multi(keys_to_names.keys, :raw => true)
71
101
  values = {}
72
102
  raw_values.each do |key, value|
@@ -83,11 +113,10 @@ module ActiveSupport
83
113
  def increment(name, amount = 1, options = nil) # :nodoc:
84
114
  options = merged_options(options)
85
115
  instrument(:increment, name, :amount => amount) do
86
- @data.incr(escape_key(namespaced_key(name, options)), amount)
116
+ rescue_error_with nil do
117
+ @data.incr(normalize_key(name, options), amount)
118
+ end
87
119
  end
88
- rescue Dalli::DalliError => e
89
- logger.error("DalliError (#{e}): #{e.message}") if logger
90
- nil
91
120
  end
92
121
 
93
122
  # Decrement a cached value. This method uses the memcached decr atomic
@@ -97,20 +126,16 @@ module ActiveSupport
97
126
  def decrement(name, amount = 1, options = nil) # :nodoc:
98
127
  options = merged_options(options)
99
128
  instrument(:decrement, name, :amount => amount) do
100
- @data.decr(escape_key(namespaced_key(name, options)), amount)
129
+ rescue_error_with nil do
130
+ @data.decr(normalize_key(name, options), amount)
131
+ end
101
132
  end
102
- rescue Dalli::DalliError => e
103
- logger.error("DalliError (#{e}): #{e.message}") if logger
104
- nil
105
133
  end
106
134
 
107
135
  # Clear the entire cache on all memcached servers. This method should
108
136
  # be used with care when shared cache is being used.
109
137
  def clear(options = nil)
110
- @data.flush_all
111
- rescue Dalli::DalliError => e
112
- logger.error("DalliError (#{e}): #{e.message}") if logger
113
- nil
138
+ rescue_error_with(nil) { @data.flush_all }
114
139
  end
115
140
 
116
141
  # Get the statistics from the memcached servers.
@@ -121,10 +146,7 @@ module ActiveSupport
121
146
  protected
122
147
  # Read an entry from the cache.
123
148
  def read_entry(key, options) # :nodoc:
124
- deserialize_entry(@data.get(escape_key(key), options))
125
- rescue Dalli::DalliError => e
126
- logger.error("DalliError (#{e}): #{e.message}") if logger
127
- nil
149
+ rescue_error_with(nil) { deserialize_entry(@data.get(key, options)) }
128
150
  end
129
151
 
130
152
  # Write an entry to the cache.
@@ -136,18 +158,14 @@ module ActiveSupport
136
158
  # Set the memcache expire a few minutes in the future to support race condition ttls on read
137
159
  expires_in += 5.minutes
138
160
  end
139
- @data.send(method, escape_key(key), value, expires_in, options)
140
- rescue Dalli::DalliError => e
141
- logger.error("DalliError (#{e}): #{e.message}") if logger
142
- false
161
+ rescue_error_with false do
162
+ @data.send(method, key, value, expires_in, options)
163
+ end
143
164
  end
144
165
 
145
166
  # Delete an entry from the cache.
146
167
  def delete_entry(key, options) # :nodoc:
147
- @data.delete(escape_key(key))
148
- rescue Dalli::DalliError => e
149
- logger.error("DalliError (#{e}): #{e.message}") if logger
150
- false
168
+ rescue_error_with(false) { @data.delete(key) }
151
169
  end
152
170
 
153
171
  private
@@ -155,44 +173,35 @@ module ActiveSupport
155
173
  # Memcache keys are binaries. So we need to force their encoding to binary
156
174
  # before applying the regular expression to ensure we are escaping all
157
175
  # characters properly.
158
- def escape_key(key)
159
- key = key.to_s.dup
176
+ def normalize_key(key, options)
177
+ key = super.dup
160
178
  key = key.force_encoding(Encoding::ASCII_8BIT)
161
179
  key = key.gsub(ESCAPE_KEY_CHARS){ |match| "%#{match.getbyte(0).to_s(16).upcase}" }
162
180
  key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250
163
181
  key
164
182
  end
165
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
+
166
192
  def deserialize_entry(raw_value)
167
193
  if raw_value
168
194
  entry = Marshal.load(raw_value) rescue raw_value
169
195
  entry.is_a?(Entry) ? entry : Entry.new(entry)
170
- else
171
- nil
172
196
  end
173
197
  end
174
198
 
175
- # Provide support for raw values in the local cache strategy.
176
- module LocalCacheWithRaw # :nodoc:
177
- protected
178
- def read_entry(key, options)
179
- entry = super
180
- if options[:raw] && local_cache && entry
181
- entry = deserialize_entry(entry.value)
182
- end
183
- entry
184
- end
185
-
186
- def write_entry(key, entry, options) # :nodoc:
187
- retval = super
188
- if options[:raw] && local_cache && retval
189
- raw_entry = Entry.new(entry.value.to_s)
190
- raw_entry.expires_at = entry.expires_at
191
- local_cache.write_entry(key, raw_entry, options)
192
- end
193
- retval
194
- end
195
- end
199
+ def rescue_error_with(fallback)
200
+ yield
201
+ rescue Dalli::DalliError => e
202
+ logger.error("DalliError (#{e}): #{e.message}") if logger
203
+ fallback
204
+ end
196
205
  end
197
206
  end
198
207
  end
@@ -75,30 +75,12 @@ module ActiveSupport
75
75
 
76
76
  # Increment an integer value in the cache.
77
77
  def increment(name, amount = 1, options = nil)
78
- synchronize do
79
- options = merged_options(options)
80
- if num = read(name, options)
81
- num = num.to_i + amount
82
- write(name, num, options)
83
- num
84
- else
85
- nil
86
- end
87
- end
78
+ modify_value(name, amount, options)
88
79
  end
89
80
 
90
81
  # Decrement an integer value in the cache.
91
82
  def decrement(name, amount = 1, options = nil)
92
- synchronize do
93
- options = merged_options(options)
94
- if num = read(name, options)
95
- num = num.to_i - amount
96
- write(name, num, options)
97
- num
98
- else
99
- nil
100
- end
101
- end
83
+ modify_value(name, -amount, options)
102
84
  end
103
85
 
104
86
  def delete_matched(matcher, options = nil)
@@ -126,7 +108,7 @@ module ActiveSupport
126
108
 
127
109
  PER_ENTRY_OVERHEAD = 240
128
110
 
129
- def cached_size(key, entry)
111
+ def cached_size(key, entry) # :nodoc:
130
112
  key.to_s.bytesize + entry.size + PER_ENTRY_OVERHEAD
131
113
  end
132
114
 
@@ -167,6 +149,19 @@ module ActiveSupport
167
149
  !!entry
168
150
  end
169
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
170
165
  end
171
166
  end
172
167
  end
@@ -8,10 +8,7 @@ module ActiveSupport
8
8
  # be cached inside blocks that utilize this strategy. See
9
9
  # ActiveSupport::Cache::Strategy::LocalCache for more details.
10
10
  class NullStore < Store
11
- def initialize(options = nil)
12
- super(options)
13
- extend Strategy::LocalCache
14
- end
11
+ prepend Strategy::LocalCache
15
12
 
16
13
  def clear(options = nil)
17
14
  end
@@ -39,7 +39,7 @@ module ActiveSupport
39
39
  @data = {}
40
40
  end
41
41
 
42
- # Don't allow synchronizing since it isn't thread safe,
42
+ # Don't allow synchronizing since it isn't thread safe.
43
43
  def synchronize # :nodoc:
44
44
  yield
45
45
  end
@@ -60,6 +60,10 @@ module ActiveSupport
60
60
  def delete_entry(key, options)
61
61
  !!@data.delete(key)
62
62
  end
63
+
64
+ def fetch_entry(key, options = nil) # :nodoc:
65
+ @data.fetch(key) { @data[key] = yield }
66
+ end
63
67
  end
64
68
 
65
69
  # Use a local cache for the duration of block.
@@ -75,36 +79,35 @@ module ActiveSupport
75
79
  end
76
80
 
77
81
  def clear(options = nil) # :nodoc:
78
- local_cache.clear(options) if local_cache
82
+ return super unless cache = local_cache
83
+ cache.clear(options)
79
84
  super
80
85
  end
81
86
 
82
87
  def cleanup(options = nil) # :nodoc:
83
- local_cache.clear(options) if local_cache
88
+ return super unless cache = local_cache
89
+ cache.clear(options)
84
90
  super
85
91
  end
86
92
 
87
93
  def increment(name, amount = 1, options = nil) # :nodoc:
94
+ return super unless local_cache
88
95
  value = bypass_local_cache{super}
89
- set_cache_value(value, name, amount, options)
96
+ write_cache_value(name, value, options)
90
97
  value
91
98
  end
92
99
 
93
100
  def decrement(name, amount = 1, options = nil) # :nodoc:
101
+ return super unless local_cache
94
102
  value = bypass_local_cache{super}
95
- set_cache_value(value, name, amount, options)
103
+ write_cache_value(name, value, options)
96
104
  value
97
105
  end
98
106
 
99
107
  protected
100
108
  def read_entry(key, options) # :nodoc:
101
- if local_cache
102
- entry = local_cache.read_entry(key, options)
103
- unless entry
104
- entry = super
105
- local_cache.write_entry(key, entry, options)
106
- end
107
- entry
109
+ if cache = local_cache
110
+ cache.fetch_entry(key) { super }
108
111
  else
109
112
  super
110
113
  end
@@ -120,14 +123,22 @@ module ActiveSupport
120
123
  super
121
124
  end
122
125
 
123
- def set_cache_value(value, name, amount, options)
124
- if local_cache
125
- local_cache.mute do
126
- if value
127
- local_cache.write(name, value, options)
128
- else
129
- local_cache.delete(name, options)
130
- end
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)
131
142
  end
132
143
  end
133
144
  end