activesupport 4.2.11.3 → 5.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 (174) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +309 -485
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -3
  5. data/lib/active_support.rb +8 -15
  6. data/lib/active_support/array_inquirer.rb +44 -0
  7. data/lib/active_support/backtrace_cleaner.rb +1 -1
  8. data/lib/active_support/cache.rb +59 -72
  9. data/lib/active_support/cache/file_store.rb +27 -19
  10. data/lib/active_support/cache/mem_cache_store.rb +71 -60
  11. data/lib/active_support/cache/memory_store.rb +16 -21
  12. data/lib/active_support/cache/null_store.rb +1 -4
  13. data/lib/active_support/cache/strategy/local_cache.rb +31 -20
  14. data/lib/active_support/callbacks.rb +107 -111
  15. data/lib/active_support/concern.rb +1 -1
  16. data/lib/active_support/concurrency/latch.rb +7 -15
  17. data/lib/active_support/concurrency/share_lock.rb +142 -0
  18. data/lib/active_support/configurable.rb +1 -0
  19. data/lib/active_support/core_ext.rb +2 -1
  20. data/lib/active_support/core_ext/array.rb +1 -0
  21. data/lib/active_support/core_ext/array/access.rb +13 -1
  22. data/lib/active_support/core_ext/array/conversions.rb +6 -4
  23. data/lib/active_support/core_ext/array/inquiry.rb +17 -0
  24. data/lib/active_support/core_ext/array/wrap.rb +5 -4
  25. data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -10
  26. data/lib/active_support/core_ext/class.rb +0 -1
  27. data/lib/active_support/core_ext/class/attribute.rb +10 -9
  28. data/lib/active_support/core_ext/class/subclasses.rb +5 -2
  29. data/lib/active_support/core_ext/date.rb +1 -1
  30. data/lib/active_support/core_ext/date/blank.rb +12 -0
  31. data/lib/active_support/core_ext/date/calculations.rb +1 -1
  32. data/lib/active_support/core_ext/date/conversions.rb +3 -3
  33. data/lib/active_support/core_ext/date_and_time/calculations.rb +93 -27
  34. data/lib/active_support/core_ext/date_and_time/zones.rb +1 -2
  35. data/lib/active_support/core_ext/date_time.rb +1 -1
  36. data/lib/active_support/core_ext/date_time/blank.rb +12 -0
  37. data/lib/active_support/core_ext/date_time/calculations.rb +7 -23
  38. data/lib/active_support/core_ext/date_time/conversions.rb +2 -0
  39. data/lib/active_support/core_ext/enumerable.rb +27 -17
  40. data/lib/active_support/core_ext/file/atomic.rb +30 -25
  41. data/lib/active_support/core_ext/hash/compact.rb +15 -19
  42. data/lib/active_support/core_ext/hash/conversions.rb +21 -2
  43. data/lib/active_support/core_ext/hash/deep_merge.rb +1 -1
  44. data/lib/active_support/core_ext/hash/except.rb +9 -8
  45. data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -1
  46. data/lib/active_support/core_ext/hash/keys.rb +22 -18
  47. data/lib/active_support/core_ext/hash/slice.rb +1 -1
  48. data/lib/active_support/core_ext/hash/transform_values.rb +13 -7
  49. data/lib/active_support/core_ext/integer/time.rb +1 -1
  50. data/lib/active_support/core_ext/kernel.rb +0 -1
  51. data/lib/active_support/core_ext/kernel/debugger.rb +3 -10
  52. data/lib/active_support/core_ext/kernel/reporting.rb +0 -84
  53. data/lib/active_support/core_ext/load_error.rb +4 -2
  54. data/lib/active_support/core_ext/marshal.rb +8 -13
  55. data/lib/active_support/core_ext/module.rb +1 -0
  56. data/lib/active_support/core_ext/module/aliasing.rb +6 -1
  57. data/lib/active_support/core_ext/module/anonymous.rb +10 -1
  58. data/lib/active_support/core_ext/module/attr_internal.rb +2 -5
  59. data/lib/active_support/core_ext/module/attribute_accessors.rb +7 -7
  60. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
  61. data/lib/active_support/core_ext/module/concerning.rb +4 -4
  62. data/lib/active_support/core_ext/module/delegation.rb +7 -14
  63. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -13
  64. data/lib/active_support/core_ext/module/qualified_const.rb +30 -12
  65. data/lib/active_support/core_ext/module/remove_method.rb +23 -0
  66. data/lib/active_support/core_ext/name_error.rb +15 -2
  67. data/lib/active_support/core_ext/numeric.rb +1 -0
  68. data/lib/active_support/core_ext/numeric/bytes.rb +20 -0
  69. data/lib/active_support/core_ext/numeric/conversions.rb +12 -23
  70. data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
  71. data/lib/active_support/core_ext/numeric/time.rb +20 -0
  72. data/lib/active_support/core_ext/object.rb +0 -1
  73. data/lib/active_support/core_ext/object/blank.rb +11 -2
  74. data/lib/active_support/core_ext/object/deep_dup.rb +10 -3
  75. data/lib/active_support/core_ext/object/duplicable.rb +39 -70
  76. data/lib/active_support/core_ext/object/inclusion.rb +2 -2
  77. data/lib/active_support/core_ext/object/instance_variables.rb +1 -1
  78. data/lib/active_support/core_ext/object/json.rb +9 -7
  79. data/lib/active_support/core_ext/object/to_query.rb +1 -1
  80. data/lib/active_support/core_ext/object/try.rb +67 -21
  81. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  82. data/lib/active_support/core_ext/range/conversions.rb +18 -6
  83. data/lib/active_support/core_ext/range/each.rb +16 -18
  84. data/lib/active_support/core_ext/range/include_range.rb +20 -20
  85. data/lib/active_support/core_ext/securerandom.rb +23 -0
  86. data/lib/active_support/core_ext/string/access.rb +1 -1
  87. data/lib/active_support/core_ext/string/behavior.rb +1 -1
  88. data/lib/active_support/core_ext/string/conversions.rb +2 -2
  89. data/lib/active_support/core_ext/string/filters.rb +1 -2
  90. data/lib/active_support/core_ext/string/inflections.rb +23 -5
  91. data/lib/active_support/core_ext/string/multibyte.rb +11 -7
  92. data/lib/active_support/core_ext/string/output_safety.rb +8 -9
  93. data/lib/active_support/core_ext/string/strip.rb +3 -6
  94. data/lib/active_support/core_ext/struct.rb +3 -6
  95. data/lib/active_support/core_ext/time.rb +0 -2
  96. data/lib/active_support/core_ext/time/calculations.rb +18 -16
  97. data/lib/active_support/core_ext/time/conversions.rb +4 -2
  98. data/lib/active_support/core_ext/time/marshal.rb +2 -29
  99. data/lib/active_support/core_ext/time/zones.rb +19 -3
  100. data/lib/active_support/core_ext/uri.rb +1 -3
  101. data/lib/active_support/dependencies.rb +79 -44
  102. data/lib/active_support/dependencies/interlock.rb +47 -0
  103. data/lib/active_support/deprecation/behaviors.rb +12 -0
  104. data/lib/active_support/deprecation/method_wrappers.rb +42 -16
  105. data/lib/active_support/deprecation/proxy_wrappers.rb +47 -24
  106. data/lib/active_support/deprecation/reporting.rb +13 -2
  107. data/lib/active_support/duration.rb +5 -8
  108. data/lib/active_support/evented_file_update_checker.rb +150 -0
  109. data/lib/active_support/file_update_checker.rb +1 -1
  110. data/lib/active_support/gem_version.rb +5 -5
  111. data/lib/active_support/hash_with_indifferent_access.rb +15 -17
  112. data/lib/active_support/i18n_railtie.rb +25 -4
  113. data/lib/active_support/inflector/inflections.rb +36 -5
  114. data/lib/active_support/inflector/methods.rb +87 -89
  115. data/lib/active_support/inflector/transliterate.rb +36 -21
  116. data/lib/active_support/json/decoding.rb +2 -8
  117. data/lib/active_support/json/encoding.rb +0 -50
  118. data/lib/active_support/key_generator.rb +4 -4
  119. data/lib/active_support/log_subscriber.rb +1 -1
  120. data/lib/active_support/log_subscriber/test_helper.rb +3 -3
  121. data/lib/active_support/logger.rb +4 -52
  122. data/lib/active_support/logger_silence.rb +3 -5
  123. data/lib/active_support/message_encryptor.rb +4 -11
  124. data/lib/active_support/message_verifier.rb +64 -8
  125. data/lib/active_support/multibyte/chars.rb +12 -3
  126. data/lib/active_support/multibyte/unicode.rb +6 -8
  127. data/lib/active_support/notifications.rb +2 -2
  128. data/lib/active_support/notifications/fanout.rb +5 -5
  129. data/lib/active_support/notifications/instrumenter.rb +19 -2
  130. data/lib/active_support/number_helper.rb +21 -15
  131. data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -4
  132. data/lib/active_support/number_helper/number_to_delimited_converter.rb +7 -2
  133. data/lib/active_support/number_helper/number_to_human_converter.rb +6 -4
  134. data/lib/active_support/number_helper/number_to_human_size_converter.rb +5 -1
  135. data/lib/active_support/number_helper/number_to_percentage_converter.rb +1 -1
  136. data/lib/active_support/number_helper/number_to_rounded_converter.rb +28 -25
  137. data/lib/active_support/ordered_options.rb +15 -1
  138. data/lib/active_support/per_thread_registry.rb +3 -0
  139. data/lib/active_support/rails.rb +2 -2
  140. data/lib/active_support/railtie.rb +6 -1
  141. data/lib/active_support/rescuable.rb +4 -4
  142. data/lib/active_support/security_utils.rb +0 -7
  143. data/lib/active_support/string_inquirer.rb +1 -1
  144. data/lib/active_support/subscriber.rb +5 -10
  145. data/lib/active_support/tagged_logging.rb +3 -1
  146. data/lib/active_support/test_case.rb +13 -25
  147. data/lib/active_support/testing/assertions.rb +15 -13
  148. data/lib/active_support/testing/autorun.rb +8 -1
  149. data/lib/active_support/testing/composite_filter.rb +54 -0
  150. data/lib/active_support/testing/deprecation.rb +9 -8
  151. data/lib/active_support/testing/file_fixtures.rb +34 -0
  152. data/lib/active_support/testing/isolation.rb +22 -8
  153. data/lib/active_support/testing/method_call_assertions.rb +41 -0
  154. data/lib/active_support/testing/stream.rb +42 -0
  155. data/lib/active_support/testing/time_helpers.rb +6 -6
  156. data/lib/active_support/time_with_zone.rb +135 -53
  157. data/lib/active_support/values/time_zone.rb +80 -46
  158. data/lib/active_support/values/unicode_tables.dat +0 -0
  159. data/lib/active_support/xml_mini.rb +15 -30
  160. data/lib/active_support/xml_mini/jdom.rb +1 -1
  161. data/lib/active_support/xml_mini/libxml.rb +5 -3
  162. data/lib/active_support/xml_mini/libxmlsax.rb +4 -1
  163. data/lib/active_support/xml_mini/nokogiri.rb +5 -3
  164. data/lib/active_support/xml_mini/nokogirisax.rb +3 -1
  165. data/lib/active_support/xml_mini/rexml.rb +3 -1
  166. metadata +57 -21
  167. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
  168. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  169. data/lib/active_support/core_ext/date_and_time/compatibility.rb +0 -15
  170. data/lib/active_support/core_ext/date_time/compatibility.rb +0 -16
  171. data/lib/active_support/core_ext/object/itself.rb +0 -15
  172. data/lib/active_support/core_ext/thread.rb +0 -86
  173. data/lib/active_support/core_ext/time/compatibility.rb +0 -14
  174. data/lib/active_support/logger_thread_safe_level.rb +0 -32
