activesupport 4.2.11.3 → 5.0.7.2

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 (182) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +678 -348
  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/strategy/local_cache_middleware.rb +4 -4
  14. data/lib/active_support/cache.rb +71 -87
  15. data/lib/active_support/callbacks.rb +109 -113
  16. data/lib/active_support/concern.rb +1 -1
  17. data/lib/active_support/concurrency/latch.rb +11 -12
  18. data/lib/active_support/concurrency/share_lock.rb +226 -0
  19. data/lib/active_support/configurable.rb +1 -0
  20. data/lib/active_support/core_ext/array/access.rb +27 -1
  21. data/lib/active_support/core_ext/array/conversions.rb +6 -4
  22. data/lib/active_support/core_ext/array/grouping.rb +9 -18
  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/array.rb +1 -0
  26. data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -10
  27. data/lib/active_support/core_ext/class/attribute.rb +10 -9
  28. data/lib/active_support/core_ext/class/subclasses.rb +3 -2
  29. data/lib/active_support/core_ext/class.rb +0 -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 +7 -6
  33. data/lib/active_support/core_ext/date.rb +1 -1
  34. data/lib/active_support/core_ext/date_and_time/calculations.rb +100 -27
  35. data/lib/active_support/core_ext/date_and_time/compatibility.rb +0 -1
  36. data/lib/active_support/core_ext/date_and_time/zones.rb +3 -4
  37. data/lib/active_support/core_ext/date_time/blank.rb +12 -0
  38. data/lib/active_support/core_ext/date_time/calculations.rb +14 -8
  39. data/lib/active_support/core_ext/date_time/conversions.rb +2 -0
  40. data/lib/active_support/core_ext/date_time.rb +1 -1
  41. data/lib/active_support/core_ext/enumerable.rb +75 -25
  42. data/lib/active_support/core_ext/file/atomic.rb +30 -25
  43. data/lib/active_support/core_ext/hash/conversions.rb +22 -2
  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 +25 -21
  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 +2 -2
  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 -84
  54. data/lib/active_support/core_ext/kernel.rb +0 -1
  55. data/lib/active_support/core_ext/load_error.rb +5 -2
  56. data/lib/active_support/core_ext/marshal.rb +7 -9
  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 +11 -20
  64. data/lib/active_support/core_ext/module/deprecation.rb +2 -2
  65. data/lib/active_support/core_ext/module/introspection.rb +8 -2
  66. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -13
  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 +78 -77
  73. data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
  74. data/lib/active_support/core_ext/numeric/time.rb +26 -6
  75. data/lib/active_support/core_ext/numeric.rb +1 -0
  76. data/lib/active_support/core_ext/object/blank.rb +15 -3
  77. data/lib/active_support/core_ext/object/deep_dup.rb +10 -3
  78. data/lib/active_support/core_ext/object/duplicable.rb +7 -12
  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 +67 -21
  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/behavior.rb +1 -1
  91. data/lib/active_support/core_ext/string/conversions.rb +3 -2
  92. data/lib/active_support/core_ext/string/filters.rb +1 -2
  93. data/lib/active_support/core_ext/string/inflections.rb +32 -5
  94. data/lib/active_support/core_ext/string/multibyte.rb +11 -7
  95. data/lib/active_support/core_ext/string/output_safety.rb +12 -14
  96. data/lib/active_support/core_ext/string/strip.rb +3 -6
  97. data/lib/active_support/core_ext/struct.rb +3 -6
  98. data/lib/active_support/core_ext/time/calculations.rb +18 -9
  99. data/lib/active_support/core_ext/time/conversions.rb +4 -2
  100. data/lib/active_support/core_ext/time/marshal.rb +2 -29
  101. data/lib/active_support/core_ext/time/zones.rb +36 -4
  102. data/lib/active_support/core_ext/time.rb +0 -1
  103. data/lib/active_support/core_ext/uri.rb +1 -3
  104. data/lib/active_support/core_ext.rb +2 -1
  105. data/lib/active_support/dependencies/interlock.rb +55 -0
  106. data/lib/active_support/dependencies.rb +88 -95
  107. data/lib/active_support/deprecation/behaviors.rb +15 -1
  108. data/lib/active_support/deprecation/instance_delegator.rb +13 -0
  109. data/lib/active_support/deprecation/method_wrappers.rb +42 -16
  110. data/lib/active_support/deprecation/proxy_wrappers.rb +47 -24
  111. data/lib/active_support/deprecation/reporting.rb +23 -5
  112. data/lib/active_support/deprecation.rb +1 -1
  113. data/lib/active_support/duration/iso8601_parser.rb +122 -0
  114. data/lib/active_support/duration/iso8601_serializer.rb +51 -0
  115. data/lib/active_support/duration.rb +90 -15
  116. data/lib/active_support/evented_file_update_checker.rb +199 -0
  117. data/lib/active_support/execution_wrapper.rb +126 -0
  118. data/lib/active_support/executor.rb +6 -0
  119. data/lib/active_support/file_update_checker.rb +23 -3
  120. data/lib/active_support/gem_version.rb +5 -5
  121. data/lib/active_support/gzip.rb +1 -1
  122. data/lib/active_support/hash_with_indifferent_access.rb +40 -11
  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 +1 -51
  129. data/lib/active_support/key_generator.rb +7 -9
  130. data/lib/active_support/lazy_load_hooks.rb +46 -18
  131. data/lib/active_support/locale/en.yml +2 -0
  132. data/lib/active_support/log_subscriber/test_helper.rb +3 -3
  133. data/lib/active_support/log_subscriber.rb +1 -1
  134. data/lib/active_support/logger.rb +3 -4
  135. data/lib/active_support/logger_silence.rb +2 -1
  136. data/lib/active_support/logger_thread_safe_level.rb +2 -3
  137. data/lib/active_support/message_encryptor.rb +7 -7
  138. data/lib/active_support/message_verifier.rb +70 -8
  139. data/lib/active_support/multibyte/chars.rb +12 -3
  140. data/lib/active_support/multibyte/unicode.rb +44 -21
  141. data/lib/active_support/notifications/fanout.rb +5 -5
  142. data/lib/active_support/notifications/instrumenter.rb +20 -2
  143. data/lib/active_support/notifications.rb +2 -2
  144. data/lib/active_support/number_helper/number_to_currency_converter.rb +7 -9
  145. data/lib/active_support/number_helper/number_to_delimited_converter.rb +8 -3
  146. data/lib/active_support/number_helper/number_to_human_converter.rb +6 -4
  147. data/lib/active_support/number_helper/number_to_human_size_converter.rb +6 -2
  148. data/lib/active_support/number_helper/number_to_percentage_converter.rb +1 -1
  149. data/lib/active_support/number_helper/number_to_phone_converter.rb +11 -2
  150. data/lib/active_support/number_helper/number_to_rounded_converter.rb +30 -25
  151. data/lib/active_support/number_helper.rb +90 -67
  152. data/lib/active_support/ordered_hash.rb +1 -1
  153. data/lib/active_support/ordered_options.rb +15 -1
  154. data/lib/active_support/per_thread_registry.rb +3 -0
  155. data/lib/active_support/rails.rb +2 -2
  156. data/lib/active_support/railtie.rb +6 -1
  157. data/lib/active_support/reloader.rb +129 -0
  158. data/lib/active_support/rescuable.rb +101 -47
  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 +8 -7
  162. data/lib/active_support/test_case.rb +17 -29
  163. data/lib/active_support/testing/assertions.rb +15 -13
  164. data/lib/active_support/testing/deprecation.rb +9 -8
  165. data/lib/active_support/testing/file_fixtures.rb +34 -0
  166. data/lib/active_support/testing/isolation.rb +22 -8
  167. data/lib/active_support/testing/method_call_assertions.rb +41 -0
  168. data/lib/active_support/testing/stream.rb +42 -0
  169. data/lib/active_support/testing/time_helpers.rb +3 -1
  170. data/lib/active_support/time_with_zone.rb +123 -33
  171. data/lib/active_support/values/time_zone.rb +101 -47
  172. data/lib/active_support/values/unicode_tables.dat +0 -0
  173. data/lib/active_support/xml_mini/jdom.rb +1 -1
  174. data/lib/active_support/xml_mini/libxml.rb +2 -2
  175. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  176. data/lib/active_support.rb +11 -6
  177. metadata +36 -17
  178. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
  179. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  180. data/lib/active_support/core_ext/date_time/zones.rb +0 -6
  181. data/lib/active_support/core_ext/object/itself.rb +0 -15
  182. data/lib/active_support/core_ext/thread.rb +0 -86
