diff options
66 files changed, 399 insertions, 144 deletions
diff --git a/.gitignore b/.gitignore index d19b982f85..e57310cdc8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,9 @@ actionpack/doc actionmailer/doc activesupport/doc railties/doc +activeresource/pkg +activerecord/pkg +actionpack/pkg +actionmailer/pkg +activesupport/pkg +railties/pkg diff --git a/actionmailer/lib/action_mailer/vendor.rb b/actionmailer/lib/action_mailer/vendor.rb index 56a2858be5..7a20e9bd6e 100644 --- a/actionmailer/lib/action_mailer/vendor.rb +++ b/actionmailer/lib/action_mailer/vendor.rb @@ -2,9 +2,9 @@ require 'rubygems' begin - gem 'tmail', '~> 1.2.2' + gem 'tmail', '~> 1.2.3' rescue Gem::LoadError - $:.unshift "#{File.dirname(__FILE__)}/vendor/tmail-1.2.2" + $:.unshift "#{File.dirname(__FILE__)}/vendor/tmail-1.2.3" end begin diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail.rb index 18003659a6..18003659a6 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/address.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/address.rb index fa8e5bcd8c..fa8e5bcd8c 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/address.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/address.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/attachments.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/attachments.rb index 5dc5efae5e..5dc5efae5e 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/attachments.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/attachments.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/base64.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/base64.rb index e294c62960..e294c62960 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/base64.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/base64.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/compat.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/compat.rb index 1275df79a6..1275df79a6 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/compat.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/compat.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/config.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/config.rb index 3a876dcdbd..3a876dcdbd 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/config.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/config.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/core_extensions.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/core_extensions.rb index da62c33bbf..da62c33bbf 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/core_extensions.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/core_extensions.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/encode.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/encode.rb index 63bccce4fc..458dbbfe6a 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/encode.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/encode.rb @@ -339,22 +339,36 @@ module TMail def scanadd( str, force = false ) types = '' strs = [] - + if str.respond_to?(:encoding) + enc = str.encoding + str.force_encoding(Encoding::ASCII_8BIT) + end until str.empty? if m = /\A[^\e\t\r\n ]+/.match(str) types << (force ? 'j' : 'a') - strs.push m[0] - + if str.respond_to?(:encoding) + strs.push m[0].force_encoding(enc) + else + strs.push m[0] + end elsif m = /\A[\t\r\n ]+/.match(str) types << 's' - strs.push m[0] + if str.respond_to?(:encoding) + strs.push m[0].force_encoding(enc) + else + strs.push m[0] + end elsif m = /\A\e../.match(str) esc = m[0] str = m.post_match if esc != "\e(B" and m = /\A[^\e]+/.match(str) types << 'j' - strs.push m[0] + if str.respond_to?(:encoding) + strs.push m[0].force_encoding(enc) + else + strs.push m[0] + end end else @@ -453,7 +467,13 @@ module TMail size = max_bytes(chunksize, str.size) - 6 size = (size % 2 == 0) ? (size) : (size - 1) return nil if size <= 0 - "\e$B#{str.slice!(0, size)}\e(B" + if str.respond_to?(:encoding) + enc = str.encoding + str.force_encoding(Encoding::ASCII_8BIT) + "\e$B#{str.slice!(0, size)}\e(B".force_encoding(enc) + else + "\e$B#{str.slice!(0, size)}\e(B" + end end def extract_A( chunksize, str ) diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/header.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/header.rb index 9153dcd7c6..9153dcd7c6 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/header.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/header.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/index.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/index.rb index 554e2fd696..554e2fd696 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/index.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/index.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/interface.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/interface.rb index 206653bd5d..a6d428d7d6 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/interface.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/interface.rb @@ -591,12 +591,17 @@ module TMail end # Destructively sets the message ID of the mail object instance to the passed in string + # + # Invalid message IDs are ignored (silently, unless configured otherwise) and result in + # a nil message ID. Left and right angle brackets are required. # # Example: # # mail = TMail::Mail.new + # mail.message_id = "<348F04F142D69C21-291E56D292BC@xxxx.net>" + # mail.message_id #=> "<348F04F142D69C21-291E56D292BC@xxxx.net>" # mail.message_id = "this_is_my_badly_formatted_message_id" - # mail.message_id #=> "this_is_my_badly_formatted_message_id" + # mail.message_id #=> nil def message_id=( str ) set_string_attr 'Message-Id', str end diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/loader.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/loader.rb index 6c0e251102..6c0e251102 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/loader.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/loader.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mail.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb index fef6b01c39..5a319907ae 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mail.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb @@ -408,8 +408,8 @@ module TMail when /\AFrom (\S+)/ unixfrom = $1 - when /^charset=.*/ - + when /^charset=.*/ + else raise SyntaxError, "wrong mail header: '#{line.inspect}'" end diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mailbox.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mailbox.rb index b0bc6a7f74..b0bc6a7f74 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mailbox.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mailbox.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/main.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/main.rb index e52772793f..e52772793f 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/main.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/main.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mbox.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mbox.rb index 6c0e251102..6c0e251102 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mbox.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mbox.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/net.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/net.rb index 65147228a1..65147228a1 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/net.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/net.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/obsolete.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/obsolete.rb index 22b0a126ca..22b0a126ca 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/obsolete.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/obsolete.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/parser.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/parser.rb index ab1a828471..ab1a828471 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/parser.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/parser.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/port.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/port.rb index 445f0e632b..445f0e632b 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/port.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/port.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/quoting.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/quoting.rb index cb9f4288f1..cb9f4288f1 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/quoting.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/quoting.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/require_arch.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/require_arch.rb index b4fffb8abb..b4fffb8abb 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/require_arch.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/require_arch.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner.rb index a5d01396b8..a5d01396b8 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner_r.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner_r.rb index f2075502d8..f2075502d8 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner_r.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner_r.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/stringio.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/stringio.rb index 8357398788..8357398788 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/stringio.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/stringio.rb diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/utils.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/utils.rb index 9a3afe8985..dc594a4229 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/utils.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/utils.rb @@ -118,7 +118,7 @@ module TMail ATOM_UNSAFE = /[#{Regexp.quote aspecial}#{control}#{lwsp}]/n PHRASE_UNSAFE = /[#{Regexp.quote aspecial}#{control}]/n TOKEN_UNSAFE = /[#{Regexp.quote tspecial}#{control}#{lwsp}]/n - + # Returns true if the string supplied is free from characters not allowed as an ATOM def atom_safe?( str ) not ATOM_UNSAFE === str diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/version.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/version.rb index 6bf8cc8061..95228497c0 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/version.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/version.rb @@ -32,7 +32,7 @@ module TMail module VERSION MAJOR = 1 MINOR = 2 - TINY = 2 + TINY = 3 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 4a24d2f8b9..5c4bfbf3c9 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,3 +1,5 @@ +* InstanceTag#default_time_from_options overflows to DateTime [Geoff Buesing] + *2.1.0 RC1 (May 11th, 2008)* * Fixed that forgery protection can be used without session tracking (Peter Jones) [#139] diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/action_controller/caching/fragments.rb index e4d8678a07..e4f5de44ab 100644 --- a/actionpack/lib/action_controller/caching/fragments.rb +++ b/actionpack/lib/action_controller/caching/fragments.rb @@ -98,6 +98,17 @@ module ActionController #:nodoc: end end + # Check if a cached fragment from the location signified by <tt>key</tt> exists (see <tt>expire_fragment</tt> for acceptable formats) + def fragment_exist?(key, options = nil) + return unless cache_configured? + + key = fragment_cache_key(key) + + self.class.benchmark "Cached fragment exists?: #{key}" do + cache_store.exist?(key, options) + end + end + # Name can take one of three forms: # * String: This would normally take the form of a path like "pages/45/notes" # * Hash: Is treated as an implicit call to url_for, like { :controller => "pages", :action => "notes", :id => 45 } @@ -124,4 +135,4 @@ module ActionController #:nodoc: end end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_controller/cgi_ext/stdinput.rb b/actionpack/lib/action_controller/cgi_ext/stdinput.rb index b0ca63ef2f..5e9b6784af 100644 --- a/actionpack/lib/action_controller/cgi_ext/stdinput.rb +++ b/actionpack/lib/action_controller/cgi_ext/stdinput.rb @@ -16,6 +16,7 @@ module ActionController def initialize_with_stdinput(type = nil, stdinput = $stdin) @stdinput = stdinput + @stdinput.set_encoding(Encoding::BINARY) if @stdinput.respond_to?(:set_encoding) initialize_without_stdinput(type || 'query') end end diff --git a/actionpack/lib/action_controller/cgi_process.rb b/actionpack/lib/action_controller/cgi_process.rb index b529db8af4..7e58c98bf2 100644 --- a/actionpack/lib/action_controller/cgi_process.rb +++ b/actionpack/lib/action_controller/cgi_process.rb @@ -65,6 +65,7 @@ module ActionController #:nodoc: # variable is already set, wrap it in a StringIO. def body if raw_post = env['RAW_POST_DATA'] + raw_post.force_encoding(Encoding::BINARY) if raw_post.respond_to?(:force_encoding) StringIO.new(raw_post) else @cgi.stdinput diff --git a/actionpack/lib/action_controller/integration.rb b/actionpack/lib/action_controller/integration.rb index 3b1d2b5641..a2fe631172 100644 --- a/actionpack/lib/action_controller/integration.rb +++ b/actionpack/lib/action_controller/integration.rb @@ -228,6 +228,8 @@ module ActionController super + stdinput.set_encoding(Encoding::BINARY) if stdinput.respond_to?(:set_encoding) + stdinput.force_encoding(Encoding::BINARY) if stdinput.respond_to?(:force_encoding) @stdinput = stdinput.is_a?(IO) ? stdinput : StringIO.new(stdinput || '') end end @@ -382,6 +384,8 @@ module ActionController multipart_requestify(params).map do |key, value| if value.respond_to?(:original_filename) File.open(value.path) do |f| + f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding) + <<-EOF --#{boundary}\r Content-Disposition: form-data; name="#{key}"; filename="#{CGI.escape(value.original_filename)}"\r diff --git a/actionpack/lib/action_controller/request.rb b/actionpack/lib/action_controller/request.rb index d5ecbd9d29..a35b904194 100755 --- a/actionpack/lib/action_controller/request.rb +++ b/actionpack/lib/action_controller/request.rb @@ -466,8 +466,8 @@ EOM parser.result end - def parse_multipart_form_parameters(body, boundary, content_length, env) - parse_request_parameters(read_multipart(body, boundary, content_length, env)) + def parse_multipart_form_parameters(body, boundary, body_size, env) + parse_request_parameters(read_multipart(body, boundary, body_size, env)) end def extract_multipart_boundary(content_type_with_parameters) @@ -519,7 +519,7 @@ EOM EOL = "\015\012" - def read_multipart(body, boundary, content_length, env) + def read_multipart(body, boundary, body_size, env) params = Hash.new([]) boundary = "--" + boundary quoted_boundary = Regexp.quote(boundary) @@ -529,8 +529,14 @@ EOM # start multipart/form-data body.binmode if defined? body.binmode + case body + when File + body.set_encoding(Encoding::BINARY) if body.respond_to?(:set_encoding) + when StringIO + body.string.force_encoding(Encoding::BINARY) if body.string.respond_to?(:force_encoding) + end boundary_size = boundary.size + EOL.size - content_length -= boundary_size + body_size -= boundary_size status = body.read(boundary_size) if nil == status raise EOFError, "no content body" @@ -541,7 +547,7 @@ EOM loop do head = nil content = - if 10240 < content_length + if 10240 < body_size UploadedTempfile.new("CGI") else UploadedStringIO.new @@ -563,24 +569,24 @@ EOM buf[0 ... (buf.size - (EOL + boundary + EOL).size)] = "" end - c = if bufsize < content_length + c = if bufsize < body_size body.read(bufsize) else - body.read(content_length) + body.read(body_size) end if c.nil? || c.empty? raise EOFError, "bad content body" end buf.concat(c) - content_length -= c.size + body_size -= c.size end buf = buf.sub(/\A((?:.|\n)*?)(?:[\r\n]{1,2})?#{quoted_boundary}([\r\n]{1,2}|--)/n) do content.print $1 if "--" == $2 - content_length = -1 + body_size = -1 end - boundary_end = $2.dup + boundary_end = $2.dup "" end @@ -607,7 +613,7 @@ EOM else params[name] = [content] end - break if content_length == -1 + break if body_size == -1 end raise EOFError, "bad boundary end of body part" unless boundary_end=~/--/ diff --git a/actionpack/lib/action_controller/test_process.rb b/actionpack/lib/action_controller/test_process.rb index eeb49a7021..b9966e38d5 100644 --- a/actionpack/lib/action_controller/test_process.rb +++ b/actionpack/lib/action_controller/test_process.rb @@ -49,7 +49,7 @@ module ActionController #:nodoc: # Either the RAW_POST_DATA environment variable or the URL-encoded request # parameters. def raw_post - env['RAW_POST_DATA'] ||= url_encoded_request_parameters + env['RAW_POST_DATA'] ||= returning(url_encoded_request_parameters) { |b| b.force_encoding(Encoding::BINARY) if b.respond_to?(:force_encoding) } end def port=(number) @@ -340,6 +340,7 @@ module ActionController #:nodoc: @content_type = content_type @original_filename = path.sub(/^.*#{File::SEPARATOR}([^#{File::SEPARATOR}]+)$/) { $1 } @tempfile = Tempfile.new(@original_filename) + @tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding) @tempfile.binmode if binary FileUtils.copy_file(path, @tempfile.path) end diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 4840b2526d..f398756550 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -168,12 +168,12 @@ module ActionView #:nodoc: # Specify whether file modification times should be checked to see if a template needs recompilation @@cache_template_loading = false cattr_accessor :cache_template_loading - - # Specify whether file extension lookup should be cached, and whether template base path lookup should be cached. - # Should be +false+ for development environments. Defaults to +true+. - @@cache_template_extensions = true - cattr_accessor :cache_template_extensions + def self.cache_template_extensions=(*args) + ActiveSupport::Deprecation.warn("config.action_view.cache_template_extensions option has been deprecated and has no affect. " << + "Please remove it from your config files.", caller) + end + # Specify whether RJS responses should be wrapped in a try/catch block # that alert()s the caught exception (and then re-raises it). @@debug_rjs = false diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb index 8a9c8044ae..7ed6272898 100755 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -689,7 +689,7 @@ module ActionView default[key] ||= time.send(key) end - Time.utc(default[:year], default[:month], default[:day], default[:hour], default[:min], default[:sec]) + Time.utc_time(default[:year], default[:month], default[:day], default[:hour], default[:min], default[:sec]) end end end diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 460d47fb0f..59d95d3631 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -146,6 +146,12 @@ module ActionView # to TimeZone. This may be used by users to specify a different time # zone model object. (See +time_zone_options_for_select+ for more # information.) + # + # You can also supply an array of TimeZone objects + # as +priority_zones+, so that they will be listed above the rest of the + # (long) list. (You can use TimeZone.us_zones as a convenience for + # obtaining a list of the US time zones.) + # # Finally, this method supports a <tt>:default</tt> option, which selects # a default TimeZone if the object's time zone is +nil+. # @@ -156,6 +162,8 @@ module ActionView # # time_zone_select( "user", 'time_zone', TimeZone.us_zones, :default => "Pacific Time (US & Canada)") # + # time_zone_select( "user", 'time_zone', [ TimeZone['Alaska'], TimeZone['Hawaii'] ]) + # # time_zone_select( "user", "time_zone", TZInfo::Timezone.all.sort, :model => TZInfo::Timezone) def time_zone_select(object, method, priority_zones = nil, options = {}, html_options = {}) InstanceTag.new(object, method, self, nil, options.delete(:object)).to_time_zone_select_tag(priority_zones, options, html_options) diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index c79f791c57..602832e470 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -1068,7 +1068,7 @@ module ActionView def build_observer(klass, name, options = {}) if options[:with] && (options[:with] !~ /[\{=(.]/) - options[:with] = "'#{options[:with]}=' + value" + options[:with] = "'#{options[:with]}=' + encodeURIComponent(value)" else options[:with] ||= 'value' unless options[:function] end diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index 1db057580b..f152b1d19c 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -131,6 +131,10 @@ class AssertResponseWithUnexpectedErrorController < ActionController::Base def index raise 'FAIL' end + + def show + render :text => "Boom", :status => 500 + end end module Admin @@ -483,6 +487,16 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase rescue Test::Unit::AssertionFailedError => e assert e.message.include?('FAIL') end + + def test_assert_response_failure_response_with_no_exception + @controller = AssertResponseWithUnexpectedErrorController.new + get :show + assert_response :success + flunk 'Expected non-success response' + rescue Test::Unit::AssertionFailedError + rescue + flunk "assert_response failed to handle failure response with missing, but optional, exception." + end end class ActionPackHeaderTest < Test::Unit::TestCase diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index 4aacb4a78a..f9b6b87bc6 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -232,7 +232,7 @@ class ActionCacheTest < Test::Unit::TestCase get :index cached_time = content_to_cache assert_equal cached_time, @response.body - assert_cache_exists 'hostname.com/action_caching_test' + assert fragment_exist?('hostname.com/action_caching_test') reset! get :index @@ -243,7 +243,7 @@ class ActionCacheTest < Test::Unit::TestCase get :destroy cached_time = content_to_cache assert_equal cached_time, @response.body - assert_cache_does_not_exist 'hostname.com/action_caching_test/destroy' + assert !fragment_exist?('hostname.com/action_caching_test/destroy') reset! get :destroy @@ -254,7 +254,7 @@ class ActionCacheTest < Test::Unit::TestCase get :with_layout cached_time = content_to_cache assert_not_equal cached_time, @response.body - assert_cache_exists 'hostname.com/action_caching_test/with_layout' + assert fragment_exist?('hostname.com/action_caching_test/with_layout') reset! get :with_layout @@ -266,14 +266,14 @@ class ActionCacheTest < Test::Unit::TestCase def test_action_cache_conditional_options @request.env['HTTP_ACCEPT'] = 'application/json' get :index - assert_cache_does_not_exist 'hostname.com/action_caching_test' + assert !fragment_exist?('hostname.com/action_caching_test') end def test_action_cache_with_custom_cache_path get :show cached_time = content_to_cache assert_equal cached_time, @response.body - assert_cache_exists 'test.host/custom/show' + assert fragment_exist?('test.host/custom/show') reset! get :show @@ -282,11 +282,11 @@ class ActionCacheTest < Test::Unit::TestCase def test_action_cache_with_custom_cache_path_in_block get :edit - assert_cache_exists 'test.host/edit' + assert fragment_exist?('test.host/edit') reset! get :edit, :id => 1 - assert_cache_exists 'test.host/1;edit' + assert fragment_exist?('test.host/1;edit') end def test_cache_expiration @@ -395,18 +395,8 @@ class ActionCacheTest < Test::Unit::TestCase @request.host = 'hostname.com' end - def assert_cache_exists(path) - full_path = cache_path(path) - assert File.exist?(full_path), "#{full_path.inspect} does not exist." - end - - def assert_cache_does_not_exist(path) - full_path = cache_path(path) - assert !File.exist?(full_path), "#{full_path.inspect} should not exist." - end - - def cache_path(path) - File.join(FILE_STORE_PATH, 'views', path + '.cache') + def fragment_exist?(path) + @controller.fragment_exist?(path) end def read_fragment(path) @@ -450,6 +440,19 @@ class FragmentCachingTest < Test::Unit::TestCase assert_nil @controller.read_fragment('name') end + def test_fragment_exist__with_caching_enabled + @store.write('views/name', 'value') + assert @controller.fragment_exist?('name') + assert !@controller.fragment_exist?('other_name') + end + + def test_fragment_exist__with_caching_disabled + ActionController::Base.perform_caching = false + @store.write('views/name', 'value') + assert !@controller.fragment_exist?('name') + assert !@controller.fragment_exist?('other_name') + end + def test_write_fragment__with_caching_enabled assert_nil @store.read('views/name') assert_equal 'value', @controller.write_fragment('name', 'value') @@ -494,7 +497,6 @@ class FragmentCachingTest < Test::Unit::TestCase assert_equal 'generated till now -> ', buffer end - def test_fragment_for @store.write('views/expensive', 'fragment content') fragment_computed = false diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb index 6dc77a4aaf..83e3b085e7 100644 --- a/actionpack/test/controller/helper_test.rb +++ b/actionpack/test/controller/helper_test.rb @@ -85,7 +85,7 @@ class HelperTest < Test::Unit::TestCase def test_helper_block_include assert_equal expected_helper_methods, missing_methods assert_nothing_raised { - @controller_class.helper { include TestHelper } + @controller_class.helper { include HelperTest::TestHelper } } assert [], missing_methods end diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb index ba6c7f4299..38898a1f75 100644 --- a/actionpack/test/controller/test_test.rb +++ b/actionpack/test/controller/test_test.rb @@ -511,16 +511,26 @@ XML FILES_DIR = File.dirname(__FILE__) + '/../fixtures/multipart' + if RUBY_VERSION < '1.9' + READ_BINARY = 'rb' + READ_PLAIN = 'r' + else + READ_BINARY = 'rb:binary' + READ_PLAIN = 'r:binary' + end + def test_test_uploaded_file filename = 'mona_lisa.jpg' path = "#{FILES_DIR}/#{filename}" content_type = 'image/png' + expected = File.read(path) + expected.force_encoding(Encoding::BINARY) if expected.respond_to?(:force_encoding) file = ActionController::TestUploadedFile.new(path, content_type) assert_equal filename, file.original_filename assert_equal content_type, file.content_type assert_equal file.path, file.local_path - assert_equal File.read(path), file.read + assert_equal expected, file.read end def test_test_uploaded_file_with_binary @@ -529,10 +539,10 @@ XML content_type = 'image/png' binary_uploaded_file = ActionController::TestUploadedFile.new(path, content_type, :binary) - assert_equal File.open(path, 'rb').read, binary_uploaded_file.read + assert_equal File.open(path, READ_BINARY).read, binary_uploaded_file.read plain_uploaded_file = ActionController::TestUploadedFile.new(path, content_type) - assert_equal File.open(path, 'r').read, plain_uploaded_file.read + assert_equal File.open(path, READ_PLAIN).read, plain_uploaded_file.read end def test_fixture_file_upload_with_binary @@ -541,10 +551,10 @@ XML content_type = 'image/jpg' binary_file_upload = fixture_file_upload(path, content_type, :binary) - assert_equal File.open(path, 'rb').read, binary_file_upload.read + assert_equal File.open(path, READ_BINARY).read, binary_file_upload.read plain_file_upload = fixture_file_upload(path, content_type) - assert_equal File.open(path, 'r').read, plain_file_upload.read + assert_equal File.open(path, READ_PLAIN).read, plain_file_upload.read end def test_fixture_file_upload diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb index ae83c7bf47..0a7b19ba96 100755 --- a/actionpack/test/template/date_helper_test.rb +++ b/actionpack/test/template/date_helper_test.rb @@ -1722,6 +1722,12 @@ class DateHelperTest < ActionView::TestCase assert_equal 2, dummy_instance_tag.send!(:default_time_from_options, :hour => 2).hour end end + + def test_instance_tag_default_time_from_options_handles_far_future_date + dummy_instance_tag = ActionView::Helpers::InstanceTag.new(1,2,3) + time = dummy_instance_tag.send!(:default_time_from_options, :year => 2050, :month => 2, :day => 10, :hour => 15, :min => 30, :sec => 45) + assert_equal 2050, time.year + end end protected diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb index 9a1079b297..5e00eadb8d 100644 --- a/actionpack/test/template/prototype_helper_test.rb +++ b/actionpack/test/template/prototype_helper_test.rb @@ -219,9 +219,9 @@ class PrototypeHelperTest < PrototypeHelperBaseTest end def test_observe_field_using_with_option - expected = %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/check_value', {asynchronous:true, evalScripts:true, parameters:'id=' + value})})\n//]]>\n</script>) + expected = %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/check_value', {asynchronous:true, evalScripts:true, parameters:'id=' + encodeURIComponent(value)})})\n//]]>\n</script>) assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id') - assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + value") + assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + encodeURIComponent(value)") end def test_observe_field_using_json_in_with_option diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb index 68503a3c40..ec16af3897 100644 --- a/activerecord/lib/active_record/associations/association_proxy.rb +++ b/activerecord/lib/active_record/associations/association_proxy.rb @@ -49,7 +49,7 @@ module ActiveRecord alias_method :proxy_respond_to?, :respond_to? alias_method :proxy_extend, :extend delegate :to_param, :to => :proxy_target - instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_)/ } + instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^object_id$)/ } def initialize(owner, reflection) @owner, @reflection = owner, reflection diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index c2604894a8..d753778d52 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -162,6 +162,8 @@ module ActiveRecord evaluate_attribute_method attr_name, "def #{attr_name}; unserialize_attribute('#{attr_name}'); end" end + # Defined for all datetime and timestamp attributes when time_zone_aware_attributes are enabled. + # This enhanced read method automatically converts the UTC time stored in the database to the time zone stored in Time.zone def define_read_method_for_time_zone_conversion(attr_name) method_body = <<-EOV def #{attr_name}(reload = false) @@ -183,6 +185,8 @@ module ActiveRecord evaluate_attribute_method attr_name, "def #{attr_name}=(new_value);write_attribute('#{attr_name}', new_value);end", "#{attr_name}=" end + # Defined for all datetime and timestamp attributes when time_zone_aware_attributes are enabled. + # This enhanced write method will automatically convert the time passed to it to the zone stored in Time.zone. def define_write_method_for_time_zone_conversion(attr_name) method_body = <<-EOV def #{attr_name}=(time) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 01e128f02f..67d70b3886 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -302,7 +302,7 @@ module ActiveRecord def dump_schema_information #:nodoc: sm_table = ActiveRecord::Migrator.schema_migrations_table_name migrated = select_values("SELECT version FROM #{sm_table}") - migrated.map { |v| "INSERT INTO #{sm_table} (version) VALUES ('#{v}');" }.join("\n") + migrated.map { |v| "INSERT INTO #{sm_table} (version) VALUES ('#{v}');" }.join("\n\n") end # Should not be called normally, but this operation is non-destructive. diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index d43ebefc3b..06edaed3d5 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -102,7 +102,7 @@ module ActiveRecord class Scope attr_reader :proxy_scope, :proxy_options - [].methods.each { |m| delegate m, :to => :proxy_found unless m =~ /(^__|^nil\?|^send|class|extend|find|count|sum|average|maximum|minimum|paginate)/ } + [].methods.each { |m| delegate m, :to => :proxy_found unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|find|count|sum|average|maximum|minimum|paginate)/ } delegate :scopes, :with_scope, :to => :proxy_scope def initialize(proxy_scope, options, &block) @@ -136,4 +136,4 @@ module ActiveRecord end end end -end
\ No newline at end of file +end diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index b8ec9117af..4382ba17ef 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -54,8 +54,8 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase original_proxy = citibank.firm citibank.firm = another_firm - assert_equal first_firm.object_id, original_proxy.object_id - assert_equal another_firm.object_id, citibank.firm.object_id + assert_equal first_firm.object_id, original_proxy.target.object_id + assert_equal another_firm.object_id, citibank.firm.target.object_id end def test_creating_the_belonging_object diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index e8821060f9..6250f33998 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,3 +1,9 @@ +* Hash.from_xml: datetime xml types overflow to Ruby DateTime class when out of range of Time. Adding tests for utc offsets [Geoff Buesing] + +* TimeWithZone #+ and #- : ensure overflow to DateTime with Numeric arg [Geoff Buesing] + +* Time#to_json: don't convert to utc before encoding. References #175 [Geoff Buesing] + *2.1.0 RC1 (May 11th, 2008)* * Remove unused JSON::RESERVED_WORDS, JSON.valid_identifier? and JSON.reserved_word? methods. Resolves #164. [Cheah Chu Yeow] diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index b3c9c23d9f..2f1143e610 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -87,8 +87,12 @@ module ActiveSupport def delete_matched(matcher, options = nil) log("delete matched", matcher.inspect, options) - end - + end + + def exist?(key, options = nil) + log("exist?", key, options) + end + def increment(key, amount = 1) log("incrementing", key, amount) if num = read(key) diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb index 16a2509ce2..5b771b1da0 100644 --- a/activesupport/lib/active_support/cache/file_store.rb +++ b/activesupport/lib/active_support/cache/file_store.rb @@ -40,13 +40,18 @@ module ActiveSupport end end + def exist?(name, options = nil) + super + File.exist?(real_file_path(name)) + end + private def real_file_path(name) '%s/%s.cache' % [@cache_path, name.gsub('?', '.').gsub(':', '.')] end def ensure_cache_path(path) - FileUtils.makedirs(path) unless File.exists?(path) + FileUtils.makedirs(path) unless File.exist?(path) end def search_dir(dir, &callback) diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb index bfe7e2ccf3..b3769b812f 100644 --- a/activesupport/lib/active_support/cache/mem_cache_store.rb +++ b/activesupport/lib/active_support/cache/mem_cache_store.rb @@ -48,7 +48,13 @@ module ActiveSupport rescue MemCache::MemCacheError => e logger.error("MemCacheError (#{e}): #{e.message}") false - end + end + + def exist?(key, options = nil) + # Doesn't call super, cause exist? in memcache is in fact a read + # But who cares? Reading is very fast anyway + !read(key, options).nil? + end def increment(key, amount = 1) log("incrementing", key, amount) diff --git a/activesupport/lib/active_support/cache/memory_store.rb b/activesupport/lib/active_support/cache/memory_store.rb index 4872e025cd..6f114273e4 100644 --- a/activesupport/lib/active_support/cache/memory_store.rb +++ b/activesupport/lib/active_support/cache/memory_store.rb @@ -24,7 +24,12 @@ module ActiveSupport super @data.delete_if { |k,v| k =~ matcher } end - + + def exist?(name,options = nil) + super + @data.has_key?(name) + end + def clear @data.clear end diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb index f0f54a92fe..2c606b401b 100644 --- a/activesupport/lib/active_support/core_ext/hash/conversions.rb +++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb @@ -70,7 +70,7 @@ module ActiveSupport #:nodoc: XML_PARSING = { "symbol" => Proc.new { |symbol| symbol.to_sym }, "date" => Proc.new { |date| ::Date.parse(date) }, - "datetime" => Proc.new { |time| ::Time.parse(time).utc }, + "datetime" => Proc.new { |time| ::Time.parse(time).utc rescue ::DateTime.parse(time).utc }, "integer" => Proc.new { |integer| integer.to_i }, "float" => Proc.new { |float| float.to_f }, "decimal" => Proc.new { |number| BigDecimal(number) }, diff --git a/activesupport/lib/active_support/core_ext/time/zones.rb b/activesupport/lib/active_support/core_ext/time/zones.rb index 3ffc71407c..cf28d0fa95 100644 --- a/activesupport/lib/active_support/core_ext/time/zones.rb +++ b/activesupport/lib/active_support/core_ext/time/zones.rb @@ -1,9 +1,7 @@ module ActiveSupport #:nodoc: module CoreExtensions #:nodoc: module Time #:nodoc: - # Methods for creating TimeWithZone objects from Time instances module Zones - def self.included(base) #:nodoc: base.extend(ClassMethods) if base == ::Time # i.e., don't include class methods in DateTime end @@ -11,18 +9,31 @@ module ActiveSupport #:nodoc: module ClassMethods attr_accessor :zone_default + # Returns the TimeZone for the current request, if this has been set (via Time.zone=). + # If Time.zone has not been set for the current request, returns the TimeZone specified in config.time_zone def zone Thread.current[:time_zone] || zone_default end - # Sets a global default time zone, separate from the system time zone in ENV['TZ']. - # Accepts either a Rails TimeZone object, a string that identifies a - # Rails TimeZone object (e.g., "Central Time (US & Canada)"), or a TZInfo::Timezone object. + # Sets Time.zone to a TimeZone object for the current request/thread. + # + # This method accepts any of the following: + # + # * a Rails TimeZone object + # * an identifier for a Rails TimeZone object (e.g., "Eastern Time (US & Canada)", -5.hours) + # * a TZInfo::Timezone object + # * an identifier for a TZInfo::Timezone object (e.g., "America/New_York") + # + # Here's an example of how you might set Time.zone on a per request basis -- current_user.time_zone + # just needs to return a string identifying the user's preferred TimeZone: # - # Any Time or DateTime object can use this default time zone, via <tt>in_time_zone</tt>. + # class ApplicationController < ActionController::Base + # before_filter :set_time_zone # - # Time.zone = 'Hawaii' # => 'Hawaii' - # Time.utc(2000).in_time_zone # => Fri, 31 Dec 1999 14:00:00 HST -10:00 + # def set_time_zone + # Time.zone = current_user.time_zone + # end + # end def zone=(time_zone) Thread.current[:time_zone] = get_zone(time_zone) end diff --git a/activesupport/lib/active_support/json/encoders/time.rb b/activesupport/lib/active_support/json/encoders/time.rb index 3660d87c82..57ed3c9e31 100644 --- a/activesupport/lib/active_support/json/encoders/time.rb +++ b/activesupport/lib/active_support/json/encoders/time.rb @@ -6,7 +6,7 @@ class Time # # => 2005/02/01 15:15:10 +0000" def to_json(options = nil) if ActiveSupport.use_standard_json_time_format - utc.xmlschema.inspect + xmlschema.inspect else %("#{strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)}") end diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb index b2a937edd0..ed8e34510a 100644 --- a/activesupport/lib/active_support/testing/setup_and_teardown.rb +++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb @@ -1,6 +1,14 @@ module ActiveSupport module Testing module SetupAndTeardown + # For compatibility with Ruby < 1.8.6 + PASSTHROUGH_EXCEPTIONS = + if defined?(Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS) + Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS + else + [NoMemoryError, SignalException, Interrupt, SystemExit] + end + def self.included(base) base.send :include, ActiveSupport::Callbacks base.define_callbacks :setup, :teardown @@ -25,7 +33,7 @@ module ActiveSupport __send__(@method_name) rescue Test::Unit::AssertionFailedError => e add_failure(e.message, e.backtrace) - rescue *Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS + rescue *PASSTHROUGH_EXCEPTIONS raise rescue Exception add_error($!) @@ -35,7 +43,7 @@ module ActiveSupport run_callbacks :teardown, :enumerator => :reverse_each rescue Test::Unit::AssertionFailedError => e add_failure(e.message, e.backtrace) - rescue *Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS + rescue *PASSTHROUGH_EXCEPTIONS raise rescue Exception add_error($!) diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index fbdc680235..c9fb615fa5 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -1,7 +1,34 @@ require 'tzinfo' module ActiveSupport # A Time-like class that can represent a time in any time zone. Necessary because standard Ruby Time instances are - # limited to UTC and the system's ENV['TZ'] zone + # limited to UTC and the system's ENV['TZ'] zone. + # + # You shouldn't ever need to create a TimeWithZone instance directly via .new -- instead, Rails provides the methods + # #local, #parse, #at and #now on TimeZone instances, and #in_time_zone on Time and DateTime instances, for a more + # user-friendly syntax. Examples: + # + # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)' + # Time.zone.local(2007, 2, 10, 15, 30, 45) # => Sat, 10 Feb 2007 15:30:45 EST -05:00 + # Time.zone.parse('2007-02-01 15:30:45') # => Sat, 10 Feb 2007 15:30:45 EST -05:00 + # Time.zone.at(1170361845) # => Sat, 10 Feb 2007 15:30:45 EST -05:00 + # Time.zone.now # => Sun, 18 May 2008 13:07:55 EDT -04:00 + # Time.utc(2007, 2, 10, 20, 30, 45).in_time_zone # => Sat, 10 Feb 2007 15:30:45 EST -05:00 + # + # See TimeZone and ActiveSupport::CoreExtensions::Time::Zones for further documentation for these methods. + # + # TimeWithZone instances implement the same API as Ruby Time instances, so that Time and TimeWithZone instances are interchangable. Examples: + # + # t = Time.zone.now # => Sun, 18 May 2008 13:27:25 EDT -04:00 + # t.hour # => 13 + # t.dst? # => true + # t.utc_offset # => -14400 + # t.zone # => "EDT" + # t.to_s(:rfc822) # => "Sun, 18 May 2008 13:27:25 -0400" + # t + 1.day # => Mon, 19 May 2008 13:27:25 EDT -04:00 + # t.beginning_of_year # => Tue, 01 Jan 2008 00:00:00 EST -05:00 + # t > Time.utc(1999) # => true + # t.is_a?(Time) # => true + # t.is_a?(ActiveSupport::TimeWithZone) # => true class TimeWithZone include Comparable attr_reader :time_zone @@ -135,7 +162,7 @@ module ActiveSupport # If wrapped #time is a DateTime, use DateTime#since instead of <tt>+</tt>. # Otherwise, just pass on to +method_missing+. def +(other) - result = utc.acts_like?(:date) ? utc.since(other) : utc + other + result = utc.acts_like?(:date) ? utc.since(other) : utc + other rescue utc.since(other) result.in_time_zone(time_zone) end @@ -146,7 +173,7 @@ module ActiveSupport if other.acts_like?(:time) utc - other else - result = utc.acts_like?(:date) ? utc.ago(other) : utc - other + result = utc.acts_like?(:date) ? utc.ago(other) : utc - other rescue utc.ago(other) result.in_time_zone(time_zone) end end diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 323429d126..886c3e952d 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -1,3 +1,24 @@ +# The TimeZone class serves as a wrapper around TZInfo::Timezone instances. It allows us to do the following: +# +# * limit the set of zones provided by TZInfo to a meaningful subset of 142 zones +# * retrieve and display zones with a friendlier name (e.g., "Eastern Time (US & Canada)" instead of "America/New_York") +# * lazily load TZInfo::Timezone instances only when they're needed +# * create ActiveSupport::TimeWithZone instances via TimeZone #local, #parse, #at and #now methods +# +# If you set config.time_zone in the Rails Initializer, you can access this TimeZone object via Time.zone: +# +# # environment.rb: +# Rails::Initializer.run do |config| +# config.time_zone = "Eastern Time (US & Canada)" +# end +# +# Time.zone # => #<TimeZone:0x514834...> +# Time.zone.name # => "Eastern Time (US & Canada)" +# Time.zone.now # => Sun, 18 May 2008 14:30:44 EDT -04:00 +# +# The version of TZInfo bundled with ActiveSupport only includes the definitions necessary to support the zones +# defined by the TimeZone class. If you need to use zones that aren't defined by TimeZone, you'll need to install the TZInfo gem +# (if a recent version of the gem is installed locally, this will be used instead of the bundled version.) class TimeZone unless const_defined?(:MAPPING) # Keys are Rails TimeZone names, values are TZInfo identifiers diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/offset_rationals.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/offset_rationals.rb index 5857de623d..32fa4123f1 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/offset_rationals.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/offset_rationals.rb @@ -27,63 +27,63 @@ module TZInfo # -14 and +14 hours to avoid having to call gcd at runtime. module OffsetRationals #:nodoc: @@rational_cache = { - -50400 => Rational.new!(-7,12), - -48600 => Rational.new!(-9,16), - -46800 => Rational.new!(-13,24), - -45000 => Rational.new!(-25,48), - -43200 => Rational.new!(-1,2), - -41400 => Rational.new!(-23,48), - -39600 => Rational.new!(-11,24), - -37800 => Rational.new!(-7,16), - -36000 => Rational.new!(-5,12), - -34200 => Rational.new!(-19,48), - -32400 => Rational.new!(-3,8), - -30600 => Rational.new!(-17,48), - -28800 => Rational.new!(-1,3), - -27000 => Rational.new!(-5,16), - -25200 => Rational.new!(-7,24), - -23400 => Rational.new!(-13,48), - -21600 => Rational.new!(-1,4), - -19800 => Rational.new!(-11,48), - -18000 => Rational.new!(-5,24), - -16200 => Rational.new!(-3,16), - -14400 => Rational.new!(-1,6), - -12600 => Rational.new!(-7,48), - -10800 => Rational.new!(-1,8), - -9000 => Rational.new!(-5,48), - -7200 => Rational.new!(-1,12), - -5400 => Rational.new!(-1,16), - -3600 => Rational.new!(-1,24), - -1800 => Rational.new!(-1,48), - 0 => Rational.new!(0,1), - 1800 => Rational.new!(1,48), - 3600 => Rational.new!(1,24), - 5400 => Rational.new!(1,16), - 7200 => Rational.new!(1,12), - 9000 => Rational.new!(5,48), - 10800 => Rational.new!(1,8), - 12600 => Rational.new!(7,48), - 14400 => Rational.new!(1,6), - 16200 => Rational.new!(3,16), - 18000 => Rational.new!(5,24), - 19800 => Rational.new!(11,48), - 21600 => Rational.new!(1,4), - 23400 => Rational.new!(13,48), - 25200 => Rational.new!(7,24), - 27000 => Rational.new!(5,16), - 28800 => Rational.new!(1,3), - 30600 => Rational.new!(17,48), - 32400 => Rational.new!(3,8), - 34200 => Rational.new!(19,48), - 36000 => Rational.new!(5,12), - 37800 => Rational.new!(7,16), - 39600 => Rational.new!(11,24), - 41400 => Rational.new!(23,48), - 43200 => Rational.new!(1,2), - 45000 => Rational.new!(25,48), - 46800 => Rational.new!(13,24), - 48600 => Rational.new!(9,16), - 50400 => Rational.new!(7,12)} + -50400 => Rational(-7,12), + -48600 => Rational(-9,16), + -46800 => Rational(-13,24), + -45000 => Rational(-25,48), + -43200 => Rational(-1,2), + -41400 => Rational(-23,48), + -39600 => Rational(-11,24), + -37800 => Rational(-7,16), + -36000 => Rational(-5,12), + -34200 => Rational(-19,48), + -32400 => Rational(-3,8), + -30600 => Rational(-17,48), + -28800 => Rational(-1,3), + -27000 => Rational(-5,16), + -25200 => Rational(-7,24), + -23400 => Rational(-13,48), + -21600 => Rational(-1,4), + -19800 => Rational(-11,48), + -18000 => Rational(-5,24), + -16200 => Rational(-3,16), + -14400 => Rational(-1,6), + -12600 => Rational(-7,48), + -10800 => Rational(-1,8), + -9000 => Rational(-5,48), + -7200 => Rational(-1,12), + -5400 => Rational(-1,16), + -3600 => Rational(-1,24), + -1800 => Rational(-1,48), + 0 => Rational(0,1), + 1800 => Rational(1,48), + 3600 => Rational(1,24), + 5400 => Rational(1,16), + 7200 => Rational(1,12), + 9000 => Rational(5,48), + 10800 => Rational(1,8), + 12600 => Rational(7,48), + 14400 => Rational(1,6), + 16200 => Rational(3,16), + 18000 => Rational(5,24), + 19800 => Rational(11,48), + 21600 => Rational(1,4), + 23400 => Rational(13,48), + 25200 => Rational(7,24), + 27000 => Rational(5,16), + 28800 => Rational(1,3), + 30600 => Rational(17,48), + 32400 => Rational(3,8), + 34200 => Rational(19,48), + 36000 => Rational(5,12), + 37800 => Rational(7,16), + 39600 => Rational(11,24), + 41400 => Rational(23,48), + 43200 => Rational(1,2), + 45000 => Rational(25,48), + 46800 => Rational(13,24), + 48600 => Rational(9,16), + 50400 => Rational(7,12)} # Returns a Rational expressing the fraction of a day that offset in # seconds represents (i.e. equivalent to Rational(offset, 86400)). diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index 706e218abc..69028a123f 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -733,6 +733,44 @@ class HashToXmlTest < Test::Unit::TestCase assert_equal hash, Hash.from_xml(hash.to_xml(@xml_options))['person'] end + + def test_datetime_xml_type_with_utc_time + alert_xml = <<-XML + <alert> + <alert_at type="datetime">2008-02-10T15:30:45Z</alert_at> + </alert> + XML + alert_at = Hash.from_xml(alert_xml)['alert']['alert_at'] + assert alert_at.utc? + assert_equal Time.utc(2008, 2, 10, 15, 30, 45), alert_at + end + + def test_datetime_xml_type_with_non_utc_time + alert_xml = <<-XML + <alert> + <alert_at type="datetime">2008-02-10T10:30:45-05:00</alert_at> + </alert> + XML + alert_at = Hash.from_xml(alert_xml)['alert']['alert_at'] + assert alert_at.utc? + assert_equal Time.utc(2008, 2, 10, 15, 30, 45), alert_at + end + + def test_datetime_xml_type_with_far_future_date + alert_xml = <<-XML + <alert> + <alert_at type="datetime">2050-02-10T15:30:45Z</alert_at> + </alert> + XML + alert_at = Hash.from_xml(alert_xml)['alert']['alert_at'] + assert alert_at.utc? + assert_equal 2050, alert_at.year + assert_equal 2, alert_at.month + assert_equal 10, alert_at.day + assert_equal 15, alert_at.hour + assert_equal 30, alert_at.min + assert_equal 45, alert_at.sec + end end class QueryTest < Test::Unit::TestCase diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb index 70c393dd46..c373bca88d 100644 --- a/activesupport/test/core_ext/time_with_zone_test.rb +++ b/activesupport/test/core_ext/time_with_zone_test.rb @@ -170,6 +170,13 @@ class TimeWithZoneTest < Test::Unit::TestCase assert_equal DateTime.civil(1999, 12, 31, 19, 0 ,5), (twz + 5).time end end + + def test_plus_when_crossing_time_class_limit + silence_warnings do # silence warnings raised by tzinfo gem + twz = ActiveSupport::TimeWithZone.new(Time.utc(2038, 1, 19), @time_zone) + assert_equal [0, 0, 19, 19, 1, 2038], (twz + 86_400).to_a[0,6] + end + end def test_plus_with_duration silence_warnings do # silence warnings raised by tzinfo gem diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb index 7bc8eaf06c..38bb8f3e79 100644 --- a/activesupport/test/json/encoding_test.rb +++ b/activesupport/test/json/encoding_test.rb @@ -90,6 +90,15 @@ class TestJSONEncoding < Test::Unit::TestCase def test_hash_should_allow_key_filtering_with_except assert_equal %({"b": 2}), { 'foo' => 'bar', :b => 2, :c => 3 }.to_json(:except => ['foo', :c]) end + + def test_time_to_json_includes_local_offset + ActiveSupport.use_standard_json_time_format = true + with_env_tz 'US/Eastern' do + assert_equal %("2005-02-01T15:15:10-05:00"), Time.local(2005,2,1,15,15,10).to_json + end + ensure + ActiveSupport.use_standard_json_time_format = false + end protected def with_kcode(code) @@ -108,6 +117,13 @@ class TestJSONEncoding < Test::Unit::TestCase def object_keys(json_object) json_object[1..-2].scan(/([^{}:,\s]+):/).flatten.sort end + + def with_env_tz(new_tz = 'US/Eastern') + old_tz, ENV['TZ'] = ENV['TZ'], new_tz + yield + ensure + old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') + end end uses_mocha 'JsonOptionsTests' do |