@@ -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,14 +95,17 @@ 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]}]
70
- raw_values = @data.get_multi(keys_to_names.keys)
71
- values = {}
72
- raw_values.each do |key, value|
73
- entry = deserialize_entry(value)
74
- values[keys_to_names[key]] = entry.value unless entry.expired?
98
+
99
+ instrument_multi(:read, names, options) do
100
+ keys_to_names = Hash[names.map{|name| [normalize_key(name, options), name]}]
101
+ raw_values = @data.get_multi(keys_to_names.keys, :raw => true)
102
+ values = {}
103
+ raw_values.each do |key, value|
104
+ entry = deserialize_entry(value)
105
+ values[keys_to_names[key]] = entry.value unless entry.expired?
106
+ end
107
+ values
75
108
  end
76
- values
77
109
  end
78
110
 
79
111
  # Increment a cached value. This method uses the memcached incr atomic
@@ -83,11 +115,10 @@ module ActiveSupport
83
115
  def increment(name, amount = 1, options = nil) # :nodoc:
84
116
  options = merged_options(options)
85
117
  instrument(:increment, name, :amount => amount) do
86
- @data.incr(escape_key(namespaced_key(name, options)), amount)
118
+ rescue_error_with nil do
119
+ @data.incr(normalize_key(name, options), amount)
120
+ end
87
121
  end