@@ -1,19 +1,31 @@
1
- class Range
1
+ module ActiveSupport::RangeWithFormat
2
2
  RANGE_FORMATS = {
3
3
  :db => Proc.new { |start, stop| "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'" }
4
4
  }
5
5
 
6
- # Gives a human readable format of the range.
6
+ # Convert range to a formatted string. See RANGE_FORMATS for predefined formats.
7
7
  #
8
- # (1..100).to_formatted_s # => "1..100"
9
- def to_formatted_s(format = :default)
8
+ # range = (1..100) # => 1..100
9
+ #
10
+ # range.to_s # => "1..100"
11
+ # range.to_s(:db) # => "BETWEEN '1' AND '100'"
12
+ #
13
+ # == Adding your own range formats to to_s
14
+ # You can add your own formats to the Range::RANGE_FORMATS hash.
15
+ # Use the format name as the hash key and a Proc instance.
16
+ #
17
+ # # config/initializers/range_formats.rb
18
+ # Range::RANGE_FORMATS[:short] = ->(start, stop) { "Between #{start.to_s(:db)} and #{stop.to_s(:db)}" }
19
+ def to_s(format = :default)
10
20
  if formatter = RANGE_FORMATS[format]
11
21
  formatter.call(first, last)
12
22
  else
13
- to_default_s
23
+ super()
14
24
  end
