activesupport 4.2.0 → 4.2.10

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +280 -0
  3. data/lib/active_support/cache/mem_cache_store.rb +1 -1
  4. data/lib/active_support/cache.rb +3 -3
  5. data/lib/active_support/callbacks.rb +126 -82
  6. data/lib/active_support/concern.rb +1 -1
  7. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +2 -0
  8. data/lib/active_support/core_ext/class/subclasses.rb +0 -2
  9. data/lib/active_support/core_ext/date/conversions.rb +6 -0
  10. data/lib/active_support/core_ext/date_and_time/calculations.rb +11 -0
  11. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  12. data/lib/active_support/core_ext/date_time/calculations.rb +23 -3
  13. data/lib/active_support/core_ext/date_time/compatibility.rb +15 -0
  14. data/lib/active_support/core_ext/date_time.rb +1 -0
  15. data/lib/active_support/core_ext/enumerable.rb +16 -0
  16. data/lib/active_support/core_ext/hash/compact.rb +19 -15
  17. data/lib/active_support/core_ext/hash/conversions.rb +1 -2
  18. data/lib/active_support/core_ext/hash/transform_values.rb +2 -2
  19. data/lib/active_support/core_ext/integer/time.rb +0 -15
  20. data/lib/active_support/core_ext/kernel/debugger.rb +1 -1
  21. data/lib/active_support/core_ext/kernel/reporting.rb +1 -0
  22. data/lib/active_support/core_ext/marshal.rb +8 -5
  23. data/lib/active_support/core_ext/module/delegation.rb +24 -12
  24. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -1
  25. data/lib/active_support/core_ext/numeric/conversions.rb +11 -3
  26. data/lib/active_support/core_ext/numeric/time.rb +0 -15
  27. data/lib/active_support/core_ext/object/blank.rb +2 -2
  28. data/lib/active_support/core_ext/object/duplicable.rb +58 -32
  29. data/lib/active_support/core_ext/object/json.rb +2 -2
  30. data/lib/active_support/core_ext/object/try.rb +2 -2
  31. data/lib/active_support/core_ext/string/access.rb +1 -1
  32. data/lib/active_support/core_ext/string/conversions.rb +1 -1
  33. data/lib/active_support/core_ext/string/filters.rb +4 -3
  34. data/lib/active_support/core_ext/string/output_safety.rb +6 -2
  35. data/lib/active_support/core_ext/time/calculations.rb +18 -2
  36. data/lib/active_support/core_ext/time/compatibility.rb +14 -0
  37. data/lib/active_support/core_ext/time.rb +1 -0
  38. data/lib/active_support/deprecation/behaviors.rb +1 -1
  39. data/lib/active_support/duration.rb +25 -1
  40. data/lib/active_support/gem_version.rb +1 -1
  41. data/lib/active_support/hash_with_indifferent_access.rb +22 -3
  42. data/lib/active_support/inflector/methods.rb +1 -1
  43. data/lib/active_support/json/encoding.rb +5 -0
  44. data/lib/active_support/logger.rb +50 -0
  45. data/lib/active_support/logger_silence.rb +7 -4
  46. data/lib/active_support/logger_thread_safe_level.rb +32 -0
  47. data/lib/active_support/message_encryptor.rb +8 -1
  48. data/lib/active_support/message_verifier.rb +1 -1
  49. data/lib/active_support/multibyte/chars.rb +1 -1
  50. data/lib/active_support/notifications/fanout.rb +1 -1
  51. data/lib/active_support/number_helper/number_to_rounded_converter.rb +1 -1
  52. data/lib/active_support/per_thread_registry.rb +5 -3
  53. data/lib/active_support/security_utils.rb +7 -0
  54. data/lib/active_support/testing/time_helpers.rb +16 -13
  55. data/lib/active_support/time_with_zone.rb +29 -17
  56. data/lib/active_support/values/time_zone.rb +10 -5
  57. data/lib/active_support/xml_mini/jdom.rb +6 -5
  58. data/lib/active_support/xml_mini/libxml.rb +1 -3
  59. data/lib/active_support/xml_mini/libxmlsax.rb +1 -4
  60. data/lib/active_support/xml_mini/nokogiri.rb +1 -3
  61. data/lib/active_support/xml_mini/nokogirisax.rb +1 -3
  62. data/lib/active_support/xml_mini/rexml.rb +7 -8
  63. data/lib/active_support/xml_mini.rb +33 -15
  64. data/lib/active_support.rb +9 -0
  65. metadata +7 -23
