activesupport 5.0.0.beta1.1 → 5.0.0.beta2

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 (32) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +79 -45
  3. data/MIT-LICENSE +2 -2
  4. data/lib/active_support.rb +1 -1
  5. data/lib/active_support/cache.rb +13 -12
  6. data/lib/active_support/cache/file_store.rb +9 -3
  7. data/lib/active_support/concurrency/share_lock.rb +37 -19
  8. data/lib/active_support/core_ext/hash/conversions.rb +2 -0
  9. data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -6
  10. data/lib/active_support/core_ext/module/deprecation.rb +2 -2
  11. data/lib/active_support/core_ext/numeric/conversions.rb +8 -1
  12. data/lib/active_support/core_ext/string/output_safety.rb +3 -4
  13. data/lib/active_support/core_ext/time/zones.rb +17 -1
  14. data/lib/active_support/dependencies/interlock.rb +3 -3
  15. data/lib/active_support/deprecation.rb +1 -1
  16. data/lib/active_support/deprecation/behaviors.rb +2 -0
  17. data/lib/active_support/deprecation/method_wrappers.rb +3 -3
  18. data/lib/active_support/gem_version.rb +1 -1
  19. data/lib/active_support/hash_with_indifferent_access.rb +18 -6
  20. data/lib/active_support/inflector/methods.rb +1 -1
  21. data/lib/active_support/locale/en.yml +2 -0
  22. data/lib/active_support/logger.rb +26 -4
  23. data/lib/active_support/logger_silence.rb +23 -3
  24. data/lib/active_support/multibyte/unicode.rb +38 -13
  25. data/lib/active_support/notifications/instrumenter.rb +1 -0
  26. data/lib/active_support/number_helper.rb +10 -0
  27. data/lib/active_support/number_helper/number_to_currency_converter.rb +3 -5
  28. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  29. data/lib/active_support/ordered_hash.rb +1 -1
  30. data/lib/active_support/test_case.rb +0 -10
  31. metadata +4 -4
  32. data/lib/active_support/testing/composite_filter.rb +0 -54
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 024273a23d7e6cc96b22a85a01b06381086fc6e4
4
- data.tar.gz: 37c109760b68500ed51cdef73f9f2c4133a724ca
3
+ metadata.gz: feeceb08e3de4f23beb469414fac32aa949de4ca
4
+ data.tar.gz: ed224db38f3a6524c78cd4833484eb93d4a4cc4f
5
5
  SHA512:
6
- metadata.gz: 1780db97c7a6fb5717de6f6de150f554029e8c0b98d7edd7713e104b0653202dff412762234c9a5417aec82fa8c38732ef4ef94309148655b6691d12dd284d76
7
- data.tar.gz: 1b9086c031e6092441900dc315d93292159cfb7a6f3aafb8201363ca4b75fddcbd184fd1550fda107f8159830ad321374e221e6d6627421d2e0e47c2940c3057
6
+ metadata.gz: 2714c0f5258a1d8678f750cf4ec835f033db1a999652e439f958b5077d1b10bbec05323366393b2b7db06bcc049f01a4111e2a7aa8a82f7dd236523254bb586d
7
+ data.tar.gz: 5dca3370c49f9d30af666064201f536cec39a49c2864fb3ccbaf56a1ab9c42fe0de7e6baca81b669873ed41471367a83271d338ccb8ace0f29aae812a051a4b4
@@ -1,7 +1,41 @@
1
- ## Rails 5.0.0.beta1 (December 18, 2015) ##
1
+ ## Rails 5.0.0.beta2 (February 01, 2016) ##
2
+
3
+ * Change number_to_currency behavior for checking negativity.
4
+
5
+ Used `to_f.negative` instead of using `to_f.phase` for checking negativity
6
+ of a number in number_to_currency helper.
7
+ This change works same for all cases except when number is "-0.0".
8
+
9
+ -0.0.to_f.negative? => false
10
+ -0.0.to_f.phase? => 3.14
11
+
12
+ This change reverts changes from https://github.com/rails/rails/pull/6512.
13
+ But it should be acceptable as we could not find any currency which
14
+ supports negative zeros.
15
+
16
+ *Prathamesh Sonpatki*, *Rafael Mendonça França*
17
+
18
+ * Match `HashWithIndifferentAccess#default`'s behaviour with `Hash#default`.
19
+
20
+ *David Cornu*
21
+
22
+ * Adds `:exception_object` key to `ActiveSupport::Notifications::Instrumenter`
23
+ payload when an exception is raised.
24
+
25
+ Adds new key/value pair to payload when an exception is raised:
26
+ e.g. `:exception_object => #<RuntimeError: FAIL>`.
27
+
28
+ *Ryan T. Hosford*
29
+
30
+ * Support extended grapheme clusters and UAX 29.
31
+
32
+ *Adam Roben*
33
+
34
+ * Add petabyte and exabyte numeric conversion.
2
35
 
3
- * No changes.
36
+ *Akshay Vishnoi*
4
37
 
38
+ ## Rails 5.0.0.beta1 (December 18, 2015) ##
5
39
 
6
40
  * Add thread_m/cattr_accessor/reader/writer suite of methods for declaring class and module variables that live per-thread.
7
41
  This makes it easy to declare per-thread globals that are encapsulated. Note: This is a sharp edge. A wild proliferation
@@ -10,44 +44,44 @@
10
44
  Here's an example of a simple event tracking system where the object being tracked needs not pass a creator that it
11
45
  doesn't need itself along:
12
46
 