15
25
  end
16
26
 
17
27
  alias_method :to_default_s, :to_s
18
- alias_method :to_s, :to_formatted_s
28
+ alias_method :to_formatted_s, :to_s
19
29
  end
30
+
31
+ Range.prepend(ActiveSupport::RangeWithFormat)
@@ -1,23 +1,21 @@
1
- require 'active_support/core_ext/module/aliasing'
1
+ module ActiveSupport
2
+ module EachTimeWithZone #:nodoc:
3
+ def each(&block)
4
+ ensure_iteration_allowed
5
+ super
6
+ end
2
7
 
3
- class Range #:nodoc:
8
+ def step(n = 1, &block)
9
+ ensure_iteration_allowed
10
+ super
11
+ end
4
12
 
5
- def each_with_time_with_zone(&block)
6
- ensure_iteration_allowed
7
- each_without_time_with_zone(&block)
8
- end
9
- alias_method_chain :each, :time_with_zone
13
+ private
10
14
 
11
- def step_with_time_with_zone(n = 1, &block)
12
- ensure_iteration_allowed
13
- step_without_time_with_zone(n, &block)
14
- end
15
- alias_method_chain :step, :time_with_zone
16
-
17
- private
18
- def ensure_iteration_allowed
19
- if first.is_a?(Time)
20
- raise TypeError, "can't iterate from #{first.class}"
21
- end
15
+ def ensure_iteration_allowed
16
+ raise TypeError, "can't iterate from #{first.class}" if first.is_a?(Time)
17
+ end
22
18
  end
23
19
  end
20
+
21
+ Range.prepend(ActiveSupport::EachTimeWithZone)
@@ -1,23 +1,23 @@
1
- require 'active_support/core_ext/module/aliasing'
2
-
3
- class Range
4
- # Extends the default Range#include? to support range comparisons.
5
- # (1..5).include?(1..5) # => true
6
- # (1..5).include?(2..3) # => true
7
- # (1..5).include?(2..6) # => false
8
- #
9
- # The native Range#include? behavior is untouched.
10
- # ('a'..'f').include?('c') # => true
11
- # (5..9).include?(11) # => false
12
- def include_with_range?(value)
13
- if value.is_a?(::Range)
14
- # 1...10 includes 1..9 but it does not include 1..10.
15
- operator = exclude_end? && !value.exclude_end? ? :< : :<=
16
- include_without_range?(value.first) && value.last.send(operator, last)
17
- else
18
- include_without_range?(value)
1
+ module ActiveSupport
2
+ module IncludeWithRange #:nodoc:
3
+ # Extends the default Range#include? to support range comparisons.
4
+ # (1..5).include?(1..5) # => true
5
+ # (1..5).include?(2..3) # => true
6
+ # (1..5).include?(2..6) # => false
7
+ #
8
+ # The native Range#include? behavior is untouched.
9
+ # ('a'..'f').include?('c') # => true
10
+ # (5..9).include?(11) # => false
11
+ def include?(value)
12
+ if value.is_a?(::Range)
13
+ # 1...10 includes 1..9 but it does not include 1..10.
14
+ operator = exclude_end? && !value.exclude_end? ? :< : :<=
15
+ super(value.first) && value.last.send(operator, last)
16
+ else
17
+ super
18
+ end
19
19
  end
20
20
  end
21
-
22
- alias_method_chain :include?, :range
23
21
  end
22
+
23
+ Range.prepend(ActiveSupport::IncludeWithRange)
@@ -0,0 +1,23 @@
1
+ require 'securerandom'
2
+
3
+ module SecureRandom
4
+ BASE58_ALPHABET = ('0'..'9').to_a + ('A'..'Z').to_a + ('a'..'z').to_a - ['0', 'O', 'I', 'l']
5
+ # SecureRandom.base58 generates a random base58 string.
6
+ #
7
+ # The argument _n_ specifies the length, of the random string to be generated.
8
+ #
9
+ # If _n_ is not specified or is nil, 16 is assumed. It may be larger in the future.
10
+ #
11
+ # The result may contain alphanumeric characters except 0, O, I and l
12
+ #
13
+ # p SecureRandom.base58 # => "4kUgL2pdQMSCQtjE"
14
+ # p SecureRandom.base58(24) # => "77TMHrHJFvFDwodq8w7Ev2m7"
15
+ #
16
+ def self.base58(n = 16)
17
+ SecureRandom.random_bytes(n).unpack("C*").map do |byte|
18
+ idx = byte % 64
19
+ idx = SecureRandom.random_number(58) if idx >= 58
20
+ BASE58_ALPHABET[idx]
21
+ end.join
22
+ end
23
+ end
@@ -1,5 +1,5 @@
1
1
  class String
