diff options
250 files changed, 2248 insertions, 2681 deletions
diff --git a/.gitignore b/.gitignore index 8c5dfb64e1..96a1c2117a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ debug.log +doc activeresource/doc activerecord/doc actionpack/doc @@ -1,4 +1,6 @@ require 'rake' +require 'rake/rdoctask' +require 'rake/contrib/sshpublisher' env = %(PKG_BUILD="#{ENV['PKG_BUILD']}") if ENV['PKG_BUILD'] @@ -11,7 +13,7 @@ end desc 'Run all tests by default' task :default => :test -%w(test rdoc package pgem release).each do |task_name| +%w(test rdoc package release).each do |task_name| desc "Run #{task_name} task for all projects" task task_name do PROJECTS.each do |project| @@ -19,3 +21,61 @@ task :default => :test end end end + + +desc "Generate documentation for the Rails framework" +Rake::RDocTask.new do |rdoc| + rdoc.rdoc_dir = 'doc' + rdoc.title = "Rails Framework Documentation" + + rdoc.options << '--line-numbers' << '--inline-source' + rdoc.options << '-A cattr_accessor=object' + rdoc.options << '--charset' << 'utf-8' + + rdoc.template = "#{ENV['template']}.rb" if ENV['template'] + + rdoc.rdoc_files.include('railties/CHANGELOG') + rdoc.rdoc_files.include('railties/MIT-LICENSE') + rdoc.rdoc_files.include('railties/README') + rdoc.rdoc_files.include('railties/lib/{*.rb,commands/*.rb,rails/*.rb,rails_generator/*.rb}') + + rdoc.rdoc_files.include('activerecord/README') + rdoc.rdoc_files.include('activerecord/CHANGELOG') + rdoc.rdoc_files.include('activerecord/lib/active_record/**/*.rb') + rdoc.rdoc_files.exclude('activerecord/lib/active_record/vendor/*') + + rdoc.rdoc_files.include('activeresource/README') + rdoc.rdoc_files.include('activeresource/CHANGELOG') + rdoc.rdoc_files.include('activeresource/lib/active_resource.rb') + rdoc.rdoc_files.include('activeresource/lib/active_resource/*') + + rdoc.rdoc_files.include('actionpack/README') + rdoc.rdoc_files.include('actionpack/CHANGELOG') + rdoc.rdoc_files.include('actionpack/lib/action_controller/**/*.rb') + rdoc.rdoc_files.include('actionpack/lib/action_view/**/*.rb') + rdoc.rdoc_files.exclude('actionpack/lib/action_controller/vendor/*') + + rdoc.rdoc_files.include('actionmailer/README') + rdoc.rdoc_files.include('actionmailer/CHANGELOG') + rdoc.rdoc_files.include('actionmailer/lib/action_mailer/base.rb') + rdoc.rdoc_files.exclude('actionmailer/lib/action_mailer/vendor/*') + + rdoc.rdoc_files.include('activesupport/README') + rdoc.rdoc_files.include('activesupport/CHANGELOG') + rdoc.rdoc_files.include('activesupport/lib/active_support/**/*.rb') + rdoc.rdoc_files.exclude('activesupport/lib/active_support/vendor/*') +end + +# Enhance rdoc task to copy referenced images also +task :rdoc do + FileUtils.mkdir_p "doc/files/examples/" + FileUtils.copy "activerecord/examples/associations.png", "doc/files/examples/associations.png" +end + +desc "Publish API docs for Rails as a whole and for each component" +task :pdoc => :rdoc do + Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/api", "doc").upload + PROJECTS.each do |project| + system %(cd #{project} && #{env} #{$0} pdoc) + end +end diff --git a/actionmailer/Rakefile b/actionmailer/Rakefile index c09526cbef..b003f4d559 100755 --- a/actionmailer/Rakefile +++ b/actionmailer/Rakefile @@ -76,12 +76,12 @@ end desc "Publish the API documentation" task :pgem => [:package] do - Rake::SshFilePublisher.new("davidhh@wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload + Rake::SshFilePublisher.new("wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload end desc "Publish the API documentation" task :pdoc => [:rdoc] do - Rake::SshDirPublisher.new("davidhh@wrath.rubyonrails.org", "public_html/am", "doc").upload + Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/am", "doc").upload end desc "Publish the release files to RubyForge." diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 51fc6032cc..1518e23dfe 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -426,8 +426,7 @@ module ActionMailer #:nodoc: end def template_root=(root) - write_inheritable_attribute(:template_root, root) - ActionView::TemplateFinder.process_view_paths(root) + write_inheritable_attribute(:template_root, ActionView::ViewLoadPaths.new(Array(root))) end end @@ -547,7 +546,7 @@ module ActionMailer #:nodoc: end def initialize_template_class(assigns) - ActionView::Base.new([template_root], assigns, self) + ActionView::Base.new(template_root, assigns, self) end def sort_parts(parts, order = []) diff --git a/actionmailer/test/mail_service_test.rb b/actionmailer/test/mail_service_test.rb index e5ecb0e254..7f4a8817ca 100755 --- a/actionmailer/test/mail_service_test.rb +++ b/actionmailer/test/mail_service_test.rb @@ -942,13 +942,13 @@ end # uses_mocha class InheritableTemplateRootTest < Test::Unit::TestCase def test_attr expected = "#{File.dirname(__FILE__)}/fixtures/path.with.dots" - assert_equal expected, FunkyPathMailer.template_root + assert_equal [expected], FunkyPathMailer.template_root.map(&:to_s) sub = Class.new(FunkyPathMailer) sub.template_root = 'test/path' - assert_equal 'test/path', sub.template_root - assert_equal expected, FunkyPathMailer.template_root + assert_equal ['test/path'], sub.template_root.map(&:to_s) + assert_equal [expected], FunkyPathMailer.template_root.map(&:to_s) end end diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 8265b5b04f..4a6e70a153 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,19 @@ *Edge* +* Replaced TemplateFinder abstraction with ViewLoadPaths [Josh Peek] + +* Added block-call style to link_to [Sam Stephenson/DHH]. Example: + + <% link_to(@profile) do %> + <strong><%= @profile.name %></strong> -- <span>Check it out!!</span> + <% end %> + +* Performance: integration test benchmarking and profiling. [Jeremy Kemper] + +* Make caching more aware of mime types. Ensure request format is not considered while expiring cache. [Jonathan del Strother] + +* Drop ActionController::Base.allow_concurrency flag [Josh Peek] + * More efficient concat and capture helpers. Remove ActionView::Base.erb_variable. [Jeremy Kemper] * Added page.reload functionality. Resolves #277. [Sean Huber] diff --git a/actionpack/Rakefile b/actionpack/Rakefile index b37f756c1e..86a2f3af14 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -54,7 +54,9 @@ Rake::RDocTask.new { |rdoc| rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/)) else rdoc.rdoc_files.include('README', 'RUNNING_UNIT_TESTS', 'CHANGELOG') - rdoc.rdoc_files.include('lib/**/*.rb') + rdoc.rdoc_files.include(Dir['lib/**/*.rb'] - + Dir['lib/*/vendor/**/*.rb']) + rdoc.rdoc_files.exclude('lib/actionpack.rb') end } @@ -132,13 +134,13 @@ task :update_js => [ :update_scriptaculous ] desc "Publish the API documentation" task :pgem => [:package] do - Rake::SshFilePublisher.new("davidhh@wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload - `ssh davidhh@wrath.rubyonrails.org './gemupdate.sh'` + Rake::SshFilePublisher.new("wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload + `ssh wrath.rubyonrails.org './gemupdate.sh'` end desc "Publish the API documentation" task :pdoc => [:rdoc] do - Rake::SshDirPublisher.new("davidhh@wrath.rubyonrails.org", "public_html/ap", "doc").upload + Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/ap", "doc").upload end desc "Publish the release files to RubyForge." diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index a036600c2b..bf34edcd85 100755 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -283,13 +283,6 @@ module ActionController #:nodoc: @@debug_routes = true cattr_accessor :debug_routes - # Indicates to Mongrel or Webrick whether to allow concurrent action - # processing. Your controller actions and any other code they call must - # also behave well when called from concurrent threads. Turned off by - # default. - @@allow_concurrency = false - cattr_accessor :allow_concurrency - # Modern REST web services often need to submit complex data to the web application. # The <tt>@@param_parsers</tt> hash lets you register handlers which will process the HTTP body and add parameters to the # <tt>params</tt> hash. These handlers are invoked for POST and PUT requests. @@ -428,8 +421,7 @@ module ActionController #:nodoc: end def view_paths=(value) - @view_paths = value - ActionView::TemplateFinder.process_view_paths(value) + @view_paths = ActionView::ViewLoadPaths.new(Array(value)) if value end # Adds a view_path to the front of the view_paths array. @@ -441,8 +433,7 @@ module ActionController #:nodoc: # def prepend_view_path(path) @view_paths = superclass.view_paths.dup if @view_paths.nil? - view_paths.unshift(*path) - ActionView::TemplateFinder.process_view_paths(path) + @view_paths.unshift(*path) end # Adds a view_path to the end of the view_paths array. @@ -454,8 +445,7 @@ module ActionController #:nodoc: # def append_view_path(path) @view_paths = superclass.view_paths.dup if @view_paths.nil? - view_paths.push(*path) - ActionView::TemplateFinder.process_view_paths(path) + @view_paths.push(*path) end # Replace sensitive parameter data from the request log. @@ -613,8 +603,8 @@ module ActionController #:nodoc: # # This takes the current URL as is and only exchanges the action. In contrast, <tt>url_for :action => 'print'</tt> # would have slashed-off the path components after the changed action. - def url_for(options = nil) #:doc: - case options || {} + def url_for(options = {}) #:doc: + case options when String options when Hash @@ -647,11 +637,11 @@ module ActionController #:nodoc: # View load paths for controller. def view_paths - @template.finder.view_paths + @template.view_paths end def view_paths=(value) - @template.finder.view_paths = value # Mutex needed + @template.view_paths = ViewLoadPaths.new(value) end # Adds a view_path to the front of the view_paths array. @@ -661,7 +651,7 @@ module ActionController #:nodoc: # self.prepend_view_path(["views/default", "views/custom"]) # def prepend_view_path(path) - @template.finder.prepend_view_path(path) # Mutex needed + @template.view_paths.unshift(*path) end # Adds a view_path to the end of the view_paths array. @@ -671,7 +661,7 @@ module ActionController #:nodoc: # self.append_view_path(["views/default", "views/custom"]) # def append_view_path(path) - @template.finder.append_view_path(path) # Mutex needed + @template.view_paths.push(*path) end protected @@ -1232,7 +1222,7 @@ module ActionController #:nodoc: end def template_exists?(template_name = default_template_name) - @template.finder.file_exists?(template_name) + @template.file_exists?(template_name) end def template_public?(template_name = default_template_name) @@ -1240,9 +1230,8 @@ module ActionController #:nodoc: end def template_exempt_from_layout?(template_name = default_template_name) - extension = @template && @template.finder.pick_template_extension(template_name) - name_with_extension = !template_name.include?('.') && extension ? "#{template_name}.#{extension}" : template_name - @@exempt_from_layout.any? { |ext| name_with_extension =~ ext } + template_name = @template.send(:template_file_from_name, template_name) if @template + @@exempt_from_layout.any? { |ext| template_name.to_s =~ ext } end def default_template_name(action_name = self.action_name) diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb index c4b0a97a33..65a36f7f98 100644 --- a/actionpack/lib/action_controller/caching/actions.rb +++ b/actionpack/lib/action_controller/caching/actions.rb @@ -67,10 +67,10 @@ module ActionController #:nodoc: if options[:action].is_a?(Array) options[:action].dup.each do |action| - expire_fragment(ActionCachePath.path_for(self, options.merge({ :action => action }))) + expire_fragment(ActionCachePath.path_for(self, options.merge({ :action => action }), false)) end else - expire_fragment(ActionCachePath.path_for(self, options)) + expire_fragment(ActionCachePath.path_for(self, options, false)) end end @@ -125,16 +125,24 @@ module ActionController #:nodoc: attr_reader :path, :extension class << self - def path_for(controller, options) - new(controller, options).path + def path_for(controller, options, infer_extension=true) + new(controller, options, infer_extension).path end end - - def initialize(controller, options = {}) - @extension = extract_extension(controller.request.path) + + # When true, infer_extension will look up the cache path extension from the request's path & format. + # This is desirable when reading and writing the cache, but not when expiring the cache - expire_action should expire the same files regardless of the request format. + def initialize(controller, options = {}, infer_extension=true) + if infer_extension and options.is_a? Hash + request_extension = extract_extension(controller.request) + options = options.reverse_merge(:format => request_extension) + end path = controller.url_for(options).split('://').last normalize!(path) - add_extension!(path, @extension) + if infer_extension + @extension = request_extension + add_extension!(path, @extension) + end @path = URI.unescape(path) end @@ -144,13 +152,22 @@ module ActionController #:nodoc: end def add_extension!(path, extension) - path << ".#{extension}" if extension + path << ".#{extension}" if extension and !path.ends_with?(extension) end - - def extract_extension(file_path) + + def extract_extension(request) # Don't want just what comes after the last '.' to accommodate multi part extensions # such as tar.gz. - file_path[/^[^.]+\.(.+)$/, 1] + extension = request.path[/^[^.]+\.(.+)$/, 1] + + # If there's no extension in the path, check request.format + if extension.nil? + extension = request.format.to_sym.to_s + if extension=='all' + extension = nil + end + end + extension end end end diff --git a/actionpack/lib/action_controller/dispatcher.rb b/actionpack/lib/action_controller/dispatcher.rb index fe4f6b4a7e..7df987d525 100644 --- a/actionpack/lib/action_controller/dispatcher.rb +++ b/actionpack/lib/action_controller/dispatcher.rb @@ -134,7 +134,7 @@ module ActionController run_callbacks :prepare_dispatch Routing::Routes.reload - ActionView::TemplateFinder.reload! unless ActionView::Base.cache_template_loading + ActionController::Base.view_paths.reload! end # Cleanup the application by clearing out loaded classes so they can diff --git a/actionpack/lib/action_controller/integration.rb b/actionpack/lib/action_controller/integration.rb index bd69d02ed7..18c2df8b37 100644 --- a/actionpack/lib/action_controller/integration.rb +++ b/actionpack/lib/action_controller/integration.rb @@ -1,9 +1,10 @@ -require 'stringio' -require 'uri' - +require 'active_support/test_case' require 'action_controller/dispatcher' require 'action_controller/test_process' +require 'stringio' +require 'uri' + module ActionController module Integration #:nodoc: # An integration Session instance represents a set of requests and responses @@ -580,7 +581,7 @@ EOF # end # end # end - class IntegrationTest < Test::Unit::TestCase + class IntegrationTest < ActiveSupport::TestCase include Integration::Runner # Work around a bug in test/unit caused by the default test being named diff --git a/actionpack/lib/action_controller/layout.rb b/actionpack/lib/action_controller/layout.rb index b5b59f2d7c..0721f71498 100644 --- a/actionpack/lib/action_controller/layout.rb +++ b/actionpack/lib/action_controller/layout.rb @@ -304,7 +304,7 @@ module ActionController #:nodoc: end def layout_directory?(layout_name) - @template.finder.find_template_extension_from_handler(File.join('layouts', layout_name)) + @template.view_paths.find_template_file_for_path("#{File.join('layouts', layout_name)}.#{@template.template_format}.erb") ? true : false end end end diff --git a/actionpack/lib/action_controller/performance_test.rb b/actionpack/lib/action_controller/performance_test.rb new file mode 100644 index 0000000000..85543fffae --- /dev/null +++ b/actionpack/lib/action_controller/performance_test.rb @@ -0,0 +1,16 @@ +require 'action_controller/integration' +require 'active_support/testing/performance' +require 'active_support/testing/default' + +module ActionController + # An integration test that runs a code profiler on your test methods. + # Profiling output for combinations of each test method, measurement, and + # output format are written to your tmp/performance directory. + # + # By default, process_time is measured and both flat and graph_html output + # formats are written, so you'll have two output files per test method. + class PerformanceTest < ActionController::IntegrationTest + include ActiveSupport::Testing::Performance + include ActiveSupport::Testing::Default + end +end diff --git a/actionpack/lib/action_controller/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb index f69c3d6163..742d290ad6 100644 --- a/actionpack/lib/action_controller/record_identifier.rb +++ b/actionpack/lib/action_controller/record_identifier.rb @@ -66,12 +66,12 @@ module ActionController # The DOM id convention is to use the singular form of an object or class with the id following an underscore. # If no id is found, prefix with "new_" instead. Examples: # - # dom_id(Post.new(:id => 45)) # => "post_45" + # dom_id(Post.find(45)) # => "post_45" # dom_id(Post.new) # => "new_post" # # If you need to address multiple instances of the same class in the same view, you can prefix the dom_id: # - # dom_id(Post.new(:id => 45), :edit) # => "edit_post_45" + # dom_id(Post.find(45), :edit) # => "edit_post_45" def dom_id(record, prefix = nil) if record_id = record.id "#{dom_class(record, prefix)}#{JOIN}#{record_id}" diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb index 9fb1f9fa39..af2fcaf3ad 100644 --- a/actionpack/lib/action_controller/resources.rb +++ b/actionpack/lib/action_controller/resources.rb @@ -72,7 +72,7 @@ module ActionController end def conditions - @conditions = @options[:conditions] || {} + @conditions ||= @options[:conditions] || {} end def path @@ -80,9 +80,9 @@ module ActionController end def new_path - new_action = self.options[:path_names][:new] if self.options[:path_names] + new_action = self.options[:path_names][:new] if self.options[:path_names] new_action ||= Base.resources_path_names[:new] - @new_path ||= "#{path}/#{new_action}" + @new_path ||= "#{path}/#{new_action}" end def member_path diff --git a/actionpack/lib/action_controller/templates/rescues/layout.erb b/actionpack/lib/action_controller/templates/rescues/layout.erb index d38f3e67f9..4a04742e40 100644 --- a/actionpack/lib/action_controller/templates/rescues/layout.erb +++ b/actionpack/lib/action_controller/templates/rescues/layout.erb @@ -1,4 +1,4 @@ -<html> +<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Action Controller: Exception caught</title> <style> diff --git a/actionpack/lib/action_controller/verification.rb b/actionpack/lib/action_controller/verification.rb index 9f606e7b7c..35b12a7f13 100644 --- a/actionpack/lib/action_controller/verification.rb +++ b/actionpack/lib/action_controller/verification.rb @@ -116,7 +116,7 @@ module ActionController #:nodoc: end def apply_redirect_to(redirect_to_option) # :nodoc: - redirect_to_option.is_a?(Symbol) ? self.send!(redirect_to_option) : redirect_to_option + (redirect_to_option.is_a?(Symbol) && redirect_to_option != :back) ? self.send!(redirect_to_option) : redirect_to_option end def apply_remaining_actions(options) # :nodoc: diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index 5f4126e4e9..973020a768 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -21,13 +21,9 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ -require 'action_view/template_handler' -require 'action_view/template_handlers/compilable' -require 'action_view/template_handlers/builder' -require 'action_view/template_handlers/erb' -require 'action_view/template_handlers/rjs' - -require 'action_view/template_finder' +require 'action_view/template_handlers' +require 'action_view/template_file' +require 'action_view/view_load_paths' require 'action_view/template' require 'action_view/partial_template' require 'action_view/inline_template' diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index eeebf335dc..4f3cc46a14 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -1,17 +1,17 @@ module ActionView #:nodoc: class ActionViewError < StandardError #:nodoc: end - + class MissingTemplate < ActionViewError #:nodoc: end - # Action View templates can be written in three ways. If the template file has a <tt>.erb</tt> (or <tt>.rhtml</tt>) extension then it uses a mixture of ERb - # (included in Ruby) and HTML. If the template file has a <tt>.builder</tt> (or <tt>.rxml</tt>) extension then Jim Weirich's Builder::XmlMarkup library is used. + # Action View templates can be written in three ways. If the template file has a <tt>.erb</tt> (or <tt>.rhtml</tt>) extension then it uses a mixture of ERb + # (included in Ruby) and HTML. If the template file has a <tt>.builder</tt> (or <tt>.rxml</tt>) extension then Jim Weirich's Builder::XmlMarkup library is used. # If the template file has a <tt>.rjs</tt> extension then it will use ActionView::Helpers::PrototypeHelper::JavaScriptGenerator. - # + # # = ERb - # - # You trigger ERb by using embeddings such as <% %>, <% -%>, and <%= %>. The <%= %> tag set is used when you want output. Consider the + # + # You trigger ERb by using embeddings such as <% %>, <% -%>, and <%= %>. The <%= %> tag set is used when you want output. Consider the # following loop for names: # # <b>Names of all the people</b> @@ -51,7 +51,7 @@ module ActionView #:nodoc: # <title><%= @page_title %></title> # # == Passing local variables to sub templates - # + # # You can pass local variables to sub templates by using a hash with the variable names as keys and the objects as values: # # <%= render "shared/header", { :headline => "Welcome", :person => person } %> @@ -77,8 +77,8 @@ module ActionView #:nodoc: # # == Builder # - # Builder templates are a more programmatic alternative to ERb. They are especially useful for generating XML content. An XmlMarkup object - # named +xml+ is automatically made available to templates with a <tt>.builder</tt> extension. + # Builder templates are a more programmatic alternative to ERb. They are especially useful for generating XML content. An XmlMarkup object + # named +xml+ is automatically made available to templates with a <tt>.builder</tt> extension. # # Here are some basic examples: # @@ -87,7 +87,7 @@ module ActionView #:nodoc: # xml.a("A Link", "href"=>"http://onestepback.org") # => <a href="http://onestepback.org">A Link</a> # xml.target("name"=>"compile", "option"=>"fast") # => <target option="fast" name="compile"\> # # NOTE: order of attributes is not specified. - # + # # Any method with a block will be treated as an XML markup tag with nested markup in the block. For example, the following: # # xml.div { @@ -111,7 +111,7 @@ module ActionView #:nodoc: # xml.description "Basecamp: Recent items" # xml.language "en-us" # xml.ttl "40" - # + # # for item in @recent_items # xml.item do # xml.title(item_title(item)) @@ -119,7 +119,7 @@ module ActionView #:nodoc: # xml.pubDate(item_pubDate(item)) # xml.guid(@person.firm.account.url + @recent_items.url(item)) # xml.link(@person.firm.account.url + @recent_items.url(item)) - # + # # xml.tag!("dc:creator", item.author_name) if item_has_creator?(item) # end # end @@ -130,12 +130,12 @@ module ActionView #:nodoc: # # == JavaScriptGenerator # - # JavaScriptGenerator templates end in <tt>.rjs</tt>. Unlike conventional templates which are used to - # render the results of an action, these templates generate instructions on how to modify an already rendered page. This makes it easy to - # modify multiple elements on your page in one declarative Ajax response. Actions with these templates are called in the background with Ajax + # JavaScriptGenerator templates end in <tt>.rjs</tt>. Unlike conventional templates which are used to + # render the results of an action, these templates generate instructions on how to modify an already rendered page. This makes it easy to + # modify multiple elements on your page in one declarative Ajax response. Actions with these templates are called in the background with Ajax # and make updates to the page where the request originated from. - # - # An instance of the JavaScriptGenerator object named +page+ is automatically made available to your template, which is implicitly wrapped in an ActionView::Helpers::PrototypeHelper#update_page block. + # + # An instance of the JavaScriptGenerator object named +page+ is automatically made available to your template, which is implicitly wrapped in an ActionView::Helpers::PrototypeHelper#update_page block. # # When an <tt>.rjs</tt> action is called with +link_to_remote+, the generated JavaScript is automatically evaluated. Example: # @@ -145,15 +145,14 @@ module ActionView #:nodoc: # # page.replace_html 'sidebar', :partial => 'sidebar' # page.remove "person-#{@person.id}" - # page.visual_effect :highlight, 'user-list' + # page.visual_effect :highlight, 'user-list' # # This refreshes the sidebar, removes a person element and highlights the user list. - # + # # See the ActionView::Helpers::PrototypeHelper::GeneratorMethods documentation for more details. class Base include ERB::Util - attr_reader :finder attr_accessor :base_path, :assigns, :template_extension, :first_render attr_accessor :controller @@ -170,22 +169,22 @@ 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 - + 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). + # that alert()s the caught exception (and then re-raises it). @@debug_rjs = false cattr_accessor :debug_rjs attr_internal :request delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers, - :flash, :logger, :action_name, :to => :controller - + :flash, :logger, :action_name, :controller_name, :to => :controller + module CompiledTemplates #:nodoc: # holds compiled template code end @@ -221,11 +220,17 @@ module ActionView #:nodoc: @assigns = assigns_for_first_render @assigns_added = nil @controller = controller - @finder = TemplateFinder.new(self, view_paths) + self.view_paths = view_paths end - # Renders the template present at <tt>template_path</tt>. If <tt>use_full_path</tt> is set to true, - # it's relative to the view_paths array, otherwise it's absolute. The hash in <tt>local_assigns</tt> + attr_reader :view_paths + + def view_paths=(paths) + @view_paths = ViewLoadPaths.new(Array(paths)) + end + + # Renders the template present at <tt>template_path</tt>. If <tt>use_full_path</tt> is set to true, + # it's relative to the view_paths array, otherwise it's absolute. The hash in <tt>local_assigns</tt> # is made available as local variables. def render_file(template_path, use_full_path = true, local_assigns = {}) #:nodoc: if defined?(ActionMailer) && defined?(ActionMailer::Base) && controller.is_a?(ActionMailer::Base) && !template_path.include?("/") @@ -240,11 +245,11 @@ If you are rendering a subtemplate, you must now use controller-like partial syn render :partial => 'signup' # no mailer_name necessary END_ERROR end - + Template.new(self, template_path, use_full_path, local_assigns).render_template end - - # Renders the template present at <tt>template_path</tt> (relative to the view_paths array). + + # Renders the template present at <tt>template_path</tt> (relative to the view_paths array). # The hash in <tt>local_assigns</tt> is made available as local variables. def render(options = {}, local_assigns = {}, &block) #:nodoc: if options.is_a?(String) @@ -257,7 +262,7 @@ If you are rendering a subtemplate, you must now use controller-like partial syn if partial_layout = options.delete(:layout) if block_given? - wrap_content_for_layout capture(&block) do + wrap_content_for_layout capture(&block) do concat(render(options.merge(:partial => partial_layout))) end else @@ -314,6 +319,10 @@ If you are rendering a subtemplate, you must now use controller-like partial syn end end + def file_exists?(template_path) + view_paths.template_exists?(template_file_from_name(template_path)) + end + private def wrap_content_for_layout(content) original_content_for_layout, @content_for_layout = @content_for_layout, content @@ -334,11 +343,43 @@ If you are rendering a subtemplate, you must now use controller-like partial syn def assign_variables_from_controller @assigns.each { |key, value| instance_variable_set("@#{key}", value) } end - + def execute(template) send(template.method, template.locals) do |*names| instance_variable_get "@content_for_#{names.first || 'layout'}" - end + end + end + + def template_file_from_name(template_name) + template_name = TemplateFile.from_path(template_name) + pick_template_extension(template_name) unless template_name.extension + end + + # Gets the extension for an existing template with the given template_path. + # Returns the format with the extension if that template exists. + # + # pick_template_extension('users/show') + # # => 'html.erb' + # + # pick_template_extension('users/legacy') + # # => "rhtml" + # + def pick_template_extension(file) + if f = self.view_paths.find_template_file_for_path(file.dup_with_extension(template_format)) || file_from_first_render(file) + f + elsif template_format == :js && f = self.view_paths.find_template_file_for_path(file.dup_with_extension(:html)) + @template_format = :html + f + else + nil + end + end + + # Determine the template extension from the <tt>@first_render</tt> filename + def file_from_first_render(file) + if extension = File.basename(@first_render.to_s)[/^[^.]+\.(.+)$/, 1] + file.dup_with_extension(extension) + end end end end diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index 25e62f78fb..9cd9d3d06a 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -31,7 +31,7 @@ module ActionView # </body></html> # def capture(*args, &block) - if @output_buffer + if output_buffer with_output_buffer { block.call(*args) } else block.call(*args) @@ -121,10 +121,11 @@ module ActionView private def with_output_buffer(buf = '') - @output_buffer, old_buffer = buf, @output_buffer + self.output_buffer, old_buffer = buf, output_buffer yield + output_buffer ensure - @output_buffer = old_buffer + self.output_buffer = old_buffer 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 90bd99a861..b3f8e63c1b 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -304,7 +304,7 @@ module ActionView # # NOTE: Only the option tags are returned, you have to wrap this call in # a regular HTML select tag. - def time_zone_options_for_select(selected = nil, priority_zones = nil, model = ActiveSupport::TimeZone) + def time_zone_options_for_select(selected = nil, priority_zones = nil, model = ::ActiveSupport::TimeZone) zone_options = "" zones = model.all diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb index 85b205c264..7404a251e4 100644 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ b/actionpack/lib/action_view/helpers/javascript_helper.rb @@ -202,11 +202,6 @@ module ActionView end js_option end - - private - def block_is_within_action_view?(block) - !@output_buffer.nil? - end end JavascriptHelper = JavaScriptHelper unless const_defined? :JavascriptHelper diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb index a8a5987b1f..e1abec1847 100644 --- a/actionpack/lib/action_view/helpers/tag_helper.rb +++ b/actionpack/lib/action_view/helpers/tag_helper.rb @@ -122,10 +122,6 @@ module ActionView " #{attrs.sort * ' '}" unless attrs.empty? end end - - def block_is_within_action_view?(block) - !@output_buffer.nil? - end end end end diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 3077c8f970..a1a91f6b3d 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -29,8 +29,9 @@ module ActionView if unused_binding ActiveSupport::Deprecation.warn("The binding argument of #concat is no longer needed. Please remove it from your views and helpers.") end - if @output_buffer && string - @output_buffer << string + + if output_buffer && string + output_buffer << string else string end diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index 4b12adf225..baecd304cd 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -90,6 +90,13 @@ module ActionView # link will be used in place of a referrer if none exists. If nil is passed as # a name, the link itself will become the name. # + # ==== Signatures + # + # link_to(name, options = {}, html_options = nil) + # link_to(options = {}, html_options = nil) do + # # name + # end + # # ==== Options # * <tt>:confirm => 'question?'</tt> - This will add a JavaScript confirm # prompt with the question specified. If the user accepts, the link is @@ -147,6 +154,13 @@ module ActionView # link_to "Profiles", :controller => "profiles" # # => <a href="/profiles">Profiles</a> # + # You can use a block as well if your link target is hard to fit into the name parameter. ERb example: + # + # <% link_to(@profile) do %> + # <strong><%= @profile.name %></strong> -- <span>Check it out!!</span> + # <% end %> + # # => <a href="/profiles/1"><strong>David</strong> -- <span>Check it out!!</span></a> + # # Classes and ids for CSS are easy to produce: # # link_to "Articles", articles_path, :id => "news", :class => "article" @@ -189,27 +203,37 @@ module ActionView # f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href; # var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method'); # m.setAttribute('value', 'delete'); f.appendChild(m);f.submit(); };return false;">Delete Image</a> - def link_to(name, options = {}, html_options = nil) - url = case options - when String - options - when :back - @controller.request.env["HTTP_REFERER"] || 'javascript:history.back()' + def link_to(*args, &block) + if block_given? + options = args.first || {} + html_options = args.second + concat(link_to(capture(&block), options, html_options)) + else + name = args.first + options = args.second || {} + html_options = args.third + + url = case options + when String + options + when :back + @controller.request.env["HTTP_REFERER"] || 'javascript:history.back()' + else + self.url_for(options) + end + + if html_options + html_options = html_options.stringify_keys + href = html_options['href'] + convert_options_to_javascript!(html_options, url) + tag_options = tag_options(html_options) else - self.url_for(options) + tag_options = nil end - - if html_options - html_options = html_options.stringify_keys - href = html_options['href'] - convert_options_to_javascript!(html_options, url) - tag_options = tag_options(html_options) - else - tag_options = nil + + href_attr = "href=\"#{url}\"" unless href + "<a #{href_attr}#{tag_options}>#{name || url}</a>" end - - href_attr = "href=\"#{url}\"" unless href - "<a #{href_attr}#{tag_options}>#{name || url}</a>" end # Generates a form containing a single button that submits to the URL created diff --git a/actionpack/lib/action_view/inline_template.rb b/actionpack/lib/action_view/inline_template.rb index 87c012d181..fd0ad48302 100644 --- a/actionpack/lib/action_view/inline_template.rb +++ b/actionpack/lib/action_view/inline_template.rb @@ -1,20 +1,17 @@ module ActionView #:nodoc: class InlineTemplate < Template #:nodoc: - def initialize(view, source, locals = {}, type = nil) @view = view - @finder = @view.finder - + @source = source @extension = type @locals = locals || {} - + @handler = self.class.handler_class_for_extension(@extension).new(@view) end - + def method_key @source end - end end diff --git a/actionpack/lib/action_view/partial_template.rb b/actionpack/lib/action_view/partial_template.rb index 0b374db888..0cf996ca04 100644 --- a/actionpack/lib/action_view/partial_template.rb +++ b/actionpack/lib/action_view/partial_template.rb @@ -1,70 +1,70 @@ module ActionView #:nodoc: class PartialTemplate < Template #:nodoc: - attr_reader :variable_name, :object - + def initialize(view, partial_path, object = nil, locals = {}) - @path, @variable_name = extract_partial_name_and_path(view, partial_path) + @view_controller = view.controller if view.respond_to?(:controller) + set_path_and_variable_name!(partial_path) super(view, @path, true, locals) add_object_to_local_assigns!(object) # This is needed here in order to compile template with knowledge of 'counter' - initialize_counter - + initialize_counter! + # Prepare early. This is a performance optimization for partial collections prepare! end - + def render - ActionController::Base.benchmark("Rendered #{@path}", Logger::DEBUG, false) do + ActionController::Base.benchmark("Rendered #{@path.path_without_format_and_extension}", Logger::DEBUG, false) do @handler.render(self) end end - + def render_member(object) @locals[:object] = @locals[@variable_name] = object - + template = render_template @locals[@counter_name] += 1 @locals.delete(@variable_name) @locals.delete(:object) - + template end - + def counter=(num) @locals[@counter_name] = num end private + def add_object_to_local_assigns!(object) + @locals[:object] ||= + @locals[@variable_name] ||= + if object.is_a?(ActionView::Base::ObjectWrapper) + object.value + else + object + end || @view_controller.instance_variable_get("@#{variable_name}") + end - def add_object_to_local_assigns!(object) - @locals[:object] ||= - @locals[@variable_name] ||= - if object.is_a?(ActionView::Base::ObjectWrapper) - object.value - else - object - end || @view.controller.instance_variable_get("@#{variable_name}") - end - - def extract_partial_name_and_path(view, partial_path) - path, partial_name = partial_pieces(view, partial_path) - [File.join(path, "_#{partial_name}"), partial_name.split('/').last.split('.').first.to_sym] - end - - def partial_pieces(view, partial_path) - if partial_path.include?('/') - return File.dirname(partial_path), File.basename(partial_path) - else - return view.controller.class.controller_path, partial_path + def set_path_and_variable_name!(partial_path) + if partial_path.include?('/') + @variable_name = File.basename(partial_path) + @path = "#{File.dirname(partial_path)}/_#{@variable_name}" + elsif @view_controller + @variable_name = partial_path + @path = "#{@view_controller.class.controller_path}/_#{@variable_name}" + else + @variable_name = partial_path + @path = "_#{@variable_name}" + end + + @variable_name = @variable_name.sub(/\..*$/, '').to_sym + end + + def initialize_counter! + @counter_name ||= "#{@variable_name}_counter".to_sym + @locals[@counter_name] = 0 end - end - - def initialize_counter - @counter_name ||= "#{@variable_name}_counter".to_sym - @locals[@counter_name] = 0 - end - end end diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index 369526188f..4c3f252c10 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -1,19 +1,20 @@ module ActionView #:nodoc: class Template #:nodoc: + extend TemplateHandlers attr_accessor :locals - attr_reader :handler, :path, :extension, :filename, :path_without_extension, :method + attr_reader :handler, :path, :extension, :filename, :method def initialize(view, path, use_full_path, locals = {}) @view = view - @finder = @view.finder + @paths = view.view_paths - # Clear the forward slash at the beginning if exists - @path = use_full_path ? path.sub(/^\//, '') : path - @view.first_render ||= @path + @original_path = path + @path = TemplateFile.from_path(path, !use_full_path) + @view.first_render ||= @path.to_s @source = nil # Don't read the source until we know that it is required set_extension_and_file_name(use_full_path) - + @locals = locals || {} @handler = self.class.handler_class_for_extension(@extension).new(@view) end @@ -29,12 +30,16 @@ module ActionView #:nodoc: raise TemplateError.new(self, @view.assigns, e) end end - + def render prepare! @handler.render(self) end + def path_without_extension + @path.path_without_extension + end + def source @source ||= File.read(self.filename) end @@ -44,13 +49,13 @@ module ActionView #:nodoc: end def base_path_for_exception - @finder.find_base_path_for("#{@path_without_extension}.#{@extension}") || @finder.view_paths.first + (@paths.find_load_path_for_path(@path) || @paths.first).to_s end - + def prepare! @view.send :evaluate_assigns @view.current_render_extension = @extension - + if @handler.compilable? @handler.compile_template(self) # compile the given template, if necessary @method = @view.method_names[method_key] # Set the method name for this template and run it @@ -58,70 +63,32 @@ module ActionView #:nodoc: end private - - def set_extension_and_file_name(use_full_path) - @path_without_extension, @extension = @finder.path_and_extension(@path) - if use_full_path - if @extension - @filename = @finder.pick_template(@path_without_extension, @extension) + def set_extension_and_file_name(use_full_path) + @extension = @path.extension + + if use_full_path + unless @extension + @path = @view.send(:template_file_from_name, @path) + raise_missing_template_exception unless @path + @extension = @path.extension + end + + if @path = @paths.find_template_file_for_path(path) + @filename = @path.full_path + @extension = @path.extension + end else - @extension = @finder.pick_template_extension(@path).to_s - raise_missing_template_exception unless @extension - - @filename = @finder.pick_template(@path, @extension) - @extension = @extension.gsub(/^.+\./, '') # strip off any formats + @filename = @path.full_path end - else - @filename = @path - end - - raise_missing_template_exception if @filename.blank? - end - - def raise_missing_template_exception - full_template_path = @path.include?('.') ? @path : "#{@path}.#{@view.template_format}.erb" - display_paths = @finder.view_paths.join(':') - template_type = (@path =~ /layouts/i) ? 'layout' : 'template' - raise(MissingTemplate, "Missing #{template_type} #{full_template_path} in view path #{display_paths}") - end - - # Template Handlers - - @@template_handlers = HashWithIndifferentAccess.new - @@default_template_handlers = nil - - # Register a class that knows how to handle template files with the given - # extension. This can be used to implement new template types. - # The constructor for the class must take the ActiveView::Base instance - # as a parameter, and the class must implement a +render+ method that - # takes the contents of the template to render as well as the Hash of - # local assigns available to the template. The +render+ method ought to - # return the rendered template as a string. - def self.register_template_handler(extension, klass) - @@template_handlers[extension.to_sym] = klass - TemplateFinder.update_extension_cache_for(extension.to_s) - end - def self.template_handler_extensions - @@template_handlers.keys.map(&:to_s).sort - end - - def self.register_default_template_handler(extension, klass) - register_template_handler(extension, klass) - @@default_template_handlers = klass - end - - def self.handler_class_for_extension(extension) - (extension && @@template_handlers[extension.to_sym]) || @@default_template_handlers - end - - register_default_template_handler :erb, TemplateHandlers::ERB - register_template_handler :rjs, TemplateHandlers::RJS - register_template_handler :builder, TemplateHandlers::Builder + raise_missing_template_exception if @filename.blank? + end - # TODO: Depreciate old template extensions - register_template_handler :rhtml, TemplateHandlers::ERB - register_template_handler :rxml, TemplateHandlers::Builder - + def raise_missing_template_exception + full_template_path = @original_path.include?('.') ? @original_path : "#{@original_path}.#{@view.template_format}.erb" + display_paths = @paths.join(':') + template_type = (@original_path =~ /layouts/i) ? 'layout' : 'template' + raise(MissingTemplate, "Missing #{template_type} #{full_template_path} in view path #{display_paths}") + end end end diff --git a/actionpack/lib/action_view/template_file.rb b/actionpack/lib/action_view/template_file.rb new file mode 100644 index 0000000000..dd66482b3c --- /dev/null +++ b/actionpack/lib/action_view/template_file.rb @@ -0,0 +1,88 @@ +module ActionView #:nodoc: + # TemplateFile abstracts the pattern of querying a file path for its + # path with or without its extension. The path is only the partial path + # from the load path root e.g. "hello/index.html.erb" not + # "app/views/hello/index.html.erb" + class TemplateFile + def self.from_path(path, use_full_path = false) + path.is_a?(self) ? path : new(path, use_full_path) + end + + def self.from_full_path(load_path, full_path) + file = new(full_path.split(load_path).last) + file.load_path = load_path + file.freeze + end + + attr_accessor :load_path, :base_path, :name, :format, :extension + delegate :to_s, :inspect, :to => :path + + def initialize(path, use_full_path = false) + path = path.dup + + # Clear the forward slash in the beginning unless using full path + trim_forward_slash!(path) unless use_full_path + + @base_path, @name, @format, @extension = split(path) + end + + def freeze + @load_path.freeze + @base_path.freeze + @name.freeze + @format.freeze + @extension.freeze + super + end + + def format_and_extension + extensions = [format, extension].compact.join(".") + extensions.blank? ? nil : extensions + end + + def full_path + if load_path + "#{load_path}/#{path}" + else + path + end + end + + def path + base_path.to_s + [name, format, extension].compact.join(".") + end + + def path_without_extension + base_path.to_s + [name, format].compact.join(".") + end + + def path_without_format_and_extension + "#{base_path}#{name}" + end + + def dup_with_extension(extension) + file = dup + file.extension = extension ? extension.to_s : nil + file + end + + private + def trim_forward_slash!(path) + path.sub!(/^\//, '') + end + + # Returns file split into an array + # [base_path, name, format, extension] + def split(file) + if m = file.match(/^(.*\/)?(\w+)\.?(\w+)?\.?(\w+)?\.?(\w+)?$/) + if m[5] # Mulipart formats + [m[1], m[2], "#{m[3]}.#{m[4]}", m[5]] + elsif m[4] # Single format + [m[1], m[2], m[3], m[4]] + else # No format + [m[1], m[2], nil, m[3]] + end + end + end + end +end diff --git a/actionpack/lib/action_view/template_finder.rb b/actionpack/lib/action_view/template_finder.rb deleted file mode 100644 index 83b7e27c09..0000000000 --- a/actionpack/lib/action_view/template_finder.rb +++ /dev/null @@ -1,177 +0,0 @@ -module ActionView #:nodoc: - class TemplateFinder #:nodoc: - - class InvalidViewPath < StandardError #:nodoc: - attr_reader :unprocessed_path - def initialize(path) - @unprocessed_path = path - super("Unprocessed view path found: #{@unprocessed_path.inspect}. Set your view paths with #append_view_path, #prepend_view_path, or #view_paths=.") - end - end - - cattr_reader :processed_view_paths - @@processed_view_paths = Hash.new {|hash, key| hash[key] = []} - - cattr_reader :file_extension_cache - @@file_extension_cache = Hash.new {|hash, key| - hash[key] = Hash.new {|hash, key| hash[key] = []} - } - - class << self #:nodoc: - - # This method is not thread safe. Mutex should be used whenever this is accessed from an instance method - def process_view_paths(*view_paths) - view_paths.flatten.compact.each do |dir| - next if @@processed_view_paths.has_key?(dir) - @@processed_view_paths[dir] = [] - - # - # Dir.glob("#{dir}/**/*/**") reads all the directories in view path and templates inside those directories - # Dir.glob("#{dir}/**") reads templates residing at top level of view path - # - (Dir.glob("#{dir}/**/*/**") | Dir.glob("#{dir}/**")).each do |file| - unless File.directory?(file) - @@processed_view_paths[dir] << file.split(dir).last.sub(/^\//, '') - - # Build extension cache - extension = file.split(".").last - if template_handler_extensions.include?(extension) - key = file.split(dir).last.sub(/^\//, '').sub(/\.(\w+)$/, '') - @@file_extension_cache[dir][key] << extension - end - end - end - end - end - - def update_extension_cache_for(extension) - @@processed_view_paths.keys.each do |dir| - Dir.glob("#{dir}/**/*.#{extension}").each do |file| - key = file.split(dir).last.sub(/^\//, '').sub(/\.(\w+)$/, '') - @@file_extension_cache[dir][key] << extension - end - end - end - - def template_handler_extensions - ActionView::Template.template_handler_extensions - end - - def reload! - view_paths = @@processed_view_paths.keys - - @@processed_view_paths = Hash.new {|hash, key| hash[key] = []} - @@file_extension_cache = Hash.new {|hash, key| - hash[key] = Hash.new {|hash, key| hash[key] = []} - } - - process_view_paths(view_paths) - end - end - - attr_accessor :view_paths - - def initialize(*args) - @template = args.shift - - @view_paths = args.flatten - @view_paths = @view_paths.respond_to?(:find) ? @view_paths.dup : [*@view_paths].compact - check_view_paths(@view_paths) - end - - def prepend_view_path(path) - @view_paths.unshift(*path) - - self.class.process_view_paths(path) - end - - def append_view_path(path) - @view_paths.push(*path) - - self.class.process_view_paths(path) - end - - def view_paths=(path) - @view_paths = path - self.class.process_view_paths(path) - end - - def pick_template(template_path, extension) - file_name = "#{template_path}.#{extension}" - base_path = find_base_path_for(file_name) - base_path.blank? ? false : "#{base_path}/#{file_name}" - end - alias_method :template_exists?, :pick_template - - def file_exists?(template_path) - # Clear the forward slash in the beginning if exists - template_path = template_path.sub(/^\//, '') - - template_file_name, template_file_extension = path_and_extension(template_path) - - if template_file_extension - template_exists?(template_file_name, template_file_extension) - else - template_exists?(template_file_name, pick_template_extension(template_path)) - end - end - - def find_base_path_for(template_file_name) - @view_paths.find { |path| @@processed_view_paths[path].include?(template_file_name) } - end - - # Returns the view path that the full path resides in. - def extract_base_path_from(full_path) - @view_paths.find { |p| full_path[0..p.size - 1] == p } - end - - # Gets the extension for an existing template with the given template_path. - # Returns the format with the extension if that template exists. - # - # pick_template_extension('users/show') - # # => 'html.erb' - # - # pick_template_extension('users/legacy') - # # => "rhtml" - # - def pick_template_extension(template_path) - if extension = find_template_extension_from_handler(template_path, @template.template_format) || find_template_extension_from_first_render - extension - elsif @template.template_format == :js && extension = find_template_extension_from_handler(template_path, :html) - @template.template_format = :html - extension - end - end - - def find_template_extension_from_handler(template_path, template_format = @template.template_format) - formatted_template_path = "#{template_path}.#{template_format}" - - view_paths.each do |path| - if (extensions = @@file_extension_cache[path][formatted_template_path]).any? - return "#{template_format}.#{extensions.first}" - elsif (extensions = @@file_extension_cache[path][template_path]).any? - return extensions.first.to_s - end - end - nil - end - - # Splits the path and extension from the given template_path and returns as an array. - def path_and_extension(template_path) - template_path_without_extension = template_path.sub(/\.(\w+)$/, '') - [ template_path_without_extension, $1 ] - end - - # Determine the template extension from the <tt>@first_render</tt> filename - def find_template_extension_from_first_render - File.basename(@template.first_render.to_s)[/^[^.]+\.(.+)$/, 1] - end - - private - def check_view_paths(view_paths) - view_paths.each do |path| - raise InvalidViewPath.new(path) unless @@processed_view_paths.has_key?(path) - end - end - end -end diff --git a/actionpack/lib/action_view/template_handler.rb b/actionpack/lib/action_view/template_handler.rb index ec407e3fb3..39e578e586 100644 --- a/actionpack/lib/action_view/template_handler.rb +++ b/actionpack/lib/action_view/template_handler.rb @@ -1,6 +1,5 @@ module ActionView class TemplateHandler - def self.line_offset 0 end diff --git a/actionpack/lib/action_view/template_handlers.rb b/actionpack/lib/action_view/template_handlers.rb new file mode 100644 index 0000000000..1471e99e01 --- /dev/null +++ b/actionpack/lib/action_view/template_handlers.rb @@ -0,0 +1,46 @@ +require 'action_view/template_handler' +require 'action_view/template_handlers/compilable' +require 'action_view/template_handlers/builder' +require 'action_view/template_handlers/erb' +require 'action_view/template_handlers/rjs' + +module ActionView #:nodoc: + module TemplateHandlers #:nodoc: + def self.extended(base) + base.register_default_template_handler :erb, TemplateHandlers::ERB + base.register_template_handler :rjs, TemplateHandlers::RJS + base.register_template_handler :builder, TemplateHandlers::Builder + + # TODO: Depreciate old template extensions + base.register_template_handler :rhtml, TemplateHandlers::ERB + base.register_template_handler :rxml, TemplateHandlers::Builder + end + + @@template_handlers = {} + @@default_template_handlers = nil + + # Register a class that knows how to handle template files with the given + # extension. This can be used to implement new template types. + # The constructor for the class must take the ActiveView::Base instance + # as a parameter, and the class must implement a +render+ method that + # takes the contents of the template to render as well as the Hash of + # local assigns available to the template. The +render+ method ought to + # return the rendered template as a string. + def register_template_handler(extension, klass) + @@template_handlers[extension.to_sym] = klass + end + + def template_handler_extensions + @@template_handlers.keys.map(&:to_s).sort + end + + def register_default_template_handler(extension, klass) + register_template_handler(extension, klass) + @@default_template_handlers = klass + end + + def handler_class_for_extension(extension) + (extension && @@template_handlers[extension.to_sym]) || @@default_template_handlers + end + end +end diff --git a/actionpack/lib/action_view/template_handlers/compilable.rb b/actionpack/lib/action_view/template_handlers/compilable.rb index 28c72172a0..1aef81ba1a 100644 --- a/actionpack/lib/action_view/template_handlers/compilable.rb +++ b/actionpack/lib/action_view/template_handlers/compilable.rb @@ -106,7 +106,7 @@ module ActionView locals_code << "#{key} = local_assigns[:#{key}]\n" end - "def #{render_symbol}(local_assigns)\nold_output_buffer = @output_buffer;#{locals_code}#{body}\nensure\n@output_buffer = old_output_buffer\nend" + "def #{render_symbol}(local_assigns)\nold_output_buffer = output_buffer;#{locals_code}#{body}\nensure\nself.output_buffer = old_output_buffer\nend" end # Return true if the given template was compiled for a superset of the keys in local_assigns diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index 16fedd9732..1a3c93c283 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -37,6 +37,8 @@ module ActionView if helper_class && !self.class.ancestors.include?(helper_class) self.class.send(:include, helper_class) end + + self.output_buffer = '' end class TestController < ActionController::Base @@ -48,6 +50,9 @@ module ActionView end end + protected + attr_accessor :output_buffer + private def method_missing(selector, *args) controller = TestController.new diff --git a/actionpack/lib/action_view/view_load_paths.rb b/actionpack/lib/action_view/view_load_paths.rb new file mode 100644 index 0000000000..e873d96aa0 --- /dev/null +++ b/actionpack/lib/action_view/view_load_paths.rb @@ -0,0 +1,103 @@ +module ActionView #:nodoc: + class ViewLoadPaths < Array #:nodoc: + def self.type_cast(obj) + obj.is_a?(String) ? LoadPath.new(obj) : obj + end + + class LoadPath #:nodoc: + attr_reader :path, :paths + delegate :to_s, :inspect, :to => :path + + def initialize(path) + @path = path.freeze + reload! + end + + def eql?(view_path) + view_path.is_a?(ViewPath) && @path == view_path.path + end + + def hash + @path.hash + end + + # Rebuild load path directory cache + def reload! + @paths = {} + + files.each do |file| + @paths[file.path] = file + @paths[file.path_without_extension] ||= file + end + + @paths.freeze + end + + # Tries to find the extension for the template name. + # If it does not it exist, tries again without the format extension + # find_template_file_for_partial_path('users/show') => 'html.erb' + # find_template_file_for_partial_path('users/legacy') => 'rhtml' + def find_template_file_for_partial_path(file) + @paths[file.path] || @paths[file.path_without_extension] || @paths[file.path_without_format_and_extension] + end + + private + # Get all the files and directories in the path + def files_in_path + Dir.glob("#{@path}/**/*/**") | Dir.glob("#{@path}/**") + end + + # Create an array of all the files within the path + def files + files_in_path.map do |file| + TemplateFile.from_full_path(@path, file) unless File.directory?(file) + end.compact + end + end + + def initialize(*args) + super(*args).map! { |obj| self.class.type_cast(obj) } + end + + def reload! + each { |path| path.reload! } + end + + def <<(obj) + super(self.class.type_cast(obj)) + end + + def push(*objs) + delete_paths!(objs) + super(*objs.map { |obj| self.class.type_cast(obj) }) + end + + def unshift(*objs) + delete_paths!(objs) + super(*objs.map { |obj| self.class.type_cast(obj) }) + end + + def template_exists?(file) + find_load_path_for_path(file) ? true : false + end + + def find_load_path_for_path(file) + find { |path| path.paths[file.to_s] } + end + + def find_template_file_for_path(file) + file = TemplateFile.from_path(file) + each do |path| + if f = path.find_template_file_for_partial_path(file) + return f + end + end + nil + end + + private + def delete_paths!(paths) + paths.each { |p1| delete_if { |p2| p1.to_s == p2.to_s } } + end + end +end diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb index b28717597e..34c0200fe8 100644 --- a/actionpack/test/controller/base_test.rb +++ b/actionpack/test/controller/base_test.rb @@ -169,6 +169,22 @@ class DefaultUrlOptionsTest < Test::Unit::TestCase end end +class EmptyUrlOptionsTest < Test::Unit::TestCase + def setup + @controller = NonEmptyController.new + + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + + @request.host = 'www.example.com' + end + + def test_ensure_url_for_works_as_expected_when_called_with_no_options_if_default_url_options_is_not_set + get :public_action + assert_equal "http://www.example.com/non_empty/public_action", @controller.url_for + end +end + class EnsureNamedRoutesWorksTicket22BugTest < Test::Unit::TestCase def test_named_routes_still_work ActionController::Routing::Routes.draw do |map| @@ -180,4 +196,4 @@ class EnsureNamedRoutesWorksTicket22BugTest < Test::Unit::TestCase ensure ActionController::Routing::Routes.load! end -end
\ No newline at end of file +end diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index aee60b1c6f..14cf0a86a1 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -188,6 +188,10 @@ class ActionCachingTestController < ActionController::Base expire_action :controller => 'action_caching_test', :action => 'index' render :nothing => true end + def expire_xml + expire_action :controller => 'action_caching_test', :action => 'index', :format => 'xml' + render :nothing => true + end end class MockTime < Time @@ -213,6 +217,7 @@ class ActionCachingMockController mocked_path = @mock_path Object.new.instance_eval(<<-EVAL) def path; '#{@mock_path}' end + def format; 'all' end self EVAL end @@ -326,6 +331,20 @@ class ActionCacheTest < Test::Unit::TestCase assert_equal new_cached_time, @response.body end + def test_cache_expiration_isnt_affected_by_request_format + get :index + cached_time = content_to_cache + reset! + + @request.set_REQUEST_URI "/action_caching_test/expire.xml" + get :expire, :format => :xml + reset! + + get :index + new_cached_time = content_to_cache + assert_not_equal cached_time, @response.body + end + def test_cache_is_scoped_by_subdomain @request.host = 'jamis.hostname.com' get :index @@ -370,11 +389,35 @@ class ActionCacheTest < Test::Unit::TestCase end def test_xml_version_of_resource_is_treated_as_different_cache - @mock_controller.mock_url_for = 'http://example.org/posts/' - @mock_controller.mock_path = '/posts/index.xml' - path_object = @path_class.new(@mock_controller, {}) - assert_equal 'xml', path_object.extension - assert_equal 'example.org/posts/index.xml', path_object.path + with_routing do |set| + ActionController::Routing::Routes.draw do |map| + map.connect ':controller/:action.:format' + map.connect ':controller/:action' + end + + get :index, :format => 'xml' + cached_time = content_to_cache + assert_equal cached_time, @response.body + assert fragment_exist?('hostname.com/action_caching_test/index.xml') + reset! + + get :index, :format => 'xml' + assert_equal cached_time, @response.body + assert_equal 'application/xml', @response.content_type + reset! + + @request.env['HTTP_ACCEPT'] = "application/xml" + get :index + assert_equal cached_time, @response.body + assert_equal 'application/xml', @response.content_type + reset! + + get :expire_xml + reset! + + get :index, :format => 'xml' + assert_not_equal cached_time, @response.body + end end def test_correct_content_type_is_returned_for_cache_hit diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index 62c00c5b9a..475e13897b 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -1,5 +1,6 @@ require 'abstract_unit' require 'action_controller/integration' +require 'action_controller/routing' uses_mocha 'integration' do @@ -12,12 +13,12 @@ end class SessionTest < Test::Unit::TestCase include IntegrationSessionStubbing - + def setup @session = ActionController::Integration::Session.new stub_integration_session(@session) end - + def test_https_bang_works_and_sets_truth_by_default assert !@session.https? @session.https! @@ -196,7 +197,7 @@ class SessionTest < Test::Unit::TestCase @session.expects(:process).with(:head,path,params,headers_after_xhr) @session.xml_http_request(:head,path,params,headers) end - + def test_xml_http_request_override_accept path = "/index"; params = "blah"; headers = {:location => 'blah', "Accept" => "application/xml"} headers_after_xhr = headers.merge( @@ -227,7 +228,6 @@ class IntegrationTestTest < Test::Unit::TestCase assert_equal ::ActionController::Integration::Session, session2.class assert_not_equal session1, session2 end - end # Tests that integration tests don't call Controller test methods for processing. @@ -246,7 +246,90 @@ class IntegrationTestUsesCorrectClass < ActionController::IntegrationTest assert_nothing_raised("'#{verb}' should use integration test methods") { send!(verb, '/') } end end +end + +class IntegrationProcessTest < ActionController::IntegrationTest + class IntegrationController < ActionController::Base + session :off + + def get + render :text => "OK", :status => 200 + end + + def post + render :text => "Created", :status => 201 + end + + def cookie_monster + cookies["cookie_1"] = nil + cookies["cookie_3"] = "chocolate" + render :text => "Gone", :status => 410 + end + end + def test_get + with_test_route_set do + get '/get' + assert_equal 200, status + assert_equal "OK", status_message + assert_equal "200 OK", response.headers["Status"] + assert_equal ["200 OK"], headers["status"] + assert_equal [], response.headers["cookie"] + assert_equal [], headers["cookie"] + assert_equal({}, cookies) + assert_equal "OK", response.body + assert_kind_of HTML::Document, html_document + assert_equal 1, request_count + end + end + + def test_post + with_test_route_set do + post '/post' + assert_equal 201, status + assert_equal "Created", status_message + assert_equal "201 Created", response.headers["Status"] + assert_equal ["201 Created"], headers["status"] + assert_equal [], response.headers["cookie"] + assert_equal [], headers["cookie"] + assert_equal({}, cookies) + assert_equal "Created", response.body + assert_kind_of HTML::Document, html_document + assert_equal 1, request_count + end + end + + def test_cookie_monster + with_test_route_set do + self.cookies['cookie_1'] = "sugar" + self.cookies['cookie_2'] = "oatmeal" + get '/cookie_monster' + assert_equal 410, status + assert_equal "Gone", status_message + assert_equal "410 Gone", response.headers["Status"] + assert_equal ["410 Gone"], headers["status"] + assert_equal nil, response.headers["Set-Cookie"] + assert_equal ["cookie_1=; path=/", "cookie_3=chocolate; path=/"], headers['set-cookie'] + assert_equal [[], ["chocolate"]], response.headers["cookie"] + assert_equal [], headers["cookie"] + assert_equal({"cookie_1"=>"", "cookie_2"=>"oatmeal", "cookie_3"=>"chocolate"}, cookies) + assert_equal "Gone", response.body + end + end + + private + def with_test_route_set + with_routing do |set| + set.draw do |map| + map.with_options :controller => "IntegrationProcessTest::Integration" do |c| + c.connect '/get', :action => "get" + c.connect '/post', :action => "post" + c.connect '/cookie_monster', :action => "cookie_monster" + end + end + yield + end + end end -end # uses_mocha +end diff --git a/actionpack/test/controller/new_render_test.rb b/actionpack/test/controller/new_render_test.rb index 6b83b8337e..b77b3ceffa 100644 --- a/actionpack/test/controller/new_render_test.rb +++ b/actionpack/test/controller/new_render_test.rb @@ -220,7 +220,7 @@ class NewRenderTestController < ActionController::Base render :action => "test/hello_world" end - def render_to_string_with_partial + def render_to_string_with_partial @partial_only = render_to_string :partial => "partial_only" @partial_with_locals = render_to_string :partial => "customer", :locals => { :customer => Customer.new("david") } render :action => "test/hello_world" @@ -251,11 +251,15 @@ class NewRenderTestController < ActionController::Base def accessing_logger_in_template render :inline => "<%= logger.class %>" end - + def accessing_action_name_in_template render :inline => "<%= action_name %>" end + def accessing_controller_name_in_template + render :inline => "<%= controller_name %>" + end + def accessing_params_in_template_with_layout render :layout => nil, :inline => "Hello: <%= params[:name] %>" end @@ -559,12 +563,17 @@ class NewRenderTest < Test::Unit::TestCase get :accessing_logger_in_template assert_equal "Logger", @response.body end - + def test_access_to_action_name_in_view get :accessing_action_name_in_template assert_equal "accessing_action_name_in_template", @response.body end + def test_access_to_controller_name_in_view + get :accessing_controller_name_in_template + assert_equal "test", @response.body # name is explicitly set to 'test' inside the controller. + end + def test_render_xml get :render_xml_hello assert_equal "<html>\n <p>Hello David</p>\n<p>This is grand!</p>\n</html>\n", @response.body diff --git a/actionpack/test/controller/verification_test.rb b/actionpack/test/controller/verification_test.rb index d6fde35f83..b289443129 100644 --- a/actionpack/test/controller/verification_test.rb +++ b/actionpack/test/controller/verification_test.rb @@ -21,10 +21,10 @@ class VerificationTest < Test::Unit::TestCase verify :only => :guarded_by_method, :method => :post, :redirect_to => { :action => "unguarded" } - + verify :only => :guarded_by_xhr, :xhr => true, :redirect_to => { :action => "unguarded" } - + verify :only => :guarded_by_not_xhr, :xhr => false, :redirect_to => { :action => "unguarded" } @@ -39,10 +39,13 @@ class VerificationTest < Test::Unit::TestCase verify :only => :no_default_action, :params => "santa" + verify :only => :guarded_with_back, :method => :post, + :redirect_to => :back + def guarded_one render :text => "#{params[:one]}" end - + def guarded_one_for_named_route_test render :text => "#{params[:one]}" end @@ -70,11 +73,11 @@ class VerificationTest < Test::Unit::TestCase def guarded_by_method render :text => "#{request.method}" end - + def guarded_by_xhr render :text => "#{request.xhr?}" end - + def guarded_by_not_xhr render :text => "#{request.xhr?}" end @@ -86,15 +89,19 @@ class VerificationTest < Test::Unit::TestCase def two_redirects render :nothing => true end - + def must_be_post render :text => "Was a post!" end - + + def guarded_with_back + render :text => "#{params[:one]}" + end + def no_default_action # Will never run end - + protected def rescue_action(e) raise end @@ -109,7 +116,17 @@ class VerificationTest < Test::Unit::TestCase @response = ActionController::TestResponse.new ActionController::Routing::Routes.add_named_route :foo, '/foo', :controller => 'test', :action => 'foo' end - + + def test_using_symbol_back_with_no_referrer + assert_raise(ActionController::RedirectBackError) { get :guarded_with_back } + end + + def test_using_symbol_back_redirects_to_referrer + @request.env["HTTP_REFERER"] = "/foo" + get :guarded_with_back + assert_redirected_to '/foo' + end + def test_no_deprecation_warning_for_named_route assert_not_deprecated do get :guarded_one_for_named_route_test, :two => "not one" @@ -209,44 +226,44 @@ class VerificationTest < Test::Unit::TestCase get :guarded_by_method assert_redirected_to :action => "unguarded" end - + def test_guarded_by_xhr_with_prereqs xhr :post, :guarded_by_xhr assert_equal "true", @response.body end - + def test_guarded_by_xhr_without_prereqs get :guarded_by_xhr assert_redirected_to :action => "unguarded" end - + def test_guarded_by_not_xhr_with_prereqs get :guarded_by_not_xhr assert_equal "false", @response.body end - + def test_guarded_by_not_xhr_without_prereqs xhr :post, :guarded_by_not_xhr assert_redirected_to :action => "unguarded" end - + def test_guarded_post_and_calls_render_succeeds post :must_be_post assert_equal "Was a post!", @response.body end - + def test_default_failure_should_be_a_bad_request post :no_default_action assert_response :bad_request end - + def test_guarded_post_and_calls_render_fails_and_sets_allow_header get :must_be_post assert_response 405 assert_equal "Must be post", @response.body assert_equal "POST", @response.headers["Allow"] end - + def test_second_redirect assert_nothing_raised { get :two_redirects } end diff --git a/actionpack/test/controller/view_paths_test.rb b/actionpack/test/controller/view_paths_test.rb index 0516da32d8..1b4c1fae2f 100644 --- a/actionpack/test/controller/view_paths_test.rb +++ b/actionpack/test/controller/view_paths_test.rb @@ -1,30 +1,30 @@ require 'abstract_unit' class ViewLoadPathsTest < Test::Unit::TestCase - LOAD_PATH_ROOT = File.join(File.dirname(__FILE__), '..', 'fixtures') - ActionController::Base.view_paths = [ LOAD_PATH_ROOT ] + ActionController::Base.view_paths = [LOAD_PATH_ROOT] class TestController < ActionController::Base def self.controller_path() "test" end def rescue_action(e) raise end - + before_filter :add_view_path, :only => :hello_world_at_request_time - + def hello_world() end def hello_world_at_request_time() render(:action => 'hello_world') end + private - def add_view_path - prepend_view_path "#{LOAD_PATH_ROOT}/override" - end + def add_view_path + prepend_view_path "#{LOAD_PATH_ROOT}/override" + end end - + class Test::SubController < ActionController::Base layout 'test/sub' def hello_world; render(:template => 'test/hello_world'); end end - + def setup TestController.view_paths = nil @@ -41,68 +41,80 @@ class ViewLoadPathsTest < Test::Unit::TestCase @last_message = nil ActiveSupport::Deprecation.behavior = Proc.new { |message, callback| @last_message = message } end - + def teardown ActiveSupport::Deprecation.behavior = @old_behavior end - + def test_template_load_path_was_set_correctly - assert_equal [ LOAD_PATH_ROOT ], @controller.view_paths + assert_equal [ LOAD_PATH_ROOT ], @controller.view_paths.map(&:to_s) end - + def test_controller_appends_view_path_correctly @controller.append_view_path 'foo' - assert_equal [LOAD_PATH_ROOT, 'foo'], @controller.view_paths - + assert_equal [LOAD_PATH_ROOT, 'foo'], @controller.view_paths.map(&:to_s) + @controller.append_view_path(%w(bar baz)) - assert_equal [LOAD_PATH_ROOT, 'foo', 'bar', 'baz'], @controller.view_paths + assert_equal [LOAD_PATH_ROOT, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s) + + @controller.append_view_path(LOAD_PATH_ROOT) + assert_equal ['foo', 'bar', 'baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s) + + @controller.append_view_path([LOAD_PATH_ROOT]) + assert_equal ['foo', 'bar', 'baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s) end - + def test_controller_prepends_view_path_correctly @controller.prepend_view_path 'baz' - assert_equal ['baz', LOAD_PATH_ROOT], @controller.view_paths - + assert_equal ['baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s) + @controller.prepend_view_path(%w(foo bar)) - assert_equal ['foo', 'bar', 'baz', LOAD_PATH_ROOT], @controller.view_paths + assert_equal ['foo', 'bar', 'baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s) + + @controller.prepend_view_path(LOAD_PATH_ROOT) + assert_equal [LOAD_PATH_ROOT, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s) + + @controller.prepend_view_path([LOAD_PATH_ROOT]) + assert_equal [LOAD_PATH_ROOT, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s) end - + def test_template_appends_view_path_correctly @controller.instance_variable_set :@template, ActionView::Base.new(TestController.view_paths, {}, @controller) class_view_paths = TestController.view_paths @controller.append_view_path 'foo' - assert_equal [LOAD_PATH_ROOT, 'foo'], @controller.view_paths - + assert_equal [LOAD_PATH_ROOT, 'foo'], @controller.view_paths.map(&:to_s) + @controller.append_view_path(%w(bar baz)) - assert_equal [LOAD_PATH_ROOT, 'foo', 'bar', 'baz'], @controller.view_paths + assert_equal [LOAD_PATH_ROOT, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s) assert_equal class_view_paths, TestController.view_paths end - + def test_template_prepends_view_path_correctly @controller.instance_variable_set :@template, ActionView::Base.new(TestController.view_paths, {}, @controller) class_view_paths = TestController.view_paths - + @controller.prepend_view_path 'baz' - assert_equal ['baz', LOAD_PATH_ROOT], @controller.view_paths - + assert_equal ['baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s) + @controller.prepend_view_path(%w(foo bar)) - assert_equal ['foo', 'bar', 'baz', LOAD_PATH_ROOT], @controller.view_paths + assert_equal ['foo', 'bar', 'baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s) assert_equal class_view_paths, TestController.view_paths end - + def test_view_paths get :hello_world assert_response :success assert_equal "Hello world!", @response.body end - + def test_view_paths_override TestController.prepend_view_path "#{LOAD_PATH_ROOT}/override" get :hello_world assert_response :success assert_equal "Hello overridden world!", @response.body end - + def test_view_paths_override_for_layouts_in_controllers_with_a_module @controller = Test::SubController.new Test::SubController.view_paths = [ "#{LOAD_PATH_ROOT}/override", LOAD_PATH_ROOT, "#{LOAD_PATH_ROOT}/override2" ] @@ -110,31 +122,44 @@ class ViewLoadPathsTest < Test::Unit::TestCase assert_response :success assert_equal "layout: Hello overridden world!", @response.body end - + def test_view_paths_override_at_request_time get :hello_world_at_request_time assert_response :success assert_equal "Hello overridden world!", @response.body end - + def test_inheritance original_load_paths = ActionController::Base.view_paths - + self.class.class_eval %{ class A < ActionController::Base; end class B < A; end class C < ActionController::Base; end } - - A.view_paths = [ 'a/path' ] - - assert_equal [ 'a/path' ], A.view_paths - assert_equal A.view_paths, B.view_paths + + A.view_paths = ['a/path'] + + assert_equal ['a/path'], A.view_paths.map(&:to_s) + assert_equal A.view_paths, B.view_paths assert_equal original_load_paths, C.view_paths - + C.view_paths = [] assert_nothing_raised { C.view_paths << 'c/path' } - assert_equal ['c/path'], C.view_paths + assert_equal ['c/path'], C.view_paths.map(&:to_s) + end + + def test_find_template_file_for_path + assert_equal "test/hello_world.erb", @controller.view_paths.find_template_file_for_path("test/hello_world.erb").to_s + assert_equal "test/hello.builder", @controller.view_paths.find_template_file_for_path("test/hello.builder").to_s + assert_equal nil, @controller.view_paths.find_template_file_for_path("test/missing.erb") + end + + def test_view_paths_find_template_file_for_path + assert_equal "test/formatted_html_erb.html.erb", @controller.view_paths.find_template_file_for_path("test/formatted_html_erb.html").to_s + assert_equal "test/formatted_xml_erb.xml.erb", @controller.view_paths.find_template_file_for_path("test/formatted_xml_erb.xml").to_s + assert_equal "test/hello_world.erb", @controller.view_paths.find_template_file_for_path("test/hello_world.html").to_s + assert_equal "test/hello_world.erb", @controller.view_paths.find_template_file_for_path("test/hello_world.xml").to_s + assert_equal nil, @controller.view_paths.find_template_file_for_path("test/missing.html") end - end diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb index 3399b03dd2..11b3bdb3fa 100755 --- a/actionpack/test/template/date_helper_test.rb +++ b/actionpack/test/template/date_helper_test.rb @@ -1002,17 +1002,15 @@ class DateHelperTest < ActionView::TestCase @post = Post.new @post.written_on = Date.new(2004, 6, 15) - @output_buffer = '' - fields_for :post, @post do |f| - @output_buffer.concat f.date_select(:written_on) + concat f.date_select(:written_on) end expected = "<select id='post_written_on_1i' name='post[written_on(1i)]'>\n<option value='1999'>1999</option>\n<option value='2000'>2000</option>\n<option value='2001'>2001</option>\n<option value='2002'>2002</option>\n<option value='2003'>2003</option>\n<option selected='selected' value='2004'>2004</option>\n<option value='2005'>2005</option>\n<option value='2006'>2006</option>\n<option value='2007'>2007</option>\n<option value='2008'>2008</option>\n<option value='2009'>2009</option>\n</select>\n" expected << "<select id='post_written_on_2i' name='post[written_on(2i)]'>\n<option value='1'>January</option>\n<option value='2'>February</option>\n<option value='3'>March</option>\n<option value='4'>April</option>\n<option value='5'>May</option>\n<option selected='selected' value='6'>June</option>\n<option value='7'>July</option>\n<option value='8'>August</option>\n<option value='9'>September</option>\n<option value='10'>October</option>\n<option value='11'>November</option>\n<option value='12'>December</option>\n</select>\n" expected << "<select id='post_written_on_3i' name='post[written_on(3i)]'>\n<option value='1'>1</option>\n<option value='2'>2</option>\n<option value='3'>3</option>\n<option value='4'>4</option>\n<option value='5'>5</option>\n<option value='6'>6</option>\n<option value='7'>7</option>\n<option value='8'>8</option>\n<option value='9'>9</option>\n<option value='10'>10</option>\n<option value='11'>11</option>\n<option value='12'>12</option>\n<option value='13'>13</option>\n<option value='14'>14</option>\n<option selected='selected' value='15'>15</option>\n<option value='16'>16</option>\n<option value='17'>17</option>\n<option value='18'>18</option>\n<option value='19'>19</option>\n<option value='20'>20</option>\n<option value='21'>21</option>\n<option value='22'>22</option>\n<option value='23'>23</option>\n<option value='24'>24</option>\n<option value='25'>25</option>\n<option value='26'>26</option>\n<option value='27'>27</option>\n<option value='28'>28</option>\n<option value='29'>29</option>\n<option value='30'>30</option>\n<option value='31'>31</option>\n</select>\n" - assert_dom_equal(expected, @output_buffer) + assert_dom_equal(expected, output_buffer) end def test_date_select_with_index @@ -1287,10 +1285,8 @@ class DateHelperTest < ActionView::TestCase @post = Post.new @post.updated_at = Time.local(2004, 6, 15, 16, 35) - @output_buffer = '' - fields_for :post, @post do |f| - @output_buffer.concat f.datetime_select(:updated_at) + concat f.datetime_select(:updated_at) end expected = "<select id='post_updated_at_1i' name='post[updated_at(1i)]'>\n<option value='1999'>1999</option>\n<option value='2000'>2000</option>\n<option value='2001'>2001</option>\n<option value='2002'>2002</option>\n<option value='2003'>2003</option>\n<option selected='selected' value='2004'>2004</option>\n<option value='2005'>2005</option>\n<option value='2006'>2006</option>\n<option value='2007'>2007</option>\n<option value='2008'>2008</option>\n<option value='2009'>2009</option>\n</select>\n" @@ -1299,7 +1295,7 @@ class DateHelperTest < ActionView::TestCase expected << " — <select id='post_updated_at_4i' name='post[updated_at(4i)]'>\n<option value='00'>00</option>\n<option value='01'>01</option>\n<option value='02'>02</option>\n<option value='03'>03</option>\n<option value='04'>04</option>\n<option value='05'>05</option>\n<option value='06'>06</option>\n<option value='07'>07</option>\n<option value='08'>08</option>\n<option value='09'>09</option>\n<option value='10'>10</option>\n<option value='11'>11</option>\n<option value='12'>12</option>\n<option value='13'>13</option>\n<option value='14'>14</option>\n<option value='15'>15</option>\n<option selected='selected' value='16'>16</option>\n<option value='17'>17</option>\n<option value='18'>18</option>\n<option value='19'>19</option>\n<option value='20'>20</option>\n<option value='21'>21</option>\n<option value='22'>22</option>\n<option value='23'>23</option>\n</select>\n" expected << " : <select id='post_updated_at_5i' name='post[updated_at(5i)]'>\n<option value='00'>00</option>\n<option value='01'>01</option>\n<option value='02'>02</option>\n<option value='03'>03</option>\n<option value='04'>04</option>\n<option value='05'>05</option>\n<option value='06'>06</option>\n<option value='07'>07</option>\n<option value='08'>08</option>\n<option value='09'>09</option>\n<option value='10'>10</option>\n<option value='11'>11</option>\n<option value='12'>12</option>\n<option value='13'>13</option>\n<option value='14'>14</option>\n<option value='15'>15</option>\n<option value='16'>16</option>\n<option value='17'>17</option>\n<option value='18'>18</option>\n<option value='19'>19</option>\n<option value='20'>20</option>\n<option value='21'>21</option>\n<option value='22'>22</option>\n<option value='23'>23</option>\n<option value='24'>24</option>\n<option value='25'>25</option>\n<option value='26'>26</option>\n<option value='27'>27</option>\n<option value='28'>28</option>\n<option value='29'>29</option>\n<option value='30'>30</option>\n<option value='31'>31</option>\n<option value='32'>32</option>\n<option value='33'>33</option>\n<option value='34'>34</option>\n<option selected='selected' value='35'>35</option>\n<option value='36'>36</option>\n<option value='37'>37</option>\n<option value='38'>38</option>\n<option value='39'>39</option>\n<option value='40'>40</option>\n<option value='41'>41</option>\n<option value='42'>42</option>\n<option value='43'>43</option>\n<option value='44'>44</option>\n<option value='45'>45</option>\n<option value='46'>46</option>\n<option value='47'>47</option>\n<option value='48'>48</option>\n<option value='49'>49</option>\n<option value='50'>50</option>\n<option value='51'>51</option>\n<option value='52'>52</option>\n<option value='53'>53</option>\n<option value='54'>54</option>\n<option value='55'>55</option>\n<option value='56'>56</option>\n<option value='57'>57</option>\n<option value='58'>58</option>\n<option value='59'>59</option>\n</select>\n" - assert_dom_equal(expected, @output_buffer) + assert_dom_equal(expected, output_buffer) end def test_date_select_with_zero_value_and_no_start_year diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 65984fac44..39649c3622 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -337,14 +337,12 @@ class FormHelperTest < ActionView::TestCase end def test_form_for - @output_buffer = '' - form_for(:post, @post, :html => { :id => 'create-post' }) do |f| - @output_buffer.concat f.label(:title) - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) - @output_buffer.concat f.submit('Create post') + concat f.label(:title) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + concat f.submit('Create post') end expected = @@ -357,16 +355,14 @@ class FormHelperTest < ActionView::TestCase "<input name='commit' id='post_submit' type='submit' value='Create post' />" + "</form>" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_with_method - @output_buffer = '' - form_for(:post, @post, :html => { :id => 'create-post', :method => :put }) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -378,16 +374,14 @@ class FormHelperTest < ActionView::TestCase "<input name='post[secret]' type='hidden' value='0' />" + "</form>" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_without_object - @output_buffer = '' - form_for(:post, :html => { :id => 'create-post' }) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -398,17 +392,15 @@ class FormHelperTest < ActionView::TestCase "<input name='post[secret]' type='hidden' value='0' />" + "</form>" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_with_index - @output_buffer = '' - form_for("post[]", @post) do |f| - @output_buffer.concat f.label(:title) - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.label(:title) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -420,16 +412,14 @@ class FormHelperTest < ActionView::TestCase "<input name='post[123][secret]' type='hidden' value='0' />" + "</form>" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_with_nil_index_option_override - @output_buffer = '' - form_for("post[]", @post, :index => nil) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -440,14 +430,13 @@ class FormHelperTest < ActionView::TestCase "<input name='post[][secret]' type='hidden' value='0' />" + "</form>" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_nested_fields_for - @output_buffer = '' form_for(:post, @post) do |f| f.fields_for(:comment, @post) do |c| - @output_buffer.concat c.text_field(:title) + concat c.text_field(:title) end end @@ -455,16 +444,14 @@ class FormHelperTest < ActionView::TestCase "<input name='post[comment][title]' size='30' type='text' id='post_comment_title' value='Hello World' />" + "</form>" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_fields_for - @output_buffer = '' - fields_for(:post, @post) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -473,16 +460,14 @@ class FormHelperTest < ActionView::TestCase "<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" + "<input name='post[secret]' type='hidden' value='0' />" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_fields_for_with_index - @output_buffer = '' - fields_for("post[]", @post) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -491,16 +476,14 @@ class FormHelperTest < ActionView::TestCase "<input name='post[123][secret]' checked='checked' type='checkbox' id='post_123_secret' value='1' />" + "<input name='post[123][secret]' type='hidden' value='0' />" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_fields_for_with_nil_index_option_override - @output_buffer = '' - fields_for("post[]", @post, :index => nil) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -509,16 +492,14 @@ class FormHelperTest < ActionView::TestCase "<input name='post[][secret]' checked='checked' type='checkbox' id='post__secret' value='1' />" + "<input name='post[][secret]' type='hidden' value='0' />" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_fields_for_with_index_option_override - @output_buffer = '' - fields_for("post[]", @post, :index => "abc") do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -527,15 +508,14 @@ class FormHelperTest < ActionView::TestCase "<input name='post[abc][secret]' checked='checked' type='checkbox' id='post_abc_secret' value='1' />" + "<input name='post[abc][secret]' type='hidden' value='0' />" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_fields_for_without_object - @output_buffer = '' fields_for(:post) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -544,15 +524,14 @@ class FormHelperTest < ActionView::TestCase "<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" + "<input name='post[secret]' type='hidden' value='0' />" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_fields_for_with_only_object - @output_buffer = '' fields_for(@post) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -561,31 +540,29 @@ class FormHelperTest < ActionView::TestCase "<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" + "<input name='post[secret]' type='hidden' value='0' />" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_fields_for_object_with_bracketed_name - @output_buffer = '' fields_for("author[post]", @post) do |f| - @output_buffer.concat f.label(:title) - @output_buffer.concat f.text_field(:title) + concat f.label(:title) + concat f.text_field(:title) end assert_dom_equal "<label for=\"author_post_title\">Title</label>" + "<input name='author[post][title]' size='30' type='text' id='author_post_title' value='Hello World' />", - @output_buffer + output_buffer end def test_fields_for_object_with_bracketed_name_and_index - @output_buffer = '' fields_for("author[post]", @post, :index => 1) do |f| - @output_buffer.concat f.label(:title) - @output_buffer.concat f.text_field(:title) + concat f.label(:title) + concat f.text_field(:title) end assert_dom_equal "<label for=\"author_post_1_title\">Title</label>" + "<input name='author[post][1][title]' size='30' type='text' id='author_post_1_title' value='Hello World' />", - @output_buffer + output_buffer end def test_form_builder_does_not_have_form_for_method @@ -593,14 +570,12 @@ class FormHelperTest < ActionView::TestCase end def test_form_for_and_fields_for - @output_buffer = '' - form_for(:post, @post, :html => { :id => 'create-post' }) do |post_form| - @output_buffer.concat post_form.text_field(:title) - @output_buffer.concat post_form.text_area(:body) + concat post_form.text_field(:title) + concat post_form.text_area(:body) fields_for(:parent_post, @post) do |parent_fields| - @output_buffer.concat parent_fields.check_box(:secret) + concat parent_fields.check_box(:secret) end end @@ -612,18 +587,16 @@ class FormHelperTest < ActionView::TestCase "<input name='parent_post[secret]' type='hidden' value='0' />" + "</form>" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_and_fields_for_with_object - @output_buffer = '' - form_for(:post, @post, :html => { :id => 'create-post' }) do |post_form| - @output_buffer.concat post_form.text_field(:title) - @output_buffer.concat post_form.text_area(:body) + concat post_form.text_field(:title) + concat post_form.text_area(:body) post_form.fields_for(@comment) do |comment_fields| - @output_buffer.concat comment_fields.text_field(:name) + concat comment_fields.text_field(:name) end end @@ -634,7 +607,7 @@ class FormHelperTest < ActionView::TestCase "<input name='post[comment][name]' type='text' id='post_comment_name' value='new comment' size='30' />" + "</form>" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end class LabelledFormBuilder < ActionView::Helpers::FormBuilder @@ -649,12 +622,10 @@ class FormHelperTest < ActionView::TestCase end def test_form_for_with_labelled_builder - @output_buffer = '' - form_for(:post, @post, :builder => LabelledFormBuilder) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -665,18 +636,17 @@ class FormHelperTest < ActionView::TestCase "<input name='post[secret]' type='hidden' value='0' /><br/>" + "</form>" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_default_form_builder old_default_form_builder, ActionView::Base.default_form_builder = ActionView::Base.default_form_builder, LabelledFormBuilder - @output_buffer = '' form_for(:post, @post) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -687,17 +657,15 @@ class FormHelperTest < ActionView::TestCase "<input name='post[secret]' type='hidden' value='0' /><br/>" + "</form>" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer ensure ActionView::Base.default_form_builder = old_default_form_builder end def test_default_form_builder_with_active_record_helpers - - @output_buffer = '' form_for(:post, @post) do |f| - @output_buffer.concat f.error_message_on('author_name') - @output_buffer.concat f.error_messages + concat f.error_message_on('author_name') + concat f.error_messages end expected = %(<form action='http://www.example.com' method='post'>) + @@ -705,7 +673,7 @@ class FormHelperTest < ActionView::TestCase %(<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>) + %(</form>) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end @@ -713,10 +681,9 @@ class FormHelperTest < ActionView::TestCase post = @post @post = nil - @output_buffer = '' form_for(:post, post) do |f| - @output_buffer.concat f.error_message_on('author_name') - @output_buffer.concat f.error_messages + concat f.error_message_on('author_name') + concat f.error_messages end expected = %(<form action='http://www.example.com' method='post'>) + @@ -724,19 +691,18 @@ class FormHelperTest < ActionView::TestCase %(<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>) + %(</form>) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end # Perhaps this test should be moved to prototype helper tests. def test_remote_form_for_with_labelled_builder self.extend ActionView::Helpers::PrototypeHelper - @output_buffer = '' remote_form_for(:post, @post, :builder => LabelledFormBuilder) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -747,16 +713,14 @@ class FormHelperTest < ActionView::TestCase "<input name='post[secret]' type='hidden' value='0' /><br/>" + "</form>" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_fields_for_with_labelled_builder - @output_buffer = '' - fields_for(:post, @post, :builder => LabelledFormBuilder) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -765,29 +729,23 @@ class FormHelperTest < ActionView::TestCase "<label for='secret'>Secret:</label> <input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" + "<input name='post[secret]' type='hidden' value='0' /><br/>" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_with_html_options_adds_options_to_form_tag - @output_buffer = '' - form_for(:post, @post, :html => {:id => 'some_form', :class => 'some_class'}) do |f| end expected = "<form action=\"http://www.example.com\" class=\"some_class\" id=\"some_form\" method=\"post\"></form>" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_with_string_url_option - @output_buffer = '' - form_for(:post, @post, :url => 'http://www.otherdomain.com') do |f| end - assert_equal '<form action="http://www.otherdomain.com" method="post"></form>', @output_buffer + assert_equal '<form action="http://www.otherdomain.com" method="post"></form>', output_buffer end def test_form_for_with_hash_url_option - @output_buffer = '' - form_for(:post, @post, :url => {:controller => 'controller', :action => 'action'}) do |f| end assert_equal 'controller', @controller.url_for_options[:controller] @@ -795,26 +753,20 @@ class FormHelperTest < ActionView::TestCase end def test_form_for_with_record_url_option - @output_buffer = '' - form_for(:post, @post, :url => @post) do |f| end expected = "<form action=\"/posts/123\" method=\"post\"></form>" - assert_equal expected, @output_buffer + assert_equal expected, output_buffer end def test_form_for_with_existing_object - @output_buffer = '' - form_for(@post) do |f| end expected = "<form action=\"/posts/123\" class=\"edit_post\" id=\"edit_post_123\" method=\"post\"><div style=\"margin:0;padding:0\"><input name=\"_method\" type=\"hidden\" value=\"put\" /></div></form>" - assert_equal expected, @output_buffer + assert_equal expected, output_buffer end def test_form_for_with_new_object - @output_buffer = '' - post = Post.new post.new_record = true def post.id() nil end @@ -822,64 +774,61 @@ class FormHelperTest < ActionView::TestCase form_for(post) do |f| end expected = "<form action=\"/posts\" class=\"new_post\" id=\"new_post\" method=\"post\"></form>" - assert_equal expected, @output_buffer + assert_equal expected, output_buffer end def test_form_for_with_existing_object_in_list @post.new_record = false @comment.save - @output_buffer = '' + form_for([@post, @comment]) {} expected = %(<form action="#{comment_path(@post, @comment)}" class="edit_comment" id="edit_comment_1" method="post"><div style="margin:0;padding:0"><input name="_method" type="hidden" value="put" /></div></form>) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_with_new_object_in_list @post.new_record = false - @output_buffer = '' + form_for([@post, @comment]) {} expected = %(<form action="#{comments_path(@post)}" class="new_comment" id="new_comment" method="post"></form>) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_with_existing_object_and_namespace_in_list @post.new_record = false @comment.save - @output_buffer = '' + form_for([:admin, @post, @comment]) {} expected = %(<form action="#{admin_comment_path(@post, @comment)}" class="edit_comment" id="edit_comment_1" method="post"><div style="margin:0;padding:0"><input name="_method" type="hidden" value="put" /></div></form>) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_with_new_object_and_namespace_in_list @post.new_record = false - @output_buffer = '' + form_for([:admin, @post, @comment]) {} expected = %(<form action="#{admin_comments_path(@post)}" class="new_comment" id="new_comment" method="post"></form>) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_with_existing_object_and_custom_url - @output_buffer = '' - form_for(@post, :url => "/super_posts") do |f| end expected = "<form action=\"/super_posts\" class=\"edit_post\" id=\"edit_post_123\" method=\"post\"><div style=\"margin:0;padding:0\"><input name=\"_method\" type=\"hidden\" value=\"put\" /></div></form>" - assert_equal expected, @output_buffer + assert_equal expected, output_buffer end def test_remote_form_for_with_html_options_adds_options_to_form_tag self.extend ActionView::Helpers::PrototypeHelper - @output_buffer = '' remote_form_for(:post, @post, :html => {:id => 'some_form', :class => 'some_class'}) do |f| end expected = "<form action=\"http://www.example.com\" class=\"some_class\" id=\"some_form\" method=\"post\" onsubmit=\"new Ajax.Request('http://www.example.com', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\"></form>" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb index 3c9fb297c3..3f89a5e426 100644 --- a/actionpack/test/template/form_options_helper_test.rb +++ b/actionpack/test/template/form_options_helper_test.rb @@ -20,8 +20,6 @@ class MockTimeZone end end -ActionView::Helpers::FormOptionsHelper::TimeZone = MockTimeZone - class FormOptionsHelperTest < ActionView::TestCase tests ActionView::Helpers::FormOptionsHelper @@ -31,6 +29,8 @@ class FormOptionsHelperTest < ActionView::TestCase Country = Struct.new('Country', :country_id, :country_name) Firm = Struct.new('Firm', :time_zone) Album = Struct.new('Album', :id, :title, :genre) + + ActiveSupport::TimeZone = MockTimeZone end def test_collection_options @@ -183,7 +183,7 @@ class FormOptionsHelperTest < ActionView::TestCase end def test_time_zone_options_with_priority_zones - zones = [ TimeZone.new( "B" ), TimeZone.new( "E" ) ] + zones = [ ActiveSupport::TimeZone.new( "B" ), ActiveSupport::TimeZone.new( "E" ) ] opts = time_zone_options_for_select( nil, zones ) assert_dom_equal "<option value=\"B\">B</option>\n" + "<option value=\"E\">E</option>" + @@ -195,7 +195,7 @@ class FormOptionsHelperTest < ActionView::TestCase end def test_time_zone_options_with_selected_priority_zones - zones = [ TimeZone.new( "B" ), TimeZone.new( "E" ) ] + zones = [ ActiveSupport::TimeZone.new( "B" ), ActiveSupport::TimeZone.new( "E" ) ] opts = time_zone_options_for_select( "E", zones ) assert_dom_equal "<option value=\"B\">B</option>\n" + "<option value=\"E\" selected=\"selected\">E</option>" + @@ -207,7 +207,7 @@ class FormOptionsHelperTest < ActionView::TestCase end def test_time_zone_options_with_unselected_priority_zones - zones = [ TimeZone.new( "B" ), TimeZone.new( "E" ) ] + zones = [ ActiveSupport::TimeZone.new( "B" ), ActiveSupport::TimeZone.new( "E" ) ] opts = time_zone_options_for_select( "C", zones ) assert_dom_equal "<option value=\"B\">B</option>\n" + "<option value=\"E\">E</option>" + @@ -230,16 +230,14 @@ class FormOptionsHelperTest < ActionView::TestCase def test_select_under_fields_for @post = Post.new @post.category = "<mus>" - - @output_buffer = '' - + fields_for :post, @post do |f| - @output_buffer.concat f.select(:category, %w( abe <mus> hest)) + concat f.select(:category, %w( abe <mus> hest)) end assert_dom_equal( "<select id=\"post_category\" name=\"post[category]\"><option value=\"abe\">abe</option>\n<option value=\"<mus>\" selected=\"selected\"><mus></option>\n<option value=\"hest\">hest</option></select>", - @output_buffer + output_buffer ) end @@ -352,16 +350,14 @@ class FormOptionsHelperTest < ActionView::TestCase @post = Post.new @post.author_name = "Babe" - - @output_buffer = '' - + fields_for :post, @post do |f| - @output_buffer.concat f.collection_select(:author_name, @posts, :author_name, :author_name) + concat f.collection_select(:author_name, @posts, :author_name, :author_name) end assert_dom_equal( "<select id=\"post_author_name\" name=\"post[author_name]\"><option value=\"<Abe>\"><Abe></option>\n<option value=\"Babe\" selected=\"selected\">Babe</option>\n<option value=\"Cabe\">Cabe</option></select>", - @output_buffer + output_buffer ) end @@ -1194,11 +1190,9 @@ COUNTRIES def test_time_zone_select_under_fields_for @firm = Firm.new("D") - - @output_buffer = '' - + fields_for :firm, @firm do |f| - @output_buffer.concat f.time_zone_select(:time_zone) + concat f.time_zone_select(:time_zone) end assert_dom_equal( @@ -1209,7 +1203,7 @@ COUNTRIES "<option value=\"D\" selected=\"selected\">D</option>\n" + "<option value=\"E\">E</option>" + "</select>", - @output_buffer + output_buffer ) end @@ -1293,7 +1287,7 @@ COUNTRIES def test_time_zone_select_with_priority_zones @firm = Firm.new("D") - zones = [ TimeZone.new("A"), TimeZone.new("D") ] + zones = [ ActiveSupport::TimeZone.new("A"), ActiveSupport::TimeZone.new("D") ] html = time_zone_select("firm", "time_zone", zones ) assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" + "<option value=\"A\">A</option>\n" + diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index b281db18bd..47b3605849 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -43,19 +43,17 @@ class FormTagHelperTest < ActionView::TestCase end def test_form_tag_with_block - @output_buffer = '' - form_tag("http://example.com") { @output_buffer.concat "Hello world!" } + form_tag("http://example.com") { concat "Hello world!" } expected = %(<form action="http://example.com" method="post">Hello world!</form>) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_tag_with_block_and_method - @output_buffer = '' - form_tag("http://example.com", :method => :put) { @output_buffer.concat "Hello world!" } + form_tag("http://example.com", :method => :put) { concat "Hello world!" } expected = %(<form action="http://example.com" method="post"><div style='margin:0;padding:0'><input type="hidden" name="_method" value="put" /></div>Hello world!</form>) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_hidden_field_tag @@ -234,23 +232,22 @@ class FormTagHelperTest < ActionView::TestCase end def test_field_set_tag - @output_buffer = '' - field_set_tag("Your details") { @output_buffer.concat "Hello world!" } + field_set_tag("Your details") { concat "Hello world!" } expected = %(<fieldset><legend>Your details</legend>Hello world!</fieldset>) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer - @output_buffer = '' - field_set_tag { @output_buffer.concat "Hello world!" } + self.output_buffer = '' + field_set_tag { concat "Hello world!" } expected = %(<fieldset>Hello world!</fieldset>) - assert_dom_equal expected, @output_buffer - - @output_buffer = '' - field_set_tag('') { @output_buffer.concat "Hello world!" } + assert_dom_equal expected, output_buffer + + self.output_buffer = '' + field_set_tag('') { concat "Hello world!" } expected = %(<fieldset>Hello world!</fieldset>) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def protect_against_forgery? diff --git a/actionpack/test/template/javascript_helper_test.rb b/actionpack/test/template/javascript_helper_test.rb index 4924074c3e..8c649ea544 100644 --- a/actionpack/test/template/javascript_helper_test.rb +++ b/actionpack/test/template/javascript_helper_test.rb @@ -82,12 +82,12 @@ class JavaScriptHelperTest < ActionView::TestCase end def test_javascript_tag - @output_buffer = 'foo' + self.output_buffer = 'foo' assert_dom_equal "<script type=\"text/javascript\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", javascript_tag("alert('hello')") - assert_equal 'foo', @output_buffer, 'javascript_tag without a block should not concat to @output_buffer' + assert_equal 'foo', output_buffer, 'javascript_tag without a block should not concat to output_buffer' end def test_javascript_tag_with_options @@ -96,15 +96,13 @@ class JavaScriptHelperTest < ActionView::TestCase end def test_javascript_tag_with_block - @output_buffer = '' - javascript_tag { @output_buffer.concat "alert('hello')" } - assert_dom_equal "<script type=\"text/javascript\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", @output_buffer + javascript_tag { concat "alert('hello')" } + assert_dom_equal "<script type=\"text/javascript\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", output_buffer end def test_javascript_tag_with_block_and_options - @output_buffer = '' - javascript_tag(:id => "the_js_tag") { @output_buffer.concat "alert('hello')" } - assert_dom_equal "<script id=\"the_js_tag\" type=\"text/javascript\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", @output_buffer + javascript_tag(:id => "the_js_tag") { concat "alert('hello')" } + assert_dom_equal "<script id=\"the_js_tag\" type=\"text/javascript\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", output_buffer end def test_javascript_cdata_section diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb index 3f5ec07214..a5be0d2789 100644 --- a/actionpack/test/template/prototype_helper_test.rb +++ b/actionpack/test/template/prototype_helper_test.rb @@ -118,52 +118,46 @@ class PrototypeHelperTest < PrototypeHelperBaseTest end def test_form_remote_tag_with_block - @output_buffer = '' - form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) { @output_buffer.concat "Hello world!" } - assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">Hello world!</form>), @output_buffer + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) { concat "Hello world!" } + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">Hello world!</form>), output_buffer end def test_remote_form_for_with_record_identification_with_new_record - @output_buffer = '' remote_form_for(@record, {:html => { :id => 'create-author' }}) {} expected = %(<form action='#{authors_path}' onsubmit="new Ajax.Request('#{authors_path}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_author' id='create-author' method='post'></form>) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_remote_form_for_with_record_identification_without_html_options - @output_buffer = '' remote_form_for(@record) {} expected = %(<form action='#{authors_path}' onsubmit="new Ajax.Request('#{authors_path}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_author' method='post' id='new_author'></form>) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_remote_form_for_with_record_identification_with_existing_record @record.save - @output_buffer = '' remote_form_for(@record) {} expected = %(<form action='#{author_path(@record)}' id='edit_author_1' method='post' onsubmit="new Ajax.Request('#{author_path(@record)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='edit_author'><div style='margin:0;padding:0'><input name='_method' type='hidden' value='put' /></div></form>) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_remote_form_for_with_new_object_in_list - @output_buffer = '' remote_form_for([@author, @article]) {} expected = %(<form action='#{author_articles_path(@author)}' onsubmit="new Ajax.Request('#{author_articles_path(@author)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_article' method='post' id='new_article'></form>) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_remote_form_for_with_existing_object_in_list @author.save @article.save - @output_buffer = '' remote_form_for([@author, @article]) {} expected = %(<form action='#{author_article_path(@author, @article)}' id='edit_article_1' method='post' onsubmit="new Ajax.Request('#{author_article_path(@author, @article)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='edit_article'><div style='margin:0;padding:0'><input name='_method' type='hidden' value='put' /></div></form>) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_on_callbacks diff --git a/actionpack/test/template/record_tag_helper_test.rb b/actionpack/test/template/record_tag_helper_test.rb index c39e5c69bf..441dc6b720 100644 --- a/actionpack/test/template/record_tag_helper_test.rb +++ b/actionpack/test/template/record_tag_helper_test.rb @@ -17,37 +17,32 @@ class RecordTagHelperTest < ActionView::TestCase end def test_content_tag_for - @output_buffer = '' expected = %(<li class="post bar" id="post_45"></li>) actual = content_tag_for(:li, @post, :class => 'bar') { } assert_dom_equal expected, actual end def test_content_tag_for_prefix - @output_buffer = '' expected = %(<ul class="post" id="archived_post_45"></ul>) actual = content_tag_for(:ul, @post, :archived) { } assert_dom_equal expected, actual end def test_content_tag_for_with_extra_html_tags - @output_buffer = '' expected = %(<tr class="post bar" id="post_45" style='background-color: #f0f0f0'></tr>) actual = content_tag_for(:tr, @post, {:class => "bar", :style => "background-color: #f0f0f0"}) { } assert_dom_equal expected, actual end def test_block_works_with_content_tag_for - @output_buffer = '' expected = %(<tr class="post" id="post_45">#{@post.body}</tr>) - actual = content_tag_for(:tr, @post) { @output_buffer.concat @post.body } + actual = content_tag_for(:tr, @post) { concat @post.body } assert_dom_equal expected, actual end def test_div_for - @output_buffer = '' expected = %(<div class="post bar" id="post_45">#{@post.body}</div>) - actual = div_for(@post, :class => "bar") { @output_buffer.concat @post.body } + actual = div_for(@post, :class => "bar") { concat @post.body } assert_dom_equal expected, actual end diff --git a/actionpack/test/template/tag_helper_test.rb b/actionpack/test/template/tag_helper_test.rb index 7db04d178f..2941dfe217 100644 --- a/actionpack/test/template/tag_helper_test.rb +++ b/actionpack/test/template/tag_helper_test.rb @@ -35,18 +35,17 @@ class TagHelperTest < ActionView::TestCase end def test_content_tag_with_block - @output_buffer = '' - content_tag(:div) { @output_buffer.concat "Hello world!" } - assert_dom_equal "<div>Hello world!</div>", @output_buffer + content_tag(:div) { concat "Hello world!" } + assert_dom_equal "<div>Hello world!</div>", output_buffer end def test_content_tag_with_block_and_options - @output_buffer = '' - content_tag(:div, :class => "green") { @output_buffer.concat "Hello world!" } - assert_dom_equal %(<div class="green">Hello world!</div>), @output_buffer + content_tag(:div, :class => "green") { concat "Hello world!" } + assert_dom_equal %(<div class="green">Hello world!</div>), output_buffer end def test_content_tag_with_block_and_options_outside_of_action_view + self.output_buffer = nil assert_equal content_tag("a", "Create", :href => "create"), content_tag("a", "href" => "create") { "Create" } end diff --git a/actionpack/test/template/template_file_test.rb b/actionpack/test/template/template_file_test.rb new file mode 100644 index 0000000000..d14a966c1c --- /dev/null +++ b/actionpack/test/template/template_file_test.rb @@ -0,0 +1,95 @@ +require 'abstract_unit' + +class TemplateFileTest < Test::Unit::TestCase + LOAD_PATH_ROOT = File.join(File.dirname(__FILE__), '..', 'fixtures') + + def setup + @template = ActionView::TemplateFile.new("test/hello_world.html.erb") + @another_template = ActionView::TemplateFile.new("test/hello_world.erb") + @file_only = ActionView::TemplateFile.new("hello_world.erb") + @full_path = ActionView::TemplateFile.new("/u/app/scales/config/../app/views/test/hello_world.erb", true) + @layout = ActionView::TemplateFile.new("layouts/hello") + @multipart = ActionView::TemplateFile.new("test_mailer/implicitly_multipart_example.text.html.erb") + end + + def test_path + assert_equal "test/hello_world.html.erb", @template.path + assert_equal "test/hello_world.erb", @another_template.path + assert_equal "hello_world.erb", @file_only.path + assert_equal "/u/app/scales/config/../app/views/test/hello_world.erb", @full_path.path + assert_equal "layouts/hello", @layout.path + assert_equal "test_mailer/implicitly_multipart_example.text.html.erb", @multipart.path + end + + def test_path_without_extension + assert_equal "test/hello_world.html", @template.path_without_extension + assert_equal "test/hello_world", @another_template.path_without_extension + assert_equal "hello_world", @file_only.path_without_extension + assert_equal "layouts/hello", @layout.path_without_extension + assert_equal "test_mailer/implicitly_multipart_example.text.html", @multipart.path_without_extension + end + + def test_path_without_format_and_extension + assert_equal "test/hello_world", @template.path_without_format_and_extension + assert_equal "test/hello_world", @another_template.path_without_format_and_extension + assert_equal "hello_world", @file_only.path_without_format_and_extension + assert_equal "layouts/hello", @layout.path_without_format_and_extension + assert_equal "test_mailer/implicitly_multipart_example", @multipart.path_without_format_and_extension + end + + def test_name + assert_equal "hello_world", @template.name + assert_equal "hello_world", @another_template.name + assert_equal "hello_world", @file_only.name + assert_equal "hello_world", @full_path.name + assert_equal "hello", @layout.name + assert_equal "implicitly_multipart_example", @multipart.name + end + + def test_format + assert_equal "html", @template.format + assert_equal nil, @another_template.format + assert_equal nil, @layout.format + assert_equal "text.html", @multipart.format + end + + def test_extension + assert_equal "erb", @template.extension + assert_equal "erb", @another_template.extension + assert_equal nil, @layout.extension + assert_equal "erb", @multipart.extension + end + + def test_format_and_extension + assert_equal "html.erb", @template.format_and_extension + assert_equal "erb", @another_template.format_and_extension + assert_equal nil, @layout.format_and_extension + assert_equal "text.html.erb", @multipart.format_and_extension + end + + def test_new_file_with_extension + file = @template.dup_with_extension(:haml) + assert_equal "test/hello_world.html", file.path_without_extension + assert_equal "haml", file.extension + assert_equal "test/hello_world.html.haml", file.path + + file = @another_template.dup_with_extension(:haml) + assert_equal "test/hello_world", file.path_without_extension + assert_equal "haml", file.extension + assert_equal "test/hello_world.haml", file.path + + file = @another_template.dup_with_extension(nil) + assert_equal "test/hello_world", file.path_without_extension + assert_equal nil, file.extension + assert_equal "test/hello_world", file.path + end + + def test_freezes_entire_contents + @template.freeze + assert @template.frozen? + assert @template.base_path.frozen? + assert @template.name.frozen? + assert @template.format.frozen? + assert @template.extension.frozen? + end +end diff --git a/actionpack/test/template/template_finder_test.rb b/actionpack/test/template/template_finder_test.rb deleted file mode 100644 index 3d6baff5fb..0000000000 --- a/actionpack/test/template/template_finder_test.rb +++ /dev/null @@ -1,73 +0,0 @@ -require 'abstract_unit' - -class TemplateFinderTest < Test::Unit::TestCase - - LOAD_PATH_ROOT = File.join(File.dirname(__FILE__), '..', 'fixtures') - - def setup - ActionView::TemplateFinder.process_view_paths(LOAD_PATH_ROOT) - ActionView::Template::register_template_handler :mab, Class.new(ActionView::TemplateHandler) - @template = ActionView::Base.new - @finder = ActionView::TemplateFinder.new(@template, LOAD_PATH_ROOT) - end - - def test_should_raise_exception_for_unprocessed_view_path - assert_raises ActionView::TemplateFinder::InvalidViewPath do - ActionView::TemplateFinder.new(@template, File.dirname(__FILE__)) - end - end - - def test_should_cache_file_extension_properly - assert_equal ["builder", "erb", "rhtml", "rjs", "rxml", "mab"].sort, - ActionView::TemplateFinder.file_extension_cache[LOAD_PATH_ROOT].values.flatten.uniq.sort - - assert_equal (Dir.glob("#{LOAD_PATH_ROOT}/**/*/*.{erb,rjs,rhtml,builder,rxml,mab}") | - Dir.glob("#{LOAD_PATH_ROOT}/**.{erb,rjs,rhtml,builder,rxml,mab}")).size, - ActionView::TemplateFinder.file_extension_cache[LOAD_PATH_ROOT].keys.size - end - - def test_should_cache_dir_content_properly - assert ActionView::TemplateFinder.processed_view_paths[LOAD_PATH_ROOT] - assert_equal (Dir.glob("#{LOAD_PATH_ROOT}/**/*/**") | Dir.glob("#{LOAD_PATH_ROOT}/**")).find_all {|f| !File.directory?(f) }.size, - ActionView::TemplateFinder.processed_view_paths[LOAD_PATH_ROOT].size - end - - def test_find_template_extension_from_first_render - assert_nil @finder.send(:find_template_extension_from_first_render) - - { - nil => nil, - '' => nil, - 'foo' => nil, - '/foo' => nil, - 'foo.rb' => 'rb', - 'foo.bar.rb' => 'bar.rb', - 'baz/foo.rb' => 'rb', - 'baz/foo.bar.rb' => 'bar.rb', - 'baz/foo.o/foo.rb' => 'rb', - 'baz/foo.o/foo.bar.rb' => 'bar.rb', - }.each do |input,expectation| - @template.instance_variable_set('@first_render', input) - assert_equal expectation, @finder.send(:find_template_extension_from_first_render) - end - end - - def test_should_report_file_exists_correctly - assert_nil @finder.send(:find_template_extension_from_first_render) - assert_equal false, @finder.send(:file_exists?, 'test.rhtml') - assert_equal false, @finder.send(:file_exists?, 'test.rb') - - @template.instance_variable_set('@first_render', 'foo.rb') - - assert_equal 'rb', @finder.send(:find_template_extension_from_first_render) - assert_equal false, @finder.send(:file_exists?, 'baz') - assert_equal false, @finder.send(:file_exists?, 'baz.rb') - end - - uses_mocha 'Template finder tests' do - def test_should_update_extension_cache_when_template_handler_is_registered - ActionView::TemplateFinder.expects(:update_extension_cache_for).with("funky") - ActionView::Template::register_template_handler :funky, Class.new(ActionView::TemplateHandler) - end - end -end diff --git a/actionpack/test/template/template_object_test.rb b/actionpack/test/template/template_object_test.rb index afb5c5cc16..2cfc4523c6 100644 --- a/actionpack/test/template/template_object_test.rb +++ b/actionpack/test/template/template_object_test.rb @@ -2,60 +2,57 @@ require 'abstract_unit' class TemplateObjectTest < Test::Unit::TestCase LOAD_PATH_ROOT = File.join(File.dirname(__FILE__), '..', 'fixtures') - ActionView::TemplateFinder.process_view_paths(LOAD_PATH_ROOT) - + class TemplateTest < Test::Unit::TestCase def setup @view = ActionView::Base.new(LOAD_PATH_ROOT) @path = "test/hello_world.erb" end - + def test_should_create_valid_template template = ActionView::Template.new(@view, @path, true) - + assert_kind_of ActionView::TemplateHandlers::ERB, template.handler - assert_equal "test/hello_world.erb", template.path + assert_equal "test/hello_world.erb", template.path.to_s assert_nil template.instance_variable_get(:"@source") assert_equal "erb", template.extension end - + uses_mocha 'Template preparation tests' do - def test_should_prepare_template_properly template = ActionView::Template.new(@view, @path, true) view = template.instance_variable_get(:"@view") - + view.expects(:evaluate_assigns) template.handler.expects(:compile_template).with(template) view.expects(:method_names).returns({}) - + template.prepare! end - end end - + class PartialTemplateTest < Test::Unit::TestCase def setup @view = ActionView::Base.new(LOAD_PATH_ROOT) @path = "test/partial_only" end - + def test_should_create_valid_partial_template template = ActionView::PartialTemplate.new(@view, @path, nil) - - assert_equal "test/_partial_only", template.path + + assert_equal "test/_partial_only", template.path.path_without_format_and_extension assert_equal :partial_only, template.variable_name - + assert template.locals.has_key?(:object) assert template.locals.has_key?(:partial_only) end - + def test_partial_with_errors template = ActionView::PartialTemplate.new(@view, 'test/raise', nil) assert_raise(ActionView::TemplateError) { template.render_template } end - + uses_mocha 'Partial template preparation tests' do def test_should_prepare_on_initialization ActionView::PartialTemplate.any_instance.expects(:prepare!) @@ -63,7 +60,7 @@ class TemplateObjectTest < Test::Unit::TestCase end end end - + class PartialTemplateFallbackTest < Test::Unit::TestCase def setup @view = ActionView::Base.new(LOAD_PATH_ROOT) @@ -72,7 +69,7 @@ class TemplateObjectTest < Test::Unit::TestCase def test_default template = ActionView::PartialTemplate.new(@view, @path, nil) - assert_equal 'test/_layout_for_partial', template.path + assert_equal 'test/_layout_for_partial', template.path.path_without_format_and_extension assert_equal 'erb', template.extension assert_equal :html, @view.template_format end @@ -80,7 +77,7 @@ class TemplateObjectTest < Test::Unit::TestCase def test_js @view.template_format = :js template = ActionView::PartialTemplate.new(@view, @path, nil) - assert_equal 'test/_layout_for_partial', template.path + assert_equal 'test/_layout_for_partial', template.path.path_without_format_and_extension assert_equal 'erb', template.extension assert_equal :html, @view.template_format end diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb index 0f5c62acad..cbb5c7ee74 100644 --- a/actionpack/test/template/text_helper_test.rb +++ b/actionpack/test/template/text_helper_test.rb @@ -12,11 +12,11 @@ class TextHelperTest < ActionView::TestCase end def test_concat - @output_buffer = 'foo' + self.output_buffer = 'foo' concat 'bar' - assert_equal 'foobar', @output_buffer + assert_equal 'foobar', output_buffer assert_nothing_raised { concat nil } - assert_equal 'foobar', @output_buffer + assert_equal 'foobar', output_buffer end def test_simple_format diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index d45ea08a6f..0713cea8ac 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -211,6 +211,14 @@ class UrlHelperTest < ActionView::TestCase def test_link_tag_using_post_javascript_and_popup assert_raises(ActionView::ActionViewError) { link_to("Hello", "http://www.example.com", :popup => true, :method => :post, :confirm => "Are you serious?") } end + + def test_link_tag_using_block + self.output_buffer = '' + + link_to("http://example.com") { concat("Example site") } + + assert_equal '<a href="http://example.com">Example site</a>', output_buffer + end def test_link_to_unless assert_equal "Showing", link_to_unless(true, "Showing", :action => "show", :controller => "weblog") diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index a65771648e..a1d82fb45d 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,11 @@ *Edge* +* Add :from option to calculations. #397 [Ben Munat] + +* Add :validate option to associations to enable/disable the automatic validation of associated models. Resolves #301. [Jan De Poorter] + +* PostgreSQL: use 'INSERT ... RETURNING id' for 8.2 and later. [Jeremy Kemper] + * Added SQL escaping for :limit and :offset in MySQL [Jonathan Wiess] diff --git a/activerecord/Rakefile b/activerecord/Rakefile index fc068b16c3..7a5296c458 100755 --- a/activerecord/Rakefile +++ b/activerecord/Rakefile @@ -225,13 +225,13 @@ end desc "Publish the beta gem" task :pgem => [:package] do - Rake::SshFilePublisher.new("davidhh@wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload - `ssh davidhh@wrath.rubyonrails.org './gemupdate.sh'` + Rake::SshFilePublisher.new("wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload + `ssh wrath.rubyonrails.org './gemupdate.sh'` end desc "Publish the API documentation" task :pdoc => [:rdoc] do - Rake::SshDirPublisher.new("davidhh@wrath.rubyonrails.org", "public_html/ar", "doc").upload + Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/ar", "doc").upload end desc "Publish the release files to RubyForge." diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index a3d1f12b03..49f5270396 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -103,10 +103,10 @@ module ActiveRecord associated_records = reflection.klass.find(:all, :conditions => [conditions, ids], :include => options[:include], :joins => "INNER JOIN #{connection.quote_table_name options[:join_table]} as t0 ON #{reflection.klass.quoted_table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}", - :select => "#{options[:select] || table_name+'.*'}, t0.#{reflection.primary_key_name} as _parent_record_id", + :select => "#{options[:select] || table_name+'.*'}, t0.#{reflection.primary_key_name} as the_parent_record_id", :order => options[:order]) - set_association_collection_records(id_to_record_map, reflection.name, associated_records, '_parent_record_id') + set_association_collection_records(id_to_record_map, reflection.name, associated_records, 'the_parent_record_id') end def preload_has_one_association(records, reflection, preload_options={}) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index f32b217326..db99b7165d 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -690,6 +690,7 @@ module ActiveRecord # association is a polymorphic +belongs_to+. # * <tt>:uniq</tt> - If true, duplicates will be omitted from the collection. Useful in conjunction with <tt>:through</tt>. # * <tt>:readonly</tt> - If true, all the associated objects are readonly through the association. + # * <tt>:validate</tt> - If false, don't validate the associated objects when saving the parent object. true by default. # # Option examples: # has_many :comments, :order => "posted_on" @@ -710,7 +711,7 @@ module ActiveRecord configure_dependency_for_has_many(reflection) - add_multiple_associated_save_callbacks(reflection.name) + add_multiple_associated_save_callbacks(reflection.name) unless options[:validate] == false add_association_callbacks(reflection.name, reflection.options) if options[:through] @@ -769,6 +770,7 @@ module ActiveRecord # * <tt>:source_type</tt> - Specifies type of the source association used by <tt>has_one :through</tt> queries where the source # association is a polymorphic +belongs_to+. # * <tt>:readonly</tt> - If true, the associated object is readonly through the association. + # * <tt>:validate</tt> - If false, don't validate the associated object when saving the parent object. +false+ by default. # # Option examples: # has_one :credit_card, :dependent => :destroy # destroys the associated credit card @@ -799,7 +801,7 @@ module ActiveRecord end after_save method_name - add_single_associated_save_callbacks(reflection.name) + add_single_associated_save_callbacks(reflection.name) if options[:validate] == true association_accessor_methods(reflection, HasOneAssociation) association_constructor_method(:build, reflection, HasOneAssociation) association_constructor_method(:create, reflection, HasOneAssociation) @@ -857,6 +859,7 @@ module ActiveRecord # Note: If you've enabled the counter cache, then you may want to add the counter cache attribute # to the +attr_readonly+ list in the associated classes (e.g. <tt>class Post; attr_readonly :comments_count; end</tt>). # * <tt>:readonly</tt> - If true, the associated object is readonly through the association. + # * <tt>:validate</tt> - If false, don't validate the associated objects when saving the parent object. +false+ by default. # # Option examples: # belongs_to :firm, :foreign_key => "client_of" @@ -937,6 +940,8 @@ module ActiveRecord ) end + add_single_associated_save_callbacks(reflection.name) if options[:validate] == true + configure_dependency_for_belongs_to(reflection) end @@ -1025,6 +1030,7 @@ module ActiveRecord # * <tt>:select</tt> - By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if, for example, you want to do a join # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error. # * <tt>:readonly</tt> - If true, all the associated objects are readonly through the association. + # * <tt>:validate</tt> - If false, don't validate the associated objects when saving the parent object. +true+ by default. # # Option examples: # has_and_belongs_to_many :projects @@ -1037,7 +1043,7 @@ module ActiveRecord def has_and_belongs_to_many(association_id, options = {}, &extension) reflection = create_has_and_belongs_to_many_reflection(association_id, options, &extension) - add_multiple_associated_save_callbacks(reflection.name) + add_multiple_associated_save_callbacks(reflection.name) unless options[:validate] == false collection_accessor_methods(reflection, HasAndBelongsToManyAssociation) # Don't use a before_destroy callback since users' before_destroy @@ -1343,7 +1349,8 @@ module ActiveRecord :uniq, :finder_sql, :counter_sql, :before_add, :after_add, :before_remove, :after_remove, - :extend, :readonly + :extend, :readonly, + :validate ) options[:extend] = create_extension_modules(association_id, extension, options[:extend]) @@ -1353,7 +1360,7 @@ module ActiveRecord def create_has_one_reflection(association_id, options) options.assert_valid_keys( - :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly + :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly, :validate ) create_reflection(:has_one, association_id, options, self) @@ -1361,7 +1368,7 @@ module ActiveRecord def create_has_one_through_reflection(association_id, options) options.assert_valid_keys( - :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :through, :source, :source_type + :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :through, :source, :source_type, :validate ) create_reflection(:has_one, association_id, options, self) end @@ -1369,7 +1376,7 @@ module ActiveRecord def create_belongs_to_reflection(association_id, options) options.assert_valid_keys( :class_name, :foreign_key, :foreign_type, :remote, :select, :conditions, :include, :dependent, - :counter_cache, :extend, :polymorphic, :readonly + :counter_cache, :extend, :polymorphic, :readonly, :validate ) reflection = create_reflection(:belongs_to, association_id, options, self) @@ -1388,7 +1395,8 @@ module ActiveRecord :uniq, :finder_sql, :delete_sql, :insert_sql, :before_add, :after_add, :before_remove, :after_remove, - :extend, :readonly + :extend, :readonly, + :validate ) options[:extend] = create_extension_modules(association_id, extension, options[:extend]) @@ -1638,7 +1646,9 @@ module ActiveRecord end def join_for_table_name(table_name) - @joins.select{|j|j.aliased_table_name == table_name.gsub(/^\"(.*)\"$/){$1} }.first rescue nil + join = (@joins.select{|j|j.aliased_table_name == table_name.gsub(/^\"(.*)\"$/){$1} }.first) rescue nil + return join unless join.nil? + @joins.select{|j|j.is_a?(JoinAssociation) && j.aliased_join_table_name == table_name.gsub(/^\"(.*)\"$/){$1} }.first rescue nil end def joins_for_table_name(table_name) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 450ea5cb33..8fca34e524 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1297,6 +1297,20 @@ module ActiveRecord #:nodoc: store_full_sti_class ? name : name.demodulize end + # Merges conditions so that the result is a valid +condition+ + def merge_conditions(*conditions) + segments = [] + + conditions.each do |condition| + unless condition.blank? + sql = sanitize_sql(condition) + segments << sql unless sql.blank? + end + end + + "(#{segments.join(') AND (')})" unless segments.empty? + end + private def find_initial(options) options.update(:limit => 1) @@ -1484,20 +1498,6 @@ module ActiveRecord #:nodoc: (safe_to_array(first) + safe_to_array(second)).uniq end - # Merges conditions so that the result is a valid +condition+ - def merge_conditions(*conditions) - segments = [] - - conditions.each do |condition| - unless condition.blank? - sql = sanitize_sql(condition) - segments << sql unless sql.blank? - end - end - - "(#{segments.join(') AND (')})" unless segments.empty? - end - # Object#to_a is deprecated, though it does have the desired behavior def safe_to_array(o) case o @@ -1903,10 +1903,12 @@ module ActiveRecord #:nodoc: # MyApp::Business::Account would appear as MyApp::Business::AccountSubclass. def compute_type(type_name) modularized_name = type_name_with_module(type_name) - begin - class_eval(modularized_name, __FILE__, __LINE__) - rescue NameError - class_eval(type_name, __FILE__, __LINE__) + silence_warnings do + begin + class_eval(modularized_name, __FILE__, __LINE__) + rescue NameError + class_eval(type_name, __FILE__, __LINE__) + end end end diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb index caa8c539d5..2ca1a0aaa3 100644 --- a/activerecord/lib/active_record/calculations.rb +++ b/activerecord/lib/active_record/calculations.rb @@ -1,6 +1,6 @@ module ActiveRecord module Calculations #:nodoc: - CALCULATIONS_OPTIONS = [:conditions, :joins, :order, :select, :group, :having, :distinct, :limit, :offset, :include] + CALCULATIONS_OPTIONS = [:conditions, :joins, :order, :select, :group, :having, :distinct, :limit, :offset, :include, :from] def self.included(base) base.extend(ClassMethods) end @@ -27,6 +27,8 @@ module ActiveRecord # * <tt>:select</tt>: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not # include the joined columns. # * <tt>:distinct</tt>: Set this to true to make this a distinct calculation, such as SELECT COUNT(DISTINCT posts.id) ... + # * <tt>:from</tt> - By default, this is the table name of the class, but can be changed to an alternate table name (or even the name + # of a database view). # # Examples for counting all: # Person.count # returns the total count of all people @@ -178,8 +180,12 @@ module ActiveRecord sql = "SELECT COUNT(*) AS #{aggregate_alias}" if use_workaround sql << ", #{options[:group_field]} AS #{options[:group_alias]}" if options[:group] - sql << " FROM (SELECT #{distinct}#{column_name}" if use_workaround - sql << " FROM #{connection.quote_table_name(table_name)} " + if options[:from] + sql << " FROM #{options[:from]} " + else + sql << " FROM (SELECT #{distinct}#{column_name}" if use_workaround + sql << " FROM #{connection.quote_table_name(table_name)} " + end if merged_includes.any? join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, merged_includes, options[:joins]) sql << join_dependency.join_associations.collect{|join| join.association_join }.join 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 55f67995d1..7d8530ebef 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -356,7 +356,7 @@ module ActiveRecord def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc: if native = native_database_types[type] - column_type_sql = native.is_a?(Hash) ? native[:name] : native + column_type_sql = (native.is_a?(Hash) ? native[:name] : native).dup if type == :decimal # ignore limit, use precision and scale scale ||= native[:scale] @@ -371,7 +371,7 @@ module ActiveRecord raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale if specified" end - elsif limit ||= native.is_a?(Hash) && native[:limit] + elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit]) column_type_sql << "(#{limit})" end diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 653b45021d..93aafaaad1 100755 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -42,30 +42,6 @@ end module ActiveRecord class Base - def self.require_mysql - # Include the MySQL driver if one hasn't already been loaded - unless defined? Mysql - begin - require_library_or_gem 'mysql' - rescue LoadError => cannot_require_mysql - # Use the bundled Ruby/MySQL driver if no driver is already in place - begin - ActiveRecord::Base.logger.info( - "WARNING: You're using the Ruby-based MySQL library that ships with Rails. This library is not suited for production. " + - "Please install the C-based MySQL library instead (gem install mysql)." - ) if ActiveRecord::Base.logger - - require 'active_record/vendor/mysql' - rescue LoadError - raise cannot_require_mysql - end - end - end - - # Define Mysql::Result.all_hashes - MysqlCompat.define_all_hashes_method! - end - # Establishes a connection to the database that's used by all Active Record objects. def self.mysql_connection(config) # :nodoc: config = config.symbolize_keys @@ -81,7 +57,17 @@ module ActiveRecord raise ArgumentError, "No database specified. Missing argument: database." end - require_mysql + # Require the MySQL driver and define Mysql::Result.all_hashes + unless defined? Mysql + begin + require_library_or_gem('mysql') + rescue LoadError + $stderr.puts '!!! The bundled mysql.rb driver has been removed from Rails 2.2. Please install the mysql gem and try again: gem install mysql.' + raise + end + end + MysqlCompat.define_all_hashes_method! + mysql = Mysql.init mysql.ssl_set(config[:sslkey], config[:sslcert], config[:sslca], config[:sslcapath], config[:sslcipher]) if config[:sslkey] @@ -165,8 +151,10 @@ module ActiveRecord # # ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans = false class MysqlAdapter < AbstractAdapter - @@emulate_booleans = true cattr_accessor :emulate_booleans + self.emulate_booleans = true + + ADAPTER_NAME = 'MySQL'.freeze LOST_CONNECTION_ERROR_MESSAGES = [ "Server shutdown in progress", @@ -174,7 +162,22 @@ module ActiveRecord "Lost connection to MySQL server during query", "MySQL server has gone away" ] - QUOTED_TRUE, QUOTED_FALSE = '1', '0' + QUOTED_TRUE, QUOTED_FALSE = '1'.freeze, '0'.freeze + + NATIVE_DATABASE_TYPES = { + :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY".freeze, + :string => { :name => "varchar", :limit => 255 }, + :text => { :name => "text" }, + :integer => { :name => "int"}, + :float => { :name => "float" }, + :decimal => { :name => "decimal" }, + :datetime => { :name => "datetime" }, + :timestamp => { :name => "datetime" }, + :time => { :name => "time" }, + :date => { :name => "date" }, + :binary => { :name => "blob" }, + :boolean => { :name => "tinyint", :limit => 1 } + } def initialize(connection, logger, connection_options, config) super(connection, logger) @@ -184,7 +187,7 @@ module ActiveRecord end def adapter_name #:nodoc: - 'MySQL' + ADAPTER_NAME end def supports_migrations? #:nodoc: @@ -192,20 +195,7 @@ module ActiveRecord end def native_database_types #:nodoc: - { - :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY", - :string => { :name => "varchar", :limit => 255 }, - :text => { :name => "text" }, - :integer => { :name => "int"}, - :float => { :name => "float" }, - :decimal => { :name => "decimal" }, - :datetime => { :name => "datetime" }, - :timestamp => { :name => "datetime" }, - :time => { :name => "time" }, - :date => { :name => "date" }, - :binary => { :name => "blob" }, - :boolean => { :name => "tinyint", :limit => 1 } - } + NATIVE_DATABASE_TYPES end @@ -498,12 +488,17 @@ module ActiveRecord private def connect + @connection.reconnect = true if @connection.respond_to?(:reconnect=) + encoding = @config[:encoding] if encoding @connection.options(Mysql::SET_CHARSET_NAME, encoding) rescue nil end + @connection.ssl_set(@config[:sslkey], @config[:sslcert], @config[:sslca], @config[:sslcapath], @config[:sslcipher]) if @config[:sslkey] + @connection.real_connect(*@connection_options) + execute("SET NAMES '#{encoding}'") if encoding # By default, MySQL 'where id is null' selects the last inserted id. diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 049e6f61de..294f4c1929 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -238,9 +238,26 @@ module ActiveRecord # * <tt>:min_messages</tt> - An optional client min messages that is used in a <tt>SET client_min_messages TO <min_messages></tt> call on the connection. # * <tt>:allow_concurrency</tt> - If true, use async query methods so Ruby threads don't deadlock; otherwise, use blocking query methods. class PostgreSQLAdapter < AbstractAdapter + ADAPTER_NAME = 'PostgreSQL'.freeze + + NATIVE_DATABASE_TYPES = { + :primary_key => "serial primary key".freeze, + :string => { :name => "character varying", :limit => 255 }, + :text => { :name => "text" }, + :integer => { :name => "integer" }, + :float => { :name => "float" }, + :decimal => { :name => "decimal" }, + :datetime => { :name => "timestamp" }, + :timestamp => { :name => "timestamp" }, + :time => { :name => "time" }, + :date => { :name => "date" }, + :binary => { :name => "bytea" }, + :boolean => { :name => "boolean" } + } + # Returns 'PostgreSQL' as adapter name for identification purposes. def adapter_name - 'PostgreSQL' + ADAPTER_NAME end # Initializes and connects a PostgreSQL adapter. @@ -282,20 +299,7 @@ module ActiveRecord end def native_database_types #:nodoc: - { - :primary_key => "serial primary key", - :string => { :name => "character varying", :limit => 255 }, - :text => { :name => "text" }, - :integer => { :name => "integer" }, - :float => { :name => "float" }, - :decimal => { :name => "decimal" }, - :datetime => { :name => "timestamp" }, - :timestamp => { :name => "timestamp" }, - :time => { :name => "time" }, - :date => { :name => "date" }, - :binary => { :name => "bytea" }, - :boolean => { :name => "boolean" } - } + NATIVE_DATABASE_TYPES end # Does PostgreSQL support migrations? @@ -319,6 +323,15 @@ module ActiveRecord has_support end + def supports_insert_with_returning? + unless defined? @supports_insert_with_returning + @supports_insert_with_returning = + @connection.respond_to?(:server_version) && + @connection.server_version >= 80200 + end + @supports_insert_with_returning + end + # Returns the configured supported identifier length supported by PostgreSQL, # or report the default of 63 on PostgreSQL 7.x. def table_alias_length @@ -411,8 +424,34 @@ module ActiveRecord # Executes an INSERT query and returns the new record's ID def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) + # Extract the table from the insert sql. Yuck. table = sql.split(" ", 4)[2].gsub('"', '') - super || pk && last_insert_id(table, sequence_name || default_sequence_name(table, pk)) + + # Try an insert with 'returning id' if available (PG >= 8.2) + if supports_insert_with_returning? + pk, sequence_name = *pk_and_sequence_for(table) unless pk + if pk + id = select_value("#{sql} RETURNING #{quote_column_name(pk)}") + clear_query_cache + return id + end + end + + # Otherwise, insert then grab last_insert_id. + if insert_id = super + insert_id + else + # If neither pk nor sequence name is given, look them up. + unless pk || sequence_name + pk, sequence_name = *pk_and_sequence_for(table) + end + + # If a pk is given, fallback to default sequence name. + # Don't fetch last insert id for a table without a pk. + if pk && sequence_name ||= default_sequence_name(table, pk) + last_insert_id(table, sequence_name) + end + end end # create a 2D array representing the result set diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index c4cbe5d52f..e19614e31f 100755 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -547,7 +547,7 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash) @connection, @table_name, @fixture_path, @file_filter = connection, table_name, fixture_path, file_filter @class_name = class_name || (ActiveRecord::Base.pluralize_table_names ? @table_name.singularize.camelize : @table_name.camelize) - @table_name = ActiveRecord::Base.table_name_prefix + @table_name + ActiveRecord::Base.table_name_suffix + @table_name = "#{ActiveRecord::Base.table_name_prefix}#{@table_name}#{ActiveRecord::Base.table_name_suffix}" @table_name = class_name.table_name if class_name.respond_to?(:table_name) @connection = class_name.connection if class_name.respond_to?(:connection) read_fixture_files diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb index 6e55e36b7d..25e0e61c69 100644 --- a/activerecord/lib/active_record/observer.rb +++ b/activerecord/lib/active_record/observer.rb @@ -189,7 +189,7 @@ module ActiveRecord def add_observer!(klass) klass.add_observer(self) - klass.class_eval 'def after_find() end' unless klass.respond_to?(:after_find) + klass.class_eval 'def after_find() end' unless klass.method_defined?(:after_find) end end end diff --git a/activerecord/lib/active_record/vendor/db2.rb b/activerecord/lib/active_record/vendor/db2.rb deleted file mode 100644 index 812c8cc517..0000000000 --- a/activerecord/lib/active_record/vendor/db2.rb +++ /dev/null @@ -1,362 +0,0 @@ -require 'db2/db2cli.rb' - -module DB2 - module DB2Util - include DB2CLI - - def free() SQLFreeHandle(@handle_type, @handle); end - def handle() @handle; end - - def check_rc(rc) - if ![SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NO_DATA_FOUND].include?(rc) - rec = 1 - msg = '' - loop do - a = SQLGetDiagRec(@handle_type, @handle, rec, 500) - break if a[0] != SQL_SUCCESS - msg << a[3] if !a[3].nil? and a[3] != '' # Create message. - rec += 1 - end - raise "DB2 error: #{msg}" - end - end - end - - class Environment - include DB2Util - - def initialize - @handle_type = SQL_HANDLE_ENV - rc, @handle = SQLAllocHandle(@handle_type, SQL_NULL_HANDLE) - check_rc(rc) - end - - def data_sources(buffer_length = 1024) - retval = [] - max_buffer_length = buffer_length - - a = SQLDataSources(@handle, SQL_FETCH_FIRST, SQL_MAX_DSN_LENGTH + 1, buffer_length) - retval << [a[1], a[3]] - max_buffer_length = [max_buffer_length, a[4]].max - - loop do - a = SQLDataSources(@handle, SQL_FETCH_NEXT, SQL_MAX_DSN_LENGTH + 1, buffer_length) - break if a[0] == SQL_NO_DATA_FOUND - - retval << [a[1], a[3]] - max_buffer_length = [max_buffer_length, a[4]].max - end - - if max_buffer_length > buffer_length - get_data_sources(max_buffer_length) - else - retval - end - end - end - - class Connection - include DB2Util - - def initialize(environment) - @env = environment - @handle_type = SQL_HANDLE_DBC - rc, @handle = SQLAllocHandle(@handle_type, @env.handle) - check_rc(rc) - end - - def connect(server_name, user_name = '', auth = '') - check_rc(SQLConnect(@handle, server_name, user_name.to_s, auth.to_s)) - end - - def set_connect_attr(attr, value) - value += "\0" if value.class == String - check_rc(SQLSetConnectAttr(@handle, attr, value)) - end - - def set_auto_commit_on - set_connect_attr(SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON) - end - - def set_auto_commit_off - set_connect_attr(SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF) - end - - def disconnect - check_rc(SQLDisconnect(@handle)) - end - - def rollback - check_rc(SQLEndTran(@handle_type, @handle, SQL_ROLLBACK)) - end - - def commit - check_rc(SQLEndTran(@handle_type, @handle, SQL_COMMIT)) - end - end - - class Statement - include DB2Util - - def initialize(connection) - @conn = connection - @handle_type = SQL_HANDLE_STMT - @parms = [] #yun - @sql = '' #yun - @numParms = 0 #yun - @prepared = false #yun - @parmArray = [] #yun. attributes of the parameter markers - rc, @handle = SQLAllocHandle(@handle_type, @conn.handle) - check_rc(rc) - end - - def columns(table_name, schema_name = '%') - check_rc(SQLColumns(@handle, '', schema_name.upcase, table_name.upcase, '%')) - fetch_all - end - - def tables(schema_name = '%') - check_rc(SQLTables(@handle, '', schema_name.upcase, '%', 'TABLE')) - fetch_all - end - - def indexes(table_name, schema_name = '') - check_rc(SQLStatistics(@handle, '', schema_name.upcase, table_name.upcase, SQL_INDEX_ALL, SQL_ENSURE)) - fetch_all - end - - def prepare(sql) - @sql = sql - check_rc(SQLPrepare(@handle, sql)) - rc, @numParms = SQLNumParams(@handle) #number of question marks - check_rc(rc) - #-------------------------------------------------------------------------- - # parameter attributes are stored in instance variable @parmArray so that - # they are available when execute method is called. - #-------------------------------------------------------------------------- - if @numParms > 0 # get parameter marker attributes - 1.upto(@numParms) do |i| # parameter number starts from 1 - rc, type, size, decimalDigits = SQLDescribeParam(@handle, i) - check_rc(rc) - @parmArray << Parameter.new(type, size, decimalDigits) - end - end - @prepared = true - self - end - - def execute(*parms) - raise "The statement was not prepared" if @prepared == false - - if parms.size == 1 and parms[0].class == Array - parms = parms[0] - end - - if @numParms != parms.size - raise "Number of parameters supplied does not match with the SQL statement" - end - - if @numParms > 0 #need to bind parameters - #-------------------------------------------------------------------- - #calling bindParms may not be safe. Look comment below. - #-------------------------------------------------------------------- - #bindParms(parms) - - valueArray = [] - 1.upto(@numParms) do |i| # parameter number starts from 1 - type = @parmArray[i - 1].class - size = @parmArray[i - 1].size - decimalDigits = @parmArray[i - 1].decimalDigits - - if parms[i - 1].class == String - valueArray << parms[i - 1] - else - valueArray << parms[i - 1].to_s - end - - rc = SQLBindParameter(@handle, i, type, size, decimalDigits, valueArray[i - 1]) - check_rc(rc) - end - end - - check_rc(SQLExecute(@handle)) - - if @numParms != 0 - check_rc(SQLFreeStmt(@handle, SQL_RESET_PARAMS)) # Reset parameters - end - - self - end - - #------------------------------------------------------------------------------- - # The last argument(value) to SQLBindParameter is a deferred argument, that is, - # it should be available when SQLExecute is called. Even though "value" is - # local to bindParms method, it seems that it is available when SQLExecute - # is called. I am not sure whether it would still work if garbage collection - # is done between bindParms call and SQLExecute call inside the execute method - # above. - #------------------------------------------------------------------------------- - def bindParms(parms) # This is the real thing. It uses SQLBindParms - 1.upto(@numParms) do |i| # parameter number starts from 1 - rc, dataType, parmSize, decimalDigits = SQLDescribeParam(@handle, i) - check_rc(rc) - if parms[i - 1].class == String - value = parms[i - 1] - else - value = parms[i - 1].to_s - end - rc = SQLBindParameter(@handle, i, dataType, parmSize, decimalDigits, value) - check_rc(rc) - end - end - - #------------------------------------------------------------------------------ - # bind method does not use DB2's SQLBindParams, but replaces "?" in the - # SQL statement with the value before passing the SQL statement to DB2. - # It is not efficient and can handle only strings since it puts everything in - # quotes. - #------------------------------------------------------------------------------ - def bind(sql, args) #does not use SQLBindParams - arg_index = 0 - result = "" - tokens(sql).each do |part| - case part - when '?' - result << "'" + (args[arg_index]) + "'" #put it into quotes - arg_index += 1 - when '??' - result << "?" - else - result << part - end - end - if arg_index < args.size - raise "Too many SQL parameters" - elsif arg_index > args.size - raise "Not enough SQL parameters" - end - result - end - - ## Break the sql string into parts. - # - # This is NOT a full lexer for SQL. It just breaks up the SQL - # string enough so that question marks, double question marks and - # quoted strings are separated. This is used when binding - # arguments to "?" in the SQL string. Note: comments are not - # handled. - # - def tokens(sql) - toks = sql.scan(/('([^'\\]|''|\\.)*'|"([^"\\]|""|\\.)*"|\?\??|[^'"?]+)/) - toks.collect { |t| t[0] } - end - - def exec_direct(sql) - check_rc(SQLExecDirect(@handle, sql)) - self - end - - def set_cursor_name(name) - check_rc(SQLSetCursorName(@handle, name)) - self - end - - def get_cursor_name - rc, name = SQLGetCursorName(@handle) - check_rc(rc) - name - end - - def row_count - rc, rowcount = SQLRowCount(@handle) - check_rc(rc) - rowcount - end - - def num_result_cols - rc, cols = SQLNumResultCols(@handle) - check_rc(rc) - cols - end - - def fetch_all - if block_given? - while row = fetch do - yield row - end - else - res = [] - while row = fetch do - res << row - end - res - end - end - - def fetch - cols = get_col_desc - rc = SQLFetch(@handle) - if rc == SQL_NO_DATA_FOUND - SQLFreeStmt(@handle, SQL_CLOSE) # Close cursor - SQLFreeStmt(@handle, SQL_RESET_PARAMS) # Reset parameters - return nil - end - raise "ERROR" unless rc == SQL_SUCCESS - - retval = [] - cols.each_with_index do |c, i| - rc, content = SQLGetData(@handle, i + 1, c[1], c[2] + 1) #yun added 1 to c[2] - retval << adjust_content(content) - end - retval - end - - def fetch_as_hash - cols = get_col_desc - rc = SQLFetch(@handle) - if rc == SQL_NO_DATA_FOUND - SQLFreeStmt(@handle, SQL_CLOSE) # Close cursor - SQLFreeStmt(@handle, SQL_RESET_PARAMS) # Reset parameters - return nil - end - raise "ERROR" unless rc == SQL_SUCCESS - - retval = {} - cols.each_with_index do |c, i| - rc, content = SQLGetData(@handle, i + 1, c[1], c[2] + 1) #yun added 1 to c[2] - retval[c[0]] = adjust_content(content) - end - retval - end - - def get_col_desc - rc, nr_cols = SQLNumResultCols(@handle) - cols = (1..nr_cols).collect do |c| - rc, name, bl, type, col_sz = SQLDescribeCol(@handle, c, 1024) - [name.downcase, type, col_sz] - end - end - - def adjust_content(c) - case c.class.to_s - when 'DB2CLI::NullClass' - return nil - when 'DB2CLI::Time' - "%02d:%02d:%02d" % [c.hour, c.minute, c.second] - when 'DB2CLI::Date' - "%04d-%02d-%02d" % [c.year, c.month, c.day] - when 'DB2CLI::Timestamp' - "%04d-%02d-%02d %02d:%02d:%02d" % [c.year, c.month, c.day, c.hour, c.minute, c.second] - else - return c - end - end - end - - class Parameter - attr_reader :type, :size, :decimalDigits - def initialize(type, size, decimalDigits) - @type, @size, @decimalDigits = type, size, decimalDigits - end - end -end diff --git a/activerecord/lib/active_record/vendor/mysql.rb b/activerecord/lib/active_record/vendor/mysql.rb deleted file mode 100644 index 1c3294c719..0000000000 --- a/activerecord/lib/active_record/vendor/mysql.rb +++ /dev/null @@ -1,1214 +0,0 @@ -# $Id: mysql.rb,v 1.24 2005/02/12 11:37:15 tommy Exp $ -# -# Copyright (C) 2003-2005 TOMITA Masahiro -# tommy@tmtm.org -# - -class Mysql - - VERSION = "4.0-ruby-0.2.6-plus-changes" - - require "socket" - require "digest/sha1" - - MAX_PACKET_LENGTH = 256*256*256-1 - MAX_ALLOWED_PACKET = 1024*1024*1024 - - MYSQL_UNIX_ADDR = "/tmp/mysql.sock" - MYSQL_PORT = 3306 - PROTOCOL_VERSION = 10 - - SCRAMBLE_LENGTH = 20 - SCRAMBLE_LENGTH_323 = 8 - - # Command - COM_SLEEP = 0 - COM_QUIT = 1 - COM_INIT_DB = 2 - COM_QUERY = 3 - COM_FIELD_LIST = 4 - COM_CREATE_DB = 5 - COM_DROP_DB = 6 - COM_REFRESH = 7 - COM_SHUTDOWN = 8 - COM_STATISTICS = 9 - COM_PROCESS_INFO = 10 - COM_CONNECT = 11 - COM_PROCESS_KILL = 12 - COM_DEBUG = 13 - COM_PING = 14 - COM_TIME = 15 - COM_DELAYED_INSERT = 16 - COM_CHANGE_USER = 17 - COM_BINLOG_DUMP = 18 - COM_TABLE_DUMP = 19 - COM_CONNECT_OUT = 20 - COM_REGISTER_SLAVE = 21 - - # Client flag - CLIENT_LONG_PASSWORD = 1 - CLIENT_FOUND_ROWS = 1 << 1 - CLIENT_LONG_FLAG = 1 << 2 - CLIENT_CONNECT_WITH_DB= 1 << 3 - CLIENT_NO_SCHEMA = 1 << 4 - CLIENT_COMPRESS = 1 << 5 - CLIENT_ODBC = 1 << 6 - CLIENT_LOCAL_FILES = 1 << 7 - CLIENT_IGNORE_SPACE = 1 << 8 - CLIENT_PROTOCOL_41 = 1 << 9 - CLIENT_INTERACTIVE = 1 << 10 - CLIENT_SSL = 1 << 11 - CLIENT_IGNORE_SIGPIPE = 1 << 12 - CLIENT_TRANSACTIONS = 1 << 13 - CLIENT_RESERVED = 1 << 14 - CLIENT_SECURE_CONNECTION = 1 << 15 - CLIENT_CAPABILITIES = CLIENT_LONG_PASSWORD|CLIENT_LONG_FLAG|CLIENT_TRANSACTIONS - PROTO_AUTH41 = CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION - - # Connection Option - OPT_CONNECT_TIMEOUT = 0 - OPT_COMPRESS = 1 - OPT_NAMED_PIPE = 2 - INIT_COMMAND = 3 - READ_DEFAULT_FILE = 4 - READ_DEFAULT_GROUP = 5 - SET_CHARSET_DIR = 6 - SET_CHARSET_NAME = 7 - OPT_LOCAL_INFILE = 8 - - # Server Status - SERVER_STATUS_IN_TRANS = 1 - SERVER_STATUS_AUTOCOMMIT = 2 - - # Refresh parameter - REFRESH_GRANT = 1 - REFRESH_LOG = 2 - REFRESH_TABLES = 4 - REFRESH_HOSTS = 8 - REFRESH_STATUS = 16 - REFRESH_THREADS = 32 - REFRESH_SLAVE = 64 - REFRESH_MASTER = 128 - - def initialize(*args) - @client_flag = 0 - @max_allowed_packet = MAX_ALLOWED_PACKET - @query_with_result = true - @status = :STATUS_READY - if args[0] != :INIT then - real_connect(*args) - end - end - - def real_connect(host=nil, user=nil, passwd=nil, db=nil, port=nil, socket=nil, flag=nil) - @server_status = SERVER_STATUS_AUTOCOMMIT - if (host == nil or host == "localhost") and defined? UNIXSocket then - unix_socket = socket || ENV["MYSQL_UNIX_PORT"] || MYSQL_UNIX_ADDR - sock = UNIXSocket::new(unix_socket) - @host_info = Error::err(Error::CR_LOCALHOST_CONNECTION) - @unix_socket = unix_socket - else - sock = TCPSocket::new(host, port||ENV["MYSQL_TCP_PORT"]||(Socket::getservbyname("mysql","tcp") rescue MYSQL_PORT)) - @host_info = sprintf Error::err(Error::CR_TCP_CONNECTION), host - end - @host = host ? host.dup : nil - sock.setsockopt Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true - @net = Net::new sock - - a = read - @protocol_version = a.slice!(0) - @server_version, a = a.split(/\0/,2) - @thread_id, @scramble_buff = a.slice!(0,13).unpack("La8") - if a.size >= 2 then - @server_capabilities, = a.slice!(0,2).unpack("v") - end - if a.size >= 16 then - @server_language, @server_status = a.slice!(0,3).unpack("cv") - end - - flag = 0 if flag == nil - flag |= @client_flag | CLIENT_CAPABILITIES - flag |= CLIENT_CONNECT_WITH_DB if db - - @pre_411 = (0 == @server_capabilities & PROTO_AUTH41) - if @pre_411 - data = Net::int2str(flag)+Net::int3str(@max_allowed_packet)+ - (user||"")+"\0"+ - scramble(passwd, @scramble_buff, @protocol_version==9) - else - dummy, @salt2 = a.unpack("a13a12") - @scramble_buff += @salt2 - flag |= PROTO_AUTH41 - data = Net::int4str(flag) + Net::int4str(@max_allowed_packet) + - ([8] + Array.new(23, 0)).pack("c24") + (user||"")+"\0"+ - scramble41(passwd, @scramble_buff) - end - - if db and @server_capabilities & CLIENT_CONNECT_WITH_DB != 0 - data << "\0" if @pre_411 - data << db - @db = db.dup - end - write data - pkt = read - handle_auth_fallback(pkt, passwd) - ObjectSpace.define_finalizer(self, Mysql.finalizer(@net)) - self - end - alias :connect :real_connect - - def handle_auth_fallback(pkt, passwd) - # A packet like this means that we need to send an old-format password - if pkt.size == 1 and pkt[0] == 254 and - @server_capabilities & CLIENT_SECURE_CONNECTION != 0 then - data = scramble(passwd, @scramble_buff, @protocol_version == 9) - write data + "\0" - read - end - end - - def escape_string(str) - Mysql::escape_string str - end - alias :quote :escape_string - - def get_client_info() - VERSION - end - alias :client_info :get_client_info - - def options(option, arg=nil) - if option == OPT_LOCAL_INFILE then - if arg == false or arg == 0 then - @client_flag &= ~CLIENT_LOCAL_FILES - else - @client_flag |= CLIENT_LOCAL_FILES - end - else - raise "not implemented" - end - end - - def real_query(query) - command COM_QUERY, query, true - read_query_result - self - end - - def use_result() - if @status != :STATUS_GET_RESULT then - error Error::CR_COMMANDS_OUT_OF_SYNC - end - res = Result::new self, @fields, @field_count - @status = :STATUS_USE_RESULT - res - end - - def store_result() - if @status != :STATUS_GET_RESULT then - error Error::CR_COMMANDS_OUT_OF_SYNC - end - @status = :STATUS_READY - data = read_rows @field_count - res = Result::new self, @fields, @field_count, data - @fields = nil - @affected_rows = data.length - res - end - - def change_user(user="", passwd="", db="") - if @pre_411 - data = user+"\0"+scramble(passwd, @scramble_buff, @protocol_version==9)+"\0"+db - else - data = user+"\0"+scramble41(passwd, @scramble_buff)+db - end - pkt = command COM_CHANGE_USER, data - handle_auth_fallback(pkt, passwd) - @user = user - @passwd = passwd - @db = db - end - - def character_set_name() - raise "not implemented" - end - - def close() - @status = :STATUS_READY - command COM_QUIT, nil, true - @net.close - self - end - - def create_db(db) - command COM_CREATE_DB, db - self - end - - def drop_db(db) - command COM_DROP_DB, db - self - end - - def dump_debug_info() - command COM_DEBUG - self - end - - def get_host_info() - @host_info - end - alias :host_info :get_host_info - - def get_proto_info() - @protocol_version - end - alias :proto_info :get_proto_info - - def get_server_info() - @server_version - end - alias :server_info :get_server_info - - def kill(id) - command COM_PROCESS_KILL, Net::int4str(id) - self - end - - def list_dbs(db=nil) - real_query "show databases #{db}" - @status = :STATUS_READY - read_rows(1).flatten - end - - def list_fields(table, field=nil) - command COM_FIELD_LIST, "#{table}\0#{field}", true - if @pre_411 - f = read_rows 6 - else - f = read_rows 7 - end - fields = unpack_fields(f, @server_capabilities & CLIENT_LONG_FLAG != 0) - res = Result::new self, fields, f.length - res.eof = true - res - end - - def list_processes() - data = command COM_PROCESS_INFO - @field_count = get_length data - if @pre_411 - fields = read_rows 5 - else - fields = read_rows 7 - end - @fields = unpack_fields(fields, @server_capabilities & CLIENT_LONG_FLAG != 0) - @status = :STATUS_GET_RESULT - store_result - end - - def list_tables(table=nil) - real_query "show tables #{table}" - @status = :STATUS_READY - read_rows(1).flatten - end - - def ping() - command COM_PING - self - end - - def query(query) - real_query query - if not @query_with_result then - return self - end - if @field_count == 0 then - return nil - end - store_result - end - - def refresh(r) - command COM_REFRESH, r.chr - self - end - - def reload() - refresh REFRESH_GRANT - self - end - - def select_db(db) - command COM_INIT_DB, db - @db = db - self - end - - def shutdown() - command COM_SHUTDOWN - self - end - - def stat() - command COM_STATISTICS - end - - attr_reader :info, :insert_id, :affected_rows, :field_count, :thread_id - attr_accessor :query_with_result, :status - - def read_one_row(field_count) - data = read - if data[0] == 254 and data.length == 1 ## EOF - return - elsif data[0] == 254 and data.length == 5 - return - end - rec = [] - field_count.times do - len = get_length data - if len == nil then - rec << len - else - rec << data.slice!(0,len) - end - end - rec - end - - def skip_result() - if @status == :STATUS_USE_RESULT then - loop do - data = read - break if data[0] == 254 and data.length == 1 - end - @status = :STATUS_READY - end - end - - def inspect() - "#<#{self.class}>" - end - - private - - def read_query_result() - data = read - @field_count = get_length(data) - if @field_count == nil then # LOAD DATA LOCAL INFILE - File::open(data) do |f| - write f.read - end - write "" # mark EOF - data = read - @field_count = get_length(data) - end - if @field_count == 0 then - @affected_rows = get_length(data, true) - @insert_id = get_length(data, true) - if @server_capabilities & CLIENT_TRANSACTIONS != 0 then - a = data.slice!(0,2) - @server_status = a[0]+a[1]*256 - end - if data.size > 0 and get_length(data) then - @info = data - end - else - @extra_info = get_length(data, true) - if @pre_411 - fields = read_rows(5) - else - fields = read_rows(7) - end - @fields = unpack_fields(fields, @server_capabilities & CLIENT_LONG_FLAG != 0) - @status = :STATUS_GET_RESULT - end - self - end - - def unpack_fields(data, long_flag_protocol) - ret = [] - data.each do |f| - if @pre_411 - table = org_table = f[0] - name = f[1] - length = f[2][0]+f[2][1]*256+f[2][2]*256*256 - type = f[3][0] - if long_flag_protocol then - flags = f[4][0]+f[4][1]*256 - decimals = f[4][2] - else - flags = f[4][0] - decimals = f[4][1] - end - def_value = f[5] - max_length = 0 - else - catalog = f[0] - db = f[1] - table = f[2] - org_table = f[3] - name = f[4] - org_name = f[5] - length = f[6][2]+f[6][3]*256+f[6][4]*256*256 - type = f[6][6] - flags = f[6][7]+f[6][8]*256 - decimals = f[6][9] - def_value = "" - max_length = 0 - end - ret << Field::new(table, org_table, name, length, type, flags, decimals, def_value, max_length) - end - ret - end - - def read_rows(field_count) - ret = [] - while rec = read_one_row(field_count) do - ret << rec - end - ret - end - - def get_length(data, longlong=nil) - return if data.length == 0 - c = data.slice!(0) - case c - when 251 - return nil - when 252 - a = data.slice!(0,2) - return a[0]+a[1]*256 - when 253 - a = data.slice!(0,3) - return a[0]+a[1]*256+a[2]*256**2 - when 254 - a = data.slice!(0,8) - if longlong then - return a[0]+a[1]*256+a[2]*256**2+a[3]*256**3+ - a[4]*256**4+a[5]*256**5+a[6]*256**6+a[7]*256**7 - else - return a[0]+a[1]*256+a[2]*256**2+a[3]*256**3 - end - else - c - end - end - - def command(cmd, arg=nil, skip_check=nil) - unless @net then - error Error::CR_SERVER_GONE_ERROR - end - if @status != :STATUS_READY then - error Error::CR_COMMANDS_OUT_OF_SYNC - end - @net.clear - write cmd.chr+(arg||"") - read unless skip_check - end - - def read() - unless @net then - error Error::CR_SERVER_GONE_ERROR - end - a = @net.read - if a[0] == 255 then - if a.length > 3 then - @errno = a[1]+a[2]*256 - @error = a[3 .. -1] - else - @errno = Error::CR_UNKNOWN_ERROR - @error = Error::err @errno - end - raise Error::new(@errno, @error) - end - a - end - - def write(arg) - unless @net then - error Error::CR_SERVER_GONE_ERROR - end - @net.write arg - end - - def hash_password(password) - nr = 1345345333 - add = 7 - nr2 = 0x12345671 - password.each_byte do |i| - next if i == 0x20 or i == 9 - nr ^= (((nr & 63) + add) * i) + (nr << 8) - nr2 += (nr2 << 8) ^ nr - add += i - end - [nr & ((1 << 31) - 1), nr2 & ((1 << 31) - 1)] - end - - def scramble(password, message, old_ver) - return "" if password == nil or password == "" - raise "old version password is not implemented" if old_ver - hash_pass = hash_password password - hash_message = hash_password message.slice(0,SCRAMBLE_LENGTH_323) - rnd = Random::new hash_pass[0] ^ hash_message[0], hash_pass[1] ^ hash_message[1] - to = [] - 1.upto(SCRAMBLE_LENGTH_323) do - to << ((rnd.rnd*31)+64).floor - end - extra = (rnd.rnd*31).floor - to.map! do |t| (t ^ extra).chr end - to.join - end - - def scramble41(password, message) - return 0x00.chr if password.nil? or password.empty? - buf = [0x14] - s1 = Digest::SHA1.digest(password) - s2 = Digest::SHA1.digest(s1) - x = Digest::SHA1.digest(message + s2) - (0..s1.length - 1).each {|i| buf.push(s1[i] ^ x[i])} - buf.pack("C*") - end - - def error(errno) - @errno = errno - @error = Error::err errno - raise Error::new(@errno, @error) - end - - class Result - def initialize(mysql, fields, field_count, data=nil) - @handle = mysql - @fields = fields - @field_count = field_count - @data = data - @current_field = 0 - @current_row = 0 - @eof = false - @row_count = 0 - end - attr_accessor :eof - - def data_seek(n) - @current_row = n - end - - def fetch_field() - return if @current_field >= @field_count - f = @fields[@current_field] - @current_field += 1 - f - end - - def fetch_fields() - @fields - end - - def fetch_field_direct(n) - @fields[n] - end - - def fetch_lengths() - @data ? @data[@current_row].map{|i| i ? i.length : 0} : @lengths - end - - def fetch_row() - if @data then - if @current_row >= @data.length then - @handle.status = :STATUS_READY - return - end - ret = @data[@current_row] - @current_row += 1 - else - return if @eof - ret = @handle.read_one_row @field_count - if ret == nil then - @eof = true - return - end - @lengths = ret.map{|i| i ? i.length : 0} - @row_count += 1 - end - ret - end - - def fetch_hash(with_table=nil) - row = fetch_row - return if row == nil - hash = {} - @fields.each_index do |i| - f = with_table ? @fields[i].table+"."+@fields[i].name : @fields[i].name - hash[f] = row[i] - end - hash - end - - def field_seek(n) - @current_field = n - end - - def field_tell() - @current_field - end - - def free() - @handle.skip_result - @handle = @fields = @data = nil - end - - def num_fields() - @field_count - end - - def num_rows() - @data ? @data.length : @row_count - end - - def row_seek(n) - @current_row = n - end - - def row_tell() - @current_row - end - - def each() - while row = fetch_row do - yield row - end - end - - def each_hash(with_table=nil) - while hash = fetch_hash(with_table) do - yield hash - end - end - - def inspect() - "#<#{self.class}>" - end - - end - - class Field - # Field type - TYPE_DECIMAL = 0 - TYPE_TINY = 1 - TYPE_SHORT = 2 - TYPE_LONG = 3 - TYPE_FLOAT = 4 - TYPE_DOUBLE = 5 - TYPE_NULL = 6 - TYPE_TIMESTAMP = 7 - TYPE_LONGLONG = 8 - TYPE_INT24 = 9 - TYPE_DATE = 10 - TYPE_TIME = 11 - TYPE_DATETIME = 12 - TYPE_YEAR = 13 - TYPE_NEWDATE = 14 - TYPE_ENUM = 247 - TYPE_SET = 248 - TYPE_TINY_BLOB = 249 - TYPE_MEDIUM_BLOB = 250 - TYPE_LONG_BLOB = 251 - TYPE_BLOB = 252 - TYPE_VAR_STRING = 253 - TYPE_STRING = 254 - TYPE_GEOMETRY = 255 - TYPE_CHAR = TYPE_TINY - TYPE_INTERVAL = TYPE_ENUM - - # Flag - NOT_NULL_FLAG = 1 - PRI_KEY_FLAG = 2 - UNIQUE_KEY_FLAG = 4 - MULTIPLE_KEY_FLAG = 8 - BLOB_FLAG = 16 - UNSIGNED_FLAG = 32 - ZEROFILL_FLAG = 64 - BINARY_FLAG = 128 - ENUM_FLAG = 256 - AUTO_INCREMENT_FLAG = 512 - TIMESTAMP_FLAG = 1024 - SET_FLAG = 2048 - NUM_FLAG = 32768 - PART_KEY_FLAG = 16384 - GROUP_FLAG = 32768 - UNIQUE_FLAG = 65536 - - def initialize(table, org_table, name, length, type, flags, decimals, def_value, max_length) - @table = table - @org_table = org_table - @name = name - @length = length - @type = type - @flags = flags - @decimals = decimals - @def = def_value - @max_length = max_length - if (type <= TYPE_INT24 and (type != TYPE_TIMESTAMP or length == 14 or length == 8)) or type == TYPE_YEAR then - @flags |= NUM_FLAG - end - end - attr_reader :table, :org_table, :name, :length, :type, :flags, :decimals, :def, :max_length - - def inspect() - "#<#{self.class}:#{@name}>" - end - end - - class Error < StandardError - # Server Error - ER_HASHCHK = 1000 - ER_NISAMCHK = 1001 - ER_NO = 1002 - ER_YES = 1003 - ER_CANT_CREATE_FILE = 1004 - ER_CANT_CREATE_TABLE = 1005 - ER_CANT_CREATE_DB = 1006 - ER_DB_CREATE_EXISTS = 1007 - ER_DB_DROP_EXISTS = 1008 - ER_DB_DROP_DELETE = 1009 - ER_DB_DROP_RMDIR = 1010 - ER_CANT_DELETE_FILE = 1011 - ER_CANT_FIND_SYSTEM_REC = 1012 - ER_CANT_GET_STAT = 1013 - ER_CANT_GET_WD = 1014 - ER_CANT_LOCK = 1015 - ER_CANT_OPEN_FILE = 1016 - ER_FILE_NOT_FOUND = 1017 - ER_CANT_READ_DIR = 1018 - ER_CANT_SET_WD = 1019 - ER_CHECKREAD = 1020 - ER_DISK_FULL = 1021 - ER_DUP_KEY = 1022 - ER_ERROR_ON_CLOSE = 1023 - ER_ERROR_ON_READ = 1024 - ER_ERROR_ON_RENAME = 1025 - ER_ERROR_ON_WRITE = 1026 - ER_FILE_USED = 1027 - ER_FILSORT_ABORT = 1028 - ER_FORM_NOT_FOUND = 1029 - ER_GET_ERRNO = 1030 - ER_ILLEGAL_HA = 1031 - ER_KEY_NOT_FOUND = 1032 - ER_NOT_FORM_FILE = 1033 - ER_NOT_KEYFILE = 1034 - ER_OLD_KEYFILE = 1035 - ER_OPEN_AS_READONLY = 1036 - ER_OUTOFMEMORY = 1037 - ER_OUT_OF_SORTMEMORY = 1038 - ER_UNEXPECTED_EOF = 1039 - ER_CON_COUNT_ERROR = 1040 - ER_OUT_OF_RESOURCES = 1041 - ER_BAD_HOST_ERROR = 1042 - ER_HANDSHAKE_ERROR = 1043 - ER_DBACCESS_DENIED_ERROR = 1044 - ER_ACCESS_DENIED_ERROR = 1045 - ER_NO_DB_ERROR = 1046 - ER_UNKNOWN_COM_ERROR = 1047 - ER_BAD_NULL_ERROR = 1048 - ER_BAD_DB_ERROR = 1049 - ER_TABLE_EXISTS_ERROR = 1050 - ER_BAD_TABLE_ERROR = 1051 - ER_NON_UNIQ_ERROR = 1052 - ER_SERVER_SHUTDOWN = 1053 - ER_BAD_FIELD_ERROR = 1054 - ER_WRONG_FIELD_WITH_GROUP = 1055 - ER_WRONG_GROUP_FIELD = 1056 - ER_WRONG_SUM_SELECT = 1057 - ER_WRONG_VALUE_COUNT = 1058 - ER_TOO_LONG_IDENT = 1059 - ER_DUP_FIELDNAME = 1060 - ER_DUP_KEYNAME = 1061 - ER_DUP_ENTRY = 1062 - ER_WRONG_FIELD_SPEC = 1063 - ER_PARSE_ERROR = 1064 - ER_EMPTY_QUERY = 1065 - ER_NONUNIQ_TABLE = 1066 - ER_INVALID_DEFAULT = 1067 - ER_MULTIPLE_PRI_KEY = 1068 - ER_TOO_MANY_KEYS = 1069 - ER_TOO_MANY_KEY_PARTS = 1070 - ER_TOO_LONG_KEY = 1071 - ER_KEY_COLUMN_DOES_NOT_EXITS = 1072 - ER_BLOB_USED_AS_KEY = 1073 - ER_TOO_BIG_FIELDLENGTH = 1074 - ER_WRONG_AUTO_KEY = 1075 - ER_READY = 1076 - ER_NORMAL_SHUTDOWN = 1077 - ER_GOT_SIGNAL = 1078 - ER_SHUTDOWN_COMPLETE = 1079 - ER_FORCING_CLOSE = 1080 - ER_IPSOCK_ERROR = 1081 - ER_NO_SUCH_INDEX = 1082 - ER_WRONG_FIELD_TERMINATORS = 1083 - ER_BLOBS_AND_NO_TERMINATED = 1084 - ER_TEXTFILE_NOT_READABLE = 1085 - ER_FILE_EXISTS_ERROR = 1086 - ER_LOAD_INFO = 1087 - ER_ALTER_INFO = 1088 - ER_WRONG_SUB_KEY = 1089 - ER_CANT_REMOVE_ALL_FIELDS = 1090 - ER_CANT_DROP_FIELD_OR_KEY = 1091 - ER_INSERT_INFO = 1092 - ER_INSERT_TABLE_USED = 1093 - ER_NO_SUCH_THREAD = 1094 - ER_KILL_DENIED_ERROR = 1095 - ER_NO_TABLES_USED = 1096 - ER_TOO_BIG_SET = 1097 - ER_NO_UNIQUE_LOGFILE = 1098 - ER_TABLE_NOT_LOCKED_FOR_WRITE = 1099 - ER_TABLE_NOT_LOCKED = 1100 - ER_BLOB_CANT_HAVE_DEFAULT = 1101 - ER_WRONG_DB_NAME = 1102 - ER_WRONG_TABLE_NAME = 1103 - ER_TOO_BIG_SELECT = 1104 - ER_UNKNOWN_ERROR = 1105 - ER_UNKNOWN_PROCEDURE = 1106 - ER_WRONG_PARAMCOUNT_TO_PROCEDURE = 1107 - ER_WRONG_PARAMETERS_TO_PROCEDURE = 1108 - ER_UNKNOWN_TABLE = 1109 - ER_FIELD_SPECIFIED_TWICE = 1110 - ER_INVALID_GROUP_FUNC_USE = 1111 - ER_UNSUPPORTED_EXTENSION = 1112 - ER_TABLE_MUST_HAVE_COLUMNS = 1113 - ER_RECORD_FILE_FULL = 1114 - ER_UNKNOWN_CHARACTER_SET = 1115 - ER_TOO_MANY_TABLES = 1116 - ER_TOO_MANY_FIELDS = 1117 - ER_TOO_BIG_ROWSIZE = 1118 - ER_STACK_OVERRUN = 1119 - ER_WRONG_OUTER_JOIN = 1120 - ER_NULL_COLUMN_IN_INDEX = 1121 - ER_CANT_FIND_UDF = 1122 - ER_CANT_INITIALIZE_UDF = 1123 - ER_UDF_NO_PATHS = 1124 - ER_UDF_EXISTS = 1125 - ER_CANT_OPEN_LIBRARY = 1126 - ER_CANT_FIND_DL_ENTRY = 1127 - ER_FUNCTION_NOT_DEFINED = 1128 - ER_HOST_IS_BLOCKED = 1129 - ER_HOST_NOT_PRIVILEGED = 1130 - ER_PASSWORD_ANONYMOUS_USER = 1131 - ER_PASSWORD_NOT_ALLOWED = 1132 - ER_PASSWORD_NO_MATCH = 1133 - ER_UPDATE_INFO = 1134 - ER_CANT_CREATE_THREAD = 1135 - ER_WRONG_VALUE_COUNT_ON_ROW = 1136 - ER_CANT_REOPEN_TABLE = 1137 - ER_INVALID_USE_OF_NULL = 1138 - ER_REGEXP_ERROR = 1139 - ER_MIX_OF_GROUP_FUNC_AND_FIELDS = 1140 - ER_NONEXISTING_GRANT = 1141 - ER_TABLEACCESS_DENIED_ERROR = 1142 - ER_COLUMNACCESS_DENIED_ERROR = 1143 - ER_ILLEGAL_GRANT_FOR_TABLE = 1144 - ER_GRANT_WRONG_HOST_OR_USER = 1145 - ER_NO_SUCH_TABLE = 1146 - ER_NONEXISTING_TABLE_GRANT = 1147 - ER_NOT_ALLOWED_COMMAND = 1148 - ER_SYNTAX_ERROR = 1149 - ER_DELAYED_CANT_CHANGE_LOCK = 1150 - ER_TOO_MANY_DELAYED_THREADS = 1151 - ER_ABORTING_CONNECTION = 1152 - ER_NET_PACKET_TOO_LARGE = 1153 - ER_NET_READ_ERROR_FROM_PIPE = 1154 - ER_NET_FCNTL_ERROR = 1155 - ER_NET_PACKETS_OUT_OF_ORDER = 1156 - ER_NET_UNCOMPRESS_ERROR = 1157 - ER_NET_READ_ERROR = 1158 - ER_NET_READ_INTERRUPTED = 1159 - ER_NET_ERROR_ON_WRITE = 1160 - ER_NET_WRITE_INTERRUPTED = 1161 - ER_TOO_LONG_STRING = 1162 - ER_TABLE_CANT_HANDLE_BLOB = 1163 - ER_TABLE_CANT_HANDLE_AUTO_INCREMENT = 1164 - ER_DELAYED_INSERT_TABLE_LOCKED = 1165 - ER_WRONG_COLUMN_NAME = 1166 - ER_WRONG_KEY_COLUMN = 1167 - ER_WRONG_MRG_TABLE = 1168 - ER_DUP_UNIQUE = 1169 - ER_BLOB_KEY_WITHOUT_LENGTH = 1170 - ER_PRIMARY_CANT_HAVE_NULL = 1171 - ER_TOO_MANY_ROWS = 1172 - ER_REQUIRES_PRIMARY_KEY = 1173 - ER_NO_RAID_COMPILED = 1174 - ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE = 1175 - ER_KEY_DOES_NOT_EXITS = 1176 - ER_CHECK_NO_SUCH_TABLE = 1177 - ER_CHECK_NOT_IMPLEMENTED = 1178 - ER_CANT_DO_THIS_DURING_AN_TRANSACTION = 1179 - ER_ERROR_DURING_COMMIT = 1180 - ER_ERROR_DURING_ROLLBACK = 1181 - ER_ERROR_DURING_FLUSH_LOGS = 1182 - ER_ERROR_DURING_CHECKPOINT = 1183 - ER_NEW_ABORTING_CONNECTION = 1184 - ER_DUMP_NOT_IMPLEMENTED = 1185 - ER_FLUSH_MASTER_BINLOG_CLOSED = 1186 - ER_INDEX_REBUILD = 1187 - ER_MASTER = 1188 - ER_MASTER_NET_READ = 1189 - ER_MASTER_NET_WRITE = 1190 - ER_FT_MATCHING_KEY_NOT_FOUND = 1191 - ER_LOCK_OR_ACTIVE_TRANSACTION = 1192 - ER_UNKNOWN_SYSTEM_VARIABLE = 1193 - ER_CRASHED_ON_USAGE = 1194 - ER_CRASHED_ON_REPAIR = 1195 - ER_WARNING_NOT_COMPLETE_ROLLBACK = 1196 - ER_TRANS_CACHE_FULL = 1197 - ER_SLAVE_MUST_STOP = 1198 - ER_SLAVE_NOT_RUNNING = 1199 - ER_BAD_SLAVE = 1200 - ER_MASTER_INFO = 1201 - ER_SLAVE_THREAD = 1202 - ER_TOO_MANY_USER_CONNECTIONS = 1203 - ER_SET_CONSTANTS_ONLY = 1204 - ER_LOCK_WAIT_TIMEOUT = 1205 - ER_LOCK_TABLE_FULL = 1206 - ER_READ_ONLY_TRANSACTION = 1207 - ER_DROP_DB_WITH_READ_LOCK = 1208 - ER_CREATE_DB_WITH_READ_LOCK = 1209 - ER_WRONG_ARGUMENTS = 1210 - ER_NO_PERMISSION_TO_CREATE_USER = 1211 - ER_UNION_TABLES_IN_DIFFERENT_DIR = 1212 - ER_LOCK_DEADLOCK = 1213 - ER_TABLE_CANT_HANDLE_FULLTEXT = 1214 - ER_CANNOT_ADD_FOREIGN = 1215 - ER_NO_REFERENCED_ROW = 1216 - ER_ROW_IS_REFERENCED = 1217 - ER_CONNECT_TO_MASTER = 1218 - ER_QUERY_ON_MASTER = 1219 - ER_ERROR_WHEN_EXECUTING_COMMAND = 1220 - ER_WRONG_USAGE = 1221 - ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT = 1222 - ER_CANT_UPDATE_WITH_READLOCK = 1223 - ER_MIXING_NOT_ALLOWED = 1224 - ER_DUP_ARGUMENT = 1225 - ER_USER_LIMIT_REACHED = 1226 - ER_SPECIFIC_ACCESS_DENIED_ERROR = 1227 - ER_LOCAL_VARIABLE = 1228 - ER_GLOBAL_VARIABLE = 1229 - ER_NO_DEFAULT = 1230 - ER_WRONG_VALUE_FOR_VAR = 1231 - ER_WRONG_TYPE_FOR_VAR = 1232 - ER_VAR_CANT_BE_READ = 1233 - ER_CANT_USE_OPTION_HERE = 1234 - ER_NOT_SUPPORTED_YET = 1235 - ER_MASTER_FATAL_ERROR_READING_BINLOG = 1236 - ER_SLAVE_IGNORED_TABLE = 1237 - ER_ERROR_MESSAGES = 238 - - # Client Error - CR_MIN_ERROR = 2000 - CR_MAX_ERROR = 2999 - CR_UNKNOWN_ERROR = 2000 - CR_SOCKET_CREATE_ERROR = 2001 - CR_CONNECTION_ERROR = 2002 - CR_CONN_HOST_ERROR = 2003 - CR_IPSOCK_ERROR = 2004 - CR_UNKNOWN_HOST = 2005 - CR_SERVER_GONE_ERROR = 2006 - CR_VERSION_ERROR = 2007 - CR_OUT_OF_MEMORY = 2008 - CR_WRONG_HOST_INFO = 2009 - CR_LOCALHOST_CONNECTION = 2010 - CR_TCP_CONNECTION = 2011 - CR_SERVER_HANDSHAKE_ERR = 2012 - CR_SERVER_LOST = 2013 - CR_COMMANDS_OUT_OF_SYNC = 2014 - CR_NAMEDPIPE_CONNECTION = 2015 - CR_NAMEDPIPEWAIT_ERROR = 2016 - CR_NAMEDPIPEOPEN_ERROR = 2017 - CR_NAMEDPIPESETSTATE_ERROR = 2018 - CR_CANT_READ_CHARSET = 2019 - CR_NET_PACKET_TOO_LARGE = 2020 - CR_EMBEDDED_CONNECTION = 2021 - CR_PROBE_SLAVE_STATUS = 2022 - CR_PROBE_SLAVE_HOSTS = 2023 - CR_PROBE_SLAVE_CONNECT = 2024 - CR_PROBE_MASTER_CONNECT = 2025 - CR_SSL_CONNECTION_ERROR = 2026 - CR_MALFORMED_PACKET = 2027 - - CLIENT_ERRORS = [ - "Unknown MySQL error", - "Can't create UNIX socket (%d)", - "Can't connect to local MySQL server through socket '%-.64s' (%d)", - "Can't connect to MySQL server on '%-.64s' (%d)", - "Can't create TCP/IP socket (%d)", - "Unknown MySQL Server Host '%-.64s' (%d)", - "MySQL server has gone away", - "Protocol mismatch. Server Version = %d Client Version = %d", - "MySQL client run out of memory", - "Wrong host info", - "Localhost via UNIX socket", - "%-.64s via TCP/IP", - "Error in server handshake", - "Lost connection to MySQL server during query", - "Commands out of sync; You can't run this command now", - "%-.64s via named pipe", - "Can't wait for named pipe to host: %-.64s pipe: %-.32s (%lu)", - "Can't open named pipe to host: %-.64s pipe: %-.32s (%lu)", - "Can't set state of named pipe to host: %-.64s pipe: %-.32s (%lu)", - "Can't initialize character set %-.64s (path: %-.64s)", - "Got packet bigger than 'max_allowed_packet'", - "Embedded server", - "Error on SHOW SLAVE STATUS:", - "Error on SHOW SLAVE HOSTS:", - "Error connecting to slave:", - "Error connecting to master:", - "SSL connection error", - "Malformed packet" - ] - - def initialize(errno, error) - @errno = errno - @error = error - super error - end - attr_reader :errno, :error - - def Error::err(errno) - CLIENT_ERRORS[errno - Error::CR_MIN_ERROR] - end - end - - class Net - def initialize(sock) - @sock = sock - @pkt_nr = 0 - end - - def clear() - @pkt_nr = 0 - end - - def read() - buf = [] - len = nil - @sock.sync = false - while len == nil or len == MAX_PACKET_LENGTH do - a = @sock.read(4) - len = a[0]+a[1]*256+a[2]*256*256 - pkt_nr = a[3] - if @pkt_nr != pkt_nr then - raise "Packets out of order: #{@pkt_nr}<>#{pkt_nr}" - end - @pkt_nr = @pkt_nr + 1 & 0xff - buf << @sock.read(len) - end - @sock.sync = true - buf.join - rescue - errno = Error::CR_SERVER_LOST - raise Error::new(errno, Error::err(errno)) - end - - def write(data) - if data.is_a? Array then - data = data.join - end - @sock.sync = false - ptr = 0 - while data.length >= MAX_PACKET_LENGTH do - @sock.write Net::int3str(MAX_PACKET_LENGTH)+@pkt_nr.chr+data[ptr, MAX_PACKET_LENGTH] - @pkt_nr = @pkt_nr + 1 & 0xff - ptr += MAX_PACKET_LENGTH - end - @sock.write Net::int3str(data.length-ptr)+@pkt_nr.chr+data[ptr .. -1] - @pkt_nr = @pkt_nr + 1 & 0xff - @sock.sync = true - @sock.flush - rescue - errno = Error::CR_SERVER_LOST - raise Error::new(errno, Error::err(errno)) - end - - def close() - @sock.close - end - - def Net::int2str(n) - [n].pack("v") - end - - def Net::int3str(n) - [n%256, n>>8].pack("cv") - end - - def Net::int4str(n) - [n].pack("V") - end - - end - - class Random - def initialize(seed1, seed2) - @max_value = 0x3FFFFFFF - @seed1 = seed1 % @max_value - @seed2 = seed2 % @max_value - end - - def rnd() - @seed1 = (@seed1*3+@seed2) % @max_value - @seed2 = (@seed1+@seed2+33) % @max_value - @seed1.to_f / @max_value - end - end - -end - -class << Mysql - def init() - Mysql::new :INIT - end - - def real_connect(*args) - Mysql::new(*args) - end - alias :connect :real_connect - - def finalizer(net) - proc { - net.clear - begin - net.write(Mysql::COM_QUIT.chr) - net.close - rescue # Ignore IOError if socket is already closed. - end - } - end - - def escape_string(str) - str.gsub(/([\0\n\r\032\'\"\\])/) do - case $1 - when "\0" then "\\0" - when "\n" then "\\n" - when "\r" then "\\r" - when "\032" then "\\Z" - else "\\"+$1 - end - end - end - alias :quote :escape_string - - def get_client_info() - Mysql::VERSION - end - alias :client_info :get_client_info - - def debug(str) - raise "not implemented" - end -end - -# -# for compatibility -# - -MysqlRes = Mysql::Result -MysqlField = Mysql::Field -MysqlError = Mysql::Error diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index e0da8bfb7a..9c718c4fef 100755 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -409,4 +409,23 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase sponsor.sponsorable = new_member assert_equal nil, sponsor.sponsorable_id end + + def test_save_fails_for_invalid_belongs_to + assert log = AuditLog.create(:developer_id=>0,:message=>"") + + log.developer = Developer.new + assert !log.developer.valid? + assert !log.valid? + assert !log.save + assert_equal "is invalid", log.errors.on("developer") + end + + def test_save_succeeds_for_invalid_belongs_to_with_validate_false + assert log = AuditLog.create(:developer_id=>0,:message=>"") + + log.unvalidated_developer = Developer.new + assert !log.unvalidated_developer.valid? + assert log.valid? + assert log.save + end end diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index 3a3358e39b..f65ada550b 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -14,11 +14,14 @@ require 'models/job' require 'models/subscriber' require 'models/subscription' require 'models/book' +require 'models/developer' +require 'models/project' class EagerAssociationTest < ActiveRecord::TestCase fixtures :posts, :comments, :authors, :categories, :categories_posts, :companies, :accounts, :tags, :taggings, :people, :readers, - :owners, :pets, :author_favorites, :jobs, :references, :subscribers, :subscriptions, :books + :owners, :pets, :author_favorites, :jobs, :references, :subscribers, :subscriptions, :books, + :developers, :projects def test_loading_with_one_association posts = Post.find(:all, :include => :comments) @@ -609,4 +612,12 @@ class EagerAssociationTest < ActiveRecord::TestCase Comment.find :all, :include => :post end end + + def test_conditions_on_join_table_with_include_and_limit + assert_equal 3, Developer.find(:all, :include => 'projects', :conditions => 'developers_projects.access_level = 1', :limit => 5).size + end + + def test_order_on_join_table_with_include_and_limit + assert_equal 5, Developer.find(:all, :include => 'projects', :order => 'developers_projects.joined_on DESC', :limit => 5).size + end end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index dbfa025efb..b638143c5a 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -37,15 +37,15 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_counting_with_single_conditions - assert_equal 2, Firm.find(:first).plain_clients.count(:conditions => '1=1') + assert_equal 1, Firm.find(:first).plain_clients.count(:conditions => ['name=?', "Microsoft"]) end def test_counting_with_single_hash - assert_equal 2, Firm.find(:first).plain_clients.count(:conditions => '1=1') + assert_equal 1, Firm.find(:first).plain_clients.count(:conditions => {:name => "Microsoft"}) end def test_counting_with_column_name_and_hash - assert_equal 2, Firm.find(:first).plain_clients.count(:all, :conditions => '1=1') + assert_equal 2, Firm.find(:first).plain_clients.count(:name) end def test_finding @@ -342,6 +342,17 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert new_firm.new_record? end + def test_invalid_adding_with_validate_false + firm = Firm.find(:first) + client = Client.new + firm.unvalidated_clients_of_firm << Client.new + + assert firm.valid? + assert !client.valid? + assert firm.save + assert client.new_record? + end + def test_build company = companies(:first_firm) new_client = assert_no_queries { company.clients_of_firm.build("name" => "Another Client") } diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index abc7ee7e9d..d3ca0cae41 100755 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -275,6 +275,18 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert_equal "is invalid", firm.errors.on("account") end + + def test_save_succeeds_for_invalid_has_one_with_validate_false + firm = Firm.find(:first) + assert firm.valid? + + firm.unvalidated_account = Account.new + + assert !firm.unvalidated_account.valid? + assert firm.valid? + assert firm.save + end + def test_assignment_before_either_saved firm = Firm.new("name" => "GlobalMegaCorp") firm.account = a = Account.new("credit_limit" => 1000) diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index aefb13ea9a..754fd58f35 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -1,6 +1,7 @@ require "cases/helper" require 'models/company' require 'models/topic' +require 'models/edge' Company.has_many :accounts @@ -274,4 +275,49 @@ class CalculationsTest < ActiveRecord::TestCase def test_should_sum_expression assert_equal 636, Account.sum("2 * credit_limit") end + + def test_count_with_from_option + assert_equal Company.count(:all), Company.count(:all, :from => 'companies') + assert_equal Account.count(:all, :conditions => "credit_limit = 50"), + Account.count(:all, :from => 'accounts', :conditions => "credit_limit = 50") + assert_equal Company.count(:type, :conditions => {:type => "Firm"}), + Company.count(:type, :conditions => {:type => "Firm"}, :from => 'companies') + end + + def test_sum_with_from_option + assert_equal Account.sum(:credit_limit), Account.sum(:credit_limit, :from => 'accounts') + assert_equal Account.sum(:credit_limit, :conditions => "credit_limit > 50"), + Account.sum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50") + end + + def test_average_with_from_option + assert_equal Account.average(:credit_limit), Account.average(:credit_limit, :from => 'accounts') + assert_equal Account.average(:credit_limit, :conditions => "credit_limit > 50"), + Account.average(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50") + end + + def test_minimum_with_from_option + assert_equal Account.minimum(:credit_limit), Account.minimum(:credit_limit, :from => 'accounts') + assert_equal Account.minimum(:credit_limit, :conditions => "credit_limit > 50"), + Account.minimum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50") + end + + def test_maximum_with_from_option + assert_equal Account.maximum(:credit_limit), Account.maximum(:credit_limit, :from => 'accounts') + assert_equal Account.maximum(:credit_limit, :conditions => "credit_limit > 50"), + Account.maximum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50") + end + + def test_from_option_with_specified_index + if Edge.connection.adapter_name == 'MySQL' + assert_equal Edge.count(:all), Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)') + assert_equal Edge.count(:all, :conditions => 'sink_id < 5'), + Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)', :conditions => 'sink_id < 5') + end + end + + def test_from_option_with_table_different_than_class + assert_equal Account.count(:all), Company.count(:all, :from => 'accounts') + end + end diff --git a/activerecord/test/cases/database_statements_test.rb b/activerecord/test/cases/database_statements_test.rb new file mode 100644 index 0000000000..6274d5250f --- /dev/null +++ b/activerecord/test/cases/database_statements_test.rb @@ -0,0 +1,12 @@ +require "cases/helper" + +class DatabaseStatementsTest < ActiveRecord::TestCase + def setup + @connection = ActiveRecord::Base.connection + end + + def test_insert_should_return_the_inserted_id + id = @connection.insert("INSERT INTO accounts (firm_id,credit_limit) VALUES (42,5000)") + assert_not_nil id + end +end diff --git a/activerecord/test/cases/lifecycle_test.rb b/activerecord/test/cases/lifecycle_test.rb index ddcacacc3a..258f7c7a0f 100755 --- a/activerecord/test/cases/lifecycle_test.rb +++ b/activerecord/test/cases/lifecycle_test.rb @@ -2,6 +2,7 @@ require "cases/helper" require 'models/topic' require 'models/developer' require 'models/reply' +require 'models/minimalistic' class Topic; def after_find() end end class Developer; def after_find() end end @@ -44,6 +45,14 @@ class TopicObserver < ActiveRecord::Observer end end +class MinimalisticObserver < ActiveRecord::Observer + attr_reader :minimalistic + + def after_find(minimalistic) + @minimalistic = minimalistic + end +end + class MultiObserver < ActiveRecord::Observer attr_reader :record @@ -134,6 +143,14 @@ class LifecycleTest < ActiveRecord::TestCase assert_equal developer.name, multi_observer.record.name end + def test_observing_after_find_when_not_defined_on_the_model + observer = MinimalisticObserver.instance + assert_equal Minimalistic, MinimalisticObserver.observed_class + + minimalistic = Minimalistic.find(1) + assert_equal minimalistic, observer.minimalistic + end + def test_invalid_observer assert_raise(ArgumentError) { Topic.observers = Object.new; Topic.instantiate_observers } end diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index 8b4d232554..0c57b79401 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -160,9 +160,9 @@ class ReflectionTest < ActiveRecord::TestCase def test_reflection_of_all_associations # FIXME these assertions bust a lot - assert_equal 20, Firm.reflect_on_all_associations.size - assert_equal 16, Firm.reflect_on_all_associations(:has_many).size - assert_equal 4, Firm.reflect_on_all_associations(:has_one).size + assert_equal 22, Firm.reflect_on_all_associations.size + assert_equal 17, Firm.reflect_on_all_associations(:has_many).size + assert_equal 5, Firm.reflect_on_all_associations(:has_one).size assert_equal 0, Firm.reflect_on_all_associations(:belongs_to).size end diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb index 70f83fa8e6..9fa810ac68 100755 --- a/activerecord/test/models/company.rb +++ b/activerecord/test/models/company.rb @@ -26,6 +26,7 @@ class Firm < Company "AND (#{QUOTED_TYPE} = 'Client' OR #{QUOTED_TYPE} = 'SpecialClient' OR #{QUOTED_TYPE} = 'VerySpecialClient' )" has_many :clients_sorted_desc, :class_name => "Client", :order => "id DESC" has_many :clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id" + has_many :unvalidated_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :validate => false has_many :dependent_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id", :dependent => :destroy has_many :exclusively_dependent_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id", :dependent => :delete_all has_many :limited_clients, :class_name => "Client", :order => "id", :limit => 1 @@ -46,7 +47,8 @@ class Firm < Company has_many :plain_clients, :class_name => 'Client' has_many :readonly_clients, :class_name => 'Client', :readonly => true - has_one :account, :foreign_key => "firm_id", :dependent => :destroy + has_one :account, :foreign_key => "firm_id", :dependent => :destroy, :validate => true + has_one :unvalidated_account, :foreign_key => "firm_id", :class_name => 'Account', :validate => false has_one :account_with_select, :foreign_key => "firm_id", :select => "id, firm_id", :class_name=>'Account' has_one :readonly_account, :foreign_key => "firm_id", :class_name => "Account", :readonly => true end diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb index f77fd0e96d..9f26cacdec 100644 --- a/activerecord/test/models/developer.rb +++ b/activerecord/test/models/developer.rb @@ -56,7 +56,8 @@ class Developer < ActiveRecord::Base end class AuditLog < ActiveRecord::Base - belongs_to :developer + belongs_to :developer, :validate => true + belongs_to :unvalidated_developer, :class_name => 'Developer' end DeveloperSalary = Struct.new(:amount) diff --git a/activeresource/Rakefile b/activeresource/Rakefile index 9fd0ec4921..89901292a5 100644 --- a/activeresource/Rakefile +++ b/activeresource/Rakefile @@ -45,6 +45,7 @@ Rake::RDocTask.new { |rdoc| rdoc.template = "#{ENV['template']}.rb" if ENV['template'] rdoc.rdoc_files.include('README', 'CHANGELOG') rdoc.rdoc_files.include('lib/**/*.rb') + rdoc.rdoc_files.exclude('lib/activeresource.rb') } @@ -114,13 +115,13 @@ end desc "Publish the beta gem" task :pgem => [:package] do - Rake::SshFilePublisher.new("davidhh@wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload - `ssh davidhh@wrath.rubyonrails.org './gemupdate.sh'` + Rake::SshFilePublisher.new("wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload + `ssh wrath.rubyonrails.org './gemupdate.sh'` end desc "Publish the API documentation" task :pdoc => [:rdoc] do - Rake::SshDirPublisher.new("davidhh@wrath.rubyonrails.org", "public_html/ar", "doc").upload + Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/ar", "doc").upload end desc "Publish the release files to RubyForge." diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index 55dacfdf06..347dbb82aa 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -988,7 +988,11 @@ module ActiveResource self.class.const_get(resource_name) end rescue NameError - resource = self.class.const_set(resource_name, Class.new(ActiveResource::Base)) + if self.class.const_defined?(resource_name) + resource = self.class.const_get(resource_name) + else + resource = self.class.const_set(resource_name, Class.new(ActiveResource::Base)) + end resource.prefix = self.class.prefix resource.site = self.class.site resource diff --git a/activeresource/test/base_test.rb b/activeresource/test/base_test.rb index 9e2f6c1831..4addd52636 100644 --- a/activeresource/test/base_test.rb +++ b/activeresource/test/base_test.rb @@ -1,5 +1,6 @@ require 'abstract_unit' require "fixtures/person" +require "fixtures/customer" require "fixtures/street_address" require "fixtures/beast" @@ -15,6 +16,37 @@ class BaseTest < Test::Unit::TestCase @people_david = [{ :id => 2, :name => 'David' }].to_xml(:root => 'people') @addresses = [{ :id => 1, :street => '12345 Street' }].to_xml(:root => 'addresses') + # - deep nested resource - + # - Luis (Customer) + # - JK (Customer::Friend) + # - Mateo (Customer::Friend::Brother) + # - Edith (Customer::Friend::Brother::Child) + # - Martha (Customer::Friend::Brother::Child) + # - Felipe (Customer::Friend::Brother) + # - Bryan (Customer::Friend::Brother::Child) + # - Luke (Customer::Friend::Brother::Child) + # - Eduardo (Customer::Friend) + # - Sebas (Customer::Friend::Brother) + # - Andres (Customer::Friend::Brother::Child) + # - Jorge (Customer::Friend::Brother::Child) + # - Elsa (Customer::Friend::Brother) + # - Natacha (Customer::Friend::Brother::Child) + # - Milena (Customer::Friend::Brother) + # + @luis = {:id => 1, :name => 'Luis', + :friends => [{:name => 'JK', + :brothers => [{:name => 'Mateo', + :children => [{:name => 'Edith'},{:name => 'Martha'}]}, + {:name => 'Felipe', + :children => [{:name => 'Bryan'},{:name => 'Luke'}]}]}, + {:name => 'Eduardo', + :brothers => [{:name => 'Sebas', + :children => [{:name => 'Andres'},{:name => 'Jorge'}]}, + {:name => 'Elsa', + :children => [{:name => 'Natacha'}]}, + {:name => 'Milena', + :children => []}]}]}.to_xml(:root => 'customer') + ActiveResource::HttpMock.respond_to do |mock| mock.get "/people/1.xml", {}, @matz mock.get "/people/2.xml", {}, @david @@ -46,6 +78,8 @@ class BaseTest < Test::Unit::TestCase mock.head "/people/1/addresses/2.xml", {}, nil, 404 mock.head "/people/2/addresses/1.xml", {}, nil, 404 mock.head "/people/Greg/addresses/1.xml", {}, nil, 200 + # customer + mock.get "/customers/1.xml", {}, @luis end Person.user = nil @@ -788,4 +822,18 @@ class BaseTest < Test::Unit::TestCase matz = Person.find(1) assert_equal '1', matz.to_param end + + def test_parse_deep_nested_resources + luis = Customer.find(1) + assert_kind_of Customer, luis + luis.friends.each do |friend| + assert_kind_of Customer::Friend, friend + friend.brothers.each do |brother| + assert_kind_of Customer::Friend::Brother, brother + brother.children.each do |child| + assert_kind_of Customer::Friend::Brother::Child, child + end + end + end + end end diff --git a/activeresource/test/fixtures/customer.rb b/activeresource/test/fixtures/customer.rb new file mode 100644 index 0000000000..845d5d11cb --- /dev/null +++ b/activeresource/test/fixtures/customer.rb @@ -0,0 +1,3 @@ +class Customer < ActiveResource::Base + self.site = "http://37s.sunrise.i:3000" +end diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index c7739fd7e0..d87558aba9 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,5 +1,13 @@ *Edge* +* Added Array#second through Array#tenth as aliases for Array#[1] through Array#[9] [DHH] + +* Added test/do declaration style testing to ActiveSupport::TestCase [DHH via Jay Fields] + +* Added Object#present? which is equivalent to !Object#blank? [DHH] + +* Added Enumberable#many? to encapsulate collection.size > 1 [DHH] + * Add more standard Hash methods to ActiveSupport::OrderedHash [Steve Purcell] * Namespace Inflector, Dependencies, OrderedOptions, and TimeZone under ActiveSupport [Josh Peek] diff --git a/activesupport/Rakefile b/activesupport/Rakefile index 38ca03b658..74d2750011 100644 --- a/activesupport/Rakefile +++ b/activesupport/Rakefile @@ -36,8 +36,8 @@ Rake::RDocTask.new { |rdoc| rdoc.template = "#{ENV['template']}.rb" if ENV['template'] rdoc.rdoc_files.include('README', 'CHANGELOG') rdoc.rdoc_files.include('lib/active_support.rb') - rdoc.rdoc_files.include('lib/active_support/*.rb') rdoc.rdoc_files.include('lib/active_support/**/*.rb') + rdoc.rdoc_files.exclude('lib/active_support/vendor/*') } spec = Gem::Specification.new do |s| @@ -65,13 +65,13 @@ end desc "Publish the beta gem" task :pgem => [:package] do - Rake::SshFilePublisher.new("davidhh@wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload - `ssh davidhh@wrath.rubyonrails.org './gemupdate.sh'` + Rake::SshFilePublisher.new("wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload + `ssh wrath.rubyonrails.org './gemupdate.sh'` end desc "Publish the API documentation" task :pdoc => [:rdoc] do - Rake::SshDirPublisher.new("davidhh@wrath.rubyonrails.org", "public_html/as", "doc").upload + Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/as", "doc").upload end desc "Publish the release files to RubyForge." @@ -119,7 +119,7 @@ namespace :tzinfo do task :copy_definitions => :unpack_gem do definitions_path = "#{destination_path}/tzinfo/definitions/" mkdir_p definitions_path - TimeZone::MAPPING.values.each do |zone| + ActiveSupport::TimeZone::MAPPING.values.each do |zone| subdir = nil if /\// === zone subdir = zone.sub(/\w+$/, '') @@ -172,4 +172,4 @@ namespace :tzinfo do def excluded_classes %w(country country_index_definition country_info country_timezone timezone_index_definition timezone_proxy tzdataparser) end -end
\ No newline at end of file +end diff --git a/activesupport/lib/active_support/core_ext/array/access.rb b/activesupport/lib/active_support/core_ext/array/access.rb index 21a8584bb9..4ac95efdc7 100644 --- a/activesupport/lib/active_support/core_ext/array/access.rb +++ b/activesupport/lib/active_support/core_ext/array/access.rb @@ -20,6 +20,51 @@ module ActiveSupport #:nodoc: def to(position) self[0..position] end + + # Equal to self[1] + def second + self[1] + end + + # Equal to self[2] + def third + self[2] + end + + # Equal to self[3] + def fourth + self[3] + end + + # Equal to self[4] + def fifth + self[4] + end + + # Equal to self[5] + def sixth + self[5] + end + + # Equal to self[6] + def seventh + self[6] + end + + # Equal to self[7] + def eighth + self[7] + end + + # Equal to self[8] + def ninth + self[8] + end + + # Equal to self[9] + def tenth + self[9] + end end end end diff --git a/activesupport/lib/active_support/core_ext/blank.rb b/activesupport/lib/active_support/core_ext/blank.rb index dfe33162e8..4f8dc4e281 100644 --- a/activesupport/lib/active_support/core_ext/blank.rb +++ b/activesupport/lib/active_support/core_ext/blank.rb @@ -12,6 +12,11 @@ class Object def blank? respond_to?(:empty?) ? empty? : !self end + + # An object is present if it's not blank. + def present? + !blank? + end end class NilClass #:nodoc: diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb index f1469aa0e3..9647797ec2 100644 --- a/activesupport/lib/active_support/core_ext/enumerable.rb +++ b/activesupport/lib/active_support/core_ext/enumerable.rb @@ -1,3 +1,5 @@ +require 'active_support/ordered_hash' + module Enumerable # Ruby 1.8.7 introduces group_by, but the result isn't ordered. Override it. remove_method(:group_by) if [].respond_to?(:group_by) && RUBY_VERSION < '1.9' @@ -18,10 +20,19 @@ module Enumerable # "2006-02-24 -> Transcript, Transcript" # "2006-02-23 -> Transcript" def group_by - inject ActiveSupport::OrderedHash.new do |grouped, element| - (grouped[yield(element)] ||= []) << element - grouped + assoc = ActiveSupport::OrderedHash.new + + each do |element| + key = yield(element) + + if assoc.has_key?(key) + assoc[key] << element + else + assoc[key] = [element] + end end + + assoc end unless [].respond_to?(:group_by) # Calculates a sum from the elements. Examples: @@ -66,4 +77,9 @@ module Enumerable accum end end + + # Returns true if the collection has more than 1 element. Functionally equivalent to collection.size > 1. + def many? + size > 1 + end end diff --git a/activesupport/lib/active_support/core_ext/hash/except.rb b/activesupport/lib/active_support/core_ext/hash/except.rb index 8362cd880e..bc97fa35a6 100644 --- a/activesupport/lib/active_support/core_ext/hash/except.rb +++ b/activesupport/lib/active_support/core_ext/hash/except.rb @@ -10,13 +10,14 @@ module ActiveSupport #:nodoc: module Except # Returns a new hash without the given keys. def except(*keys) - rejected = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys) - reject { |key,| rejected.include?(key) } + clone.except!(*keys) end # Replaces the hash without only the given keys. def except!(*keys) - replace(except(*keys)) + keys.map! { |key| convert_key(key) } if respond_to?(:convert_key) + keys.each { |key| delete(key) } + self end end end diff --git a/activesupport/lib/active_support/ordered_hash.rb b/activesupport/lib/active_support/ordered_hash.rb index 59ceaec696..9757054e43 100644 --- a/activesupport/lib/active_support/ordered_hash.rb +++ b/activesupport/lib/active_support/ordered_hash.rb @@ -12,6 +12,7 @@ module ActiveSupport else self << [key, value] end + value end def [](key) diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb index 67cde1556c..2fd02d5313 100644 --- a/activesupport/lib/active_support/test_case.rb +++ b/activesupport/lib/active_support/test_case.rb @@ -9,5 +9,14 @@ end module ActiveSupport class TestCase < Test::Unit::TestCase + # test "verify something" do + # ... + # end + def self.test(name, &block) + test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym + defined = instance_method(test_name) rescue false + raise "#{test_name} is already defined in #{self}" if defined + define_method(test_name, &block) + end end end diff --git a/activesupport/lib/active_support/testing/performance.rb b/activesupport/lib/active_support/testing/performance.rb new file mode 100644 index 0000000000..2317171467 --- /dev/null +++ b/activesupport/lib/active_support/testing/performance.rb @@ -0,0 +1,397 @@ +require 'rubygems' +gem 'ruby-prof', '>= 0.6.1' +require 'ruby-prof' + +require 'fileutils' +require 'rails/version' + +module ActiveSupport + module Testing + module Performance + DEFAULTS = + if benchmark = ARGV.include?('--benchmark') # HAX for rake test + { :benchmark => true, + :runs => 10, + :metrics => [:process_time, :memory, :objects, :gc_runs, :gc_time], + :output => 'tmp/performance' } + else + { :benchmark => false, + :runs => 1, + :min_percent => 0.02, + :metrics => [:process_time, :memory, :objects, :gc_runs, :gc_time], + :formats => [:flat, :graph_html, :call_tree], + :output => 'tmp/performance' } + end + + def self.included(base) + base.class_inheritable_hash :profile_options + base.profile_options = DEFAULTS.dup + end + + def full_test_name + "#{self.class.name}##{method_name}" + end + + def run(result) + return if method_name =~ /^default_test$/ + + yield(self.class::STARTED, name) + @_result = result + + run_warmup + profile_options[:metrics].each do |metric_name| + if klass = Metrics[metric_name.to_sym] + run_profile(klass.new) + result.add_run + else + $stderr.puts '%20s: unsupported' % metric_name.to_s + end + end + + yield(self.class::FINISHED, name) + end + + def run_test(metric, mode) + run_callbacks :setup + setup + metric.send(mode) { __send__ @method_name } + rescue ::Test::Unit::AssertionFailedError => e + add_failure(e.message, e.backtrace) + rescue StandardError, ScriptError + add_error($!) + ensure + begin + teardown + run_callbacks :teardown, :enumerator => :reverse_each + rescue ::Test::Unit::AssertionFailedError => e + add_failure(e.message, e.backtrace) + rescue StandardError, ScriptError + add_error($!) + end + end + + protected + def run_warmup + 5.times { GC.start } + + time = Metrics::Time.new + run_test(time, :benchmark) + puts "%s (%s warmup)" % [full_test_name, time.format(time.total)] + + 5.times { GC.start } + end + + def run_profile(metric) + klass = profile_options[:benchmark] ? Benchmarker : Profiler + performer = klass.new(self, metric) + + performer.run + puts performer.report + performer.record + end + + class Performer + delegate :run_test, :profile_options, :full_test_name, :to => :@harness + + def initialize(harness, metric) + @harness, @metric = harness, metric + end + + def report + rate = @total / profile_options[:runs] + '%20s: %s/run' % [@metric.name, @metric.format(rate)] + end + + protected + def output_filename + "#{profile_options[:output]}/#{full_test_name}_#{@metric.name}" + end + end + + class Benchmarker < Performer + def run + profile_options[:runs].to_i.times { run_test(@metric, :benchmark) } + @total = @metric.total + end + + def record + avg = @metric.total / profile_options[:runs].to_i + now = Time.now.utc.xmlschema + with_output_file do |file| + file.puts "#{avg},#{now},#{environment}" + end + end + + def environment + unless defined? @env + app = "#{$1}.#{$2}" if `git branch -v` =~ /^\* (\S+)\s+(\S+)/ + + rails = Rails::VERSION::STRING + if File.directory?('vendor/rails/.git') + Dir.chdir('vendor/rails') do + rails += ".#{$1}.#{$2}" if `git branch -v` =~ /^\* (\S+)\s+(\S+)/ + end + end + + ruby = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby' + ruby += "-#{RUBY_VERSION}.#{RUBY_PATCHLEVEL}" + + @env = [app, rails, ruby, RUBY_PLATFORM] * ',' + end + + @env + end + + protected + HEADER = 'measurement,created_at,app,rails,ruby,platform' + + def with_output_file + fname = output_filename + + if new = !File.exist?(fname) + FileUtils.mkdir_p(File.dirname(fname)) + end + + File.open(fname, 'ab') do |file| + file.puts(HEADER) if new + yield file + end + end + + def output_filename + "#{super}.csv" + end + end + + class Profiler < Performer + def run + RubyProf.measure_mode = @metric.measure_mode + RubyProf.start + RubyProf.pause + profile_options[:runs].to_i.times { run_test(@metric, :profile) } + @data = RubyProf.stop + @total = @data.threads.values.sum(0) { |method_infos| method_infos.sort.last.total_time } + end + + def record + klasses = profile_options[:formats].map { |f| RubyProf.const_get("#{f.to_s.camelize}Printer") }.compact + + klasses.each do |klass| + fname = output_filename(klass) + FileUtils.mkdir_p(File.dirname(fname)) + File.open(fname, 'wb') do |file| + klass.new(@data).print(file, profile_options.slice(:min_percent)) + end + end + end + + protected + def output_filename(printer_class) + suffix = + case printer_class.name.demodulize + when 'FlatPrinter'; 'flat.txt' + when 'GraphPrinter'; 'graph.txt' + when 'GraphHtmlPrinter'; 'graph.html' + when 'CallTreePrinter'; 'tree.txt' + else printer_class.name.sub(/Printer$/, '').underscore + end + + "#{super()}_#{suffix}" + end + end + + module Metrics + def self.[](name) + klass = const_get(name.to_s.camelize) + klass if klass::Mode + rescue NameError + nil + end + + class Base + attr_reader :total + + def initialize + @total = 0 + end + + def name + @name ||= self.class.name.demodulize.underscore + end + + def measure_mode + self.class::Mode + end + + def measure + 0 + end + + def benchmark + with_gc_stats do + before = measure + yield + @total += (measure - before) + end + end + + def profile + RubyProf.resume + yield + ensure + RubyProf.pause + end + + protected + if GC.respond_to?(:enable_stats) + def with_gc_stats + GC.enable_stats + yield + ensure + GC.disable_stats + end + else + def with_gc_stats + yield + end + end + end + + class Time < Base + def measure + ::Time.now.to_f + end + + def format(measurement) + if measurement < 2 + '%d ms' % (measurement * 1000) + else + '%.2f sec' % measurement + end + end + end + + class ProcessTime < Time + Mode = RubyProf::PROCESS_TIME + + def measure + RubyProf.measure_process_time + end + end + + class WallTime < Time + Mode = RubyProf::WALL_TIME + + def measure + RubyProf.measure_wall_time + end + end + + class CpuTime < Time + Mode = RubyProf::CPU_TIME + + def initialize(*args) + # FIXME: yeah my CPU is 2.33 GHz + RubyProf.cpu_frequency = 2.33e9 + super + end + + def measure + RubyProf.measure_cpu_time + end + end + + class Memory < Base + Mode = RubyProf::MEMORY + + # ruby-prof wrapper + if RubyProf.respond_to?(:measure_memory) + def measure + RubyProf.measure_memory / 1024.0 + end + + # Ruby 1.8 + adymo patch + elsif GC.respond_to?(:allocated_size) + def measure + GC.allocated_size / 1024.0 + end + + # Ruby 1.8 + lloyd patch + elsif GC.respond_to?(:heap_info) + def measure + GC.heap_info['heap_current_memory'] / 1024.0 + end + + # Ruby 1.9 unpatched + elsif GC.respond_to?(:malloc_allocated_size) + def measure + GC.malloc_allocated_size / 1024.0 + end + end + + def format(measurement) + '%.2f KB' % measurement + end + end + + class Objects < Base + Mode = RubyProf::ALLOCATIONS + + if RubyProf.respond_to?(:measure_allocations) + def measure + RubyProf.measure_allocations + end + elsif ObjectSpace.respond_to?(:allocated_objects) + def measure + ObjectSpace.allocated_objects + end + end + + def format(measurement) + measurement.to_i.to_s + end + end + + class GcRuns < Base + Mode = RubyProf::GC_RUNS + + if RubyProf.respond_to?(:measure_gc_runs) + def measure + RubyProf.measure_gc_runs + end + elsif GC.respond_to?(:collections) + def measure + GC.collections + end + elsif GC.respond_to?(:heap_info) + def measure + GC.heap_info['num_gc_passes'] + end + end + + def format(measurement) + measurement.to_i.to_s + end + end + + class GcTime < Base + Mode = RubyProf::GC_TIME + + if RubyProf.respond_to?(:measure_gc_time) + def measure + RubyProf.measure_gc_time + end + elsif GC.respond_to?(:time) + def measure + GC.time + end + end + + def format(measurement) + '%d ms' % (measurement / 1000) + end + end + end + end + end +end diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb index ed8e34510a..21d71eb92a 100644 --- a/activesupport/lib/active_support/testing/setup_and_teardown.rb +++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb @@ -10,19 +10,43 @@ module ActiveSupport end def self.included(base) - base.send :include, ActiveSupport::Callbacks - base.define_callbacks :setup, :teardown + base.class_eval do + include ActiveSupport::Callbacks + define_callbacks :setup, :teardown + if defined?(::Mini) + alias_method :run, :run_with_callbacks_and_miniunit + else + begin + require 'mocha' + alias_method :run, :run_with_callbacks_and_mocha + rescue LoadError + alias_method :run, :run_with_callbacks_and_testunit + end + end + end + end + + def run_with_callbacks_and_miniunit(runner) + result = '.' begin - require 'mocha' - base.alias_method_chain :run, :callbacks_and_mocha - rescue LoadError - base.alias_method_chain :run, :callbacks + run_callbacks :setup + result = super + rescue Exception => e + result = runner.puke(self.class, self.name, e) + ensure + begin + teardown + run_callbacks :teardown, :enumerator => :reverse_each + rescue Exception => e + result = runner.puke(self.class, self.name, e) + end end + result end # This redefinition is unfortunate but test/unit shows us no alternative. - def run_with_callbacks(result) #:nodoc: + def run_with_callbacks_and_testunit(result) #:nodoc: return if @method_name.to_s == "default_test" yield(Test::Unit::TestCase::STARTED, name) diff --git a/activesupport/lib/active_support/vendor.rb b/activesupport/lib/active_support/vendor.rb index cdbcedc75a..a02e42f791 100644 --- a/activesupport/lib/active_support/vendor.rb +++ b/activesupport/lib/active_support/vendor.rb @@ -20,7 +20,7 @@ rescue Gem::LoadError end begin - gem 'tzinfo', '~> 0.3.8' + gem 'tzinfo', '~> 0.3.9' rescue Gem::LoadError - $:.unshift "#{File.dirname(__FILE__)}/vendor/tzinfo-0.3.8" + $:.unshift "#{File.dirname(__FILE__)}/vendor/tzinfo-0.3.9" end
\ No newline at end of file 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 deleted file mode 100644 index 32fa4123f1..0000000000 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/offset_rationals.rb +++ /dev/null @@ -1,95 +0,0 @@ -#-- -# Copyright (c) 2006 Philip Ross -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -#++ - -module TZInfo - - # Provides a method for getting Rationals for a timezone offset in seconds. - # Pre-reduced rationals are returned for all the half-hour intervals between - # -14 and +14 hours to avoid having to call gcd at runtime. - module OffsetRationals #:nodoc: - @@rational_cache = { - -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)). - def rational_for_offset(offset) - @@rational_cache[offset] || Rational(offset, 86400) - end - module_function :rational_for_offset - end -end diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo.rb index c8bdbeec5d..c8bdbeec5d 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone.rb index 5eccbdf0db..5eccbdf0db 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone_info.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone_info.rb index f34fabc36a..a45d94554b 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone_info.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone_info.rb @@ -40,6 +40,8 @@ module TZInfo super(identifier) @offsets = {} @transitions = [] + @previous_offset = nil + @transitions_index = nil end # Defines a offset. The id uniquely identifies this offset within the diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Algiers.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Algiers.rb index 8c5f25577f..8c5f25577f 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Algiers.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Algiers.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Cairo.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Cairo.rb index 6e6daf3522..6e6daf3522 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Cairo.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Cairo.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Casablanca.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Casablanca.rb index 10d28e7613..dddf533f61 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Casablanca.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Casablanca.rb @@ -31,6 +31,8 @@ module TZInfo tz.transition 1978, 8, :o1, 271033200 tz.transition 1984, 3, :o3, 448243200 tz.transition 1985, 12, :o1, 504918000 + tz.transition 2008, 6, :o2, 1212278400 + tz.transition 2008, 9, :o1, 1222556400 end end end diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Harare.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Harare.rb index 070c95ae0f..070c95ae0f 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Harare.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Harare.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Johannesburg.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Johannesburg.rb index f0af0d8e33..f0af0d8e33 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Johannesburg.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Johannesburg.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Monrovia.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Monrovia.rb index 40e711fa44..40e711fa44 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Monrovia.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Monrovia.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Nairobi.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Nairobi.rb index 7b0a2f43be..7b0a2f43be 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Nairobi.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Nairobi.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Argentina/Buenos_Aires.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Argentina/Buenos_Aires.rb index 7536f7553c..7536f7553c 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Argentina/Buenos_Aires.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Argentina/Buenos_Aires.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Argentina/San_Juan.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Argentina/San_Juan.rb index a5413612ee..a5413612ee 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Argentina/San_Juan.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Argentina/San_Juan.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Bogota.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Bogota.rb index ef96435c6a..ef96435c6a 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Bogota.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Bogota.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Caracas.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Caracas.rb index 27392a540a..27392a540a 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Caracas.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Caracas.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Chicago.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Chicago.rb index 0996857cf0..0996857cf0 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Chicago.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Chicago.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Chihuahua.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Chihuahua.rb index 1710b57c79..1710b57c79 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Chihuahua.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Chihuahua.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Denver.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Denver.rb index 1c1efb5ff3..1c1efb5ff3 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Denver.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Denver.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Godthab.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Godthab.rb index 1e05518b0d..1e05518b0d 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Godthab.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Godthab.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Guatemala.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Guatemala.rb index a2bf73401c..a2bf73401c 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Guatemala.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Guatemala.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Halifax.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Halifax.rb index d25ae775b3..d25ae775b3 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Halifax.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Halifax.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Indiana/Indianapolis.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Indiana/Indianapolis.rb index f1430f6c24..f1430f6c24 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Indiana/Indianapolis.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Indiana/Indianapolis.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Juneau.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Juneau.rb index f646f3f54a..f646f3f54a 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Juneau.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Juneau.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/La_Paz.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/La_Paz.rb index 45c907899f..45c907899f 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/La_Paz.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/La_Paz.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Lima.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Lima.rb index af68ac29f7..af68ac29f7 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Lima.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Lima.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Los_Angeles.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Los_Angeles.rb index 16007fd675..16007fd675 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Los_Angeles.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Los_Angeles.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Mazatlan.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Mazatlan.rb index ba9e6efcf1..ba9e6efcf1 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Mazatlan.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Mazatlan.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Mexico_City.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Mexico_City.rb index 2347fce647..2347fce647 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Mexico_City.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Mexico_City.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Monterrey.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Monterrey.rb index 5816a9eab1..5816a9eab1 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Monterrey.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Monterrey.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/New_York.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/New_York.rb index 7d802bd2de..7d802bd2de 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/New_York.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/New_York.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Phoenix.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Phoenix.rb index b514e0c0f9..b514e0c0f9 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Phoenix.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Phoenix.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Regina.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Regina.rb index ebdb68814a..ebdb68814a 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Regina.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Regina.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Santiago.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Santiago.rb index 0287c9ebc4..0287c9ebc4 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Santiago.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Santiago.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/St_Johns.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/St_Johns.rb index e4a3599d35..e4a3599d35 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/St_Johns.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/St_Johns.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Tijuana.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Tijuana.rb index 423059da46..423059da46 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Tijuana.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Tijuana.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Almaty.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Almaty.rb index 9ee18970f1..9ee18970f1 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Almaty.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Almaty.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Baghdad.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Baghdad.rb index 774dca1587..774dca1587 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Baghdad.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Baghdad.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Baku.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Baku.rb index e86340ebfa..e86340ebfa 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Baku.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Baku.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Bangkok.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Bangkok.rb index 139194e5e5..139194e5e5 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Bangkok.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Bangkok.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Chongqing.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Chongqing.rb index 8c94b4ba86..8c94b4ba86 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Chongqing.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Chongqing.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Dhaka.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Dhaka.rb index ccd0265503..ccd0265503 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Dhaka.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Dhaka.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Hong_Kong.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Hong_Kong.rb index f1edd75ac8..f1edd75ac8 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Hong_Kong.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Hong_Kong.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Irkutsk.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Irkutsk.rb index 2d47d9580b..2d47d9580b 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Irkutsk.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Irkutsk.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Jakarta.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Jakarta.rb index cc58fa173b..cc58fa173b 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Jakarta.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Jakarta.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Jerusalem.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Jerusalem.rb index 9b737b899e..9b737b899e 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Jerusalem.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Jerusalem.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kabul.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kabul.rb index 669c09790a..669c09790a 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kabul.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kabul.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kamchatka.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kamchatka.rb index 2f1690b3a9..2f1690b3a9 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kamchatka.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kamchatka.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Karachi.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Karachi.rb index baa0d41d73..bd7656ef2f 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Karachi.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Karachi.rb @@ -21,6 +21,8 @@ module TZInfo tz.transition 1971, 3, :o4, 38775600 tz.transition 2002, 4, :o5, 1018119660 tz.transition 2002, 10, :o4, 1033840860 + tz.transition 2008, 5, :o5, 1212260400 + tz.transition 2008, 8, :o4, 1220205600 end end end diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Katmandu.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Katmandu.rb index 37dbea1f41..37dbea1f41 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Katmandu.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Katmandu.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kolkata.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kolkata.rb index 1b6ffbd59d..1b6ffbd59d 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kolkata.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kolkata.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Krasnoyarsk.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Krasnoyarsk.rb index d6c503c155..d6c503c155 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Krasnoyarsk.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Krasnoyarsk.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kuala_Lumpur.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kuala_Lumpur.rb index 77a0c206fa..77a0c206fa 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kuala_Lumpur.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kuala_Lumpur.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kuwait.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kuwait.rb index 5bd5283197..5bd5283197 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kuwait.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kuwait.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Magadan.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Magadan.rb index 302093693e..302093693e 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Magadan.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Magadan.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Muscat.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Muscat.rb index 604f651dfa..604f651dfa 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Muscat.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Muscat.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Novosibirsk.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Novosibirsk.rb index a4e7796e75..a4e7796e75 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Novosibirsk.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Novosibirsk.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Rangoon.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Rangoon.rb index 759b82d77a..759b82d77a 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Rangoon.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Rangoon.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Riyadh.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Riyadh.rb index 7add410620..7add410620 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Riyadh.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Riyadh.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Seoul.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Seoul.rb index 795d2a75df..795d2a75df 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Seoul.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Seoul.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Shanghai.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Shanghai.rb index 34b13d59ae..34b13d59ae 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Shanghai.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Shanghai.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Singapore.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Singapore.rb index b323a78f74..b323a78f74 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Singapore.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Singapore.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Taipei.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Taipei.rb index 3ba12108fb..3ba12108fb 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Taipei.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Taipei.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tashkent.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tashkent.rb index c205c7934d..c205c7934d 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tashkent.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tashkent.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tbilisi.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tbilisi.rb index 15792a5651..15792a5651 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tbilisi.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tbilisi.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tehran.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tehran.rb index d8df964a46..d8df964a46 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tehran.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tehran.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tokyo.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tokyo.rb index 51c9e16421..51c9e16421 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tokyo.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tokyo.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Ulaanbaatar.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Ulaanbaatar.rb index 2854f5c5fd..2854f5c5fd 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Ulaanbaatar.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Ulaanbaatar.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Urumqi.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Urumqi.rb index d793ff1341..d793ff1341 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Urumqi.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Urumqi.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Vladivostok.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Vladivostok.rb index bd9e3d60ec..bd9e3d60ec 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Vladivostok.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Vladivostok.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Yakutsk.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Yakutsk.rb index 56435a788f..56435a788f 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Yakutsk.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Yakutsk.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Yekaterinburg.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Yekaterinburg.rb index 8ef8df4a41..8ef8df4a41 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Yekaterinburg.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Yekaterinburg.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Yerevan.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Yerevan.rb index e7f160861f..e7f160861f 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Yerevan.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Yerevan.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Atlantic/Azores.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Atlantic/Azores.rb index 1bd16a75ac..1bd16a75ac 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Atlantic/Azores.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Atlantic/Azores.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Atlantic/Cape_Verde.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Atlantic/Cape_Verde.rb index 61c8c15043..61c8c15043 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Atlantic/Cape_Verde.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Atlantic/Cape_Verde.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Atlantic/South_Georgia.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Atlantic/South_Georgia.rb index 6a4cbafb9f..6a4cbafb9f 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Atlantic/South_Georgia.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Atlantic/South_Georgia.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Adelaide.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Adelaide.rb index c5d561cc1e..c5d561cc1e 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Adelaide.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Adelaide.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Brisbane.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Brisbane.rb index dd85ddae94..dd85ddae94 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Brisbane.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Brisbane.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Darwin.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Darwin.rb index 17de88124d..17de88124d 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Darwin.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Darwin.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Hobart.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Hobart.rb index 11384b9840..11384b9840 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Hobart.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Hobart.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Melbourne.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Melbourne.rb index c1304488ea..c1304488ea 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Melbourne.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Melbourne.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Perth.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Perth.rb index d9e66f14a8..d9e66f14a8 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Perth.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Perth.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Sydney.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Sydney.rb index 9062bd7c3c..9062bd7c3c 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Sydney.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Sydney.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Etc/UTC.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Etc/UTC.rb index 28b2c6a04c..28b2c6a04c 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Etc/UTC.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Etc/UTC.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Amsterdam.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Amsterdam.rb index 2d0c95c4bc..2d0c95c4bc 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Amsterdam.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Amsterdam.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Athens.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Athens.rb index 4e21e535ca..4e21e535ca 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Athens.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Athens.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Belgrade.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Belgrade.rb index 4dbd893d75..4dbd893d75 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Belgrade.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Belgrade.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Berlin.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Berlin.rb index de2e4d951c..de2e4d951c 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Berlin.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Berlin.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Bratislava.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Bratislava.rb index 7a731a0b6a..7a731a0b6a 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Bratislava.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Bratislava.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Brussels.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Brussels.rb index 6b0a242944..6b0a242944 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Brussels.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Brussels.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Bucharest.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Bucharest.rb index 521c3c932e..521c3c932e 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Bucharest.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Bucharest.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Budapest.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Budapest.rb index 1f3a9738b7..1f3a9738b7 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Budapest.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Budapest.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Copenhagen.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Copenhagen.rb index 47cbaf14a7..47cbaf14a7 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Copenhagen.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Copenhagen.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Dublin.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Dublin.rb index 0560bb5436..0560bb5436 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Dublin.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Dublin.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Helsinki.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Helsinki.rb index 13a806bcc7..13a806bcc7 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Helsinki.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Helsinki.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Istanbul.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Istanbul.rb index 8306c47536..8306c47536 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Istanbul.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Istanbul.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Kiev.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Kiev.rb index 513d3308be..513d3308be 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Kiev.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Kiev.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Lisbon.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Lisbon.rb index 1c6d2a3d30..1c6d2a3d30 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Lisbon.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Lisbon.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Ljubljana.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Ljubljana.rb index a9828e6ef8..a9828e6ef8 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Ljubljana.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Ljubljana.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/London.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/London.rb index 64ce41e900..64ce41e900 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/London.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/London.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Madrid.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Madrid.rb index 1fb568239a..1fb568239a 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Madrid.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Madrid.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Minsk.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Minsk.rb index fa15816cc8..fa15816cc8 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Minsk.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Minsk.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Moscow.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Moscow.rb index ef269b675b..ef269b675b 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Moscow.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Moscow.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Paris.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Paris.rb index e3236c0ba1..e3236c0ba1 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Paris.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Paris.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Prague.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Prague.rb index bcabee96c1..bcabee96c1 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Prague.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Prague.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Riga.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Riga.rb index 784837f758..784837f758 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Riga.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Riga.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Rome.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Rome.rb index aa7b43d9d2..aa7b43d9d2 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Rome.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Rome.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Sarajevo.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Sarajevo.rb index 068c5fe6ad..068c5fe6ad 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Sarajevo.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Sarajevo.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Skopje.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Skopje.rb index 10b71f285e..10b71f285e 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Skopje.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Skopje.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Sofia.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Sofia.rb index 38a70eceb9..38a70eceb9 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Sofia.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Sofia.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Stockholm.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Stockholm.rb index 43db70fa61..43db70fa61 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Stockholm.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Stockholm.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Tallinn.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Tallinn.rb index de5a8569f3..de5a8569f3 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Tallinn.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Tallinn.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Vienna.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Vienna.rb index 990aabab66..990aabab66 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Vienna.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Vienna.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Vilnius.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Vilnius.rb index d89d095a75..d89d095a75 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Vilnius.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Vilnius.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Warsaw.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Warsaw.rb index 7fa51c2691..7fa51c2691 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Warsaw.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Warsaw.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Zagreb.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Zagreb.rb index ecdd903d28..ecdd903d28 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Zagreb.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Zagreb.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Auckland.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Auckland.rb index a524fd6b6b..a524fd6b6b 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Auckland.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Auckland.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Fiji.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Fiji.rb index 5fe9bbd9a6..5fe9bbd9a6 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Fiji.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Fiji.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Guam.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Guam.rb index d4c1a0a682..d4c1a0a682 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Guam.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Guam.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Honolulu.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Honolulu.rb index 204b226537..204b226537 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Honolulu.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Honolulu.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Majuro.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Majuro.rb index 32adad92c1..32adad92c1 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Majuro.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Majuro.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Midway.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Midway.rb index 97784fcc10..97784fcc10 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Midway.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Midway.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Noumea.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Noumea.rb index 70173db8ab..70173db8ab 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Noumea.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Noumea.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Pago_Pago.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Pago_Pago.rb index c8fcd7d527..c8fcd7d527 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Pago_Pago.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Pago_Pago.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Port_Moresby.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Port_Moresby.rb index f06cf6d54f..f06cf6d54f 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Port_Moresby.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Port_Moresby.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Tongatapu.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Tongatapu.rb index 7578d92f38..7578d92f38 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Tongatapu.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Tongatapu.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/info_timezone.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/info_timezone.rb index 001303c594..001303c594 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/info_timezone.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/info_timezone.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/linked_timezone.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/linked_timezone.rb index f8ec4fca87..f8ec4fca87 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/linked_timezone.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/linked_timezone.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/linked_timezone_info.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/linked_timezone_info.rb index 8197ff3e81..8197ff3e81 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/linked_timezone_info.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/linked_timezone_info.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/offset_rationals.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/offset_rationals.rb new file mode 100644 index 0000000000..c79eedb7ef --- /dev/null +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/offset_rationals.rb @@ -0,0 +1,95 @@ +#-- +# Copyright (c) 2006 Philip Ross +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +#++ + +module TZInfo + + # Provides a method for getting Rationals for a timezone offset in seconds. + # Pre-reduced rationals are returned for all the half-hour intervals between + # -14 and +14 hours to avoid having to call gcd at runtime. + module OffsetRationals #:nodoc: + @@rational_cache = { + -50400 => Rational.send(:new!, -7,12), + -48600 => Rational.send(:new!, -9,16), + -46800 => Rational.send(:new!, -13,24), + -45000 => Rational.send(:new!, -25,48), + -43200 => Rational.send(:new!, -1,2), + -41400 => Rational.send(:new!, -23,48), + -39600 => Rational.send(:new!, -11,24), + -37800 => Rational.send(:new!, -7,16), + -36000 => Rational.send(:new!, -5,12), + -34200 => Rational.send(:new!, -19,48), + -32400 => Rational.send(:new!, -3,8), + -30600 => Rational.send(:new!, -17,48), + -28800 => Rational.send(:new!, -1,3), + -27000 => Rational.send(:new!, -5,16), + -25200 => Rational.send(:new!, -7,24), + -23400 => Rational.send(:new!, -13,48), + -21600 => Rational.send(:new!, -1,4), + -19800 => Rational.send(:new!, -11,48), + -18000 => Rational.send(:new!, -5,24), + -16200 => Rational.send(:new!, -3,16), + -14400 => Rational.send(:new!, -1,6), + -12600 => Rational.send(:new!, -7,48), + -10800 => Rational.send(:new!, -1,8), + -9000 => Rational.send(:new!, -5,48), + -7200 => Rational.send(:new!, -1,12), + -5400 => Rational.send(:new!, -1,16), + -3600 => Rational.send(:new!, -1,24), + -1800 => Rational.send(:new!, -1,48), + 0 => Rational.send(:new!, 0,1), + 1800 => Rational.send(:new!, 1,48), + 3600 => Rational.send(:new!, 1,24), + 5400 => Rational.send(:new!, 1,16), + 7200 => Rational.send(:new!, 1,12), + 9000 => Rational.send(:new!, 5,48), + 10800 => Rational.send(:new!, 1,8), + 12600 => Rational.send(:new!, 7,48), + 14400 => Rational.send(:new!, 1,6), + 16200 => Rational.send(:new!, 3,16), + 18000 => Rational.send(:new!, 5,24), + 19800 => Rational.send(:new!, 11,48), + 21600 => Rational.send(:new!, 1,4), + 23400 => Rational.send(:new!, 13,48), + 25200 => Rational.send(:new!, 7,24), + 27000 => Rational.send(:new!, 5,16), + 28800 => Rational.send(:new!, 1,3), + 30600 => Rational.send(:new!, 17,48), + 32400 => Rational.send(:new!, 3,8), + 34200 => Rational.send(:new!, 19,48), + 36000 => Rational.send(:new!, 5,12), + 37800 => Rational.send(:new!, 7,16), + 39600 => Rational.send(:new!, 11,24), + 41400 => Rational.send(:new!, 23,48), + 43200 => Rational.send(:new!, 1,2), + 45000 => Rational.send(:new!, 25,48), + 46800 => Rational.send(:new!, 13,24), + 48600 => Rational.send(:new!, 9,16), + 50400 => Rational.send(:new!, 7,12)} + + # Returns a Rational expressing the fraction of a day that offset in + # seconds represents (i.e. equivalent to Rational(offset, 86400)). + def rational_for_offset(offset) + @@rational_cache[offset] || Rational(offset, 86400) + end + module_function :rational_for_offset + end +end diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/time_or_datetime.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/time_or_datetime.rb index 264517f3ee..264517f3ee 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/time_or_datetime.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/time_or_datetime.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone.rb index 04f2f2f0a5..f87fb6fb70 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone.rb @@ -371,8 +371,8 @@ module TZInfo # type as utc. Any timezone information in utc is ignored (it is treated as # a UTC time). def utc_to_local(utc) - TimeOrDateTime.wrap(utc) {|utc| - period_for_utc(utc).to_local(utc) + TimeOrDateTime.wrap(utc) {|wrapped| + period_for_utc(wrapped).to_local(wrapped) } end @@ -410,14 +410,14 @@ module TZInfo # single period to use to convert the time or return nil or an empty array # to cause an AmbiguousTime exception to be raised. def local_to_utc(local, dst = nil) - TimeOrDateTime.wrap(local) {|local| + TimeOrDateTime.wrap(local) {|wrapped| if block_given? - period = period_for_local(local, dst) {|periods| yield periods } + period = period_for_local(wrapped, dst) {|periods| yield periods } else - period = period_for_local(local, dst) + period = period_for_local(wrapped, dst) end - period.to_utc(local) + period.to_utc(wrapped) } end diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_definition.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_definition.rb index 39ca8bfa53..39ca8bfa53 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_definition.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_definition.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_info.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_info.rb index 68e38c35fb..68e38c35fb 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_info.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_info.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_offset_info.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_offset_info.rb index 913c4164af..6a0bbca46f 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_offset_info.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_offset_info.rb @@ -56,15 +56,15 @@ module TZInfo # Converts a UTC DateTime to local time based on the offset of this period. def to_local(utc) - TimeOrDateTime.wrap(utc) {|utc| - utc + @utc_total_offset + TimeOrDateTime.wrap(utc) {|wrapped| + wrapped + @utc_total_offset } end # Converts a local DateTime to UTC based on the offset of this period. def to_utc(local) - TimeOrDateTime.wrap(local) {|local| - local - @utc_total_offset + TimeOrDateTime.wrap(local) {|wrapped| + wrapped - @utc_total_offset } end diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_period.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_period.rb index 00888fcfdc..00888fcfdc 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_period.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_period.rb diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_transition_info.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_transition_info.rb index 6ae1b7df97..3fecb24f0d 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_transition_info.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_transition_info.rb @@ -48,7 +48,7 @@ module TZInfo # seconds since the epoch. If denominator is specified numerator_or_time # and denominator are used to create a DateTime as follows: # - # DateTime.new!(Rational.new!(numerator_or_time, denominator), 0, Date::ITALY) + # DateTime.new!(Rational.send(:new!, numerator_or_time, denominator), 0, Date::ITALY) # # For performance reasons, the numerator and denominator must be specified # in their lowest form. @@ -70,7 +70,7 @@ module TZInfo unless @denominator @at = TimeOrDateTime.new(@numerator_or_time) else - r = Rational.new!(@numerator_or_time, @denominator) + r = Rational.send(:new!, @numerator_or_time, @denominator) # Ruby 1.8.6 introduced new! and deprecated new0. # Ruby 1.9.0 removed new0. diff --git a/activesupport/test/core_ext/array_ext_test.rb b/activesupport/test/core_ext/array_ext_test.rb index 73fbeb8b6b..7563be44f8 100644 --- a/activesupport/test/core_ext/array_ext_test.rb +++ b/activesupport/test/core_ext/array_ext_test.rb @@ -13,6 +13,20 @@ class ArrayExtAccessTests < Test::Unit::TestCase assert_equal %w( a b c ), %w( a b c d ).to(2) assert_equal %w( a b c d ), %w( a b c d ).to(10) end + + def test_second_through_tenth + array = (1..10).to_a + + assert_equal array[1], array.second + assert_equal array[2], array.third + assert_equal array[3], array.fourth + assert_equal array[4], array.fifth + assert_equal array[5], array.sixth + assert_equal array[6], array.seventh + assert_equal array[7], array.eighth + assert_equal array[8], array.ninth + assert_equal array[9], array.tenth + end end class ArrayExtToParamTests < Test::Unit::TestCase diff --git a/activesupport/test/core_ext/blank_test.rb b/activesupport/test/core_ext/blank_test.rb index 061d940383..00fea74639 100644 --- a/activesupport/test/core_ext/blank_test.rb +++ b/activesupport/test/core_ext/blank_test.rb @@ -16,4 +16,9 @@ class BlankTest < Test::Unit::TestCase BLANK.each { |v| assert v.blank?, "#{v.inspect} should be blank" } NOT.each { |v| assert !v.blank?, "#{v.inspect} should not be blank" } end + + def test_present + BLANK.each { |v| assert !v.present?, "#{v.inspect} should not be present" } + NOT.each { |v| assert v.present?, "#{v.inspect} should be present" } + end end diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb index f5facd54ad..fb9b9b8916 100644 --- a/activesupport/test/core_ext/enumerable_test.rb +++ b/activesupport/test/core_ext/enumerable_test.rb @@ -63,4 +63,10 @@ class EnumerableTests < Test::Unit::TestCase assert_equal({ 5 => payments[0], 15 => payments[1], 10 => payments[2] }, payments.index_by { |p| p.price }) end + + def test_several + assert ![].many? + assert ![ 1 ].many? + assert [ 1, 2 ].many? + end end diff --git a/activesupport/test/test_test.rb b/activesupport/test/test_test.rb index 1e75e18602..26a45af255 100644 --- a/activesupport/test/test_test.rb +++ b/activesupport/test/test_test.rb @@ -84,6 +84,12 @@ class SetupAndTeardownTest < Test::Unit::TestCase assert_equal [:foo, :sentinel, :foo], self.class.teardown_callback_chain.map(&:method) end + def setup + end + + def teardown + end + protected def reset_callback_record @called_back = [] diff --git a/railties/CHANGELOG b/railties/CHANGELOG index 93f4f8fa28..27d4313862 100644 --- a/railties/CHANGELOG +++ b/railties/CHANGELOG @@ -6,6 +6,8 @@ * Plugins check for the gem init path (rails/init.rb) before the standard plugin init path (init.rb) [Jacek Becela] +* Changed all generated tests to use the test/do declaration style [DHH] + * Wrapped Rails.env in StringInquirer so you can do Rails.env.development? [DHH] * Fixed that RailsInfoController wasn't considering all requests local in development mode (Edgard Castro) [#310 state:resolved] diff --git a/railties/Rakefile b/railties/Rakefile index a1d1095c37..78fe8e6662 100644 --- a/railties/Rakefile +++ b/railties/Rakefile @@ -267,6 +267,7 @@ Rake::RDocTask.new { |rdoc| rdoc.template = "#{ENV['template']}.rb" if ENV['template'] rdoc.rdoc_files.include('README', 'CHANGELOG') rdoc.rdoc_files.include('lib/*.rb') + rdoc.rdoc_files.include('lib/rails/*.rb') rdoc.rdoc_files.include('lib/rails_generator/*.rb') rdoc.rdoc_files.include('lib/commands/**/*.rb') } @@ -331,10 +332,15 @@ end # Publishing ------------------------------------------------------- -desc "Publish the API documentation" +desc "Publish the rails gem" task :pgem => [:gem] do - Rake::SshFilePublisher.new("davidhh@wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload - `ssh davidhh@wrath.rubyonrails.org './gemupdate.sh'` + Rake::SshFilePublisher.new("wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload + `ssh wrath.rubyonrails.org './gemupdate.sh'` +end + +desc "Publish the API documentation" +task :pdoc => :rdoc do + # railties API isn't separately published end desc "Publish the release files to RubyForge." diff --git a/railties/configs/initializers/inflections.rb b/railties/configs/initializers/inflections.rb index 09158b865c..d531b8bb82 100644 --- a/railties/configs/initializers/inflections.rb +++ b/railties/configs/initializers/inflections.rb @@ -2,7 +2,7 @@ # Add new inflection rules using the following format # (all these examples are active by default): -# Inflector.inflections do |inflect| +# ActiveSupport::Inflector.inflections do |inflect| # inflect.plural /^(ox)$/i, '\1en' # inflect.singular /^(ox)en/i, '\1' # inflect.irregular 'person', 'people' diff --git a/railties/helpers/performance_test.rb b/railties/helpers/performance_test.rb new file mode 100644 index 0000000000..7c89816570 --- /dev/null +++ b/railties/helpers/performance_test.rb @@ -0,0 +1,8 @@ +require 'performance/test_helper' + +# Profiling results for each test method are written to tmp/performance. +class BrowsingTest < ActionController::PerformanceTest + def test_homepage + get '/' + end +end diff --git a/railties/helpers/performance_test_helper.rb b/railties/helpers/performance_test_helper.rb new file mode 100644 index 0000000000..3c4c7fb740 --- /dev/null +++ b/railties/helpers/performance_test_helper.rb @@ -0,0 +1,6 @@ +require 'test_helper' +require 'action_controller/performance_test' + +ActionController::Base.perform_caching = true +ActiveSupport::Dependencies.mechanism = :require +Rails.logger.level = ActiveSupport::BufferedLogger::INFO diff --git a/railties/lib/rails_generator/generators/applications/app/app_generator.rb b/railties/lib/rails_generator/generators/applications/app/app_generator.rb index 2f2dd82682..80e8eabfd3 100644 --- a/railties/lib/rails_generator/generators/applications/app/app_generator.rb +++ b/railties/lib/rails_generator/generators/applications/app/app_generator.rb @@ -51,6 +51,8 @@ class AppGenerator < Rails::Generator::Base m.template "helpers/application.rb", "app/controllers/application.rb", :assigns => { :app_name => @app_name, :app_secret => md5.hexdigest } m.template "helpers/application_helper.rb", "app/helpers/application_helper.rb" m.template "helpers/test_helper.rb", "test/test_helper.rb" + m.template "helpers/performance_test_helper.rb", "test/performance/test_helper.rb" + m.template "helpers/performance_test.rb", "test/performance/browsing_test.rb" # database.yml and routes.rb m.template "configs/databases/#{options[:db]}.yml", "config/database.yml", :assigns => { @@ -155,6 +157,7 @@ class AppGenerator < Rails::Generator::Base test/fixtures test/functional test/integration + test/performance test/unit vendor vendor/plugins diff --git a/railties/lib/rails_generator/generators/components/controller/templates/functional_test.rb b/railties/lib/rails_generator/generators/components/controller/templates/functional_test.rb index 38e0ae7123..62fa5d86fd 100644 --- a/railties/lib/rails_generator/generators/components/controller/templates/functional_test.rb +++ b/railties/lib/rails_generator/generators/components/controller/templates/functional_test.rb @@ -2,7 +2,7 @@ require 'test_helper' class <%= class_name %>ControllerTest < ActionController::TestCase # Replace this with your real tests. - def test_truth + test "the truth" do assert true end end diff --git a/railties/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb b/railties/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb index 149b987d81..2c57158b1c 100644 --- a/railties/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb +++ b/railties/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb @@ -1,10 +1,10 @@ require 'test_helper' class <%= class_name %>Test < ActionController::IntegrationTest - # fixtures :your, :models + fixtures :all # Replace this with your real tests. - def test_truth + test "the truth" do assert true end end diff --git a/railties/lib/rails_generator/generators/components/mailer/templates/unit_test.rb b/railties/lib/rails_generator/generators/components/mailer/templates/unit_test.rb index 0b4b2ec60a..1b7bcfef08 100644 --- a/railties/lib/rails_generator/generators/components/mailer/templates/unit_test.rb +++ b/railties/lib/rails_generator/generators/components/mailer/templates/unit_test.rb @@ -3,7 +3,7 @@ require 'test_helper' class <%= class_name %>Test < ActionMailer::TestCase tests <%= class_name %> <% for action in actions -%> - def test_<%= action %> + test "<%= action %>" do @expected.subject = '<%= class_name %>#<%= action %>' @expected.body = read_fixture('<%= action %>') @expected.date = Time.now @@ -14,7 +14,7 @@ class <%= class_name %>Test < ActionMailer::TestCase <% end -%> <% if actions.blank? -%> # replace this with your real tests - def test_truth + test "the truth" do assert true end <% end -%> diff --git a/railties/lib/rails_generator/generators/components/model/templates/unit_test.rb b/railties/lib/rails_generator/generators/components/model/templates/unit_test.rb index 96bd34adab..3e0bc29d3a 100644 --- a/railties/lib/rails_generator/generators/components/model/templates/unit_test.rb +++ b/railties/lib/rails_generator/generators/components/model/templates/unit_test.rb @@ -2,7 +2,7 @@ require 'test_helper' class <%= class_name %>Test < ActiveSupport::TestCase # Replace this with your real tests. - def test_truth + test "the truth" do assert true end end diff --git a/railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb b/railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb index 1faf8ed9ac..cae38e9a2a 100644 --- a/railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb +++ b/railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb @@ -2,7 +2,7 @@ require 'test_helper' class <%= class_name %>ObserverTest < Test::Unit::TestCase # Replace this with your real tests. - def test_truth + test "the truth" do assert true end end diff --git a/railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb b/railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb index 9028b84b7d..6ede6ef1d2 100644 --- a/railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb +++ b/railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb @@ -2,7 +2,7 @@ require 'test/unit' class <%= class_name %>Test < Test::Unit::TestCase # Replace this with your real tests. - def test_this_plugin - flunk + test "the truth" do + assert true end end diff --git a/railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb b/railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb index fbb69fcca7..b1bb1dacbf 100644 --- a/railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb +++ b/railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb @@ -2,7 +2,7 @@ require 'test_helper' class <%= controller_class_name %>ControllerTest < ActionController::TestCase # Replace this with your real tests. - def test_truth + test "the truth" do assert true end end diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb b/railties/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb index 3b430a2061..2d9d635944 100644 --- a/railties/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb +++ b/railties/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb @@ -1,18 +1,18 @@ require 'test_helper' class <%= controller_class_name %>ControllerTest < ActionController::TestCase - def test_should_get_index + test "should get index" do get :index assert_response :success assert_not_nil assigns(:<%= table_name %>) end - def test_should_get_new + test "should get new" do get :new assert_response :success end - def test_should_create_<%= file_name %> + test "should create <%= file_name %>" do assert_difference('<%= class_name %>.count') do post :create, :<%= file_name %> => { } end @@ -20,22 +20,22 @@ class <%= controller_class_name %>ControllerTest < ActionController::TestCase assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>)) end - def test_should_show_<%= file_name %> + test "should show <%= file_name %>" do get :show, :id => <%= table_name %>(:one).id assert_response :success end - def test_should_get_edit + test "should get edit" do get :edit, :id => <%= table_name %>(:one).id assert_response :success end - def test_should_update_<%= file_name %> + test "should update <%= file_name %>" do put :update, :id => <%= table_name %>(:one).id, :<%= file_name %> => { } assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>)) end - def test_should_destroy_<%= file_name %> + test "should destroy <%= file_name %>" do assert_difference('<%= class_name %>.count', -1) do delete :destroy, :id => <%= table_name %>(:one).id end diff --git a/railties/lib/tasks/databases.rake b/railties/lib/tasks/databases.rake index 8077d0a401..75fba8b45a 100644 --- a/railties/lib/tasks/databases.rake +++ b/railties/lib/tasks/databases.rake @@ -264,13 +264,15 @@ namespace :db do end namespace :test do - desc "Recreate the test database from the current environment's database schema" - task :clone => %w(db:schema:dump db:test:purge) do + desc "Recreate the test database from the current schema.rb" + task :load => 'db:test:purge' do ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test']) ActiveRecord::Schema.verbose = false Rake::Task["db:schema:load"].invoke end + desc "Recreate the test database from the current environment's database schema" + task :clone => %w(db:schema:dump db:test:load) desc "Recreate the test databases from the development structure" task :clone_structure => [ "db:structure:dump", "db:test:purge" ] do @@ -337,10 +339,10 @@ namespace :db do end end - desc 'Prepare the test database and load the schema' - task :prepare => %w(environment db:abort_if_pending_migrations) do + desc 'Check for pending migrations and load the test schema' + task :prepare => 'db:abort_if_pending_migrations' do if defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank? - Rake::Task[{ :sql => "db:test:clone_structure", :ruby => "db:test:clone" }[ActiveRecord::Base.schema_format]].invoke + Rake::Task[{ :sql => "db:test:clone_structure", :ruby => "db:test:load" }[ActiveRecord::Base.schema_format]].invoke end end end diff --git a/railties/lib/tasks/testing.rake b/railties/lib/tasks/testing.rake index cc2376cbb3..c8ba6eed94 100644 --- a/railties/lib/tasks/testing.rake +++ b/railties/lib/tasks/testing.rake @@ -103,6 +103,21 @@ namespace :test do end Rake::Task['test:integration'].comment = "Run the integration tests in test/integration" + Rake::TestTask.new(:benchmark => 'db:test:prepare') do |t| + t.libs << 'test' + t.pattern = 'test/performance/**/*_test.rb' + t.verbose = true + t.options = '-- --benchmark' + end + Rake::Task['test:benchmark'].comment = 'Benchmark the performance tests' + + Rake::TestTask.new(:profile => 'db:test:prepare') do |t| + t.libs << 'test' + t.pattern = 'test/performance/**/*_test.rb' + t.verbose = true + end + Rake::Task['test:profile'].comment = 'Profile the performance tests' + Rake::TestTask.new(:plugins => :environment) do |t| t.libs << "test" diff --git a/railties/lib/test_help.rb b/railties/lib/test_help.rb index 22ce9ab609..3cc61d7932 100644 --- a/railties/lib/test_help.rb +++ b/railties/lib/test_help.rb @@ -8,7 +8,6 @@ require 'test/unit' require 'active_support/test_case' require 'active_record/fixtures' require 'action_controller/test_case' -require 'action_controller/test_process' require 'action_controller/integration' require 'action_mailer/test_case' if defined?(ActionMailer) @@ -25,4 +24,4 @@ begin Debugger.settings[:autoeval] = true if Debugger.respond_to?(:settings) rescue LoadError # ruby-debug wasn't available so neither can the debugging be -end
\ No newline at end of file +end diff --git a/railties/lib/webrick_server.rb b/railties/lib/webrick_server.rb index ad4ca926ba..2f60151b22 100644 --- a/railties/lib/webrick_server.rb +++ b/railties/lib/webrick_server.rb @@ -43,8 +43,6 @@ end # can change this behavior by setting ActionController::Base.allow_concurrency # to true. class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet - REQUEST_MUTEX = Mutex.new - # Start the WEBrick server with the given options, mounting the # DispatchServlet at <tt>/</tt>. def self.dispatch(options = {}) @@ -73,15 +71,8 @@ class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet def service(req, res) #:nodoc: unless handle_file(req, res) - begin - REQUEST_MUTEX.lock unless ActionController::Base.allow_concurrency - unless handle_dispatch(req, res) - raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found." - end - ensure - unless ActionController::Base.allow_concurrency - REQUEST_MUTEX.unlock if REQUEST_MUTEX.locked? - end + unless handle_dispatch(req, res) + raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found." end end end |