13
- module Current
14
- thread_mattr_accessor :account
15
- thread_mattr_accessor :user
16
-
17
- def self.reset() self.account = self.user = nil end
18
- end
19
-
20
- class ApplicationController < ActiveController::Base
21
- before_action :set_current
22
- after_action { Current.reset }
23
-
24
- private
25
- def set_current
26
- Current.account = Account.find(params[:account_id])
27
- Current.user = Current.account.users.find(params[:user_id])
47
+ module Current
48
+ thread_mattr_accessor :account
49
+ thread_mattr_accessor :user
50
+
51
+ def self.reset() self.account = self.user = nil end
28
52
  end
29
- end
30
53
 
31
- class MessagesController < ApplicationController
32
- def create
33
- @message = Message.create!(message_params)
34
- end
35
- end
36
-
37
- class Message < ApplicationRecord
38
- has_many :events
39
- after_create :track_created
40
-
41
- private
42
- def track_created
43
- events.create! origin: self, action: :create
54
+ class ApplicationController < ActionController::Base
55
+ before_action :set_current
56
+ after_action { Current.reset }
57
+
58
+ private
59
+ def set_current
60
+ Current.account = Account.find(params[:account_id])
61
+ Current.user = Current.account.users.find(params[:user_id])
62
+ end
63
+ end
64
+
65
+ class MessagesController < ApplicationController
66
+ def create
67
+ @message = Message.create!(message_params)
68
+ end
44
69
  end
45
- end
46
70
 
47
- class Event < ApplicationRecord
48
- belongs_to :creator, class_name: 'User'
49
- before_validation { self.creator ||= Current.user }
50
- end
71
+ class Message < ApplicationRecord
72
+ has_many :events
73
+ after_create :track_created
74
+
75
+ private
76
+ def track_created
77
+ events.create! origin: self, action: :create
78
+ end
79
+ end
80
+
81
+ class Event < ApplicationRecord
82
+ belongs_to :creator, class_name: 'User'
83
+ before_validation { self.creator ||= Current.user }
84
+ end
51
85
 
52
86
  *DHH*
53
87
 
@@ -61,9 +95,9 @@
61
95
 
62
96
  *Yuichiro Kaneko*
63
97
 
64
- * `ActiveSupport::Cache::Store#namespaced_key`,
65
- `ActiveSupport::Cache::MemCachedStore#escape_key`, and
66
- `ActiveSupport::Cache::FileStore#key_file_path`
98
+ * `ActiveSupport::Cache::Store#namespaced_key`,
99
+ `ActiveSupport::Cache::MemCachedStore#escape_key`, and
100
+ `ActiveSupport::Cache::FileStore#key_file_path`
67
101
  are deprecated and replaced with `normalize_key` that now calls `super`.
68
102
 
69
103
  `ActiveSupport::Cache::LocaleCache#set_cache_value` is deprecated and replaced with `write_cache_value`.
@@ -122,7 +156,7 @@
122
156
 
123
157
  *Konstantinos Rousis*
124
158
 
125
- * Handle invalid UTF-8 strings when HTML escaping
159
+ * Handle invalid UTF-8 strings when HTML escaping.
126
160
 
127
161
  Use `ActiveSupport::Multibyte::Unicode.tidy_bytes` to handle invalid UTF-8
128
162
  strings in `ERB::Util.unwrapped_html_escape` and `ERB::Util.html_escape_once`.
@@ -163,7 +197,7 @@
163
197
 
164
198
  * Short-circuit `blank?` on date and time values since they are never blank.
165
199
 
166
- Fixes #21657
200
+ Fixes #21657.
167
201
 
168
202
  *Andrew White*
169
203
 
@@ -201,7 +235,7 @@
201
235
  * ActiveSupport::HashWithIndifferentAccess `select` and `reject` will now return
202
236
  enumerator if called without block.
203
237
 
204
- Fixes #20095
238
+ Fixes #20095.
205
239
 
206
240
  *Bernard Potocki*
207
241
 
@@ -215,11 +249,11 @@
215
249
 
216
250
  *Simon Eskildsen*
217
251
 
218
- * Fix setting `default_proc` on `HashWithIndifferentAccess#dup`
252
+ * Fix setting `default_proc` on `HashWithIndifferentAccess#dup`.
219
253
 
220
254
  *Simon Eskildsen*
221
255
 
222
- * Fix a range of values for parameters of the Time#change
256
+ * Fix a range of values for parameters of the Time#change.
223
257
 
224
258
  *Nikolay Kondratyev*
225
259
 
@@ -231,7 +265,7 @@
231
265
  *Kevin Deisz*
232
266
 
233
267
  * Add a bang version to `ActiveSupport::OrderedOptions` get methods which will raise
234
- an `KeyError` if the value is `.blank?`
268
+ an `KeyError` if the value is `.blank?`.
235
269
 
236
270
  Before:
237
271
 
@@ -1,4 +1,4 @@
1
- Copyright (c) 2005-2015 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.
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2015 David Heinemeier Hansson
2
+ # Copyright (c) 2005-2016 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
@@ -255,10 +255,11 @@ module ActiveSupport
255
255
  # end
256
256
  # end
257
257
  #
258
- # # val_1 => "new value 1"
259
- # # val_2 => "original value"
260
- # # sleep 10 # First thread extend the life of cache by another 10 seconds
261
- # # cache.fetch('foo') => "new value 1"
258
+ # cache.fetch('foo') # => "original value"
259
+ # sleep 10 # First thread extended the life of cache by another 10 seconds
260
+ # cache.fetch('foo') # => "new value 1"
261
+ # val_1 # => "new value 1"
262
+ # val_2 # => "original value"
262
263
  #
