activesupport 2.3.6.pre → 2.3.6

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 (123) hide show
  1. data/CHANGELOG +9 -5
  2. data/lib/active_support/buffered_logger.rb +1 -1
  3. data/lib/active_support/cache/memory_store.rb +7 -1
  4. data/lib/active_support/cache/strategy/local_cache.rb +1 -1
  5. data/lib/active_support/core_ext/array/conversions.rb +1 -1
  6. data/lib/active_support/core_ext/array/random_access.rb +11 -1
  7. data/lib/active_support/core_ext/class/attribute_accessors.rb +35 -28
  8. data/lib/active_support/core_ext/date/calculations.rb +14 -4
  9. data/lib/active_support/core_ext/kernel/reporting.rb +1 -1
  10. data/lib/active_support/core_ext/module/aliasing.rb +1 -1
  11. data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +1 -1
  12. data/lib/active_support/core_ext/module/attribute_accessors.rb +33 -26
  13. data/lib/active_support/core_ext/module/synchronization.rb +1 -1
  14. data/lib/active_support/core_ext/object/blank.rb +20 -2
  15. data/lib/active_support/core_ext/string/output_safety.rb +10 -2
  16. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -4
  17. data/lib/active_support/core_ext/time.rb +8 -4
  18. data/lib/active_support/core_ext/time/calculations.rb +11 -2
  19. data/lib/active_support/deprecation.rb +3 -2
  20. data/lib/active_support/inflections.rb +1 -1
  21. data/lib/active_support/inflector.rb +4 -1
  22. data/lib/active_support/json/backends/yaml.rb +10 -7
  23. data/lib/active_support/json/decoding.rb +1 -1
  24. data/lib/active_support/memoizable.rb +1 -1
  25. data/lib/active_support/multibyte/unicode_database.rb +2 -2
  26. data/lib/active_support/multibyte/utils.rb +6 -7
  27. data/lib/active_support/ordered_hash.rb +24 -30
  28. data/lib/active_support/testing/assertions.rb +14 -0
  29. data/lib/active_support/values/time_zone.rb +84 -76
  30. data/lib/active_support/vendor.rb +1 -1
  31. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n.rb +92 -34
  32. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend.rb +2 -0
  33. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/active_record.rb +9 -13
  34. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/active_record/missing.rb +1 -1
  35. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/active_record/store_procs.rb +6 -6
  36. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/active_record/translation.rb +14 -9
  37. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/base.rb +23 -16
  38. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/cache.rb +1 -0
  39. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/cascade.rb +22 -8
  40. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/chain.rb +2 -1
  41. data/lib/active_support/vendor/i18n-0.3.7/i18n/backend/cldr.rb +100 -0
  42. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/fallbacks.rb +20 -3
  43. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/fast.rb +14 -13
  44. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/gettext.rb +1 -1
  45. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/helpers.rb +4 -16
  46. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/interpolation_compiler.rb +2 -2
  47. data/lib/active_support/vendor/i18n-0.3.7/i18n/backend/links.rb +34 -0
  48. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/metadata.rb +0 -0
  49. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/pluralization.rb +1 -1
  50. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/simple.rb +0 -0
  51. data/lib/active_support/vendor/i18n-0.3.7/i18n/core_ext/hash/except.rb +8 -0
  52. data/lib/active_support/vendor/i18n-0.3.7/i18n/core_ext/hash/slice.rb +8 -0
  53. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/core_ext/object/meta_class.rb +0 -0
  54. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/core_ext/string/interpolate.rb +1 -1
  55. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/exceptions.rb +1 -1
  56. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/gettext.rb +0 -0
  57. data/lib/active_support/vendor/{i18n-0.3.3/vendor → i18n-0.3.7/i18n/gettext}/po_parser.rb +0 -0
  58. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/helpers.rb +0 -0
  59. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/helpers/gettext.rb +3 -2
  60. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/locale.rb +0 -0
  61. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/locale/fallbacks.rb +0 -0
  62. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/locale/tag.rb +0 -0
  63. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/locale/tag/parents.rb +0 -0
  64. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/locale/tag/rfc4646.rb +0 -0
  65. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/locale/tag/simple.rb +0 -0
  66. data/lib/active_support/vendor/i18n-0.3.7/i18n/version.rb +3 -0
  67. metadata +42 -96
  68. data/lib/active_support/vendor/i18n-0.3.3/CHANGELOG.textile +0 -76
  69. data/lib/active_support/vendor/i18n-0.3.3/MIT-LICENSE +0 -20
  70. data/lib/active_support/vendor/i18n-0.3.3/README.textile +0 -81
  71. data/lib/active_support/vendor/i18n-0.3.3/Rakefile +0 -24
  72. data/lib/active_support/vendor/i18n-0.3.3/benchmark/example.yml +0 -144
  73. data/lib/active_support/vendor/i18n-0.3.3/benchmark/run.rb +0 -71
  74. data/lib/active_support/vendor/i18n-0.3.3/contributors.txt +0 -17
  75. data/lib/active_support/vendor/i18n-0.3.3/i18n.gemspec +0 -165
  76. data/lib/active_support/vendor/i18n-0.3.3/init.rb +0 -1
  77. data/lib/active_support/vendor/i18n-0.3.3/lib/i18n/version.rb +0 -3
  78. data/lib/active_support/vendor/i18n-0.3.3/test/all.rb +0 -8
  79. data/lib/active_support/vendor/i18n-0.3.3/test/api/basics.rb +0 -15
  80. data/lib/active_support/vendor/i18n-0.3.3/test/api/defaults.rb +0 -40
  81. data/lib/active_support/vendor/i18n-0.3.3/test/api/interpolation.rb +0 -92
  82. data/lib/active_support/vendor/i18n-0.3.3/test/api/link.rb +0 -55
  83. data/lib/active_support/vendor/i18n-0.3.3/test/api/localization/date.rb +0 -91
  84. data/lib/active_support/vendor/i18n-0.3.3/test/api/localization/date_time.rb +0 -90
  85. data/lib/active_support/vendor/i18n-0.3.3/test/api/localization/procs.rb +0 -54
  86. data/lib/active_support/vendor/i18n-0.3.3/test/api/localization/time.rb +0 -84
  87. data/lib/active_support/vendor/i18n-0.3.3/test/api/lookup.rb +0 -45
  88. data/lib/active_support/vendor/i18n-0.3.3/test/api/pluralization.rb +0 -35
  89. data/lib/active_support/vendor/i18n-0.3.3/test/api/procs.rb +0 -40
  90. data/lib/active_support/vendor/i18n-0.3.3/test/cases/api/active_record_test.rb +0 -29
  91. data/lib/active_support/vendor/i18n-0.3.3/test/cases/api/all_features_test.rb +0 -40
  92. data/lib/active_support/vendor/i18n-0.3.3/test/cases/api/cascade_test.rb +0 -31
  93. data/lib/active_support/vendor/i18n-0.3.3/test/cases/api/chain_test.rb +0 -26
  94. data/lib/active_support/vendor/i18n-0.3.3/test/cases/api/fallbacks_test.rb +0 -33
  95. data/lib/active_support/vendor/i18n-0.3.3/test/cases/api/fast_test.rb +0 -31
  96. data/lib/active_support/vendor/i18n-0.3.3/test/cases/api/pluralization_test.rb +0 -33
  97. data/lib/active_support/vendor/i18n-0.3.3/test/cases/api/simple_test.rb +0 -21
  98. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/active_record/missing_test.rb +0 -60
  99. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/active_record_test.rb +0 -52
  100. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/cache_test.rb +0 -72
  101. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/cascade_test.rb +0 -66
  102. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/chain_test.rb +0 -64
  103. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/fallbacks_test.rb +0 -57
  104. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/fast_test.rb +0 -50
  105. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/helpers_test.rb +0 -26
  106. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/interpolation_compiler_test.rb +0 -107
  107. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/metadata_test.rb +0 -67
  108. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/pluralization_test.rb +0 -43
  109. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/simple_test.rb +0 -77
  110. data/lib/active_support/vendor/i18n-0.3.3/test/cases/core_ext/string/interpolate_test.rb +0 -94
  111. data/lib/active_support/vendor/i18n-0.3.3/test/cases/gettext/api_test.rb +0 -201
  112. data/lib/active_support/vendor/i18n-0.3.3/test/cases/gettext/backend_test.rb +0 -91
  113. data/lib/active_support/vendor/i18n-0.3.3/test/cases/i18n_exceptions_test.rb +0 -97
  114. data/lib/active_support/vendor/i18n-0.3.3/test/cases/i18n_load_path_test.rb +0 -23
  115. data/lib/active_support/vendor/i18n-0.3.3/test/cases/i18n_test.rb +0 -172
  116. data/lib/active_support/vendor/i18n-0.3.3/test/cases/locale/fallbacks_test.rb +0 -126
  117. data/lib/active_support/vendor/i18n-0.3.3/test/cases/locale/tag/rfc4646_test.rb +0 -143
  118. data/lib/active_support/vendor/i18n-0.3.3/test/cases/locale/tag/simple_test.rb +0 -33
  119. data/lib/active_support/vendor/i18n-0.3.3/test/fixtures/locales/de.po +0 -72
  120. data/lib/active_support/vendor/i18n-0.3.3/test/fixtures/locales/en.rb +0 -3
  121. data/lib/active_support/vendor/i18n-0.3.3/test/fixtures/locales/en.yml +0 -3
  122. data/lib/active_support/vendor/i18n-0.3.3/test/fixtures/locales/plurals.rb +0 -113
  123. data/lib/active_support/vendor/i18n-0.3.3/test/test_helper.rb +0 -100