@@ -1,11 +1,24 @@
1
1
  require 'active_support/core_ext/module/attribute_accessors'
2
2
  require 'active_support/logger_silence'
3
+ require 'active_support/logger_thread_safe_level'
3
4
  require 'logger'
4
5
 
5
6
  module ActiveSupport
6
7
  class Logger < ::Logger
8
+ include ActiveSupport::LoggerThreadSafeLevel
7
9
  include LoggerSilence
8
10
 
11
+ # Returns true if the logger destination matches one of the sources
12
+ #
13
+ # logger = Logger.new(STDOUT)
14
+ # ActiveSupport::Logger.logger_outputs_to?(logger, STDOUT)
15
+ # # => true
16
+ def self.logger_outputs_to?(logger, *sources)
17
+ logdev = logger.instance_variable_get("@logdev")
18
+ logger_source = logdev.dev if logdev.respond_to?(:dev)
19
+ sources.any? { |source| source == logger_source }
20
+ end
21
+
9
22
  # Broadcasts logs to multiple loggers.
10
23
  def self.broadcast(logger) # :nodoc:
11
24
  Module.new do
@@ -38,12 +51,49 @@ module ActiveSupport
38
51
  logger.level = level
39
52
  super(level)
40
53
  end
54
+
55
+ define_method(:local_level=) do |level|
56
+ logger.local_level = level if logger.respond_to?(:local_level=)
57
+ super(level) if respond_to?(:local_level=)
58
+ end
59
+
60
+ define_method(:silence) do |level = Logger::ERROR, &block|
61
+ if logger.respond_to?(:silence) && logger.method(:silence).owner != ::Kernel
62
+ logger.silence(level) do
63
+ if respond_to?(:silence) && method(:silence).owner != ::Kernel
64
+ super(level, &block)
65
+ else
66
+ block.call(self)
67
+ end
68
+ end
69
+ else
70
+ if respond_to?(:silence) && method(:silence).owner != ::Kernel
71
+ super(level, &block)
72
+ else
73
+ block.call(self)
74
+ end
75
+ end
76
+ end
41
77
  end
42
78
  end
43
79
 
44
80
  def initialize(*args)
45
81
  super
46
82
  @formatter = SimpleFormatter.new
83
+ after_initialize if respond_to? :after_initialize
84
+ end
85
+
86
+ def add(severity, message = nil, progname = nil, &block)
87
+ return true if @logdev.nil? || (severity || UNKNOWN) < level
88
+ super
89
+ end
90
+
91
+ Logger::Severity.constants.each do |severity|
92
+ class_eval(<<-EOT, __FILE__, __LINE__ + 1)
93
+ def #{severity.downcase}? # def debug?
94
+ Logger::#{severity} >= level # DEBUG >= level
95
+ end # end
96
+ EOT
47
97
  end
48
98
 
49
99
  # Simple formatter which only displays the message.
@@ -1,8 +1,9 @@
1
1
  require 'active_support/concern'
2
+ require 'thread_safe'
2
3
 
3
4
  module LoggerSilence
4
5
  extend ActiveSupport::Concern
5
-
6
+
6
7
  included do
7
8
  cattr_accessor :silencer
8
9
  self.silencer = true
@@ -12,13 +13,15 @@ module LoggerSilence
12
13
  def silence(temporary_level = Logger::ERROR)
13
14
  if silencer
14
15
  begin
15
- old_logger_level, self.level = level, temporary_level
16
+ old_local_level = local_level
17
+ self.local_level = temporary_level
18
+
16
19
  yield self
17
20
  ensure
18
- self.level = old_logger_level
21
+ self.local_level = old_local_level
19
22
  end
20
23
  else
21
24
  yield self
22
25
  end
23
26
  end