263
264
  # Other options will be handled by the specific cache store implementation.
264
265
  # Internally, #fetch calls #read_entry, and calls #write_entry on a cache
@@ -278,18 +279,18 @@ module ActiveSupport
278
279
  options = merged_options(options)
279
280
  key = normalize_key(name, options)
280
281
 
282
+ entry = nil
281
283
  instrument(:read, name, options) do |payload|
282
284
  cached_entry = read_entry(key, options) unless options[:force]
283
- payload[:super_operation] = :fetch if payload
284
285
  entry = handle_expired_entry(cached_entry, key, options)
286
+ payload[:super_operation] = :fetch if payload
287
+ payload[:hit] = !!entry if payload
288
+ end
285
289
 
286
- if entry
287
- payload[:hit] = true if payload
288
- get_entry_value(entry, name, options)
289
- else
290
- payload[:hit] = false if payload
291
- save_block_result_to_cache(name, options) { |_name| yield _name }
292
- end
290
+ if entry
291
+ get_entry_value(entry, name, options)
292
+ else
293
+ save_block_result_to_cache(name, options) { |_name| yield _name }
293
294
  end
294
295
  else
295
296
  read(name, options)
@@ -17,6 +17,7 @@ module ActiveSupport
17
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)
18
18
  FILEPATH_MAX_SIZE = 900 # max is 1024, plus some room
19
19
  EXCLUDED_DIRS = ['.', '..'].freeze
20
+ GITKEEP_FILES = ['.gitkeep', '.keep'].freeze
20
21
 
21
22
  def initialize(cache_path, options = nil)
22
23
  super(options)
@@ -24,10 +25,10 @@ module ActiveSupport
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)})
32
33
  rescue Errno::ENOENT
33
34
  end
@@ -154,7 +155,7 @@ module ActiveSupport
154
155
  # Delete empty directories in the cache.
155
156
  def delete_empty_directories(dir)
156
157
  return if File.realpath(dir) == File.realpath(cache_path)
157
- if Dir.entries(dir).reject {|f| EXCLUDED_DIRS.include?(f)}.empty?
158
+ if exclude_from(dir, EXCLUDED_DIRS).empty?
158
159
  Dir.delete(dir) rescue nil
159
160
  delete_empty_directories(File.dirname(dir))
160
161
  end
@@ -193,6 +194,11 @@ module ActiveSupport
193
194
  end
194
195
  end
195
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
196
202
  end
197
203
  end
198
204
  end
@@ -48,17 +48,11 @@ module ActiveSupport
48
48
  def start_exclusive(purpose: nil, compatible: [], no_wait: false)
49
49
  synchronize do
50
50
  unless @exclusive_thread == Thread.current
51
- if busy?(purpose)
51
+ if busy_for_exclusive?(purpose)
52
52
  return false if no_wait
53
53
 
54
- loose_shares = @sharing.delete(Thread.current)
55
- @waiting[Thread.current] = compatible if loose_shares
56
-
57
- begin
58
- @cv.wait_while { busy?(purpose) }
59
- ensure
60
- @waiting.delete Thread.current
61
- @sharing[Thread.current] = loose_shares if loose_shares
54
+ yield_shares(purpose, compatible) do
55
+ @cv.wait_while { busy_for_exclusive?(purpose) }
62
56
  end
63
57
  end
64
58
  @exclusive_thread = Thread.current
@@ -71,22 +65,26 @@ module ActiveSupport
71
65
 
72
66
  # Relinquish the exclusive lock. Must only be called by the thread
73
67
  # that called start_exclusive (and currently holds the lock).
74
- def stop_exclusive
68
+ def stop_exclusive(compatible: [])
75
69
  synchronize do
76
70
  raise "invalid unlock" if @exclusive_thread != Thread.current
77
71
 
78
72
  @exclusive_depth -= 1
79
73
  if @exclusive_depth == 0
80
74
  @exclusive_thread = nil
81
- @cv.broadcast
75
+
76
+ yield_shares(nil, compatible) do
77
+ @cv.broadcast
78
+ @cv.wait_while { @exclusive_thread || eligible_waiters?(compatible) }
79
+ end
82
80
  end
83
81
  end
84
82
  end
85
83
 
86
- def start_sharing
84
+ def start_sharing(purpose: :share)
87
85
  synchronize do
88
- if @exclusive_thread && @exclusive_thread != Thread.current
89
- @cv.wait_while { @exclusive_thread }
86
+ if @sharing[Thread.current] == 0 && @exclusive_thread != Thread.current && busy_for_sharing?(purpose)
87
+ @cv.wait_while { busy_for_sharing?(purpose) }
90
88
  end
91
89
  @sharing[Thread.current] += 1
92
90
  end
@@ -109,12 +107,12 @@ module ActiveSupport
109
107
  # the block.
110
108
  #
111
109
  # See +start_exclusive+ for other options.
112
- def exclusive(purpose: nil, compatible: [], no_wait: false)
110
+ def exclusive(purpose: nil, compatible: [], after_compatible: [], no_wait: false)
113
111
  if start_exclusive(purpose: purpose, compatible: compatible, no_wait: no_wait)
114
112
  begin
115
113
  yield
116
114
  ensure
117
- stop_exclusive
115
+ stop_exclusive(compatible: after_compatible)
118
116
  end
119
117
  end
120
118
  end
@@ -132,11 +130,31 @@ module ActiveSupport
132
130
  private
133
131
 
134
132
  # Must be called within synchronize