2
- # Enable more predictable duck-typing on String-like classes. See <tt>Object#acts_like?</tt>.
2
+ # Enables more predictable duck-typing on String-like classes. See <tt>Object#acts_like?</tt>.
3
3
  def acts_like_string?
4
4
  true
5
5
  end
@@ -14,11 +14,12 @@ class String
14
14
  # "06:12".to_time # => 2012-12-13 06:12:00 +0100
15
15
  # "2012-12-13 06:12".to_time # => 2012-12-13 06:12:00 +0100
16
16
  # "2012-12-13T06:12".to_time # => 2012-12-13 06:12:00 +0100
17
- # "2012-12-13T06:12".to_time(:utc) # => 2012-12-13 05:12:00 UTC
17
+ # "2012-12-13T06:12".to_time(:utc) # => 2012-12-13 06:12:00 UTC
18
18
  # "12/13/2012".to_time # => ArgumentError: argument out of range
19
19
  def to_time(form = :local)
20
20
  parts = Date._parse(self, false)
21
- return if parts.empty?
21
+ used_keys = %i(year mon mday hour min sec sec_fraction offset)
22
+ return if (parts.keys & used_keys).empty?
22
23
 
23
24
  now = Time.now
24
25
  time = Time.new(
@@ -17,9 +17,8 @@ class String
17
17
  # str.squish! # => "foo bar boo"
18
18
  # str # => "foo bar boo"
19
19
  def squish!
20
- gsub!(/\A[[:space:]]+/, '')
21
- gsub!(/[[:space:]]+\z/, '')
22
20
  gsub!(/[[:space:]]+/, ' ')
21
+ strip!
23
22
  self
24
23
  end
25
24
 
@@ -164,25 +164,43 @@ class String
164
164
  #
165
165
  # <%= link_to(@person.name, person_path) %>
166
166
  # # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a>
167
- def parameterize(sep = '-')
168
- ActiveSupport::Inflector.parameterize(self, sep)
167
+ #
168
+ # To preserve the case of the characters in a string, use the `preserve_case` argument.
169
+ #
170
+ # class Person
171
+ # def to_param
172
+ # "#{id}-#{name.parameterize(preserve_case: true)}"
173
+ # end
174
+ # end
175
+ #
176
+ # @person = Person.find(1)
177
+ # # => #<Person id: 1, name: "Donald E. Knuth">
178
+ #
179
+ # <%= link_to(@person.name, person_path) %>
180
+ # # => <a href="/person/1-Donald-E-Knuth">Donald E. Knuth</a>
181
+ def parameterize(sep = :unused, separator: '-', preserve_case: false)
182
+ unless sep == :unused
183
+ ActiveSupport::Deprecation.warn("Passing the separator argument as a positional parameter is deprecated and will soon be removed. Use `separator: '#{sep}'` instead.")
184
+ separator = sep
185
+ end
186
+ ActiveSupport::Inflector.parameterize(self, separator: separator, preserve_case: preserve_case)
169
187
  end
170
188
 
171
189
  # Creates the name of a table like Rails does for models to table names. This method
172
190
  # uses the +pluralize+ method on the last word in the string.
173
191
  #
174
192
  # 'RawScaledScorer'.tableize # => "raw_scaled_scorers"
175
- # 'egg_and_ham'.tableize # => "egg_and_hams"
193
+ # 'ham_and_egg'.tableize # => "ham_and_eggs"
176
194
  # 'fancyCategory'.tableize # => "fancy_categories"
177
195
  def tableize
178
196
  ActiveSupport::Inflector.tableize(self)
179
197
  end
180
198
 
181
- # Create a class name from a plural table name like Rails does for table names to models.
199
+ # Creates a class name from a plural table name like Rails does for table names to models.
182
200
  # Note that this returns a string and not a class. (To convert to an actual class
183
201
  # follow +classify+ with +constantize+.)
184
202
  #
185
- # 'egg_and_hams'.classify # => "EggAndHam"
203
+ # 'ham_and_eggs'.classify # => "HamAndEgg"
186
204
  # 'posts'.classify # => "Post"
187
205
  def classify
188
206
  ActiveSupport::Inflector.classify(self)
@@ -204,6 +222,15 @@ class String
204
222
  ActiveSupport::Inflector.humanize(self, options)
205
223
  end
206
224
 
225
+ # Converts just the first character to uppercase.
226
+ #
227
+ # 'what a Lovely Day'.upcase_first # => "What a Lovely Day"
228
+ # 'w'.upcase_first # => "W"
229
+ # ''.upcase_first # => ""
230
+ def upcase_first
231
+ ActiveSupport::Inflector.upcase_first(self)
232
+ end
233
+
207
234
  # Creates a foreign key name from a class name.
208
235
  # +separate_class_name_and_id_with_underscore+ sets whether
209
236
  # the method should put '_' between the name and 'id'.
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  require 'active_support/multibyte'
3
2
 
4
3
  class String
@@ -10,12 +9,10 @@ class String
10
9
  # encapsulates the original string. A Unicode safe version of all the String methods are defined on this proxy
11
10
  # class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsulated string.
12
11
  #
13
- # name = 'Claus Müller'
14
- # name.reverse # => "rell??M sualC"
15
- # name.length # => 13
16
- #
17
- # name.mb_chars.reverse.to_s # => "rellüM sualC"
18
- # name.mb_chars.length # => 12
12
+ # >> "lj".upcase
13
+ # => "lj"
14
+ # >> "lj".mb_chars.upcase.to_s
15
+ # => "LJ"
19
16
  #
20
17
  # == Method chaining
21
18
  #
@@ -36,6 +33,13 @@ class String
36
33
  ActiveSupport::Multibyte.proxy_class.new(self)
37
34
  end
38
35
 
36
+ # Returns +true+ if string has utf_8 encoding.
37
+ #
38
+ # utf_8_str = "some string".encode "UTF-8"
39
+ # iso_str = "some string".encode "ISO-8859-1"
40
+ #
41
+ # utf_8_str.is_utf8? # => true
42
+ # iso_str.is_utf8? # => false
39
43
  def is_utf8?
40
44
  case encoding
41
45
  when Encoding::UTF_8
@@ -1,12 +1,10 @@
1
1
  require 'erb'
2
2
  require 'active_support/core_ext/kernel/singleton_class'
3
- require 'active_support/deprecation'
4
3
 
5
4
  class ERB
6
5
  module Util
7
6
  HTML_ESCAPE = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;', "'" => '&#39;' }
8
7
  JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003e', '<' => '\u003c', "\u2028" => '\u2028', "\u2029" => '\u2029' }
9
- HTML_ESCAPE_REGEXP = /[&"'><]/
10
8
  HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
11
9
  JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u
12
10
 
@@ -14,7 +12,7 @@ class ERB
14
12
  # This method is also aliased as <tt>h</tt>.
15
13
  #
16
14
  # In your ERB templates, use this method to escape any unsafe content. For example:
17
- # <%=h @person.name %>
15
+ # <%= h @person.name %>
18
16
  #
19
17
  # puts html_escape('is a > 0 & a < 10?')
20
18
  # # => is a &gt; 0 &amp; a &lt; 10?
@@ -38,7 +36,7 @@ class ERB
38
36
  if s.html_safe?
39
37
  s
40
38
  else
41
- s.gsub(HTML_ESCAPE_REGEXP, HTML_ESCAPE)
39
+ CGI.escapeHTML(ActiveSupport::Multibyte::Unicode.tidy_bytes(s))
42
40
  end
43
41
  end
44
42
  module_function :unwrapped_html_escape
@@ -51,7 +49,7 @@ class ERB
51
49
  # html_escape_once('&lt;&lt; Accept & Checkout')
52
50
  # # => "&lt;&lt; Accept &amp; Checkout"
53
51
  def html_escape_once(s)
54
- result = s.to_s.gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE)
52
+ result = ActiveSupport::Multibyte::Unicode.tidy_bytes(s.to_s).gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE)
55
53
  s.html_safe? ? result.html_safe : result