24
- end
27
+ end
@@ -0,0 +1,32 @@
1
+ require 'active_support/concern'
2
+ require 'thread_safe'
3
+
4
+ module ActiveSupport
5
+ module LoggerThreadSafeLevel
6
+ extend ActiveSupport::Concern
7
+
8
+ def after_initialize
9
+ @local_levels = ThreadSafe::Cache.new
10
+ end
11
+
12
+ def local_log_id
13
+ Thread.current.__id__
14
+ end
15
+
16
+ def local_level
17
+ @local_levels[local_log_id]
18
+ end
19
+
20
+ def local_level=(level)
21
+ if level
22
+ @local_levels[local_log_id] = level
23
+ else
24
+ @local_levels.delete(local_log_id)
25
+ end
26
+ end
27
+
28
+ def level
29
+ local_level || super
30
+ end
31
+ end
32
+ end
@@ -18,6 +18,8 @@ module ActiveSupport
18
18
  # encrypted_data = crypt.encrypt_and_sign('my secret data') # => "NlFBTTMwOUV5UlA1QlNEN2xkY2d6eThYWWh..."
19
19
  # crypt.decrypt_and_verify(encrypted_data) # => "my secret data"
20
20
  class MessageEncryptor
21
+ DEFAULT_CIPHER = "aes-256-cbc"
22
+
21
23
  module NullSerializer #:nodoc:
22
24
  def self.load(value)
23
25
  value
@@ -64,6 +66,11 @@ module ActiveSupport
64
66
  _decrypt(verifier.verify(value))
65
67
  end
66
68
 
69
+ # Given a cipher, returns the key length of the cipher to help generate the key of desired size
70
+ def self.key_len(cipher = DEFAULT_CIPHER)
71
+ OpenSSL::Cipher.new(cipher).key_len
72
+ end
73
+
67
74
  private
68
75
 
69
76
  def _encrypt(value)
@@ -97,7 +104,7 @@ module ActiveSupport
97
104
  end
98
105
 
99
106
  def new_cipher
100
- OpenSSL::Cipher::Cipher.new(@cipher)
107
+ OpenSSL::Cipher.new(@cipher)
101
108
  end
102
109
 
103
110
  def verifier
@@ -35,7 +35,7 @@ module ActiveSupport
35
35
  end
36
36
 
37
37
  def verify(signed_message)
38
- raise InvalidSignature if signed_message.blank?
38
+ raise InvalidSignature if signed_message.nil? || !signed_message.valid_encoding? || signed_message.blank?
39
39
 
40
40
  data, digest = signed_message.split("--")
41
41
  if data.present? && digest.present? && ActiveSupport::SecurityUtils.secure_compare(digest, generate_digest(data))
@@ -86,7 +86,7 @@ module ActiveSupport #:nodoc:
86
86
  @wrapped_string.split(*args).map { |i| self.class.new(i) }
87
87
  end
88
88
 
89
- # Works like like <tt>String#slice!</tt>, but returns an instance of
89
+ # Works like <tt>String#slice!</tt>, but returns an instance of
90
90
  # Chars, or nil if the string was not modified.
91
91
  def slice!(*args)
92
92
  chars(@wrapped_string.slice!(*args))
@@ -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
@@ -23,7 +23,7 @@ module ActiveSupport
23
23
  precision = 0 if precision < 0 # don't let it be negative
24
24
  else
25
25
  rounded_number = number.round(precision)
26
- rounded_number = rounded_number.to_i if precision == 0
26
+ rounded_number = rounded_number.to_i if precision == 0 && rounded_number.finite?
27
27
  rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros
28
28
  end
29
29
 
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/module/delegation'
2
+
1
3
  module ActiveSupport
2
4
  # This module is used to encapsulate access to thread local variables.
3
5
  #
@@ -43,9 +45,9 @@ module ActiveSupport
43
45
  protected
44
46
  def method_missing(name, *args, &block) # :nodoc:
45
47
  # Caches the method definition as a singleton method of the receiver.
46
- define_singleton_method(name) do |*a, &b|
47
- instance.public_send(name, *a, &b)
48
- end
48
+ #
49
+ # By letting #delegate handle it, we avoid an enclosure that'll capture args.
50
+ singleton_class.delegate name, to: :instance
49
51
 
50
52
  send(name, *args, &block)
51
53
  end
@@ -1,3 +1,5 @@
1
+ require 'digest'
2
+
1
3
  module ActiveSupport
2
4
  module SecurityUtils
3
5
  # Constant time string comparison.
@@ -16,5 +18,10 @@ module ActiveSupport
16
18
  res == 0
17
19
  end
18
20
  module_function :secure_compare