88
- rescue Dalli::DalliError => e
89
- logger.error("DalliError (#{e}): #{e.message}") if logger
90
- nil
91
122
  end
92
123
 
93
124
  # Decrement a cached value. This method uses the memcached decr atomic
@@ -97,20 +128,16 @@ module ActiveSupport
97
128
  def decrement(name, amount = 1, options = nil) # :nodoc:
98
129
  options = merged_options(options)
99
130
  instrument(:decrement, name, :amount => amount) do
100
- @data.decr(escape_key(namespaced_key(name, options)), amount)
131
+ rescue_error_with nil do
132
+ @data.decr(normalize_key(name, options), amount)
133
+ end
101
134
  end
102
- rescue Dalli::DalliError => e
103
- logger.error("DalliError (#{e}): #{e.message}") if logger
104
- nil
105
135
  end
106
136
 
107
137
  # Clear the entire cache on all memcached servers. This method should
108
138
  # be used with care when shared cache is being used.
109
139
  def clear(options = nil)
110
- @data.flush_all
111
- rescue Dalli::DalliError => e
112
- logger.error("DalliError (#{e}): #{e.message}") if logger
113
- nil
140
+ rescue_error_with(nil) { @data.flush_all }
114
141
  end
115
142
 
116
143
  # Get the statistics from the memcached servers.