135
- def busy?(purpose)
136
- (@exclusive_thread && @exclusive_thread != Thread.current) ||
137
- @waiting.any? { |k, v| k != Thread.current && !v.include?(purpose) } ||
133
+ def busy_for_exclusive?(purpose)
134
+ busy_for_sharing?(purpose) ||
138
135
  @sharing.size > (@sharing[Thread.current] > 0 ? 1 : 0)
139
136
  end
137
+
138
+ def busy_for_sharing?(purpose)
139
+ (@exclusive_thread && @exclusive_thread != Thread.current) ||
140
+ @waiting.any? { |t, (_, c)| t != Thread.current && !c.include?(purpose) }
141
+ end
142
+
143
+ def eligible_waiters?(compatible)
144
+ @waiting.any? { |t, (p, _)| compatible.include?(p) && @waiting.all? { |t2, (_, c2)| t == t2 || c2.include?(p) } }
145
+ end
146
+
147
+ def yield_shares(purpose, compatible)
148
+ loose_shares = @sharing.delete(Thread.current)
149
+ @waiting[Thread.current] = [purpose, compatible] if loose_shares
150
+
151
+ begin
152
+ yield
153
+ ensure
154
+ @waiting.delete Thread.current
155
+ @sharing[Thread.current] = loose_shares if loose_shares
156
+ end
157
+ end
140
158
  end
141
159
  end
142
160
  end
@@ -138,6 +138,8 @@ end
138
138
 
139
139
  module ActiveSupport
140
140
  class XMLConverter # :nodoc:
141
+ # Raised if the XML contains attributes with type="yaml" or
142
+ # type="symbol". Read Hash#from_xml for more details.
141
143
  class DisallowedType < StandardError
142
144
  def initialize(type)
143
145
  super "Disallowed type attribute: #{type.inspect}"
@@ -49,7 +49,7 @@ class Module
49
49
  # include HairColors
50
50
  # end
51
51
  #
52
- # Person.hair_colors # => [:brown, :black, :blonde, :red]
52
+ # Person.new.hair_colors # => [:brown, :black, :blonde, :red]
53
53
  def mattr_reader(*syms)
54
54
  options = syms.extract_options!
55
55
  syms.each do |sym|
@@ -105,7 +105,7 @@ class Module
105
105
  #
106
106
  # Also, you can pass a block to set up the attribute with a default value.
107
107
  #
108
- # class HairColors
108
+ # module HairColors
109
109
  # mattr_writer :hair_colors do
110
110
  # [:brown, :black, :blonde, :red]
111
111
  # end
@@ -150,8 +150,8 @@ class Module
150
150
  # include HairColors
151
151
  # end
152
152
  #
153
- # Person.hair_colors = [:brown, :black, :blonde, :red]
154
- # Person.hair_colors # => [:brown, :black, :blonde, :red]
153
+ # HairColors.hair_colors = [:brown, :black, :blonde, :red]
154
+ # HairColors.hair_colors # => [:brown, :black, :blonde, :red]
155
155
  # Person.new.hair_colors # => [:brown, :black, :blonde, :red]
156
156
  #
157
157
  # If a subclass changes the value then that would also change the value for
@@ -161,8 +161,8 @@ class Module
161
161
  # class Male < Person
162
162
  # end
163
163
  #
164
- # Male.hair_colors << :blue
165
- # Person.hair_colors # => [:brown, :black, :blonde, :red, :blue]
164
+ # Male.new.hair_colors << :blue
165
+ # Person.new.hair_colors # => [:brown, :black, :blonde, :red, :blue]
166
166
  #
167
167
  # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
168
168
  # To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
@@ -13,8 +13,8 @@ class Module
13
13
  #
14
14
  # class MyLib::Deprecator
15
15
  # def deprecation_warning(deprecated_method_name, message, caller_backtrace = nil)
16
- # message = "#{deprecated_method_name} is deprecated and will be removed from MyLibrary | #{message}"
17
- # Kernel.warn message
16
+ # message = "#{deprecated_method_name} is deprecated and will be removed from MyLibrary | #{message}"
17
+ # Kernel.warn message
18
18
  # end
19
19
  # end
20
20
  def deprecate(*method_names)
@@ -1,5 +1,6 @@
1
1
  require 'active_support/core_ext/big_decimal/conversions'
2
2
  require 'active_support/number_helper'
3
+ require 'active_support/core_ext/module/deprecation'
3
4
 
4
5
  module ActiveSupport::NumericWithFormat
5
6
 
@@ -75,6 +76,8 @@ module ActiveSupport::NumericWithFormat
75
76
  # 1234567.to_s(:human_size) # => 1.18 MB
76
77
  # 1234567890.to_s(:human_size) # => 1.15 GB
77
78
  # 1234567890123.to_s(:human_size) # => 1.12 TB
79
+ # 1234567890123456.to_s(:human_size) # => 1.1 PB
80
+ # 1234567890123456789.to_s(:human_size) # => 1.07 EB
78
81
  # 1234567.to_s(:human_size, precision: 2) # => 1.2 MB
79
82
  # 483989.to_s(:human_size, precision: 2) # => 470 KB
80
83
  # 1234567.to_s(:human_size, precision: 2, separator: ',') # => 1,2 MB
@@ -117,7 +120,11 @@ module ActiveSupport::NumericWithFormat
117
120
  when :human_size
118
121
  return ActiveSupport::NumberHelper.number_to_human_size(self, options)
119
122
  else
120
- super
123
+ if is_a?(Float) || format.is_a?(Symbol)
124
+ super()
125
+ else
126
+ super
127
+ end
121
128
  end