@@ -157,8 +157,13 @@ module ActiveSupport #:nodoc:
157
157
  advance(:years => years)
158
158
  end
159
159
 
160
+ def last_year # :nodoc:
161
+ ActiveSupport::Deprecation.warn("Time#last_year is deprecated and has been removed in Rails 3, please use Time#prev_year instead", caller)
162
+ prev_year
163
+ end
164
+
160
165
  # Short-hand for years_ago(1)
161
- def last_year
166
+ def prev_year
162
167
  years_ago(1)
163
168
  end
164
169
 
@@ -167,9 +172,13 @@ module ActiveSupport #:nodoc:
167
172
  years_since(1)
168
173
  end
169
174
 
175
+ def last_month # :nodoc:
176
+ ActiveSupport::Deprecation.warn("Time#last_month is deprecated and has been removed in Rails 3, please use Time#prev_month instead", caller)
177
+ prev_month
178
+ end
170
179
 
171
180
  # Short-hand for months_ago(1)
172
- def last_month
181
+ def prev_month
173
182
  months_ago(1)
174
183
  end
175
184
 
@@ -52,7 +52,8 @@ module ActiveSupport
52
52
  private
53
53
  def deprecation_message(callstack, message = nil)
54
54
  message ||= "You are using deprecated behavior which will be removed from the next major or minor release."