21
+
22
+ def variable_size_secure_compare(a, b) # :nodoc:
23
+ secure_compare(::Digest::SHA256.hexdigest(a), ::Digest::SHA256.hexdigest(b))
24
+ end
25
+ module_function :variable_size_secure_compare
19
26
  end
20
27
  end
@@ -7,7 +7,7 @@ module ActiveSupport
7
7
  @stubs = {}
8
8
  end
9
9
 
10
- def stub_object(object, method_name, return_value)
10
+ def stub_object(object, method_name, &block)
11
11
  key = [object.object_id, method_name]
12
12
 
13
13
  if stub = @stubs[key]
@@ -19,7 +19,7 @@ module ActiveSupport
19
19
  @stubs[key] = Stub.new(object, method_name, new_name)
20
20
 
21
21
  object.singleton_class.send :alias_method, new_name, method_name
22
- object.define_singleton_method(method_name) { return_value }
22
+ object.define_singleton_method(method_name, &block)
23
23
  end
24
24
 
25
25
  def unstub_all!
@@ -42,12 +42,13 @@ module ActiveSupport
42
42
  # Containing helpers that helps you test passage of time.
43
43
  module TimeHelpers
44
44
  # Changes current time to the time in the future or in the past by a given time difference by
45
- # stubbing +Time.now+ and +Date.today+.
45
+ # stubbing +Time.now+, +Date.today+, and +DateTime.now+.
46
46
  #
47
- # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
47
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
48
48
  # travel 1.day
49
- # Time.current # => Sun, 10 Nov 2013 15:34:49 EST -05:00
50
- # Date.current # => Sun, 10 Nov 2013
49
+ # Time.current # => Sun, 10 Nov 2013 15:34:49 EST -05:00
50
+ # Date.current # => Sun, 10 Nov 2013
51
+ # DateTime.current # => Sun, 10 Nov 2013 15:34:49 -0500
51
52
  #
52
53
  # This method also accepts a block, which will return the current time back to its original
53
54
  # state at the end of the block:
@@ -61,13 +62,14 @@ module ActiveSupport
61
62
  travel_to Time.now + duration, &block
62
63
  end
63
64
 
64
- # Changes current time to the given time by stubbing +Time.now+ and
65
- # +Date.today+ to return the time or date passed into this method.
65
+ # Changes current time to the given time by stubbing +Time.now+,
66
+ # +Date.today+, and +DateTime.now+ to return the time or date passed into this method.
66
67
  #
67
- # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
68
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
68
69
  # travel_to Time.new(2004, 11, 24, 01, 04, 44)
69
- # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
70
- # Date.current # => Wed, 24 Nov 2004
70
+ # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
71
+ # Date.current # => Wed, 24 Nov 2004
72
+ # DateTime.current # => Wed, 24 Nov 2004 01:04:44 -0500
71
73
  #
72
74
  # Dates are taken as their timestamp at the beginning of the day in the
73
75
  # application time zone. <tt>Time.current</tt> returns said timestamp,
@@ -97,8 +99,9 @@ module ActiveSupport
97
99
  now = date_or_time.to_time.change(usec: 0)
98
100
  end
99
101
 
100
- simple_stubs.stub_object(Time, :now, now)
101
- simple_stubs.stub_object(Date, :today, now.to_date)
102
+ simple_stubs.stub_object(Time, :now) { at(now.to_i) }
103
+ simple_stubs.stub_object(Date, :today) { jd(now.to_date.jd) }
104
+ simple_stubs.stub_object(DateTime, :now) { jd(now.to_date.jd, now.hour, now.min, now.sec, Rational(now.utc_offset, 86400)) }
102
105
 
103
106
  if block_given?
104
107
  begin
@@ -1,5 +1,6 @@
1
1
  require 'active_support/values/time_zone'
2
2
  require 'active_support/core_ext/object/acts_like'
3
+ require 'active_support/core_ext/date_and_time/compatibility'
3
4
 
4
5
  module ActiveSupport
5
6
  # A Time-like class that can represent a time in any time zone. Necessary
@@ -40,20 +41,21 @@ module ActiveSupport
40
41
  'Time'
41
42
  end
42
43
 
43
- include Comparable
44
+ include Comparable, DateAndTime::Compatibility
44
45
  attr_reader :time_zone
45
46
 