122
129
  end
123
130
 
@@ -5,7 +5,6 @@ class ERB
5
5
  module Util
6
6
  HTML_ESCAPE = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;', "'" => '&#39;' }
7
7
  JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003e', '<' => '\u003c', "\u2028" => '\u2028', "\u2029" => '\u2029' }
8
- HTML_ESCAPE_REGEXP = /[&"'><]/
9
8
  HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
10
9
  JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u
11
10
 
@@ -37,7 +36,7 @@ class ERB
37
36
  if s.html_safe?
38
37
  s
39
38
  else
40
- ActiveSupport::Multibyte::Unicode.tidy_bytes(s).gsub(HTML_ESCAPE_REGEXP, HTML_ESCAPE)
39
+ CGI.escapeHTML(ActiveSupport::Multibyte::Unicode.tidy_bytes(s))
41
40
  end
42
41
  end
43
42
  module_function :unwrapped_html_escape
@@ -142,6 +141,7 @@ module ActiveSupport #:nodoc:
142
141
  alias_method :original_concat, :concat
143
142
  private :original_concat
144
143
 
144
+ # Raised when <tt>ActiveSupport::SafeBuffer#safe_concat</tt> is called on unsafe buffers.
145
145
  class SafeConcatError < StandardError
146
146
  def initialize
147
147
  super 'Could not concatenate to the buffer because it is not html safe.'
@@ -243,8 +243,7 @@ module ActiveSupport #:nodoc:
243
243
  private
244
244
 
245
245
  def html_escape_interpolated_argument(arg)
246
- (!html_safe? || arg.html_safe?) ? arg :
247
- arg.to_s.gsub(ERB::Util::HTML_ESCAPE_REGEXP, ERB::Util::HTML_ESCAPE)
246
+ (!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
248
247
  end
249
248
  end
250
249
  end
@@ -40,7 +40,23 @@ class Time
40
40
  Thread.current[:time_zone] = find_zone!(time_zone)
41
41
  end
42
42
 
43
- # Allows override of <tt>Time.zone</tt> locally inside supplied block; resets <tt>Time.zone</tt> to existing value when done.
43
+ # Allows override of <tt>Time.zone</tt> locally inside supplied block;
44
+ # resets <tt>Time.zone</tt> to existing value when done.
45
+ #
46
+ # class ApplicationController < ActionController::Base
47
+ # around_action :set_time_zone
48
+ #
49
+ # private
50
+ #
51
+ # def set_time_zone
52
+ # Time.use_zone(current_user.timezone) { yield }
53
+ # end
54
+ # end
55
+ #
56
+ # NOTE: This won't affect any <tt>ActiveSupport::TimeWithZone</tt>
57
+ # objects that have already been created, e.g. any model timestamp
58
+ # attributes that have been read before the block will remain in
59
+ # the application's default timezone.
44
60
  def use_zone(time_zone)
45
61
  new_zone = find_zone!(time_zone)
46
62
  begin
@@ -8,13 +8,13 @@ module ActiveSupport #:nodoc:
8
8
  end
9
9
 
10
10
  def loading
11
- @lock.exclusive(purpose: :load, compatible: [:load]) do
11
+ @lock.exclusive(purpose: :load, compatible: [:load], after_compatible: [:load]) do
12
12
  yield
13
13
  end
14
14
  end
15
15
 
16
16
  def unloading
17
- @lock.exclusive(purpose: :unload, compatible: [:load, :unload]) do
17
+ @lock.exclusive(purpose: :unload, compatible: [:load, :unload], after_compatible: [:load, :unload]) do
18
18
  yield
19
19
  end
20
20
  end
@@ -24,7 +24,7 @@ module ActiveSupport #:nodoc:
24
24
  # concurrent activity, return immediately (without executing the
25
25
  # block) instead of waiting.
26
26
  def attempt_unloading
27
- @lock.exclusive(purpose: :unload, compatible: [:load, :unload], no_wait: true) do
27
+ @lock.exclusive(purpose: :unload, compatible: [:load, :unload], after_compatible: [:load, :unload], no_wait: true) do
28
28
  yield
29
29
  end
30
30
  end
@@ -32,7 +32,7 @@ module ActiveSupport
32
32
  # and the second is a library name
33
33
  #
34
34
  # ActiveSupport::Deprecation.new('2.0', 'MyLibrary')
35
- def initialize(deprecation_horizon = '5.0', gem_name = 'Rails')
35
+ def initialize(deprecation_horizon = '5.1', gem_name = 'Rails')
36
36
  self.gem_name = gem_name
37
37
  self.deprecation_horizon = deprecation_horizon
38
38
  # By default, warnings are not silenced and debugging is off.
@@ -1,6 +1,8 @@
1
1
  require "active_support/notifications"
2
2
 
3
3
  module ActiveSupport
4
+ # Raised when <tt>ActiveSupport::Deprecation::Behavior#behavior</tt> is set with <tt>:raise</tt>.
5
+ # You would set <tt>:raise</tt>, as a behaviour to raise errors and proactively report exceptions from deprecations.
4
6
  class DeprecationException < StandardError
5
7
  end
6
8
 
@@ -21,15 +21,15 @@ module ActiveSupport
21
21
  # # => [:aaa, :bbb, :ccc]
22
22
  #
23
23
  # Fred.aaa
24
- # # DEPRECATION WARNING: aaa is deprecated and will be removed from Rails 5.0. (called from irb_binding at (irb):10)
24
+ # # DEPRECATION WARNING: aaa is deprecated and will be removed from Rails 5.1. (called from irb_binding at (irb):10)
25
25
  # # => nil
26
26
  #
27
27
  # Fred.bbb
28
- # # DEPRECATION WARNING: bbb is deprecated and will be removed from Rails 5.0 (use zzz instead). (called from irb_binding at (irb):11)
28
+ # # DEPRECATION WARNING: bbb is deprecated and will be removed from Rails 5.1 (use zzz instead). (called from irb_binding at (irb):11)
29
29
  # # => nil
30
30
  #
31
31
  # Fred.ccc
32
- # # DEPRECATION WARNING: ccc is deprecated and will be removed from Rails 5.0 (use Bar#ccc instead). (called from irb_binding at (irb):12)
32
+ # # DEPRECATION WARNING: ccc is deprecated and will be removed from Rails 5.1 (use Bar#ccc instead). (called from irb_binding at (irb):12)
33
33
  # # => nil
34
34
  #
35
35
  # Passing in a custom deprecator:
@@ -8,7 +8,7 @@ module ActiveSupport
8
8
  MAJOR = 5
9
9
  MINOR = 0
10
10
  TINY = 0
11
- PRE = "beta1.1"
11
+ PRE = "beta2"
12
12
 
13
13
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
14
14
  end
@@ -68,12 +68,10 @@ module ActiveSupport
68
68
  end
69
69
  end
70
70
 
71
- def default(key = nil)
72
- if key.is_a?(Symbol) && include?(key = key.to_s)
73
- self[key]
74
- else
75
- super
76
- end
71
+ def default(*args)
72
+ key = args.first
73
+ args[0] = key.to_s if key.is_a?(Symbol)
74
+ super(*args)
77
75
  end
78
76
 
79
77
  def self.new_from_hash_copying_default(hash)
@@ -159,6 +157,20 @@ module ActiveSupport
159
157
  alias_method :has_key?, :key?
160
158
  alias_method :member?, :key?
161
159
 
160
+
161
+ # Same as <tt>Hash#[]</tt> where the key passed as argument can be
162
+ # either a string or a symbol:
163
+ #
164
+ # counters = ActiveSupport::HashWithIndifferentAccess.new
165
+ # counters[:foo] = 1
166
+ #
167
+ # counters['foo'] # => 1
168
+ # counters[:foo] # => 1
169
+ # counters[:zoo] # => nil
170
+ def [](key)
171
+ super(convert_key(key))
172
+ end
173
+
162
174
  # Same as <tt>Hash#fetch</tt> where the key passed as argument can be
163
175
  # either a string or a symbol:
164
176
  #
@@ -173,7 +173,7 @@ module ActiveSupport
173
173
  #
174
174
  # Singular names are not handled correctly:
175
175
  #
176
- # classify('calculus') # => "Calculu"
176
+ # classify('calculus') # => "Calculus"
177
177
  def classify(table_name)
178
178
  # strip out any leading schema name
179
179
  camelize(singularize(table_name.to_s.sub(/.*\./, ''.freeze)))
@@ -106,6 +106,8 @@ en:
106
106
  mb: "MB"
107
107
  gb: "GB"
108
108
  tb: "TB"
109
+ pb: "PB"
110
+ eb: "EB"
109
111
  # Used in NumberHelper.number_to_human()
110
112
  decimal_units:
111
113
  format: "%n %u"
@@ -5,18 +5,27 @@ module ActiveSupport
5
5
  class Logger < ::Logger
6
6
  include LoggerSilence
7
7
 
8
- attr_accessor :broadcast_messages
8
+ # Returns true if the logger destination matches one of the sources
9
+ #
10
+ # logger = Logger.new(STDOUT)
11
+ # ActiveSupport::Logger.logger_outputs_to?(logger, STDOUT)
12
+ # # => true
13
+ def self.logger_outputs_to?(logger, *sources)
14
+ logdev = logger.instance_variable_get("@logdev")
15
+ logger_source = logdev.dev if logdev.respond_to?(:dev)
16
+ sources.any? { |source| source == logger_source }
17
+ end
9
18
 
10
19
  # Broadcasts logs to multiple loggers.
11
20
  def self.broadcast(logger) # :nodoc:
12
21
  Module.new do
13
22
  define_method(:add) do |*args, &block|
14
- logger.add(*args, &block) if broadcast_messages
23
+ logger.add(*args, &block)
15
24
  super(*args, &block)
16
25
  end
17
26
 
18
27
  define_method(:<<) do |x|
19
- logger << x if broadcast_messages
28
+ logger << x
20
29
  super(x)
21
30
  end
22
31
 
@@ -45,7 +54,20 @@ module ActiveSupport
45
54
  def initialize(*args)
46
55
  super
47
56
  @formatter = SimpleFormatter.new
48
- @broadcast_messages = true
57
+ after_initialize if respond_to? :after_initialize
58
+ end
59
+
60
+ def add(severity, message = nil, progname = nil, &block)
61
+ return true if @logdev.nil? || (severity || UNKNOWN) < level
62
+ super
63
+ end
64
+
65
+ Logger::Severity.constants.each do |severity|
66
+ class_eval(<<-EOT, __FILE__, __LINE__ + 1)
67
+ def #{severity.downcase}? # def debug?
68
+ Logger::#{severity} >= level # DEBUG >= level
69
+ end # end
70
+ EOT
49
71
  end
50
72
 
51
73
  # Simple formatter which only displays the message.
@@ -1,25 +1,45 @@
1
1
  require 'active_support/concern'
2
2
  require 'active_support/core_ext/module/attribute_accessors'
3
+ require 'concurrent'
3
4
 
4
5
  module LoggerSilence
5
6
  extend ActiveSupport::Concern
6
7
 
7
8
  included do
8
9
  cattr_accessor :silencer
10
+ attr_reader :local_levels
9
11
  self.silencer = true
10
12
  end
11
13
 
14
+ def after_initialize
15
+ @local_levels = Concurrent::Map.new(:initial_capacity => 2)
16
+ end
17
+
18
+ def local_log_id
19
+ Thread.current.__id__
20
+ end
21
+
22
+ def level
23
+ local_levels[local_log_id] || super
24
+ end
25
+
12
26
  # Silences the logger for the duration of the block.
13
27
  def silence(temporary_level = Logger::ERROR)
14
28
  if silencer
15
29
  begin
16
- old_logger_level, self.level = level, temporary_level
30
+ old_local_level = local_levels[local_log_id]
31
+ local_levels[local_log_id] = temporary_level
32
+
17
33
  yield self
18
34
  ensure
19
- self.level = old_logger_level
35
+ if old_local_level
36
+ local_levels[local_log_id] = old_local_level
37
+ else
38
+ local_levels.delete(local_log_id)
39
+ end
20
40
  end
21
41
  else
22
42
  yield self
23
43
  end
24
44
  end
25
- end
45
+ end
@@ -87,19 +87,44 @@ module ActiveSupport
87
87
  pos += 1
88
88
  previous = codepoints[pos-1]
89
89
  current = codepoints[pos]
90
- if (
91
- # CR X LF
92
- ( previous == database.boundary[:cr] and current == database.boundary[:lf] ) or
93
- # L X (L|V|LV|LVT)
94
- ( database.boundary[:l] === previous and in_char_class?(current, [:l,:v,:lv,:lvt]) ) or
95
- # (LV|V) X (V|T)
96
- ( in_char_class?(previous, [:lv,:v]) and in_char_class?(current, [:v,:t]) ) or
97
- # (LVT|T) X (T)
98
- ( in_char_class?(previous, [:lvt,:t]) and database.boundary[:t] === current ) or
99
- # X Extend
100
- (database.boundary[:extend] === current)
101
- )
102
- else
90
+
91
+ should_break =
92
+ # GB3. CR X LF
93
+ if previous == database.boundary[:cr] and current == database.boundary[:lf]
94
+ false
95
+ # GB4. (Control|CR|LF) ÷
96
+ elsif previous and in_char_class?(previous, [:control,:cr,:lf])
97
+ true
98
+ # GB5. ÷ (Control|CR|LF)
99
+ elsif in_char_class?(current, [:control,:cr,:lf])
100
+ true
101
+ # GB6. L X (L|V|LV|LVT)
102
+ elsif database.boundary[:l] === previous and in_char_class?(current, [:l,:v,:lv,:lvt])
103
+ false
104
+ # GB7. (LV|V) X (V|T)
105
+ elsif in_char_class?(previous, [:lv,:v]) and in_char_class?(current, [:v,:t])
106
+ false
107
+ # GB8. (LVT|T) X (T)
108
+ elsif in_char_class?(previous, [:lvt,:t]) and database.boundary[:t] === current
109
+ false
110
+ # GB8a. Regional_Indicator X Regional_Indicator
111
+ elsif database.boundary[:regional_indicator] === previous and database.boundary[:regional_indicator] === current
112
+ false
113
+ # GB9. X Extend
114
+ elsif database.boundary[:extend] === current
115
+ false
116
+ # GB9a. X SpacingMark
117
+ elsif database.boundary[:spacingmark] === current
118
+ false
119
+ # GB9b. Prepend X
120
+ elsif database.boundary[:prepend] === previous
121
+ false
122
+ # GB10. Any ÷ Any
123
+ else
124
+ true
125
+ end
126
+
127
+ if should_break
103
128
  unpacked << codepoints[marker..pos-1]
104
129
  marker = pos
105
130
  end
@@ -21,6 +21,7 @@ module ActiveSupport
21
21
  yield payload
22
22
  rescue Exception => e
23
23
  payload[:exception] = [e.class.name, e.message]
24
+ payload[:exception_object] = e
24
25
  raise e
25
26
  ensure
26
27
  finish_with_state listeners_state, name, payload
@@ -47,6 +47,14 @@ module ActiveSupport
47
47
  # Formats a +number+ into a currency string (e.g., $13.65). You
48
48
  # can customize the format in the +options+ hash.
49
49
  #
50
+ # The currency unit and number formatting of the current locale will be used
51
+ # unless otherwise specified in the provided options. No currency conversion
52
+ # is performed. If the user is given a way to change their locale, they will
53
+ # also be able to change the relative value of the currency displayed with
54
+ # this helper. If your application will ever support multiple locales, you
55
+ # may want to specify a constant <tt>:locale</tt> option or consider
56
+ # using a library capable of currency conversion.
57
+ #
50
58
  # ==== Options
51
59
  #
52
60
  # * <tt>:locale</tt> - Sets the locale to be used for formatting
@@ -235,6 +243,8 @@ module ActiveSupport
235
243
  # number_to_human_size(1234567) # => 1.18 MB
236
244
  # number_to_human_size(1234567890) # => 1.15 GB
237
245
  # number_to_human_size(1234567890123) # => 1.12 TB
246
+ # number_to_human_size(1234567890123456) # => 1.1 PB
247
+ # number_to_human_size(1234567890123456789) # => 1.07 EB
238
248
  # number_to_human_size(1234567, precision: 2) # => 1.2 MB
239
249
  # number_to_human_size(483989, precision: 2) # => 470 KB
240
250
  # number_to_human_size(1234567, precision: 2, separator: ',') # => 1,2 MB
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/numeric/inquiry'
2
+
1
3
  module ActiveSupport
2
4
  module NumberHelper
3
5
  class NumberToCurrencyConverter < NumberConverter # :nodoc:
@@ -7,7 +9,7 @@ module ActiveSupport
7
9
  number = self.number.to_s.strip
8
10
  format = options[:format]
9
11
 
10
- if is_negative?(number)
12
+ if number.to_f.negative?
11
13
  format = options[:negative_format]
12
14
  number = absolute_value(number)
13
15
  end
@@ -18,10 +20,6 @@ module ActiveSupport
18
20
 
19
21
  private
20
22
 
21
- def is_negative?(number)
22
- number.to_f.phase != 0
23
- end
24
-
25
23
  def absolute_value(number)
26
24
  number.respond_to?(:abs) ? number.abs : number.sub(/\A-/, '')
27
25
  end
@@ -1,7 +1,7 @@
1
1
  module ActiveSupport
2
2
  module NumberHelper
3
3
  class NumberToHumanSizeConverter < NumberConverter #:nodoc:
4
- STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb]
4
+ STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb, :pb, :eb]
5
5
 