56
54
  end
57
55
 
@@ -86,6 +84,11 @@ class ERB
86
84
  # automatically flag the result as HTML safe, since the raw value is unsafe to
87
85
  # use inside HTML attributes.
88
86
  #
87
+ # If your JSON is being used downstream for insertion into the DOM, be aware of
88
+ # whether or not it is being inserted via +html()+. Most jQuery plugins do this.
89
+ # If that is the case, be sure to +html_escape+ or +sanitize+ any user-generated
90
+ # content returned by your JSON.
91
+ #
89
92
  # If you need to output JSON elsewhere in your HTML, you can just do something
90
93
  # like this, as any unsafe characters (including quotation marks) will be
91
94
  # automatically escaped for you:
@@ -138,6 +141,7 @@ module ActiveSupport #:nodoc:
138
141
  alias_method :original_concat, :concat
139
142
  private :original_concat
140
143
 
144
+ # Raised when <tt>ActiveSupport::SafeBuffer#safe_concat</tt> is called on unsafe buffers.
141
145
  class SafeConcatError < StandardError
142
146
  def initialize
143
147
  super 'Could not concatenate to the buffer because it is not html safe.'
@@ -167,7 +171,7 @@ module ActiveSupport #:nodoc:
167
171
  original_concat(value)
168
172
  end