46
47
  def initialize(utc_time, time_zone, local_time = nil, period = nil)
47
- @utc, @time_zone, @time = utc_time, time_zone, local_time
48
+ @utc = utc_time ? transfer_time_values_to_utc_constructor(utc_time) : nil
49
+ @time_zone, @time = time_zone, local_time
48
50
  @period = @utc ? period : get_period_and_ensure_valid_local_time(period)
49
51
  end
50
52
 
51
- # Returns a Time or DateTime instance that represents the time in +time_zone+.
53
+ # Returns a <tt>Time</tt> instance that represents the time in +time_zone+.
52
54
  def time
53
55
  @time ||= period.to_local(@utc)
54
56
  end
55
57
 
56
- # Returns a Time or DateTime instance that represents the time in UTC.
58
+ # Returns a <tt>Time</tt> instance of the simultaneous time in the UTC timezone.
57
59
  def utc
58
60
  @utc ||= period.to_utc(@time)
59
61
  end
@@ -73,10 +75,9 @@ module ActiveSupport
73
75
  utc.in_time_zone(new_zone)
74
76
  end
75
77
 
76
- # Returns a <tt>Time.local()</tt> instance of the simultaneous time in your
77
- # system's <tt>ENV['TZ']</tt> zone.
78
+ # Returns a <tt>Time</tt> instance of the simultaneous time in the system timezone.
78
79
  def localtime(utc_offset = nil)
79
- utc.respond_to?(:getlocal) ? utc.getlocal(utc_offset) : utc.to_time.getlocal(utc_offset)
80
+ utc.getlocal(utc_offset)
80
81
  end
81
82
  alias_method :getlocal, :localtime
82
83
 
@@ -160,7 +161,11 @@ module ActiveSupport
160
161
  end
161
162
  end
162
163
 
163
- def encode_with(coder)
164
+ def init_with(coder) #:nodoc:
165
+ initialize(coder['utc'], coder['zone'], coder['time'])
166
+ end
167
+
168
+ def encode_with(coder) #:nodoc:
164
169
  if coder.respond_to?(:represent_object)
165
170
  coder.represent_object(nil, utc)
166
171
  else
@@ -236,7 +241,7 @@ module ActiveSupport
236
241
  end
237
242
 
238
243
  def eql?(other)
239
- utc.eql?(other)
244
+ other.eql?(utc)
240
245
  end
241
246
 
242
247
  def hash
@@ -276,6 +281,7 @@ module ActiveSupport
276
281
  utc.since(other).in_time_zone(time_zone)
277
282
  end
278
283
  end
284
+ alias_method :in, :since
279
285
 
280
286
  def ago(other)
281
287
  since(-other)
@@ -316,13 +322,19 @@ module ActiveSupport
316
322
  utc.to_r
317
323
  end
318
324
 
319
- # Return an instance of Time in the system timezone.
320
- def to_time
321
- utc.to_time
325
+ def to_datetime
326
+ @to_datetime ||= utc.to_datetime.new_offset(Rational(utc_offset, 86_400))
322
327
  end
323
328
 
324
- def to_datetime
325
- utc.to_datetime.new_offset(Rational(utc_offset, 86_400))
329
+ # Returns an instance of +Time+, either with the same UTC offset
330
+ # as +self+ or in the local system timezone depending on the setting
331
+ # of +ActiveSupport.to_time_preserves_timezone+.
332
+ def to_time
333
+ if preserve_timezone
334
+ @to_time_with_instance_offset ||= getlocal(utc_offset)
335
+ else
336
+ @to_time_with_system_offset ||= getlocal
337
+ end
326
338
  end
327
339
 
328
340
  # So that +self+ <tt>acts_like?(:time)</tt>.
@@ -337,7 +349,8 @@ module ActiveSupport
337
349
  alias_method :kind_of?, :is_a?
338
350
 
339
351
  def freeze
340
- period; utc; time # preload instance variables before freezing
352
+ # preload instance variables before freezing
353
+ period; utc; time; to_datetime; to_time
341
354
  super
342
355
  end
343
356
 
@@ -360,7 +373,6 @@ module ActiveSupport
360
373
  # Ensure proxy class responds to all methods that underlying time instance
361
374
  # responds to.
362
375
  def respond_to_missing?(sym, include_priv)