6
6
  self.namespace = :human
7
7
  self.validate_float = true
@@ -5,7 +5,7 @@ YAML.add_builtin_type("omap") do |type, val|
5
5
  end
6
6
 
7
7
  module ActiveSupport
8
- # <tt>ActiveSupport::OrderedHash</tt> implements a hash that preserves
8
+ # DEPRECATED: <tt>ActiveSupport::OrderedHash</tt> implements a hash that preserves
9
9
  # insertion order.
10
10
  #
11
11
  # oh = ActiveSupport::OrderedHash.new
@@ -9,7 +9,6 @@ require 'active_support/testing/isolation'
9
9
  require 'active_support/testing/constant_lookup'
10
10
  require 'active_support/testing/time_helpers'
11
11
  require 'active_support/testing/file_fixtures'
12
- require 'active_support/testing/composite_filter'
13
12
  require 'active_support/core_ext/kernel/reporting'
14
13
 
15
14
  module ActiveSupport
@@ -39,15 +38,6 @@ module ActiveSupport
39
38
  def test_order
40
39
  ActiveSupport.test_order ||= :random
41
40
  end
42
-
43
- def run(reporter, options = {})
44
- if options[:patterns] && options[:patterns].any? { |p| p =~ /:\d+/ }
45
- options[:filter] = \
46
- Testing::CompositeFilter.new(self, options[:filter], options[:patterns])
47
- end
48
-
49
- super
50
- end
51
41
  end