169
173
 
170
- def initialize(*)
174
+ def initialize(str = '')
171
175
  @html_safe = true
172
176
  super
173
177
  end
@@ -190,11 +194,6 @@ module ActiveSupport #:nodoc:
190
194
  super(html_escape_interpolated_argument(value))
191
195
  end
192
196
 
193
- def prepend!(value)
194
- ActiveSupport::Deprecation.deprecation_warning "ActiveSupport::SafeBuffer#prepend!", :prepend
195
- prepend value
196
- end
197
-
198
197
  def +(other)
199
198
  dup.concat(other)
200
199
  end
@@ -244,15 +243,14 @@ module ActiveSupport #:nodoc:
244
243
  private
245
244
 
246
245
  def html_escape_interpolated_argument(arg)
247
- (!html_safe? || arg.html_safe?) ? arg :
248
- 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)
249
247
  end
250
248
  end
251
249
  end
252
250
 
253
251
  class String
254
252
  # Marks a string as trusted safe. It will be inserted into HTML with no
255
- # additional escaping performed. It is your responsibilty to ensure that the
253
+ # additional escaping performed. It is your responsibility to ensure that the
256
254
  # string contains no malicious content. This method is equivalent to the
257
255
  # `raw` helper in views. It is recommended that you use `sanitize` instead of
258
256
  # this method. It should never be called on user input.
@@ -1,5 +1,3 @@
1
- require 'active_support/core_ext/object/try'
2
-
3
1
  class String
4
2
  # Strips indentation in heredocs.
5
3
  #
@@ -17,10 +15,9 @@ class String
17
15
  #
18
16
  # the user would see the usage message aligned against the left margin.
19
17
  #
20
- # Technically, it looks for the least indented line in the whole string, and removes
21
- # that amount of leading whitespace.
18
+ # Technically, it looks for the least indented non-empty line
19
+ # in the whole string, and removes that amount of leading whitespace.
22
20
  def strip_heredoc