@@ -121,10 +148,7 @@ module ActiveSupport
121
148
  protected
122
149
  # Read an entry from the cache.
123
150
  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
151
+ rescue_error_with(nil) { deserialize_entry(@data.get(key, options)) }
128
152
  end
129
153
 
130
154
  # Write an entry to the cache.
@@ -136,18 +160,14 @@ module ActiveSupport
136
160
  # Set the memcache expire a few minutes in the future to support race condition ttls on read
137
161
  expires_in += 5.minutes
138
162
  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
163
+ rescue_error_with false do
164
+ @data.send(method, key, value, expires_in, options)
165
+ end
143
166
  end
144
167
 
145
168
  # Delete an entry from the cache.
146
169
  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
170
+ rescue_error_with(false) { @data.delete(key) }
151
171
  end
152
172
 
153
173
  private
@@ -155,44 +175,35 @@ module ActiveSupport
155
175
  # Memcache keys are binaries. So we need to force their encoding to binary
156
176
  # before applying the regular expression to ensure we are escaping all
157
177
  # characters properly.
158
- def escape_key(key)
159
- key = key.to_s.dup
178
+ def normalize_key(key, options)
179
+ key = super.dup
160
180
  key = key.force_encoding(Encoding::ASCII_8BIT)
161
181
  key = key.gsub(ESCAPE_KEY_CHARS){ |match| "%#{match.getbyte(0).to_s(16).upcase}" }
162
182
  key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250
163
183
  key
164
184
  end
165
185
 
186
+ def escape_key(key)
187
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
188
+ `escape_key` is deprecated and will be removed from Rails 5.1.
189
+ Please use `normalize_key` which will return a fully resolved key or nothing.
190
+ MESSAGE
191
+ key
192
+ end
193
+
166
194
  def deserialize_entry(raw_value)