363
- # consistently respond false to acts_like?(:date), regardless of whether #time is a Time or DateTime
364
376
  return false if sym.to_sym == :acts_like_date?
365
377
  time.respond_to?(sym, include_priv)
366
378
  end
@@ -388,7 +400,7 @@ module ActiveSupport
388
400
  end
389
401
 
390
402
  def transfer_time_values_to_utc_constructor(time)
391
- ::Time.utc(time.year, time.month, time.day, time.hour, time.min, time.sec, Rational(time.nsec, 1000))
403
+ ::Time.utc(time.year, time.month, time.day, time.hour, time.min, time.sec + time.subsec)
392
404
  end
393
405
 
394
406
  def duration_of_variable_length?(obj)
@@ -111,9 +111,11 @@ module ActiveSupport
111
111
  "Jerusalem" => "Asia/Jerusalem",
112
112
  "Harare" => "Africa/Harare",
113
113
  "Pretoria" => "Africa/Johannesburg",
114
+ "Kaliningrad" => "Europe/Kaliningrad",
114
115
  "Moscow" => "Europe/Moscow",
115
116
  "St. Petersburg" => "Europe/Moscow",
116
- "Volgograd" => "Europe/Moscow",
117
+ "Volgograd" => "Europe/Volgograd",
118
+ "Samara" => "Europe/Samara",
117
119
  "Kuwait" => "Asia/Kuwait",
118
120
  "Riyadh" => "Asia/Riyadh",
119
121
  "Nairobi" => "Africa/Nairobi",
@@ -170,6 +172,7 @@ module ActiveSupport
170
172
  "Guam" => "Pacific/Guam",
171
173
  "Port Moresby" => "Pacific/Port_Moresby",
172
174
  "Magadan" => "Asia/Magadan",
175
+ "Srednekolymsk" => "Asia/Srednekolymsk",
173
176
  "Solomon Is." => "Pacific/Guadalcanal",
174
177
  "New Caledonia" => "Pacific/Noumea",
175
178
  "Fiji" => "Pacific/Fiji",
@@ -221,7 +224,7 @@ module ActiveSupport
221
224
  @zones ||= zones_map.values.sort
222
225
  end
223
226
 
224
- def zones_map
227
+ def zones_map #:nodoc:
225
228
  @zones_map ||= begin
226
229
  MAPPING.each_key {|place| self[place]} # load all the zones
227
230
  @lazy_zones_map
@@ -268,7 +271,10 @@ module ActiveSupport
268
271
  @name = name
269
272
  @utc_offset = utc_offset
270
273
  @tzinfo = tzinfo || TimeZone.find_tzinfo(name)
271
- @current_period = nil
274
+ end
275
+
276
+ def init_with(coder) #:nodoc:
277
+ initialize(coder['name'])
272
278
  end
273
279
 
274
280
  # Returns the offset of this time zone from UTC in seconds.
@@ -276,8 +282,7 @@ module ActiveSupport
276
282
  if @utc_offset
277
283
  @utc_offset
278
284
  else
279
- @current_period ||= tzinfo.current_period if tzinfo
280
- @current_period.utc_offset if @current_period
285
+ tzinfo.current_period.utc_offset if tzinfo && tzinfo.current_period
281
286
  end
282
287
  end
283
288
 
@@ -46,7 +46,7 @@ module ActiveSupport
46
46
  xml_string_reader = StringReader.new(data)
47
47
  xml_input_source = InputSource.new(xml_string_reader)
48
48
  doc = @dbf.new_document_builder.parse(xml_input_source)
49
- merge_element!({CONTENT_KEY => ''}, doc.document_element)
49
+ merge_element!({CONTENT_KEY => ''}, doc.document_element, XmlMini.depth)
50
50
  end
51
51
  end
52
52
 
@@ -58,9 +58,10 @@ module ActiveSupport
58
58
  # Hash to merge the converted element into.
59
59
  # element::
60
60
  # XML element to merge into hash
61
- def merge_element!(hash, element)
61
+ def merge_element!(hash, element, depth)
62
+ raise 'Document too deep!' if depth == 0
62
63
  delete_empty(hash)
63
- merge!(hash, element.tag_name, collapse(element))
64
+ merge!(hash, element.tag_name, collapse(element, depth))
64
65
  end
65
66
 
66
67
  def delete_empty(hash)