52
42
 
53
43
  alias_method :method_name, :name
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activesupport
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0.beta1.1
4
+ version: 5.0.0.beta2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-25 00:00:00.000000000 Z
11
+ date: 2016-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -312,7 +312,6 @@ files:
312
312
  - lib/active_support/test_case.rb
313
313
  - lib/active_support/testing/assertions.rb
314
314
  - lib/active_support/testing/autorun.rb
315
- - lib/active_support/testing/composite_filter.rb
316
315
  - lib/active_support/testing/constant_lookup.rb
317
316
  - lib/active_support/testing/declarative.rb
318
317
  - lib/active_support/testing/deprecation.rb
@@ -357,9 +356,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
357
356
  version: 1.3.1
358
357
  requirements: []
359
358
  rubyforge_project:
360
- rubygems_version: 2.5.1
359
+ rubygems_version: 2.5.2
361
360
  signing_key:
362
361
  specification_version: 4
363
362
  summary: A toolkit of support libraries and Ruby core extensions extracted from the
364
363
  Rails framework.
365
364
  test_files: []
365
+ has_rdoc:
@@ -1,54 +0,0 @@
1
- require 'method_source'
2
-
3
- module ActiveSupport
4
- module Testing
5
- class CompositeFilter # :nodoc:
6
- def initialize(runnable, filter, patterns)
7
- @runnable = runnable
8
- @filters = [ derive_regexp(filter), *derive_line_filters(patterns) ].compact
9
- end
10
-
11
- def ===(method)
12
- @filters.any? { |filter| filter === method }
13
- end
14
-
15
- private
16
- def derive_regexp(filter)
17
- filter =~ %r%/(.*)/% ? Regexp.new($1) : filter
18
- end
19
-
20
- def derive_line_filters(patterns)
21
- patterns.map do |file_and_line|
22
- file, line = file_and_line.split(':')
23
- Filter.new(@runnable, file, line) if file
24
- end
25
- end
26
-
27
- class Filter # :nodoc:
28
- def initialize(runnable, file, line)
29
- @runnable, @file = runnable, File.expand_path(file)
30
- @line = line.to_i if line
31
- end
32
-
33
- def ===(method)
34
- return unless @runnable.method_defined?(method)
35
-
36
- if @line
37
- test_file, test_range = definition_for(@runnable.instance_method(method))
38
- test_file == @file && test_range.include?(@line)
39
- else
40
- @runnable.instance_method(method).source_location.first == @file
41
- end
42
- end
43
-
44
- private
45
- def definition_for(method)
46
- file, start_line = method.source_location
47
- end_line = method.source.count("\n") + start_line - 1
48
-
49
- return file, start_line..end_line
50
- end
51
- end
52
- end
53
- end
54
- end