activesupport 4.2.0 → 5.0.0

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

Potentially problematic release.


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

Files changed (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 +3 -3
  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 +32 -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
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  module ActiveSupport
3
2
  module Multibyte
4
3
  module Unicode
@@ -11,7 +10,7 @@ module ActiveSupport
11
10
  NORMALIZATION_FORMS = [:c, :kc, :d, :kd]
12
11
 
13
12
  # The Unicode version that is supported by the implementation
14
- UNICODE_VERSION = '7.0.0'
13
+ UNICODE_VERSION = '8.0.0'
15
14
 
16
15
  # The default normalization used for operations that require
17
16
  # normalization. It can be set to any of the normalizations
@@ -58,7 +57,7 @@ module ActiveSupport
58
57
  # Returns a regular expression pattern that matches the passed Unicode
59
58
  # codepoints.
60
59
  def self.codepoints_to_pattern(array_of_codepoints) #:nodoc:
61
- array_of_codepoints.collect{ |e| [e].pack 'U*' }.join('|')
60
+ array_of_codepoints.collect{ |e| [e].pack 'U*'.freeze }.join('|'.freeze)
62
61
  end
63
62
  TRAILERS_PAT = /(#{codepoints_to_pattern(LEADERS_AND_TRAILERS)})+\Z/u
64
63
  LEADERS_PAT = /\A(#{codepoints_to_pattern(LEADERS_AND_TRAILERS)})+/u
@@ -88,19 +87,44 @@ module ActiveSupport
88
87
  pos += 1
89
88
  previous = codepoints[pos-1]
90
89
  current = codepoints[pos]
91
- if (
92
- # CR X LF
93
- ( previous == database.boundary[:cr] and current == database.boundary[:lf] ) or
94
- # L X (L|V|LV|LVT)
95
- ( database.boundary[:l] === previous and in_char_class?(current, [:l,:v,:lv,:lvt]) ) or
96
- # (LV|V) X (V|T)
97
- ( in_char_class?(previous, [:lv,:v]) and in_char_class?(current, [:v,:t]) ) or
98
- # (LVT|T) X (T)
99
- ( in_char_class?(previous, [:lvt,:t]) and database.boundary[:t] === current ) or
100
- # X Extend
101
- (database.boundary[:extend] === current)
102
- )
103
- 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
104
128
  unpacked << codepoints[marker..pos-1]
105
129
  marker = pos
106
130
  end
@@ -211,9 +235,8 @@ module ActiveSupport
211
235
  codepoints
212
236
  end
213
237
 
214
- # Ruby >= 2.1 has String#scrub, which is faster than the workaround used for < 2.1.
215
238
  # Rubinius' String#scrub, however, doesn't support ASCII-incompatible chars.
216
- if '<3'.respond_to?(:scrub) && !defined?(Rubinius)
239
+ if !defined?(Rubinius)
217
240
  # Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
218
241
  # resulting in a valid UTF-8 string.
219
242
  #
@@ -258,7 +281,7 @@ module ActiveSupport
258
281
  # * <tt>string</tt> - The string to perform normalization on.
259
282
  # * <tt>form</tt> - The form you want to normalize in. Should be one of
260
283
  # the following: <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>.
261
- # Default is ActiveSupport::Multibyte.default_normalization_form.
284
+ # Default is ActiveSupport::Multibyte::Unicode.default_normalization_form.
262
285
  def normalize(string, form=nil)
263
286
  form ||= @default_normalization_form
264
287
  # See http://www.unicode.org/reports/tr15, Table 1
@@ -274,7 +297,7 @@ module ActiveSupport
274
297
  compose(reorder_characters(decompose(:compatibility, codepoints)))
275
298
  else
276
299
  raise ArgumentError, "#{form} is not a valid normalization variant", caller
277
- end.pack('U*')
300
+ end.pack('U*'.freeze)
278
301
  end
279
302
 
280
303
  def downcase(string)
@@ -339,7 +362,7 @@ module ActiveSupport
339
362
  end
340
363
 
341
364
  # Redefine the === method so we can write shorter rules for grapheme cluster breaks
342
- @boundary.each do |k,_|
365
+ @boundary.each_key do |k|
343
366
  @boundary[k].instance_eval do
344
367
  def ===(other)
345
368
  detect { |i| i === other } ? true : false
@@ -1,5 +1,5 @@
1
1
  require 'mutex_m'
2
- require 'thread_safe'
2
+ require 'concurrent/map'
3
3
 
4
4
  module ActiveSupport
5
5
  module Notifications
@@ -12,7 +12,7 @@ module ActiveSupport
12
12
 
13
13
  def initialize
14
14
  @subscribers = []
15
- @listeners_for = ThreadSafe::Cache.new
15
+ @listeners_for = Concurrent::Map.new
16
16
  super
17
17
  end
18
18
 
@@ -42,8 +42,8 @@ module ActiveSupport
42
42
  listeners_for(name).each { |s| s.start(name, id, payload) }
43
43
  end
44
44
 
45
- def finish(name, id, payload)
46
- listeners_for(name).each { |s| s.finish(name, id, payload) }
45
+ def finish(name, id, payload, listeners = listeners_for(name))
46
+ listeners.each { |s| s.finish(name, id, payload) }
47
47
  end
48
48
 
49
49
  def publish(name, *args)
@@ -51,7 +51,7 @@ module ActiveSupport
51
51
  end
52
52
 
53
53
  def listeners_for(name)
54
- # this is correctly done double-checked locking (ThreadSafe::Cache's lookups have volatile semantics)
54
+ # this is correctly done double-checked locking (Concurrent::Map's lookups have volatile semantics)
55
55
  @listeners_for[name] || synchronize do
56
56
  # use synchronisation when accessing @subscribers
57
57
  @listeners_for[name] ||= @subscribers.select { |s| s.subscribed_to?(name) }
@@ -111,7 +111,7 @@ module ActiveSupport
111
111
  end
112
112
  end
113
113
 
114
- class Timed < Evented
114
+ class Timed < Evented # :nodoc:
115
115
  def publish(name, *args)
116
116
  @delegate.call name, *args
117
117
  end
@@ -15,14 +15,16 @@ module ActiveSupport
15
15
  # and publish it. Notice that events get sent even if an error occurs
16
16
  # in the passed-in block.
17
17
  def instrument(name, payload={})
18
- start name, payload
18
+ # some of the listeners might have state
19
+ listeners_state = start name, payload
19
20
  begin
20
21
  yield payload
21
22
  rescue Exception => e
22
23
  payload[:exception] = [e.class.name, e.message]
24
+ payload[:exception_object] = e
23
25
  raise e
24
26
  ensure
25
- finish name, payload
27
+ finish_with_state listeners_state, name, payload
26
28
  end
27
29
  end
28
30
 
@@ -36,6 +38,10 @@ module ActiveSupport
36
38
  @notifier.finish name, @id, payload
37
39
  end
38
40
 
41
+ def finish_with_state(listeners_state, name, payload)
42
+ @notifier.finish name, @id, payload, listeners_state
43
+ end
44
+
39
45
  private
40
46
 
41
47
  def unique_id
@@ -57,6 +63,18 @@ module ActiveSupport
57
63
  @duration = nil
58
64
  end
59
65
 
66
+ # Returns the difference in milliseconds between when the execution of the
67
+ # event started and when it ended.
68
+ #
69
+ # ActiveSupport::Notifications.subscribe('wait') do |*args|
70
+ # @event = ActiveSupport::Notifications::Event.new(*args)
71
+ # end
72
+ #
73
+ # ActiveSupport::Notifications.instrument('wait') do
74
+ # sleep 1
75
+ # end
76
+ #
77
+ # @event.duration # => 1000.138
60
78
  def duration
61
79
  @duration ||= 1000.0 * (self.end - time)
62
80
  end
@@ -69,8 +69,8 @@ module ActiveSupport
69
69
  # is able to take the arguments as they come and provide an object-oriented
70
70
  # interface to that data.
71
71
  #
72
- # It is also possible to pass an object as the second parameter passed to the
73
- # <tt>subscribe</tt> method instead of a block:
72
+ # It is also possible to pass an object which responds to <tt>call</tt> method
73
+ # as the second parameter to the <tt>subscribe</tt> method instead of a block:
74
74
  #
75
75
  # module ActionController
76
76
  # class PageRequest
@@ -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,36 +9,32 @@ 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
14
16
 
15
17
  rounded_number = NumberToRoundedConverter.convert(number, options)
16
- format.gsub(/%n/, rounded_number).gsub(/%u/, options[:unit])
18
+ format.gsub('%n'.freeze, rounded_number).gsub('%u'.freeze, options[:unit])
17
19
  end
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
- number.respond_to?("abs") ? number.abs : number.sub(/\A-/, '')
24
+ number.respond_to?(:abs) ? number.abs : number.sub(/\A-/, '')
27
25
  end
28
26
 
29
27
  def options
30
28
  @options ||= begin
31
29
  defaults = default_format_options.merge(i18n_opts)
32
- # Override negative format if format options is given
30
+ # Override negative format if format options are given
33
31
  defaults[:negative_format] = "-#{opts[:format]}" if opts[:format]
34
32
  defaults.merge!(opts)
35
33
  end
36
34
  end
37
35
 
38
36
  def i18n_opts
39
- # Set International negative format if not exists
37
+ # Set International negative format if it does not exist
40
38
  i18n = i18n_format_options
41
39
  i18n[:negative_format] ||= "-#{i18n[:format]}" if i18n[:format]
42
40
  i18n
@@ -3,7 +3,7 @@ module ActiveSupport
3
3
  class NumberToDelimitedConverter < NumberConverter #:nodoc:
4
4
  self.validate_float = true
5
5
 
6
- DELIMITED_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/
6
+ DEFAULT_DELIMITER_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/
7
7
 
8
8
  def convert
9
9
  parts.join(options[:separator])
@@ -12,12 +12,17 @@ module ActiveSupport
12
12
  private
13
13
 
14
14
  def parts
15
- left, right = number.to_s.split('.')
16
- left.gsub!(DELIMITED_REGEX) do |digit_to_delimit|
15
+ left, right = number.to_s.split('.'.freeze)
16
+ left.gsub!(delimiter_pattern) do |digit_to_delimit|
17
17
  "#{digit_to_delimit}#{options[:delimiter]}"
18
18
  end
19
19
  [left, right].compact
20
20
  end
21
+
22
+ def delimiter_pattern
23
+ options.fetch(:delimiter_pattern, DEFAULT_DELIMITER_REGEX)
24
+ end
25
+
21
26
  end
22
27
  end
23
28
  end
@@ -20,10 +20,12 @@ module ActiveSupport
20
20
  exponent = calculate_exponent(units)
21
21
  @number = number / (10 ** exponent)
22
22
 
23
+ until (rounded_number = NumberToRoundedConverter.convert(number, options)) != NumberToRoundedConverter.convert(1000, options)
24
+ @number = number / 1000.0
25
+ exponent += 3
26
+ end
23
27
  unit = determine_unit(units, exponent)
24
-
25
- rounded_number = NumberToRoundedConverter.convert(number, options)
26
- format.gsub(/%n/, rounded_number).gsub(/%u/, unit).strip
28
+ format.gsub('%n'.freeze, rounded_number).gsub('%u'.freeze, unit).strip
27
29
  end
28
30
 
29
31
  private
@@ -59,7 +61,7 @@ module ActiveSupport
59
61
  translate_in_locale("human.decimal_units.units", raise: true)
60
62
  else
61
63
  raise ArgumentError, ":units must be a Hash or String translation scope."
62
- end.keys.map { |e_name| INVERTED_DECIMAL_UNITS[e_name] }.sort_by { |e| -e }
64
+ end.keys.map { |e_name| INVERTED_DECIMAL_UNITS[e_name] }.sort_by(&:-@)
63
65
  end
64
66
  end
65
67
  end
@@ -1,12 +1,16 @@
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
8
8
 
9
9
  def convert
10
+ if opts.key?(:prefix)
11
+ ActiveSupport::Deprecation.warn('The :prefix option of `number_to_human_size` is deprecated and will be removed in Rails 5.1 with no replacement.')
12
+ end
13
+
10
14
  @number = Float(number)
11
15
 
12
16
  # for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
@@ -20,7 +24,7 @@ module ActiveSupport
20
24
  human_size = number / (base ** exponent)
21
25
  number_to_format = NumberToRoundedConverter.convert(human_size, options)
22
26
  end
23
- conversion_format.gsub(/%n/, number_to_format).gsub(/%u/, unit)
27
+ conversion_format.gsub('%n'.freeze, number_to_format).gsub('%u'.freeze, unit)
24
28
  end
25
29
 
26
30
  private
@@ -5,7 +5,7 @@ module ActiveSupport
5
5
 
6
6
  def convert
7
7
  rounded_number = NumberToRoundedConverter.convert(number, options)
8
- options[:format].gsub(/%n/, rounded_number)
8
+ options[:format].gsub('%n'.freeze, rounded_number)
9
9
  end
10
10
  end
11
11
  end
@@ -18,12 +18,16 @@ module ActiveSupport
18
18
  end
19
19
 
20
20
  def convert_with_area_code(number)
21
- number.gsub!(/(\d{1,3})(\d{3})(\d{4}$)/,"(\\1) \\2#{delimiter}\\3")
21
+ default_pattern = /(\d{1,3})(\d{3})(\d{4}$)/
22
+ number.gsub!(regexp_pattern(default_pattern),
23
+ "(\\1) \\2#{delimiter}\\3")
22
24
  number
23
25
  end
24
26
 
25
27
  def convert_without_area_code(number)
26
- number.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
28
+ default_pattern = /(\d{0,3})(\d{3})(\d{4})$/
29
+ number.gsub!(regexp_pattern(default_pattern),
30
+ "\\1#{delimiter}\\2#{delimiter}\\3")
27
31
  number.slice!(0, 1) if start_with_delimiter?(number)
28
32
  number
29
33
  end
@@ -43,6 +47,11 @@ module ActiveSupport
43
47
  def phone_ext(ext)
44
48
  ext.blank? ? "" : " x #{ext}"
45
49
  end
50
+
51
+ def regexp_pattern(default_pattern)
52
+ opts.fetch :pattern, default_pattern
53
+ end
54
+
46
55
  end
47
56
  end
48
57
  end
@@ -6,36 +6,41 @@ module ActiveSupport
6
6
 
7
7
  def convert
8
8
  precision = options.delete :precision
9
- significant = options.delete :significant
10
9
 
11
- case number
12
- when Float, String
13
- @number = BigDecimal(number.to_s)
14
- when Rational
15
- @number = BigDecimal(number, digit_count(number.to_i) + precision)
16
- else
17
- @number = number.to_d
18
- end
19
-
20
- if significant && precision > 0
21
- digits, rounded_number = digits_and_rounded_number(precision)
22
- precision -= digits
23
- precision = 0 if precision < 0 # don't let it be negative
24
- else
25
- rounded_number = number.round(precision)
26
- rounded_number = rounded_number.to_i if precision == 0
27
- rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros
28
- end
10
+ if precision
11
+ case number
12
+ when Float, String
13
+ @number = BigDecimal(number.to_s)
14
+ when Rational
15
+ @number = BigDecimal(number, digit_count(number.to_i) + precision)
16
+ else
17
+ @number = number.to_d
18
+ end
29
19
 
30
- formatted_string =
31
- if BigDecimal === rounded_number && rounded_number.finite?
32
- s = rounded_number.to_s('F') + '0'*precision
33
- a, b = s.split('.', 2)
34
- a + '.' + b[0, precision]
20
+ if options.delete(:significant) && precision > 0
21
+ digits, rounded_number = digits_and_rounded_number(precision)
22
+ precision -= digits
23
+ precision = 0 if precision < 0 # don't let it be negative
35
24
  else
36
- "%00.#{precision}f" % rounded_number
25
+ rounded_number = number.round(precision)
26
+ rounded_number = rounded_number.to_i if precision == 0 && rounded_number.finite?
27
+ rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros
37
28
  end
38
29
 
30
+ formatted_string =
31
+ if BigDecimal === rounded_number && rounded_number.finite?
32
+ s = rounded_number.to_s('F')
33
+ s << '0'.freeze * precision
34
+ a, b = s.split('.'.freeze, 2)
35
+ a << '.'.freeze
36
+ a << b[0, precision]
37
+ else
38
+ "%00.#{precision}f" % rounded_number
39
+ end
40
+ else
41
+ formatted_string = number
42
+ end
43
+
39
44
  delimited_number = NumberToDelimitedConverter.convert(formatted_string, options)
40
45
  format_number(delimited_number)
41
46
  end