167
195
  if raw_value
168
196
  entry = Marshal.load(raw_value) rescue raw_value
169
197
  entry.is_a?(Entry) ? entry : Entry.new(entry)
170
- else
171
- nil
172
198
  end
173
199
  end
174
200
 
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
201
+ def rescue_error_with(fallback)
202
+ yield
203
+ rescue Dalli::DalliError => e
204
+ logger.error("DalliError (#{e}): #{e.message}") if logger
205
+ fallback
206
+ end
196
207
  end
197
208
  end
198
209
  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`
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
@@ -4,6 +4,9 @@ require 'active_support/core_ext/array/extract_options'
4
4
  require 'active_support/core_ext/class/attribute'
5
5
  require 'active_support/core_ext/kernel/reporting'
6
6
  require 'active_support/core_ext/kernel/singleton_class'
7
+ require 'active_support/core_ext/module/attribute_accessors'
8
+ require 'active_support/core_ext/string/filters'
9
+ require 'active_support/deprecation'
7
10
  require 'thread'
8
11
 
9
12
  module ActiveSupport
@@ -64,6 +67,12 @@ module ActiveSupport
64
67
 
65
68
  CALLBACK_FILTER_TYPES = [:before, :after, :around]
66
69
 
70
+ # If true, Active Record and Active Model callbacks returning +false+ will
71
+ # halt the entire callback chain and display a deprecation message.
72
+ # If false, callback chains will only be halted by calling +throw :abort+.
73
+ # Defaults to +true+.
74
+ mattr_accessor(:halt_and_display_warning_on_return_false) { true }
75
+
67
76
  # Runs the callbacks for the given event.
68
77
  #
69
78
  # Calls the before and around callbacks in the order they were set, yields
@@ -124,14 +133,10 @@ module ActiveSupport
124
133
  def self.build(callback_sequence, user_callback, user_conditions, chain_config, filter)
125
134
  halted_lambda = chain_config[:terminator]
126
135
 
127
- if chain_config.key?(:terminator) && user_conditions.any?
136
+ if user_conditions.any?
128
137
  halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter)
129
- elsif chain_config.key? :terminator
130
- halting(callback_sequence, user_callback, halted_lambda, filter)
131
- elsif user_conditions.any?
132
- conditional(callback_sequence, user_callback, user_conditions)
133
138
  else
134
- simple callback_sequence, user_callback
139
+ halting(callback_sequence, user_callback, halted_lambda, filter)
135
140
  end
136
141
  end
137
142
 
@@ -142,8 +147,8 @@ module ActiveSupport
142
147
  halted = env.halted
143
148
 
144
149
  if !halted && user_conditions.all? { |c| c.call(target, value) }
145
- result = user_callback.call target, value
146
- env.halted = halted_lambda.call(target, result)
150
+ result_lambda = -> { user_callback.call target, value }
151
+ env.halted = halted_lambda.call(target, result_lambda)
147
152
  if env.halted
148
153
  target.send :halted_callback_hook, filter
149
154
  end
@@ -161,8 +166,9 @@ module ActiveSupport
161
166
  halted = env.halted
162
167
 
163
168
  unless halted
164
- result = user_callback.call target, value
165
- env.halted = halted_lambda.call(target, result)
169
+ result_lambda = -> { user_callback.call target, value }
170
+ env.halted = halted_lambda.call(target, result_lambda)
171
+
166
172
  if env.halted
167
173
  target.send :halted_callback_hook, filter
168
174
  end
@@ -172,42 +178,15 @@ module ActiveSupport
172
178
  end
173
179
  end
174
180
  private_class_method :halting
175
-
176
- def self.conditional(callback_sequence, user_callback, user_conditions)
177
- callback_sequence.before do |env|
178
- target = env.target
179
- value = env.value
180
-
181
- if user_conditions.all? { |c| c.call(target, value) }
182
- user_callback.call target, value
183
- end
184
-
185
- env
186
- end
187
- end
188
- private_class_method :conditional
189
-
190
- def self.simple(callback_sequence, user_callback)
191
- callback_sequence.before do |env|
192
- user_callback.call env.target, env.value
193
-
194
- env
195
- end
196
- end
197
- private_class_method :simple
198
181
  end
199
182
 
200
183
  class After
201
184
  def self.build(callback_sequence, user_callback, user_conditions, chain_config)
202
185
  if chain_config[:skip_after_callbacks_if_terminated]
203
- if chain_config.key?(:terminator) && user_conditions.any?
186
+ if user_conditions.any?
204
187
  halting_and_conditional(callback_sequence, user_callback, user_conditions)
205
- elsif chain_config.key?(:terminator)
206
- halting(callback_sequence, user_callback)
207
- elsif user_conditions.any?
208
- conditional callback_sequence, user_callback, user_conditions
209
188
  else
210
- simple callback_sequence, user_callback
189
+ halting(callback_sequence, user_callback)
211
190
  end
212
191
  else
213
192
  if user_conditions.any?
@@ -270,14 +249,10 @@ module ActiveSupport
270
249
 
271
250
  class Around
272
251
  def self.build(callback_sequence, user_callback, user_conditions, chain_config)
273
- if chain_config.key?(:terminator) && user_conditions.any?
252
+ if user_conditions.any?
274
253
  halting_and_conditional(callback_sequence, user_callback, user_conditions)
275
- elsif chain_config.key? :terminator
276
- halting(callback_sequence, user_callback)
277
- elsif user_conditions.any?
278
- conditional(callback_sequence, user_callback, user_conditions)
279
254
  else
280
- simple(callback_sequence, user_callback)
255
+ halting(callback_sequence, user_callback)
281
256
  end
282
257
  end
283
258
 
@@ -289,13 +264,11 @@ module ActiveSupport
289
264
 
290
265
  if !halted && user_conditions.all? { |c| c.call(target, value) }
291
266
  user_callback.call(target, value) {
292
- env = run.call env
293
- env.value
267
+ run.call.value
294
268
  }
295
-
296
269
  env
297
270
  else
298
- run.call env
271
+ run.call
299
272
  end
300
273
  end
301
274
  end
@@ -307,51 +280,28 @@ module ActiveSupport
307
280
  value = env.value
308
281
 
309
282
  if env.halted
310
- run.call env
283
+ run.call
311
284
  else
312
285
  user_callback.call(target, value) {
313
- env = run.call env
314
- env.value
286
+ run.call.value
315
287
  }
316
288
  env
317
289
  end
318
290
  end
319
291
  end
320
292
  private_class_method :halting
321
-
322
- def self.conditional(callback_sequence, user_callback, user_conditions)
323
- callback_sequence.around do |env, &run|
324
- target = env.target
325
- value = env.value
326
-
327
- if user_conditions.all? { |c| c.call(target, value) }
328
- user_callback.call(target, value) {
329
- env = run.call env
330
- env.value
331
- }
332
- env
333
- else
334
- run.call env
335
- end
336
- end
337
- end
338
- private_class_method :conditional
339
-
340
- def self.simple(callback_sequence, user_callback)
341
- callback_sequence.around do |env, &run|
342
- user_callback.call(env.target, env.value) {
343
- env = run.call env
344
- env.value
345
- }
346
- env
347
- end
348
- end
349
- private_class_method :simple
350
293
  end
351
294
  end
352
295
 
353
296
  class Callback #:nodoc:#
354
297
  def self.build(chain, filter, kind, options)
298
+ if filter.is_a?(String)
299
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
300
+ Passing string to define callback is deprecated and will be removed
301
+ in Rails 5.1 without replacement.
302
+ MSG
303
+ end
304
+
355
305
  new chain.name, filter, kind, options, chain.config
356
306
  end
357
307
 
@@ -371,14 +321,14 @@ module ActiveSupport
371
321
  def filter; @key; end
372
322
  def raw_filter; @filter; end
373
323
 
374
- def merge(chain, new_options)
324
+ def merge_conditional_options(chain, if_option:, unless_option:)
375
325
  options = {
376
326
  :if => @if.dup,
377
327
  :unless => @unless.dup
378
328
  }
379
329
 
380
- options[:if].concat Array(new_options.fetch(:unless, []))
381
- options[:unless].concat Array(new_options.fetch(:if, []))
330
+ options[:if].concat Array(unless_option)
331
+ options[:unless].concat Array(if_option)
382
332
 
383
333
  self.class.build chain, @filter, @kind, options
384
334
  end
@@ -493,17 +443,17 @@ module ActiveSupport
493
443
  end
494
444
 
495
445
  def around(&around)
496
- CallbackSequence.new do |*args|
497
- around.call(*args) {
498
- self.call(*args)
446
+ CallbackSequence.new do |arg|
447
+ around.call(arg) {
448
+ self.call(arg)
499
449
  }
500
450
  end
501
451
  end
502
452
 
503
- def call(*args)
504
- @before.each { |b| b.call(*args) }
505
- value = @call.call(*args)
506
- @after.each { |a| a.call(*args) }
453
+ def call(arg)
454
+ @before.each { |b| b.call(arg) }
455
+ value = @call.call(arg)
456
+ @after.each { |a| a.call(arg) }
507
457
  value
508
458
  end
509
459
  end
@@ -517,7 +467,8 @@ module ActiveSupport
517
467
  def initialize(name, config)
518
468
  @name = name
519
469
  @config = {
520
- :scope => [ :kind ]
470
+ scope: [:kind],
471
+ terminator: default_terminator
521
472
  }.merge!(config)
522
473
  @chain = []
523
474
  @callbacks = nil
@@ -588,6 +539,17 @@ module ActiveSupport
588
539
  @callbacks = nil
589
540
  @chain.delete_if { |c| callback.duplicates?(c) }
590
541
  end
542
+
543
+ def default_terminator
544
+ Proc.new do |target, result_lambda|
545
+ terminate = true
546
+ catch(:abort) do
547
+ result_lambda.call if result_lambda.is_a?(Proc)
548
+ terminate = false
549
+ end
550
+ terminate
551
+ end
552
+ end
591
553
  end
592
554
 
593
555
  module ClassMethods
@@ -613,14 +575,14 @@ module ActiveSupport
613
575
  # set_callback :save, :after, :after_meth, if: :condition
614
576
  # set_callback :save, :around, ->(r, block) { stuff; result = block.call; stuff }
615
577
  #
616
- # The second arguments indicates whether the callback is to be run +:before+,
578
+ # The second argument indicates whether the callback is to be run +:before+,
617
579
  # +:after+, or +:around+ the event. If omitted, +:before+ is assumed. This
618
580
  # means the first example above can also be written as:
619
581
  #
620
582
  # set_callback :save, :before_meth
621
583
  #
622
584
  # The callback can be specified as a symbol naming an instance method; as a
623
- # proc, lambda, or block; as a string to be instance evaluated; or as an
585
+ # proc, lambda, or block; as a string to be instance evaluated(deprecated); or as an
624
586
  # object that responds to a certain method determined by the <tt>:scope</tt>
625
587
  # argument to +define_callbacks+.
626
588
  #
@@ -664,19 +626,27 @@ module ActiveSupport
664
626
  # class Writer < Person
665
627
  # skip_callback :validate, :before, :check_membership, if: -> { self.age > 18 }
666
628
  # end
629
+ #
630
+ # An <tt>ArgumentError</tt> will be raised if the callback has not
631
+ # already been set (unless the <tt>:raise</tt> option is set to <tt>false</tt>).
667
632
  def skip_callback(name, *filter_list, &block)
668
633
  type, filters, options = normalize_callback_params(filter_list, block)
634
+ options[:raise] = true unless options.key?(:raise)
669
635
 
670
636
  __update_callbacks(name) do |target, chain|
671
637
  filters.each do |filter|
672
- filter = chain.find {|c| c.matches?(type, filter) }
638
+ callback = chain.find {|c| c.matches?(type, filter) }
639
+
640
+ if !callback && options[:raise]
641
+ raise ArgumentError, "#{type.to_s.capitalize} #{name} callback #{filter.inspect} has not been defined"
642
+ end
673
643
 
674
- if filter && options.any?
675
- new_filter = filter.merge(chain, options)
676
- chain.insert(chain.index(filter), new_filter)
644
+ if callback && (options.key?(:if) || options.key?(:unless))
645
+ new_callback = callback.merge_conditional_options(chain, if_option: options[:if], unless_option: options[:unless])
646
+ chain.insert(chain.index(callback), new_callback)
677
647
  end
678
648
 
679
- chain.delete(filter)
649
+ chain.delete(callback)
680
650
  end
681
651
  target.set_callbacks name, chain
682
652
  end
@@ -703,21 +673,23 @@ module ActiveSupport
703
673
  # ===== Options
704
674
  #
705
675
  # * <tt>:terminator</tt> - Determines when a before filter will halt the
706
- # callback chain, preventing following callbacks from being called and
707
- # the event from being triggered. This should be a lambda to be executed.
708
- # The current object and the return result of the callback will be called
709
- # with the lambda.
676
+ # callback chain, preventing following before and around callbacks from
677
+ # being called and the event from being triggered.
678
+ # This should be a lambda to be executed.
679
+ # The current object and the result lambda of the callback will be provided
680
+ # to the terminator lambda.
710
681
  #
711
- # define_callbacks :validate, terminator: ->(target, result) { result == false }
682
+ # define_callbacks :validate, terminator: ->(target, result_lambda) { result_lambda.call == false }
712
683
  #
713
684
  # In this example, if any before validate callbacks returns +false+,
714
- # other callbacks are not executed. Defaults to +false+, meaning no value
715
- # halts the chain.
685
+ # any successive before and around callback is not executed.
686
+ #
687
+ # The default terminator halts the chain when a callback throws +:abort+.
716
688
  #
717
689
  # * <tt>:skip_after_callbacks_if_terminated</tt> - Determines if after
718
690
  # callbacks should be terminated by the <tt>:terminator</tt> option. By
719
- # default after callbacks executed no matter if callback chain was
720
- # terminated or not. Option makes sense only when <tt>:terminator</tt>
691
+ # default after callbacks are executed no matter if callback chain was
692
+ # terminated or not. This option makes sense only when <tt>:terminator</tt>
721
693
  # option is specified.
722
694
  #
723
695
  # * <tt>:scope</tt> - Indicates which methods should be executed when an
@@ -770,7 +742,7 @@ module ActiveSupport
770
742
  options = names.extract_options!
771
743
 
772
744
  names.each do |name|
773
- class_attribute "_#{name}_callbacks", instance_writer: false
745
+ class_attribute "_#{name}_callbacks"
774
746
  set_callbacks name, CallbackChain.new(name, options)
775
747
 
776
748
  module_eval <<-RUBY, __FILE__, __LINE__ + 1
@@ -783,13 +755,37 @@ module ActiveSupport
783
755
 
784
756
  protected
785
757
 
786
- def get_callbacks(name)
758
+ def get_callbacks(name) # :nodoc:
787
759
  send "_#{name}_callbacks"
788
760
  end
789
761
 
790
- def set_callbacks(name, callbacks)
762
+ def set_callbacks(name, callbacks) # :nodoc:
791
763
  send "_#{name}_callbacks=", callbacks
792
764
  end
765
+
766
+ def deprecated_false_terminator # :nodoc:
767
+ Proc.new do |target, result_lambda|
768
+ terminate = true
769
+ catch(:abort) do
770
+ result = result_lambda.call if result_lambda.is_a?(Proc)
771
+ if Callbacks.halt_and_display_warning_on_return_false && result == false
772
+ display_deprecation_warning_for_false_terminator
773
+ else
774
+ terminate = false
775
+ end
776
+ end
777
+ terminate
778
+ end
779
+ end
780
+
781
+ private
782
+
783
+ def display_deprecation_warning_for_false_terminator
784
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
785
+ Returning `false` in Active Record and Active Model callbacks will not implicitly halt a callback chain in the next release of Rails.
786
+ To explicitly halt the callback chain, please use `throw :abort` instead.
787
+ MSG
788
+ end
793
789
  end
794
790
  end
795
791
  end