@@ -71,14 +72,14 @@ module ActiveSupport
71
72
  #
72
73
  # element::
73
74
  # The document element to be collapsed.
74
- def collapse(element)
75
+ def collapse(element, depth)
75
76
  hash = get_attributes(element)
76
77
 
77
78
  child_nodes = element.child_nodes
78
79
  if child_nodes.length > 0
79
80
  (0...child_nodes.length).each do |i|
80
81
  child = child_nodes.item(i)
81
- merge_element!(hash, child) unless child.node_type == Node.TEXT_NODE
82
+ merge_element!(hash, child, depth - 1) unless child.node_type == Node.TEXT_NODE
82
83
  end
83
84
  merge_texts!(hash, element) unless empty_content?(element)
84
85
  hash
@@ -14,11 +14,9 @@ module ActiveSupport
14
14
  data = StringIO.new(data || '')
15
15
  end
16
16
 
17
- char = data.getc
18
- if char.nil?
17
+ if data.eof?
19
18
  {}
20
19
  else
21
- data.ungetc(char)
22
20
  LibXML::XML::Parser.io(data).parse.to_hash
23
21
  end
24
22
  end
@@ -66,12 +66,9 @@ module ActiveSupport
66
66
  data = StringIO.new(data || '')
67
67
  end
68
68
 
69
- char = data.getc
70
- if char.nil?
69
+ if data.eof?
71
70
  {}
72
71
  else
73
- data.ungetc(char)
74
-
75
72
  LibXML::XML::Error.set_handler(&LibXML::XML::Error::QUIET_HANDLER)
76
73
  parser = LibXML::XML::SaxParser.io(data)
77
74
  document = self.document_class.new
@@ -19,11 +19,9 @@ module ActiveSupport
19
19
  data = StringIO.new(data || '')
20
20
  end
21
21
 
22
- char = data.getc
23
- if char.nil?
22
+ if data.eof?
24
23
  {}
25
24
  else
26
- data.ungetc(char)
27
25
  doc = Nokogiri::XML(data)
28
26
  raise doc.errors.first if doc.errors.length > 0
29
27
  doc.to_hash
@@ -72,11 +72,9 @@ module ActiveSupport
72
72
  data = StringIO.new(data || '')
73
73
  end
74
74
 
75
- char = data.getc
76
- if char.nil?
75
+ if data.eof?
77
76
  {}
78
77
  else
79
- data.ungetc(char)
80
78
  document = self.document_class.new
81
79
  parser = Nokogiri::XML::SAX::Parser.new(document)
82
80
  parser.parse(data)
@@ -20,16 +20,14 @@ module ActiveSupport
20
20
  data = StringIO.new(data || '')
21
21
  end
22
22
 
23
- char = data.getc
24
- if char.nil?
23
+ if data.eof?
25
24
  {}
26
25
  else
27
- data.ungetc(char)
28
26
  silence_warnings { require 'rexml/document' } unless defined?(REXML::Document)
29
27
  doc = REXML::Document.new(data)
30
28
 
31
29
  if doc.root
32
- merge_element!({}, doc.root)
30
+ merge_element!({}, doc.root, XmlMini.depth)
33
31
  else
34
32
  raise REXML::ParseException,
35
33
  "The document #{doc.to_s.inspect} does not have a valid root"
@@ -44,19 +42,20 @@ module ActiveSupport
44
42
  # Hash to merge the converted element into.
45
43
  # element::
46
44
  # XML element to merge into hash
47
- def merge_element!(hash, element)
48
- merge!(hash, element.name, collapse(element))
45
+ def merge_element!(hash, element, depth)
46
+ raise REXML::ParseException, "The document is too deep" if depth == 0
47
+ merge!(hash, element.name, collapse(element, depth))
49
48
  end
50
49
 
51
50
  # Actually converts an XML document element into a data structure.
52
51
  #
53
52
  # element::
54
53
  # The document element to be collapsed.
55
- def collapse(element)
54
+ def collapse(element, depth)
56
55
  hash = get_attributes(element)
57
56
 
58
57
  if element.has_elements?
59
- element.each_element {|child| merge_element!(hash, child) }
58
+ element.each_element {|child| merge_element!(hash, child, depth - 1) }
60
59
  merge_texts!(hash, element) unless empty_content?(element)
61
60
  hash
62
61
  else