23
- indent = scan(/^[ \t]*(?=\S)/).min.try(:size) || 0
24
- gsub(/^[ \t]{#{indent}}/, '')
21
+ gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, ''.freeze)
25
22
  end
26
23
  end
@@ -1,6 +1,3 @@
1
- # Backport of Struct#to_h from Ruby 2.0
2
- class Struct # :nodoc:
3
- def to_h
4
- Hash[members.zip(values)]
5
- end
6
- end unless Struct.instance_methods.include?(:to_h)
1
+ require 'active_support/deprecation'
2
+
3
+ ActiveSupport::Deprecation.warn("This file is deprecated and will be removed in Rails 5.1 with no replacement.")
@@ -16,9 +16,9 @@ class Time
16
16
  super || (self == Time && other.is_a?(ActiveSupport::TimeWithZone))
17
17
  end
18
18
 
19
- # Return the number of days in the given month.
19
+ # Returns the number of days in the given month.
20
20
  # If no year is specified, it will use the current year.
21
- def days_in_month(month, year = now.year)
21
+ def days_in_month(month, year = current.year)
22
22
  if month == 2 && ::Date.gregorian_leap?(year)
23
23
  29
24
24
  else
@@ -26,6 +26,12 @@ class Time
26
26
  end
27
27
  end
28
28
 
29
+ # Returns the number of days in the given year.
30
+ # If no year is specified, it will use the current year.
31
+ def days_in_year(year = current.year)
32
+ days_in_month(2, year) + 337
33
+ end
34
+
29
35
  # Returns <tt>Time.zone.now</tt> when <tt>Time.zone</tt> or <tt>config.time_zone</tt> are set, otherwise just returns <tt>Time.now</tt>.
30
36
  def current
31
37
  ::Time.zone ? ::Time.zone.now : ::Time.now
@@ -49,7 +55,11 @@ class Time
49
55
  alias_method :at, :at_with_coercion
50
56
  end
51
57
 
52
- # Seconds since midnight: Time.now.seconds_since_midnight
58
+ # Returns the number of seconds since 00:00:00.
59
+ #
60
+ # Time.new(2012, 8, 29, 0, 0, 0).seconds_since_midnight # => 0.0
61
+ # Time.new(2012, 8, 29, 12, 34, 56).seconds_since_midnight # => 45296.0
62
+ # Time.new(2012, 8, 29, 23, 59, 59).seconds_since_midnight # => 86399.0
53
63
  def seconds_since_midnight
54
64
  to_i - change(:hour => 0).to_i + (usec / 1.0e+6)
55
65
  end
@@ -77,7 +87,7 @@ class Time
77
87
  # and minute is passed, then sec, usec and nsec is set to 0. The +options+
78
88
  # parameter takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>,
79
89
  # <tt>:day</tt>, <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>
80
- # <tt>:nsec</tt>. Path either <tt>:usec</tt> or <tt>:nsec</tt>, not both.
90
+ # <tt>:nsec</tt>. Pass either <tt>:usec</tt> or <tt>:nsec</tt>, not both.
81
91
  #
82
92
  # Time.new(2012, 8, 29, 22, 35, 0).change(day: 1) # => Time.new(2012, 8, 1, 22, 35, 0)
83
93
  # Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, day: 1) # => Time.new(1981, 8, 1, 22, 35, 0)
@@ -159,7 +169,6 @@ class Time
159
169
 
160
170
  # Returns a new Time representing the start of the day (0:00)
161
171
  def beginning_of_day
162
- #(self - seconds_since_midnight).change(usec: 0)
163
172
  change(:hour => 0)
164
173
  end
165
174
  alias :midnight :beginning_of_day
@@ -176,7 +185,7 @@ class Time
176
185
  alias :at_noon :middle_of_day
177
186
  alias :at_middle_of_day :middle_of_day
178
187
 
179
- # Returns a new Time representing the end of the day, 23:59:59.999999 (.999999999 in ruby1.9)
188
+ # Returns a new Time representing the end of the day, 23:59:59.999999
180
189
  def end_of_day
181
190
  change(
182
191
  :hour => 23,
@@ -193,7 +202,7 @@ class Time
193
202
  end
194
203
  alias :at_beginning_of_hour :beginning_of_hour
195
204
 
196
- # Returns a new Time representing the end of the hour, x:59:59.999999 (.999999999 in ruby1.9)
205
+ # Returns a new Time representing the end of the hour, x:59:59.999999
197
206
  def end_of_hour
198
207
  change(
199
208
  :min => 59,
@@ -209,7 +218,7 @@ class Time
209
218
  end
210
219
  alias :at_beginning_of_minute :beginning_of_minute
211
220
 
212
- # Returns a new Time representing the end of the minute, x:xx:59.999999 (.999999999 in ruby1.9)
221
+ # Returns a new Time representing the end of the minute, x:xx:59.999999
213
222
  def end_of_minute
214
223
  change(
215
224
  :sec => 59,
@@ -256,7 +265,7 @@ class Time
256
265
  # Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances
257
266
  # can be chronologically compared with a Time
258
267
  def compare_with_coercion(other)
259
- # we're avoiding Time#to_datetime cause it's expensive
268
+ # we're avoiding Time#to_datetime and Time#to_time because they're expensive
260
269
  if other.class == Time
261
270
  compare_without_coercion(other)
262
271
  elsif other.is_a?(Time)
@@ -6,6 +6,7 @@ class Time
6
6
  :db => '%Y-%m-%d %H:%M:%S',
7
7
  :number => '%Y%m%d%H%M%S',
8
8
  :nsec => '%Y%m%d%H%M%S%9N',
9
+ :usec => '%Y%m%d%H%M%S%6N',
9
10
  :time => '%H:%M',
10
11
  :short => '%d %b %H:%M',
11
12
  :long => '%B %d, %Y %H:%M',
@@ -24,7 +25,7 @@ class Time
24
25
  #
25
26
  # This method is aliased to <tt>to_s</tt>.
26
27
  #
27
- # time = Time.now # => Thu Jan 18 06:10:17 CST 2007
28
+ # time = Time.now # => 2007-01-18 06:10:17 -06:00
28
29
  #
29
30
  # time.to_formatted_s(:time) # => "06:10"
30
31
  # time.to_s(:time) # => "06:10"
@@ -55,7 +56,8 @@ class Time
55
56
  alias_method :to_default_s, :to_s
56
57
  alias_method :to_s, :to_formatted_s
57
58
 
58
- # Returns the UTC offset as an +HH:MM formatted string.
59
+ # Returns a formatted string of the offset from UTC, or an alternative
60
+ # string if the time zone is already UTC.
59
61
  #
60
62
  # Time.local(2000).formatted_offset # => "-06:00"
61
63
  # Time.local(2000).formatted_offset(false) # => "-0600"
@@ -1,30 +1,3 @@
1
- # Ruby 1.9.2 adds utc_offset and zone to Time, but marshaling only
2
- # preserves utc_offset. Preserve zone also, even though it may not
3
- # work in some edge cases.
4
- if Time.local(2010).zone != Marshal.load(Marshal.dump(Time.local(2010))).zone
5
- class Time
6
- class << self
7
- alias_method :_load_without_zone, :_load
8
- def _load(marshaled_time)
9
- time = _load_without_zone(marshaled_time)
10
- time.instance_eval do
11
- if zone = defined?(@_zone) && remove_instance_variable('@_zone')
12
- ary = to_a
13
- ary[0] += subsec if ary[0] == sec
14
- ary[-1] = zone
15
- utc? ? Time.utc(*ary) : Time.local(*ary)
16
- else
17
- self
18
- end
19
- end
20
- end
21
- end
1
+ require 'active_support/deprecation'
22
2
 
23
- alias_method :_dump_without_zone, :_dump
24
- def _dump(*args)
25
- obj = dup
26
- obj.instance_variable_set('@_zone', zone)
27
- obj.send :_dump_without_zone, *args
28
- end
29
- end
30
- end
3
+ ActiveSupport::Deprecation.warn("This is deprecated and will be removed in Rails 5.1 with no replacement.")
@@ -26,7 +26,7 @@ class Time
26
26
  # <tt>current_user.time_zone</tt> just needs to return a string identifying the user's preferred time zone:
27
27
  #
28
28
  # class ApplicationController < ActionController::Base
29
- # around_filter :set_time_zone
29
+ # around_action :set_time_zone
30
30
  #
31
31
  # def set_time_zone
32
32
  # if logged_in?
@@ -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
@@ -51,12 +67,22 @@ class Time
51
67
  end
52
68
  end
53
69
 
54
- # Returns a TimeZone instance or nil, or raises an ArgumentError for invalid timezones.
70
+ # Returns a TimeZone instance matching the time zone provided.
71
+ # Accepts the time zone in any format supported by <tt>Time.zone=</tt>.
72
+ # Raises an +ArgumentError+ for invalid time zones.
73
+ #
74
+ # Time.find_zone! "America/New_York" # => #<ActiveSupport::TimeZone @name="America/New_York" ...>
75
+ # Time.find_zone! "EST" # => #<ActiveSupport::TimeZone @name="EST" ...>
76
+ # Time.find_zone! -5.hours # => #<ActiveSupport::TimeZone @name="Bogota" ...>
77
+ # Time.find_zone! nil # => nil
78
+ # Time.find_zone! false # => false
79
+ # Time.find_zone! "NOT-A-TIMEZONE" # => ArgumentError: Invalid Timezone: NOT-A-TIMEZONE
55
80
  def find_zone!(time_zone)
56
81
  if !time_zone || time_zone.is_a?(ActiveSupport::TimeZone)
57
82
  time_zone
58
83
  else
59
- # lookup timezone based on identifier (unless we've been passed a TZInfo::Timezone)
84
+ # Look up the timezone based on the identifier (unless we've been
85
+ # passed a TZInfo::Timezone)
60
86
  unless time_zone.respond_to?(:period_for_local)
61
87
  time_zone = ActiveSupport::TimeZone[time_zone] || TZInfo::Timezone.get(time_zone)
62
88
  end
@@ -72,6 +98,12 @@ class Time
72
98
  raise ArgumentError, "Invalid Timezone: #{time_zone}"
73
99
  end
74
100
 
101
+ # Returns a TimeZone instance matching the time zone provided.
102
+ # Accepts the time zone in any format supported by <tt>Time.zone=</tt>.
103
+ # Returns +nil+ for invalid time zones.
104
+ #
105
+ # Time.find_zone "America/New_York" # => #<ActiveSupport::TimeZone @name="America/New_York" ...>
106
+ # Time.find_zone "NOT-A-TIMEZONE" # => nil
75
107
  def find_zone(time_zone)
76
108
  find_zone!(time_zone) rescue nil
77
109
  end
@@ -2,5 +2,4 @@ require 'active_support/core_ext/time/acts_like'
2
2
  require 'active_support/core_ext/time/calculations'
3
3
  require 'active_support/core_ext/time/compatibility'
4
4
  require 'active_support/core_ext/time/conversions'
5
- require 'active_support/core_ext/time/marshal'
6
5
  require 'active_support/core_ext/time/zones'
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  require 'uri'
4
2
  str = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E" # Ni-ho-nn-go in UTF-8, means Japanese.
5
3
  parser = URI::Parser.new
@@ -12,7 +10,7 @@ unless str == parser.unescape(parser.escape(str))
12
10
  # YK: My initial experiments say yes, but let's be sure please
13
11
  enc = str.encoding
14
12
  enc = Encoding::UTF_8 if enc == Encoding::US_ASCII
15
- str.gsub(escaped) { [$&[1, 2].hex].pack('C') }.force_encoding(enc)
13
+ str.gsub(escaped) { |match| [match[1, 2].hex].pack('C') }.force_encoding(enc)
16
14
  end
17
15
  end
18
16
  end