55
- "DEPRECATION WARNING: #{message}. #{deprecation_caller_message(callstack)}"
55
+ message += '.' unless message =~ /\.$/
56
+ "DEPRECATION WARNING: #{message} #{deprecation_caller_message(callstack)}"
56
57
  end
57
58
 
58
59
  def deprecation_caller_message(callstack)
@@ -89,7 +90,7 @@ module ActiveSupport
89
90
  method_names = method_names + options.keys
90
91
  method_names.each do |method_name|
91
92
  alias_method_chain(method_name, :deprecation) do |target, punctuation|
92
- class_eval(<<-EOS, __FILE__, __LINE__)
93
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
93
94
  def #{target}_with_deprecation#{punctuation}(*args, &block) # def generate_secret_with_deprecation(*args, &block)
94
95
  ::ActiveSupport::Deprecation.warn( # ::ActiveSupport::Deprecation.warn(
95
96
  self.class.deprecated_method_warning( # self.class.deprecated_method_warning(
@@ -51,6 +51,6 @@ module ActiveSupport
51
51
  inflect.irregular('move', 'moves')
52
52
  inflect.irregular('cow', 'kine')
53
53
 
54
- inflect.uncountable(%w(equipment information rice money species series fish sheep))
54
+ inflect.uncountable(%w(equipment information rice money species series fish sheep jeans))
55
55
  end
56
56
  end
@@ -1,6 +1,7 @@
1
1
  # encoding: utf-8
2
2
  require 'singleton'
3
3
  require 'iconv'
4
+ require 'kconv'
4
5
 
5
6
  module ActiveSupport
6
7
  # The Inflector transforms words from singular to plural, class names to table names, modularized class names to ones without,
@@ -157,7 +158,7 @@ module ActiveSupport
157
158
  def singularize(word)
158
159
  result = word.to_s.dup
159
160
 
160
- if inflections.uncountables.include?(result.downcase)
161
+ if inflections.uncountables.any? { |inflection| result =~ /#{inflection}\Z/i }
161
162
  result
162
163
  else
163
164
  inflections.singulars.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
@@ -257,6 +258,8 @@ module ActiveSupport
257
258
  # <%= link_to(@person.name, person_path(@person)) %>
258
259
  # # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a>
259
260
  def parameterize(string, sep = '-')
261
+ # remove malformed utf8 characters
262
+ string = string.toutf8 unless string.is_utf8?
260
263
  # replace accented chars with ther ascii equivalents
261
264
  parameterized_string = transliterate(string)
262
265
  # Turn unwanted chars into the seperator
@@ -27,11 +27,9 @@ module ActiveSupport
27
27
  pos = scanner.pos
28
28
  elsif quoting == char
29
29
  if json[pos..scanner.pos-2] =~ DATE_REGEX
30
- # found a date, track the exact positions of the quotes so we can remove them later.
31
- # oh, and increment them for each current mark, each one is an extra padded space that bumps
32
- # the position in the final YAML output
33
- total_marks = marks.size
34
- times << pos+total_marks << scanner.pos+total_marks
30
+ # found a date, track the exact positions of the quotes so we can
31
+ # overwrite them with spaces later.
32
+ times << pos << scanner.pos
35
33
  end
36
34
  quoting = false
37
35
  end
@@ -59,7 +57,12 @@ module ActiveSupport
59
57
  output = []
60
58
  left_pos.each_with_index do |left, i|
61
59
  scanner.pos = left.succ
62
- output << scanner.peek(right_pos[i] - scanner.pos + 1).gsub(/\\([\\\/]|u[[:xdigit:]]{4})/) do
60
+ chunk = scanner.peek(right_pos[i] - scanner.pos + 1)
61
+ # overwrite the quotes found around the dates with spaces
62
+ while times.size > 0 && times[0] <= right_pos[i]
63
+ chunk[times.shift - scanner.pos - 1] = ' '
64
+ end
65
+ chunk.gsub!(/\\([\\\/]|u[[:xdigit:]]{4})/) do
63
66
  ustr = $1
64
67
  if ustr.start_with?('u')
65
68
  [ustr[1..-1].to_i(16)].pack("U")
@@ -69,10 +72,10 @@ module ActiveSupport
69
72
  ustr
70
73
  end
71
74
  end
75
+ output << chunk
72
76
  end
73
77
  output = output * " "
74
78
 
75
- times.each { |i| output[i-1] = ' ' }
76
79
  output.gsub!(/\\\//, '/')
77
80
  output
78
81
  end
@@ -6,7 +6,7 @@ module ActiveSupport
6
6
 
7
7
  module JSON
8
8
  # Listed in order of preference.
9
- DECODERS = %w(Yajl JSONGem Yaml)
9
+ DECODERS = %w(Yajl Yaml)
10
10
 
11
11
  class << self
12
12
  attr_reader :parse_error
@@ -58,7 +58,7 @@ module ActiveSupport
58
58
  original_method = :"_unmemoized_#{symbol}"
59
59
  memoized_ivar = ActiveSupport::Memoizable.memoized_ivar_for(symbol)
60
60
 
61
- class_eval <<-EOS, __FILE__, __LINE__
61
+ class_eval <<-EOS, __FILE__, __LINE__ + 1
62
62
  include InstanceMethods # include InstanceMethods
63
63
  #
64
64
  if method_defined?(:#{original_method}) # if method_defined?(:_unmemoized_mime_type)
@@ -23,7 +23,7 @@ module ActiveSupport #:nodoc:
23
23
 
24
24
  # Lazy load the Unicode database so it's only loaded when it's actually used
25
25
  ATTRIBUTES.each do |attr_name|
26
- class_eval(<<-EOS, __FILE__, __LINE__)
26
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
27
27
  def #{attr_name} # def codepoints
28
28
  load # load
29
29
  @#{attr_name} # @codepoints
@@ -68,4 +68,4 @@ module ActiveSupport #:nodoc:
68
68
  # UniCode Database
69
69
  UCD = UnicodeDatabase.new
70
70
  end
71
- end
71
+ end
@@ -26,11 +26,11 @@ module ActiveSupport #:nodoc:
26
26
  else
27
27
  def self.verify(string)
28
28
  if expression = valid_character
29
- for c in string.split(//)
30
- return false unless expression.match(c)
31
- end
29
+ # Splits the string on character boundaries, which are determined based on $KCODE.
30
+ string.split(//).all? { |c| expression =~ c }
31
+ else
32
+ true
32
33
  end
33
- true
34
34
  end
35
35
  end
36
36
 
@@ -49,9 +49,8 @@ module ActiveSupport #:nodoc:
49
49
  else
50
50
  def self.clean(string)
51
51
  if expression = valid_character
52
- stripped = []; for c in string.split(//)
53
- stripped << c if expression.match(c)
54
- end; stripped.join
52
+ # Splits the string on character boundaries, which are determined based on $KCODE.
53
+ string.split(//).grep(expression).join
55
54
  else
56
55
  string
57
56
  end
@@ -1,13 +1,28 @@
1
1
  require 'yaml'
2
2
 
3
+ YAML.add_builtin_type("omap") do |type, val|
4
+ ActiveSupport::OrderedHash[val.map(&:to_a).map(&:first)]
5
+ end
6
+
3
7
  # OrderedHash is namespaced to prevent conflicts with other implementations
4
8
  module ActiveSupport
5
- # Hash is ordered in Ruby 1.9!
6
- if RUBY_VERSION >= '1.9'
7
- class OrderedHash < ::Hash #:nodoc:
9
+ class OrderedHash < ::Hash #:nodoc:
10
+ def to_yaml_type
11
+ "!tag:yaml.org,2002:omap"
8
12
  end
9
- else
10
- class OrderedHash < Hash #:nodoc:
13
+
14
+ def to_yaml(opts = {})
15
+ YAML.quick_emit(self, opts) do |out|
16
+ out.seq(taguri, to_yaml_style) do |seq|
17
+ each do |k, v|
18
+ seq.add(k => v)
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ # Hash is ordered in Ruby 1.9!
25
+ if RUBY_VERSION < '1.9'
11
26
  def initialize(*args, &block)
12
27
  super
13
28
  @keys = []
@@ -55,7 +70,7 @@ module ActiveSupport
55
70
  end
56
71
  super
57
72
  end
58
-
73
+
59
74
  def delete_if
60
75
  super
61
76
  sync_keys!
@@ -134,31 +149,10 @@ module ActiveSupport
134
149
  "#<OrderedHash #{super}>"
135
150
  end
136
151
 
137
- private
138
-
139
- def sync_keys!
140
- @keys.delete_if {|k| !has_key?(k)}
141
- end
142
- end
143
- end
144
-
145
- class OrderedHash #:nodoc:
146
- def to_yaml_type
147
- "!tag:yaml.org,2002:omap"
148
- end
149
-
150
- def to_yaml(opts = {})
151
- YAML.quick_emit(self, opts) do |out|
152
- out.seq(taguri, to_yaml_style) do |seq|
153
- each do |k, v|
154
- seq.add(k => v)
155
- end
152
+ private
153
+ def sync_keys!
154
+ @keys.delete_if {|k| !has_key?(k)}
156
155
  end
157
- end
158
156
  end
159
157
  end
160
-
161
- YAML.add_builtin_type("omap") do |type, val|
162
- ActiveSupport::OrderedHash[val.map(&:to_a).map(&:first)]
163
- end
164
158
  end
@@ -60,6 +60,20 @@ module ActiveSupport
60
60
  def assert_no_difference(expression, message = nil, &block)
61
61
  assert_difference expression, 0, message, &block
62
62
  end
63
+
64
+ # Test if an expression is blank. Passes if object.blank? is true.
65
+ #
66
+ # assert_blank [] # => true
67
+ def assert_blank(object)
68
+ assert object.blank?, "#{object.inspect} is not blank"
69
+ end
70
+
71
+ # Test if an expression is not blank. Passes if object.present? is true.
72
+ #
73
+ # assert_present {:data => 'x' } # => true
74
+ def assert_present(object)
75
+ assert object.present?, "#{object.inspect} is blank"
76
+ end
63
77
  end
64
78
  end
65
79
  end
@@ -172,19 +172,26 @@ module ActiveSupport
172
172
 
173
173
  include Comparable
174
174
  attr_reader :name
175
+ attr_reader :tzinfo
175
176
 
176
177
  # Create a new TimeZone object with the given name and offset. The
177
178
  # offset is the number of seconds that this time zone is offset from UTC
178
179
  # (GMT). Seconds were chosen as the offset unit because that is the unit that
179
180
  # Ruby uses to represent time zone offsets (see Time#utc_offset).
180
- def initialize(name, utc_offset, tzinfo = nil)
181
+ def initialize(name, utc_offset = nil, tzinfo = nil)
181
182
  @name = name
182
183
  @utc_offset = utc_offset
183
- @tzinfo = tzinfo
184
+ @tzinfo = tzinfo || TimeZone.find_tzinfo(name)
185
+ @current_period = nil
184
186
  end
185
187
 
186
188
  def utc_offset
187
- @utc_offset ||= tzinfo.current_period.utc_offset
189
+ if @utc_offset
190
+ @utc_offset
191
+ else
192
+ @current_period ||= tzinfo.current_period
193
+ @current_period.utc_offset
194
+ end
188
195
  end
189
196
 
190
197
  # Returns the offset of this time zone as a formatted string, of the
@@ -287,77 +294,11 @@ module ActiveSupport
287
294
  end
288
295
 
289
296
  # TODO: Preload instead of lazy load for thread safety
290
- def tzinfo
297
+ def self.find_tzinfo(name)
291
298
  require 'tzinfo' unless defined?(TZInfo)
292
- @tzinfo ||= TZInfo::Timezone.get(MAPPING[name])
293
- end
294
-
295
- unless const_defined?(:ZONES)
296
- ZONES = []
297
- ZONES_MAP = {}
298
- [[-39_600, "International Date Line West", "Midway Island", "Samoa" ],
299
- [-36_000, "Hawaii" ],
300
- [-32_400, "Alaska" ],
301
- [-28_800, "Pacific Time (US & Canada)", "Tijuana" ],
302
- [-25_200, "Mountain Time (US & Canada)", "Chihuahua", "Mazatlan",
303
- "Arizona" ],
304
- [-21_600, "Central Time (US & Canada)", "Saskatchewan", "Guadalajara",
305
- "Mexico City", "Monterrey", "Central America" ],
306
- [-18_000, "Eastern Time (US & Canada)", "Indiana (East)", "Bogota",
307
- "Lima", "Quito" ],
308
- [-16_200, "Caracas" ],
309
- [-14_400, "Atlantic Time (Canada)", "La Paz", "Santiago" ],
310
- [-12_600, "Newfoundland" ],
311
- [-10_800, "Brasilia", "Buenos Aires", "Georgetown", "Greenland" ],
312
- [ -7_200, "Mid-Atlantic" ],
313
- [ -3_600, "Azores", "Cape Verde Is." ],
314
- [ 0, "Dublin", "Edinburgh", "Lisbon", "London", "Casablanca",
315
- "Monrovia", "UTC" ],
316
- [ 3_600, "Belgrade", "Bratislava", "Budapest", "Ljubljana", "Prague",
317
- "Sarajevo", "Skopje", "Warsaw", "Zagreb", "Brussels",
318
- "Copenhagen", "Madrid", "Paris", "Amsterdam", "Berlin",
319
- "Bern", "Rome", "Stockholm", "Vienna",
320
- "West Central Africa" ],
321
- [ 7_200, "Bucharest", "Cairo", "Helsinki", "Kyev", "Riga", "Sofia",
322
- "Tallinn", "Vilnius", "Athens", "Istanbul", "Minsk",
323
- "Jerusalem", "Harare", "Pretoria" ],
324
- [ 10_800, "Moscow", "St. Petersburg", "Volgograd", "Kuwait", "Riyadh",
325
- "Nairobi", "Baghdad" ],
326
- [ 12_600, "Tehran" ],
327
- [ 14_400, "Abu Dhabi", "Muscat", "Baku", "Tbilisi", "Yerevan" ],
328
- [ 16_200, "Kabul" ],
329
- [ 18_000, "Ekaterinburg", "Islamabad", "Karachi", "Tashkent" ],
330
- [ 19_800, "Chennai", "Kolkata", "Mumbai", "New Delhi", "Sri Jayawardenepura" ],
331
- [ 20_700, "Kathmandu" ],
332
- [ 21_600, "Astana", "Dhaka", "Almaty",
333
- "Novosibirsk" ],
334
- [ 23_400, "Rangoon" ],
335
- [ 25_200, "Bangkok", "Hanoi", "Jakarta", "Krasnoyarsk" ],
336
- [ 28_800, "Beijing", "Chongqing", "Hong Kong", "Urumqi",
337
- "Kuala Lumpur", "Singapore", "Taipei", "Perth", "Irkutsk",
338
- "Ulaan Bataar" ],
339
- [ 32_400, "Seoul", "Osaka", "Sapporo", "Tokyo", "Yakutsk" ],
340
- [ 34_200, "Darwin", "Adelaide" ],
341
- [ 36_000, "Canberra", "Melbourne", "Sydney", "Brisbane", "Hobart",
342
- "Vladivostok", "Guam", "Port Moresby" ],
343
- [ 39_600, "Magadan", "Solomon Is.", "New Caledonia" ],
344
- [ 43_200, "Fiji", "Kamchatka", "Marshall Is.", "Auckland",
345
- "Wellington" ],
346
- [ 46_800, "Nuku'alofa" ]].
347
- each do |offset, *places|
348
- places.each do |place|
349
- place.freeze
350
- zone = new(place, offset)
351
- ZONES << zone
352
- ZONES_MAP[place] = zone
353
- end
354
- end
355
- ZONES.sort!
356
- ZONES.freeze
357
- ZONES_MAP.freeze
358
-
359
- US_ZONES = ZONES.find_all { |z| z.name =~ /US|Arizona|Indiana|Hawaii|Alaska/ }
360
- US_ZONES.freeze
299
+ ::TZInfo::Timezone.get(MAPPING[name] || name)
300
+ rescue TZInfo::InvalidTimezoneIdentifier
301
+ nil
361
302
  end
362
303
 
363
304
  class << self
@@ -374,7 +315,68 @@ module ActiveSupport
374
315
  # TimeZone objects per time zone, in many cases, to make it easier
375
316
  # for users to find their own time zone.
376
317
  def all
377
- ZONES
318
+ @zones ||= zones_map.values.sort
319
+ end
320
+
321
+ def zones_map
322
+ unless defined?(@zones_map)
323
+ @zones_map = {}
324
+ [[-39_600, "International Date Line West", "Midway Island", "Samoa" ],
325
+ [-36_000, "Hawaii" ],
326
+ [-32_400, "Alaska" ],
327
+ [-28_800, "Pacific Time (US & Canada)", "Tijuana" ],
328
+ [-25_200, "Mountain Time (US & Canada)", "Chihuahua", "Mazatlan",
329
+ "Arizona" ],
330
+ [-21_600, "Central Time (US & Canada)", "Saskatchewan", "Guadalajara",
331
+ "Mexico City", "Monterrey", "Central America" ],
332
+ [-18_000, "Eastern Time (US & Canada)", "Indiana (East)", "Bogota",
333
+ "Lima", "Quito" ],
334
+ [-16_200, "Caracas" ],
335
+ [-14_400, "Atlantic Time (Canada)", "La Paz", "Santiago" ],
336
+ [-12_600, "Newfoundland" ],
337
+ [-10_800, "Brasilia", "Buenos Aires", "Georgetown", "Greenland" ],
338
+ [ -7_200, "Mid-Atlantic" ],
339
+ [ -3_600, "Azores", "Cape Verde Is." ],
340
+ [ 0, "Dublin", "Edinburgh", "Lisbon", "London", "Casablanca",
341
+ "Monrovia", "UTC" ],
342
+ [ 3_600, "Belgrade", "Bratislava", "Budapest", "Ljubljana", "Prague",
343
+ "Sarajevo", "Skopje", "Warsaw", "Zagreb", "Brussels",
344
+ "Copenhagen", "Madrid", "Paris", "Amsterdam", "Berlin",
345
+ "Bern", "Rome", "Stockholm", "Vienna",
346
+ "West Central Africa" ],
347
+ [ 7_200, "Bucharest", "Cairo", "Helsinki", "Kyev", "Riga", "Sofia",
348
+ "Tallinn", "Vilnius", "Athens", "Istanbul", "Minsk",
349
+ "Jerusalem", "Harare", "Pretoria" ],
350
+ [ 10_800, "Moscow", "St. Petersburg", "Volgograd", "Kuwait", "Riyadh",
351
+ "Nairobi", "Baghdad" ],
352
+ [ 12_600, "Tehran" ],
353
+ [ 14_400, "Abu Dhabi", "Muscat", "Baku", "Tbilisi", "Yerevan" ],
354
+ [ 16_200, "Kabul" ],
355
+ [ 18_000, "Ekaterinburg", "Islamabad", "Karachi", "Tashkent" ],
356
+ [ 19_800, "Chennai", "Kolkata", "Mumbai", "New Delhi", "Sri Jayawardenepura" ],
357
+ [ 20_700, "Kathmandu" ],
358
+ [ 21_600, "Astana", "Dhaka", "Almaty",
359
+ "Novosibirsk" ],
360
+ [ 23_400, "Rangoon" ],
361
+ [ 25_200, "Bangkok", "Hanoi", "Jakarta", "Krasnoyarsk" ],
362
+ [ 28_800, "Beijing", "Chongqing", "Hong Kong", "Urumqi",
363
+ "Kuala Lumpur", "Singapore", "Taipei", "Perth", "Irkutsk",
364
+ "Ulaan Bataar" ],
365
+ [ 32_400, "Seoul", "Osaka", "Sapporo", "Tokyo", "Yakutsk" ],
366
+ [ 34_200, "Darwin", "Adelaide" ],
367
+ [ 36_000, "Canberra", "Melbourne", "Sydney", "Brisbane", "Hobart",
368
+ "Vladivostok", "Guam", "Port Moresby" ],
369
+ [ 39_600, "Magadan", "Solomon Is.", "New Caledonia" ],
370
+ [ 43_200, "Fiji", "Kamchatka", "Marshall Is.", "Auckland",
371
+ "Wellington" ],
372
+ [ 46_800, "Nuku'alofa" ]].
373
+ each do |offset, *places|
374
+ places.each do |place|
375
+ @zones_map[place] = create(place, offset)
376
+ end
377
+ end
378
+ end
379
+ @zones_map
378
380
  end
379
381
 
380
382
  # Locate a specific time zone object. If the argument is a string, it
@@ -385,7 +387,7 @@ module ActiveSupport
385
387
  def [](arg)
386
388
  case arg
387
389
  when String
388
- ZONES_MAP[arg]
390
+ zones_map[arg] ||= lookup(arg)
389
391
  when Numeric, ActiveSupport::Duration
390
392
  arg *= 3600 if arg.abs <= 13
391
393
  all.find { |z| z.utc_offset == arg.to_i }
@@ -397,8 +399,14 @@ module ActiveSupport
397
399
  # A convenience method for returning a collection of TimeZone objects
398
400
  # for time zones in the USA.
399
401
  def us_zones
400
- US_ZONES
402
+ @us_zones ||= all.find_all { |z| z.name =~ /US|Arizona|Indiana|Hawaii|Alaska/ }
401
403
  end
404
+
405
+ private
406
+
407
+ def lookup(name)
408
+ (tzinfo = find_tzinfo(name)) && create(tzinfo.name.freeze)
409
+ end
402
410
  end
403
411
  end
404
412
  end