From c2f9c42719b248bec93801d69791351bdf97ecd0 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 9 Aug 2009 11:02:34 -0700 Subject: Fix that RedCloth shouldn't be required to run tests --- actionpack/test/template/text_helper_test.rb | 30 +++++++++++++++++----------- 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb index b7823b9394..08143ba680 100644 --- a/actionpack/test/template/text_helper_test.rb +++ b/actionpack/test/template/text_helper_test.rb @@ -1,6 +1,10 @@ require 'abstract_unit' require 'testing_sandbox' -require 'redcloth' +begin + require 'redcloth' +rescue LoadError + $stderr.puts "Skipping textilize tests. `gem install RedCloth` to enable." +end class TextHelperTest < ActionView::TestCase tests ActionView::Helpers::TextHelper @@ -530,19 +534,21 @@ class TextHelperTest < ActionView::TestCase assert_equal(%w{Specialized Fuji Giant}, @cycles) end - def test_textilize - assert_equal("

This is Textile! Rejoice!

", textilize("*This is Textile!* Rejoice!")) - end + if defined? RedCloth + def test_textilize + assert_equal("

This is Textile! Rejoice!

", textilize("*This is Textile!* Rejoice!")) + end - def test_textilize_with_blank - assert_equal("", textilize("")) - end + def test_textilize_with_blank + assert_equal("", textilize("")) + end - def test_textilize_with_options - assert_equal("

This is worded <strong>strongly</strong>

", textilize("This is worded strongly", :filter_html)) - end + def test_textilize_with_options + assert_equal("

This is worded <strong>strongly</strong>

", textilize("This is worded strongly", :filter_html)) + end - def test_textilize_with_hard_breaks - assert_equal("

This is one scary world.
\n True.

", textilize("This is one scary world.\n True.")) + def test_textilize_with_hard_breaks + assert_equal("

This is one scary world.
\n True.

", textilize("This is one scary world.\n True.")) + end end end -- cgit v1.2.3 From e1b73b975264c622f692a46eec060ff35a588d96 Mon Sep 17 00:00:00 2001 From: Bence Nagy Date: Sat, 27 Dec 2008 23:28:37 +0100 Subject: path_names could be used to customize collection actions too Signed-off-by: Jeremy Kemper --- actionpack/lib/action_controller/routing/resources.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/routing/resources.rb b/actionpack/lib/action_controller/routing/resources.rb index 2dee0a3d87..c1ebd46b48 100644 --- a/actionpack/lib/action_controller/routing/resources.rb +++ b/actionpack/lib/action_controller/routing/resources.rb @@ -589,7 +589,10 @@ module ActionController resource.collection_methods.each do |method, actions| actions.each do |action| [method].flatten.each do |m| - map_resource_routes(map, resource, action, "#{resource.path}#{resource.action_separator}#{action}", "#{action}_#{resource.name_prefix}#{resource.plural}", m) + action_path = resource.options[:path_names][action] if resource.options[:path_names].is_a?(Hash) + action_path ||= action + + map_resource_routes(map, resource, action, "#{resource.path}#{resource.action_separator}#{action_path}", "#{action}_#{resource.name_prefix}#{resource.plural}", m) end end end -- cgit v1.2.3 From 202b091373ed4d6c78adc7af5e89a359ff0fff2d Mon Sep 17 00:00:00 2001 From: Hugo Peixoto Date: Sun, 9 Aug 2009 07:28:29 +0100 Subject: Added both the documentation and a test case for the collection path name customization feature. [#1218 state:committed] Signed-off-by: Jeremy Kemper --- .../lib/action_controller/routing/resources.rb | 5 ++- actionpack/test/controller/resources_test.rb | 44 ++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/routing/resources.rb b/actionpack/lib/action_controller/routing/resources.rb index c1ebd46b48..7fd3ffd3f1 100644 --- a/actionpack/lib/action_controller/routing/resources.rb +++ b/actionpack/lib/action_controller/routing/resources.rb @@ -320,9 +320,10 @@ module ActionController # notes.resources :attachments # end # - # * :path_names - Specify different names for the 'new' and 'edit' actions. For example: + # * :path_names - Specify different path names for the actions. For example: # # new_products_path == '/productos/nuevo' - # map.resources :products, :as => 'productos', :path_names => { :new => 'nuevo', :edit => 'editar' } + # # bids_product_path(1) == '/productos/1/licitacoes' + # map.resources :products, :as => 'productos', :member => { :bids => :get }, :path_names => { :new => 'nuevo', :bids => 'licitacoes' } # # You can also set default action names from an environment, like this: # config.action_controller.resources_path_names = { :new => 'nuevo', :edit => 'editar' } diff --git a/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb index 30ab110ef7..0b639e363d 100644 --- a/actionpack/test/controller/resources_test.rb +++ b/actionpack/test/controller/resources_test.rb @@ -76,6 +76,50 @@ class ResourcesTest < ActionController::TestCase end end + def test_override_paths_for_member_and_collection_methods + collection_methods = { 'rss' => :get, 'reorder' => :post, 'csv' => :post } + member_methods = { 'rss' => :get, :atom => :get, :upload => :post, :fix => :post } + path_names = {:new => 'nuevo', 'rss' => 'canal', :fix => 'corrigir' } + + with_restful_routing :messages, + :collection => collection_methods, + :member => member_methods, + :path_names => path_names do + + assert_restful_routes_for :messages, + :collection => collection_methods, + :member => member_methods, + :path_names => path_names do |options| + member_methods.each do |action, method| + assert_recognizes(options.merge(:action => action.to_s, :id => '1'), + :path => "/messages/1/#{path_names[action] || action}", + :method => method) + end + + collection_methods.each do |action, method| + assert_recognizes(options.merge(:action => action), + :path => "/messages/#{path_names[action] || action}", + :method => method) + end + end + + assert_restful_named_routes_for :messages, + :collection => collection_methods, + :member => member_methods, + :path_names => path_names do |options| + + collection_methods.keys.each do |action| + assert_named_route "/messages/#{path_names[action] || action}", "#{action}_messages_path", :action => action + end + + member_methods.keys.each do |action| + assert_named_route "/messages/1/#{path_names[action] || action}", "#{action}_message_path", :action => action, :id => "1" + end + + end + end + end + def test_override_paths_for_default_restful_actions resource = ActionController::Resources::Resource.new(:messages, :path_names => {:new => 'nuevo', :edit => 'editar'}) -- cgit v1.2.3 From 920ef4e6f3832ea1d3297e2e7e5f0f775dab69a8 Mon Sep 17 00:00:00 2001 From: Matt Duncan Date: Sat, 8 Aug 2009 11:50:17 -0400 Subject: Fixed to_label_tag to accept id attribute without changing for attribute [#2660 status:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_view/helpers/form_helper.rb | 1 + actionpack/test/template/form_helper_test.rb | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 72f162cb20..81029102b1 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -738,6 +738,7 @@ module ActionView options = options.stringify_keys tag_value = options.delete("value") name_and_id = options.dup + name_and_id["id"] = name_and_id["for"] add_default_name_and_id_for_value(tag_value, name_and_id) options.delete("index") options["for"] ||= name_and_id["id"] diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 2b1d80b1bf..8fd018f86d 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -157,6 +157,22 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal('', label(:post, :title, nil, "for" => "my_for")) end + def test_label_with_id_attribute_as_symbol + assert_dom_equal('', label(:post, :title, nil, :id => "my_id")) + end + + def test_label_with_id_attribute_as_string + assert_dom_equal('', label(:post, :title, nil, "id" => "my_id")) + end + + def test_label_with_for_and_id_attributes_as_symbol + assert_dom_equal('', label(:post, :title, nil, :for => "my_for", :id => "my_id")) + end + + def test_label_with_for_and_id_attributes_as_string + assert_dom_equal('', label(:post, :title, nil, "for" => "my_for", "id" => "my_id")) + end + def test_label_for_radio_buttons_with_value assert_dom_equal('', label("post", "title", "The title goes here", :value => "great_title")) assert_dom_equal('', label("post", "title", "The title goes here", :value => "great title")) -- cgit v1.2.3 From 0af4b0755f507d41590b5315966c9a20949f79f9 Mon Sep 17 00:00:00 2001 From: Max Lapshin Date: Mon, 16 Mar 2009 18:20:15 +0300 Subject: Make sure link_to generates the form with the specified :href if any [#2254 state:resolved] Signed-off-by: Pratik Naik --- actionpack/lib/action_view/helpers/url_helper.rb | 2 +- actionpack/test/template/url_helper_test.rb | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index c5a6d1f084..b07304e361 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -568,7 +568,7 @@ module ActionView when confirm && popup "if (#{confirm_javascript_function(confirm)}) { #{popup_javascript_function(popup)} };return false;" when confirm && method - "if (#{confirm_javascript_function(confirm)}) { #{method_javascript_function(method)} };return false;" + "if (#{confirm_javascript_function(confirm)}) { #{method_javascript_function(method, url, href)} };return false;" when confirm "return #{confirm_javascript_function(confirm)};" when method diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index 9eeb26831c..0e24fbd24d 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -220,6 +220,14 @@ class UrlHelperTest < ActionView::TestCase ) end + def test_link_tag_using_delete_javascript_and_href_and_confirm + assert_dom_equal( + "Destroy", + link_to("Destroy", "http://www.example.com", :method => :delete, :href => '#', :confirm => "Are you serious?"), + "When specifying url, form should be generated with it, but not this.href" + ) + end + def test_link_tag_using_post_javascript_and_popup assert_raise(ActionView::ActionViewError) { link_to("Hello", "http://www.example.com", :popup => true, :method => :post, :confirm => "Are you serious?") } end -- cgit v1.2.3 From 734e903af5913342c65d4c294e45f9095fa89986 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 9 Aug 2009 22:38:50 -0500 Subject: Deprecate router generation "best match" sorting --- .../lib/action_controller/routing/resources.rb | 4 +-- .../lib/action_controller/routing/route_set.rb | 32 +++++++++++++++++++--- actionpack/test/controller/caching_test.rb | 2 +- actionpack/test/controller/routing_test.rb | 8 ++++-- actionpack/test/controller/url_rewriter_test.rb | 6 ++-- 5 files changed, 39 insertions(+), 13 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/routing/resources.rb b/actionpack/lib/action_controller/routing/resources.rb index 7fd3ffd3f1..4862cf7115 100644 --- a/actionpack/lib/action_controller/routing/resources.rb +++ b/actionpack/lib/action_controller/routing/resources.rb @@ -529,13 +529,13 @@ module ActionController resource = Resource.new(entities, options) with_options :controller => resource.controller do |map| + map_associations(resource, options) + map_collection_actions(map, resource) map_default_collection_actions(map, resource) map_new_actions(map, resource) map_member_actions(map, resource) - map_associations(resource, options) - if block_given? with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block) end diff --git a/actionpack/lib/action_controller/routing/route_set.rb b/actionpack/lib/action_controller/routing/route_set.rb index 0c499f3b46..09f6024d39 100644 --- a/actionpack/lib/action_controller/routing/route_set.rb +++ b/actionpack/lib/action_controller/routing/route_set.rb @@ -407,9 +407,24 @@ module ActionController # don't use the recalled keys when determining which routes to check routes = routes_by_controller[controller][action][options.reject {|k,v| !v}.keys.sort_by { |x| x.object_id }] - routes.each do |route| + routes[1].each_with_index do |route, index| results = route.__send__(method, options, merged, expire_on) - return results if results && (!results.is_a?(Array) || results.first) + if results && (!results.is_a?(Array) || results.first) + + # Compare results with Rails 3.0 behavior + if routes[0][index] != route + routes[0].each do |route2| + new_results = route2.__send__(method, options, merged, expire_on) + if new_results && (!new_results.is_a?(Array) || new_results.first) + ActiveSupport::Deprecation.warn "The URL you generated will use the first matching route in routes.rb rather than the \"best\" match. " + + "In Rails 3.0 #{new_results} would of been generated instead of #{results}" + break + end + end + end + + return results + end end end @@ -448,7 +463,10 @@ module ActionController @routes_by_controller ||= Hash.new do |controller_hash, controller| controller_hash[controller] = Hash.new do |action_hash, action| action_hash[action] = Hash.new do |key_hash, keys| - key_hash[keys] = routes_for_controller_and_action_and_keys(controller, action, keys) + key_hash[keys] = [ + routes_for_controller_and_action_and_keys(controller, action, keys), + deprecated_routes_for_controller_and_action_and_keys(controller, action, keys) + ] end end end @@ -460,10 +478,16 @@ module ActionController merged = options if expire_on[:controller] action = merged[:action] || 'index' - routes_by_controller[controller][action][merged.keys] + routes_by_controller[controller][action][merged.keys][1] end def routes_for_controller_and_action_and_keys(controller, action, keys) + routes.select do |route| + route.matches_controller_and_action? controller, action + end + end + + def deprecated_routes_for_controller_and_action_and_keys(controller, action, keys) selected = routes.select do |route| route.matches_controller_and_action? controller, action end diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index 68529cc8f7..346fa09414 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -51,7 +51,7 @@ class PageCachingTest < ActionController::TestCase ActionController::Routing::Routes.clear! ActionController::Routing::Routes.draw do |map| - map.main '', :controller => 'posts' + map.main '', :controller => 'posts', :format => nil map.formatted_posts 'posts.:format', :controller => 'posts' map.resources :posts map.connect ':controller/:action/:id' diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index 5f9ae6292c..2534c232c7 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -1610,7 +1610,7 @@ class RouteTest < Test::Unit::TestCase end end -class RouteSetTest < Test::Unit::TestCase +class RouteSetTest < ActiveSupport::TestCase def set @set ||= ROUTING::RouteSet.new end @@ -2191,8 +2191,10 @@ class RouteSetTest < Test::Unit::TestCase map.connect "/ws/people", :controller => "people", :action => "index", :ws => true end - url = set.generate(:controller => "people", :action => "index", :ws => true) - assert_equal "/ws/people", url + assert_deprecated { + url = set.generate(:controller => "people", :action => "index", :ws => true) + assert_equal "/ws/people", url + } end def test_generate_changes_controller_module diff --git a/actionpack/test/controller/url_rewriter_test.rb b/actionpack/test/controller/url_rewriter_test.rb index 863f8414c5..0e149cf8ae 100644 --- a/actionpack/test/controller/url_rewriter_test.rb +++ b/actionpack/test/controller/url_rewriter_test.rb @@ -304,7 +304,7 @@ class UrlWriterTests < ActionController::TestCase def test_named_routes_with_nil_keys ActionController::Routing::Routes.clear! ActionController::Routing::Routes.draw do |map| - map.main '', :controller => 'posts' + map.main '', :controller => 'posts', :format => nil map.resources :posts map.connect ':controller/:action/:id' end @@ -314,9 +314,9 @@ class UrlWriterTests < ActionController::TestCase controller = kls.new params = {:action => :index, :controller => :posts, :format => :xml} - assert_equal("http://www.basecamphq.com/posts.xml", controller.send(:url_for, params)) + assert_equal("http://www.basecamphq.com/posts.xml", controller.send(:url_for, params)) params[:format] = nil - assert_equal("http://www.basecamphq.com/", controller.send(:url_for, params)) + assert_equal("http://www.basecamphq.com/", controller.send(:url_for, params)) ensure ActionController::Routing::Routes.load! end -- cgit v1.2.3 From 8c32248acbd71f7906a037fad499e2f8cae61bed Mon Sep 17 00:00:00 2001 From: codeape Date: Sun, 9 Aug 2009 19:18:01 -0700 Subject: Introduce grouped_collection_select helper. [#1249 state:committed] Signed-off-by: Jeremy Kemper --- actionpack/CHANGELOG | 2 + .../lib/action_view/helpers/form_options_helper.rb | 67 ++++++++++++++++++++++ .../test/template/form_options_helper_test.rb | 34 +++++++++++ 3 files changed, 103 insertions(+) (limited to 'actionpack') diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 75de1fe2a6..30f3f31563 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *Edge* +* Introduce grouped_collection_select helper. #1249 [Dan Codeape, Erik Ostrom] + * Make sure javascript_include_tag/stylesheet_link_tag does not append ".js" or ".css" onto external urls. #1664 [Matthew Rudy Jacobs] * Ruby 1.9: fix Content-Length for multibyte send_data streaming. #2661 [Sava Chankov] diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 8cb5882aab..4620a52272 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -162,6 +162,60 @@ module ActionView InstanceTag.new(object, method, self, options.delete(:object)).to_collection_select_tag(collection, value_method, text_method, options, html_options) end + + # Returns + # + # + # + # + # + # + # + # + # + # + def grouped_collection_select(object, method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {}) + InstanceTag.new(object, method, self, options.delete(:object)).to_grouped_collection_select_tag(collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options) + end + + + # Return select and option tags for the given object and method, using # #time_zone_options_for_select to generate the list of option tags. # @@ -490,6 +544,15 @@ module ActionView ) end + def to_grouped_collection_select_tag(collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options) + html_options = html_options.stringify_keys + add_default_name_and_id(html_options) + value = value(object) + content_tag( + "select", add_options(option_groups_from_collection_for_select(collection, group_method, group_label_method, option_key_method, option_value_method, value), options, value), html_options + ) + end + def to_time_zone_select_tag(priority_zones, options, html_options) html_options = html_options.stringify_keys add_default_name_and_id(html_options) @@ -524,6 +587,10 @@ module ActionView @template.collection_select(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options)) end + def grouped_collection_select(method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {}) + @template.grouped_collection_select(@object_name, method, collection, group_method, group_label_method, option_key_method, option_value_method, objectify_options(options), @default_options.merge(html_options)) + end + def time_zone_select(method, priority_zones = nil, options = {}, html_options = {}) @template.time_zone_select(@object_name, method, priority_zones, objectify_options(options), @default_options.merge(html_options)) end diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb index 73624406be..aa40e46aa8 100644 --- a/actionpack/test/template/form_options_helper_test.rb +++ b/actionpack/test/template/form_options_helper_test.rb @@ -763,6 +763,40 @@ class FormOptionsHelperTest < ActionView::TestCase html end + def test_grouped_collection_select + @continents = [ + Continent.new("", [Country.new("", ""), Country.new("so", "Somalia")] ), + Continent.new("Europe", [Country.new("dk", "Denmark"), Country.new("ie", "Ireland")] ) + ] + + @post = Post.new + @post.origin = 'dk' + + assert_dom_equal( + %Q{}, + grouped_collection_select("post", "origin", @continents, :countries, :continent_name, :country_id, :country_name) + ) + end + + def test_grouped_collection_select_under_fields_for + @continents = [ + Continent.new("", [Country.new("", ""), Country.new("so", "Somalia")] ), + Continent.new("Europe", [Country.new("dk", "Denmark"), Country.new("ie", "Ireland")] ) + ] + + @post = Post.new + @post.origin = 'dk' + + fields_for :post, @post do |f| + concat f.grouped_collection_select("origin", @continents, :countries, :continent_name, :country_id, :country_name) + end + + assert_dom_equal( + %Q{}, + output_buffer + ) + end + private def dummy_posts -- cgit v1.2.3 From 04d4537cd40d0415d15af4395213632735c8683f Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Sun, 9 Aug 2009 07:14:24 -0300 Subject: This change causes some failing tests, but it should be possible to make them pass with minimal performance impact. --- actionpack/examples/minimal.rb | 6 ++++-- actionpack/lib/action_dispatch/http/request.rb | 23 ++++++++++++----------- actionpack/lib/action_view/template/resolver.rb | 6 ++++-- 3 files changed, 20 insertions(+), 15 deletions(-) (limited to 'actionpack') diff --git a/actionpack/examples/minimal.rb b/actionpack/examples/minimal.rb index a9015da053..b3733b487b 100644 --- a/actionpack/examples/minimal.rb +++ b/actionpack/examples/minimal.rb @@ -91,6 +91,8 @@ class HttpPostController < ActionController::Metal end end +ActionController::Base.use_accept_header = false + unless ENV["PROFILE"] Runner.run(BasePostController.action(:overhead), N, 'overhead', false) Runner.run(BasePostController.action(:index), N, 'index', false) @@ -108,10 +110,10 @@ unless ENV["PROFILE"] Runner.run(BasePostController.action(:show_template), N, 'template') end else - Runner.run(BasePostController.action(:many_partials), N, 'many_partials') + Runner.run(BasePostController.action(ENV["PROFILE"].to_sym), N, ENV["PROFILE"]) require "ruby-prof" RubyProf.start - Runner.run(BasePostController.action(:many_partials), N, 'many_partials') + Runner.run(BasePostController.action(ENV["PROFILE"].to_sym), N, ENV["PROFILE"]) result = RubyProf.stop printer = RubyProf::CallStackPrinter.new(result) printer.print(File.open("output.html", "w")) diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 4190fa21cd..958a541436 100755 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -176,17 +176,18 @@ module ActionDispatch # Expand raw_formats by converting Mime::ALL to the Mime::SET. # def formats - if ActionController::Base.use_accept_header - raw_formats.tap do |ret| - if ret == ONLY_ALL - ret.replace Mime::SET - elsif all = ret.index(Mime::ALL) - ret.delete_at(all) && ret.insert(all, *Mime::SET) - end - end - else - raw_formats + Mime::SET - end + return raw_formats + # if ActionController::Base.use_accept_header + # raw_formats.tap do |ret| + # if ret == ONLY_ALL + # ret.replace Mime::SET + # elsif all = ret.index(Mime::ALL) + # ret.delete_at(all) && ret.insert(all, *Mime::SET) + # end + # end + # else + # raw_formats + Mime::SET + # end end # Sets the \format by string extension, which can be used to force custom formats diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index ebfc6cc8ce..3bd2acae7a 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -41,8 +41,10 @@ module ActionView end def handler_glob - e = TemplateHandlers.extensions.map{|h| ".#{h},"}.join - "{#{e}}" + @handler_glob ||= begin + e = TemplateHandlers.extensions.map{|h| ".#{h},"}.join + "{#{e}}" + end end def formats_glob -- cgit v1.2.3 From 02d9dd900048407ef555cf09b0038a57ae924b0a Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Sun, 9 Aug 2009 09:46:50 -0300 Subject: Add some more caching to the lookup --- actionpack/lib/abstract_controller/layouts.rb | 22 ++++++++++++++---- actionpack/lib/action_view/template/resolver.rb | 30 +++++++++++++++---------- actionpack/test/dispatch/request_test.rb | 4 ++-- 3 files changed, 38 insertions(+), 18 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index 0063d54149..d7317b415c 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -15,6 +15,18 @@ module AbstractController klass._write_layout_method end + def cache_layout(details) + layout = @found_layouts ||= {} + values = details.values_at(:formats, :locale) + + # Cache nil + if layout.key?(values) + return layout[values] + else + layout[values] = yield + end + end + # Specify the layout to use for this class. # # If the specified layout is a: @@ -76,10 +88,12 @@ module AbstractController when nil self.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1 def _layout(details) - if view_paths.exists?("#{_implied_layout_name}", details, "layouts") - "#{_implied_layout_name}" - else - super + self.class.cache_layout(details) do + if view_paths.exists?("#{_implied_layout_name}", details, "layouts") + "#{_implied_layout_name}" + else + super + end end end ruby_eval diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index 3bd2acae7a..10f664736f 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -62,6 +62,10 @@ module ActionView class FileSystemResolver < Resolver + def self.cached_glob + @@cached_glob ||= {} + end + def initialize(path, options = {}) raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver) super(options) @@ -107,20 +111,22 @@ module ActionView # :api: plugin def details_to_glob(name, details, prefix, partial, root) - path = "" - path << "#{prefix}/" unless prefix.empty? - path << (partial ? "_#{name}" : name) - - extensions = "" - [:locales, :formats].each do |k| - extensions << if exts = details[k] - '{' + exts.map {|e| ".#{e},"}.join + '}' - else - k == :formats ? formats_glob : '' + self.class.cached_glob[[name, prefix, partial, details, root]] ||= begin + path = "" + path << "#{prefix}/" unless prefix.empty? + path << (partial ? "_#{name}" : name) + + extensions = "" + [:locales, :formats].each do |k| + extensions << if exts = details[k] + '{' + exts.map {|e| ".#{e},"}.join + '}' + else + k == :formats ? formats_glob : '' + end end - end - "#{root}#{path}#{extensions}#{handler_glob}" + "#{root}#{path}#{extensions}#{handler_glob}" + end end # TODO: fix me diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index f3500fca34..b626063df4 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -427,7 +427,7 @@ class RequestTest < ActiveSupport::TestCase request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8' request.expects(:parameters).at_least_once.returns({}) - assert_equal with_set(Mime::XML, Mime::HTML), request.formats + assert_equal with_set(Mime::XML, Mime::HTML, Mime::ALL), request.formats end with_accept_header false do @@ -460,7 +460,7 @@ protected end def with_set(*args) - args + Mime::SET + args end def with_accept_header(value) -- cgit v1.2.3 From bef7576c09bbd51aeeb8e83b4cf24a994a0256b0 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Sun, 9 Aug 2009 09:59:54 -0300 Subject: Add a few more benches --- actionpack/examples/minimal.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'actionpack') diff --git a/actionpack/examples/minimal.rb b/actionpack/examples/minimal.rb index b3733b487b..c4e5ffd36e 100644 --- a/actionpack/examples/minimal.rb +++ b/actionpack/examples/minimal.rb @@ -73,10 +73,18 @@ class BasePostController < ActionController::Base render :partial => "/many_partials" end + def hundred_partials + render :partial => "/hundred_partials" + end + def partial_collection render :partial => "/collection", :collection => [1,2,3,4,5,6,7,8,9,10] end + def large_collection + render :partial => "/collection", :collection => (1...100).to_a + end + def show_template render :template => "template" end @@ -99,6 +107,8 @@ unless ENV["PROFILE"] Runner.run(BasePostController.action(:partial), N, 'partial', false) Runner.run(BasePostController.action(:many_partials), N, 'many_partials', false) Runner.run(BasePostController.action(:partial_collection), N, 'collection', false) + Runner.run(BasePostController.action(:hundred_partials), N, 'hundred_partials', false) + Runner.run(BasePostController.action(:large_collection), N, 'large_collection', false) Runner.run(BasePostController.action(:show_template), N, 'template', false) (ENV["M"] || 1).to_i.times do @@ -107,6 +117,8 @@ unless ENV["PROFILE"] Runner.run(BasePostController.action(:partial), N, 'partial') Runner.run(BasePostController.action(:many_partials), N, 'many_partials') Runner.run(BasePostController.action(:partial_collection), N, 'collection') + Runner.run(BasePostController.action(:hundred_partials), N, 'hundred_partials') + Runner.run(BasePostController.action(:large_collection), N, 'large_collection') Runner.run(BasePostController.action(:show_template), N, 'template') end else -- cgit v1.2.3 From 4945d8223964d4ccb3c0a0f4107f15ae1c6c4a09 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Mon, 10 Aug 2009 02:54:17 -0400 Subject: Further experimentation. Was able to cut the cost of rendering 100 partials in a collection in half. To discuss: What are the desired semantics (if any) for layouts in a collection. There are no tests for it at present, and I'm not sure if it's needed at all. Deprecated on this branch: `object` pointing at the current object in partials. You can still use the partial name, or use :as to achieve the same thing. This is obviously up for discussion. --- actionpack/examples/minimal.rb | 4 +- actionpack/examples/views/_hundred_partials.erb | 12 ++++++ actionpack/lib/action_view/render/partials.rb | 49 ++++++++++++++++++++----- actionpack/lib/action_view/test_case.rb | 20 +++++----- 4 files changed, 65 insertions(+), 20 deletions(-) create mode 100644 actionpack/examples/views/_hundred_partials.erb (limited to 'actionpack') diff --git a/actionpack/examples/minimal.rb b/actionpack/examples/minimal.rb index c4e5ffd36e..90435d0b89 100644 --- a/actionpack/examples/minimal.rb +++ b/actionpack/examples/minimal.rb @@ -104,22 +104,22 @@ ActionController::Base.use_accept_header = false unless ENV["PROFILE"] Runner.run(BasePostController.action(:overhead), N, 'overhead', false) Runner.run(BasePostController.action(:index), N, 'index', false) + Runner.run(BasePostController.action(:show_template), N, 'template', false) Runner.run(BasePostController.action(:partial), N, 'partial', false) Runner.run(BasePostController.action(:many_partials), N, 'many_partials', false) Runner.run(BasePostController.action(:partial_collection), N, 'collection', false) Runner.run(BasePostController.action(:hundred_partials), N, 'hundred_partials', false) Runner.run(BasePostController.action(:large_collection), N, 'large_collection', false) - Runner.run(BasePostController.action(:show_template), N, 'template', false) (ENV["M"] || 1).to_i.times do Runner.run(BasePostController.action(:overhead), N, 'overhead') Runner.run(BasePostController.action(:index), N, 'index') + Runner.run(BasePostController.action(:show_template), N, 'template') Runner.run(BasePostController.action(:partial), N, 'partial') Runner.run(BasePostController.action(:many_partials), N, 'many_partials') Runner.run(BasePostController.action(:partial_collection), N, 'collection') Runner.run(BasePostController.action(:hundred_partials), N, 'hundred_partials') Runner.run(BasePostController.action(:large_collection), N, 'large_collection') - Runner.run(BasePostController.action(:show_template), N, 'template') end else Runner.run(BasePostController.action(ENV["PROFILE"].to_sym), N, ENV["PROFILE"]) diff --git a/actionpack/examples/views/_hundred_partials.erb b/actionpack/examples/views/_hundred_partials.erb new file mode 100644 index 0000000000..15e99c1b68 --- /dev/null +++ b/actionpack/examples/views/_hundred_partials.erb @@ -0,0 +1,12 @@ +<% 10.times do %> + <%= render :partial => '/hello' %> + <%= render :partial => '/hello' %> + <%= render :partial => '/hello' %> + <%= render :partial => '/hello' %> + <%= render :partial => '/hello' %> + <%= render :partial => '/hello' %> + <%= render :partial => '/hello' %> + <%= render :partial => '/hello' %> + <%= render :partial => '/hello' %> + <%= render :partial => '/hello' %> +<% end %> \ No newline at end of file diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb index 64f08c447d..2aa3bd7db8 100644 --- a/actionpack/lib/action_view/render/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -207,9 +207,7 @@ module ActionView end def render_collection - # Even if no template is rendered, this will ensure that the MIME type - # for the empty response is the same as the provided template - @options[:_template] = default_template = find_template + @options[:_template] = template = find_template return nil if collection.blank? @@ -217,15 +215,48 @@ module ActionView spacer = find_template(@options[:spacer_template]).render(@view, @locals) end - segments = [] + result = template ? collection_with_template(template) : collection_without_template + result.join(spacer) + end + + def collection_with_template(template) + options = @options + + segments, locals, as = [], @locals, options[:as] + + [].tap do |segments| + variable_name = template.variable_name + counter_name = template.counter_name + locals[counter_name] = -1 - collection.each_with_index do |object, index| - template = default_template || find_template(partial_path(object)) - @locals[template.counter_name] = index - segments << render_template(template, object) + collection.each do |object| + locals[counter_name] += 1 + locals[variable_name] = object + locals[as] = object if as + + segments << template.render(@view, locals) + end end + end - segments.join(spacer) + def collection_without_template + options = @options + + segments, locals, as = [], @locals, options[:as] + index, template = -1, nil + + [].tap do |segments| + collection.each do |object| + template = find_template(partial_path(object)) + locals[template.counter_name] = (index += 1) + locals[template.variable_name] = object + locals[as] = object if as + + segments << template.render(@view, locals) + end + + @options[:_template] = template + end end def render_template(template, object = @object) diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index e51744d095..b317b6dc1a 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -9,14 +9,16 @@ module ActionView end attr_internal :rendered - alias_method :_render_template_without_template_tracking, :_render_single_template - def _render_single_template(template, local_assigns, &block) - if template.respond_to?(:identifier) && template.present? - @_rendered[:partials][template] += 1 if template.partial? - @_rendered[:template] ||= [] - @_rendered[:template] << template - end - _render_template_without_template_tracking(template, local_assigns, &block) + end + + class Template + alias_method :render_without_tracking, :render + def render(view, locals, &blk) + rendered = view.rendered + rendered[:partials][self] += 1 if partial? + rendered[:template] ||= [] + rendered[:template] << self + render_without_tracking(view, locals, &blk) end end @@ -68,7 +70,7 @@ module ActionView def initialize @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new - + @params = {} send(:initialize_current_url) end -- cgit v1.2.3 From 945a7df9f8ad2986ba2351b331a9f7225dfaf61c Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Mon, 10 Aug 2009 03:28:21 -0400 Subject: Make large_collection 1,000 partials --- actionpack/examples/minimal.rb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'actionpack') diff --git a/actionpack/examples/minimal.rb b/actionpack/examples/minimal.rb index 90435d0b89..62b71de2cb 100644 --- a/actionpack/examples/minimal.rb +++ b/actionpack/examples/minimal.rb @@ -82,7 +82,7 @@ class BasePostController < ActionController::Base end def large_collection - render :partial => "/collection", :collection => (1...100).to_a + render :partial => "/collection", :collection => (1...1000).to_a end def show_template @@ -102,14 +102,14 @@ end ActionController::Base.use_accept_header = false unless ENV["PROFILE"] - Runner.run(BasePostController.action(:overhead), N, 'overhead', false) - Runner.run(BasePostController.action(:index), N, 'index', false) - Runner.run(BasePostController.action(:show_template), N, 'template', false) - Runner.run(BasePostController.action(:partial), N, 'partial', false) - Runner.run(BasePostController.action(:many_partials), N, 'many_partials', false) - Runner.run(BasePostController.action(:partial_collection), N, 'collection', false) - Runner.run(BasePostController.action(:hundred_partials), N, 'hundred_partials', false) - Runner.run(BasePostController.action(:large_collection), N, 'large_collection', false) + Runner.run(BasePostController.action(:overhead), 1, 'overhead', false) + Runner.run(BasePostController.action(:index), 1, 'index', false) + Runner.run(BasePostController.action(:show_template), 1, 'template', false) + Runner.run(BasePostController.action(:partial), 1, 'partial', false) + Runner.run(BasePostController.action(:many_partials), 1, 'many_partials', false) + Runner.run(BasePostController.action(:partial_collection), 1, 'collection', false) + Runner.run(BasePostController.action(:hundred_partials), 1, 'hundred_partials', false) + Runner.run(BasePostController.action(:large_collection), 1, 'large_collection', false) (ENV["M"] || 1).to_i.times do Runner.run(BasePostController.action(:overhead), N, 'overhead') @@ -122,7 +122,7 @@ unless ENV["PROFILE"] Runner.run(BasePostController.action(:large_collection), N, 'large_collection') end else - Runner.run(BasePostController.action(ENV["PROFILE"].to_sym), N, ENV["PROFILE"]) + Runner.run(BasePostController.action(ENV["PROFILE"].to_sym), 1, ENV["PROFILE"]) require "ruby-prof" RubyProf.start Runner.run(BasePostController.action(ENV["PROFILE"].to_sym), N, ENV["PROFILE"]) -- cgit v1.2.3 From 9e62d6d1c0c53e8b03c9659500e2b5549a1fd2ec Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Mon, 10 Aug 2009 08:57:44 -0400 Subject: Tentatively accept the ":as or :object, but not both" solution --- actionpack/lib/action_view/render/partials.rb | 43 +++++++++++----------- .../test/fixtures/test/_customer_with_var.erb | 2 +- 2 files changed, 22 insertions(+), 23 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb index 2aa3bd7db8..83175ab4cf 100644 --- a/actionpack/lib/action_view/render/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -184,6 +184,7 @@ module ActionView def initialize(view_context, options, block) partial = options[:partial] + @memo = {} @view = view_context @options = options @locals = options[:locals] || {} @@ -222,41 +223,39 @@ module ActionView def collection_with_template(template) options = @options - segments, locals, as = [], @locals, options[:as] + segments, locals, as = [], @locals, options[:as] || :object - [].tap do |segments| - variable_name = template.variable_name - counter_name = template.counter_name - locals[counter_name] = -1 + variable_name = template.variable_name + counter_name = template.counter_name + locals[counter_name] = -1 - collection.each do |object| - locals[counter_name] += 1 - locals[variable_name] = object - locals[as] = object if as + collection.each do |object| + locals[counter_name] += 1 + locals[variable_name] = object + locals[as] = object if as - segments << template.render(@view, locals) - end + segments << template.render(@view, locals) end + segments end def collection_without_template options = @options - segments, locals, as = [], @locals, options[:as] + segments, locals, as = [], @locals, options[:as] || :object index, template = -1, nil - [].tap do |segments| - collection.each do |object| - template = find_template(partial_path(object)) - locals[template.counter_name] = (index += 1) - locals[template.variable_name] = object - locals[as] = object if as - - segments << template.render(@view, locals) - end + collection.each do |object| + template = find_template(partial_path(object)) + locals[template.counter_name] = (index += 1) + locals[template.variable_name] = object + locals[as] = object if as - @options[:_template] = template + segments << template.render(@view, locals) end + + @options[:_template] = template + segments end def render_template(template, object = @object) diff --git a/actionpack/test/fixtures/test/_customer_with_var.erb b/actionpack/test/fixtures/test/_customer_with_var.erb index 3379246b7e..c28824936b 100644 --- a/actionpack/test/fixtures/test/_customer_with_var.erb +++ b/actionpack/test/fixtures/test/_customer_with_var.erb @@ -1 +1 @@ -<%= customer.name %> <%= object.name %> <%= customer_with_var.name %> \ No newline at end of file +<%= customer.name %> <%= customer.name %> <%= customer_with_var.name %> \ No newline at end of file -- cgit v1.2.3 From 0adbeeb0c92c6de2e4a148e4b54d56cd4a325800 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Mon, 10 Aug 2009 11:40:41 -0400 Subject: Got overhead down from 127 to 85. All tests pass: * Tentatively replaced HeaderHash with SimpleHeaderHash, which does not preserve case but does handle converting Arrays to Strings in to_hash. This requires further discussion. * Moved default_charset to ActionDispatch::Response to avoid having to hop over to ActionController. Ideally, this would be a constant on AD::Response, but some tests expect to be able to change it dynamically and I didn't want to change them yet. * Completely override #initialize from Rack::Response. Previously, it was creating a HeaderHash, and then we were creating an entirely new one. There is no way to call super without incurring the overhead of creating a HeaderHash. * Override #write from Rack::Response. Its implementation tracks Content-Length, and doing so adds additional overhead that could be mooted if other middleware changes the body. It is more efficiently done at the top-level server. * Change sending_file to an instance_variable instead of header inspection. In general, if a state is important, it should be set as a property of the response not reconstructed later. * Set the Etag to @body instead of .body. AS::Cache.expand_cache_key handles Arrays fine, and it's more efficient to let it handle the body parts, since it is not forced to create a joined String. * If we detect the default cache control case, just set it, rather than setting the constituent parts and then running the normal (expensive) code to generate the string. --- .../lib/action_controller/metal/compatibility.rb | 5 +- .../lib/action_controller/metal/streaming.rb | 3 +- .../lib/action_controller/testing/process.rb | 2 +- actionpack/lib/action_dispatch/http/response.rb | 92 +++++++++++++--------- 4 files changed, 62 insertions(+), 40 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal/compatibility.rb b/actionpack/lib/action_controller/metal/compatibility.rb index f94d1c669c..a008b53d45 100644 --- a/actionpack/lib/action_controller/metal/compatibility.rb +++ b/actionpack/lib/action_controller/metal/compatibility.rb @@ -25,8 +25,9 @@ module ActionController cattr_accessor :relative_url_root self.relative_url_root = ENV['RAILS_RELATIVE_URL_ROOT'] - cattr_accessor :default_charset - self.default_charset = "utf-8" + class << self + delegate :default_charset=, :to => "ActionDispatch::Response" + end # cattr_reader :protected_instance_variables cattr_accessor :protected_instance_variables diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb index 57318e8747..4761763a26 100644 --- a/actionpack/lib/action_controller/metal/streaming.rb +++ b/actionpack/lib/action_controller/metal/streaming.rb @@ -145,7 +145,6 @@ module ActionController #:nodoc: def send_data(data, options = {}) #:doc: logger.info "Sending data #{options[:filename]}" if logger send_file_headers! options.merge(:length => data.bytesize) - @performed_render = false render :status => options[:status], :text => data end @@ -175,6 +174,8 @@ module ActionController #:nodoc: 'Content-Transfer-Encoding' => 'binary' ) + response.sending_file = true + # Fix a problem with IE 6.0 on opening downloaded files: # If Cache-Control: no-cache is set (which Rails does by default), # IE removes the file it just downloaded from its cache immediately diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index d32d5562e8..147a7e7631 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -52,7 +52,7 @@ module ActionController #:nodoc: class TestResponse < ActionDispatch::TestResponse def recycle! @status = 200 - @header = Rack::Utils::HeaderHash.new + @header = ActionDispatch::Response::SimpleHeaderHash.new @writer = lambda { |x| @body << x } @block = nil @length = 0 diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index 03d1780b77..1d3cf63984 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -32,18 +32,42 @@ module ActionDispatch # :nodoc: # end # end class Response < Rack::Response + class SimpleHeaderHash < Hash + def to_hash + result = {} + each do |k,v| + v = v.join("\n") if v.is_a?(Array) + result[k] = v + end + result + end + end + attr_accessor :request attr_reader :cache_control - attr_writer :header + attr_writer :header, :sending_file alias_method :headers=, :header= - delegate :default_charset, :to => 'ActionController::Base' - def initialize - super + @status = 200 + @header = SimpleHeaderHash.new @cache_control = {} - @header = Rack::Utils::HeaderHash.new + + @writer = lambda { |x| @body << x } + @block = nil + @length = 0 + + @body = [] + @sending_file = false + + yield self if block_given? + end + + def write(str) + s = str.to_s + @writer.call s + str end def status=(status) @@ -128,20 +152,20 @@ module ActionDispatch # :nodoc: end end - def sending_file? - headers["Content-Transfer-Encoding"] == "binary" - end + CONTENT_TYPE = "Content-Type" + + cattr_accessor(:default_charset) { "utf-8" } def assign_default_content_type_and_charset! - return if !headers["Content-Type"].blank? + return if !headers[CONTENT_TYPE].blank? @content_type ||= Mime::HTML - @charset ||= default_charset + @charset ||= self.class.default_charset type = @content_type.to_s.dup - type << "; charset=#{@charset}" unless sending_file? + type << "; charset=#{@charset}" unless @sending_file - headers["Content-Type"] = type + headers[CONTENT_TYPE] = type end def prepare! @@ -168,17 +192,6 @@ module ActionDispatch # :nodoc: str end - def set_cookie(key, value) - if value.has_key?(:http_only) - ActiveSupport::Deprecation.warn( - "The :http_only option in ActionController::Response#set_cookie " + - "has been renamed. Please use :httponly instead.", caller) - value[:httponly] ||= value.delete(:http_only) - end - - super(key, value) - end - # Returns the response cookies, converted to a Hash of (name => value) pairs # # assert_equal 'AuthorOfNewPage', r.cookies['author'] @@ -201,7 +214,7 @@ module ActionDispatch # :nodoc: if etag? || last_modified? || !cache_control.empty? set_conditional_cache_control! elsif nonempty_ok_response? - self.etag = body + self.etag = @body if request && request.etag_matches?(etag) self.status = 304 @@ -214,30 +227,37 @@ module ActionDispatch # :nodoc: end end + EMPTY_RESPONSE = [" "] + def nonempty_ok_response? ok = !@status || @status == 200 - ok && string_body? + ok && string_body? && @body != EMPTY_RESPONSE end def string_body? !body_parts.respond_to?(:call) && body_parts.any? && body_parts.all? { |part| part.is_a?(String) } end + DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate" + def set_conditional_cache_control! - if cache_control.empty? - cache_control.merge!(:public => false, :max_age => 0, :must_revalidate => true) - end + control = cache_control - public_cache, max_age, must_revalidate, extras = - cache_control.values_at(:public, :max_age, :must_revalidate, :extras) + if control.empty? + headers["Cache-Control"] = DEFAULT_CACHE_CONTROL + else + extras = control[:extras] + max_age = control[:max_age] + + options = [] + options << "max-age=#{max_age}" if max_age + options << (control[:public] ? "public" : "private") + options << "must-revalidate" if control[:must_revalidate] + options.concat(extras) if extras - options = [] - options << "max-age=#{max_age}" if max_age - options << (public_cache ? "public" : "private") - options << "must-revalidate" if must_revalidate - options.concat(extras) if extras + headers["Cache-Control"] = options.join(", ") + end - headers["Cache-Control"] = options.join(", ") end end end -- cgit v1.2.3 From 4bf516e072f5279bdb462c6592e17b195fd9cf05 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Mon, 10 Aug 2009 15:49:33 -0700 Subject: More perf work: * Move #set_cookie and #delete_cookie inline to optimize. These optimizations should almost certainly be sent back upstream to Rack. The optimization involves using an ivar for cookies instead of indexing into the headers each time. * Was able to use a bare Hash for headers now that cookies have their own joining semantics (some code assumed that the raw cookies were an Array). * Cache blankness of body on body= * Improve expand_cache_key for Arrays of a single element (common in our case) * Use a simple layout condition check unless conditions are used * Cache visible actions * Lazily load the UrlRewriter * Make etag an ivar that is set on prepare! --- actionpack/lib/abstract_controller/layouts.rb | 49 ++++++++----- .../lib/action_controller/metal/compatibility.rb | 7 +- .../lib/action_controller/metal/hide_actions.rb | 14 +++- actionpack/lib/action_controller/metal/url_for.rb | 10 +-- .../lib/action_controller/testing/process.rb | 2 +- .../lib/action_controller/testing/test_case.rb | 1 - actionpack/lib/action_dispatch/http/request.rb | 37 +++------- actionpack/lib/action_dispatch/http/response.rb | 84 ++++++++++++++-------- actionpack/lib/action_view/test_case.rb | 1 - actionpack/test/controller/caching_test.rb | 1 - 10 files changed, 113 insertions(+), 93 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index d7317b415c..ac2154dffc 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -6,17 +6,21 @@ module AbstractController included do extlib_inheritable_accessor(:_layout_conditions) { Hash.new } + extlib_inheritable_accessor(:_action_has_layout) { Hash.new } _write_layout_method end module ClassMethods def inherited(klass) super - klass._write_layout_method + klass.class_eval do + _write_layout_method + @found_layouts = {} + end end def cache_layout(details) - layout = @found_layouts ||= {} + layout = @found_layouts values = details.values_at(:formats, :locale) # Cache nil @@ -27,6 +31,28 @@ module AbstractController end end + # This module is mixed in if layout conditions are provided. This means + # that if no layout conditions are used, this method is not used + module LayoutConditions + # Determines whether the current action has a layout by checking the + # action name against the :only and :except conditions set on the + # layout. + # + # ==== Returns + # Boolean:: True if the action has a layout, false otherwise. + def _action_has_layout? + conditions = _layout_conditions + + if only = conditions[:only] + only.include?(action_name) + elsif except = conditions[:except] + !except.include?(action_name) + else + true + end + end + end + # Specify the layout to use for this class. # # If the specified layout is a: @@ -43,6 +69,8 @@ module AbstractController # :only<#to_s, Array[#to_s]>:: A list of actions to apply this layout to. # :except<#to_s, Array[#to_s]>:: Apply this layout to all actions but this one def layout(layout, conditions = {}) + include LayoutConditions unless conditions.empty? + conditions.each {|k, v| conditions[k] = Array(v).map {|a| a.to_s} } self._layout_conditions = conditions @@ -150,7 +178,7 @@ module AbstractController view_paths.find(name, details, prefix) end - # Returns the default layout for this controller and a given set of details. + # Returns the default layout for this controller and a given set of details. # Optionally raises an exception if the layout could not be found. # # ==== Parameters @@ -176,21 +204,8 @@ module AbstractController end end - # Determines whether the current action has a layout by checking the - # action name against the :only and :except conditions set on the - # layout. - # - # ==== Returns - # Boolean:: True if the action has a layout, false otherwise. def _action_has_layout? - conditions = _layout_conditions - if only = conditions[:only] - only.include?(action_name) - elsif except = conditions[:except] - !except.include?(action_name) - else - true - end + true end end end diff --git a/actionpack/lib/action_controller/metal/compatibility.rb b/actionpack/lib/action_controller/metal/compatibility.rb index a008b53d45..5b0165f0e7 100644 --- a/actionpack/lib/action_controller/metal/compatibility.rb +++ b/actionpack/lib/action_controller/metal/compatibility.rb @@ -102,11 +102,10 @@ module ActionController options[:template].sub!(/^\//, '') end - options[:text] = nil if options[:nothing] == true + options[:text] = nil if options.delete(:nothing) == true + options[:text] = " " if options.key?(:text) && options[:text].nil? - body = super - body = [' '] if body.blank? - body + super || " " end def _handle_method_missing diff --git a/actionpack/lib/action_controller/metal/hide_actions.rb b/actionpack/lib/action_controller/metal/hide_actions.rb index af68c772b1..cdacdc40a6 100644 --- a/actionpack/lib/action_controller/metal/hide_actions.rb +++ b/actionpack/lib/action_controller/metal/hide_actions.rb @@ -13,7 +13,9 @@ module ActionController # Overrides AbstractController::Base#action_method? to return false if the # action name is in the list of hidden actions. def action_method?(action_name) - !hidden_actions.include?(action_name) && super + self.class.visible_action?(action_name) do + !hidden_actions.include?(action_name) && super + end end module ClassMethods @@ -25,6 +27,16 @@ module ActionController hidden_actions.merge(args.map! {|a| a.to_s }) end + def inherited(klass) + klass.instance_variable_set("@visible_actions", {}) + super + end + + def visible_action?(action_name) + return @visible_actions[action_name] if @visible_actions.key?(action_name) + @visible_actions[action_name] = yield + end + # Overrides AbstractController::Base#action_methods to remove any methods # that are listed as hidden methods. def action_methods diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb index 7119c14cd3..14c6523045 100644 --- a/actionpack/lib/action_controller/metal/url_for.rb +++ b/actionpack/lib/action_controller/metal/url_for.rb @@ -4,15 +4,6 @@ module ActionController include RackConvenience - def process_action(*) - initialize_current_url - super - end - - def initialize_current_url - @url = UrlRewriter.new(request, params.clone) - end - # Overwrite to implement a number of default options that all url_for-based methods will use. The default options should come in # the form of a hash, just like the one you would use for url_for directly. Example: # @@ -40,6 +31,7 @@ module ActionController when String options when Hash + @url ||= UrlRewriter.new(request, params) @url.rewrite(rewrite_options(options)) else polymorphic_url(options) diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 147a7e7631..09b1a59254 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -52,7 +52,7 @@ module ActionController #:nodoc: class TestResponse < ActionDispatch::TestResponse def recycle! @status = 200 - @header = ActionDispatch::Response::SimpleHeaderHash.new + @header = {} @writer = lambda { |x| @body << x } @block = nil @length = 0 diff --git a/actionpack/lib/action_controller/testing/test_case.rb b/actionpack/lib/action_controller/testing/test_case.rb index a11755b517..b66a4c15ff 100644 --- a/actionpack/lib/action_controller/testing/test_case.rb +++ b/actionpack/lib/action_controller/testing/test_case.rb @@ -179,7 +179,6 @@ module ActionController if @controller @controller.request = @request @controller.params = {} - @controller.send(:initialize_current_url) end end diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 958a541436..b23306af62 100755 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -173,21 +173,16 @@ module ActionDispatch end end - # Expand raw_formats by converting Mime::ALL to the Mime::SET. - # def formats - return raw_formats - # if ActionController::Base.use_accept_header - # raw_formats.tap do |ret| - # if ret == ONLY_ALL - # ret.replace Mime::SET - # elsif all = ret.index(Mime::ALL) - # ret.delete_at(all) && ret.insert(all, *Mime::SET) - # end - # end - # else - # raw_formats + Mime::SET - # end + if ActionController::Base.use_accept_header + if param = parameters[:format] + Array.wrap(Mime[param]) + else + accepts.dup + end + else + [format] + end end # Sets the \format by string extension, which can be used to force custom formats @@ -488,7 +483,7 @@ EOM # matches the order array. # def negotiate_mime(order) - raw_formats.each do |priority| + formats.each do |priority| if priority == Mime::ALL return order.first elsif order.include?(priority) @@ -501,18 +496,6 @@ EOM private - def raw_formats - if ActionController::Base.use_accept_header - if param = parameters[:format] - Array.wrap(Mime[param]) - else - accepts.dup - end - else - [format] - end - end - def named_host?(host) !(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host)) end diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index 1d3cf63984..055f29a972 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -32,18 +32,7 @@ module ActionDispatch # :nodoc: # end # end class Response < Rack::Response - class SimpleHeaderHash < Hash - def to_hash - result = {} - each do |k,v| - v = v.join("\n") if v.is_a?(Array) - result[k] = v - end - result - end - end - - attr_accessor :request + attr_accessor :request, :blank attr_reader :cache_control attr_writer :header, :sending_file @@ -51,19 +40,23 @@ module ActionDispatch # :nodoc: def initialize @status = 200 - @header = SimpleHeaderHash.new + @header = {} @cache_control = {} @writer = lambda { |x| @body << x } @block = nil @length = 0 - @body = [] + @body, @cookie = [], [] @sending_file = false yield self if block_given? end + def cache_control + @cache_control ||= {} + end + def write(str) s = str.to_s @writer.call s @@ -95,7 +88,10 @@ module ActionDispatch # :nodoc: str end + EMPTY = " " + def body=(body) + @blank = true if body == EMPTY @body = body.respond_to?(:to_str) ? [body] : body end @@ -137,19 +133,16 @@ module ActionDispatch # :nodoc: end def etag - headers['ETag'] + @etag end def etag? - headers.include?('ETag') + @etag end def etag=(etag) - if etag.blank? - headers.delete('ETag') - else - headers['ETag'] = %("#{Digest::MD5.hexdigest(ActiveSupport::Cache.expand_cache_key(etag))}") - end + key = ActiveSupport::Cache.expand_cache_key(etag) + @etag = %("#{Digest::MD5.hexdigest(key)}") end CONTENT_TYPE = "Content-Type" @@ -157,7 +150,7 @@ module ActionDispatch # :nodoc: cattr_accessor(:default_charset) { "utf-8" } def assign_default_content_type_and_charset! - return if !headers[CONTENT_TYPE].blank? + return if headers[CONTENT_TYPE].present? @content_type ||= Mime::HTML @charset ||= self.class.default_charset @@ -171,7 +164,8 @@ module ActionDispatch # :nodoc: def prepare! assign_default_content_type_and_charset! handle_conditional_get! - self["Set-Cookie"] ||= "" + self["Set-Cookie"] = @cookie.join("\n") + self["ETag"] = @etag if @etag end def each(&callback) @@ -197,7 +191,7 @@ module ActionDispatch # :nodoc: # assert_equal 'AuthorOfNewPage', r.cookies['author'] def cookies cookies = {} - if header = headers['Set-Cookie'] + if header = @cookie header = header.split("\n") if header.respond_to?(:to_str) header.each do |cookie| if pair = cookie.split(';').first @@ -209,9 +203,40 @@ module ActionDispatch # :nodoc: cookies end + def set_cookie(key, value) + case value + when Hash + domain = "; domain=" + value[:domain] if value[:domain] + path = "; path=" + value[:path] if value[:path] + # According to RFC 2109, we need dashes here. + # N.B.: cgi.rb uses spaces... + expires = "; expires=" + value[:expires].clone.gmtime. + strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires] + secure = "; secure" if value[:secure] + httponly = "; HttpOnly" if value[:httponly] + value = value[:value] + end + value = [value] unless Array === value + cookie = Rack::Utils.escape(key) + "=" + + value.map { |v| Rack::Utils.escape v }.join("&") + + "#{domain}#{path}#{expires}#{secure}#{httponly}" + + @cookie << cookie + end + + def delete_cookie(key, value={}) + @cookie.reject! { |cookie| + cookie =~ /\A#{Rack::Utils.escape(key)}=/ + } + + set_cookie(key, + {:value => '', :path => nil, :domain => nil, + :expires => Time.at(0) }.merge(value)) + end + private def handle_conditional_get! - if etag? || last_modified? || !cache_control.empty? + if etag? || last_modified? || !@cache_control.empty? set_conditional_cache_control! elsif nonempty_ok_response? self.etag = @body @@ -227,21 +252,18 @@ module ActionDispatch # :nodoc: end end - EMPTY_RESPONSE = [" "] - def nonempty_ok_response? - ok = !@status || @status == 200 - ok && string_body? && @body != EMPTY_RESPONSE + @status == 200 && string_body? end def string_body? - !body_parts.respond_to?(:call) && body_parts.any? && body_parts.all? { |part| part.is_a?(String) } + !@blank && @body.respond_to?(:all?) && @body.all? { |part| part.is_a?(String) } end DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate" def set_conditional_cache_control! - control = cache_control + control = @cache_control if control.empty? headers["Cache-Control"] = DEFAULT_CACHE_CONTROL diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index b317b6dc1a..c2ccd1d3a5 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -72,7 +72,6 @@ module ActionView @response = ActionController::TestResponse.new @params = {} - send(:initialize_current_url) end end diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index 346fa09414..f1c93e6b1e 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -536,7 +536,6 @@ class FragmentCachingTest < ActionController::TestCase @controller.params = @params @controller.request = @request @controller.response = @response - @controller.send(:initialize_current_url) @controller.send(:initialize_template_class, @response) @controller.send(:assign_shortcuts, @request, @response) end -- cgit v1.2.3 From 27e880729eeb058583b79ccf84a7577c434addfd Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Tue, 11 Aug 2009 16:49:27 -0700 Subject: Made benchmarks submodule so it's easier to keep in sync --- actionpack/examples | 1 + actionpack/examples/minimal.rb | 132 ----------------------- actionpack/examples/very_simple.rb | 50 --------- actionpack/examples/views/_collection.erb | 1 - actionpack/examples/views/_hello.erb | 1 - actionpack/examples/views/_hundred_partials.erb | 12 --- actionpack/examples/views/_many_partials.erb | 10 -- actionpack/examples/views/_partial.erb | 10 -- actionpack/examples/views/layouts/alt.html.erb | 1 - actionpack/examples/views/layouts/kaigi.html.erb | 1 - actionpack/examples/views/template.html.erb | 1 - 11 files changed, 1 insertion(+), 219 deletions(-) create mode 160000 actionpack/examples delete mode 100644 actionpack/examples/minimal.rb delete mode 100644 actionpack/examples/very_simple.rb delete mode 100644 actionpack/examples/views/_collection.erb delete mode 100644 actionpack/examples/views/_hello.erb delete mode 100644 actionpack/examples/views/_hundred_partials.erb delete mode 100644 actionpack/examples/views/_many_partials.erb delete mode 100644 actionpack/examples/views/_partial.erb delete mode 100644 actionpack/examples/views/layouts/alt.html.erb delete mode 100644 actionpack/examples/views/layouts/kaigi.html.erb delete mode 100644 actionpack/examples/views/template.html.erb (limited to 'actionpack') diff --git a/actionpack/examples b/actionpack/examples new file mode 160000 index 0000000000..4e1327f06d --- /dev/null +++ b/actionpack/examples @@ -0,0 +1 @@ +Subproject commit 4e1327f06da6df1a1981d69c04e8d6463b38a4c1 diff --git a/actionpack/examples/minimal.rb b/actionpack/examples/minimal.rb deleted file mode 100644 index 62b71de2cb..0000000000 --- a/actionpack/examples/minimal.rb +++ /dev/null @@ -1,132 +0,0 @@ -# Pass NEW=1 to run with the new Base -ENV['RAILS_ENV'] ||= 'production' -ENV['NO_RELOAD'] ||= '1' - -$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib" -$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../activesupport/lib" -require 'action_controller' -require 'action_controller/new_base' if ENV['NEW'] -require 'action_view' -require 'benchmark' - -class Runner - def initialize(app, output) - @app, @output = app, output - end - - def puts(*) - super if @output - end - - def call(env) - env['n'].to_i.times { @app.call(env) } - @app.call(env).tap { |response| report(env, response) } - end - - def report(env, response) - return unless ENV["DEBUG"] - out = env['rack.errors'] - out.puts response[0], response[1].to_yaml, '---' - response[2].each { |part| out.puts part } - out.puts '---' - end - - def self.puts(*) - super if @output - end - - def self.run(app, n, label, output = true) - @output = output - puts label, '=' * label.size if label - env = Rack::MockRequest.env_for("/").merge('n' => n, 'rack.input' => StringIO.new(''), 'rack.errors' => $stdout) - t = Benchmark.realtime { new(app, output).call(env) } - puts "%d ms / %d req = %.1f usec/req" % [10**3 * t, n, 10**6 * t / n] - puts - end -end - - -N = (ENV['N'] || 1000).to_i - -module ActionController::Rails2Compatibility - instance_methods.each do |name| - remove_method name - end -end - -class BasePostController < ActionController::Base - append_view_path "#{File.dirname(__FILE__)}/views" - - def overhead - self.response_body = '' - end - - def index - render :text => '' - end - - def partial - render :partial => "/partial" - end - - def many_partials - render :partial => "/many_partials" - end - - def hundred_partials - render :partial => "/hundred_partials" - end - - def partial_collection - render :partial => "/collection", :collection => [1,2,3,4,5,6,7,8,9,10] - end - - def large_collection - render :partial => "/collection", :collection => (1...1000).to_a - end - - def show_template - render :template => "template" - end -end - -OK = [200, {}, []] -MetalPostController = lambda { OK } - -class HttpPostController < ActionController::Metal - def index - self.response_body = '' - end -end - -ActionController::Base.use_accept_header = false - -unless ENV["PROFILE"] - Runner.run(BasePostController.action(:overhead), 1, 'overhead', false) - Runner.run(BasePostController.action(:index), 1, 'index', false) - Runner.run(BasePostController.action(:show_template), 1, 'template', false) - Runner.run(BasePostController.action(:partial), 1, 'partial', false) - Runner.run(BasePostController.action(:many_partials), 1, 'many_partials', false) - Runner.run(BasePostController.action(:partial_collection), 1, 'collection', false) - Runner.run(BasePostController.action(:hundred_partials), 1, 'hundred_partials', false) - Runner.run(BasePostController.action(:large_collection), 1, 'large_collection', false) - - (ENV["M"] || 1).to_i.times do - Runner.run(BasePostController.action(:overhead), N, 'overhead') - Runner.run(BasePostController.action(:index), N, 'index') - Runner.run(BasePostController.action(:show_template), N, 'template') - Runner.run(BasePostController.action(:partial), N, 'partial') - Runner.run(BasePostController.action(:many_partials), N, 'many_partials') - Runner.run(BasePostController.action(:partial_collection), N, 'collection') - Runner.run(BasePostController.action(:hundred_partials), N, 'hundred_partials') - Runner.run(BasePostController.action(:large_collection), N, 'large_collection') - end -else - Runner.run(BasePostController.action(ENV["PROFILE"].to_sym), 1, ENV["PROFILE"]) - require "ruby-prof" - RubyProf.start - Runner.run(BasePostController.action(ENV["PROFILE"].to_sym), N, ENV["PROFILE"]) - result = RubyProf.stop - printer = RubyProf::CallStackPrinter.new(result) - printer.print(File.open("output.html", "w")) -end \ No newline at end of file diff --git a/actionpack/examples/very_simple.rb b/actionpack/examples/very_simple.rb deleted file mode 100644 index 6714185172..0000000000 --- a/actionpack/examples/very_simple.rb +++ /dev/null @@ -1,50 +0,0 @@ -$:.push "rails/activesupport/lib" -$:.push "rails/actionpack/lib" - -require "action_controller" - -class Kaigi < ActionController::Metal - include AbstractController::Callbacks - include ActionController::RackConvenience - include ActionController::RenderingController - include ActionController::Layouts - include ActionView::Context - - before_filter :set_name - append_view_path "views" - - def view_context - self - end - - def controller - self - end - - DEFAULT_LAYOUT = Object.new.tap {|l| def l.render(*) yield end } - - def render_template(template, layout = DEFAULT_LAYOUT, options = {}, partial = false) - ret = template.render(self, {}) - layout.render(self, {}) { ret } - end - - def index - render :template => "template" - end - - def alt - render :template => "template", :layout => "alt" - end - - private - def set_name - @name = params[:name] - end -end - -app = Rack::Builder.new do - map("/kaigi") { run Kaigi.action(:index) } - map("/kaigi/alt") { run Kaigi.action(:alt) } -end.to_app - -Rack::Handler::Mongrel.run app, :Port => 3000 diff --git a/actionpack/examples/views/_collection.erb b/actionpack/examples/views/_collection.erb deleted file mode 100644 index bcfe958e2c..0000000000 --- a/actionpack/examples/views/_collection.erb +++ /dev/null @@ -1 +0,0 @@ -<%= collection %> \ No newline at end of file diff --git a/actionpack/examples/views/_hello.erb b/actionpack/examples/views/_hello.erb deleted file mode 100644 index 5ab2f8a432..0000000000 --- a/actionpack/examples/views/_hello.erb +++ /dev/null @@ -1 +0,0 @@ -Hello \ No newline at end of file diff --git a/actionpack/examples/views/_hundred_partials.erb b/actionpack/examples/views/_hundred_partials.erb deleted file mode 100644 index 15e99c1b68..0000000000 --- a/actionpack/examples/views/_hundred_partials.erb +++ /dev/null @@ -1,12 +0,0 @@ -<% 10.times do %> - <%= render :partial => '/hello' %> - <%= render :partial => '/hello' %> - <%= render :partial => '/hello' %> - <%= render :partial => '/hello' %> - <%= render :partial => '/hello' %> - <%= render :partial => '/hello' %> - <%= render :partial => '/hello' %> - <%= render :partial => '/hello' %> - <%= render :partial => '/hello' %> - <%= render :partial => '/hello' %> -<% end %> \ No newline at end of file diff --git a/actionpack/examples/views/_many_partials.erb b/actionpack/examples/views/_many_partials.erb deleted file mode 100644 index 7e379d46f5..0000000000 --- a/actionpack/examples/views/_many_partials.erb +++ /dev/null @@ -1,10 +0,0 @@ -<%= render :partial => '/hello' %> -<%= render :partial => '/hello' %> -<%= render :partial => '/hello' %> -<%= render :partial => '/hello' %> -<%= render :partial => '/hello' %> -<%= render :partial => '/hello' %> -<%= render :partial => '/hello' %> -<%= render :partial => '/hello' %> -<%= render :partial => '/hello' %> -<%= render :partial => '/hello' %> \ No newline at end of file diff --git a/actionpack/examples/views/_partial.erb b/actionpack/examples/views/_partial.erb deleted file mode 100644 index 3ca8e80b52..0000000000 --- a/actionpack/examples/views/_partial.erb +++ /dev/null @@ -1,10 +0,0 @@ -<%= "Hello" %> -<%= "Hello" %> -<%= "Hello" %> -<%= "Hello" %> -<%= "Hello" %> -<%= "Hello" %> -<%= "Hello" %> -<%= "Hello" %> -<%= "Hello" %> -<%= "Hello" %> diff --git a/actionpack/examples/views/layouts/alt.html.erb b/actionpack/examples/views/layouts/alt.html.erb deleted file mode 100644 index c4816337a6..0000000000 --- a/actionpack/examples/views/layouts/alt.html.erb +++ /dev/null @@ -1 +0,0 @@ -+ <%= yield %> + \ No newline at end of file diff --git a/actionpack/examples/views/layouts/kaigi.html.erb b/actionpack/examples/views/layouts/kaigi.html.erb deleted file mode 100644 index 274607a96a..0000000000 --- a/actionpack/examples/views/layouts/kaigi.html.erb +++ /dev/null @@ -1 +0,0 @@ -Hello <%= yield %> Goodbye \ No newline at end of file diff --git a/actionpack/examples/views/template.html.erb b/actionpack/examples/views/template.html.erb deleted file mode 100644 index 5ab2f8a432..0000000000 --- a/actionpack/examples/views/template.html.erb +++ /dev/null @@ -1 +0,0 @@ -Hello \ No newline at end of file -- cgit v1.2.3 From ba67e256b8bb3749090fcf7ccaff497ea006b1d1 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Tue, 11 Aug 2009 23:44:44 -0700 Subject: Remove submodule --- actionpack/examples | 1 - 1 file changed, 1 deletion(-) delete mode 160000 actionpack/examples (limited to 'actionpack') diff --git a/actionpack/examples b/actionpack/examples deleted file mode 160000 index 4e1327f06d..0000000000 --- a/actionpack/examples +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4e1327f06da6df1a1981d69c04e8d6463b38a4c1 -- cgit v1.2.3 From 4f9047ecc8f0e2c3d4491bae0051679569da71dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 13 Aug 2009 10:27:41 +0200 Subject: Ensure collections are not treated as nested resources. --- .../lib/action_controller/metal/mime_responds.rb | 5 ++-- .../lib/action_controller/metal/responder.rb | 10 ++++---- actionpack/test/controller/mime_responds_test.rb | 27 ++++++++++++++++------ actionpack/test/lib/controller/fake_models.rb | 12 ++++++---- 4 files changed, 36 insertions(+), 18 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index c8d042acb5..950105e63f 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -226,10 +226,11 @@ module ActionController #:nodoc: # is quite simple (it just needs to respond to call), you can even give # a proc to it. # - def respond_with(resource, options={}, &block) + def respond_with(*resources, &block) respond_to(&block) rescue ActionView::MissingTemplate - (options.delete(:responder) || responder).call(self, resource, options) + options = resources.extract_options! + (options.delete(:responder) || responder).call(self, resources, options) end def responder diff --git a/actionpack/lib/action_controller/metal/responder.rb b/actionpack/lib/action_controller/metal/responder.rb index 9ed99ca623..fc01a0924a 100644 --- a/actionpack/lib/action_controller/metal/responder.rb +++ b/actionpack/lib/action_controller/metal/responder.rb @@ -64,7 +64,7 @@ module ActionController #:nodoc: # @project = Project.find(params[:project_id]) # @task = @project.comments.build(params[:task]) # flash[:notice] = 'Task was successfully created.' if @task.save - # respond_with([@project, @task]) + # respond_with(@project, @task) # end # # Giving an array of resources, you ensure that the responder will redirect to @@ -74,19 +74,19 @@ module ActionController #:nodoc: # polymorphic urls. If a project has one manager which has many tasks, it # should be invoked as: # - # respond_with([@project, :manager, @task]) + # respond_with(@project, :manager, @task) # # Check polymorphic_url documentation for more examples. # class Responder attr_reader :controller, :request, :format, :resource, :resource_location, :options - def initialize(controller, resource, options={}) + def initialize(controller, resources, options={}) @controller = controller @request = controller.request @format = controller.formats.first - @resource = resource.is_a?(Array) ? resource.last : resource - @resource_location = options[:location] || resource + @resource = resources.is_a?(Array) ? resources.last : resources + @resource_location = options[:location] || resources @options = options end diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index 8319b5c573..2e2dba5aae 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -497,8 +497,12 @@ class RespondWithController < ActionController::Base respond_with(Customer.new("david", 13)) end + def using_resource_with_collection + respond_with([Customer.new("david", 13), Customer.new("jamis", 9)]) + end + def using_resource_with_parent - respond_with([Quiz::Store.new("developer?", 11), Customer.new("david", 13)]) + respond_with(Quiz::Store.new("developer?", 11), Customer.new("david", 13)) end def using_resource_with_status_and_location @@ -506,7 +510,7 @@ class RespondWithController < ActionController::Base end def using_resource_with_responder - responder = proc { |c, r, o| c.render :text => "Resource name is #{r.name}" } + responder = proc { |c, r, o| c.render :text => "Resource name is #{r.first.name}" } respond_with(Customer.new("david", 13), :responder => responder) end @@ -592,7 +596,7 @@ class RespondWithControllerTest < ActionController::TestCase @request.accept = "application/xml" get :using_resource assert_equal "application/xml", @response.content_type - assert_equal "XML", @response.body + assert_equal "david", @response.body @request.accept = "application/json" assert_raise ActionView::MissingTemplate do @@ -622,7 +626,7 @@ class RespondWithControllerTest < ActionController::TestCase post :using_resource assert_equal "application/xml", @response.content_type assert_equal 201, @response.status - assert_equal "XML", @response.body + assert_equal "david", @response.body assert_equal "http://www.example.com/customers/13", @response.location errors = { :name => :invalid } @@ -689,7 +693,7 @@ class RespondWithControllerTest < ActionController::TestCase get :using_resource_with_parent assert_equal "application/xml", @response.content_type assert_equal 200, @response.status - assert_equal "XML", @response.body + assert_equal "david", @response.body end def test_using_resource_with_parent_for_post @@ -698,7 +702,7 @@ class RespondWithControllerTest < ActionController::TestCase post :using_resource_with_parent assert_equal "application/xml", @response.content_type assert_equal 201, @response.status - assert_equal "XML", @response.body + assert_equal "david", @response.body assert_equal "http://www.example.com/quiz_stores/11/customers/13", @response.location errors = { :name => :invalid } @@ -710,6 +714,15 @@ class RespondWithControllerTest < ActionController::TestCase assert_nil @response.location end + def test_using_resource_with_collection + @request.accept = "application/xml" + get :using_resource_with_collection + assert_equal "application/xml", @response.content_type + assert_equal 200, @response.status + assert_match /david<\/name>/, @response.body + assert_match /jamis<\/name>/, @response.body + end + def test_clear_respond_to @controller = InheritedRespondWithController.new @request.accept = "text/html" @@ -722,7 +735,7 @@ class RespondWithControllerTest < ActionController::TestCase @request.accept = "*/*" get :index assert_equal "application/xml", @response.content_type - assert_equal "XML", @response.body + assert_equal "david", @response.body end def test_no_double_render_is_raised diff --git a/actionpack/test/lib/controller/fake_models.rb b/actionpack/test/lib/controller/fake_models.rb index 0faf8f3f9a..18eff7516b 100644 --- a/actionpack/test/lib/controller/fake_models.rb +++ b/actionpack/test/lib/controller/fake_models.rb @@ -10,12 +10,16 @@ class Customer < Struct.new(:name, :id) id.to_s end - def to_xml - "XML" + def to_xml(options={}) + if options[:builder] + options[:builder].name name + else + "#{name}" + end end - def to_js - "JS" + def to_js(options={}) + "name: #{name.inspect}" end def errors -- cgit v1.2.3 From 7a26c21d8e853ed648e4668843a3958de4ac5791 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 13 Aug 2009 21:02:49 -0500 Subject: Use safe tmp dir --- actionpack/test/abstract_unit.rb | 2 ++ actionpack/test/tmp/.gitignore | 0 2 files changed, 2 insertions(+) create mode 100644 actionpack/test/tmp/.gitignore (limited to 'actionpack') diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index b062a71442..eb4e2fb585 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -6,6 +6,8 @@ $:.unshift(File.dirname(__FILE__) + '/lib') $:.unshift(File.dirname(__FILE__) + '/fixtures/helpers') $:.unshift(File.dirname(__FILE__) + '/fixtures/alternate_helpers') +ENV['TMPDIR'] = File.join(File.dirname(__FILE__), 'tmp') + ENV['new_base'] = "true" $stderr.puts "Running old tests on new_base" diff --git a/actionpack/test/tmp/.gitignore b/actionpack/test/tmp/.gitignore new file mode 100644 index 0000000000..e69de29bb2 -- cgit v1.2.3 From f86a4b84ddded3fe29184196e4fdd7ffaa4c27ac Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Fri, 14 Aug 2009 14:30:19 -0500 Subject: Kill routing timed tests --- actionpack/test/controller/routing_test.rb | 53 ++---------------------------- 1 file changed, 3 insertions(+), 50 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index 2534c232c7..398e22fd81 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -9,7 +9,6 @@ class MilestonesController < ActionController::Base def rescue_action(e) raise e end end -RunTimeTests = ARGV.include? 'time' ROUTING = ActionController::Routing class ROUTING::RouteBuilder @@ -759,7 +758,7 @@ class LegacyRouteSetTests < Test::Unit::TestCase ActionController::Routing.use_controllers! %w(content admin/user admin/news_feed) end - + def teardown @rs.clear! end @@ -815,52 +814,6 @@ class LegacyRouteSetTests < Test::Unit::TestCase map.resources :pages map.connect ':controller/:action/:id' } - n = 1000 - if RunTimeTests - GC.start - rectime = Benchmark.realtime do - n.times do - rs.recognize_path("/videos/1234567", {:method => :get}) - rs.recognize_path("/videos/1234567/abuse", {:method => :get}) - rs.recognize_path("/users/1234567/settings", {:method => :get}) - rs.recognize_path("/channels/1234567", {:method => :get}) - rs.recognize_path("/session/new", {:method => :get}) - rs.recognize_path("/admin/user/show/10", {:method => :get}) - end - end - puts "\n\nRecognition (#{rs.routes.size} routes):" - per_url = rectime / (n * 6) - puts "#{per_url * 1000} ms/url" - puts "#{1 / per_url} url/s\n\n" - end - end - - def test_time_generation - n = 5000 - if RunTimeTests - GC.start - pairs = [ - [{:controller => 'content', :action => 'index'}, {:controller => 'content', :action => 'show'}], - [{:controller => 'content'}, {:controller => 'content', :action => 'index'}], - [{:controller => 'content', :action => 'list'}, {:controller => 'content', :action => 'index'}], - [{:controller => 'content', :action => 'show', :id => '10'}, {:controller => 'content', :action => 'list'}], - [{:controller => 'admin/user', :action => 'index'}, {:controller => 'admin/user', :action => 'show'}], - [{:controller => 'admin/user'}, {:controller => 'admin/user', :action => 'index'}], - [{:controller => 'admin/user', :action => 'list'}, {:controller => 'admin/user', :action => 'index'}], - [{:controller => 'admin/user', :action => 'show', :id => '10'}, {:controller => 'admin/user', :action => 'list'}], - ] - p = nil - gentime = Benchmark.realtime do - n.times do - pairs.each {|(a, b)| rs.generate(a, b)} - end - end - - puts "\n\nGeneration (RouteSet): (#{(n * 8)} urls)" - per_url = gentime / (n * 8) - puts "#{per_url * 1000} ms/url" - puts "#{1 / per_url} url/s\n\n" - end end def test_route_with_colon_first @@ -2567,10 +2520,10 @@ class RouteLoadingTest < Test::Unit::TestCase routes.reload end - + def test_load_multiple_configurations routes.add_configuration_file("engines.rb") - + File.expects(:stat).at_least_once.returns(@stat) routes.expects(:load).with('./config/routes.rb') -- cgit v1.2.3 From 940a391c9b0aaefa8d1e836332bd46ed74e7a9f4 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Fri, 14 Aug 2009 16:16:29 -0500 Subject: Attempt to rewrite most of the highly coupled router segments tests --- actionpack/test/controller/routing_test.rb | 962 +++++++---------------------- 1 file changed, 221 insertions(+), 741 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index 398e22fd81..000f35e0f2 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -59,590 +59,6 @@ class UriReservedCharactersRoutingTest < Test::Unit::TestCase end end -class SegmentTest < Test::Unit::TestCase - def test_first_segment_should_interpolate_for_structure - s = ROUTING::Segment.new - def s.interpolation_statement(array) 'hello' end - assert_equal 'hello', s.continue_string_structure([]) - end - - def test_interpolation_statement - s = ROUTING::StaticSegment.new("Hello") - assert_equal "Hello", eval(s.interpolation_statement([])) - assert_equal "HelloHello", eval(s.interpolation_statement([s])) - - s2 = ROUTING::StaticSegment.new("-") - assert_equal "Hello-Hello", eval(s.interpolation_statement([s, s2])) - - s3 = ROUTING::StaticSegment.new("World") - assert_equal "Hello-World", eval(s3.interpolation_statement([s, s2])) - end -end - -class StaticSegmentTest < Test::Unit::TestCase - def test_interpolation_chunk_should_respect_raw - s = ROUTING::StaticSegment.new('Hello World') - assert !s.raw? - assert_equal 'Hello%20World', s.interpolation_chunk - - s = ROUTING::StaticSegment.new('Hello World', :raw => true) - assert s.raw? - assert_equal 'Hello World', s.interpolation_chunk - end - - def test_value_should_not_be_double_unescaped - s = ROUTING::StaticSegment.new('%D0%9A%D0%B0%D1%80%D1%82%D0%B0') # Карта - assert_equal '%D0%9A%D0%B0%D1%80%D1%82%D0%B0', s.interpolation_chunk - end - - def test_regexp_chunk_should_escape_specials - s = ROUTING::StaticSegment.new('Hello*World') - assert_equal 'Hello\*World', s.regexp_chunk - - s = ROUTING::StaticSegment.new('HelloWorld') - assert_equal 'HelloWorld', s.regexp_chunk - end - - def test_regexp_chunk_should_add_question_mark_for_optionals - s = ROUTING::StaticSegment.new("/", :optional => true) - assert_equal "/?", s.regexp_chunk - - s = ROUTING::StaticSegment.new("hello", :optional => true) - assert_equal "(?:hello)?", s.regexp_chunk - end -end - -class DynamicSegmentTest < Test::Unit::TestCase - def segment(options = {}) - unless @segment - @segment = ROUTING::DynamicSegment.new(:a, options) - end - @segment - end - - def test_extract_value - s = ROUTING::DynamicSegment.new(:a) - - hash = {:a => '10', :b => '20'} - assert_equal '10', eval(s.extract_value) - - hash = {:b => '20'} - assert_equal nil, eval(s.extract_value) - - s.default = '20' - assert_equal '20', eval(s.extract_value) - end - - def test_default_local_name - assert_equal 'a_value', segment.local_name, - "Unexpected name -- all value_check tests will fail!" - end - - def test_presence_value_check - a_value = 10 - assert eval(segment.value_check) - end - - def test_regexp_value_check_rejects_nil - segment = segment(:regexp => /\d+/) - - a_value = nil - assert !eval(segment.value_check) - end - - def test_optional_regexp_value_check_should_accept_nil - segment = segment(:regexp => /\d+/, :optional => true) - - a_value = nil - assert eval(segment.value_check) - end - - def test_regexp_value_check_rejects_no_match - segment = segment(:regexp => /\d+/) - - a_value = "Hello20World" - assert !eval(segment.value_check) - - a_value = "20Hi" - assert !eval(segment.value_check) - end - - def test_regexp_value_check_accepts_match - segment = segment(:regexp => /\d+/) - a_value = "30" - assert eval(segment.value_check) - end - - def test_value_check_fails_on_nil - a_value = nil - assert ! eval(segment.value_check) - end - - def test_optional_value_needs_no_check - segment = segment(:optional => true) - - a_value = nil - assert_equal nil, segment.value_check - end - - def test_regexp_value_check_should_accept_match_with_default - segment = segment(:regexp => /\d+/, :default => '200') - - a_value = '100' - assert eval(segment.value_check) - end - - def test_expiry_should_not_trigger_once_expired - expired = true - hash = merged = {:a => 2, :b => 3} - options = {:b => 3} - expire_on = Hash.new { raise 'No!!!' } - - eval(segment.expiry_statement) - rescue RuntimeError - flunk "Expiry check should not have occurred!" - end - - def test_expiry_should_occur_according_to_expire_on - expired = false - hash = merged = {:a => 2, :b => 3} - options = {:b => 3} - - expire_on = {:b => true, :a => false} - eval(segment.expiry_statement) - assert !expired - assert_equal({:a => 2, :b => 3}, hash) - - expire_on = {:b => true, :a => true} - eval(segment.expiry_statement) - assert expired - assert_equal({:b => 3}, hash) - end - - def test_extraction_code_should_return_on_nil - hash = merged = {:b => 3} - options = {:b => 3} - a_value = nil - - # Local jump because of return inside eval. - assert_raise(LocalJumpError) { eval(segment.extraction_code) } - end - - def test_extraction_code_should_return_on_mismatch - segment = segment(:regexp => /\d+/) - hash = merged = {:a => 'Hi', :b => '3'} - options = {:b => '3'} - a_value = nil - - # Local jump because of return inside eval. - assert_raise(LocalJumpError) { eval(segment.extraction_code) } - end - - def test_extraction_code_should_accept_value_and_set_local - hash = merged = {:a => 'Hi', :b => '3'} - options = {:b => '3'} - a_value = nil - expired = true - - eval(segment.extraction_code) - assert_equal 'Hi', a_value - end - - def test_extraction_should_work_without_value_check - segment.default = 'hi' - hash = merged = {:b => '3'} - options = {:b => '3'} - a_value = nil - expired = true - - eval(segment.extraction_code) - assert_equal 'hi', a_value - end - - def test_extraction_code_should_perform_expiry - expired = false - hash = merged = {:a => 'Hi', :b => '3'} - options = {:b => '3'} - expire_on = {:a => true} - a_value = nil - - eval(segment.extraction_code) - assert_equal 'Hi', a_value - assert expired - assert_equal options, hash - end - - def test_interpolation_chunk_should_replace_value - a_value = 'Hi' - assert_equal a_value, eval(%("#{segment.interpolation_chunk}")) - end - - def test_interpolation_chunk_should_accept_nil - a_value = nil - assert_equal '', eval(%("#{segment.interpolation_chunk('a_value')}")) - end - - def test_value_regexp_should_be_nil_without_regexp - assert_equal nil, segment.value_regexp - end - - def test_value_regexp_should_match_exacly - segment = segment(:regexp => /\d+/) - assert_no_match segment.value_regexp, "Hello 10 World" - assert_no_match segment.value_regexp, "Hello 10" - assert_no_match segment.value_regexp, "10 World" - assert_match segment.value_regexp, "10" - end - - def test_regexp_chunk_should_return_string - segment = segment(:regexp => /\d+/) - assert_kind_of String, segment.regexp_chunk - end - - def test_build_pattern_non_optional_with_no_captures - # Non optional - a_segment = ROUTING::DynamicSegment.new(nil, :regexp => /\d+/) - assert_equal "(\\d+)stuff", a_segment.build_pattern('stuff') - end - - def test_build_pattern_non_optional_with_captures - # Non optional - a_segment = ROUTING::DynamicSegment.new(nil, :regexp => /(\d+)(.*?)/) - assert_equal "((\\d+)(.*?))stuff", a_segment.build_pattern('stuff') - end - - def test_optionality_implied - a_segment = ROUTING::DynamicSegment.new(:id) - assert a_segment.optionality_implied? - - a_segment = ROUTING::DynamicSegment.new(:action) - assert a_segment.optionality_implied? - end - - def test_modifiers_must_be_handled_sensibly - a_segment = ROUTING::DynamicSegment.new(nil, :regexp => /david|jamis/i) - assert_equal "((?i-mx:david|jamis))stuff", a_segment.build_pattern('stuff') - a_segment = ROUTING::DynamicSegment.new(nil, :regexp => /david|jamis/x) - assert_equal "((?x-mi:david|jamis))stuff", a_segment.build_pattern('stuff') - a_segment = ROUTING::DynamicSegment.new(nil, :regexp => /david|jamis/) - assert_equal "(david|jamis)stuff", a_segment.build_pattern('stuff') - end -end - -class ControllerSegmentTest < Test::Unit::TestCase - def test_regexp_should_only_match_possible_controllers - ActionController::Routing.with_controllers %w(admin/accounts admin/users account pages) do - cs = ROUTING::ControllerSegment.new :controller - regexp = %r{\A#{cs.regexp_chunk}\Z} - - ActionController::Routing.possible_controllers.each do |name| - assert_match regexp, name - assert_no_match regexp, "#{name}_fake" - - match = regexp.match name - assert_equal name, match[1] - end - end - end -end - -class PathSegmentTest < Test::Unit::TestCase - def segment(options = {}) - unless @segment - @segment = ROUTING::PathSegment.new(:path, options) - end - @segment - end - - def test_regexp_chunk_should_return_string - segment = segment(:regexp => /[a-z]+/) - assert_kind_of String, segment.regexp_chunk - end - - def test_regexp_chunk_should_be_wrapped_with_parenthesis - segment = segment(:regexp => /[a-z]+/) - assert_equal "([a-z]+)", segment.regexp_chunk - end - - def test_regexp_chunk_should_respect_options - segment = segment(:regexp => /[a-z]+/i) - assert_equal "((?i-mx:[a-z]+))", segment.regexp_chunk - end -end - -class RouteBuilderTest < Test::Unit::TestCase - def builder - @builder ||= ROUTING::RouteBuilder.new - end - - def build(path, options) - builder.build(path, options) - end - - def test_options_should_not_be_modified - requirements1 = { :id => /\w+/, :controller => /(?:[a-z](?:-?[a-z]+)*)/ } - requirements2 = requirements1.dup - - assert_equal requirements1, requirements2 - - with_options(:controller => 'folder', - :requirements => requirements2) do |m| - m.build 'folders/new', :action => 'new' - end - - assert_equal requirements1, requirements2 - end - - def test_segment_for_static - segment, rest = builder.segment_for 'ulysses' - assert_equal '', rest - assert_kind_of ROUTING::StaticSegment, segment - assert_equal 'ulysses', segment.value - end - - def test_segment_for_action - segment, rest = builder.segment_for ':action' - assert_equal '', rest - assert_kind_of ROUTING::DynamicSegment, segment - assert_equal :action, segment.key - assert_equal 'index', segment.default - end - - def test_segment_for_dynamic - segment, rest = builder.segment_for ':login' - assert_equal '', rest - assert_kind_of ROUTING::DynamicSegment, segment - assert_equal :login, segment.key - assert_equal nil, segment.default - assert ! segment.optional? - end - - def test_segment_for_with_rest - segment, rest = builder.segment_for ':login/:action' - assert_equal :login, segment.key - assert_equal '/:action', rest - segment, rest = builder.segment_for rest - assert_equal '/', segment.value - assert_equal ':action', rest - segment, rest = builder.segment_for rest - assert_equal :action, segment.key - assert_equal '', rest - end - - def test_segments_for - segments = builder.segments_for_route_path '/:controller/:action/:id' - - assert_kind_of ROUTING::DividerSegment, segments[0] - assert_equal '/', segments[2].value - - assert_kind_of ROUTING::DynamicSegment, segments[1] - assert_equal :controller, segments[1].key - - assert_kind_of ROUTING::DividerSegment, segments[2] - assert_equal '/', segments[2].value - - assert_kind_of ROUTING::DynamicSegment, segments[3] - assert_equal :action, segments[3].key - - assert_kind_of ROUTING::DividerSegment, segments[4] - assert_equal '/', segments[4].value - - assert_kind_of ROUTING::DynamicSegment, segments[5] - assert_equal :id, segments[5].key - end - - def test_segment_for_action - s, r = builder.segment_for(':action/something/else') - assert_equal '/something/else', r - assert_equal :action, s.key - end - - def test_action_default_should_not_trigger_on_prefix - s, r = builder.segment_for ':action_name/something/else' - assert_equal '/something/else', r - assert_equal :action_name, s.key - assert_equal nil, s.default - end - - def test_divide_route_options - segments = builder.segments_for_route_path '/cars/:action/:person/:car/' - defaults, requirements = builder.divide_route_options(segments, - :action => 'buy', :person => /\w+/, :car => /\w+/, - :defaults => {:person => nil, :car => nil} - ) - - assert_equal({:action => 'buy', :person => nil, :car => nil}, defaults) - assert_equal({:person => /\w+/, :car => /\w+/}, requirements) - end - - def test_assign_route_options - segments = builder.segments_for_route_path '/cars/:action/:person/:car/' - defaults = {:action => 'buy', :person => nil, :car => nil} - requirements = {:person => /\w+/, :car => /\w+/} - - route_requirements = builder.assign_route_options(segments, defaults, requirements) - assert_equal({}, route_requirements) - - assert_equal :action, segments[3].key - assert_equal 'buy', segments[3].default - - assert_equal :person, segments[5].key - assert_equal %r/\w+/, segments[5].regexp - assert segments[5].optional? - - assert_equal :car, segments[7].key - assert_equal %r/\w+/, segments[7].regexp - assert segments[7].optional? - end - - def test_assign_route_options_with_anchor_chars - segments = builder.segments_for_route_path '/cars/:action/:person/:car/' - defaults = {:action => 'buy', :person => nil, :car => nil} - requirements = {:person => /\w+/, :car => /^\w+$/} - - assert_raise ArgumentError do - route_requirements = builder.assign_route_options(segments, defaults, requirements) - end - - requirements[:car] = /[^\/]+/ - route_requirements = builder.assign_route_options(segments, defaults, requirements) - end - - def test_optional_segments_preceding_required_segments - segments = builder.segments_for_route_path '/cars/:action/:person/:car/' - defaults = {:action => 'buy', :person => nil, :car => "model-t"} - assert builder.assign_route_options(segments, defaults, {}).empty? - - 0.upto(1) { |i| assert !segments[i].optional?, "segment #{i} is optional and it shouldn't be" } - assert segments[2].optional? - - assert_equal nil, builder.warn_output # should only warn on the :person segment - end - - def test_segmentation_of_dot_path - segments = builder.segments_for_route_path '/books/:action.rss' - assert builder.assign_route_options(segments, {}, {}).empty? - assert_equal 6, segments.length # "/", "books", "/", ":action", ".", "rss" - assert !segments.any? { |seg| seg.optional? } - end - - def test_segmentation_of_dynamic_dot_path - segments = builder.segments_for_route_path '/books/:action.:format' - assert builder.assign_route_options(segments, {}, {}).empty? - assert_equal 6, segments.length # "/", "books", "/", ":action", ".", ":format" - assert !segments.any? { |seg| seg.optional? } - assert_kind_of ROUTING::DynamicSegment, segments.last - end - - def test_assignment_of_default_options - segments = builder.segments_for_route_path '/:controller/:action/:id/' - action, id = segments[-4], segments[-2] - - assert_equal :action, action.key - assert_equal :id, id.key - assert ! action.optional? - assert ! id.optional? - - builder.assign_default_route_options(segments) - - assert_equal 'index', action.default - assert action.optional? - assert id.optional? - end - - def test_assignment_of_default_options_respects_existing_defaults - segments = builder.segments_for_route_path '/:controller/:action/:id/' - action, id = segments[-4], segments[-2] - - assert_equal :action, action.key - assert_equal :id, id.key - action.default = 'show' - action.is_optional = true - - id.default = 'Welcome' - id.is_optional = true - - builder.assign_default_route_options(segments) - - assert_equal 'show', action.default - assert action.optional? - assert_equal 'Welcome', id.default - assert id.optional? - end - - def test_assignment_of_default_options_respects_regexps - segments = builder.segments_for_route_path '/:controller/:action/:id/' - action = segments[-4] - - assert_equal :action, action.key - segments[-4] = ROUTING::DynamicSegment.new(:action, :regexp => /show|in/) - - builder.assign_default_route_options(segments) - - assert_equal nil, action.default - assert ! action.optional? - end - - def test_assignment_of_is_optional_when_default - segments = builder.segments_for_route_path '/books/:action.rss' - assert_equal segments[3].key, :action - segments[3].default = 'changes' - builder.ensure_required_segments(segments) - assert ! segments[3].optional? - end - - def test_is_optional_is_assigned_to_default_segments - segments = builder.segments_for_route_path '/books/:action' - builder.assign_route_options(segments, {:action => 'index'}, {}) - - assert_equal segments[3].key, :action - assert segments[3].optional? - assert_kind_of ROUTING::DividerSegment, segments[2] - assert segments[2].optional? - end - - # XXX is optional not being set right? - # /blah/:defaulted_segment <-- is the second slash optional? it should be. - - def test_route_build - ActionController::Routing.with_controllers %w(users pages) do - r = builder.build '/:controller/:action/:id/', :action => nil - - [0, 2, 4].each do |i| - assert_kind_of ROUTING::DividerSegment, r.segments[i] - assert_equal '/', r.segments[i].value - assert r.segments[i].optional? if i > 1 - end - - assert_kind_of ROUTING::DynamicSegment, r.segments[1] - assert_equal :controller, r.segments[1].key - assert_equal nil, r.segments[1].default - - assert_kind_of ROUTING::DynamicSegment, r.segments[3] - assert_equal :action, r.segments[3].key - assert_equal 'index', r.segments[3].default - - assert_kind_of ROUTING::DynamicSegment, r.segments[5] - assert_equal :id, r.segments[5].key - assert r.segments[5].optional? - end - end - - def test_slashes_are_implied - routes = [ - builder.build('/:controller/:action/:id/', :action => nil), - builder.build('/:controller/:action/:id', :action => nil), - builder.build(':controller/:action/:id', :action => nil), - builder.build('/:controller/:action/:id/', :action => nil) - ] - expected = routes.first.segments.length - routes.each_with_index do |route, i| - found = route.segments.length - assert_equal expected, found, "Route #{i + 1} has #{found} segments, expected #{expected}" - end - end -end - class RoutingTest < Test::Unit::TestCase def test_possible_controllers true_controller_paths = ActionController::Routing.controller_paths @@ -1091,8 +507,7 @@ class LegacyRouteSetTests < Test::Unit::TestCase map.connect '*path', :controller => 'content', :action => 'show_file' end - recall_path = ActionController::Routing::PathSegment::Result.new(%w(pages boo)) - assert_equal '/pages/boo', rs.generate({}, :controller => 'content', :action => 'show_file', :path => recall_path) + assert_equal '/pages/boo', rs.generate({}, :controller => 'content', :action => 'show_file', :path => %w(pages boo)) end def test_backwards @@ -1408,161 +823,6 @@ class LegacyRouteSetTests < Test::Unit::TestCase end end -class RouteTest < Test::Unit::TestCase - def setup - @route = ROUTING::Route.new - end - - def slash_segment(is_optional = false) - ROUTING::DividerSegment.new('/', :optional => is_optional) - end - - def default_route - unless defined?(@default_route) - segments = [] - segments << ROUTING::StaticSegment.new('/', :raw => true) - segments << ROUTING::DynamicSegment.new(:controller) - segments << slash_segment(:optional) - segments << ROUTING::DynamicSegment.new(:action, :default => 'index', :optional => true) - segments << slash_segment(:optional) - segments << ROUTING::DynamicSegment.new(:id, :optional => true) - segments << slash_segment(:optional) - @default_route = ROUTING::Route.new(segments).freeze - end - @default_route - end - - def test_default_route_recognition - expected = {:controller => 'accounts', :action => 'show', :id => '10'} - assert_equal expected, default_route.recognize('/accounts/show/10') - assert_equal expected, default_route.recognize('/accounts/show/10/') - - expected[:id] = 'jamis' - assert_equal expected, default_route.recognize('/accounts/show/jamis/') - - expected.delete :id - assert_equal expected, default_route.recognize('/accounts/show') - assert_equal expected, default_route.recognize('/accounts/show/') - - expected[:action] = 'index' - assert_equal expected, default_route.recognize('/accounts/') - assert_equal expected, default_route.recognize('/accounts') - - assert_equal nil, default_route.recognize('/') - assert_equal nil, default_route.recognize('/accounts/how/goood/it/is/to/be/free') - end - - def test_default_route_should_omit_default_action - o = {:controller => 'accounts', :action => 'index'} - assert_equal '/accounts', default_route.generate(o, o, {}) - end - - def test_default_route_should_include_default_action_when_id_present - o = {:controller => 'accounts', :action => 'index', :id => '20'} - assert_equal '/accounts/index/20', default_route.generate(o, o, {}) - end - - def test_default_route_should_work_with_action_but_no_id - o = {:controller => 'accounts', :action => 'list_all'} - assert_equal '/accounts/list_all', default_route.generate(o, o, {}) - end - - def test_default_route_should_uri_escape_pluses - expected = { :controller => 'accounts', :action => 'show', :id => 'hello world' } - assert_equal expected, default_route.recognize('/accounts/show/hello world') - assert_equal expected, default_route.recognize('/accounts/show/hello%20world') - assert_equal '/accounts/show/hello%20world', default_route.generate(expected, expected, {}) - - expected[:id] = 'hello+world' - assert_equal expected, default_route.recognize('/accounts/show/hello+world') - assert_equal expected, default_route.recognize('/accounts/show/hello%2Bworld') - assert_equal '/accounts/show/hello+world', default_route.generate(expected, expected, {}) - end - - def test_matches_controller_and_action - # requirement_for should only be called for the action and controller _once_ - @route.expects(:requirement_for).with(:controller).times(1).returns('pages') - @route.expects(:requirement_for).with(:action).times(1).returns('show') - - @route.requirements = {:controller => 'pages', :action => 'show'} - assert @route.matches_controller_and_action?('pages', 'show') - assert !@route.matches_controller_and_action?('not_pages', 'show') - assert !@route.matches_controller_and_action?('pages', 'not_show') - end - - def test_parameter_shell - page_url = ROUTING::Route.new - page_url.requirements = {:controller => 'pages', :action => 'show', :id => /\d+/} - assert_equal({:controller => 'pages', :action => 'show'}, page_url.parameter_shell) - end - - def test_defaults - route = ROUTING::RouteBuilder.new.build '/users/:id.:format', :controller => "users", :action => "show", :format => "html" - assert_equal( - { :controller => "users", :action => "show", :format => "html" }, - route.defaults) - end - - def test_builder_complains_without_controller - assert_raise(ArgumentError) do - ROUTING::RouteBuilder.new.build '/contact', :contoller => "contact", :action => "index" - end - end - - def test_significant_keys_for_default_route - keys = default_route.significant_keys.sort_by {|k| k.to_s } - assert_equal [:action, :controller, :id], keys - end - - def test_significant_keys - segments = [] - segments << ROUTING::StaticSegment.new('/', :raw => true) - segments << ROUTING::StaticSegment.new('user') - segments << ROUTING::StaticSegment.new('/', :raw => true, :optional => true) - segments << ROUTING::DynamicSegment.new(:user) - segments << ROUTING::StaticSegment.new('/', :raw => true, :optional => true) - - requirements = {:controller => 'users', :action => 'show'} - - user_url = ROUTING::Route.new(segments, requirements) - keys = user_url.significant_keys.sort_by { |k| k.to_s } - assert_equal [:action, :controller, :user], keys - end - - def test_build_empty_query_string - assert_equal '', @route.build_query_string({}) - end - - def test_build_query_string_with_nil_value - assert_equal '', @route.build_query_string({:x => nil}) - end - - def test_simple_build_query_string - assert_equal '?x=1&y=2', order_query_string(@route.build_query_string(:x => '1', :y => '2')) - end - - def test_convert_ints_build_query_string - assert_equal '?x=1&y=2', order_query_string(@route.build_query_string(:x => 1, :y => 2)) - end - - def test_escape_spaces_build_query_string - assert_equal '?x=hello+world&y=goodbye+world', order_query_string(@route.build_query_string(:x => 'hello world', :y => 'goodbye world')) - end - - def test_expand_array_build_query_string - assert_equal '?x%5B%5D=1&x%5B%5D=2', order_query_string(@route.build_query_string(:x => [1, 2])) - end - - def test_escape_spaces_build_query_string_selected_keys - assert_equal '?x=hello+world', order_query_string(@route.build_query_string({:x => 'hello world', :y => 'goodbye world'}, [:x])) - end - - private - def order_query_string(qs) - '?' + qs[1..-1].split('&').sort.join('&') - end -end - class RouteSetTest < ActiveSupport::TestCase def set @set ||= ROUTING::RouteSet.new @@ -1572,6 +832,19 @@ class RouteSetTest < ActiveSupport::TestCase @request ||= ActionController::TestRequest.new end + def default_route_set + @default_route_set ||= begin + set = nil + ActionController::Routing.with_controllers(['accounts']) do + set = ROUTING::RouteSet.new + set.draw do |map| + map.connect '/:controller/:action/:id/' + end + end + set + end + end + def test_generate_extras set.draw { |m| m.connect ':controller/:action/:id' } path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world") @@ -2457,6 +1730,213 @@ class RouteSetTest < ActiveSupport::TestCase assert_equal({:controller => 'pages', :action => 'show', :name => :as_symbol}, set.recognize_path('/named')) end + + def test_interpolation_chunk_should_respect_raw + ActionController::Routing.with_controllers(['hello']) do + set.draw do |map| + map.connect '/Hello World', :controller => 'hello' + end + + assert_equal '/Hello%20World', set.generate(:controller => 'hello') + assert_equal({:controller => "hello", :action => "index"}, set.recognize_path('/Hello World')) + assert_raise(ActionController::RoutingError) { set.recognize_path('/Hello%20World') } + end + end + + def test_value_should_not_be_double_unescaped + ActionController::Routing.with_controllers(['foo']) do + set.draw do |map| + map.connect '/Карта', :controller => 'foo' + end + + assert_equal '/%D0%9A%D0%B0%D1%80%D1%82%D0%B0', set.generate(:controller => 'foo') + assert_equal({:controller => "foo", :action => "index"}, set.recognize_path('/Карта')) + assert_raise(ActionController::RoutingError) { set.recognize_path('/%D0%9A%D0%B0%D1%80%D1%82%D0%B0') } + end + end + + def test_regexp_chunk_should_escape_specials + ActionController::Routing.with_controllers(['foo', 'bar']) do + set.draw do |map| + map.connect '/Hello*World', :controller => 'foo' + map.connect '/HelloWorld', :controller => 'bar' + end + + assert_equal '/Hello*World', set.generate(:controller => 'foo') + assert_equal '/HelloWorld', set.generate(:controller => 'bar') + + assert_equal({:controller => "foo", :action => "index"}, set.recognize_path('/Hello*World')) + assert_equal({:controller => "bar", :action => "index"}, set.recognize_path('/HelloWorld')) + end + end + + def test_regexp_chunk_should_add_question_mark_for_optionals + ActionController::Routing.with_controllers(['foo', 'bar']) do + set.draw do |map| + map.connect '/', :controller => 'foo' + map.connect '/hello', :controller => 'bar' + end + + assert_equal '/', set.generate(:controller => 'foo') + assert_equal '/hello', set.generate(:controller => 'bar') + + assert_equal({:controller => "foo", :action => "index"}, set.recognize_path('/')) + assert_equal({:controller => "bar", :action => "index"}, set.recognize_path('/hello')) + end + end + + def test_assign_route_options_with_anchor_chars + ActionController::Routing.with_controllers(['cars']) do + set.draw do |map| + map.connect '/cars/:action/:person/:car/', :controller => 'cars' + end + + assert_equal '/cars/buy/1/2', set.generate(:controller => 'cars', :action => 'buy', :person => '1', :car => '2') + + assert_equal({:controller => "cars", :action => "buy", :person => "1", :car => "2"}, set.recognize_path('/cars/buy/1/2')) + end + end + + def test_segmentation_of_dot_path + ActionController::Routing.with_controllers(['books']) do + set.draw do |map| + map.connect '/books/:action.rss', :controller => 'books' + end + + assert_equal '/books/list.rss', set.generate(:controller => 'books', :action => 'list') + + assert_equal({:controller => "books", :action => "list"}, set.recognize_path('/books/list.rss')) + end + end + + def test_segmentation_of_dynamic_dot_path + ActionController::Routing.with_controllers(['books']) do + set.draw do |map| + map.connect '/books/:action.:format', :controller => 'books' + end + + assert_equal '/books/list.rss', set.generate(:controller => 'books', :action => 'list', :format => 'rss') + assert_equal '/books/list.xml', set.generate(:controller => 'books', :action => 'list', :format => 'xml') + assert_equal '/books/list', set.generate(:controller => 'books', :action => 'list') + assert_equal '/books', set.generate(:controller => 'books', :action => 'index') + + assert_equal({:controller => "books", :action => "list", :format => "rss"}, set.recognize_path('/books/list.rss')) + assert_equal({:controller => "books", :action => "list", :format => "xml"}, set.recognize_path('/books/list.xml')) + assert_equal({:controller => "books", :action => "list"}, set.recognize_path('/books/list')) + assert_equal({:controller => "books", :action => "index"}, set.recognize_path('/books')) + end + end + + def test_slashes_are_implied + ActionController::Routing.with_controllers(['foo']) do + ['/:controller/:action/:id/', '/:controller/:action/:id', + ':controller/:action/:id', '/:controller/:action/:id/' + ].each do |path| + @set = nil + set.draw { |map| map.connect(path) } + + assert_equal '/foo', set.generate(:controller => 'foo', :action => 'index') + assert_equal '/foo/list', set.generate(:controller => 'foo', :action => 'list') + assert_equal '/foo/show/1', set.generate(:controller => 'foo', :action => 'show', :id => '1') + + assert_equal({:controller => "foo", :action => "index"}, set.recognize_path('/foo')) + assert_equal({:controller => "foo", :action => "index"}, set.recognize_path('/foo/index')) + assert_equal({:controller => "foo", :action => "list"}, set.recognize_path('/foo/list')) + assert_equal({:controller => "foo", :action => "show", :id => "1"}, set.recognize_path('/foo/show/1')) + end + end + end + + def test_default_route_recognition + expected = {:controller => 'accounts', :action => 'show', :id => '10'} + assert_equal expected, default_route_set.recognize_path('/accounts/show/10') + assert_equal expected, default_route_set.recognize_path('/accounts/show/10/') + + expected[:id] = 'jamis' + assert_equal expected, default_route_set.recognize_path('/accounts/show/jamis/') + + expected.delete :id + assert_equal expected, default_route_set.recognize_path('/accounts/show') + assert_equal expected, default_route_set.recognize_path('/accounts/show/') + + expected[:action] = 'index' + assert_equal expected, default_route_set.recognize_path('/accounts/') + assert_equal expected, default_route_set.recognize_path('/accounts') + + assert_raise(ActionController::RoutingError) { default_route_set.recognize_path('/') } + assert_raise(ActionController::RoutingError) { default_route_set.recognize_path('/accounts/how/goood/it/is/to/be/free') } + end + + def test_default_route_should_omit_default_action + assert_equal '/accounts', default_route_set.generate({:controller => 'accounts', :action => 'index'}) + end + + def test_default_route_should_include_default_action_when_id_present + assert_equal '/accounts/index/20', default_route_set.generate({:controller => 'accounts', :action => 'index', :id => '20'}) + end + + def test_default_route_should_work_with_action_but_no_id + assert_equal '/accounts/list_all', default_route_set.generate({:controller => 'accounts', :action => 'list_all'}) + end + + def test_default_route_should_uri_escape_pluses + expected = { :controller => 'accounts', :action => 'show', :id => 'hello world' } + assert_equal expected, default_route_set.recognize_path('/accounts/show/hello world') + assert_equal expected, default_route_set.recognize_path('/accounts/show/hello%20world') + assert_equal '/accounts/show/hello%20world', default_route_set.generate(expected, expected) + + expected[:id] = 'hello+world' + assert_equal expected, default_route_set.recognize_path('/accounts/show/hello+world') + assert_equal expected, default_route_set.recognize_path('/accounts/show/hello%2Bworld') + assert_equal '/accounts/show/hello+world', default_route_set.generate(expected, expected) + end + + def test_parameter_shell + page_url = ROUTING::Route.new + page_url.requirements = {:controller => 'pages', :action => 'show', :id => /\d+/} + assert_equal({:controller => 'pages', :action => 'show'}, page_url.parameter_shell) + end + + def test_defaults + route = ROUTING::RouteBuilder.new.build '/users/:id.:format', :controller => "users", :action => "show", :format => "html" + assert_equal( + { :controller => "users", :action => "show", :format => "html" }, + route.defaults) + end + + def test_builder_complains_without_controller + assert_raise(ArgumentError) do + ROUTING::RouteBuilder.new.build '/contact', :contoller => "contact", :action => "index" + end + end + + def test_build_empty_query_string + assert_equal '/foo', default_route_set.generate({:controller => 'foo'}) + end + + def test_build_query_string_with_nil_value + assert_equal '/foo', default_route_set.generate({:controller => 'foo', :x => nil}) + end + + def test_simple_build_query_string + assert_equal '/foo?x=1&y=2', default_route_set.generate({:controller => 'foo', :x => '1', :y => '2'}) + end + + def test_convert_ints_build_query_string + assert_equal '/foo?x=1&y=2', default_route_set.generate({:controller => 'foo', :x => 1, :y => 2}) + end + + def test_escape_spaces_build_query_string + assert_equal '/foo?x=hello+world&y=goodbye+world', default_route_set.generate({:controller => 'foo', :x => 'hello world', :y => 'goodbye world'}) + end + + def test_expand_array_build_query_string + assert_equal '/foo?x%5B%5D=1&x%5B%5D=2', default_route_set.generate({:controller => 'foo', :x => [1, 2]}) + end + + def test_escape_spaces_build_query_string_selected_keys + assert_equal '/foo?x=hello+world', default_route_set.generate({:controller => 'foo', :x => 'hello world'}) + end end class RouteLoadingTest < Test::Unit::TestCase -- cgit v1.2.3 From 27adcd1c1a5cc566cfa8c5f8268b65ef01a7e865 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Tue, 11 Aug 2009 15:02:05 -0700 Subject: Clean up ActionView some: * Call _evaluate_assigns_and_ivars at the two entry points so we don't have to do a check at every render. * Make template.render viable without having to go through a wrapper method * Remove old TemplateHandler#render(template, local_assigns) path so we don't have to set self.template every time we render a template. * Move Template rescuing code to Template#render so it gets caught every time. * Pull in some tests from Pratik that test render @object in ActionView --- actionpack/lib/action_view/base.rb | 16 ------- actionpack/lib/action_view/render/partials.rb | 6 ++- actionpack/lib/action_view/render/rendering.rb | 61 ++++++++----------------- actionpack/lib/action_view/template/handler.rb | 2 +- actionpack/lib/action_view/template/template.rb | 12 ++++- actionpack/test/template/render_test.rb | 34 +++++++++----- 6 files changed, 56 insertions(+), 75 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index c171a5a8f5..edfd1fd71c 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -255,15 +255,6 @@ module ActionView #:nodoc: @view_paths = self.class.process_view_paths(paths) end - def with_template(current_template) - _evaluate_assigns_and_ivars - last_template, self.template = template, current_template - last_formats, self.formats = formats, current_template.formats - yield - ensure - self.template, self.formats = last_template, last_formats - end - def punctuate_body!(part) flush_output_buffer response.body_parts << part @@ -272,18 +263,11 @@ module ActionView #:nodoc: # Evaluates the local assigns and controller ivars, pushes them to the view. def _evaluate_assigns_and_ivars #:nodoc: - @assigns_added ||= _copy_ivars_from_controller - end - - private - - def _copy_ivars_from_controller #:nodoc: if @controller variables = @controller.instance_variable_names variables -= @controller.protected_instance_variables if @controller.respond_to?(:protected_instance_variables) variables.each { |name| instance_variable_set(name, @controller.instance_variable_get(name)) } end - true end end diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb index 83175ab4cf..e287021eb1 100644 --- a/actionpack/lib/action_view/render/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -265,7 +265,9 @@ module ActionView @locals[:object] = @locals[template.variable_name] = object @locals[@options[:as]] = object if @options[:as] - content = @view._render_single_template(template, @locals, &@block) + content = template.render(@view, @locals) do |*names| + @view._layout_for(names, &@block) + end return content if @block || !@options[:layout] find_template(@options[:layout]).render(@view, @locals) { content } end @@ -302,7 +304,7 @@ module ActionView end def render_partial(options) - @assigns_added = false + _evaluate_assigns_and_ivars # TODO: Handle other details here. self.formats = options[:_details][:formats] if options[:_details] _render_partial(options) diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index c7afc56e3b..e505fe6c8c 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -12,8 +12,6 @@ module ActionView # as the locals hash. def render(options = {}, locals = {}, &block) #:nodoc: case options - when String, NilClass - _render_partial(:partial => options, :locals => locals || {}) when Hash layout = options[:layout] @@ -35,26 +33,8 @@ module ActionView end when :update update_page(&block) - end - end - - def _render_content(content, layout, locals) - return content unless layout - - locals ||= {} - - if controller && layout - @_layout = layout.identifier - logger.info("Rendering template within #{layout.identifier}") if logger - end - - begin - old_content, @_content_for[:layout] = @_content_for[:layout], content - - @cached_content_for_layout = @_content_for[:layout] - _render_single_template(layout, locals) - ensure - @_content_for[:layout] = old_content + else + _render_partial(:partial => options, :locals => locals) end end @@ -108,30 +88,17 @@ module ActionView end end - def _render_single_template(template, locals = {}, &block) - with_template(template) do - template.render(self, locals) do |*names| - _layout_for(names, &block) - end - end - rescue Exception => e - if e.is_a?(TemplateError) - e.sub_template_of(template) - raise e - else - raise TemplateError.new(template, assigns, e) - end - end - def _render_inline(inline, layout, options) handler = Template.handler_class_for_extension(options[:type] || "erb") template = Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {}) - content = _render_single_template(template, options[:locals] || {}) - layout ? _render_content(content, layout, options[:locals]) : content + locals = options[:locals] || {} + content = template.render(self, locals) + content = layout.render(self, locals) { content } if layout + content end def _render_text(text, layout, options) - layout ? _render_content(text, layout, options[:locals]) : text + text = layout.render(self, options[:locals]) { text } if layout end # This is the API to render a ViewContext's template from a controller. @@ -141,7 +108,7 @@ module ActionView # _layout:: The layout, if any, to wrap the Template in # _partial:: true if the template is a partial def render_template(options) - @assigns_added = nil + _evaluate_assigns_and_ivars template, layout, partial = options.values_at(:_template, :_layout, :_partial) _render_template(template, layout, options, partial) end @@ -158,10 +125,18 @@ module ActionView content = if partial _render_partial_object(template, options) else - _render_single_template(template, locals) + template.render(self, locals) end - _render_content(content, layout, locals) + @cached_content_for_layout = content + @_content_for[:layout] = content + + if layout + @_layout = layout.identifier + logger.info("Rendering template within #{layout.identifier}") if logger + content = layout.render(self, locals) + end + content end end end \ No newline at end of file diff --git a/actionpack/lib/action_view/template/handler.rb b/actionpack/lib/action_view/template/handler.rb index 3071c78174..7311e5e12f 100644 --- a/actionpack/lib/action_view/template/handler.rb +++ b/actionpack/lib/action_view/template/handler.rb @@ -26,7 +26,7 @@ module ActionView self.default_format = Mime::HTML def self.call(template) - "#{name}.new(self).render(template, local_assigns)" + raise "Need to implement #{self.class.name}#call(template)" end def initialize(view = nil) diff --git a/actionpack/lib/action_view/template/template.rb b/actionpack/lib/action_view/template/template.rb index 33d3f79ad3..f6270e5616 100644 --- a/actionpack/lib/action_view/template/template.rb +++ b/actionpack/lib/action_view/template/template.rb @@ -26,9 +26,17 @@ module ActionView @details[:formats] = Array.wrap(format.to_sym) end - def render(view, locals, &blk) + def render(view, locals, &block) method_name = compile(locals, view) - view.send(method_name, locals, &blk) + block ||= proc {|*names| view._layout_for(names) } + view.send(method_name, locals, &block) + rescue Exception => e + if e.is_a?(TemplateError) + e.sub_template_of(self) + raise e + else + raise TemplateError.new(self, view.assigns, e) + end end # TODO: Figure out how to abstract this diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 7f30ae88a1..50074b3b9d 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -2,10 +2,14 @@ require 'abstract_unit' require 'controller/fake_models' +class TestController < ActionController::Base +end + module RenderTestCases def setup_view(paths) @assigns = { :secret => 'in the sauce' } @view = ActionView::Base.new(paths, @assigns) + @controller_view = ActionView::Base.for_controller(TestController.new) # Reload and register danish language for testing I18n.reload! @@ -158,6 +162,25 @@ module RenderTestCases assert_nil @view.render(:partial => []) end + def test_render_partial_using_string + assert_equal "Hello: Anonymous", @controller_view.render('customer') + end + + def test_render_partial_with_locals_using_string + assert_equal "Hola: david", @controller_view.render('customer_greeting', :greeting => 'Hola', :customer_greeting => Customer.new("david")) + end + + def test_render_partial_using_object + assert_equal "Hello: lifo", + @controller_view.render(Customer.new("lifo"), :greeting => "Hello") + end + + def test_render_partial_using_collection + customers = [ Customer.new("Amazon"), Customer.new("Yahoo") ] + assert_equal "Hello: AmazonHello: Yahoo", + @controller_view.render(customers, :greeting => "Hello") + end + # TODO: The reason for this test is unclear, improve documentation def test_render_partial_and_fallback_to_layout assert_equal "Before (Josh)\n\nAfter", @view.render(:partial => "test/layout_for_partial", :locals => { :name => "Josh" }) @@ -196,17 +219,6 @@ module RenderTestCases assert_equal 'source: "Hello, <%= name %>!"', @view.render(:inline => "Hello, <%= name %>!", :locals => { :name => "Josh" }, :type => :foo) end - class LegacyHandler < ActionView::TemplateHandler - def render(template, local_assigns) - "source: #{template.source}; locals: #{local_assigns.inspect}" - end - end - - def test_render_legacy_handler_with_custom_type - ActionView::Template.register_template_handler :foo, LegacyHandler - assert_equal 'source: Hello, <%= name %>!; locals: {:name=>"Josh"}', @view.render(:inline => "Hello, <%= name %>!", :locals => { :name => "Josh" }, :type => :foo) - end - def test_render_ignores_templates_with_malformed_template_handlers %w(malformed malformed.erb malformed.html.erb malformed.en.html.erb).each do |name| assert_raise(ActionView::MissingTemplate) { @view.render(:file => "test/malformed/#{name}") } -- cgit v1.2.3 From 9f5cd0156ab907d8097fc9c588823a9b09038b93 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Tue, 11 Aug 2009 23:43:15 -0700 Subject: More cleanup of ActionView and reduction in need for blocks in some cases: * only one of partial_name or :as will be available as a local * `object` is removed * Simplify _layout_for in most cases. * Remove <% render :partial do |args| %> * <% render :partial do %> still works fine --- actionpack/lib/action_view/render/partials.rb | 13 +++++-------- actionpack/lib/action_view/render/rendering.rb | 22 ++++++---------------- actionpack/lib/action_view/template/handler.rb | 4 ---- actionpack/lib/action_view/template/template.rb | 1 - actionpack/test/controller/render_test.rb | 9 --------- .../test/fixtures/test/_customer_with_var.erb | 2 +- actionpack/test/fixtures/test/_hash_object.erb | 2 +- .../using_layout_around_block_with_args.html.erb | 1 - actionpack/test/template/render_test.rb | 2 +- 9 files changed, 14 insertions(+), 42 deletions(-) delete mode 100644 actionpack/test/fixtures/test/using_layout_around_block_with_args.html.erb (limited to 'actionpack') diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb index e287021eb1..188f0d0214 100644 --- a/actionpack/lib/action_view/render/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -223,16 +223,14 @@ module ActionView def collection_with_template(template) options = @options - segments, locals, as = [], @locals, options[:as] || :object + segments, locals, as = [], @locals, options[:as] || template.variable_name - variable_name = template.variable_name counter_name = template.counter_name locals[counter_name] = -1 collection.each do |object| locals[counter_name] += 1 - locals[variable_name] = object - locals[as] = object if as + locals[as] = object segments << template.render(@view, locals) end @@ -242,14 +240,13 @@ module ActionView def collection_without_template options = @options - segments, locals, as = [], @locals, options[:as] || :object + segments, locals, as = [], @locals, options[:as] index, template = -1, nil collection.each do |object| template = find_template(partial_path(object)) locals[template.counter_name] = (index += 1) locals[template.variable_name] = object - locals[as] = object if as segments << template.render(@view, locals) end @@ -265,8 +262,8 @@ module ActionView @locals[:object] = @locals[template.variable_name] = object @locals[@options[:as]] = object if @options[:as] - content = template.render(@view, @locals) do |*names| - @view._layout_for(names, &@block) + content = template.render(@view, @locals) do |*name| + @view._layout_for(*name, &@block) end return content if @block || !@options[:layout] find_template(@options[:layout]).render(@view, @locals) { content } diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index e505fe6c8c..e04800e6e8 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -70,21 +70,11 @@ module ActionView # In this case, the layout would receive the block passed into render :layout, # and the Struct specified in the layout would be passed into the block. The result # would be Hello David. - def _layout_for(names, &block) + def _layout_for(name = nil) + return @_content_for[name || :layout] if !block_given? || name + with_output_buffer do - # This is due to the potentially ambiguous use of yield when - # a block is passed in to a template *and* there is a content_for() - # of the same name. Suggested solution: require explicit use of content_for - # in these ambiguous cases. - # - # We would be able to continue supporting yield in all non-ambiguous - # cases. Question: should we deprecate yield in favor of content_for - # and reserve yield for cases where there is a yield into a real block? - if @_content_for.key?(names.first) || !block_given? - return @_content_for[names.first || :layout] - else - return yield(names) - end + return yield end end @@ -93,7 +83,7 @@ module ActionView template = Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {}) locals = options[:locals] || {} content = template.render(self, locals) - content = layout.render(self, locals) { content } if layout + content = layout.render(self, locals) {|*name| _layout_for(*name) } if layout content end @@ -134,7 +124,7 @@ module ActionView if layout @_layout = layout.identifier logger.info("Rendering template within #{layout.identifier}") if logger - content = layout.render(self, locals) + content = layout.render(self, locals) {|*name| _layout_for(*name) } end content end diff --git a/actionpack/lib/action_view/template/handler.rb b/actionpack/lib/action_view/template/handler.rb index 7311e5e12f..4bf58b9fa8 100644 --- a/actionpack/lib/action_view/template/handler.rb +++ b/actionpack/lib/action_view/template/handler.rb @@ -29,10 +29,6 @@ module ActionView raise "Need to implement #{self.class.name}#call(template)" end - def initialize(view = nil) - @view = view - end - def render(template, local_assigns) raise "Need to implement #{self.class.name}#render(template, local_assigns)" end diff --git a/actionpack/lib/action_view/template/template.rb b/actionpack/lib/action_view/template/template.rb index f6270e5616..8f23f9b9e3 100644 --- a/actionpack/lib/action_view/template/template.rb +++ b/actionpack/lib/action_view/template/template.rb @@ -28,7 +28,6 @@ module ActionView def render(view, locals, &block) method_name = compile(locals, view) - block ||= proc {|*names| view._layout_for(names) } view.send(method_name, locals, &block) rescue Exception => e if e.is_a?(TemplateError) diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 0c0599679c..9c5b560c2c 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -486,10 +486,6 @@ class TestController < ActionController::Base render :action => "using_layout_around_block" end - def render_using_layout_around_block_with_args - render :action => "using_layout_around_block_with_args" - end - def render_using_layout_around_block_in_main_layout_and_within_content_for_layout render :action => "using_layout_around_block", :layout => "layouts/block_with_layout" end @@ -1161,11 +1157,6 @@ class RenderTest < ActionController::TestCase assert_equal "Before (Anthony)\nInside from first block in layout\nAfter\nBefore (David)\nInside from block\nAfter\nBefore (Ramm)\nInside from second block in layout\nAfter\n", @response.body end - def test_using_layout_around_block_with_args - get :render_using_layout_around_block_with_args - assert_equal "Before\narg1arg2\nAfter", @response.body - end - def test_partial_only get :partial_only assert_equal "only partial", @response.body diff --git a/actionpack/test/fixtures/test/_customer_with_var.erb b/actionpack/test/fixtures/test/_customer_with_var.erb index c28824936b..00047dd20e 100644 --- a/actionpack/test/fixtures/test/_customer_with_var.erb +++ b/actionpack/test/fixtures/test/_customer_with_var.erb @@ -1 +1 @@ -<%= customer.name %> <%= customer.name %> <%= customer_with_var.name %> \ No newline at end of file +<%= customer.name %> <%= customer.name %> <%= customer.name %> \ No newline at end of file diff --git a/actionpack/test/fixtures/test/_hash_object.erb b/actionpack/test/fixtures/test/_hash_object.erb index 55c03afb27..34a92c6a56 100644 --- a/actionpack/test/fixtures/test/_hash_object.erb +++ b/actionpack/test/fixtures/test/_hash_object.erb @@ -1,2 +1,2 @@ <%= hash_object[:first_name] %> -<%= object[:first_name].reverse %> +<%= hash_object[:first_name].reverse %> diff --git a/actionpack/test/fixtures/test/using_layout_around_block_with_args.html.erb b/actionpack/test/fixtures/test/using_layout_around_block_with_args.html.erb deleted file mode 100644 index 71b1f30ad0..0000000000 --- a/actionpack/test/fixtures/test/using_layout_around_block_with_args.html.erb +++ /dev/null @@ -1 +0,0 @@ -<% render(:layout => "layout_for_block_with_args") do |*args| %><%= args.join %><% end %> \ No newline at end of file diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 50074b3b9d..ff65404c79 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -142,7 +142,7 @@ module RenderTestCases end def test_render_partial_collection_without_as - assert_equal "local_inspector,local_inspector_counter,object", + assert_equal "local_inspector,local_inspector_counter", @view.render(:partial => "test/local_inspector", :collection => [ Customer.new("mary") ]) end -- cgit v1.2.3 From 9b552fb300c4606fe517eadaa30708e9d75498a6 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Fri, 14 Aug 2009 12:00:52 -0700 Subject: Caches and cache clearing seems to actually work, but the actual architecture is kind of messy. Next: CLEAN UP. --- actionpack/lib/abstract_controller/layouts.rb | 13 ++- .../abstract_controller/rendering_controller.rb | 17 ++- .../metal/rendering_controller.rb | 32 ++++++ actionpack/lib/action_view/render/partials.rb | 122 ++++++++++++--------- actionpack/lib/action_view/template/template.rb | 17 ++- 5 files changed, 144 insertions(+), 57 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index ac2154dffc..a8bd2b80e1 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -19,15 +19,20 @@ module AbstractController end end + def clear_template_caches! + @found_layouts.clear if @found_layouts + super + end + def cache_layout(details) layout = @found_layouts - values = details.values_at(:formats, :locale) + key = Thread.current[:format_locale_key] # Cache nil - if layout.key?(values) - return layout[values] + if layout.key?(key) + return layout[key] else - layout[values] = yield + layout[key] = yield end end diff --git a/actionpack/lib/abstract_controller/rendering_controller.rb b/actionpack/lib/abstract_controller/rendering_controller.rb index bb7891fbfd..feca1bc4b7 100644 --- a/actionpack/lib/abstract_controller/rendering_controller.rb +++ b/actionpack/lib/abstract_controller/rendering_controller.rb @@ -111,12 +111,21 @@ module AbstractController def _determine_template(options) name = (options[:_template_name] || action_name).to_s - options[:_template] ||= view_paths.find( - name, { :formats => formats }, options[:_prefix], options[:_partial] - ) + options[:_template] ||= with_template_cache(name) do + view_paths.find( + name, { :formats => formats }, options[:_prefix], options[:_partial] + ) + end + end + + def with_template_cache(name) + yield end module ClassMethods + def clear_template_caches! + end + # Append a path to the list of view paths for this controller. # # ==== Parameters @@ -134,6 +143,7 @@ module AbstractController # the default view path. You may also provide a custom view path # (see ActionView::ViewPathSet for more information) def prepend_view_path(path) + clear_template_caches! self.view_paths.unshift(path) end @@ -148,6 +158,7 @@ module AbstractController # paths:: If a ViewPathSet is provided, use that; # otherwise, process the parameter into a ViewPathSet. def view_paths=(paths) + clear_template_caches! self._view_paths = paths.is_a?(ActionView::PathSet) ? paths : ActionView::Base.process_view_paths(paths) end diff --git a/actionpack/lib/action_controller/metal/rendering_controller.rb b/actionpack/lib/action_controller/metal/rendering_controller.rb index 5b1be763ad..46a69b6b57 100644 --- a/actionpack/lib/action_controller/metal/rendering_controller.rb +++ b/actionpack/lib/action_controller/metal/rendering_controller.rb @@ -1,11 +1,39 @@ module ActionController + class HashKey + @hash_keys = Hash.new {|h,k| h[k] = Hash.new {|h,k| h[k] = {} } } + + def self.get(klass, formats, locale) + @hash_keys[klass][formats][locale] ||= new(klass, formats, locale) + end + + attr_accessor :hash + def initialize(klass, formats, locale) + @hash = [formats, locale].hash + end + + alias_method :eql?, :equal? + end + module RenderingController extend ActiveSupport::Concern include AbstractController::RenderingController + module ClassMethods + def clear_template_caches! + ActionView::Partials::PartialRenderer::TEMPLATES.clear + template_cache.clear + super + end + + def template_cache + @template_cache ||= Hash.new {|h,k| h[k] = {} } + end + end + def process_action(*) self.formats = request.formats.map {|x| x.to_sym} + Thread.current[:format_locale_key] = HashKey.get(self.class, formats, I18n.locale) super end @@ -34,6 +62,10 @@ module ActionController controller_path end + def with_template_cache(name) + self.class.template_cache[Thread.current[:format_locale_key]][name] ||= super + end + def _determine_template(options) if options.key?(:text) options[:_template] = ActionView::TextTemplate.new(options[:text], formats.first) diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb index 188f0d0214..7f10f54d2e 100644 --- a/actionpack/lib/action_view/render/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -173,44 +173,50 @@ module ActionView extend ActiveSupport::Concern class PartialRenderer - def self.partial_names - @partial_names ||= Hash.new {|h,k| h[k] = ActiveSupport::ConcurrentHash.new } - end + PARTIAL_NAMES = Hash.new {|h,k| h[k] = {} } + TEMPLATES = Hash.new {|h,k| h[k] = {} } - def self.formats - @formats ||= Hash.new {|h,k| h[k] = Hash.new{|h,k| h[k] = Hash.new {|h,k| h[k] = {}}}} - end + attr_reader :template def initialize(view_context, options, block) - partial = options[:partial] - - @memo = {} @view = view_context - @options = options - @locals = options[:locals] || {} - @block = block - - # Set up some instance variables to speed up memoizing - @partial_names = self.class.partial_names[@view.controller.class] - @templates = self.class.formats - @format = view_context.formats - - # Set up the object and path - @object = partial.is_a?(String) ? options[:object] : partial - @path = partial_path(partial) + @partial_names = PARTIAL_NAMES[@view.controller.class] + + key = Thread.current[:format_locale_key] + @templates = TEMPLATES[key] if key + + setup(options, block) + end + + def setup(options, block) + partial = options[:partial] + + @options = options + @locals = options[:locals] || {} + @block = block + + if String === partial + @object = options[:object] + @path = partial + else + @object = partial + @path = partial_path(partial) + end end def render - return render_collection if collection - - template = find_template - render_template(template, @object || @locals[template.variable_name]) + if @collection = collection + render_collection + else + @template = template = find_template + render_template(template, @object || @locals[template.variable_name]) + end end def render_collection - @options[:_template] = template = find_template + @template = template = find_template - return nil if collection.blank? + return nil if @collection.blank? if @options.key?(:spacer_template) spacer = find_template(@options[:spacer_template]).render(@view, @locals) @@ -228,12 +234,14 @@ module ActionView counter_name = template.counter_name locals[counter_name] = -1 - collection.each do |object| + @collection.each do |object| locals[counter_name] += 1 locals[as] = object segments << template.render(@view, locals) end + + @template = template segments end @@ -243,7 +251,7 @@ module ActionView segments, locals, as = [], @locals, options[:as] index, template = -1, nil - collection.each do |object| + @collection.each do |object| template = find_template(partial_path(object)) locals[template.counter_name] = (index += 1) locals[template.variable_name] = object @@ -251,28 +259,28 @@ module ActionView segments << template.render(@view, locals) end - @options[:_template] = template + @template = template segments end def render_template(template, object = @object) - @options[:_template] ||= template - - # TODO: is locals[:object] really necessary? - @locals[:object] = @locals[template.variable_name] = object - @locals[@options[:as]] = object if @options[:as] + options, locals, view = @options, @locals, @view + locals[options[:as] || template.variable_name] = object - content = template.render(@view, @locals) do |*name| + content = template.render(view, locals) do |*name| @view._layout_for(*name, &@block) end - return content if @block || !@options[:layout] - find_template(@options[:layout]).render(@view, @locals) { content } - end + if @block || !options[:layout] + content + else + find_template(options[:layout]).render(@view, @locals) { content } + end + end private def collection - @collection ||= if @object.respond_to?(:to_ary) + if @object.respond_to?(:to_ary) @object elsif @options.key?(:collection) @options[:collection] || [] @@ -280,15 +288,19 @@ module ActionView end def find_template(path = @path) - return if !path - @templates[path][@view.controller_path][@format][I18n.locale] ||= begin - prefix = @view.controller.controller_path unless path.include?(?/) - @view.find(path, {:formats => @view.formats}, prefix, true) + unless @templates + path && _find_template(path) + else + path && @templates[path] ||= _find_template(path) end end + + def _find_template(path) + prefix = @view.controller.controller_path unless path.include?(?/) + @view.find(path, {:formats => @view.formats}, prefix, true) + end def partial_path(object = @object) - return object if object.is_a?(String) @partial_names[object.class] ||= begin return nil unless object.respond_to?(:to_model) @@ -302,13 +314,25 @@ module ActionView def render_partial(options) _evaluate_assigns_and_ivars - # TODO: Handle other details here. - self.formats = options[:_details][:formats] if options[:_details] - _render_partial(options) + + details = options[:_details] + + # Is this needed + self.formats = details[:formats] if details + renderer = PartialRenderer.new(self, options, nil) + text = renderer.render + options[:_template] = renderer.template + text end def _render_partial(options, &block) #:nodoc: - PartialRenderer.new(self, options, block).render + if @renderer + @renderer.setup(options, block) + else + @renderer = PartialRenderer.new(self, options, block) + end + + @renderer.render end end diff --git a/actionpack/lib/action_view/template/template.rb b/actionpack/lib/action_view/template/template.rb index 8f23f9b9e3..7d6964e3e3 100644 --- a/actionpack/lib/action_view/template/template.rb +++ b/actionpack/lib/action_view/template/template.rb @@ -97,7 +97,22 @@ module ActionView raise ActionView::TemplateError.new(self, {}, e) end end - + + class LocalsKey + @hash_keys = Hash.new {|h,k| h[k] = Hash.new {|h,k| h[k] = {} } } + + def self.get(*locals) + @hash_keys[*locals] ||= new(klass, format, locale) + end + + attr_accessor :hash + def initialize(klass, format, locale) + @hash = locals.hash + end + + alias_method :eql?, :equal? + end + def build_method_name(locals) # TODO: is locals.keys.hash reliably the same? @method_names[locals.keys.hash] ||= -- cgit v1.2.3 From 1310231c15742bf7d99e2f143d88b383c32782d3 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Fri, 14 Aug 2009 22:32:40 -0700 Subject: Got tests to pass with some more changes. * request.formats is much simpler now * For XHRs or Accept headers with a single item, we use the Accept header * For other requests, we use params[:format] or fallback to HTML * This is primarily to work around the fact that browsers provide completely broken Accept headers, so we have to whitelist the few cases we can specifically isolate and treat other requests as coming from the browser * For APIs, we can support single-item Accept headers, which disambiguates from the browsers * Requests to an action that only has an XML template from the browser will no longer find the template. This worked previously because most browsers provide a catch-all */*, but this was mostly accidental behavior. If you want to serve XML, either use the :xml format in links, or explicitly specify the XML template: render "template.xml". --- .../metal/rendering_controller.rb | 22 +++++--- .../lib/action_controller/testing/process.rb | 2 +- actionpack/lib/action_dispatch/http/request.rb | 36 +++++-------- actionpack/lib/action_view/base.rb | 13 ++++- .../lib/action_view/helpers/prototype_helper.rb | 5 +- actionpack/lib/action_view/template/resolver.rb | 2 +- actionpack/test/controller/content_type_test.rb | 2 +- actionpack/test/controller/mime_responds_test.rb | 51 ++++++------------ actionpack/test/controller/render_js_test.rb | 6 +-- actionpack/test/dispatch/mime_type_test.rb | 2 +- actionpack/test/dispatch/request_test.rb | 63 +++++++++++----------- ...nder_default_content_types_for_respond_to.rhtml | 1 - actionpack/test/lib/fixture_template.rb | 20 +++---- actionpack/test/new_base/content_type_test.rb | 4 +- actionpack/test/new_base/render_layout_test.rb | 2 +- actionpack/test/new_base/render_rjs_test.rb | 7 ++- actionpack/test/new_base/render_template_test.rb | 2 +- actionpack/test/template/javascript_helper_test.rb | 4 ++ actionpack/test/template/prototype_helper_test.rb | 4 ++ actionpack/test/template/render_test.rb | 2 + 20 files changed, 123 insertions(+), 127 deletions(-) delete mode 100644 actionpack/test/fixtures/content_type/render_default_content_types_for_respond_to.rhtml (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal/rendering_controller.rb b/actionpack/lib/action_controller/metal/rendering_controller.rb index 46a69b6b57..4da32ca1b3 100644 --- a/actionpack/lib/action_controller/metal/rendering_controller.rb +++ b/actionpack/lib/action_controller/metal/rendering_controller.rb @@ -8,12 +8,17 @@ module ActionController attr_accessor :hash def initialize(klass, formats, locale) + @formats, @locale = formats, locale @hash = [formats, locale].hash end alias_method :eql?, :equal? + + def inspect + "#" + end end - + module RenderingController extend ActiveSupport::Concern @@ -25,7 +30,7 @@ module ActionController template_cache.clear super end - + def template_cache @template_cache ||= Hash.new {|h,k| h[k] = {} } end @@ -33,16 +38,19 @@ module ActionController def process_action(*) self.formats = request.formats.map {|x| x.to_sym} - Thread.current[:format_locale_key] = HashKey.get(self.class, formats, I18n.locale) + + super + end + + def _determine_template(*) super end def render(options) + Thread.current[:format_locale_key] = HashKey.get(self.class, formats, I18n.locale) + super - self.content_type ||= begin - mime = options[:_template].mime_type - formats.include?(mime && mime.to_sym) || formats.include?(:all) ? mime : Mime::Type.lookup_by_extension(formats.first) - end.to_s + self.content_type ||= options[:_template].mime_type.to_s response_body end diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 09b1a59254..6bc7d60d76 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -148,7 +148,7 @@ module ActionController #:nodoc: def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil) @request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' - @request.env['HTTP_ACCEPT'] = [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ') + @request.env['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ') returning __send__(request_method, action, parameters, session, flash) do @request.env.delete 'HTTP_X_REQUESTED_WITH' @request.env.delete 'HTTP_ACCEPT' diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index b23306af62..bff030f0e4 100755 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -106,16 +106,10 @@ module ActionDispatch @env["action_dispatch.request.accepts"] ||= begin header = @env['HTTP_ACCEPT'].to_s.strip - fallback = xhr? ? Mime::JS : Mime::HTML - if header.empty? - [content_type, fallback, Mime::ALL].compact + [content_type] else - ret = Mime::Type.parse(header) - if ret.last == Mime::ALL - ret.insert(-2, fallback) - end - ret + Mime::Type.parse(header) end end end @@ -163,26 +157,20 @@ module ActionDispatch # GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first depending on the value of ActionController::Base.use_accept_header # def format(view_path = []) - @env["action_dispatch.request.format"] ||= - if parameters[:format] - Mime[parameters[:format]] - elsif ActionController::Base.use_accept_header && !(accepts == ONLY_ALL) - accepts.first - elsif xhr? then Mime::JS - else Mime::HTML - end + formats.first end def formats - if ActionController::Base.use_accept_header - if param = parameters[:format] - Array.wrap(Mime[param]) + accept = @env['HTTP_ACCEPT'] + + @env["action_dispatch.request.formats"] ||= + if parameters[:format] + [Mime[parameters[:format]]] + elsif xhr? || (accept && !accept.include?(?,)) + accepts else - accepts.dup + [Mime::HTML] end - else - [format] - end end # Sets the \format by string extension, which can be used to force custom formats @@ -198,7 +186,7 @@ module ActionDispatch # end def format=(extension) parameters[:format] = extension.to_s - @env["action_dispatch.request.format"] = Mime::Type.lookup_by_extension(parameters[:format]) + @env["action_dispatch.request.formats"] = [Mime::Type.lookup_by_extension(parameters[:format])] end # Returns a symbolized version of the :format parameter of the request. diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index edfd1fd71c..ec1b07797b 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -175,6 +175,17 @@ module ActionView #:nodoc: attr_accessor :controller attr_internal :captures + def reset_formats(formats) + @formats = formats + + if defined?(ActionController) + # This is expensive, but we need to reset this when the format is updated, + # which currently only happens + Thread.current[:format_locale_key] = + ActionController::HashKey.get(self.class, formats, I18n.locale) + end + end + class << self delegate :erb_trim_mode=, :to => 'ActionView::TemplateHandlers::ERB' delegate :logger, :to => 'ActionController::Base', :allow_nil => true @@ -240,7 +251,7 @@ module ActionView #:nodoc: end def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil, formats = nil)#:nodoc: - @formats = formats || [:html] + @formats = formats @assigns = assigns_for_first_render.each { |key, value| instance_variable_set("@#{key}", value) } @controller = controller @helpers = self.class.helpers || Module.new diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index 624b537ad2..03f1dabb4e 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -991,12 +991,13 @@ module ActionView def render(*options_for_render) old_formats = @context && @context.formats - @context.formats = [:html] if @context + + @context.reset_formats([:html]) if @context Hash === options_for_render.first ? @context.render(*options_for_render) : options_for_render.first.to_s ensure - @context.formats = old_formats if @context + @context.reset_formats(old_formats) if @context end def javascript_object_for(object) diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index 10f664736f..fe657166d5 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -42,7 +42,7 @@ module ActionView def handler_glob @handler_glob ||= begin - e = TemplateHandlers.extensions.map{|h| ".#{h},"}.join + e = TemplateHandlers.extensions.map{|h| ".#{h}"}.join(",") "{#{e}}" end end diff --git a/actionpack/test/controller/content_type_test.rb b/actionpack/test/controller/content_type_test.rb index 511788aec8..c249788c67 100644 --- a/actionpack/test/controller/content_type_test.rb +++ b/actionpack/test/controller/content_type_test.rb @@ -46,7 +46,7 @@ class ContentTypeController < ActionController::Base def render_default_content_types_for_respond_to respond_to do |format| format.html { render :text => "hello world!" } - format.xml { render :action => "render_default_content_types_for_respond_to.rhtml" } + format.xml { render :action => "render_default_content_types_for_respond_to" } format.js { render :text => "hello world!" } format.rss { render :text => "hello world!", :content_type => Mime::XML } end diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index 2e2dba5aae..3f00b9ba2f 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -79,29 +79,20 @@ class RespondToController < ActionController::Base end end - def custom_constant_handling - Mime::Type.register("text/x-mobile", :mobile) + Mime::Type.register("text/x-mobile", :mobile) + def custom_constant_handling respond_to do |type| type.html { render :text => "HTML" } type.mobile { render :text => "Mobile" } end - ensure - Mime::SET.delete(:mobile) - Mime.module_eval { remove_const :MOBILE if const_defined?(:MOBILE) } end def custom_constant_handling_without_block - Mime::Type.register("text/x-mobile", :mobile) - respond_to do |type| type.html { render :text => "HTML" } type.mobile end - - ensure - Mime::SET.delete(:mobile) - Mime.module_eval { remove_const :MOBILE if const_defined?(:MOBILE) } end def handle_any @@ -125,32 +116,24 @@ class RespondToController < ActionController::Base end end + Mime::Type.register_alias("text/html", :iphone) + def iphone_with_html_response_type - Mime::Type.register_alias("text/html", :iphone) request.format = :iphone if request.env["HTTP_ACCEPT"] == "text/iphone" respond_to do |type| type.html { @type = "Firefox" } type.iphone { @type = "iPhone" } end - - ensure - Mime::SET.delete(:iphone) - Mime.module_eval { remove_const :IPHONE if const_defined?(:IPHONE) } end def iphone_with_html_response_type_without_layout - Mime::Type.register_alias("text/html", :iphone) request.format = "iphone" if request.env["HTTP_ACCEPT"] == "text/iphone" respond_to do |type| type.html { @type = "Firefox"; render :action => "iphone_with_html_response_type" } type.iphone { @type = "iPhone" ; render :action => "iphone_with_html_response_type" } end - - ensure - Mime::SET.delete(:iphone) - Mime.module_eval { remove_const :IPHONE if const_defined?(:IPHONE) } end def rescue_action(e) @@ -213,18 +196,20 @@ class RespondToControllerTest < ActionController::TestCase def test_js_or_html @request.accept = "text/javascript, text/html" - get :js_or_html + xhr :get, :js_or_html assert_equal 'JS', @response.body - get :html_or_xml + @request.accept = "text/javascript, text/html" + xhr :get, :html_or_xml assert_equal 'HTML', @response.body - get :just_xml + @request.accept = "text/javascript, text/html" + xhr :get, :just_xml assert_response 406 end def test_json_or_yaml - get :json_or_yaml + xhr :get, :json_or_yaml assert_equal 'JSON', @response.body get :json_or_yaml, :format => 'json' @@ -246,13 +231,13 @@ class RespondToControllerTest < ActionController::TestCase def test_js_or_anything @request.accept = "text/javascript, */*" - get :js_or_html + xhr :get, :js_or_html assert_equal 'JS', @response.body - get :html_or_xml + xhr :get, :html_or_xml assert_equal 'HTML', @response.body - get :just_xml + xhr :get, :just_xml assert_equal 'XML', @response.body end @@ -291,14 +276,16 @@ class RespondToControllerTest < ActionController::TestCase end def test_with_atom_content_type + @request.accept = "" @request.env["CONTENT_TYPE"] = "application/atom+xml" - get :made_for_content_type + xhr :get, :made_for_content_type assert_equal "ATOM", @response.body end def test_with_rss_content_type + @request.accept = "" @request.env["CONTENT_TYPE"] = "application/rss+xml" - get :made_for_content_type + xhr :get, :made_for_content_type assert_equal "RSS", @response.body end @@ -795,12 +782,8 @@ class PostController < AbstractPostController protected def with_iphone - Mime::Type.register_alias("text/html", :iphone) request.format = "iphone" if request.env["HTTP_ACCEPT"] == "text/iphone" yield - ensure - Mime::SET.delete(:iphone) - Mime.module_eval { remove_const :IPHONE if const_defined?(:IPHONE) } end end diff --git a/actionpack/test/controller/render_js_test.rb b/actionpack/test/controller/render_js_test.rb index d02fd3fd4c..bc850de733 100644 --- a/actionpack/test/controller/render_js_test.rb +++ b/actionpack/test/controller/render_js_test.rb @@ -13,7 +13,7 @@ class TestController < ActionController::Base # let's just rely on the template end - def partial + def show_partial render :partial => 'partial' end end @@ -33,7 +33,7 @@ class RenderTest < ActionController::TestCase end def test_should_render_js_partial - xhr :get, :partial, :format => 'js' + xhr :get, :show_partial, :format => 'js' assert_equal 'partial js', @response.body - end + end end \ No newline at end of file diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index 4ea0fedb8f..0832943d4c 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -56,7 +56,7 @@ class MimeTypeTest < ActiveSupport::TestCase test "type convenience methods" do # Don't test Mime::ALL, since it Mime::ALL#html? == true - types = Mime::SET.symbols.uniq - [:all] + types = Mime::SET.symbols.uniq - [:all, :iphone] # Remove custom Mime::Type instances set in other tests, like Mime::GIF and Mime::IPHONE types.delete_if { |type| !Mime.const_defined?(type.to_s.upcase) } diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index b626063df4..239fda98e0 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -366,12 +366,12 @@ class RequestTest < ActiveSupport::TestCase end test "XMLHttpRequest" do - with_accept_header false do - request = stub_request 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest' - request.expects(:parameters).at_least_once.returns({}) - assert request.xhr? - assert_equal Mime::JS, request.format - end + request = stub_request 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest', + 'HTTP_ACCEPT' => + [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(",") + request.expects(:parameters).at_least_once.returns({}) + assert request.xhr? + assert_equal Mime::JS, request.format end test "content type" do @@ -420,37 +420,34 @@ class RequestTest < ActiveSupport::TestCase end test "formats with accept header" do - with_accept_header true do - request = stub_request 'HTTP_ACCEPT' => 'text/html' - request.expects(:parameters).at_least_once.returns({}) - assert_equal [ Mime::HTML ], request.formats - - request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8' - request.expects(:parameters).at_least_once.returns({}) - assert_equal with_set(Mime::XML, Mime::HTML, Mime::ALL), request.formats - end + request = stub_request 'HTTP_ACCEPT' => 'text/html' + request.expects(:parameters).at_least_once.returns({}) + assert_equal [ Mime::HTML ], request.formats - with_accept_header false do - request = stub_request - request.expects(:parameters).at_least_once.returns({ :format => :txt }) - assert_equal with_set(Mime::TEXT), request.formats - end + request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8', + 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" + request.expects(:parameters).at_least_once.returns({}) + assert_equal with_set(Mime::XML), request.formats + + request = stub_request + request.expects(:parameters).at_least_once.returns({ :format => :txt }) + assert_equal with_set(Mime::TEXT), request.formats end test "negotiate_mime" do - with_accept_header true do - request = stub_request 'HTTP_ACCEPT' => 'text/html' - request.expects(:parameters).at_least_once.returns({}) - - assert_equal nil, request.negotiate_mime([Mime::XML, Mime::JSON]) - assert_equal Mime::HTML, request.negotiate_mime([Mime::XML, Mime::HTML]) - assert_equal Mime::HTML, request.negotiate_mime([Mime::XML, Mime::ALL]) - - request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8' - request.expects(:parameters).at_least_once.returns({}) - assert_equal Mime::XML, request.negotiate_mime([Mime::XML, Mime::CSV]) - assert_equal Mime::CSV, request.negotiate_mime([Mime::CSV, Mime::YAML]) - end + request = stub_request 'HTTP_ACCEPT' => 'text/html', + 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" + + request.expects(:parameters).at_least_once.returns({}) + + assert_equal nil, request.negotiate_mime([Mime::XML, Mime::JSON]) + assert_equal Mime::HTML, request.negotiate_mime([Mime::XML, Mime::HTML]) + assert_equal Mime::HTML, request.negotiate_mime([Mime::XML, Mime::ALL]) + + request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8', + 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" + request.expects(:parameters).at_least_once.returns({}) + assert_equal Mime::XML, request.negotiate_mime([Mime::XML, Mime::CSV]) end protected diff --git a/actionpack/test/fixtures/content_type/render_default_content_types_for_respond_to.rhtml b/actionpack/test/fixtures/content_type/render_default_content_types_for_respond_to.rhtml deleted file mode 100644 index 25dc746886..0000000000 --- a/actionpack/test/fixtures/content_type/render_default_content_types_for_respond_to.rhtml +++ /dev/null @@ -1 +0,0 @@ -world \ No newline at end of file diff --git a/actionpack/test/lib/fixture_template.rb b/actionpack/test/lib/fixture_template.rb index ee526b5de5..8da92180d1 100644 --- a/actionpack/test/lib/fixture_template.rb +++ b/actionpack/test/lib/fixture_template.rb @@ -4,7 +4,7 @@ module ActionView #:nodoc: super(options) @hash = hash end - + def find_templates(name, details, prefix, partial) if regexp = details_to_regexp(name, details, prefix, partial) cached(regexp) do @@ -16,26 +16,26 @@ module ActionView #:nodoc: end end end - + private - + def formats_regexp @formats_regexp ||= begin formats = Mime::SET.symbols '(?:' + formats.map { |l| "\\.#{Regexp.escape(l.to_s)}" }.join('|') + ')?' end end - + def handler_regexp e = TemplateHandlers.extensions.map{|h| "\\.#{Regexp.escape(h.to_s)}"}.join("|") - "(?:#{e})?" + "(?:#{e})" end - + def details_to_regexp(name, details, prefix, partial) path = "" path << "#{prefix}/" unless prefix.empty? path << (partial ? "_#{name}" : name) - + extensions = "" [:locales, :formats].each do |k| extensions << if exts = details[k] @@ -47,7 +47,7 @@ module ActionView #:nodoc: %r'^#{Regexp.escape(path)}#{extensions}#{handler_regexp}$' end - + # TODO: fix me # :api: plugin def path_to_details(path) @@ -56,10 +56,10 @@ module ActionView #:nodoc: partial = m[1] == '_' details = (m[2]||"").split('.').reject { |e| e.empty? } handler = Template.handler_class_for_extension(m[3]) - + format = Mime[details.last] && details.pop.to_sym locale = details.last && details.pop.to_sym - + return handler, :format => format, :locale => locale, :partial => partial end end diff --git a/actionpack/test/new_base/content_type_test.rb b/actionpack/test/new_base/content_type_test.rb index cfc03a3024..ceee508224 100644 --- a/actionpack/test/new_base/content_type_test.rb +++ b/actionpack/test/new_base/content_type_test.rb @@ -75,7 +75,7 @@ module ContentType end test "sets Content-Type as application/xml when rendering *.xml.erb" do - get "/content_type/implied/i_am_xml_erb" + get "/content_type/implied/i_am_xml_erb", "format" => "xml" assert_header "Content-Type", "application/xml; charset=utf-8" end @@ -87,7 +87,7 @@ module ContentType end test "sets Content-Type as application/xml when rendering *.xml.builder" do - get "/content_type/implied/i_am_xml_builder" + get "/content_type/implied/i_am_xml_builder", "format" => "xml" assert_header "Content-Type", "application/xml; charset=utf-8" end diff --git a/actionpack/test/new_base/render_layout_test.rb b/actionpack/test/new_base/render_layout_test.rb index 279b807a5f..933eef58e7 100644 --- a/actionpack/test/new_base/render_layout_test.rb +++ b/actionpack/test/new_base/render_layout_test.rb @@ -83,7 +83,7 @@ module ControllerLayouts testing ControllerLayouts::MismatchFormatController test "if JS is selected, an HTML template is not also selected" do - get :index + get :index, "format" => "js" assert_response "$(\"test\").omg();" end diff --git a/actionpack/test/new_base/render_rjs_test.rb b/actionpack/test/new_base/render_rjs_test.rb index bd4c87b3bf..3d3e516905 100644 --- a/actionpack/test/new_base/render_rjs_test.rb +++ b/actionpack/test/new_base/render_rjs_test.rb @@ -21,24 +21,23 @@ module RenderRjs def index_locale old_locale, I18n.locale = I18n.locale, :da end - end class TestBasic < SimpleRouteCase testing BasicController test "rendering a partial in an RJS template should pick the JS template over the HTML one" do - get :index + get :index, "format" => "js" assert_response("$(\"customer\").update(\"JS Partial\");") end test "replacing an element with a partial in an RJS template should pick the HTML template over the JS one" do - get :index_html + get :index_html, "format" => "js" assert_response("$(\"customer\").update(\"HTML Partial\");") end test "replacing an element with a partial in an RJS template with a locale should pick the localed HTML template" do - get :index_locale, :format => :js + get :index_locale, "format" => "js" assert_response("$(\"customer\").update(\"Danish HTML Partial\");") end diff --git a/actionpack/test/new_base/render_template_test.rb b/actionpack/test/new_base/render_template_test.rb index 94ea38fc7b..967cbd07b0 100644 --- a/actionpack/test/new_base/render_template_test.rb +++ b/actionpack/test/new_base/render_template_test.rb @@ -73,7 +73,7 @@ module RenderTemplate end test "rendering a builder template" do - get :builder_template + get :builder_template, "format" => "xml" assert_response "\n

Hello

\n\n" end end diff --git a/actionpack/test/template/javascript_helper_test.rb b/actionpack/test/template/javascript_helper_test.rb index 8caabfc3e1..f0f686f6e2 100644 --- a/actionpack/test/template/javascript_helper_test.rb +++ b/actionpack/test/template/javascript_helper_test.rb @@ -7,6 +7,10 @@ class JavaScriptHelperTest < ActionView::TestCase attr_accessor :formats, :output_buffer + def reset_formats(format) + @format = format + end + def setup super @template = self diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb index acbf311212..313a769088 100644 --- a/actionpack/test/template/prototype_helper_test.rb +++ b/actionpack/test/template/prototype_helper_test.rb @@ -36,6 +36,10 @@ class Author::Nested < Author; end class PrototypeHelperBaseTest < ActionView::TestCase attr_accessor :formats, :output_buffer + def reset_formats(format) + @format = format + end + def setup super @template = self diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index ff65404c79..c86d5215cd 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -190,6 +190,8 @@ module RenderTestCases def test_render_missing_xml_partial_and_raise_missing_template @view.formats = [:xml] assert_raise(ActionView::MissingTemplate) { @view.render(:partial => "test/layout_for_partial") } + ensure + @view.formats = nil end def test_render_inline -- cgit v1.2.3 From df6617bc8ac1677ab2b2cf7ed2859cdcc393ccb5 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 15 Aug 2009 15:56:52 -0700 Subject: Normalize route generation order: associations, yield block, then own routes. --- actionpack/lib/action_controller/routing/resources.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/routing/resources.rb b/actionpack/lib/action_controller/routing/resources.rb index 4862cf7115..06506435a2 100644 --- a/actionpack/lib/action_controller/routing/resources.rb +++ b/actionpack/lib/action_controller/routing/resources.rb @@ -531,14 +531,14 @@ module ActionController with_options :controller => resource.controller do |map| map_associations(resource, options) + if block_given? + with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block) + end + map_collection_actions(map, resource) map_default_collection_actions(map, resource) map_new_actions(map, resource) map_member_actions(map, resource) - - if block_given? - with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block) - end end end @@ -546,16 +546,16 @@ module ActionController resource = SingletonResource.new(entities, options) with_options :controller => resource.controller do |map| - map_collection_actions(map, resource) - map_new_actions(map, resource) - map_member_actions(map, resource) - map_default_singleton_actions(map, resource) - map_associations(resource, options) if block_given? with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block) end + + map_collection_actions(map, resource) + map_new_actions(map, resource) + map_member_actions(map, resource) + map_default_singleton_actions(map, resource) end end -- cgit v1.2.3 From 911acc10de483e0d7a9e6b3c475aeaecad49bfc5 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sat, 15 Aug 2009 18:08:46 -0500 Subject: Axe "best fit" generation support --- .../lib/action_controller/routing/route_set.rb | 29 ++-------------------- actionpack/test/controller/routing_test.rb | 12 --------- 2 files changed, 2 insertions(+), 39 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/routing/route_set.rb b/actionpack/lib/action_controller/routing/route_set.rb index 09f6024d39..a4f54ad662 100644 --- a/actionpack/lib/action_controller/routing/route_set.rb +++ b/actionpack/lib/action_controller/routing/route_set.rb @@ -407,22 +407,9 @@ module ActionController # don't use the recalled keys when determining which routes to check routes = routes_by_controller[controller][action][options.reject {|k,v| !v}.keys.sort_by { |x| x.object_id }] - routes[1].each_with_index do |route, index| + routes.each_with_index do |route, index| results = route.__send__(method, options, merged, expire_on) if results && (!results.is_a?(Array) || results.first) - - # Compare results with Rails 3.0 behavior - if routes[0][index] != route - routes[0].each do |route2| - new_results = route2.__send__(method, options, merged, expire_on) - if new_results && (!new_results.is_a?(Array) || new_results.first) - ActiveSupport::Deprecation.warn "The URL you generated will use the first matching route in routes.rb rather than the \"best\" match. " + - "In Rails 3.0 #{new_results} would of been generated instead of #{results}" - break - end - end - end - return results end end @@ -463,10 +450,7 @@ module ActionController @routes_by_controller ||= Hash.new do |controller_hash, controller| controller_hash[controller] = Hash.new do |action_hash, action| action_hash[action] = Hash.new do |key_hash, keys| - key_hash[keys] = [ - routes_for_controller_and_action_and_keys(controller, action, keys), - deprecated_routes_for_controller_and_action_and_keys(controller, action, keys) - ] + key_hash[keys] = routes_for_controller_and_action_and_keys(controller, action, keys) end end end @@ -487,15 +471,6 @@ module ActionController end end - def deprecated_routes_for_controller_and_action_and_keys(controller, action, keys) - selected = routes.select do |route| - route.matches_controller_and_action? controller, action - end - selected.sort_by do |route| - (keys - route.significant_keys).length - end - end - # Subclasses and plugins may override this method to extract further attributes # from the request, for use by route conditions and such. def extract_request_environment(request) diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index 000f35e0f2..33fb6ac017 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -1411,18 +1411,6 @@ class RouteSetTest < ActiveSupport::TestCase Object.send(:remove_const, :Api) end - def test_generate_finds_best_fit - set.draw do |map| - map.connect "/people", :controller => "people", :action => "index" - map.connect "/ws/people", :controller => "people", :action => "index", :ws => true - end - - assert_deprecated { - url = set.generate(:controller => "people", :action => "index", :ws => true) - assert_equal "/ws/people", url - } - end - def test_generate_changes_controller_module set.draw { |map| map.connect ':controller/:action/:id' } current = { :controller => "bling/bloop", :action => "bap", :id => 9 } -- cgit v1.2.3 From 679128da58636f3ec96e24fcb7daac24666b2dad Mon Sep 17 00:00:00 2001 From: Jay Pignata Date: Tue, 11 Aug 2009 00:56:46 -0400 Subject: Adding a call to logger from params_parser to give detailed debug information when invalid xml or json is posted [#2481 state:committed] Signed-off-by: Jeremy Kemper --- .../action_dispatch/middleware/params_parser.rb | 6 +++++ .../dispatch/request/json_params_parsing_test.rb | 28 ++++++++++++++++++---- .../dispatch/request/xml_params_parsing_test.rb | 17 ++++++++++++- 3 files changed, 46 insertions(+), 5 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb index e83cf9236b..ff2b2fe74b 100644 --- a/actionpack/lib/action_dispatch/middleware/params_parser.rb +++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb @@ -47,6 +47,8 @@ module ActionDispatch false end rescue Exception => e # YAML, XML or Ruby code block errors + logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{request.raw_post}" + raise { "body" => request.raw_post, "content_type" => request.content_type, @@ -67,5 +69,9 @@ module ActionDispatch nil end + + def logger + defined?(Rails.logger) ? Rails.logger : Logger.new($stderr) + end end end diff --git a/actionpack/test/dispatch/request/json_params_parsing_test.rb b/actionpack/test/dispatch/request/json_params_parsing_test.rb index a3dde72c4e..db6cf7b330 100644 --- a/actionpack/test/dispatch/request/json_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/json_params_parsing_test.rb @@ -30,16 +30,36 @@ class JsonParamsParsingTest < ActionController::IntegrationTest ) end + test "logs error if parsing unsuccessful" do + with_test_routing do + begin + $stderr = StringIO.new + json = "[\"person]\": {\"name\": \"David\"}}" + post "/parse", json, {'CONTENT_TYPE' => 'application/json'} + assert_response :error + $stderr.rewind && err = $stderr.read + assert err =~ /Error occurred while parsing request parameters/ + ensure + $stderr = STDERR + end + end + end + private def assert_parses(expected, actual, headers = {}) + with_test_routing do + post "/parse", actual, headers + assert_response :ok + assert_equal(expected, TestController.last_request_parameters) + end + end + + def with_test_routing with_routing do |set| set.draw do |map| map.connect ':action', :controller => "json_params_parsing_test/test" end - - post "/parse", actual, headers - assert_response :ok - assert_equal(expected, TestController.last_request_parameters) + yield end end end diff --git a/actionpack/test/dispatch/request/xml_params_parsing_test.rb b/actionpack/test/dispatch/request/xml_params_parsing_test.rb index ee764e726e..521002b519 100644 --- a/actionpack/test/dispatch/request/xml_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/xml_params_parsing_test.rb @@ -38,6 +38,21 @@ class XmlParamsParsingTest < ActionController::IntegrationTest end end + test "logs error if parsing unsuccessful" do + with_test_routing do + begin + $stderr = StringIO.new + xml = "David#{ActiveSupport::Base64.encode64('ABC')}" + post "/parse", xml, default_headers + assert_response :error + $stderr.rewind && err = $stderr.read + assert err =~ /Error occurred while parsing request parameters/ + ensure + $stderr = STDERR + end + end + end + test "parses multiple files" do xml = <<-end_body @@ -85,4 +100,4 @@ class LegacyXmlParamsParsingTest < XmlParamsParsingTest def default_headers {'HTTP_X_POST_DATA_FORMAT' => 'xml'} end -end +end \ No newline at end of file -- cgit v1.2.3 From d6d550f0cbbe37fc8caf851e9143749f2fa5cd38 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Sat, 15 Aug 2009 20:33:34 -0700 Subject: Missing fixture template -- fixes AP tests --- .../content_type/render_default_content_types_for_respond_to.xml.erb | 1 + 1 file changed, 1 insertion(+) create mode 100644 actionpack/test/fixtures/content_type/render_default_content_types_for_respond_to.xml.erb (limited to 'actionpack') diff --git a/actionpack/test/fixtures/content_type/render_default_content_types_for_respond_to.xml.erb b/actionpack/test/fixtures/content_type/render_default_content_types_for_respond_to.xml.erb new file mode 100644 index 0000000000..25dc746886 --- /dev/null +++ b/actionpack/test/fixtures/content_type/render_default_content_types_for_respond_to.xml.erb @@ -0,0 +1 @@ +world \ No newline at end of file -- cgit v1.2.3 From ccf28d2499d1b4e2aba41291eb800e0e02120923 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Sat, 15 Aug 2009 20:38:50 -0700 Subject: Fixes ActionMailer regression [#3059 state:resolved] --- actionpack/lib/action_view/render/rendering.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index e04800e6e8..b0b75918b7 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -83,7 +83,7 @@ module ActionView template = Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {}) locals = options[:locals] || {} content = template.render(self, locals) - content = layout.render(self, locals) {|*name| _layout_for(*name) } if layout + content = layout.render(self, locals) {|*name| _layout_for(*name) { content } } if layout content end -- cgit v1.2.3 From 24ad9ae3d228acdf9aa31cf28bfe6dfb0139c247 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 16 Aug 2009 21:14:26 -0500 Subject: Cleanup route reloading in tests. Prefer with_routing over using ActionController::Routing::Routes directly --- .../lib/action_controller/routing/route_set.rb | 12 +- actionpack/test/abstract_unit.rb | 11 +- .../test/controller/action_pack_assertions_test.rb | 8 +- actionpack/test/controller/base_test.rb | 34 ++--- actionpack/test/controller/caching_test.rb | 3 - actionpack/test/controller/mime_responds_test.rb | 1 + actionpack/test/controller/redirect_test.rb | 24 ++-- actionpack/test/controller/render_test.rb | 18 +-- actionpack/test/controller/render_xml_test.rb | 14 +- .../controller/request_forgery_protection_test.rb | 6 +- actionpack/test/controller/routing_test.rb | 3 +- actionpack/test/controller/test_test.rb | 6 +- actionpack/test/controller/url_rewriter_test.rb | 141 +++++++++++---------- actionpack/test/controller/verification_test.rb | 5 +- 14 files changed, 147 insertions(+), 139 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/routing/route_set.rb b/actionpack/lib/action_controller/routing/route_set.rb index a4f54ad662..25fdbf480e 100644 --- a/actionpack/lib/action_controller/routing/route_set.rb +++ b/actionpack/lib/action_controller/routing/route_set.rb @@ -213,7 +213,7 @@ module ActionController self.routes = [] self.named_routes = NamedRouteCollection.new - clear_recognize_optimized! + clear! end # Subclasses and plugins may override this method to specify a different @@ -223,6 +223,7 @@ module ActionController end def draw + clear! yield Mapper.new(self) install_helpers end @@ -230,8 +231,10 @@ module ActionController def clear! routes.clear named_routes.clear + @combined_regexp = nil @routes_by_controller = nil + # This will force routing/recognition_optimization.rb # to refresh optimisations. clear_recognize_optimized! @@ -262,7 +265,6 @@ module ActionController def load! Routing.use_controllers!(nil) # Clear the controller cache so we may discover new ones - clear! load_routes! end @@ -286,10 +288,12 @@ module ActionController configuration_files.each { |config| load(config) } @routes_last_modified = routes_changed_at else - add_route ":controller/:action/:id" + draw do |map| + map.connect ":controller/:action/:id" + end end end - + def routes_changed_at routes_changed_at = nil diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index eb4e2fb585..b618c059a3 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -51,6 +51,10 @@ module ActionView ActionController::Routing::Routes.draw do |map| map.connect ':controller/:action/:id' end + + teardown do + ActionController::Routing::Routes.reload! + end end end end @@ -70,12 +74,17 @@ module ActionController class TestCase include TestProcess + setup do ActionController::Routing::Routes.draw do |map| map.connect ':controller/:action/:id' end end - + + teardown do + ActionController::Routing::Routes.reload! + end + def assert_template(options = {}, message = nil) validate_request! diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index ecbaba39d1..06827e5fbc 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -185,13 +185,9 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase # let's get this party started def setup super - ActionController::Routing::Routes.reload - ActionController::Routing.use_controllers!(%w(action_pack_assertions admin/inner_module user content admin/user)) - end - def teardown - super - ActionController::Routing::Routes.reload + ActionController::Routing.use_controllers!(%w(action_pack_assertions admin/inner_module user content admin/user)) + ActionController::Routing::Routes.load_routes! end # -- assertion-based testing ------------------------------------------------ diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb index 8877057070..b97ceb4594 100644 --- a/actionpack/test/controller/base_test.rb +++ b/actionpack/test/controller/base_test.rb @@ -177,17 +177,17 @@ class DefaultUrlOptionsTest < ActionController::TestCase end def test_default_url_options_are_used_if_set - ActionController::Routing::Routes.draw do |map| - map.default_url_options 'default_url_options', :controller => 'default_url_options' - map.connect ':controller/:action/:id' - end + with_routing do |set| + set.draw do |map| + map.default_url_options 'default_url_options', :controller => 'default_url_options' + map.connect ':controller/:action/:id' + end - get :default_url_options_action # Make a dummy request so that the controller is initialized properly. + get :default_url_options_action # Make a dummy request so that the controller is initialized properly. - assert_equal 'http://www.override.com/default_url_options/new?bacon=chunky', @controller.url_for(:controller => 'default_url_options') - assert_equal 'http://www.override.com/default_url_options?bacon=chunky', @controller.send(:default_url_options_url) - ensure - ActionController::Routing::Routes.load! + assert_equal 'http://www.override.com/default_url_options/new?bacon=chunky', @controller.url_for(:controller => 'default_url_options') + assert_equal 'http://www.override.com/default_url_options?bacon=chunky', @controller.send(:default_url_options_url) + end end end @@ -206,15 +206,15 @@ class EmptyUrlOptionsTest < ActionController::TestCase end end -class EnsureNamedRoutesWorksTicket22BugTest < Test::Unit::TestCase +class EnsureNamedRoutesWorksTicket22BugTest < ActionController::TestCase def test_named_routes_still_work - ActionController::Routing::Routes.draw do |map| - map.resources :things - end - EmptyController.send :include, ActionController::UrlWriter + with_routing do |set| + set.draw do |map| + map.resources :things + end + EmptyController.send :include, ActionController::UrlWriter - assert_equal '/things', EmptyController.new.send(:things_path) - ensure - ActionController::Routing::Routes.load! + assert_equal '/things', EmptyController.new.send(:things_path) + end end end diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index f1c93e6b1e..82c790bc19 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -48,8 +48,6 @@ class PageCachingTest < ActionController::TestCase super ActionController::Base.perform_caching = true - ActionController::Routing::Routes.clear! - ActionController::Routing::Routes.draw do |map| map.main '', :controller => 'posts', :format => nil map.formatted_posts 'posts.:format', :controller => 'posts' @@ -72,7 +70,6 @@ class PageCachingTest < ActionController::TestCase def teardown FileUtils.rm_rf(File.dirname(FILE_STORE_PATH)) - ActionController::Routing::Routes.clear! ActionController::Base.perform_caching = false end diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index 3f00b9ba2f..44536ce54e 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -531,6 +531,7 @@ class RespondWithControllerTest < ActionController::TestCase ActionController::Routing::Routes.draw do |map| map.resources :customers map.resources :quiz_stores, :has_many => :customers + map.connect ":controller/:action/:id" end end diff --git a/actionpack/test/controller/redirect_test.rb b/actionpack/test/controller/redirect_test.rb index 7755af592d..ea278fd8f0 100644 --- a/actionpack/test/controller/redirect_test.rb +++ b/actionpack/test/controller/redirect_test.rb @@ -231,18 +231,20 @@ class RedirectTest < ActionController::TestCase end def test_redirect_to_record - ActionController::Routing::Routes.draw do |map| - map.resources :workshops - map.connect ':controller/:action/:id' + with_routing do |set| + set.draw do |map| + map.resources :workshops + map.connect ':controller/:action/:id' + end + + get :redirect_to_existing_record + assert_equal "http://test.host/workshops/5", redirect_to_url + assert_redirected_to Workshop.new(5, false) + + get :redirect_to_new_record + assert_equal "http://test.host/workshops", redirect_to_url + assert_redirected_to Workshop.new(5, true) end - - get :redirect_to_existing_record - assert_equal "http://test.host/workshops/5", redirect_to_url - assert_redirected_to Workshop.new(5, false) - - get :redirect_to_new_record - assert_equal "http://test.host/workshops", redirect_to_url - assert_redirected_to Workshop.new(5, true) end def test_redirect_to_nil diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 9c5b560c2c..abcc8bf384 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -1086,15 +1086,17 @@ class RenderTest < ActionController::TestCase end def test_head_with_location_object - ActionController::Routing::Routes.draw do |map| - map.resources :customers - map.connect ':controller/:action/:id' - end + with_routing do |set| + set.draw do |map| + map.resources :customers + map.connect ':controller/:action/:id' + end - get :head_with_location_object - assert @response.body.blank? - assert_equal "http://www.nextangle.com/customers/1", @response.headers["Location"] - assert_response :ok + get :head_with_location_object + assert @response.body.blank? + assert_equal "http://www.nextangle.com/customers/1", @response.headers["Location"] + assert_response :ok + end end def test_head_with_custom_header diff --git a/actionpack/test/controller/render_xml_test.rb b/actionpack/test/controller/render_xml_test.rb index 139f55d8bd..e96e8a4d57 100644 --- a/actionpack/test/controller/render_xml_test.rb +++ b/actionpack/test/controller/render_xml_test.rb @@ -55,13 +55,15 @@ class RenderTest < ActionController::TestCase end def test_rendering_with_object_location_should_set_header_with_url_for - ActionController::Routing::Routes.draw do |map| - map.resources :customers - map.connect ':controller/:action/:id' - end + with_routing do |set| + set.draw do |map| + map.resources :customers + map.connect ':controller/:action/:id' + end - get :render_with_object_location - assert_equal "http://www.nextangle.com/customers/1", @response.headers["Location"] + get :render_with_object_location + assert_equal "http://www.nextangle.com/customers/1", @response.headers["Location"] + end end def test_should_render_formatted_xml_erb_template diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb index 83925ed4db..7111796f8d 100644 --- a/actionpack/test/controller/request_forgery_protection_test.rb +++ b/actionpack/test/controller/request_forgery_protection_test.rb @@ -1,10 +1,6 @@ require 'abstract_unit' require 'digest/sha1' -ActionController::Routing::Routes.draw do |map| - map.connect ':controller/:action/:id' -end - # common controller actions module RequestForgeryProtectionActions def index @@ -50,7 +46,7 @@ module RequestForgeryProtectionTests def teardown ActionController::Base.request_forgery_protection_token = nil end - + def test_should_render_form_with_token_tag get :index diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index 33fb6ac017..5be780dd42 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -102,8 +102,7 @@ class RoutingTest < Test::Unit::TestCase ActionController::Routing.use_controllers! true_possible_controllers Object.send(:remove_const, :RAILS_ROOT) rescue nil - ActionController::Routing::Routes.clear! - ActionController::Routing::Routes.load_routes! + ActionController::Routing::Routes.reload! end def test_with_controllers diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb index 9e88188b9a..84c97851ee 100644 --- a/actionpack/test/controller/test_test.rb +++ b/actionpack/test/controller/test_test.rb @@ -123,15 +123,11 @@ XML @controller = TestController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new + ActionController::Routing.use_controllers! %w(content admin/user test_test/test) ActionController::Routing::Routes.load_routes! end - def teardown - super - ActionController::Routing::Routes.reload - end - def test_raw_post_handling params = {:page => {:name => 'page name'}, 'some key' => 123} post :render_raw_post, params.dup diff --git a/actionpack/test/controller/url_rewriter_test.rb b/actionpack/test/controller/url_rewriter_test.rb index 0e149cf8ae..ad915e7a57 100644 --- a/actionpack/test/controller/url_rewriter_test.rb +++ b/actionpack/test/controller/url_rewriter_test.rb @@ -195,61 +195,62 @@ class UrlWriterTests < ActionController::TestCase end def test_named_routes - ActionController::Routing::Routes.draw do |map| - map.no_args '/this/is/verbose', :controller => 'home', :action => 'index' - map.home '/home/sweet/home/:user', :controller => 'home', :action => 'index' - map.connect ':controller/:action/:id' + with_routing do |set| + set.draw do |map| + map.no_args '/this/is/verbose', :controller => 'home', :action => 'index' + map.home '/home/sweet/home/:user', :controller => 'home', :action => 'index' + map.connect ':controller/:action/:id' + end + + # We need to create a new class in order to install the new named route. + kls = Class.new { include ActionController::UrlWriter } + controller = kls.new + assert controller.respond_to?(:home_url) + assert_equal 'http://www.basecamphq.com/home/sweet/home/again', + controller.send(:home_url, :host => 'www.basecamphq.com', :user => 'again') + + assert_equal("/home/sweet/home/alabama", controller.send(:home_path, :user => 'alabama', :host => 'unused')) + assert_equal("http://www.basecamphq.com/home/sweet/home/alabama", controller.send(:home_url, :user => 'alabama', :host => 'www.basecamphq.com')) + assert_equal("http://www.basecamphq.com/this/is/verbose", controller.send(:no_args_url, :host=>'www.basecamphq.com')) end - - # We need to create a new class in order to install the new named route. - kls = Class.new { include ActionController::UrlWriter } - controller = kls.new - assert controller.respond_to?(:home_url) - assert_equal 'http://www.basecamphq.com/home/sweet/home/again', - controller.send(:home_url, :host => 'www.basecamphq.com', :user => 'again') - - assert_equal("/home/sweet/home/alabama", controller.send(:home_path, :user => 'alabama', :host => 'unused')) - assert_equal("http://www.basecamphq.com/home/sweet/home/alabama", controller.send(:home_url, :user => 'alabama', :host => 'www.basecamphq.com')) - assert_equal("http://www.basecamphq.com/this/is/verbose", controller.send(:no_args_url, :host=>'www.basecamphq.com')) - ensure - ActionController::Routing::Routes.load! end def test_relative_url_root_is_respected_for_named_routes orig_relative_url_root = ActionController::Base.relative_url_root ActionController::Base.relative_url_root = '/subdir' - ActionController::Routing::Routes.draw do |map| - map.home '/home/sweet/home/:user', :controller => 'home', :action => 'index' - end + with_routing do |set| + set.draw do |map| + map.home '/home/sweet/home/:user', :controller => 'home', :action => 'index' + end - kls = Class.new { include ActionController::UrlWriter } - controller = kls.new + kls = Class.new { include ActionController::UrlWriter } + controller = kls.new - assert_equal 'http://www.basecamphq.com/subdir/home/sweet/home/again', - controller.send(:home_url, :host => 'www.basecamphq.com', :user => 'again') + assert_equal 'http://www.basecamphq.com/subdir/home/sweet/home/again', + controller.send(:home_url, :host => 'www.basecamphq.com', :user => 'again') + end ensure - ActionController::Routing::Routes.load! ActionController::Base.relative_url_root = orig_relative_url_root end def test_only_path - ActionController::Routing::Routes.draw do |map| - map.home '/home/sweet/home/:user', :controller => 'home', :action => 'index' - map.connect ':controller/:action/:id' + with_routing do |set| + set.draw do |map| + map.home '/home/sweet/home/:user', :controller => 'home', :action => 'index' + map.connect ':controller/:action/:id' + end + + # We need to create a new class in order to install the new named route. + kls = Class.new { include ActionController::UrlWriter } + controller = kls.new + assert controller.respond_to?(:home_url) + assert_equal '/brave/new/world', + controller.send(:url_for, :controller => 'brave', :action => 'new', :id => 'world', :only_path => true) + + assert_equal("/home/sweet/home/alabama", controller.send(:home_url, :user => 'alabama', :host => 'unused', :only_path => true)) + assert_equal("/home/sweet/home/alabama", controller.send(:home_path, 'alabama')) end - - # We need to create a new class in order to install the new named route. - kls = Class.new { include ActionController::UrlWriter } - controller = kls.new - assert controller.respond_to?(:home_url) - assert_equal '/brave/new/world', - controller.send(:url_for, :controller => 'brave', :action => 'new', :id => 'world', :only_path => true) - - assert_equal("/home/sweet/home/alabama", controller.send(:home_url, :user => 'alabama', :host => 'unused', :only_path => true)) - assert_equal("/home/sweet/home/alabama", controller.send(:home_path, 'alabama')) - ensure - ActionController::Routing::Routes.load! end def test_one_parameter @@ -302,41 +303,41 @@ class UrlWriterTests < ActionController::TestCase end def test_named_routes_with_nil_keys - ActionController::Routing::Routes.clear! - ActionController::Routing::Routes.draw do |map| - map.main '', :controller => 'posts', :format => nil - map.resources :posts - map.connect ':controller/:action/:id' + with_routing do |set| + set.draw do |map| + map.main '', :controller => 'posts', :format => nil + map.resources :posts + map.connect ':controller/:action/:id' + end + + # We need to create a new class in order to install the new named route. + kls = Class.new { include ActionController::UrlWriter } + kls.default_url_options[:host] = 'www.basecamphq.com' + + controller = kls.new + params = {:action => :index, :controller => :posts, :format => :xml} + assert_equal("http://www.basecamphq.com/posts.xml", controller.send(:url_for, params)) + params[:format] = nil + assert_equal("http://www.basecamphq.com/", controller.send(:url_for, params)) end - # We need to create a new class in order to install the new named route. - kls = Class.new { include ActionController::UrlWriter } - kls.default_url_options[:host] = 'www.basecamphq.com' - - controller = kls.new - params = {:action => :index, :controller => :posts, :format => :xml} - assert_equal("http://www.basecamphq.com/posts.xml", controller.send(:url_for, params)) - params[:format] = nil - assert_equal("http://www.basecamphq.com/", controller.send(:url_for, params)) - ensure - ActionController::Routing::Routes.load! end def test_formatted_url_methods_are_deprecated - ActionController::Routing::Routes.draw do |map| - map.resources :posts + with_routing do |set| + set.draw do |map| + map.resources :posts + end + # We need to create a new class in order to install the new named route. + kls = Class.new { include ActionController::UrlWriter } + controller = kls.new + params = {:id => 1, :format => :xml} + assert_deprecated do + assert_equal("/posts/1.xml", controller.send(:formatted_post_path, params)) + end + assert_deprecated do + assert_equal("/posts/1.xml", controller.send(:formatted_post_path, 1, :xml)) + end end - # We need to create a new class in order to install the new named route. - kls = Class.new { include ActionController::UrlWriter } - controller = kls.new - params = {:id => 1, :format => :xml} - assert_deprecated do - assert_equal("/posts/1.xml", controller.send(:formatted_post_path, params)) - end - assert_deprecated do - assert_equal("/posts/1.xml", controller.send(:formatted_post_path, 1, :xml)) - end - ensure - ActionController::Routing::Routes.load! end def test_multiple_includes_maintain_distinct_options diff --git a/actionpack/test/controller/verification_test.rb b/actionpack/test/controller/verification_test.rb index d568030e41..ee558f3465 100644 --- a/actionpack/test/controller/verification_test.rb +++ b/actionpack/test/controller/verification_test.rb @@ -112,7 +112,10 @@ class VerificationTest < ActionController::TestCase tests TestController setup do - ActionController::Routing::Routes.add_named_route :foo, '/foo', :controller => 'test', :action => 'foo' + ActionController::Routing::Routes.draw do |map| + map.foo '/foo', :controller => 'test', :action => 'foo' + map.connect ":controller/:action/:id" + end end def test_using_symbol_back_with_no_referrer -- cgit v1.2.3 From ff1b0d3c86c2b26470a30a5edb958a365f00098e Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 16 Aug 2009 21:21:39 -0500 Subject: k, thats really slow, lets not --- actionpack/test/abstract_unit.rb | 8 -------- 1 file changed, 8 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index b618c059a3..a21b00915e 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -51,10 +51,6 @@ module ActionView ActionController::Routing::Routes.draw do |map| map.connect ':controller/:action/:id' end - - teardown do - ActionController::Routing::Routes.reload! - end end end end @@ -81,10 +77,6 @@ module ActionController end end - teardown do - ActionController::Routing::Routes.reload! - end - def assert_template(options = {}, message = nil) validate_request! -- cgit v1.2.3 From b58acea5696c777ae828d7866fcff334d493b4d3 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Fri, 21 Aug 2009 16:49:33 -0500 Subject: Move legacy param_parsers config onto AD::ParamsParser --- .../lib/action_controller/metal/compatibility.rb | 6 - .../action_dispatch/middleware/params_parser.rb | 12 +- actionpack/test/controller/webservice_test.rb | 129 +++++++++++---------- 3 files changed, 74 insertions(+), 73 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal/compatibility.rb b/actionpack/lib/action_controller/metal/compatibility.rb index 5b0165f0e7..22f9ab219c 100644 --- a/actionpack/lib/action_controller/metal/compatibility.rb +++ b/actionpack/lib/action_controller/metal/compatibility.rb @@ -16,12 +16,6 @@ module ActionController cattr_accessor :allow_concurrency self.allow_concurrency = false - cattr_accessor :param_parsers - self.param_parsers = { Mime::MULTIPART_FORM => :multipart_form, - Mime::URL_ENCODED_FORM => :url_encoded_form, - Mime::XML => :xml_simple, - Mime::JSON => :json } - cattr_accessor :relative_url_root self.relative_url_root = ENV['RAILS_RELATIVE_URL_ROOT'] diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb index ff2b2fe74b..32ccb5c931 100644 --- a/actionpack/lib/action_dispatch/middleware/params_parser.rb +++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb @@ -2,11 +2,13 @@ require 'active_support/json' module ActionDispatch class ParamsParser - ActionController::Base.param_parsers[Mime::XML] = :xml_simple - ActionController::Base.param_parsers[Mime::JSON] = :json + DEFAULT_PARSERS = { + Mime::XML => :xml_simple, + Mime::JSON => :json + } - def initialize(app) - @app = app + def initialize(app, parsers = {}) + @app, @parsers = app, DEFAULT_PARSERS.merge(parsers) end def call(env) @@ -24,7 +26,7 @@ module ActionDispatch return false if request.content_length.zero? mime_type = content_type_from_legacy_post_data_format_header(env) || request.content_type - strategy = ActionController::Base.param_parsers[mime_type] + strategy = @parsers[mime_type] return false unless strategy diff --git a/actionpack/test/controller/webservice_test.rb b/actionpack/test/controller/webservice_test.rb index 9bf8da7276..3fded34d78 100644 --- a/actionpack/test/controller/webservice_test.rb +++ b/actionpack/test/controller/webservice_test.rb @@ -24,11 +24,6 @@ class WebServiceTest < ActionController::IntegrationTest def setup @controller = TestController.new - @default_param_parsers = ActionController::Base.param_parsers.dup - end - - def teardown - ActionController::Base.param_parsers = @default_param_parsers end def test_check_parameters @@ -110,58 +105,61 @@ class WebServiceTest < ActionController::IntegrationTest def test_post_xml_using_an_attributted_node_named_type with_test_route_set do - ActionController::Base.param_parsers[Mime::XML] = Proc.new { |data| Hash.from_xml(data)['request'].with_indifferent_access } - post "/", 'Arial,123', - {'CONTENT_TYPE' => 'application/xml'} - - assert_equal 'type, z', @controller.response.body - assert @controller.params.has_key?(:type) - assert_equal 'Arial,12', @controller.params['type'], @controller.params.inspect - assert_equal '3', @controller.params['z'], @controller.params.inspect + with_params_parsers Mime::XML => Proc.new { |data| Hash.from_xml(data)['request'].with_indifferent_access } do + post "/", 'Arial,123', + {'CONTENT_TYPE' => 'application/xml'} + + assert_equal 'type, z', @controller.response.body + assert @controller.params.has_key?(:type) + assert_equal 'Arial,12', @controller.params['type'], @controller.params.inspect + assert_equal '3', @controller.params['z'], @controller.params.inspect + end end end def test_register_and_use_yaml with_test_route_set do - ActionController::Base.param_parsers[Mime::YAML] = Proc.new { |d| YAML.load(d) } - post "/", {"entry" => "loaded from yaml"}.to_yaml, - {'CONTENT_TYPE' => 'application/x-yaml'} + with_params_parsers Mime::YAML => Proc.new { |d| YAML.load(d) } do + post "/", {"entry" => "loaded from yaml"}.to_yaml, + {'CONTENT_TYPE' => 'application/x-yaml'} - assert_equal 'entry', @controller.response.body - assert @controller.params.has_key?(:entry) - assert_equal 'loaded from yaml', @controller.params["entry"] + assert_equal 'entry', @controller.response.body + assert @controller.params.has_key?(:entry) + assert_equal 'loaded from yaml', @controller.params["entry"] + end end end def test_register_and_use_yaml_as_symbol with_test_route_set do - ActionController::Base.param_parsers[Mime::YAML] = :yaml - post "/", {"entry" => "loaded from yaml"}.to_yaml, - {'CONTENT_TYPE' => 'application/x-yaml'} + with_params_parsers Mime::YAML => :yaml do + post "/", {"entry" => "loaded from yaml"}.to_yaml, + {'CONTENT_TYPE' => 'application/x-yaml'} - assert_equal 'entry', @controller.response.body - assert @controller.params.has_key?(:entry) - assert_equal 'loaded from yaml', @controller.params["entry"] + assert_equal 'entry', @controller.response.body + assert @controller.params.has_key?(:entry) + assert_equal 'loaded from yaml', @controller.params["entry"] + end end end def test_register_and_use_xml_simple with_test_route_set do - ActionController::Base.param_parsers[Mime::XML] = Proc.new { |data| Hash.from_xml(data)['request'].with_indifferent_access } - post "/", 'content...SimpleXml', - {'CONTENT_TYPE' => 'application/xml'} - - assert_equal 'summary, title', @controller.response.body - assert @controller.params.has_key?(:summary) - assert @controller.params.has_key?(:title) - assert_equal 'content...', @controller.params["summary"] - assert_equal 'SimpleXml', @controller.params["title"] + with_params_parsers Mime::XML => Proc.new { |data| Hash.from_xml(data)['request'].with_indifferent_access } do + post "/", 'content...SimpleXml', + {'CONTENT_TYPE' => 'application/xml'} + + assert_equal 'summary, title', @controller.response.body + assert @controller.params.has_key?(:summary) + assert @controller.params.has_key?(:title) + assert_equal 'content...', @controller.params["summary"] + assert_equal 'SimpleXml', @controller.params["title"] + end end end def test_use_xml_ximple_with_empty_request with_test_route_set do - ActionController::Base.param_parsers[Mime::XML] = :xml_simple assert_nothing_raised { post "/", "", {'CONTENT_TYPE' => 'application/xml'} } assert @controller.response.body.blank? end @@ -169,7 +167,6 @@ class WebServiceTest < ActionController::IntegrationTest def test_dasherized_keys_as_xml with_test_route_set do - ActionController::Base.param_parsers[Mime::XML] = :xml_simple post "/?full=1", "\n...\n", {'CONTENT_TYPE' => 'application/xml'} assert_equal 'action, controller, first_key(sub_key), full', @controller.response.body @@ -179,7 +176,6 @@ class WebServiceTest < ActionController::IntegrationTest def test_typecast_as_xml with_test_route_set do - ActionController::Base.param_parsers[Mime::XML] = :xml_simple xml = <<-XML 15 @@ -208,7 +204,6 @@ class WebServiceTest < ActionController::IntegrationTest def test_entities_unescaped_as_xml_simple with_test_route_set do - ActionController::Base.param_parsers[Mime::XML] = :xml_simple xml = <<-XML <foo "bar's" & friends> XML @@ -219,34 +214,44 @@ class WebServiceTest < ActionController::IntegrationTest def test_typecast_as_yaml with_test_route_set do - ActionController::Base.param_parsers[Mime::YAML] = :yaml - yaml = <<-YAML - --- - data: - a: 15 - b: false - c: true - d: 2005-03-17 - e: 2005-03-17T21:41:07Z - f: unparsed - g: - - 1 - - hello - - 1974-07-25 - YAML - post "/", yaml, {'CONTENT_TYPE' => 'application/x-yaml'} - params = @controller.params - assert_equal 15, params[:data][:a] - assert_equal false, params[:data][:b] - assert_equal true, params[:data][:c] - assert_equal Date.new(2005,3,17), params[:data][:d] - assert_equal Time.utc(2005,3,17,21,41,7), params[:data][:e] - assert_equal "unparsed", params[:data][:f] - assert_equal [1, "hello", Date.new(1974,7,25)], params[:data][:g] + with_params_parsers Mime::YAML => :yaml do + yaml = <<-YAML + --- + data: + a: 15 + b: false + c: true + d: 2005-03-17 + e: 2005-03-17T21:41:07Z + f: unparsed + g: + - 1 + - hello + - 1974-07-25 + YAML + post "/", yaml, {'CONTENT_TYPE' => 'application/x-yaml'} + params = @controller.params + assert_equal 15, params[:data][:a] + assert_equal false, params[:data][:b] + assert_equal true, params[:data][:c] + assert_equal Date.new(2005,3,17), params[:data][:d] + assert_equal Time.utc(2005,3,17,21,41,7), params[:data][:e] + assert_equal "unparsed", params[:data][:f] + assert_equal [1, "hello", Date.new(1974,7,25)], params[:data][:g] + end end end private + def with_params_parsers(parsers = {}) + old_session = @integration_session + app = ActionDispatch::ParamsParser.new(ActionController::Routing::Routes, parsers) + @integration_session = open_session(app) + yield + ensure + @integration_session = old_session + end + def with_test_route_set with_routing do |set| set.draw do |map| -- cgit v1.2.3 From c7ba911a43e513bd1adbee93f16d2b8efea7cc88 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Tue, 25 Aug 2009 12:14:31 -0700 Subject: ActionController::Metal can be a middleware --- actionpack/lib/action_controller/metal.rb | 40 ++++++++++++++++--- .../action_controller/metal/rack_convenience.rb | 8 +--- actionpack/lib/action_dispatch/http/response.rb | 5 ++- actionpack/test/new_base/metal_test.rb | 45 ++++++++++++++++++++++ 4 files changed, 85 insertions(+), 13 deletions(-) create mode 100644 actionpack/test/new_base/metal_test.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb index 5333ca497c..aad9570237 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -47,7 +47,7 @@ module ActionController # and response object available. You might wish to control the # environment and response manually for performance reasons. - attr_internal :status, :headers, :content_type + attr_internal :status, :headers, :content_type, :app, :response def initialize(*) @_headers = {} @@ -75,7 +75,34 @@ module ActionController # :api: private def to_a - [status, headers, response_body] + response ? response.to_a : [status, headers, response_body] + end + + class ActionEndpoint + def initialize(controller, action) + @controller, @action = controller, action + end + + def call(env) + controller = @controller.new.call(@action, env) + end + end + + class ActionMiddleware + def initialize(controller, action) + @controller, @action = controller, action + end + + def call(env) + controller = @controller.new + controller.app = @app + controller.call(@action, env) + end + + def new(app) + @app = app + self + end end # Return a rack endpoint for the given action. Memoize the endpoint, so @@ -89,9 +116,12 @@ module ActionController # Proc:: A rack application def self.action(name) @actions ||= {} - @actions[name.to_s] ||= proc do |env| - new.call(name, env) - end + @actions[name.to_s] ||= ActionEndpoint.new(self, name) + end + + def self.middleware(name) + @middlewares ||= {} + @middlewares[name.to_s] ||= ActionMiddleware.new(self, name) end end end diff --git a/actionpack/lib/action_controller/metal/rack_convenience.rb b/actionpack/lib/action_controller/metal/rack_convenience.rb index 5fac445dab..a80569c530 100644 --- a/actionpack/lib/action_controller/metal/rack_convenience.rb +++ b/actionpack/lib/action_controller/metal/rack_convenience.rb @@ -5,7 +5,7 @@ module ActionController included do delegate :headers, :status=, :location=, :content_type=, :status, :location, :content_type, :to => "@_response" - attr_internal :request, :response + attr_internal :request end def call(name, env) @@ -19,12 +19,6 @@ module ActionController @_params ||= @_request.parameters end - # :api: private - def to_a - @_response.prepare! - @_response.to_a - end - def response_body=(body) response.body = body if response super diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index 055f29a972..e457450059 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -161,13 +161,16 @@ module ActionDispatch # :nodoc: headers[CONTENT_TYPE] = type end - def prepare! + def to_a assign_default_content_type_and_charset! handle_conditional_get! self["Set-Cookie"] = @cookie.join("\n") self["ETag"] = @etag if @etag + super end + alias prepare! to_a + def each(&callback) if @body.respond_to?(:call) @writer = lambda { |x| callback.call(x) } diff --git a/actionpack/test/new_base/metal_test.rb b/actionpack/test/new_base/metal_test.rb new file mode 100644 index 0000000000..c7c45b5cc9 --- /dev/null +++ b/actionpack/test/new_base/metal_test.rb @@ -0,0 +1,45 @@ +require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") + +module MetalTest + class MetalMiddleware < ActionController::Metal + def index + if env["PATH_INFO"] =~ /authed/ + self.response = app.call(env) + else + self.response_body = "Not authed!" + self.status = 401 + end + end + end + + class Endpoint + def call(env) + [200, {}, "Hello World"] + end + end + + class TestMiddleware < ActiveSupport::TestCase + def setup + @app = Rack::Builder.new do + use MetalMiddleware.middleware(:index) + run Endpoint.new + end.to_app + end + + test "it can call the next app by using @app" do + env = Rack::MockRequest.env_for("/authed") + response = @app.call(env) + + assert_equal "Hello World", response[2] + end + + test "it can return a response using the normal AC::Metal techniques" do + env = Rack::MockRequest.env_for("/") + response = @app.call(env) + + assert_equal "Not authed!", response[2] + assert_equal 401, response[0] + end + end +end + -- cgit v1.2.3 From 86c7b144fadf87736cf3d7e623d56eddae8e9963 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Tue, 25 Aug 2009 15:04:09 -0700 Subject: Add a TODO so we remember to fix partial layouts --- actionpack/lib/abstract_controller/layouts.rb | 3 +++ 1 file changed, 3 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index a8bd2b80e1..ef66b24dd6 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -145,6 +145,9 @@ module AbstractController # This is a little bit messy. We need to explicitly handle partial # layouts here since the core lookup logic is in the view, but # we need to determine the layout based on the controller + # + # TODO: An easier way to handle this would probably be to override + # render_template if layout layout = _layout_for_option(layout, options[:_template].details) response = layout.render(view_context, options[:locals] || {}) { response } -- cgit v1.2.3 From 469424c85e877c4c6f822c31e8462ff1778550eb Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Tue, 25 Aug 2009 15:05:23 -0700 Subject: Modify Digest and Basic to take a request so they can be used outside of the controller --- .../lib/action_controller/metal/http_authentication.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb index 2b62a1be85..e33882cc1b 100644 --- a/actionpack/lib/action_controller/metal/http_authentication.rb +++ b/actionpack/lib/action_controller/metal/http_authentication.rb @@ -115,7 +115,7 @@ module ActionController end def authenticate_with_http_basic(&login_procedure) - HttpAuthentication::Basic.authenticate(self, &login_procedure) + HttpAuthentication::Basic.authenticate(request, &login_procedure) end def request_http_basic_authentication(realm = "Application") @@ -123,9 +123,9 @@ module ActionController end end - def authenticate(controller, &login_procedure) - unless authorization(controller.request).blank? - login_procedure.call(*user_name_and_password(controller.request)) + def authenticate(request, &login_procedure) + unless authorization(request).blank? + login_procedure.call(*user_name_and_password(request)) end end @@ -164,7 +164,7 @@ module ActionController # Authenticate with HTTP Digest, returns true or false def authenticate_with_http_digest(realm = "Application", &password_procedure) - HttpAuthentication::Digest.authenticate(self, realm, &password_procedure) + HttpAuthentication::Digest.authenticate(request, realm, &password_procedure) end # Render output including the HTTP Digest authentication header @@ -174,8 +174,8 @@ module ActionController end # Returns false on a valid response, true otherwise - def authenticate(controller, realm, &password_procedure) - authorization(controller.request) && validate_digest_response(controller.request, realm, &password_procedure) + def authenticate(request, realm, &password_procedure) + authorization(request) && validate_digest_response(request, realm, &password_procedure) end def authorization(request) -- cgit v1.2.3 From a21aaca8eaa8f451fb0ec4814b51323439bd36ff Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Tue, 25 Aug 2009 17:04:09 -0700 Subject: Rework Middleware stack to match the Rack middleware protocol more closely --- actionpack/lib/action_dispatch/middleware/stack.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb index ade2d6f05e..4f71ea6165 100644 --- a/actionpack/lib/action_dispatch/middleware/stack.rb +++ b/actionpack/lib/action_dispatch/middleware/stack.rb @@ -27,10 +27,10 @@ module ActionDispatch end def klass - if @klass.respond_to?(:call) - @klass.call - elsif @klass.is_a?(Class) + if @klass.respond_to?(:new) @klass + elsif @klass.respond_to?(:call) + @klass.call else @klass.to_s.constantize end -- cgit v1.2.3 From 303f9b8841b1f12ddd7bbc9c6b2e010eafd8e551 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Tue, 25 Aug 2009 17:20:58 -0700 Subject: Redirector had an undeclared dependency on Logger. --- actionpack/lib/action_controller/metal/redirector.rb | 3 +++ 1 file changed, 3 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal/redirector.rb b/actionpack/lib/action_controller/metal/redirector.rb index 20060b001f..f79fd54acd 100644 --- a/actionpack/lib/action_controller/metal/redirector.rb +++ b/actionpack/lib/action_controller/metal/redirector.rb @@ -8,6 +8,9 @@ module ActionController end module Redirector + extend ActiveSupport::Concern + include AbstractController::Logger + def redirect_to(url, status) #:doc: raise AbstractController::DoubleRenderError if response_body logger.info("Redirected to #{url}") if logger && logger.info? -- cgit v1.2.3 From 3a5269eba434b56cca2688218b7687bd7c1bc53c Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Tue, 25 Aug 2009 17:29:48 -0700 Subject: HTTP Auth should not depend on RenderingController --- actionpack/lib/action_controller/metal/http_authentication.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb index e33882cc1b..473fa164a6 100644 --- a/actionpack/lib/action_controller/metal/http_authentication.rb +++ b/actionpack/lib/action_controller/metal/http_authentication.rb @@ -243,7 +243,8 @@ module ActionController def authentication_request(controller, realm, message = nil) message ||= "HTTP Digest: Access denied.\n" authentication_header(controller, realm) - controller.__send__ :render, :text => message, :status => :unauthorized + controller.response_body = message + controller.status = 401 end # Uses an MD5 digest based on time to generate a value to be used only once. -- cgit v1.2.3 From 5bc66f160d03bd60a748ac65728227ed9e4fc577 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Tue, 25 Aug 2009 17:34:07 -0700 Subject: And the same thing for Basic --- actionpack/lib/action_controller/metal/http_authentication.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb index 473fa164a6..0f35a7c040 100644 --- a/actionpack/lib/action_controller/metal/http_authentication.rb +++ b/actionpack/lib/action_controller/metal/http_authentication.rb @@ -150,7 +150,8 @@ module ActionController def authentication_request(controller, realm) controller.headers["WWW-Authenticate"] = %(Basic realm="#{realm.gsub(/"/, "")}") - controller.__send__ :render, :text => "HTTP Basic: Access denied.\n", :status => :unauthorized + controller.response_body = "HTTP Basic: Access denied.\n" + controller.status = 401 end end -- cgit v1.2.3 From 78129b1731a1e6f3b091e996bcf55917d84b5f0e Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 25 Aug 2009 23:34:48 -0500 Subject: Track all AC base subclasses as possible controllers for internal testing --- actionpack/test/abstract_unit.rb | 12 +++ .../test/controller/action_pack_assertions_test.rb | 8 -- actionpack/test/controller/routing_test.rb | 86 ++++------------------ actionpack/test/controller/test_test.rb | 3 - actionpack/test/lib/controller/fake_controllers.rb | 9 ++- actionpack/test/new_base/test_helper.rb | 24 ++++-- 6 files changed, 50 insertions(+), 92 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index a21b00915e..07ba37c51c 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -62,8 +62,20 @@ module ActionController } Base.session_store = nil + class << Routing + def possible_controllers + @@possible_controllers ||= [] + end + end + class Base include ActionController::Testing + + def self.inherited(klass) + name = klass.name.underscore.sub(/_controller$/, '') + ActionController::Routing.possible_controllers << name unless name.blank? + super + end end Base.view_paths = FIXTURE_LOAD_PATH diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index 06827e5fbc..453812c128 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -182,14 +182,6 @@ end # a test case to exercise the new capabilities TestRequest & TestResponse class ActionPackAssertionsControllerTest < ActionController::TestCase - # let's get this party started - def setup - super - - ActionController::Routing.use_controllers!(%w(action_pack_assertions admin/inner_module user content admin/user)) - ActionController::Routing::Routes.load_routes! - end - # -- assertion-based testing ------------------------------------------------ def test_assert_tag_and_url_for diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index 5be780dd42..d20684296f 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -44,11 +44,11 @@ class UriReservedCharactersRoutingTest < Test::Unit::TestCase end def test_route_recognition_unescapes_path_components - options = { :controller => "controller", + options = { :controller => "content", :action => "act#{@segment}ion", :variable => "var#{@segment}iable", :additional => ["add#{@segment}itional-1", "add#{@segment}itional-2"] } - assert_equal options, @set.recognize_path("/controller/act#{@escaped}ion/var#{@escaped}iable/add#{@escaped}itional-1/add#{@escaped}itional-2") + assert_equal options, @set.recognize_path("/content/act#{@escaped}ion/var#{@escaped}iable/add#{@escaped}itional-1/add#{@escaped}itional-2") end def test_route_generation_allows_passing_non_string_values_to_generated_helper @@ -60,58 +60,6 @@ class UriReservedCharactersRoutingTest < Test::Unit::TestCase end class RoutingTest < Test::Unit::TestCase - def test_possible_controllers - true_controller_paths = ActionController::Routing.controller_paths - - ActionController::Routing.use_controllers! nil - - Object.send(:remove_const, :RAILS_ROOT) if defined?(::RAILS_ROOT) - Object.const_set(:RAILS_ROOT, File.dirname(__FILE__) + '/controller_fixtures') - - ActionController::Routing.controller_paths = [ - RAILS_ROOT, RAILS_ROOT + '/app/controllers', RAILS_ROOT + '/vendor/plugins/bad_plugin/lib' - ] - - assert_equal ["admin/user", "plugin", "user"], ActionController::Routing.possible_controllers.sort - ensure - if true_controller_paths - ActionController::Routing.controller_paths = true_controller_paths - end - ActionController::Routing.use_controllers! nil - Object.send(:remove_const, :RAILS_ROOT) rescue nil - end - - def test_possible_controllers_are_reset_on_each_load - true_possible_controllers = ActionController::Routing.possible_controllers - true_controller_paths = ActionController::Routing.controller_paths - - ActionController::Routing.use_controllers! nil - root = File.dirname(__FILE__) + '/controller_fixtures' - - ActionController::Routing.controller_paths = [] - assert_equal [], ActionController::Routing.possible_controllers - - ActionController::Routing.controller_paths = [ - root, root + '/app/controllers', root + '/vendor/plugins/bad_plugin/lib' - ] - ActionController::Routing::Routes.load! - - assert_equal ["admin/user", "plugin", "user"], ActionController::Routing.possible_controllers.sort - ensure - ActionController::Routing.controller_paths = true_controller_paths - ActionController::Routing.use_controllers! true_possible_controllers - Object.send(:remove_const, :RAILS_ROOT) rescue nil - - ActionController::Routing::Routes.reload! - end - - def test_with_controllers - c = %w(admin/accounts admin/users account pages) - ActionController::Routing.with_controllers c do - assert_equal c, ActionController::Routing.possible_controllers - end - end - def test_normalize_unix_paths load_paths = %w(. config/../app/controllers config/../app//helpers script/../config/../vendor/rails/actionpack/lib vendor/rails/railties/builtin/rails_info app/models lib script/../config/../foo/bar/../../app/models .foo/../.bar foo.bar/../config) paths = ActionController::Routing.normalize_paths(load_paths) @@ -1815,22 +1763,20 @@ class RouteSetTest < ActiveSupport::TestCase end def test_slashes_are_implied - ActionController::Routing.with_controllers(['foo']) do - ['/:controller/:action/:id/', '/:controller/:action/:id', - ':controller/:action/:id', '/:controller/:action/:id/' - ].each do |path| - @set = nil - set.draw { |map| map.connect(path) } - - assert_equal '/foo', set.generate(:controller => 'foo', :action => 'index') - assert_equal '/foo/list', set.generate(:controller => 'foo', :action => 'list') - assert_equal '/foo/show/1', set.generate(:controller => 'foo', :action => 'show', :id => '1') - - assert_equal({:controller => "foo", :action => "index"}, set.recognize_path('/foo')) - assert_equal({:controller => "foo", :action => "index"}, set.recognize_path('/foo/index')) - assert_equal({:controller => "foo", :action => "list"}, set.recognize_path('/foo/list')) - assert_equal({:controller => "foo", :action => "show", :id => "1"}, set.recognize_path('/foo/show/1')) - end + ['/:controller/:action/:id/', '/:controller/:action/:id', + ':controller/:action/:id', '/:controller/:action/:id/' + ].each do |path| + @set = nil + set.draw { |map| map.connect(path) } + + assert_equal '/content', set.generate(:controller => 'content', :action => 'index') + assert_equal '/content/list', set.generate(:controller => 'content', :action => 'list') + assert_equal '/content/show/1', set.generate(:controller => 'content', :action => 'show', :id => '1') + + assert_equal({:controller => "content", :action => "index"}, set.recognize_path('/content')) + assert_equal({:controller => "content", :action => "index"}, set.recognize_path('/content/index')) + assert_equal({:controller => "content", :action => "list"}, set.recognize_path('/content/list')) + assert_equal({:controller => "content", :action => "show", :id => "1"}, set.recognize_path('/content/show/1')) end end diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb index 84c97851ee..73870a56bb 100644 --- a/actionpack/test/controller/test_test.rb +++ b/actionpack/test/controller/test_test.rb @@ -123,9 +123,6 @@ XML @controller = TestController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new - - ActionController::Routing.use_controllers! %w(content admin/user test_test/test) - ActionController::Routing::Routes.load_routes! end def test_raw_post_handling diff --git a/actionpack/test/lib/controller/fake_controllers.rb b/actionpack/test/lib/controller/fake_controllers.rb index 75c114c103..6e02e2d21b 100644 --- a/actionpack/test/lib/controller/fake_controllers.rb +++ b/actionpack/test/lib/controller/fake_controllers.rb @@ -1,15 +1,16 @@ class << Object; alias_method :const_available?, :const_defined?; end - -class ContentController < Class.new(ActionController::Base) + +class ContentController < ActionController::Base end class NotAController end module Admin class << self; alias_method :const_available?, :const_defined?; end - class UserController < Class.new(ActionController::Base); end - class NewsFeedController < Class.new(ActionController::Base); end + class UserController < ActionController::Base; end + class NewsFeedController < ActionController::Base; end end + # For speed test class SpeedController < ActionController::Base; end class SearchController < SpeedController; end diff --git a/actionpack/test/new_base/test_helper.rb b/actionpack/test/new_base/test_helper.rb index 9271b2dd59..b7ccd3db8d 100644 --- a/actionpack/test/new_base/test_helper.rb +++ b/actionpack/test/new_base/test_helper.rb @@ -35,12 +35,6 @@ class Rack::TestCase < ActionController::IntegrationTest setup do ActionController::Base.session_options[:key] = "abc" ActionController::Base.session_options[:secret] = ("*" * 30) - - controllers = ActionController::Base.subclasses.map do |k| - k.underscore.sub(/_controller$/, '') - end - - ActionController::Routing.use_controllers!(controllers) end def app @@ -91,10 +85,26 @@ end class ::ApplicationController < ActionController::Base end +module ActionController + class << Routing + def possible_controllers + @@possible_controllers ||= [] + end + end + + class Base + def self.inherited(klass) + name = klass.name.underscore.sub(/_controller$/, '') + ActionController::Routing.possible_controllers << name unless name.blank? + super + end + end +end + class SimpleRouteCase < Rack::TestCase setup do ActionController::Routing::Routes.draw do |map| map.connect ':controller/:action/:id' end end -end \ No newline at end of file +end -- cgit v1.2.3 From 9408fcd2e858ae48dd30d9e8d1bb1dcbbfffb840 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Wed, 26 Aug 2009 00:18:52 -0700 Subject: Create new ActionController::Middleware class that will work as a normal Rack middleware. * This initial implementation is a bit hackish, but it uses a normal middleware API so it's future-proof when we improve the internals. --- actionpack/lib/abstract_controller/base.rb | 1 - actionpack/lib/action_controller.rb | 1 + actionpack/lib/action_controller/metal.rb | 22 ----- actionpack/lib/action_controller/middleware.rb | 34 ++++++++ .../abstract_controller_test.rb | 53 +++++++----- .../test/abstract_controller/callbacks_test.rb | 94 +++++++++++++--------- actionpack/test/abstract_controller/helper_test.rb | 5 +- .../test/abstract_controller/layouts_test.rb | 55 ++++++++----- actionpack/test/new_base/metal_test.rb | 11 ++- 9 files changed, 166 insertions(+), 110 deletions(-) create mode 100644 actionpack/lib/action_controller/middleware.rb (limited to 'actionpack') diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb index b93e6ce634..f5b1c9e4d1 100644 --- a/actionpack/lib/abstract_controller/base.rb +++ b/actionpack/lib/abstract_controller/base.rb @@ -89,7 +89,6 @@ module AbstractController end process_action(action_name) - self end private diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index 37ff618edd..d27a867efe 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -3,6 +3,7 @@ module ActionController autoload :ConditionalGet, "action_controller/metal/conditional_get" autoload :HideActions, "action_controller/metal/hide_actions" autoload :Metal, "action_controller/metal" + autoload :Middleware, "action_controller/middleware" autoload :Layouts, "action_controller/metal/layouts" autoload :RackConvenience, "action_controller/metal/rack_convenience" autoload :Rails2Compatibility, "action_controller/metal/compatibility" diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb index aad9570237..51fbba3661 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -88,23 +88,6 @@ module ActionController end end - class ActionMiddleware - def initialize(controller, action) - @controller, @action = controller, action - end - - def call(env) - controller = @controller.new - controller.app = @app - controller.call(@action, env) - end - - def new(app) - @app = app - self - end - end - # Return a rack endpoint for the given action. Memoize the endpoint, so # multiple calls into MyController.action will return the same object # for the same action. @@ -118,10 +101,5 @@ module ActionController @actions ||= {} @actions[name.to_s] ||= ActionEndpoint.new(self, name) end - - def self.middleware(name) - @middlewares ||= {} - @middlewares[name.to_s] ||= ActionMiddleware.new(self, name) - end end end diff --git a/actionpack/lib/action_controller/middleware.rb b/actionpack/lib/action_controller/middleware.rb new file mode 100644 index 0000000000..5fccca0b48 --- /dev/null +++ b/actionpack/lib/action_controller/middleware.rb @@ -0,0 +1,34 @@ +module ActionController + class Middleware < Metal + class ActionMiddleware + def initialize(controller) + @controller = controller + end + + def call(env) + controller = @controller.allocate + controller.app = @app + controller._call(env) + end + + def app=(app) + @app = app + end + end + + def self.new(app) + middleware = ActionMiddleware.new(self) + middleware.app = app + middleware + end + + def _call(env) + @_env = env + process(:index) + end + + def index + call(env) + end + end +end \ No newline at end of file diff --git a/actionpack/test/abstract_controller/abstract_controller_test.rb b/actionpack/test/abstract_controller/abstract_controller_test.rb index 9438a4dfc9..7991436703 100644 --- a/actionpack/test/abstract_controller/abstract_controller_test.rb +++ b/actionpack/test/abstract_controller/abstract_controller_test.rb @@ -19,8 +19,9 @@ module AbstractController class TestBasic < ActiveSupport::TestCase test "dispatching works" do - result = Me.new.process(:index) - assert_equal "Hello world", result.response_body + controller = Me.new + controller.process(:index) + assert_equal "Hello world", controller.response_body end end @@ -67,29 +68,33 @@ module AbstractController end class TestRenderingController < ActiveSupport::TestCase + def setup + @controller = Me2.new + end + test "rendering templates works" do - result = Me2.new.process(:index) - assert_equal "Hello from index.erb", result.response_body + @controller.process(:index) + assert_equal "Hello from index.erb", @controller.response_body end test "rendering passes ivars to the view" do - result = Me2.new.process(:action_with_ivars) - assert_equal "Hello from index_with_ivars.erb", result.response_body + @controller.process(:action_with_ivars) + assert_equal "Hello from index_with_ivars.erb", @controller.response_body end test "rendering with no template name" do - result = Me2.new.process(:naked_render) - assert_equal "Hello from naked_render.erb", result.response_body + @controller.process(:naked_render) + assert_equal "Hello from naked_render.erb", @controller.response_body end test "rendering to a rack body" do - result = Me2.new.process(:rendering_to_body) - assert_equal "Hello from naked_render.erb", result.response_body + @controller.process(:rendering_to_body) + assert_equal "Hello from naked_render.erb", @controller.response_body end test "rendering to a string" do - result = Me2.new.process(:rendering_to_string) - assert_equal "Hello from naked_render.erb", result.response_body + @controller.process(:rendering_to_string) + assert_equal "Hello from naked_render.erb", @controller.response_body end end @@ -119,14 +124,18 @@ module AbstractController end class TestPrefixedViews < ActiveSupport::TestCase + def setup + @controller = Me3.new + end + test "templates are located inside their 'prefix' folder" do - result = Me3.new.process(:index) - assert_equal "Hello from me3/index.erb", result.response_body + @controller.process(:index) + assert_equal "Hello from me3/index.erb", @controller.response_body end test "templates included their format" do - result = Me3.new.process(:formatted) - assert_equal "Hello from me3/formatted.html.erb", result.response_body + @controller.process(:formatted) + assert_equal "Hello from me3/formatted.html.erb", @controller.response_body end end @@ -168,8 +177,9 @@ module AbstractController class TestLayouts < ActiveSupport::TestCase test "layouts are included" do - result = Me4.new.process(:index) - assert_equal "Me4 Enter : Hello from me4/index.erb : Exit", result.response_body + controller = Me4.new + result = controller.process(:index) + assert_equal "Me4 Enter : Hello from me4/index.erb : Exit", controller.response_body end end @@ -203,10 +213,11 @@ module AbstractController end class TestRespondToAction < ActiveSupport::TestCase - + def assert_dispatch(klass, body = "success", action = :index) - response = klass.new.process(action).response_body - assert_equal body, response + controller = klass.new + controller.process(action) + assert_equal body, controller.response_body end test "an arbitrary method is available as an action by default" do diff --git a/actionpack/test/abstract_controller/callbacks_test.rb b/actionpack/test/abstract_controller/callbacks_test.rb index 817f60f7d1..8f62adce8c 100644 --- a/actionpack/test/abstract_controller/callbacks_test.rb +++ b/actionpack/test/abstract_controller/callbacks_test.rb @@ -19,10 +19,11 @@ module AbstractController end end - class TestCallbacks < ActiveSupport::TestCase + class TestCallbacks1 < ActiveSupport::TestCase test "basic callbacks work" do - result = Callback1.new.process(:index) - assert_equal "Hello world", result.response_body + controller = Callback1.new + result = controller.process(:index) + assert_equal "Hello world", controller.response_body end end @@ -50,20 +51,24 @@ module AbstractController end end - class TestCallbacks < ActiveSupport::TestCase + class TestCallbacks2 < ActiveSupport::TestCase + def setup + @controller = Callback2.new + end + test "before_filter works" do - result = Callback2.new.process(:index) - assert_equal "Hello world", result.response_body + result = @controller.process(:index) + assert_equal "Hello world", @controller.response_body end test "after_filter works" do - result = Callback2.new.process(:index) - assert_equal "Goodbye", result.instance_variable_get("@second") + @controller.process(:index) + assert_equal "Goodbye", @controller.instance_variable_get("@second") end test "around_filter works" do - result = Callback2.new.process(:index) - assert_equal "FIRSTSECOND", result.instance_variable_get("@aroundz") + @controller.process(:index) + assert_equal "FIRSTSECOND", @controller.instance_variable_get("@aroundz") end end @@ -81,15 +86,19 @@ module AbstractController end end - class TestCallbacks < ActiveSupport::TestCase + class TestCallbacks3 < ActiveSupport::TestCase + def setup + @controller = Callback3.new + end + test "before_filter works with procs" do - result = Callback3.new.process(:index) - assert_equal "Hello world", result.response_body + result = @controller.process(:index) + assert_equal "Hello world", @controller.response_body end test "after_filter works with procs" do - result = Callback3.new.process(:index) - assert_equal "Goodbye", result.instance_variable_get("@second") + result = @controller.process(:index) + assert_equal "Goodbye", @controller.instance_variable_get("@second") end end @@ -116,20 +125,24 @@ module AbstractController end end - class TestCallbacks < ActiveSupport::TestCase + class TestCallbacksWithConditions < ActiveSupport::TestCase + def setup + @controller = CallbacksWithConditions.new + end + test "when :only is specified, a before filter is triggered on that action" do - result = CallbacksWithConditions.new.process(:index) - assert_equal "Hello, World", result.response_body + @controller.process(:index) + assert_equal "Hello, World", @controller.response_body end test "when :only is specified, a before filter is not triggered on other actions" do - result = CallbacksWithConditions.new.process(:sekrit_data) - assert_equal "true", result.response_body + @controller.process(:sekrit_data) + assert_equal "true", @controller.response_body end test "when :except is specified, an after filter is not triggered on that action" do - result = CallbacksWithConditions.new.process(:index) - assert_nil result.instance_variable_get("@authenticated") + result = @controller.process(:index) + assert_nil @controller.instance_variable_get("@authenticated") end end @@ -156,20 +169,24 @@ module AbstractController end end - class TestCallbacks < ActiveSupport::TestCase + class TestCallbacksWithArrayConditions < ActiveSupport::TestCase + def setup + @controller = CallbacksWithArrayConditions.new + end + test "when :only is specified with an array, a before filter is triggered on that action" do - result = CallbacksWithArrayConditions.new.process(:index) - assert_equal "Hello, World", result.response_body + result = @controller.process(:index) + assert_equal "Hello, World", @controller.response_body end test "when :only is specified with an array, a before filter is not triggered on other actions" do - result = CallbacksWithArrayConditions.new.process(:sekrit_data) - assert_equal "true", result.response_body + result = @controller.process(:sekrit_data) + assert_equal "true", @controller.response_body end test "when :except is specified with an array, an after filter is not triggered on that action" do - result = CallbacksWithArrayConditions.new.process(:index) - assert_nil result.instance_variable_get("@authenticated") + result = @controller.process(:index) + assert_nil @controller.instance_variable_get("@authenticated") end end @@ -181,15 +198,19 @@ module AbstractController end end - class TestCallbacks < ActiveSupport::TestCase + class TestCallbacksWithChangedConditions < ActiveSupport::TestCase + def setup + @controller = ChangedConditions.new + end + test "when a callback is modified in a child with :only, it works for the :only action" do - result = ChangedConditions.new.process(:index) - assert_equal "Hello world", result.response_body + result = @controller.process(:index) + assert_equal "Hello world", @controller.response_body end test "when a callback is modified in a child with :only, it does not work for other actions" do - result = ChangedConditions.new.process(:not_index) - assert_equal "", result.response_body + result = @controller.process(:not_index) + assert_equal "", @controller.response_body end end @@ -207,8 +228,9 @@ module AbstractController class TestHalting < ActiveSupport::TestCase test "when a callback sets the response body, the action should not be invoked" do - result = SetsResponseBody.new.process(:index) - assert_equal "Success", result.response_body + controller = SetsResponseBody.new + controller.process(:index) + assert_equal "Success", controller.response_body end end diff --git a/actionpack/test/abstract_controller/helper_test.rb b/actionpack/test/abstract_controller/helper_test.rb index e9a60c0307..34a10cecc9 100644 --- a/actionpack/test/abstract_controller/helper_test.rb +++ b/actionpack/test/abstract_controller/helper_test.rb @@ -34,8 +34,9 @@ module AbstractController class TestHelpers < ActiveSupport::TestCase def test_helpers - result = MyHelpers1.new.process(:index) - assert_equal "Hello World : Included", result.response_body + controller = MyHelpers1.new + controller.process(:index) + assert_equal "Hello World : Included", controller.response_body end end diff --git a/actionpack/test/abstract_controller/layouts_test.rb b/actionpack/test/abstract_controller/layouts_test.rb index 42f73faa61..995aac7fad 100644 --- a/actionpack/test/abstract_controller/layouts_test.rb +++ b/actionpack/test/abstract_controller/layouts_test.rb @@ -143,13 +143,15 @@ module AbstractControllerTests class TestBase < ActiveSupport::TestCase test "when no layout is specified, and no default is available, render without a layout" do - result = Blank.new.process(:index) - assert_equal "Hello blank!", result.response_body + controller = Blank.new + controller.process(:index) + assert_equal "Hello blank!", controller.response_body end test "when layout is specified as a string, render with that layout" do - result = WithString.new.process(:index) - assert_equal "With String Hello string!", result.response_body + controller = WithString.new + controller.process(:index) + assert_equal "With String Hello string!", controller.response_body end test "when layout is specified as a string, but the layout is missing, raise an exception" do @@ -157,23 +159,27 @@ module AbstractControllerTests end test "when layout is specified as false, do not use a layout" do - result = WithFalseLayout.new.process(:index) - assert_equal "Hello false!", result.response_body + controller = WithFalseLayout.new + controller.process(:index) + assert_equal "Hello false!", controller.response_body end test "when layout is specified as nil, do not use a layout" do - result = WithNilLayout.new.process(:index) - assert_equal "Hello nil!", result.response_body + controller = WithNilLayout.new + controller.process(:index) + assert_equal "Hello nil!", controller.response_body end test "when layout is specified as a symbol, call the requested method and use the layout returned" do - result = WithSymbol.new.process(:index) - assert_equal "OMGHI2U Hello symbol!", result.response_body + controller = WithSymbol.new + controller.process(:index) + assert_equal "OMGHI2U Hello symbol!", controller.response_body end test "when layout is specified as a symbol and the method returns nil, don't use a layout" do - result = WithSymbolReturningNil.new.process(:index) - assert_equal "Hello nilz!", result.response_body + controller = WithSymbolReturningNil.new + controller.process(:index) + assert_equal "Hello nilz!", controller.response_body end test "when the layout is specified as a symbol and the method doesn't exist, raise an exception" do @@ -185,29 +191,34 @@ module AbstractControllerTests end test "when a child controller does not have a layout, use the parent controller layout" do - result = WithStringChild.new.process(:index) - assert_equal "With String Hello string!", result.response_body + controller = WithStringChild.new + controller.process(:index) + assert_equal "With String Hello string!", controller.response_body end test "when a child controller has specified a layout, use that layout and not the parent controller layout" do - result = WithStringOverriddenChild.new.process(:index) - assert_equal "With Override Hello string!", result.response_body + controller = WithStringOverriddenChild.new + controller.process(:index) + assert_equal "With Override Hello string!", controller.response_body end test "when a child controller has an implied layout, use that layout and not the parent controller layout" do - result = WithStringImpliedChild.new.process(:index) - assert_equal "With Implied Hello string!", result.response_body + controller = WithStringImpliedChild.new + controller.process(:index) + assert_equal "With Implied Hello string!", controller.response_body end test "when a child controller specifies layout nil, do not use the parent layout" do - result = WithNilChild.new.process(:index) - assert_equal "Hello string!", result.response_body + controller = WithNilChild.new + controller.process(:index) + assert_equal "Hello string!", controller.response_body end test "when a grandchild has no layout specified, the child has an implied layout, and the " \ "parent has specified a layout, use the child controller layout" do - result = WithChildOfImplied.new.process(:index) - assert_equal "With Implied Hello string!", result.response_body + controller = WithChildOfImplied.new + controller.process(:index) + assert_equal "With Implied Hello string!", controller.response_body end test "raises an exception when specifying layout true" do diff --git a/actionpack/test/new_base/metal_test.rb b/actionpack/test/new_base/metal_test.rb index c7c45b5cc9..2b7720863a 100644 --- a/actionpack/test/new_base/metal_test.rb +++ b/actionpack/test/new_base/metal_test.rb @@ -1,13 +1,12 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") module MetalTest - class MetalMiddleware < ActionController::Metal - def index + class MetalMiddleware < ActionController::Middleware + def call(env) if env["PATH_INFO"] =~ /authed/ - self.response = app.call(env) + app.call(env) else - self.response_body = "Not authed!" - self.status = 401 + [401, headers, "Not authed!"] end end end @@ -21,7 +20,7 @@ module MetalTest class TestMiddleware < ActiveSupport::TestCase def setup @app = Rack::Builder.new do - use MetalMiddleware.middleware(:index) + use MetalMiddleware run Endpoint.new end.to_app end -- cgit v1.2.3 From adedf72821a5623227ce91e6b298838e692477e4 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Wed, 26 Aug 2009 14:00:06 +0200 Subject: I18n: use I18n for select helpers' prompt text [#2252 state:committed] Signed-off-by: Jeremy Kemper --- .../lib/action_view/helpers/form_options_helper.rb | 3 ++- actionpack/lib/action_view/locale/en.yml | 4 ++++ .../test/template/form_options_helper_i18n_test.rb | 22 ++++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 actionpack/test/template/form_options_helper_i18n_test.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 4620a52272..3db5202e7d 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -571,7 +571,8 @@ module ActionView option_tags = "\n" + option_tags end if value.blank? && options[:prompt] - ("\n") + option_tags + prompt = options[:prompt].kind_of?(String) ? options[:prompt] : I18n.translate('support.select.prompt', :default => 'Please select') + "\n" + option_tags else option_tags end diff --git a/actionpack/lib/action_view/locale/en.yml b/actionpack/lib/action_view/locale/en.yml index afe35691bc..c82cd07ec2 100644 --- a/actionpack/lib/action_view/locale/en.yml +++ b/actionpack/lib/action_view/locale/en.yml @@ -108,3 +108,7 @@ # The variable :count is also available body: "There were problems with the following fields:" + support: + select: + # default value for :prompt => true in FormOptionsHelper + prompt: "Please select" \ No newline at end of file diff --git a/actionpack/test/template/form_options_helper_i18n_test.rb b/actionpack/test/template/form_options_helper_i18n_test.rb new file mode 100644 index 0000000000..4f25d41fc9 --- /dev/null +++ b/actionpack/test/template/form_options_helper_i18n_test.rb @@ -0,0 +1,22 @@ +require 'abstract_unit' + +class FormOptionsHelperI18nTests < ActionView::TestCase + tests ActionView::Helpers::FormOptionsHelper + + def setup + @prompt_message = 'Select!' + I18n.backend.store_translations :en, :support => { :select => { :prompt => @prompt_message} } + end + + def test_select_with_prompt_true_translates_prompt_message + I18n.expects(:translate).with('support.select.prompt', { :default => 'Please select' }) + select 'post', 'category', [], :prompt => true + end + + def test_select_with_translated_prompt + assert_dom_equal( + %Q(), + select('post', 'category', [], :prompt => true) + ) + end +end \ No newline at end of file -- cgit v1.2.3 From a7ca5595a21fa3bfd0ef51e6a56fbb80a13e040b Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 26 Aug 2009 12:12:40 -0700 Subject: Revert "I18n: use I18n for select helpers' prompt text" Broke CI. [#2252 state:open] This reverts commit adedf72821a5623227ce91e6b298838e692477e4. --- .../lib/action_view/helpers/form_options_helper.rb | 3 +-- actionpack/lib/action_view/locale/en.yml | 4 ---- .../test/template/form_options_helper_i18n_test.rb | 22 ---------------------- 3 files changed, 1 insertion(+), 28 deletions(-) delete mode 100644 actionpack/test/template/form_options_helper_i18n_test.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 3db5202e7d..4620a52272 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -571,8 +571,7 @@ module ActionView option_tags = "\n" + option_tags end if value.blank? && options[:prompt] - prompt = options[:prompt].kind_of?(String) ? options[:prompt] : I18n.translate('support.select.prompt', :default => 'Please select') - "\n" + option_tags + ("\n") + option_tags else option_tags end diff --git a/actionpack/lib/action_view/locale/en.yml b/actionpack/lib/action_view/locale/en.yml index c82cd07ec2..afe35691bc 100644 --- a/actionpack/lib/action_view/locale/en.yml +++ b/actionpack/lib/action_view/locale/en.yml @@ -108,7 +108,3 @@ # The variable :count is also available body: "There were problems with the following fields:" - support: - select: - # default value for :prompt => true in FormOptionsHelper - prompt: "Please select" \ No newline at end of file diff --git a/actionpack/test/template/form_options_helper_i18n_test.rb b/actionpack/test/template/form_options_helper_i18n_test.rb deleted file mode 100644 index 4f25d41fc9..0000000000 --- a/actionpack/test/template/form_options_helper_i18n_test.rb +++ /dev/null @@ -1,22 +0,0 @@ -require 'abstract_unit' - -class FormOptionsHelperI18nTests < ActionView::TestCase - tests ActionView::Helpers::FormOptionsHelper - - def setup - @prompt_message = 'Select!' - I18n.backend.store_translations :en, :support => { :select => { :prompt => @prompt_message} } - end - - def test_select_with_prompt_true_translates_prompt_message - I18n.expects(:translate).with('support.select.prompt', { :default => 'Please select' }) - select 'post', 'category', [], :prompt => true - end - - def test_select_with_translated_prompt - assert_dom_equal( - %Q(), - select('post', 'category', [], :prompt => true) - ) - end -end \ No newline at end of file -- cgit v1.2.3 From cc9af20da7af98464ece18d4abc6a22ef3f00b5d Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Wed, 26 Aug 2009 14:00:06 +0200 Subject: I18n: use I18n for select helpers' prompt text [#2252 state:committed] Signed-off-by: Jeremy Kemper --- .../lib/action_view/helpers/form_options_helper.rb | 3 ++- actionpack/lib/action_view/locale/en.yml | 4 ++++ .../test/template/form_options_helper_i18n_test.rb | 27 ++++++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 actionpack/test/template/form_options_helper_i18n_test.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 4620a52272..3db5202e7d 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -571,7 +571,8 @@ module ActionView option_tags = "\n" + option_tags end if value.blank? && options[:prompt] - ("\n") + option_tags + prompt = options[:prompt].kind_of?(String) ? options[:prompt] : I18n.translate('support.select.prompt', :default => 'Please select') + "\n" + option_tags else option_tags end diff --git a/actionpack/lib/action_view/locale/en.yml b/actionpack/lib/action_view/locale/en.yml index afe35691bc..c82cd07ec2 100644 --- a/actionpack/lib/action_view/locale/en.yml +++ b/actionpack/lib/action_view/locale/en.yml @@ -108,3 +108,7 @@ # The variable :count is also available body: "There were problems with the following fields:" + support: + select: + # default value for :prompt => true in FormOptionsHelper + prompt: "Please select" \ No newline at end of file diff --git a/actionpack/test/template/form_options_helper_i18n_test.rb b/actionpack/test/template/form_options_helper_i18n_test.rb new file mode 100644 index 0000000000..91e370efa7 --- /dev/null +++ b/actionpack/test/template/form_options_helper_i18n_test.rb @@ -0,0 +1,27 @@ +require 'abstract_unit' + +class FormOptionsHelperI18nTests < ActionView::TestCase + tests ActionView::Helpers::FormOptionsHelper + + def setup + @prompt_message = 'Select!' + I18n.backend.send(:init_translations) + I18n.backend.store_translations :en, :support => { :select => { :prompt => @prompt_message } } + end + + def teardown + I18n.backend = I18n::Backend::Simple.new + end + + def test_select_with_prompt_true_translates_prompt_message + I18n.expects(:translate).with('support.select.prompt', { :default => 'Please select' }) + select('post', 'category', [], :prompt => true) + end + + def test_select_with_translated_prompt + assert_dom_equal( + %Q(), + select('post', 'category', [], :prompt => true) + ) + end +end \ No newline at end of file -- cgit v1.2.3 From 05b529ca57f75ce64540b9d34597e0c3bfe1fca7 Mon Sep 17 00:00:00 2001 From: Jeffrey Hardy Date: Tue, 2 Jun 2009 13:28:44 -0400 Subject: UrlRewriter#rewrite_url should call #to_param on the value given in :anchor option, just as #url_for does [#2746 state:committed] Signed-off-by: Jeremy Kemper --- .../routing/generation/url_rewriter.rb | 2 +- actionpack/test/controller/url_rewriter_test.rb | 26 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/routing/generation/url_rewriter.rb b/actionpack/lib/action_controller/routing/generation/url_rewriter.rb index 9717582b5e..52b66c9303 100644 --- a/actionpack/lib/action_controller/routing/generation/url_rewriter.rb +++ b/actionpack/lib/action_controller/routing/generation/url_rewriter.rb @@ -172,7 +172,7 @@ module ActionController path = rewrite_path(options) rewritten_url << ActionController::Base.relative_url_root.to_s unless options[:skip_relative_url_root] rewritten_url << (options[:trailing_slash] ? path.sub(/\?|\z/) { "/" + $& } : path) - rewritten_url << "##{options[:anchor]}" if options[:anchor] + rewritten_url << "##{CGI.escape(options[:anchor].to_param.to_s)}" if options[:anchor] rewritten_url end diff --git a/actionpack/test/controller/url_rewriter_test.rb b/actionpack/test/controller/url_rewriter_test.rb index ad915e7a57..9b8d07222b 100644 --- a/actionpack/test/controller/url_rewriter_test.rb +++ b/actionpack/test/controller/url_rewriter_test.rb @@ -46,6 +46,20 @@ class UrlRewriterTests < ActionController::TestCase ) end + def test_anchor_should_call_to_param + assert_equal( + 'http://test.host/c/a/i#anchor', + @rewriter.rewrite(:controller => 'c', :action => 'a', :id => 'i', :anchor => Struct.new(:to_param).new('anchor')) + ) + end + + def test_anchor_should_be_cgi_escaped + assert_equal( + 'http://test.host/c/a/i#anc%2Fhor', + @rewriter.rewrite(:controller => 'c', :action => 'a', :id => 'i', :anchor => Struct.new(:to_param).new('anc/hor')) + ) + end + def test_overwrite_params @params[:controller] = 'hi' @params[:action] = 'bye' @@ -110,6 +124,18 @@ class UrlWriterTests < ActionController::TestCase ) end + def test_anchor_should_call_to_param + assert_equal('/c/a#anchor', + W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :anchor => Struct.new(:to_param).new('anchor')) + ) + end + + def test_anchor_should_be_cgi_escaped + assert_equal('/c/a#anc%2Fhor', + W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :anchor => Struct.new(:to_param).new('anc/hor')) + ) + end + def test_default_host add_host! assert_equal('http://www.basecamphq.com/c/a/i', -- cgit v1.2.3 From efbd535f367a8cb46965c91e8edb1786b21bdefb Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Wed, 26 Aug 2009 11:11:54 -0700 Subject: Have AbstractController::Logger#process_action return super's value --- actionpack/lib/abstract_controller/logger.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/abstract_controller/logger.rb b/actionpack/lib/abstract_controller/logger.rb index fd33bd2ddd..1b879b963b 100644 --- a/actionpack/lib/abstract_controller/logger.rb +++ b/actionpack/lib/abstract_controller/logger.rb @@ -29,7 +29,7 @@ module AbstractController # Override process_action in the AbstractController::Base # to log details about the method. def process_action(action) - super + retval = super if logger log = DelayedLog.new do @@ -40,6 +40,8 @@ module AbstractController logger.info(log) end + + retval end private -- cgit v1.2.3 From 289076066551b5439e48ef743ca277af95eba36c Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Wed, 26 Aug 2009 11:13:02 -0700 Subject: Set the request and response in ActionController::Middleware --- actionpack/lib/action_controller/middleware.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/middleware.rb b/actionpack/lib/action_controller/middleware.rb index 5fccca0b48..d2a404c1b1 100644 --- a/actionpack/lib/action_controller/middleware.rb +++ b/actionpack/lib/action_controller/middleware.rb @@ -7,6 +7,7 @@ module ActionController def call(env) controller = @controller.allocate + controller.send(:initialize) controller.app = @app controller._call(env) end @@ -24,6 +25,9 @@ module ActionController def _call(env) @_env = env + @_request = ActionDispatch::Request.new(env) + @_response = ActionDispatch::Response.new + @_response.request = request process(:index) end -- cgit v1.2.3 From 78ced08338e227f6cc380bb3e0f2ee8cda131d9a Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Wed, 26 Aug 2009 19:45:33 -0700 Subject: Add a default parameter for Resolver#initialize --- actionpack/lib/action_view/template/resolver.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index fe657166d5..0b4c62d4d0 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -4,7 +4,7 @@ require "action_view/template/template" module ActionView # Abstract superclass class Resolver - def initialize(options) + def initialize(options = {}) @cache = options[:cache] @cached = {} end -- cgit v1.2.3 From 4467fa7d2414d623f8d48ffb5ddb2d9ba8f60b27 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Wed, 26 Aug 2009 20:51:54 -0700 Subject: Fixed stupid mistake... nothing to see here. --- actionpack/lib/action_controller/middleware.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/middleware.rb b/actionpack/lib/action_controller/middleware.rb index d2a404c1b1..fac0ed2645 100644 --- a/actionpack/lib/action_controller/middleware.rb +++ b/actionpack/lib/action_controller/middleware.rb @@ -27,7 +27,7 @@ module ActionController @_env = env @_request = ActionDispatch::Request.new(env) @_response = ActionDispatch::Response.new - @_response.request = request + @_response.request = @_request process(:index) end -- cgit v1.2.3 From 6a001e925e54d2b82164d98c1c1498a4e73ccad1 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Wed, 26 Aug 2009 23:07:55 -0700 Subject: Require necessary active_support files in cookie store --- actionpack/lib/action_dispatch/middleware/session/cookie_store.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb index 547a2d2062..9cfd6956d0 100644 --- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb @@ -1,3 +1,5 @@ +require "active_support/core_ext/hash/keys" + module ActionDispatch module Session # This cookie-based session store is the Rails default. Sessions typically -- cgit v1.2.3 From bb91beabbde29a52bb2851884eaa90636aff0b95 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Thu, 27 Aug 2009 04:59:39 -0500 Subject: Remove some old cruft --- actionpack/lib/action_view/paths.rb | 3 --- 1 file changed, 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb index 4001757a9b..5524a3219a 100644 --- a/actionpack/lib/action_view/paths.rb +++ b/actionpack/lib/action_view/paths.rb @@ -34,7 +34,6 @@ module ActionView #:nodoc: end def find(path, details = {}, prefix = nil, partial = false) - # template_path = path.sub(/^\//, '') template_path = path each do |load_path| @@ -43,8 +42,6 @@ module ActionView #:nodoc: end end - # TODO: Have a fallback absolute path? - extension = details[:formats] || [] raise ActionView::MissingTemplate.new(self, "#{prefix}/#{path} - #{details.inspect} - partial: #{!!partial}") end -- cgit v1.2.3 From ba5995dcd983498aea342fd06ccb6337f3bd15ab Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 27 Aug 2009 12:43:26 -0500 Subject: Reset session in integration tests after changing routes to reload the middleware stack --- .../lib/action_controller/testing/process.rb | 4 +++- .../test/activerecord/active_record_store_test.rb | 25 ++++++++++++---------- actionpack/test/controller/webservice_test.rb | 1 + .../dispatch/request/json_params_parsing_test.rb | 1 + .../request/multipart_params_parsing_test.rb | 1 + .../dispatch/request/query_string_parsing_test.rb | 1 + .../request/url_encoded_params_parsing_test.rb | 1 + .../dispatch/request/xml_params_parsing_test.rb | 1 + .../test/dispatch/session/cookie_store_test.rb | 19 +++++++++------- .../test/dispatch/session/mem_cache_store_test.rb | 16 +++++++------- 10 files changed, 42 insertions(+), 28 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 6bc7d60d76..4185b803c5 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -249,6 +249,7 @@ module ActionController #:nodoc: temporary_routes = ActionController::Routing::RouteSet.new ActionController::Routing.module_eval { const_set :Routes, temporary_routes } + ActionController::Dispatcher.router = temporary_routes yield temporary_routes ensure @@ -256,6 +257,7 @@ module ActionController #:nodoc: ActionController::Routing.module_eval { remove_const :Routes } end ActionController::Routing.const_set(:Routes, real_routes) if real_routes + ActionController::Dispatcher.router = ActionController::Routing::Routes end end -end \ No newline at end of file +end diff --git a/actionpack/test/activerecord/active_record_store_test.rb b/actionpack/test/activerecord/active_record_store_test.rb index 47f8496181..a46ce7a0aa 100644 --- a/actionpack/test/activerecord/active_record_store_test.rb +++ b/actionpack/test/activerecord/active_record_store_test.rb @@ -1,12 +1,6 @@ require 'active_record_unit' class ActiveRecordStoreTest < ActionController::IntegrationTest - DispatcherApp = ActionController::Dispatcher.new - SessionApp = ActiveRecord::SessionStore.new(DispatcherApp, - :key => '_session_id') - SessionAppWithFixation = ActiveRecord::SessionStore.new(DispatcherApp, - :key => '_session_id', :cookie_only => false) - class TestController < ActionController::Base def no_session_access head :ok @@ -39,7 +33,7 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest def setup ActiveRecord::SessionStore.session_class.create_table! - @integration_session = open_session(SessionApp) + reset_app! end def teardown @@ -138,9 +132,9 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest end def test_allows_session_fixation - @integration_session = open_session(SessionAppWithFixation) - with_test_route_set do + reset_with_fixation! + get '/set_session_value' assert_response :success assert cookies['_session_id'] @@ -151,8 +145,7 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest session_id = cookies['_session_id'] assert session_id - reset! - @integration_session = open_session(SessionAppWithFixation) + reset_with_fixation! get '/set_session_value', :_session_id => session_id, :foo => "baz" assert_response :success @@ -166,6 +159,16 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest end private + def reset_app! + app = ActiveRecord::SessionStore.new(ActionController::Dispatcher.new, :key => '_session_id') + @integration_session = open_session(app) + end + + def reset_with_fixation! + app = ActiveRecord::SessionStore.new(ActionController::Dispatcher.new, :key => '_session_id', :cookie_only => false) + @integration_session = open_session(app) + end + def with_test_route_set with_routing do |set| set.draw do |map| diff --git a/actionpack/test/controller/webservice_test.rb b/actionpack/test/controller/webservice_test.rb index 3fded34d78..916124e221 100644 --- a/actionpack/test/controller/webservice_test.rb +++ b/actionpack/test/controller/webservice_test.rb @@ -259,6 +259,7 @@ class WebServiceTest < ActionController::IntegrationTest c.connect "/", :action => "assign_parameters" end end + reset! yield end end diff --git a/actionpack/test/dispatch/request/json_params_parsing_test.rb b/actionpack/test/dispatch/request/json_params_parsing_test.rb index db6cf7b330..995f36bb29 100644 --- a/actionpack/test/dispatch/request/json_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/json_params_parsing_test.rb @@ -59,6 +59,7 @@ class JsonParamsParsingTest < ActionController::IntegrationTest set.draw do |map| map.connect ':action', :controller => "json_params_parsing_test/test" end + reset! yield end end diff --git a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb index 301080842e..d4ee4362eb 100644 --- a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb @@ -153,6 +153,7 @@ class MultipartParamsParsingTest < ActionController::IntegrationTest set.draw do |map| map.connect ':action', :controller => "multipart_params_parsing_test/test" end + reset! yield end end diff --git a/actionpack/test/dispatch/request/query_string_parsing_test.rb b/actionpack/test/dispatch/request/query_string_parsing_test.rb index a31e326ddf..2261934e45 100644 --- a/actionpack/test/dispatch/request/query_string_parsing_test.rb +++ b/actionpack/test/dispatch/request/query_string_parsing_test.rb @@ -111,6 +111,7 @@ class QueryStringParsingTest < ActionController::IntegrationTest set.draw do |map| map.connect ':action', :controller => "query_string_parsing_test/test" end + reset! get "/parse", actual assert_response :ok diff --git a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb index 7167cdafac..6c9967d26e 100644 --- a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb @@ -132,6 +132,7 @@ class UrlEncodedParamsParsingTest < ActionController::IntegrationTest set.draw do |map| map.connect ':action', :controller => "url_encoded_params_parsing_test/test" end + reset! yield end end diff --git a/actionpack/test/dispatch/request/xml_params_parsing_test.rb b/actionpack/test/dispatch/request/xml_params_parsing_test.rb index 521002b519..2f2dd695c4 100644 --- a/actionpack/test/dispatch/request/xml_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/xml_params_parsing_test.rb @@ -86,6 +86,7 @@ class XmlParamsParsingTest < ActionController::IntegrationTest set.draw do |map| map.connect ':action', :controller => "xml_params_parsing_test/test" end + reset! yield end end diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb index 2db76818ac..0723a76d2b 100644 --- a/actionpack/test/dispatch/session/cookie_store_test.rb +++ b/actionpack/test/dispatch/session/cookie_store_test.rb @@ -8,10 +8,6 @@ class CookieStoreTest < ActionController::IntegrationTest # Make sure Session middleware doesnt get included in the middleware stack ActionController::Base.session_store = nil - DispatcherApp = ActionController::Dispatcher.new - CookieStoreApp = ActionDispatch::Session::CookieStore.new(DispatcherApp, - :key => SessionKey, :secret => SessionSecret) - Verifier = ActiveSupport::MessageVerifier.new(SessionSecret, 'SHA1') SignedBar = Verifier.generate(:foo => "bar", :session_id => ActiveSupport::SecureRandom.hex(16)) @@ -51,7 +47,7 @@ class CookieStoreTest < ActionController::IntegrationTest end def setup - @integration_session = open_session(CookieStoreApp) + reset_app! end def test_raises_argument_error_if_missing_session_key @@ -197,10 +193,10 @@ class CookieStoreTest < ActionController::IntegrationTest end def test_session_store_with_expire_after - app = ActionDispatch::Session::CookieStore.new(DispatcherApp, :key => SessionKey, :secret => SessionSecret, :expire_after => 5.hours) - @integration_session = open_session(app) - with_test_route_set do + app = ActionDispatch::Session::CookieStore.new(ActionController::Dispatcher.new, :key => SessionKey, :secret => SessionSecret, :expire_after => 5.hours) + @integration_session = open_session(app) + # First request accesses the session time = Time.local(2008, 4, 24) Time.stubs(:now).returns(time) @@ -230,6 +226,12 @@ class CookieStoreTest < ActionController::IntegrationTest end private + def reset_app! + app = ActionDispatch::Session::CookieStore.new(ActionController::Dispatcher.new, + :key => SessionKey, :secret => SessionSecret) + @integration_session = open_session(app) + end + def with_test_route_set with_routing do |set| set.draw do |map| @@ -237,6 +239,7 @@ class CookieStoreTest < ActionController::IntegrationTest c.connect "/:action" end end + reset_app! yield end end diff --git a/actionpack/test/dispatch/session/mem_cache_store_test.rb b/actionpack/test/dispatch/session/mem_cache_store_test.rb index 7561c93e4a..1588918be7 100644 --- a/actionpack/test/dispatch/session/mem_cache_store_test.rb +++ b/actionpack/test/dispatch/session/mem_cache_store_test.rb @@ -32,14 +32,7 @@ class MemCacheStoreTest < ActionController::IntegrationTest end begin - DispatcherApp = ActionController::Dispatcher.new - MemCacheStoreApp = ActionDispatch::Session::MemCacheStore.new( - DispatcherApp, :key => '_session_id') - - - def setup - @integration_session = open_session(MemCacheStoreApp) - end + App = ActionDispatch::Session::MemCacheStore.new(ActionController::Dispatcher.new, :key => '_session_id') def test_setting_and_getting_session_value with_test_route_set do @@ -114,6 +107,12 @@ class MemCacheStoreTest < ActionController::IntegrationTest end private + def reset_app! + app = ActionDispatch::Session::MemCacheStore.new( + ActionController::Dispatcher.new, :key => '_session_id') + @integration_session = open_session(app) + end + def with_test_route_set with_routing do |set| set.draw do |map| @@ -121,6 +120,7 @@ class MemCacheStoreTest < ActionController::IntegrationTest c.connect "/:action" end end + reset_app! yield end end -- cgit v1.2.3 From 684a6b3c71110b018199bf412e485189343e1f6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 29 Aug 2009 16:18:37 +0200 Subject: Attempt to render the template inside the responder, so it can be used for caching and pagination. Signed-off-by: Yehuda Katz --- .../lib/action_controller/metal/mime_responds.rb | 49 ++++++++++++---------- .../lib/action_controller/metal/responder.rb | 14 ++++--- 2 files changed, 37 insertions(+), 26 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index 950105e63f..6a32aeae24 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -178,23 +178,7 @@ module ActionController #:nodoc: # def respond_to(*mimes, &block) raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given? - - collector = Collector.new - mimes = collect_mimes_from_class_level if mimes.empty? - mimes.each { |mime| collector.send(mime) } - block.call(collector) if block_given? - - if format = request.negotiate_mime(collector.order) - self.formats = [format.to_sym] - - if response = collector.response_for(format) - response.call - else - default_render - end - else - head :not_acceptable - end + collect_mimes_for_render(mimes, block){ default_render } end # respond_with wraps a resource around a responder for default representation. @@ -227,10 +211,10 @@ module ActionController #:nodoc: # a proc to it. # def respond_with(*resources, &block) - respond_to(&block) - rescue ActionView::MissingTemplate - options = resources.extract_options! - (options.delete(:responder) || responder).call(self, resources, options) + collect_mimes_for_render([], block) do + options = resources.extract_options! + (options.delete(:responder) || responder).call(self, resources, options) + end end def responder @@ -258,6 +242,29 @@ module ActionController #:nodoc: end end + # Receives a collection of mimes and a block with formats and initialize a + # collector. If a response was added to the collector, uses it to satisfy + # the request, otherwise yields the block given. + # + def collect_mimes_for_render(mimes, formats) + collector = Collector.new + mimes = collect_mimes_from_class_level if mimes.empty? + mimes.each { |mime| collector.send(mime) } + formats.call(collector) if formats + + if format = request.negotiate_mime(collector.order) + self.formats = [format.to_sym] + + if response = collector.response_for(format) + response.call + else + yield + end + else + head :not_acceptable + end + end + class Collector #:nodoc: attr_accessor :order diff --git a/actionpack/lib/action_controller/metal/responder.rb b/actionpack/lib/action_controller/metal/responder.rb index fc01a0924a..ac7f5dafe9 100644 --- a/actionpack/lib/action_controller/metal/responder.rb +++ b/actionpack/lib/action_controller/metal/responder.rb @@ -109,8 +109,10 @@ module ActionController #:nodoc: # template. # def to_html + render + rescue ActionView::MissingTemplate if get? - render + raise elsif has_errors? render :action => default_action else @@ -118,12 +120,14 @@ module ActionController #:nodoc: end end - # All others formats try to render the resource given instead. For this - # purpose a helper called display as a shortcut to render a resource with - # the current format. + # All others formats follow the procedure below. First we try to render a + # template, if the template is not available, we verify if the resource + # responds to :to_format and display it. # def to_format - return render unless resourceful? + render + rescue ActionView::MissingTemplate + raise unless resourceful? if get? display resource -- cgit v1.2.3 From 3f78de67b5827ee47d738a1dc96518f24bbb0129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 29 Aug 2009 17:48:11 +0200 Subject: Ensure that blocks are also handled inside the responder. --- .../lib/action_controller/metal/mime_responds.rb | 34 ++++++++++------------ .../lib/action_controller/metal/responder.rb | 25 ++++++++++++---- actionpack/test/controller/mime_responds_test.rb | 7 +++++ 3 files changed, 43 insertions(+), 23 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index 6a32aeae24..3026067868 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -178,7 +178,10 @@ module ActionController #:nodoc: # def respond_to(*mimes, &block) raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given? - collect_mimes_for_render(mimes, block){ default_render } + + if response = retrieve_response_from_mimes(mimes, &block) + response.call + end end # respond_with wraps a resource around a responder for default representation. @@ -211,8 +214,9 @@ module ActionController #:nodoc: # a proc to it. # def respond_with(*resources, &block) - collect_mimes_for_render([], block) do + if response = retrieve_response_from_mimes([], &block) options = resources.extract_options! + options.merge!(:default_response => response) (options.delete(:responder) || responder).call(self, resources, options) end end @@ -242,34 +246,29 @@ module ActionController #:nodoc: end end - # Receives a collection of mimes and a block with formats and initialize a - # collector. If a response was added to the collector, uses it to satisfy - # the request, otherwise yields the block given. + # Collects mimes and return the response for the negotiated format. Returns + # nil if :not_acceptable was sent to the client. # - def collect_mimes_for_render(mimes, formats) - collector = Collector.new + def retrieve_response_from_mimes(mimes, &block) + collector = Collector.new { default_render } mimes = collect_mimes_from_class_level if mimes.empty? mimes.each { |mime| collector.send(mime) } - formats.call(collector) if formats + block.call(collector) if block_given? if format = request.negotiate_mime(collector.order) self.formats = [format.to_sym] - - if response = collector.response_for(format) - response.call - else - yield - end + collector.response_for(format) else head :not_acceptable + nil end end class Collector #:nodoc: attr_accessor :order - def initialize - @order, @responses = [], {} + def initialize(&block) + @order, @responses, @default_response = [], {}, block end def any(*args, &block) @@ -283,13 +282,12 @@ module ActionController #:nodoc: def custom(mime_type, &block) mime_type = mime_type.is_a?(Mime::Type) ? mime_type : Mime::Type.lookup(mime_type.to_s) - @order << mime_type @responses[mime_type] ||= block end def response_for(mime) - @responses[mime] || @responses[Mime::ALL] + @responses[mime] || @responses[Mime::ALL] || @default_response end def self.generate_method_for_mime(mime) diff --git a/actionpack/lib/action_controller/metal/responder.rb b/actionpack/lib/action_controller/metal/responder.rb index ac7f5dafe9..a16ed97131 100644 --- a/actionpack/lib/action_controller/metal/responder.rb +++ b/actionpack/lib/action_controller/metal/responder.rb @@ -79,15 +79,16 @@ module ActionController #:nodoc: # Check polymorphic_url documentation for more examples. # class Responder - attr_reader :controller, :request, :format, :resource, :resource_location, :options + attr_reader :controller, :request, :format, :resource, :resources, :options def initialize(controller, resources, options={}) @controller = controller @request = controller.request @format = controller.formats.first @resource = resources.is_a?(Array) ? resources.last : resources - @resource_location = options[:location] || resources + @resources = resources @options = options + @default_response = options.delete(:default_response) end delegate :head, :render, :redirect_to, :to => :controller @@ -109,7 +110,7 @@ module ActionController #:nodoc: # template. # def to_html - render + default_render rescue ActionView::MissingTemplate if get? raise @@ -125,7 +126,7 @@ module ActionController #:nodoc: # responds to :to_format and display it. # def to_format - render + default_render rescue ActionView::MissingTemplate raise unless resourceful? @@ -148,6 +149,20 @@ module ActionController #:nodoc: resource.respond_to?(:"to_#{format}") end + # Returns the resource location by retrieving it from the options or + # returning the resources array. + # + def resource_location + options[:location] || resources + end + + # If a given response block was given, use it, otherwise call render on + # controller. + # + def default_render + @default_response.call + end + # display is just a shortcut to render a resource with the current format. # # display @user, :status => :ok @@ -166,7 +181,7 @@ module ActionController #:nodoc: # render :xml => @user, :status => :created # def display(resource, given_options={}) - render given_options.merge!(options).merge!(format => resource) + controller.render given_options.merge!(options).merge!(format => resource) end # Check if the resource has errors or not. diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index 44536ce54e..93a815adae 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -726,6 +726,13 @@ class RespondWithControllerTest < ActionController::TestCase assert_equal "david", @response.body end + def test_block_inside_respond_with_is_rendered + @controller = InheritedRespondWithController.new + @request.accept = "application/json" + get :index + assert_equal "JSON", @response.body + end + def test_no_double_render_is_raised @request.accept = "text/html" assert_raise ActionView::MissingTemplate do -- cgit v1.2.3 From 6f40139b53b8e9ac805a15bb7c070d7bf9f6ce66 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 31 Aug 2009 13:39:06 -0500 Subject: SessionHash#update and SessionHash#delete are missing a call to load! [#3056 state:resolved] --- actionpack/lib/action_dispatch/middleware/session/abstract_store.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb index 03761b10bd..a8768633cc 100644 --- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb @@ -45,6 +45,7 @@ module ActionDispatch ActiveSupport::Deprecation.warn('use replace instead', caller) replace({}) else + load! unless @loaded super(hash.stringify_keys) end end @@ -54,6 +55,7 @@ module ActionDispatch ActiveSupport::Deprecation.warn('use clear instead', caller) clear else + load! unless @loaded super(key.to_s) end end -- cgit v1.2.3 From c63dac81c1c6476fff81dda7e1b72f239209c7a4 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 31 Aug 2009 14:27:10 -0500 Subject: Switch over to rack-test gem --- actionpack/Rakefile | 1 + actionpack/lib/action_dispatch.rb | 4 +- .../vendor/rack-test/rack/mock_session.rb | 50 ----- .../action_dispatch/vendor/rack-test/rack/test.rb | 239 --------------------- .../vendor/rack-test/rack/test/cookie_jar.rb | 169 --------------- .../vendor/rack-test/rack/test/methods.rb | 45 ---- .../rack-test/rack/test/mock_digest_request.rb | 27 --- .../vendor/rack-test/rack/test/uploaded_file.rb | 36 ---- .../vendor/rack-test/rack/test/utils.rb | 75 ------- 9 files changed, 4 insertions(+), 642 deletions(-) delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-test/rack/mock_session.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-test/rack/test.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-test/rack/test/cookie_jar.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-test/rack/test/methods.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-test/rack/test/mock_digest_request.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-test/rack/test/uploaded_file.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-test/rack/test/utils.rb (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 1fc5018561..f76c47aff1 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -116,6 +116,7 @@ spec = Gem::Specification.new do |s| s.requirements << 'none' s.add_dependency('activesupport', '= 3.0.pre' + PKG_BUILD) + s.add_dependency('rack-test', '~> 0.4.1') s.require_path = 'lib' s.autorequire = 'action_controller' diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 884828a01a..94d4e14e31 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -33,7 +33,9 @@ end require 'rack' -$:.unshift "#{File.dirname(__FILE__)}/action_dispatch/vendor/rack-test" +module Rack + autoload :Test, 'rack/test' +end module ActionDispatch autoload :Request, 'action_dispatch/http/request' diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/mock_session.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/mock_session.rb deleted file mode 100644 index eba6226538..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-test/rack/mock_session.rb +++ /dev/null @@ -1,50 +0,0 @@ -module Rack - - class MockSession - attr_writer :cookie_jar - attr_reader :last_response - - def initialize(app, default_host = Rack::Test::DEFAULT_HOST) - @app = app - @default_host = default_host - end - - def clear_cookies - @cookie_jar = Rack::Test::CookieJar.new([], @default_host) - end - - def set_cookie(cookie, uri = nil) - cookie_jar.merge(cookie, uri) - end - - def request(uri, env) - env["HTTP_COOKIE"] ||= cookie_jar.for(uri) - @last_request = Rack::Request.new(env) - status, headers, body = @app.call(@last_request.env) - @last_response = MockResponse.new(status, headers, body, env["rack.errors"].flush) - cookie_jar.merge(last_response.headers["Set-Cookie"], uri) - - @last_response - end - - # Return the last request issued in the session. Raises an error if no - # requests have been sent yet. - def last_request - raise Rack::Test::Error.new("No request yet. Request a page first.") unless @last_request - @last_request - end - - # Return the last response received in the session. Raises an error if - # no requests have been sent yet. - def last_response - raise Rack::Test::Error.new("No response yet. Request a page first.") unless @last_response - @last_response - end - - def cookie_jar - @cookie_jar ||= Rack::Test::CookieJar.new([], @default_host) - end - - end - -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test.rb deleted file mode 100644 index 70384b1d76..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test.rb +++ /dev/null @@ -1,239 +0,0 @@ -unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__) + "/..")) - $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/..")) -end - -require "uri" -require "rack" -require "rack/mock_session" -require "rack/test/cookie_jar" -require "rack/test/mock_digest_request" -require "rack/test/utils" -require "rack/test/methods" -require "rack/test/uploaded_file" - -module Rack - module Test - - VERSION = "0.3.0" - - DEFAULT_HOST = "example.org" - MULTIPART_BOUNDARY = "----------XnJLe9ZIbbGUYtzPQJ16u1" - - # The common base class for exceptions raised by Rack::Test - class Error < StandardError; end - - class Session - extend Forwardable - include Rack::Test::Utils - - def_delegators :@rack_mock_session, :clear_cookies, :set_cookie, :last_response, :last_request - - # Initialize a new session for the given Rack app - def initialize(app, default_host = DEFAULT_HOST) - @headers = {} - @default_host = default_host - @rack_mock_session = Rack::MockSession.new(app, default_host) - end - - # Issue a GET request for the given URI with the given params and Rack - # environment. Stores the issues request object in #last_request and - # the app's response in #last_response. Yield #last_response to a block - # if given. - # - # Example: - # get "/" - def get(uri, params = {}, env = {}, &block) - env = env_for(uri, env.merge(:method => "GET", :params => params)) - process_request(uri, env, &block) - end - - # Issue a POST request for the given URI. See #get - # - # Example: - # post "/signup", "name" => "Bryan" - def post(uri, params = {}, env = {}, &block) - env = env_for(uri, env.merge(:method => "POST", :params => params)) - process_request(uri, env, &block) - end - - # Issue a PUT request for the given URI. See #get - # - # Example: - # put "/" - def put(uri, params = {}, env = {}, &block) - env = env_for(uri, env.merge(:method => "PUT", :params => params)) - process_request(uri, env, &block) - end - - # Issue a DELETE request for the given URI. See #get - # - # Example: - # delete "/" - def delete(uri, params = {}, env = {}, &block) - env = env_for(uri, env.merge(:method => "DELETE", :params => params)) - process_request(uri, env, &block) - end - - # Issue a HEAD request for the given URI. See #get - # - # Example: - # head "/" - def head(uri, params = {}, env = {}, &block) - env = env_for(uri, env.merge(:method => "HEAD", :params => params)) - process_request(uri, env, &block) - end - - # Issue a request to the Rack app for the given URI and optional Rack - # environment. Stores the issues request object in #last_request and - # the app's response in #last_response. Yield #last_response to a block - # if given. - # - # Example: - # request "/" - def request(uri, env = {}, &block) - env = env_for(uri, env) - process_request(uri, env, &block) - end - - # Set a header to be included on all subsequent requests through the - # session. Use a value of nil to remove a previously configured header. - # - # Example: - # header "User-Agent", "Firefox" - def header(name, value) - if value.nil? - @headers.delete(name) - else - @headers[name] = value - end - end - - # Set the username and password for HTTP Basic authorization, to be - # included in subsequent requests in the HTTP_AUTHORIZATION header. - # - # Example: - # basic_authorize "bryan", "secret" - def basic_authorize(username, password) - encoded_login = ["#{username}:#{password}"].pack("m*") - header('HTTP_AUTHORIZATION', "Basic #{encoded_login}") - end - - alias_method :authorize, :basic_authorize - - def digest_authorize(username, password) - @digest_username = username - @digest_password = password - end - - # Rack::Test will not follow any redirects automatically. This method - # will follow the redirect returned in the last response. If the last - # response was not a redirect, an error will be raised. - def follow_redirect! - unless last_response.redirect? - raise Error.new("Last response was not a redirect. Cannot follow_redirect!") - end - - get(last_response["Location"]) - end - - private - - def env_for(path, env) - uri = URI.parse(path) - uri.host ||= @default_host - - env = default_env.merge(env) - - env.update("HTTPS" => "on") if URI::HTTPS === uri - env["X-Requested-With"] = "XMLHttpRequest" if env[:xhr] - - if (env[:method] == "POST" || env["REQUEST_METHOD"] == "POST") && !env.has_key?(:input) - env["CONTENT_TYPE"] = "application/x-www-form-urlencoded" - - multipart = (Hash === env[:params]) && - env[:params].any? { |_, v| UploadedFile === v } - - if multipart - env[:input] = multipart_body(env.delete(:params)) - env["CONTENT_LENGTH"] ||= env[:input].length.to_s - env["CONTENT_TYPE"] = "multipart/form-data; boundary=#{MULTIPART_BOUNDARY}" - else - env[:input] = params_to_string(env.delete(:params)) - end - end - - params = env[:params] || {} - params.update(parse_query(uri.query)) - - uri.query = requestify(params) - - if env.has_key?(:cookie) - set_cookie(env.delete(:cookie), uri) - end - - Rack::MockRequest.env_for(uri.to_s, env) - end - - def process_request(uri, env) - uri = URI.parse(uri) - uri.host ||= @default_host - - @rack_mock_session.request(uri, env) - - if retry_with_digest_auth?(env) - auth_env = env.merge({ - "HTTP_AUTHORIZATION" => digest_auth_header, - "rack-test.digest_auth_retry" => true - }) - auth_env.delete('rack.request') - process_request(uri.path, auth_env) - else - yield last_response if block_given? - - last_response - end - end - - def digest_auth_header - challenge = last_response["WWW-Authenticate"].split(" ", 2).last - params = Rack::Auth::Digest::Params.parse(challenge) - - params.merge!({ - "username" => @digest_username, - "nc" => "00000001", - "cnonce" => "nonsensenonce", - "uri" => last_request.path_info, - "method" => last_request.env["REQUEST_METHOD"], - }) - - params["response"] = MockDigestRequest.new(params).response(@digest_password) - - "Digest #{params}" - end - - def retry_with_digest_auth?(env) - last_response.status == 401 && - digest_auth_configured? && - !env["rack-test.digest_auth_retry"] - end - - def digest_auth_configured? - @digest_username - end - - def default_env - { "rack.test" => true, "REMOTE_ADDR" => "127.0.0.1" }.merge(@headers) - end - - def params_to_string(params) - case params - when Hash then requestify(params) - when nil then "" - else params - end - end - - end - - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/cookie_jar.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/cookie_jar.rb deleted file mode 100644 index d58c914c9b..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/cookie_jar.rb +++ /dev/null @@ -1,169 +0,0 @@ -require "uri" -module Rack - module Test - - class Cookie - include Rack::Utils - - # :api: private - attr_reader :name, :value - - # :api: private - def initialize(raw, uri = nil, default_host = DEFAULT_HOST) - @default_host = default_host - uri ||= default_uri - - # separate the name / value pair from the cookie options - @name_value_raw, options = raw.split(/[;,] */n, 2) - - @name, @value = parse_query(@name_value_raw, ';').to_a.first - @options = parse_query(options, ';') - - @options["domain"] ||= (uri.host || default_host) - @options["path"] ||= uri.path.sub(/\/[^\/]*\Z/, "") - end - - def replaces?(other) - [name.downcase, domain, path] == [other.name.downcase, other.domain, other.path] - end - - # :api: private - def raw - @name_value_raw - end - - # :api: private - def empty? - @value.nil? || @value.empty? - end - - # :api: private - def domain - @options["domain"] - end - - def secure? - @options.has_key?("secure") - end - - # :api: private - def path - @options["path"].strip || "/" - end - - # :api: private - def expires - Time.parse(@options["expires"]) if @options["expires"] - end - - # :api: private - def expired? - expires && expires < Time.now - end - - # :api: private - def valid?(uri) - uri ||= default_uri - - if uri.host.nil? - uri.host = @default_host - end - - (!secure? || (secure? && uri.scheme == "https")) && - uri.host =~ Regexp.new("#{Regexp.escape(domain)}$", Regexp::IGNORECASE) && - uri.path =~ Regexp.new("^#{Regexp.escape(path)}") - end - - # :api: private - def matches?(uri) - ! expired? && valid?(uri) - end - - # :api: private - def <=>(other) - # Orders the cookies from least specific to most - [name, path, domain.reverse] <=> [other.name, other.path, other.domain.reverse] - end - - protected - - def default_uri - URI.parse("//" + @default_host + "/") - end - - end - - class CookieJar - - # :api: private - def initialize(cookies = [], default_host = DEFAULT_HOST) - @default_host = default_host - @cookies = cookies - @cookies.sort! - end - - def [](name) - cookies = hash_for(nil) - # TODO: Should be case insensitive - cookies[name] && cookies[name].value - end - - def []=(name, value) - # TODO: needs proper escaping - merge("#{name}=#{value}") - end - - def merge(raw_cookies, uri = nil) - return unless raw_cookies - - raw_cookies.each_line do |raw_cookie| - cookie = Cookie.new(raw_cookie, uri, @default_host) - self << cookie if cookie.valid?(uri) - end - end - - def <<(new_cookie) - @cookies.reject! do |existing_cookie| - new_cookie.replaces?(existing_cookie) - end - - @cookies << new_cookie - @cookies.sort! - end - - # :api: private - def for(uri) - hash_for(uri).values.map { |c| c.raw }.join(';') - end - - def to_hash - cookies = {} - - hash_for(nil).each do |name, cookie| - cookies[name] = cookie.value - end - - return cookies - end - - protected - - def hash_for(uri = nil) - cookies = {} - - # The cookies are sorted by most specific first. So, we loop through - # all the cookies in order and add it to a hash by cookie name if - # the cookie can be sent to the current URI. It's added to the hash - # so that when we are done, the cookies will be unique by name and - # we'll have grabbed the most specific to the URI. - @cookies.each do |cookie| - cookies[cookie.name] = cookie if cookie.matches?(uri) - end - - return cookies - end - - end - - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/methods.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/methods.rb deleted file mode 100644 index a191fa23d8..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/methods.rb +++ /dev/null @@ -1,45 +0,0 @@ -require "forwardable" - -module Rack - module Test - module Methods - extend Forwardable - - def rack_test_session - @_rack_test_session ||= Rack::Test::Session.new(app) - end - - def rack_mock_session - @_rack_mock_session ||= Rack::MockSession.new(app) - end - - METHODS = [ - :request, - - # HTTP verbs - :get, - :post, - :put, - :delete, - :head, - - # Redirects - :follow_redirect!, - - # Header-related features - :header, - :set_cookie, - :clear_cookies, - :authorize, - :basic_authorize, - :digest_authorize, - - # Expose the last request and response - :last_response, - :last_request - ] - - def_delegators :rack_test_session, *METHODS - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/mock_digest_request.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/mock_digest_request.rb deleted file mode 100644 index 81c398ba51..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/mock_digest_request.rb +++ /dev/null @@ -1,27 +0,0 @@ -module Rack - module Test - - class MockDigestRequest - def initialize(params) - @params = params - end - - def method_missing(sym) - if @params.has_key? k = sym.to_s - return @params[k] - end - - super - end - - def method - @params['method'] - end - - def response(password) - Rack::Auth::Digest::MD5.new(nil).send :digest, self, password - end - end - - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/uploaded_file.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/uploaded_file.rb deleted file mode 100644 index 239302fbe4..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/uploaded_file.rb +++ /dev/null @@ -1,36 +0,0 @@ -require "tempfile" - -module Rack - module Test - - class UploadedFile - # The filename, *not* including the path, of the "uploaded" file - attr_reader :original_filename - - # The content type of the "uploaded" file - attr_accessor :content_type - - def initialize(path, content_type = "text/plain", binary = false) - raise "#{path} file does not exist" unless ::File.exist?(path) - @content_type = content_type - @original_filename = ::File.basename(path) - @tempfile = Tempfile.new(@original_filename) - @tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding) - @tempfile.binmode if binary - FileUtils.copy_file(path, @tempfile.path) - end - - def path - @tempfile.path - end - - alias_method :local_path, :path - - def method_missing(method_name, *args, &block) #:nodoc: - @tempfile.__send__(method_name, *args, &block) - end - - end - - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/utils.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/utils.rb deleted file mode 100644 index d25b849709..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/utils.rb +++ /dev/null @@ -1,75 +0,0 @@ -module Rack - module Test - - module Utils - include Rack::Utils - - def requestify(value, prefix = nil) - case value - when Array - value.map do |v| - requestify(v, "#{prefix}[]") - end.join("&") - when Hash - value.map do |k, v| - requestify(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k)) - end.join("&") - else - "#{prefix}=#{escape(value)}" - end - end - - module_function :requestify - - def multipart_requestify(params, first=true) - p = Hash.new - - params.each do |key, value| - k = first ? key.to_s : "[#{key}]" - - if Hash === value - multipart_requestify(value, false).each do |subkey, subvalue| - p[k + subkey] = subvalue - end - else - p[k] = value - end - end - - return p - end - - module_function :multipart_requestify - - def multipart_body(params) - multipart_requestify(params).map do |key, value| - if value.respond_to?(:original_filename) - ::File.open(value.path, "rb") do |f| - f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding) - - <<-EOF ---#{MULTIPART_BOUNDARY}\r -Content-Disposition: form-data; name="#{key}"; filename="#{escape(value.original_filename)}"\r -Content-Type: #{value.content_type}\r -Content-Length: #{::File.stat(value.path).size}\r -\r -#{f.read}\r -EOF - end - else -<<-EOF ---#{MULTIPART_BOUNDARY}\r -Content-Disposition: form-data; name="#{key}"\r -\r -#{value}\r -EOF - end - end.join("")+"--#{MULTIPART_BOUNDARY}--\r" - end - - module_function :multipart_body - - end - - end -end -- cgit v1.2.3 From 8974ab2e2e2faf647b03859b618b0302ac6cfcf4 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 31 Aug 2009 14:49:59 -0500 Subject: action_dispatch and action_view are just more autoloads, so its okay to require them --- actionpack/lib/action_controller.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index d27a867efe..634206e065 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -59,9 +59,8 @@ end autoload :HTML, 'action_controller/vendor/html-scanner' autoload :AbstractController, 'abstract_controller' -autoload :Rack, 'action_dispatch' -autoload :ActionDispatch, 'action_dispatch' -autoload :ActionView, 'action_view' +require 'action_dispatch' +require 'action_view' # Common ActiveSupport usage in ActionController require "active_support/concern" -- cgit v1.2.3 From 5e5e34377ca22a4b5ea55975c119fb31d996ef80 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 31 Aug 2009 15:39:19 -0500 Subject: Back off rack 1.1-pre and bundle in the new testing goodies --- .../lib/action_controller/testing/integration.rb | 3 +- .../lib/action_controller/testing/process.rb | 2 +- actionpack/lib/action_dispatch.rb | 6 - .../lib/action_dispatch/testing/test_request.rb | 299 +++++++++++- .../action_dispatch/vendor/rack-1.1.pre/rack.rb | 90 ---- .../vendor/rack-1.1.pre/rack/adapter/camping.rb | 22 - .../rack-1.1.pre/rack/auth/abstract/handler.rb | 37 -- .../rack-1.1.pre/rack/auth/abstract/request.rb | 37 -- .../vendor/rack-1.1.pre/rack/auth/basic.rb | 58 --- .../vendor/rack-1.1.pre/rack/auth/digest/md5.rb | 124 ----- .../vendor/rack-1.1.pre/rack/auth/digest/nonce.rb | 51 -- .../vendor/rack-1.1.pre/rack/auth/digest/params.rb | 55 --- .../rack-1.1.pre/rack/auth/digest/request.rb | 40 -- .../vendor/rack-1.1.pre/rack/auth/openid.rb | 480 ------------------ .../vendor/rack-1.1.pre/rack/builder.rb | 63 --- .../vendor/rack-1.1.pre/rack/cascade.rb | 36 -- .../vendor/rack-1.1.pre/rack/chunked.rb | 49 -- .../vendor/rack-1.1.pre/rack/commonlogger.rb | 61 --- .../vendor/rack-1.1.pre/rack/conditionalget.rb | 47 -- .../vendor/rack-1.1.pre/rack/content_length.rb | 29 -- .../vendor/rack-1.1.pre/rack/content_type.rb | 23 - .../vendor/rack-1.1.pre/rack/deflater.rb | 96 ---- .../vendor/rack-1.1.pre/rack/directory.rb | 153 ------ .../vendor/rack-1.1.pre/rack/file.rb | 88 ---- .../vendor/rack-1.1.pre/rack/handler.rb | 69 --- .../vendor/rack-1.1.pre/rack/handler/cgi.rb | 61 --- .../rack-1.1.pre/rack/handler/evented_mongrel.rb | 8 - .../vendor/rack-1.1.pre/rack/handler/fastcgi.rb | 88 ---- .../vendor/rack-1.1.pre/rack/handler/lsws.rb | 55 --- .../vendor/rack-1.1.pre/rack/handler/mongrel.rb | 84 ---- .../vendor/rack-1.1.pre/rack/handler/scgi.rb | 59 --- .../rack/handler/swiftiplied_mongrel.rb | 8 - .../vendor/rack-1.1.pre/rack/handler/thin.rb | 18 - .../vendor/rack-1.1.pre/rack/handler/webrick.rb | 67 --- .../vendor/rack-1.1.pre/rack/head.rb | 19 - .../vendor/rack-1.1.pre/rack/lint.rb | 537 --------------------- .../vendor/rack-1.1.pre/rack/lobster.rb | 65 --- .../vendor/rack-1.1.pre/rack/lock.rb | 16 - .../vendor/rack-1.1.pre/rack/methodoverride.rb | 27 -- .../vendor/rack-1.1.pre/rack/mime.rb | 204 -------- .../vendor/rack-1.1.pre/rack/mock.rb | 184 ------- .../vendor/rack-1.1.pre/rack/recursive.rb | 57 --- .../vendor/rack-1.1.pre/rack/reloader.rb | 106 ---- .../vendor/rack-1.1.pre/rack/request.rb | 254 ---------- .../vendor/rack-1.1.pre/rack/response.rb | 183 ------- .../vendor/rack-1.1.pre/rack/rewindable_input.rb | 98 ---- .../rack-1.1.pre/rack/session/abstract/id.rb | 142 ------ .../vendor/rack-1.1.pre/rack/session/cookie.rb | 91 ---- .../vendor/rack-1.1.pre/rack/session/memcache.rb | 109 ----- .../vendor/rack-1.1.pre/rack/session/pool.rb | 100 ---- .../vendor/rack-1.1.pre/rack/showexceptions.rb | 349 ------------- .../vendor/rack-1.1.pre/rack/showstatus.rb | 106 ---- .../vendor/rack-1.1.pre/rack/static.rb | 38 -- .../vendor/rack-1.1.pre/rack/urlmap.rb | 55 --- .../vendor/rack-1.1.pre/rack/utils.rb | 516 -------------------- 55 files changed, 300 insertions(+), 5422 deletions(-) delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/adapter/camping.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/handler.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/request.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/basic.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/md5.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/nonce.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/params.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/request.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/openid.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/builder.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/cascade.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/chunked.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/commonlogger.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/conditionalget.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_length.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_type.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/deflater.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/directory.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/file.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/cgi.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/evented_mongrel.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/fastcgi.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/lsws.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/mongrel.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/scgi.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/swiftiplied_mongrel.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/thin.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/webrick.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/head.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lint.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lobster.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lock.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/methodoverride.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mime.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mock.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/recursive.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/reloader.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/request.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/response.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/rewindable_input.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/abstract/id.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/cookie.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/memcache.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/pool.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showexceptions.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showstatus.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/static.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/urlmap.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/utils.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/integration.rb b/actionpack/lib/action_controller/testing/integration.rb index 5cb0f48f82..fb82f866fe 100644 --- a/actionpack/lib/action_controller/testing/integration.rb +++ b/actionpack/lib/action_controller/testing/integration.rb @@ -267,7 +267,8 @@ module ActionController "CONTENT_TYPE" => "application/x-www-form-urlencoded", "HTTP_ACCEPT" => accept } - env = Rack::MockRequest.env_for(path, opts) + + env = ActionDispatch::TestRequest.env_for(path, opts) (rack_environment || {}).each do |key, value| env[key] = value diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 4185b803c5..a58b2de379 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -84,7 +84,7 @@ module ActionController #:nodoc: # # Pass a true third parameter to ensure the uploaded file is opened in binary mode (only required for Windows): # post :change_avatar, :avatar => ActionController::TestUploadedFile.new(ActionController::TestCase.fixture_path + '/files/spongebob.png', 'image/png', :binary) - TestUploadedFile = Rack::Utils::Multipart::UploadedFile + TestUploadedFile = ActionDispatch::TestRequest::Multipart::UploadedFile module TestProcess def self.included(base) diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 94d4e14e31..849f268a8c 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -25,12 +25,6 @@ activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib" $:.unshift activesupport_path if File.directory?(activesupport_path) require 'active_support' -begin - gem 'rack', '~> 1.1.pre' -rescue Gem::LoadError, ArgumentError - $:.unshift "#{File.dirname(__FILE__)}/action_dispatch/vendor/rack-1.1.pre" -end - require 'rack' module Rack diff --git a/actionpack/lib/action_dispatch/testing/test_request.rb b/actionpack/lib/action_dispatch/testing/test_request.rb index 20288aa7a5..8242ea4ef6 100644 --- a/actionpack/lib/action_dispatch/testing/test_request.rb +++ b/actionpack/lib/action_dispatch/testing/test_request.rb @@ -1,13 +1,308 @@ module ActionDispatch class TestRequest < Request - DEFAULT_ENV = Rack::MockRequest.env_for('/') + # Improve version of Multipart thats in rack/master + module Multipart #:nodoc: + class UploadedFile + # The filename, *not* including the path, of the "uploaded" file + attr_reader :original_filename + + # The content type of the "uploaded" file + attr_accessor :content_type + + def initialize(path, content_type = "text/plain", binary = false) + raise "#{path} file does not exist" unless ::File.exist?(path) + @content_type = content_type + @original_filename = ::File.basename(path) + @tempfile = Tempfile.new(@original_filename) + @tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding) + @tempfile.binmode if binary + FileUtils.copy_file(path, @tempfile.path) + end + + def path + @tempfile.path + end + alias_method :local_path, :path + + def method_missing(method_name, *args, &block) #:nodoc: + @tempfile.__send__(method_name, *args, &block) + end + end + + EOL = "\r\n" + MULTIPART_BOUNDARY = "AaB03x" + + def self.parse_multipart(env) + unless env['CONTENT_TYPE'] =~ + %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n + nil + else + boundary = "--#{$1}" + + params = {} + buf = "" + content_length = env['CONTENT_LENGTH'].to_i + input = env['rack.input'] + input.rewind + + boundary_size = Utils.bytesize(boundary) + EOL.size + bufsize = 16384 + + content_length -= boundary_size + + read_buffer = '' + + status = input.read(boundary_size, read_buffer) + raise EOFError, "bad content body" unless status == boundary + EOL + + rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/n + + loop { + head = nil + body = '' + filename = content_type = name = nil + + until head && buf =~ rx + if !head && i = buf.index(EOL+EOL) + head = buf.slice!(0, i+2) # First \r\n + buf.slice!(0, 2) # Second \r\n + + filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1] + content_type = head[/Content-Type: (.*)#{EOL}/ni, 1] + name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1] + + if content_type || filename + body = Tempfile.new("RackMultipart") + body.binmode if body.respond_to?(:binmode) + end + + next + end + + # Save the read body part. + if head && (boundary_size+4 < buf.size) + body << buf.slice!(0, buf.size - (boundary_size+4)) + end + + c = input.read(bufsize < content_length ? bufsize : content_length, read_buffer) + raise EOFError, "bad content body" if c.nil? || c.empty? + buf << c + content_length -= c.size + end + + # Save the rest. + if i = buf.index(rx) + body << buf.slice!(0, i) + buf.slice!(0, boundary_size+2) + + content_length = -1 if $1 == "--" + end + + if filename == "" + # filename is blank which means no file has been selected + data = nil + elsif filename + body.rewind + + # Take the basename of the upload's original filename. + # This handles the full Windows paths given by Internet Explorer + # (and perhaps other broken user agents) without affecting + # those which give the lone filename. + filename =~ /^(?:.*[:\\\/])?(.*)/m + filename = $1 + + data = {:filename => filename, :type => content_type, + :name => name, :tempfile => body, :head => head} + elsif !filename && content_type + body.rewind + + # Generic multipart cases, not coming from a form + data = {:type => content_type, + :name => name, :tempfile => body, :head => head} + else + data = body + end + + Utils.normalize_params(params, name, data) unless data.nil? + + break if buf.empty? || content_length == -1 + } + + input.rewind + + params + end + end + + def self.build_multipart(params, first = true) + if first + unless params.is_a?(Hash) + raise ArgumentError, "value must be a Hash" + end + + multipart = false + query = lambda { |value| + case value + when Array + value.each(&query) + when Hash + value.values.each(&query) + when UploadedFile + multipart = true + end + } + params.values.each(&query) + return nil unless multipart + end + + flattened_params = Hash.new + + params.each do |key, value| + k = first ? key.to_s : "[#{key}]" + + case value + when Array + value.map { |v| + build_multipart(v, false).each { |subkey, subvalue| + flattened_params["#{k}[]#{subkey}"] = subvalue + } + } + when Hash + build_multipart(value, false).each { |subkey, subvalue| + flattened_params[k + subkey] = subvalue + } + else + flattened_params[k] = value + end + end + + if first + flattened_params.map { |name, file| + if file.respond_to?(:original_filename) + ::File.open(file.path, "rb") do |f| + f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding) +<<-EOF +--#{MULTIPART_BOUNDARY}\r +Content-Disposition: form-data; name="#{name}"; filename="#{Rack::Utils.escape(file.original_filename)}"\r +Content-Type: #{file.content_type}\r +Content-Length: #{::File.stat(file.path).size}\r +\r +#{f.read}\r +EOF + end + else +<<-EOF +--#{MULTIPART_BOUNDARY}\r +Content-Disposition: form-data; name="#{name}"\r +\r +#{file}\r +EOF + end + }.join + "--#{MULTIPART_BOUNDARY}--\r" + else + flattened_params + end + end + end + + DEFAULT_ENV = { + "rack.version" => [1,0], + "rack.input" => StringIO.new, + "rack.errors" => StringIO.new, + "rack.multithread" => true, + "rack.multiprocess" => true, + "rack.run_once" => false, + } + + # Improve version of env_for thats in rack/master + def self.env_for(uri="", opts={}) #:nodoc: + uri = URI(uri) + uri.path = "/#{uri.path}" unless uri.path[0] == ?/ + + env = DEFAULT_ENV.dup + + env["REQUEST_METHOD"] = opts[:method] ? opts[:method].to_s.upcase : "GET" + env["SERVER_NAME"] = uri.host || "example.org" + env["SERVER_PORT"] = uri.port ? uri.port.to_s : "80" + env["QUERY_STRING"] = uri.query.to_s + env["PATH_INFO"] = (!uri.path || uri.path.empty?) ? "/" : uri.path + env["rack.url_scheme"] = uri.scheme || "http" + env["HTTPS"] = env["rack.url_scheme"] == "https" ? "on" : "off" + + env["SCRIPT_NAME"] = opts[:script_name] || "" + + if opts[:fatal] + env["rack.errors"] = FatalWarner.new + else + env["rack.errors"] = StringIO.new + end + + if params = opts[:params] + if env["REQUEST_METHOD"] == "GET" + params = Rack::Utils.parse_nested_query(params) if params.is_a?(String) + params.update(Rack::Utils.parse_nested_query(env["QUERY_STRING"])) + env["QUERY_STRING"] = build_nested_query(params) + elsif !opts.has_key?(:input) + opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded" + if params.is_a?(Hash) + if data = Multipart.build_multipart(params) + opts[:input] = data + opts["CONTENT_LENGTH"] ||= data.length.to_s + opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Multipart::MULTIPART_BOUNDARY}" + else + opts[:input] = build_nested_query(params) + end + else + opts[:input] = params + end + end + end + + empty_str = "" + empty_str.force_encoding("ASCII-8BIT") if empty_str.respond_to? :force_encoding + opts[:input] ||= empty_str + if String === opts[:input] + rack_input = StringIO.new(opts[:input]) + else + rack_input = opts[:input] + end + + rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding) + env['rack.input'] = rack_input + + env["CONTENT_LENGTH"] ||= env["rack.input"].length.to_s + + opts.each { |field, value| + env[field] = value if String === field + } + + env + end + + def self.build_nested_query(value, prefix = nil) + case value + when Array + value.map { |v| + build_nested_query(v, "#{prefix}[]") + }.join("&") + when Hash + value.map { |k, v| + build_nested_query(v, prefix ? "#{prefix}[#{Rack::Utils.escape(k)}]" : Rack::Utils.escape(k)) + }.join("&") + when String + raise ArgumentError, "value must be a Hash" if prefix.nil? + "#{prefix}=#{Rack::Utils.escape(value)}" + else + prefix + end + end def self.new(env = {}) super end def initialize(env = {}) - super(DEFAULT_ENV.merge(env)) + super(self.class.env_for('/').merge(env)) self.host = 'test.host' self.remote_addr = '0.0.0.0' diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack.rb deleted file mode 100644 index 371d015690..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack.rb +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright (C) 2007, 2008, 2009 Christian Neukirchen -# -# Rack is freely distributable under the terms of an MIT-style license. -# See COPYING or http://www.opensource.org/licenses/mit-license.php. - -path = File.expand_path(File.dirname(__FILE__)) -$:.unshift(path) unless $:.include?(path) - - -# The Rack main module, serving as a namespace for all core Rack -# modules and classes. -# -# All modules meant for use in your application are autoloaded here, -# so it should be enough just to require rack.rb in your code. - -module Rack - # The Rack protocol version number implemented. - VERSION = [1,0] - - # Return the Rack protocol version as a dotted string. - def self.version - VERSION.join(".") - end - - # Return the Rack release as a dotted string. - def self.release - "1.0" - end - - autoload :Builder, "rack/builder" - autoload :Cascade, "rack/cascade" - autoload :Chunked, "rack/chunked" - autoload :CommonLogger, "rack/commonlogger" - autoload :ConditionalGet, "rack/conditionalget" - autoload :ContentLength, "rack/content_length" - autoload :ContentType, "rack/content_type" - autoload :File, "rack/file" - autoload :Deflater, "rack/deflater" - autoload :Directory, "rack/directory" - autoload :ForwardRequest, "rack/recursive" - autoload :Handler, "rack/handler" - autoload :Head, "rack/head" - autoload :Lint, "rack/lint" - autoload :Lock, "rack/lock" - autoload :MethodOverride, "rack/methodoverride" - autoload :Mime, "rack/mime" - autoload :Recursive, "rack/recursive" - autoload :Reloader, "rack/reloader" - autoload :ShowExceptions, "rack/showexceptions" - autoload :ShowStatus, "rack/showstatus" - autoload :Static, "rack/static" - autoload :URLMap, "rack/urlmap" - autoload :Utils, "rack/utils" - - autoload :MockRequest, "rack/mock" - autoload :MockResponse, "rack/mock" - - autoload :Request, "rack/request" - autoload :Response, "rack/response" - - module Auth - autoload :Basic, "rack/auth/basic" - autoload :AbstractRequest, "rack/auth/abstract/request" - autoload :AbstractHandler, "rack/auth/abstract/handler" - autoload :OpenID, "rack/auth/openid" - module Digest - autoload :MD5, "rack/auth/digest/md5" - autoload :Nonce, "rack/auth/digest/nonce" - autoload :Params, "rack/auth/digest/params" - autoload :Request, "rack/auth/digest/request" - end - end - - module Session - autoload :Cookie, "rack/session/cookie" - autoload :Pool, "rack/session/pool" - autoload :Memcache, "rack/session/memcache" - end - - # *Adapters* connect Rack with third party web frameworks. - # - # Rack includes an adapter for Camping, see README for other - # frameworks supporting Rack in their code bases. - # - # Refer to the submodules for framework-specific calling details. - - module Adapter - autoload :Camping, "rack/adapter/camping" - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/adapter/camping.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/adapter/camping.rb deleted file mode 100644 index 63bc787f54..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/adapter/camping.rb +++ /dev/null @@ -1,22 +0,0 @@ -module Rack - module Adapter - class Camping - def initialize(app) - @app = app - end - - def call(env) - env["PATH_INFO"] ||= "" - env["SCRIPT_NAME"] ||= "" - controller = @app.run(env['rack.input'], env) - h = controller.headers - h.each_pair do |k,v| - if v.kind_of? URI - h[k] = v.to_s - end - end - [controller.status, controller.headers, [controller.body.to_s]] - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/handler.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/handler.rb deleted file mode 100644 index 214df6299e..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/handler.rb +++ /dev/null @@ -1,37 +0,0 @@ -module Rack - module Auth - # Rack::Auth::AbstractHandler implements common authentication functionality. - # - # +realm+ should be set for all handlers. - - class AbstractHandler - - attr_accessor :realm - - def initialize(app, realm=nil, &authenticator) - @app, @realm, @authenticator = app, realm, authenticator - end - - - private - - def unauthorized(www_authenticate = challenge) - return [ 401, - { 'Content-Type' => 'text/plain', - 'Content-Length' => '0', - 'WWW-Authenticate' => www_authenticate.to_s }, - [] - ] - end - - def bad_request - return [ 400, - { 'Content-Type' => 'text/plain', - 'Content-Length' => '0' }, - [] - ] - end - - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/request.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/request.rb deleted file mode 100644 index 1d9ccec685..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/request.rb +++ /dev/null @@ -1,37 +0,0 @@ -module Rack - module Auth - class AbstractRequest - - def initialize(env) - @env = env - end - - def provided? - !authorization_key.nil? - end - - def parts - @parts ||= @env[authorization_key].split(' ', 2) - end - - def scheme - @scheme ||= parts.first.downcase.to_sym - end - - def params - @params ||= parts.last - end - - - private - - AUTHORIZATION_KEYS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION'] - - def authorization_key - @authorization_key ||= AUTHORIZATION_KEYS.detect { |key| @env.has_key?(key) } - end - - end - - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/basic.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/basic.rb deleted file mode 100644 index 9557224648..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/basic.rb +++ /dev/null @@ -1,58 +0,0 @@ -require 'rack/auth/abstract/handler' -require 'rack/auth/abstract/request' - -module Rack - module Auth - # Rack::Auth::Basic implements HTTP Basic Authentication, as per RFC 2617. - # - # Initialize with the Rack application that you want protecting, - # and a block that checks if a username and password pair are valid. - # - # See also: example/protectedlobster.rb - - class Basic < AbstractHandler - - def call(env) - auth = Basic::Request.new(env) - - return unauthorized unless auth.provided? - - return bad_request unless auth.basic? - - if valid?(auth) - env['REMOTE_USER'] = auth.username - - return @app.call(env) - end - - unauthorized - end - - - private - - def challenge - 'Basic realm="%s"' % realm - end - - def valid?(auth) - @authenticator.call(*auth.credentials) - end - - class Request < Auth::AbstractRequest - def basic? - :basic == scheme - end - - def credentials - @credentials ||= params.unpack("m*").first.split(/:/, 2) - end - - def username - credentials.first - end - end - - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/md5.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/md5.rb deleted file mode 100644 index e579dc9632..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/md5.rb +++ /dev/null @@ -1,124 +0,0 @@ -require 'rack/auth/abstract/handler' -require 'rack/auth/digest/request' -require 'rack/auth/digest/params' -require 'rack/auth/digest/nonce' -require 'digest/md5' - -module Rack - module Auth - module Digest - # Rack::Auth::Digest::MD5 implements the MD5 algorithm version of - # HTTP Digest Authentication, as per RFC 2617. - # - # Initialize with the [Rack] application that you want protecting, - # and a block that looks up a plaintext password for a given username. - # - # +opaque+ needs to be set to a constant base64/hexadecimal string. - # - class MD5 < AbstractHandler - - attr_accessor :opaque - - attr_writer :passwords_hashed - - def initialize(*args) - super - @passwords_hashed = nil - end - - def passwords_hashed? - !!@passwords_hashed - end - - def call(env) - auth = Request.new(env) - - unless auth.provided? - return unauthorized - end - - if !auth.digest? || !auth.correct_uri? || !valid_qop?(auth) - return bad_request - end - - if valid?(auth) - if auth.nonce.stale? - return unauthorized(challenge(:stale => true)) - else - env['REMOTE_USER'] = auth.username - - return @app.call(env) - end - end - - unauthorized - end - - - private - - QOP = 'auth'.freeze - - def params(hash = {}) - Params.new do |params| - params['realm'] = realm - params['nonce'] = Nonce.new.to_s - params['opaque'] = H(opaque) - params['qop'] = QOP - - hash.each { |k, v| params[k] = v } - end - end - - def challenge(hash = {}) - "Digest #{params(hash)}" - end - - def valid?(auth) - valid_opaque?(auth) && valid_nonce?(auth) && valid_digest?(auth) - end - - def valid_qop?(auth) - QOP == auth.qop - end - - def valid_opaque?(auth) - H(opaque) == auth.opaque - end - - def valid_nonce?(auth) - auth.nonce.valid? - end - - def valid_digest?(auth) - digest(auth, @authenticator.call(auth.username)) == auth.response - end - - def md5(data) - ::Digest::MD5.hexdigest(data) - end - - alias :H :md5 - - def KD(secret, data) - H([secret, data] * ':') - end - - def A1(auth, password) - [ auth.username, auth.realm, password ] * ':' - end - - def A2(auth) - [ auth.method, auth.uri ] * ':' - end - - def digest(auth, password) - password_hash = passwords_hashed? ? password : H(A1(auth, password)) - - KD(password_hash, [ auth.nonce, auth.nc, auth.cnonce, QOP, H(A2(auth)) ] * ':') - end - - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/nonce.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/nonce.rb deleted file mode 100644 index dbe109f29a..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/nonce.rb +++ /dev/null @@ -1,51 +0,0 @@ -require 'digest/md5' - -module Rack - module Auth - module Digest - # Rack::Auth::Digest::Nonce is the default nonce generator for the - # Rack::Auth::Digest::MD5 authentication handler. - # - # +private_key+ needs to set to a constant string. - # - # +time_limit+ can be optionally set to an integer (number of seconds), - # to limit the validity of the generated nonces. - - class Nonce - - class << self - attr_accessor :private_key, :time_limit - end - - def self.parse(string) - new(*string.unpack("m*").first.split(' ', 2)) - end - - def initialize(timestamp = Time.now, given_digest = nil) - @timestamp, @given_digest = timestamp.to_i, given_digest - end - - def to_s - [([ @timestamp, digest ] * ' ')].pack("m*").strip - end - - def digest - ::Digest::MD5.hexdigest([ @timestamp, self.class.private_key ] * ':') - end - - def valid? - digest == @given_digest - end - - def stale? - !self.class.time_limit.nil? && (@timestamp - Time.now.to_i) < self.class.time_limit - end - - def fresh? - !stale? - end - - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/params.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/params.rb deleted file mode 100644 index 730e2efdc8..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/params.rb +++ /dev/null @@ -1,55 +0,0 @@ -module Rack - module Auth - module Digest - class Params < Hash - - def self.parse(str) - split_header_value(str).inject(new) do |header, param| - k, v = param.split('=', 2) - header[k] = dequote(v) - header - end - end - - def self.dequote(str) # From WEBrick::HTTPUtils - ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup - ret.gsub!(/\\(.)/, "\\1") - ret - end - - def self.split_header_value(str) - str.scan( /(\w+\=(?:"[^\"]+"|[^,]+))/n ).collect{ |v| v[0] } - end - - def initialize - super - - yield self if block_given? - end - - def [](k) - super k.to_s - end - - def []=(k, v) - super k.to_s, v.to_s - end - - UNQUOTED = ['qop', 'nc', 'stale'] - - def to_s - inject([]) do |parts, (k, v)| - parts << "#{k}=" + (UNQUOTED.include?(k) ? v.to_s : quote(v)) - parts - end.join(', ') - end - - def quote(str) # From WEBrick::HTTPUtils - '"' << str.gsub(/[\\\"]/o, "\\\1") << '"' - end - - end - end - end -end - diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/request.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/request.rb deleted file mode 100644 index a8aa3bf996..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/request.rb +++ /dev/null @@ -1,40 +0,0 @@ -require 'rack/auth/abstract/request' -require 'rack/auth/digest/params' -require 'rack/auth/digest/nonce' - -module Rack - module Auth - module Digest - class Request < Auth::AbstractRequest - - def method - @env['rack.methodoverride.original_method'] || @env['REQUEST_METHOD'] - end - - def digest? - :digest == scheme - end - - def correct_uri? - (@env['SCRIPT_NAME'].to_s + @env['PATH_INFO'].to_s) == uri - end - - def nonce - @nonce ||= Nonce.parse(params['nonce']) - end - - def params - @params ||= Params.parse(parts.last) - end - - def method_missing(sym) - if params.has_key? key = sym.to_s - return params[key] - end - super - end - - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/openid.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/openid.rb deleted file mode 100644 index c5f6a5143e..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/openid.rb +++ /dev/null @@ -1,480 +0,0 @@ -# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net - -gem 'ruby-openid', '~> 2' if defined? Gem -require 'rack/request' -require 'rack/utils' -require 'rack/auth/abstract/handler' -require 'uri' -require 'openid' #gem -require 'openid/extension' #gem -require 'openid/store/memory' #gem - -module Rack - class Request - def openid_request - @env['rack.auth.openid.request'] - end - - def openid_response - @env['rack.auth.openid.response'] - end - end - - module Auth - - # Rack::Auth::OpenID provides a simple method for setting up an OpenID - # Consumer. It requires the ruby-openid library from janrain to operate, - # as well as a rack method of session management. - # - # The ruby-openid home page is at http://openidenabled.com/ruby-openid/. - # - # The OpenID specifications can be found at - # http://openid.net/specs/openid-authentication-1_1.html - # and - # http://openid.net/specs/openid-authentication-2_0.html. Documentation - # for published OpenID extensions and related topics can be found at - # http://openid.net/developers/specs/. - # - # It is recommended to read through the OpenID spec, as well as - # ruby-openid's documentation, to understand what exactly goes on. However - # a setup as simple as the presented examples is enough to provide - # Consumer functionality. - # - # This library strongly intends to utilize the OpenID 2.0 features of the - # ruby-openid library, which provides OpenID 1.0 compatiblity. - # - # NOTE: Due to the amount of data that this library stores in the - # session, Rack::Session::Cookie may fault. - - class OpenID - - class NoSession < RuntimeError; end - class BadExtension < RuntimeError; end - # Required for ruby-openid - ValidStatus = [:success, :setup_needed, :cancel, :failure] - - # = Arguments - # - # The first argument is the realm, identifying the site they are trusting - # with their identity. This is required, also treated as the trust_root - # in OpenID 1.x exchanges. - # - # The optional second argument is a hash of options. - # - # == Options - # - # :return_to defines the url to return to after the client - # authenticates with the openid service provider. This url should point - # to where Rack::Auth::OpenID is mounted. If :return_to is not - # provided, return_to will be the current url which allows flexibility - # with caveats. - # - # :session_key defines the key to the session hash in the env. - # It defaults to 'rack.session'. - # - # :openid_param defines at what key in the request parameters to - # find the identifier to resolve. As per the 2.0 spec, the default is - # 'openid_identifier'. - # - # :store defined what OpenID Store to use for persistant - # information. By default a Store::Memory will be used. - # - # :immediate as true will make initial requests to be of an - # immediate type. This is false by default. See OpenID specification - # documentation. - # - # :extensions should be a hash of openid extension - # implementations. The key should be the extension main module, the value - # should be an array of arguments for extension::Request.new. - # The hash is iterated over and passed to #add_extension for processing. - # Please see #add_extension for further documentation. - # - # == Examples - # - # simple_oid = OpenID.new('http://mysite.com/') - # - # return_oid = OpenID.new('http://mysite.com/', { - # :return_to => 'http://mysite.com/openid' - # }) - # - # complex_oid = OpenID.new('http://mysite.com/', - # :immediate => true, - # :extensions => { - # ::OpenID::SReg => [['email'],['nickname']] - # } - # ) - # - # = Advanced - # - # Most of the functionality of this library is encapsulated such that - # expansion and overriding functions isn't difficult nor tricky. - # Alternately, to avoid opening up singleton objects or subclassing, a - # wrapper rack middleware can be composed to act upon Auth::OpenID's - # responses. See #check and #finish for locations of pertinent data. - # - # == Responses - # - # To change the responses that Auth::OpenID returns, override the methods - # #redirect, #bad_request, #unauthorized, #access_denied, and - # #foreign_server_failure. - # - # Additionally #confirm_post_params is used when the URI would exceed - # length limits on a GET request when doing the initial verification - # request. - # - # == Processing - # - # To change methods of processing completed transactions, override the - # methods #success, #setup_needed, #cancel, and #failure. Please ensure - # the returned object is a rack compatible response. - # - # The first argument is an OpenID::Response, the second is a - # Rack::Request of the current request, the last is the hash used in - # ruby-openid handling, which can be found manually at - # env['rack.session'][:openid]. - # - # This is useful if you wanted to expand the processing done, such as - # setting up user accounts. - # - # oid_app = Rack::Auth::OpenID.new realm, :return_to => return_to - # def oid_app.success oid, request, session - # user = Models::User[oid.identity_url] - # user ||= Models::User.create_from_openid oid - # request['rack.session'][:user] = user.id - # redirect MyApp.site_home - # end - # - # site_map['/openid'] = oid_app - # map = Rack::URLMap.new site_map - # ... - - def initialize(realm, options={}) - realm = URI(realm) - raise ArgumentError, "Invalid realm: #{realm}" \ - unless realm.absolute? \ - and realm.fragment.nil? \ - and realm.scheme =~ /^https?$/ \ - and realm.host =~ /^(\*\.)?#{URI::REGEXP::PATTERN::URIC_NO_SLASH}+/ - realm.path = '/' if realm.path.empty? - @realm = realm.to_s - - if ruri = options[:return_to] - ruri = URI(ruri) - raise ArgumentError, "Invalid return_to: #{ruri}" \ - unless ruri.absolute? \ - and ruri.scheme =~ /^https?$/ \ - and ruri.fragment.nil? - raise ArgumentError, "return_to #{ruri} not within realm #{realm}" \ - unless self.within_realm?(ruri) - @return_to = ruri.to_s - end - - @session_key = options[:session_key] || 'rack.session' - @openid_param = options[:openid_param] || 'openid_identifier' - @store = options[:store] || ::OpenID::Store::Memory.new - @immediate = !!options[:immediate] - - @extensions = {} - if extensions = options.delete(:extensions) - extensions.each do |ext, args| - add_extension ext, *args - end - end - - # Undocumented, semi-experimental - @anonymous = !!options[:anonymous] - end - - attr_reader :realm, :return_to, :session_key, :openid_param, :store, - :immediate, :extensions - - # Sets up and uses session data at :openid within the session. - # Errors in this setup will raise a NoSession exception. - # - # If the parameter 'openid.mode' is set, which implies a followup from - # the openid server, processing is passed to #finish and the result is - # returned. However, if there is no appropriate openid information in the - # session, a 400 error is returned. - # - # If the parameter specified by options[:openid_param] is - # present, processing is passed to #check and the result is returned. - # - # If neither of these conditions are met, #unauthorized is called. - - def call(env) - env['rack.auth.openid'] = self - env_session = env[@session_key] - unless env_session and env_session.is_a?(Hash) - raise NoSession, 'No compatible session' - end - # let us work in our own namespace... - session = (env_session[:openid] ||= {}) - unless session and session.is_a?(Hash) - raise NoSession, 'Incompatible openid session' - end - - request = Rack::Request.new(env) - consumer = ::OpenID::Consumer.new(session, @store) - - if mode = request.GET['openid.mode'] - if session.key?(:openid_param) - finish(consumer, session, request) - else - bad_request - end - elsif request.GET[@openid_param] - check(consumer, session, request) - else - unauthorized - end - end - - # As the first part of OpenID consumer action, #check retrieves the data - # required for completion. - # - # If all parameters fit within the max length of a URI, a 303 redirect - # will be returned. Otherwise #confirm_post_params will be called. - # - # Any messages from OpenID's request are logged to env['rack.errors'] - # - # env['rack.auth.openid.request'] is the openid checkid request - # instance. - # - # session[:openid_param] is set to the openid identifier - # provided by the user. - # - # session[:return_to] is set to the return_to uri given to the - # identity provider. - - def check(consumer, session, req) - oid = consumer.begin(req.GET[@openid_param], @anonymous) - req.env['rack.auth.openid.request'] = oid - req.env['rack.errors'].puts(oid.message) - p oid if $DEBUG - - ## Extension support - extensions.each do |ext,args| - oid.add_extension(ext::Request.new(*args)) - end - - session[:openid_param] = req.GET[openid_param] - return_to_uri = return_to ? return_to : req.url - session[:return_to] = return_to_uri - immediate = session.key?(:setup_needed) ? false : immediate - - if oid.send_redirect?(realm, return_to_uri, immediate) - uri = oid.redirect_url(realm, return_to_uri, immediate) - redirect(uri) - else - confirm_post_params(oid, realm, return_to_uri, immediate) - end - rescue ::OpenID::DiscoveryFailure => e - # thrown from inside OpenID::Consumer#begin by yadis stuff - req.env['rack.errors'].puts([e.message, *e.backtrace]*"\n") - return foreign_server_failure - end - - # This is the final portion of authentication. - # If successful, a redirect to the realm is be returned. - # Data gathered from extensions are stored in session[:openid] with the - # extension's namespace uri as the key. - # - # Any messages from OpenID's response are logged to env['rack.errors'] - # - # env['rack.auth.openid.response'] will contain the openid - # response. - - def finish(consumer, session, req) - oid = consumer.complete(req.GET, req.url) - req.env['rack.auth.openid.response'] = oid - req.env['rack.errors'].puts(oid.message) - p oid if $DEBUG - - raise unless ValidStatus.include?(oid.status) - __send__(oid.status, oid, req, session) - end - - # The first argument should be the main extension module. - # The extension module should contain the constants: - # * class Request, should have OpenID::Extension as an ancestor - # * class Response, should have OpenID::Extension as an ancestor - # * string NS_URI, which defining the namespace of the extension - # - # All trailing arguments will be passed to extension::Request.new in - # #check. - # The openid response will be passed to - # extension::Response#from_success_response, #get_extension_args will be - # called on the result to attain the gathered data. - # - # This method returns the key at which the response data will be found in - # the session, which is the namespace uri by default. - - def add_extension(ext, *args) - raise BadExtension unless valid_extension?(ext) - extensions[ext] = args - return ext::NS_URI - end - - # Checks the validitity, in the context of usage, of a submitted - # extension. - - def valid_extension?(ext) - if not %w[NS_URI Request Response].all?{|c| ext.const_defined?(c) } - raise ArgumentError, 'Extension is missing constants.' - elsif not ext::Response.respond_to?(:from_success_response) - raise ArgumentError, 'Response is missing required method.' - end - return true - rescue - return false - end - - # Checks the provided uri to ensure it'd be considered within the realm. - # is currently not compatible with wildcard realms. - - def within_realm? uri - uri = URI.parse(uri.to_s) - realm = URI.parse(self.realm) - return false unless uri.absolute? - return false unless uri.path[0, realm.path.size] == realm.path - return false unless uri.host == realm.host or realm.host[/^\*\./] - # for wildcard support, is awkward with URI limitations - realm_match = Regexp.escape(realm.host). - sub(/^\*\./,"^#{URI::REGEXP::PATTERN::URIC_NO_SLASH}+.")+'$' - return false unless uri.host.match(realm_match) - return true - end - alias_method :include?, :within_realm? - - protected - - ### These methods define some of the boilerplate responses. - - # Returns an html form page for posting to an Identity Provider if the - # GET request would exceed the upper URI length limit. - - def confirm_post_params(oid, realm, return_to, immediate) - Rack::Response.new.finish do |r| - r.write 'Confirm...' - r.write oid.form_markup(realm, return_to, immediate) - r.write '' - end - end - - # Returns a 303 redirect with the destination of that provided by the - # argument. - - def redirect(uri) - [ 303, {'Content-Length'=>'0', 'Content-Type'=>'text/plain', - 'Location' => uri}, - [] ] - end - - # Returns an empty 400 response. - - def bad_request - [ 400, {'Content-Type'=>'text/plain', 'Content-Length'=>'0'}, - [''] ] - end - - # Returns a basic unauthorized 401 response. - - def unauthorized - [ 401, {'Content-Type' => 'text/plain', 'Content-Length' => '13'}, - ['Unauthorized.'] ] - end - - # Returns a basic access denied 403 response. - - def access_denied - [ 403, {'Content-Type' => 'text/plain', 'Content-Length' => '14'}, - ['Access denied.'] ] - end - - # Returns a 503 response to be used if communication with the remote - # OpenID server fails. - - def foreign_server_failure - [ 503, {'Content-Type'=>'text/plain', 'Content-Length' => '23'}, - ['Foreign server failure.'] ] - end - - private - - ### These methods are called after a transaction is completed, depending - # on its outcome. These should all return a rack compatible response. - # You'd want to override these to provide additional functionality. - - # Called to complete processing on a successful transaction. - # Within the openid session, :openid_identity and :openid_identifier are - # set to the user friendly and the standard representation of the - # validated identity. All other data in the openid session is cleared. - - def success(oid, request, session) - session.clear - session[:openid_identity] = oid.display_identifier - session[:openid_identifier] = oid.identity_url - extensions.keys.each do |ext| - label = ext.name[/[^:]+$/].downcase - response = ext::Response.from_success_response(oid) - session[label] = response.data - end - redirect(realm) - end - - # Called if the Identity Provider indicates further setup by the user is - # required. - # The identifier is retrived from the openid session at :openid_param. - # And :setup_needed is set to true to prevent looping. - - def setup_needed(oid, request, session) - identifier = session[:openid_param] - session[:setup_needed] = true - redirect req.script_name + '?' + openid_param + '=' + identifier - end - - # Called if the user indicates they wish to cancel identification. - # Data within openid session is cleared. - - def cancel(oid, request, session) - session.clear - access_denied - end - - # Called if the Identity Provider indicates the user is unable to confirm - # their identity. Data within the openid session is left alone, in case - # of swarm auth attacks. - - def failure(oid, request, session) - unauthorized - end - end - - # A class developed out of the request to use OpenID as an authentication - # middleware. The request will be sent to the OpenID instance unless the - # block evaluates to true. For example in rackup, you can use it as such: - # - # use Rack::Session::Pool - # use Rack::Auth::OpenIDAuth, realm, openid_options do |env| - # env['rack.session'][:authkey] == a_string - # end - # run RackApp - # - # Or simply: - # - # app = Rack::Auth::OpenIDAuth.new app, realm, openid_options, &auth - - class OpenIDAuth < Rack::Auth::AbstractHandler - attr_reader :oid - def initialize(app, realm, options={}, &auth) - @oid = OpenID.new(realm, options) - super(app, &auth) - end - - def call(env) - to = auth.call(env) ? @app : @oid - to.call env - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/builder.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/builder.rb deleted file mode 100644 index 295235e56a..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/builder.rb +++ /dev/null @@ -1,63 +0,0 @@ -module Rack - # Rack::Builder implements a small DSL to iteratively construct Rack - # applications. - # - # Example: - # - # app = Rack::Builder.new { - # use Rack::CommonLogger - # use Rack::ShowExceptions - # map "/lobster" do - # use Rack::Lint - # run Rack::Lobster.new - # end - # } - # - # Or - # - # app = Rack::Builder.app do - # use Rack::CommonLogger - # lambda { |env| [200, {'Content-Type' => 'text/plain'}, 'OK'] } - # end - # - # +use+ adds a middleware to the stack, +run+ dispatches to an application. - # You can use +map+ to construct a Rack::URLMap in a convenient way. - - class Builder - def initialize(&block) - @ins = [] - instance_eval(&block) if block_given? - end - - def self.app(&block) - self.new(&block).to_app - end - - def use(middleware, *args, &block) - @ins << lambda { |app| middleware.new(app, *args, &block) } - end - - def run(app) - @ins << app #lambda { |nothing| app } - end - - def map(path, &block) - if @ins.last.kind_of? Hash - @ins.last[path] = self.class.new(&block).to_app - else - @ins << {} - map(path, &block) - end - end - - def to_app - @ins[-1] = Rack::URLMap.new(@ins.last) if Hash === @ins.last - inner_app = @ins.last - @ins[0...-1].reverse.inject(inner_app) { |a, e| e.call(a) } - end - - def call(env) - to_app.call(env) - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/cascade.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/cascade.rb deleted file mode 100644 index a038aa1105..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/cascade.rb +++ /dev/null @@ -1,36 +0,0 @@ -module Rack - # Rack::Cascade tries an request on several apps, and returns the - # first response that is not 404 (or in a list of configurable - # status codes). - - class Cascade - attr_reader :apps - - def initialize(apps, catch=404) - @apps = apps - @catch = [*catch] - end - - def call(env) - status = headers = body = nil - raise ArgumentError, "empty cascade" if @apps.empty? - @apps.each { |app| - begin - status, headers, body = app.call(env) - break unless @catch.include?(status.to_i) - end - } - [status, headers, body] - end - - def add app - @apps << app - end - - def include? app - @apps.include? app - end - - alias_method :<<, :add - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/chunked.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/chunked.rb deleted file mode 100644 index 280d89dd65..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/chunked.rb +++ /dev/null @@ -1,49 +0,0 @@ -require 'rack/utils' - -module Rack - - # Middleware that applies chunked transfer encoding to response bodies - # when the response does not include a Content-Length header. - class Chunked - include Rack::Utils - - def initialize(app) - @app = app - end - - def call(env) - status, headers, body = @app.call(env) - headers = HeaderHash.new(headers) - - if env['HTTP_VERSION'] == 'HTTP/1.0' || - STATUS_WITH_NO_ENTITY_BODY.include?(status) || - headers['Content-Length'] || - headers['Transfer-Encoding'] - [status, headers.to_hash, body] - else - dup.chunk(status, headers, body) - end - end - - def chunk(status, headers, body) - @body = body - headers.delete('Content-Length') - headers['Transfer-Encoding'] = 'chunked' - [status, headers.to_hash, self] - end - - def each - term = "\r\n" - @body.each do |chunk| - size = bytesize(chunk) - next if size == 0 - yield [size.to_s(16), term, chunk, term].join - end - yield ["0", term, "", term].join - end - - def close - @body.close if @body.respond_to?(:close) - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/commonlogger.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/commonlogger.rb deleted file mode 100644 index 5e68ac626d..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/commonlogger.rb +++ /dev/null @@ -1,61 +0,0 @@ -module Rack - # Rack::CommonLogger forwards every request to an +app+ given, and - # logs a line in the Apache common log format to the +logger+, or - # rack.errors by default. - - class CommonLogger - def initialize(app, logger=nil) - @app = app - @logger = logger - end - - def call(env) - dup._call(env) - end - - def _call(env) - @env = env - @logger ||= self - @time = Time.now - @status, @header, @body = @app.call(env) - [@status, @header, self] - end - - def close - @body.close if @body.respond_to? :close - end - - # By default, log to rack.errors. - def <<(str) - @env["rack.errors"].write(str) - @env["rack.errors"].flush - end - - def each - length = 0 - @body.each { |part| - length += part.size - yield part - } - - @now = Time.now - - # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common - # lilith.local - - [07/Aug/2006 23:58:02] "GET / HTTP/1.1" 500 - - # %{%s - %s [%s] "%s %s%s %s" %d %s\n} % - @logger << %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n} % - [ - @env['HTTP_X_FORWARDED_FOR'] || @env["REMOTE_ADDR"] || "-", - @env["REMOTE_USER"] || "-", - @now.strftime("%d/%b/%Y %H:%M:%S"), - @env["REQUEST_METHOD"], - @env["PATH_INFO"], - @env["QUERY_STRING"].empty? ? "" : "?"+@env["QUERY_STRING"], - @env["HTTP_VERSION"], - @status.to_s[0..3], - (length.zero? ? "-" : length.to_s), - @now - @time - ] - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/conditionalget.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/conditionalget.rb deleted file mode 100644 index 046ebdb00a..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/conditionalget.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'rack/utils' - -module Rack - - # Middleware that enables conditional GET using If-None-Match and - # If-Modified-Since. The application should set either or both of the - # Last-Modified or Etag response headers according to RFC 2616. When - # either of the conditions is met, the response body is set to be zero - # length and the response status is set to 304 Not Modified. - # - # Applications that defer response body generation until the body's each - # message is received will avoid response body generation completely when - # a conditional GET matches. - # - # Adapted from Michael Klishin's Merb implementation: - # http://github.com/wycats/merb-core/tree/master/lib/merb-core/rack/middleware/conditional_get.rb - class ConditionalGet - def initialize(app) - @app = app - end - - def call(env) - return @app.call(env) unless %w[GET HEAD].include?(env['REQUEST_METHOD']) - - status, headers, body = @app.call(env) - headers = Utils::HeaderHash.new(headers) - if etag_matches?(env, headers) || modified_since?(env, headers) - status = 304 - headers.delete('Content-Type') - headers.delete('Content-Length') - body = [] - end - [status, headers, body] - end - - private - def etag_matches?(env, headers) - etag = headers['Etag'] and etag == env['HTTP_IF_NONE_MATCH'] - end - - def modified_since?(env, headers) - last_modified = headers['Last-Modified'] and - last_modified == env['HTTP_IF_MODIFIED_SINCE'] - end - end - -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_length.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_length.rb deleted file mode 100644 index 1e56d43853..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_length.rb +++ /dev/null @@ -1,29 +0,0 @@ -require 'rack/utils' - -module Rack - # Sets the Content-Length header on responses with fixed-length bodies. - class ContentLength - include Rack::Utils - - def initialize(app) - @app = app - end - - def call(env) - status, headers, body = @app.call(env) - headers = HeaderHash.new(headers) - - if !STATUS_WITH_NO_ENTITY_BODY.include?(status) && - !headers['Content-Length'] && - !headers['Transfer-Encoding'] && - (body.respond_to?(:to_ary) || body.respond_to?(:to_str)) - - body = [body] if body.respond_to?(:to_str) # rack 0.4 compat - length = body.to_ary.inject(0) { |len, part| len + bytesize(part) } - headers['Content-Length'] = length.to_s - end - - [status, headers, body] - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_type.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_type.rb deleted file mode 100644 index 0c1e1ca3e1..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_type.rb +++ /dev/null @@ -1,23 +0,0 @@ -require 'rack/utils' - -module Rack - - # Sets the Content-Type header on responses which don't have one. - # - # Builder Usage: - # use Rack::ContentType, "text/plain" - # - # When no content type argument is provided, "text/html" is assumed. - class ContentType - def initialize(app, content_type = "text/html") - @app, @content_type = app, content_type - end - - def call(env) - status, headers, body = @app.call(env) - headers = Utils::HeaderHash.new(headers) - headers['Content-Type'] ||= @content_type - [status, headers.to_hash, body] - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/deflater.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/deflater.rb deleted file mode 100644 index 14137a944d..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/deflater.rb +++ /dev/null @@ -1,96 +0,0 @@ -require "zlib" -require "stringio" -require "time" # for Time.httpdate -require 'rack/utils' - -module Rack - class Deflater - def initialize(app) - @app = app - end - - def call(env) - status, headers, body = @app.call(env) - headers = Utils::HeaderHash.new(headers) - - # Skip compressing empty entity body responses and responses with - # no-transform set. - if Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status) || - headers['Cache-Control'].to_s =~ /\bno-transform\b/ - return [status, headers, body] - end - - request = Request.new(env) - - encoding = Utils.select_best_encoding(%w(gzip deflate identity), - request.accept_encoding) - - # Set the Vary HTTP header. - vary = headers["Vary"].to_s.split(",").map { |v| v.strip } - unless vary.include?("*") || vary.include?("Accept-Encoding") - headers["Vary"] = vary.push("Accept-Encoding").join(",") - end - - case encoding - when "gzip" - headers['Content-Encoding'] = "gzip" - headers.delete('Content-Length') - mtime = headers.key?("Last-Modified") ? - Time.httpdate(headers["Last-Modified"]) : Time.now - [status, headers, GzipStream.new(body, mtime)] - when "deflate" - headers['Content-Encoding'] = "deflate" - headers.delete('Content-Length') - [status, headers, DeflateStream.new(body)] - when "identity" - [status, headers, body] - when nil - message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found." - [406, {"Content-Type" => "text/plain", "Content-Length" => message.length.to_s}, [message]] - end - end - - class GzipStream - def initialize(body, mtime) - @body = body - @mtime = mtime - end - - def each(&block) - @writer = block - gzip =::Zlib::GzipWriter.new(self) - gzip.mtime = @mtime - @body.each { |part| gzip << part } - @body.close if @body.respond_to?(:close) - gzip.close - @writer = nil - end - - def write(data) - @writer.call(data) - end - end - - class DeflateStream - DEFLATE_ARGS = [ - Zlib::DEFAULT_COMPRESSION, - # drop the zlib header which causes both Safari and IE to choke - -Zlib::MAX_WBITS, - Zlib::DEF_MEM_LEVEL, - Zlib::DEFAULT_STRATEGY - ] - - def initialize(body) - @body = body - end - - def each - deflater = ::Zlib::Deflate.new(*DEFLATE_ARGS) - @body.each { |part| yield deflater.deflate(part) } - @body.close if @body.respond_to?(:close) - yield deflater.finish - nil - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/directory.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/directory.rb deleted file mode 100644 index acdd3029d3..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/directory.rb +++ /dev/null @@ -1,153 +0,0 @@ -require 'time' -require 'rack/utils' -require 'rack/mime' - -module Rack - # Rack::Directory serves entries below the +root+ given, according to the - # path info of the Rack request. If a directory is found, the file's contents - # will be presented in an html based index. If a file is found, the env will - # be passed to the specified +app+. - # - # If +app+ is not specified, a Rack::File of the same +root+ will be used. - - class Directory - DIR_FILE = "%s%s%s%s" - DIR_PAGE = <<-PAGE - - %s - - - -

%s

-
- - - - - - - -%s -
NameSizeTypeLast Modified
-
- - PAGE - - attr_reader :files - attr_accessor :root, :path - - def initialize(root, app=nil) - @root = F.expand_path(root) - @app = app || Rack::File.new(@root) - end - - def call(env) - dup._call(env) - end - - F = ::File - - def _call(env) - @env = env - @script_name = env['SCRIPT_NAME'] - @path_info = Utils.unescape(env['PATH_INFO']) - - if forbidden = check_forbidden - forbidden - else - @path = F.join(@root, @path_info) - list_path - end - end - - def check_forbidden - return unless @path_info.include? ".." - - body = "Forbidden\n" - size = Rack::Utils.bytesize(body) - return [403, {"Content-Type" => "text/plain","Content-Length" => size.to_s}, [body]] - end - - def list_directory - @files = [['../','Parent Directory','','','']] - glob = F.join(@path, '*') - - Dir[glob].sort.each do |node| - stat = stat(node) - next unless stat - basename = F.basename(node) - ext = F.extname(node) - - url = F.join(@script_name, @path_info, basename) - size = stat.size - type = stat.directory? ? 'directory' : Mime.mime_type(ext) - size = stat.directory? ? '-' : filesize_format(size) - mtime = stat.mtime.httpdate - url << '/' if stat.directory? - basename << '/' if stat.directory? - - @files << [ url, basename, size, type, mtime ] - end - - return [ 200, {'Content-Type'=>'text/html; charset=utf-8'}, self ] - end - - def stat(node, max = 10) - F.stat(node) - rescue Errno::ENOENT, Errno::ELOOP - return nil - end - - # TODO: add correct response if not readable, not sure if 404 is the best - # option - def list_path - @stat = F.stat(@path) - - if @stat.readable? - return @app.call(@env) if @stat.file? - return list_directory if @stat.directory? - else - raise Errno::ENOENT, 'No such file or directory' - end - - rescue Errno::ENOENT, Errno::ELOOP - return entity_not_found - end - - def entity_not_found - body = "Entity not found: #{@path_info}\n" - size = Rack::Utils.bytesize(body) - return [404, {"Content-Type" => "text/plain", "Content-Length" => size.to_s}, [body]] - end - - def each - show_path = @path.sub(/^#{@root}/,'') - files = @files.map{|f| DIR_FILE % f }*"\n" - page = DIR_PAGE % [ show_path, show_path , files ] - page.each_line{|l| yield l } - end - - # Stolen from Ramaze - - FILESIZE_FORMAT = [ - ['%.1fT', 1 << 40], - ['%.1fG', 1 << 30], - ['%.1fM', 1 << 20], - ['%.1fK', 1 << 10], - ] - - def filesize_format(int) - FILESIZE_FORMAT.each do |format, size| - return format % (int.to_f / size) if int >= size - end - - int.to_s + 'B' - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/file.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/file.rb deleted file mode 100644 index fe62bd6b86..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/file.rb +++ /dev/null @@ -1,88 +0,0 @@ -require 'time' -require 'rack/utils' -require 'rack/mime' - -module Rack - # Rack::File serves files below the +root+ given, according to the - # path info of the Rack request. - # - # Handlers can detect if bodies are a Rack::File, and use mechanisms - # like sendfile on the +path+. - - class File - attr_accessor :root - attr_accessor :path - - alias :to_path :path - - def initialize(root) - @root = root - end - - def call(env) - dup._call(env) - end - - F = ::File - - def _call(env) - @path_info = Utils.unescape(env["PATH_INFO"]) - return forbidden if @path_info.include? ".." - - @path = F.join(@root, @path_info) - - begin - if F.file?(@path) && F.readable?(@path) - serving - else - raise Errno::EPERM - end - rescue SystemCallError - not_found - end - end - - def forbidden - body = "Forbidden\n" - [403, {"Content-Type" => "text/plain", - "Content-Length" => body.size.to_s}, - [body]] - end - - # NOTE: - # We check via File::size? whether this file provides size info - # via stat (e.g. /proc files often don't), otherwise we have to - # figure it out by reading the whole file into memory. And while - # we're at it we also use this as body then. - - def serving - if size = F.size?(@path) - body = self - else - body = [F.read(@path)] - size = Utils.bytesize(body.first) - end - - [200, { - "Last-Modified" => F.mtime(@path).httpdate, - "Content-Type" => Mime.mime_type(F.extname(@path), 'text/plain'), - "Content-Length" => size.to_s - }, body] - end - - def not_found - body = "File not found: #{@path_info}\n" - [404, {"Content-Type" => "text/plain", - "Content-Length" => body.size.to_s}, - [body]] - end - - def each - F.open(@path, "rb") { |file| - while part = file.read(8192) - yield part - end - } - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler.rb deleted file mode 100644 index 5624a1e79d..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler.rb +++ /dev/null @@ -1,69 +0,0 @@ -module Rack - # *Handlers* connect web servers with Rack. - # - # Rack includes Handlers for Mongrel, WEBrick, FastCGI, CGI, SCGI - # and LiteSpeed. - # - # Handlers usually are activated by calling MyHandler.run(myapp). - # A second optional hash can be passed to include server-specific - # configuration. - module Handler - def self.get(server) - return unless server - server = server.to_s - - if klass = @handlers[server] - obj = Object - klass.split("::").each { |x| obj = obj.const_get(x) } - obj - else - try_require('rack/handler', server) - const_get(server) - end - end - - # Transforms server-name constants to their canonical form as filenames, - # then tries to require them but silences the LoadError if not found - # - # Naming convention: - # - # Foo # => 'foo' - # FooBar # => 'foo_bar.rb' - # FooBAR # => 'foobar.rb' - # FOObar # => 'foobar.rb' - # FOOBAR # => 'foobar.rb' - # FooBarBaz # => 'foo_bar_baz.rb' - def self.try_require(prefix, const_name) - file = const_name.gsub(/^[A-Z]+/) { |pre| pre.downcase }. - gsub(/[A-Z]+[^A-Z]/, '_\&').downcase - - require(::File.join(prefix, file)) - rescue LoadError - end - - def self.register(server, klass) - @handlers ||= {} - @handlers[server] = klass - end - - autoload :CGI, "rack/handler/cgi" - autoload :FastCGI, "rack/handler/fastcgi" - autoload :Mongrel, "rack/handler/mongrel" - autoload :EventedMongrel, "rack/handler/evented_mongrel" - autoload :SwiftipliedMongrel, "rack/handler/swiftiplied_mongrel" - autoload :WEBrick, "rack/handler/webrick" - autoload :LSWS, "rack/handler/lsws" - autoload :SCGI, "rack/handler/scgi" - autoload :Thin, "rack/handler/thin" - - register 'cgi', 'Rack::Handler::CGI' - register 'fastcgi', 'Rack::Handler::FastCGI' - register 'mongrel', 'Rack::Handler::Mongrel' - register 'emongrel', 'Rack::Handler::EventedMongrel' - register 'smongrel', 'Rack::Handler::SwiftipliedMongrel' - register 'webrick', 'Rack::Handler::WEBrick' - register 'lsws', 'Rack::Handler::LSWS' - register 'scgi', 'Rack::Handler::SCGI' - register 'thin', 'Rack::Handler::Thin' - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/cgi.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/cgi.rb deleted file mode 100644 index f45f3d735a..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/cgi.rb +++ /dev/null @@ -1,61 +0,0 @@ -require 'rack/content_length' - -module Rack - module Handler - class CGI - def self.run(app, options=nil) - serve app - end - - def self.serve(app) - app = ContentLength.new(app) - - env = ENV.to_hash - env.delete "HTTP_CONTENT_LENGTH" - - env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" - - env.update({"rack.version" => [1,0], - "rack.input" => $stdin, - "rack.errors" => $stderr, - - "rack.multithread" => false, - "rack.multiprocess" => true, - "rack.run_once" => true, - - "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" - }) - - env["QUERY_STRING"] ||= "" - env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] - env["REQUEST_PATH"] ||= "/" - - status, headers, body = app.call(env) - begin - send_headers status, headers - send_body body - ensure - body.close if body.respond_to? :close - end - end - - def self.send_headers(status, headers) - STDOUT.print "Status: #{status}\r\n" - headers.each { |k, vs| - vs.split("\n").each { |v| - STDOUT.print "#{k}: #{v}\r\n" - } - } - STDOUT.print "\r\n" - STDOUT.flush - end - - def self.send_body(body) - body.each { |part| - STDOUT.print part - STDOUT.flush - } - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/evented_mongrel.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/evented_mongrel.rb deleted file mode 100644 index 0f5cbf7293..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/evented_mongrel.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'swiftcore/evented_mongrel' - -module Rack - module Handler - class EventedMongrel < Handler::Mongrel - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/fastcgi.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/fastcgi.rb deleted file mode 100644 index 11e1fcaa74..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/fastcgi.rb +++ /dev/null @@ -1,88 +0,0 @@ -require 'fcgi' -require 'socket' -require 'rack/content_length' -require 'rack/rewindable_input' - -class FCGI::Stream - alias _rack_read_without_buffer read - - def read(n, buffer=nil) - buf = _rack_read_without_buffer n - buffer.replace(buf.to_s) if buffer - buf - end -end - -module Rack - module Handler - class FastCGI - def self.run(app, options={}) - file = options[:File] and STDIN.reopen(UNIXServer.new(file)) - port = options[:Port] and STDIN.reopen(TCPServer.new(port)) - FCGI.each { |request| - serve request, app - } - end - - def self.serve(request, app) - app = Rack::ContentLength.new(app) - - env = request.env - env.delete "HTTP_CONTENT_LENGTH" - - env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" - - rack_input = RewindableInput.new(request.in) - - env.update({"rack.version" => [1,0], - "rack.input" => rack_input, - "rack.errors" => request.err, - - "rack.multithread" => false, - "rack.multiprocess" => true, - "rack.run_once" => false, - - "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http" - }) - - env["QUERY_STRING"] ||= "" - env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] - env["REQUEST_PATH"] ||= "/" - env.delete "PATH_INFO" if env["PATH_INFO"] == "" - env.delete "CONTENT_TYPE" if env["CONTENT_TYPE"] == "" - env.delete "CONTENT_LENGTH" if env["CONTENT_LENGTH"] == "" - - begin - status, headers, body = app.call(env) - begin - send_headers request.out, status, headers - send_body request.out, body - ensure - body.close if body.respond_to? :close - end - ensure - rack_input.close - request.finish - end - end - - def self.send_headers(out, status, headers) - out.print "Status: #{status}\r\n" - headers.each { |k, vs| - vs.split("\n").each { |v| - out.print "#{k}: #{v}\r\n" - } - } - out.print "\r\n" - out.flush - end - - def self.send_body(out, body) - body.each { |part| - out.print part - out.flush - } - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/lsws.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/lsws.rb deleted file mode 100644 index 7231336d7b..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/lsws.rb +++ /dev/null @@ -1,55 +0,0 @@ -require 'lsapi' -require 'rack/content_length' - -module Rack - module Handler - class LSWS - def self.run(app, options=nil) - while LSAPI.accept != nil - serve app - end - end - def self.serve(app) - app = Rack::ContentLength.new(app) - - env = ENV.to_hash - env.delete "HTTP_CONTENT_LENGTH" - env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" - env.update({"rack.version" => [1,0], - "rack.input" => StringIO.new($stdin.read.to_s), - "rack.errors" => $stderr, - "rack.multithread" => false, - "rack.multiprocess" => true, - "rack.run_once" => false, - "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" - }) - env["QUERY_STRING"] ||= "" - env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] - env["REQUEST_PATH"] ||= "/" - status, headers, body = app.call(env) - begin - send_headers status, headers - send_body body - ensure - body.close if body.respond_to? :close - end - end - def self.send_headers(status, headers) - print "Status: #{status}\r\n" - headers.each { |k, vs| - vs.split("\n").each { |v| - print "#{k}: #{v}\r\n" - } - } - print "\r\n" - STDOUT.flush - end - def self.send_body(body) - body.each { |part| - print part - STDOUT.flush - } - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/mongrel.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/mongrel.rb deleted file mode 100644 index 3a5ef32d4b..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/mongrel.rb +++ /dev/null @@ -1,84 +0,0 @@ -require 'mongrel' -require 'stringio' -require 'rack/content_length' -require 'rack/chunked' - -module Rack - module Handler - class Mongrel < ::Mongrel::HttpHandler - def self.run(app, options={}) - server = ::Mongrel::HttpServer.new(options[:Host] || '0.0.0.0', - options[:Port] || 8080) - # Acts like Rack::URLMap, utilizing Mongrel's own path finding methods. - # Use is similar to #run, replacing the app argument with a hash of - # { path=>app, ... } or an instance of Rack::URLMap. - if options[:map] - if app.is_a? Hash - app.each do |path, appl| - path = '/'+path unless path[0] == ?/ - server.register(path, Rack::Handler::Mongrel.new(appl)) - end - elsif app.is_a? URLMap - app.instance_variable_get(:@mapping).each do |(host, path, appl)| - next if !host.nil? && !options[:Host].nil? && options[:Host] != host - path = '/'+path unless path[0] == ?/ - server.register(path, Rack::Handler::Mongrel.new(appl)) - end - else - raise ArgumentError, "first argument should be a Hash or URLMap" - end - else - server.register('/', Rack::Handler::Mongrel.new(app)) - end - yield server if block_given? - server.run.join - end - - def initialize(app) - @app = Rack::Chunked.new(Rack::ContentLength.new(app)) - end - - def process(request, response) - env = {}.replace(request.params) - env.delete "HTTP_CONTENT_TYPE" - env.delete "HTTP_CONTENT_LENGTH" - - env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" - - env.update({"rack.version" => [1,0], - "rack.input" => request.body || StringIO.new(""), - "rack.errors" => $stderr, - - "rack.multithread" => true, - "rack.multiprocess" => false, # ??? - "rack.run_once" => false, - - "rack.url_scheme" => "http", - }) - env["QUERY_STRING"] ||= "" - env.delete "PATH_INFO" if env["PATH_INFO"] == "" - - status, headers, body = @app.call(env) - - begin - response.status = status.to_i - response.send_status(nil) - - headers.each { |k, vs| - vs.split("\n").each { |v| - response.header[k] = v - } - } - response.send_header - - body.each { |part| - response.write part - response.socket.flush - } - ensure - body.close if body.respond_to? :close - end - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/scgi.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/scgi.rb deleted file mode 100644 index 6c4932df95..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/scgi.rb +++ /dev/null @@ -1,59 +0,0 @@ -require 'scgi' -require 'stringio' -require 'rack/content_length' -require 'rack/chunked' - -module Rack - module Handler - class SCGI < ::SCGI::Processor - attr_accessor :app - - def self.run(app, options=nil) - new(options.merge(:app=>app, - :host=>options[:Host], - :port=>options[:Port], - :socket=>options[:Socket])).listen - end - - def initialize(settings = {}) - @app = Rack::Chunked.new(Rack::ContentLength.new(settings[:app])) - @log = Object.new - def @log.info(*args); end - def @log.error(*args); end - super(settings) - end - - def process_request(request, input_body, socket) - env = {}.replace(request) - env.delete "HTTP_CONTENT_TYPE" - env.delete "HTTP_CONTENT_LENGTH" - env["REQUEST_PATH"], env["QUERY_STRING"] = env["REQUEST_URI"].split('?', 2) - env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] - env["PATH_INFO"] = env["REQUEST_PATH"] - env["QUERY_STRING"] ||= "" - env["SCRIPT_NAME"] = "" - env.update({"rack.version" => [1,0], - "rack.input" => StringIO.new(input_body), - "rack.errors" => $stderr, - - "rack.multithread" => true, - "rack.multiprocess" => true, - "rack.run_once" => false, - - "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http" - }) - status, headers, body = app.call(env) - begin - socket.write("Status: #{status}\r\n") - headers.each do |k, vs| - vs.split("\n").each { |v| socket.write("#{k}: #{v}\r\n")} - end - socket.write("\r\n") - body.each {|s| socket.write(s)} - ensure - body.close if body.respond_to? :close - end - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/swiftiplied_mongrel.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/swiftiplied_mongrel.rb deleted file mode 100644 index 4bafd0b953..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/swiftiplied_mongrel.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'swiftcore/swiftiplied_mongrel' - -module Rack - module Handler - class SwiftipliedMongrel < Handler::Mongrel - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/thin.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/thin.rb deleted file mode 100644 index 3d4fedff75..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/thin.rb +++ /dev/null @@ -1,18 +0,0 @@ -require "thin" -require "rack/content_length" -require "rack/chunked" - -module Rack - module Handler - class Thin - def self.run(app, options={}) - app = Rack::Chunked.new(Rack::ContentLength.new(app)) - server = ::Thin::Server.new(options[:Host] || '0.0.0.0', - options[:Port] || 8080, - app) - yield server if block_given? - server.start - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/webrick.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/webrick.rb deleted file mode 100644 index 2bdc83a9ff..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/webrick.rb +++ /dev/null @@ -1,67 +0,0 @@ -require 'webrick' -require 'stringio' -require 'rack/content_length' - -module Rack - module Handler - class WEBrick < ::WEBrick::HTTPServlet::AbstractServlet - def self.run(app, options={}) - server = ::WEBrick::HTTPServer.new(options) - server.mount "/", Rack::Handler::WEBrick, app - trap(:INT) { server.shutdown } - yield server if block_given? - server.start - end - - def initialize(server, app) - super server - @app = Rack::ContentLength.new(app) - end - - def service(req, res) - env = req.meta_vars - env.delete_if { |k, v| v.nil? } - - env.update({"rack.version" => [1,0], - "rack.input" => StringIO.new(req.body.to_s), - "rack.errors" => $stderr, - - "rack.multithread" => true, - "rack.multiprocess" => false, - "rack.run_once" => false, - - "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" - }) - - env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] - env["QUERY_STRING"] ||= "" - env["REQUEST_PATH"] ||= "/" - if env["PATH_INFO"] == "" - env.delete "PATH_INFO" - else - path, n = req.request_uri.path, env["SCRIPT_NAME"].length - env["PATH_INFO"] = path[n, path.length-n] - end - - status, headers, body = @app.call(env) - begin - res.status = status.to_i - headers.each { |k, vs| - if k.downcase == "set-cookie" - res.cookies.concat vs.split("\n") - else - vs.split("\n").each { |v| - res[k] = v - } - end - } - body.each { |part| - res.body << part - } - ensure - body.close if body.respond_to? :close - end - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/head.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/head.rb deleted file mode 100644 index deab822a99..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/head.rb +++ /dev/null @@ -1,19 +0,0 @@ -module Rack - -class Head - def initialize(app) - @app = app - end - - def call(env) - status, headers, body = @app.call(env) - - if env["REQUEST_METHOD"] == "HEAD" - [status, headers, []] - else - [status, headers, body] - end - end -end - -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lint.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lint.rb deleted file mode 100644 index bf2e9787a1..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lint.rb +++ /dev/null @@ -1,537 +0,0 @@ -require 'rack/utils' - -module Rack - # Rack::Lint validates your application and the requests and - # responses according to the Rack spec. - - class Lint - def initialize(app) - @app = app - end - - # :stopdoc: - - class LintError < RuntimeError; end - module Assertion - def assert(message, &block) - unless block.call - raise LintError, message - end - end - end - include Assertion - - ## This specification aims to formalize the Rack protocol. You - ## can (and should) use Rack::Lint to enforce it. - ## - ## When you develop middleware, be sure to add a Lint before and - ## after to catch all mistakes. - - ## = Rack applications - - ## A Rack application is an Ruby object (not a class) that - ## responds to +call+. - def call(env=nil) - dup._call(env) - end - - def _call(env) - ## It takes exactly one argument, the *environment* - assert("No env given") { env } - check_env env - - env['rack.input'] = InputWrapper.new(env['rack.input']) - env['rack.errors'] = ErrorWrapper.new(env['rack.errors']) - - ## and returns an Array of exactly three values: - status, headers, @body = @app.call(env) - ## The *status*, - check_status status - ## the *headers*, - check_headers headers - ## and the *body*. - check_content_type status, headers - check_content_length status, headers, env - [status, headers, self] - end - - ## == The Environment - def check_env(env) - ## The environment must be an true instance of Hash (no - ## subclassing allowed) that includes CGI-like headers. - ## The application is free to modify the environment. - assert("env #{env.inspect} is not a Hash, but #{env.class}") { - env.instance_of? Hash - } - - ## - ## The environment is required to include these variables - ## (adopted from PEP333), except when they'd be empty, but see - ## below. - - ## REQUEST_METHOD:: The HTTP request method, such as - ## "GET" or "POST". This cannot ever - ## be an empty string, and so is - ## always required. - - ## SCRIPT_NAME:: The initial portion of the request - ## URL's "path" that corresponds to the - ## application object, so that the - ## application knows its virtual - ## "location". This may be an empty - ## string, if the application corresponds - ## to the "root" of the server. - - ## PATH_INFO:: The remainder of the request URL's - ## "path", designating the virtual - ## "location" of the request's target - ## within the application. This may be an - ## empty string, if the request URL targets - ## the application root and does not have a - ## trailing slash. This value may be - ## percent-encoded when I originating from - ## a URL. - - ## QUERY_STRING:: The portion of the request URL that - ## follows the ?, if any. May be - ## empty, but is always required! - - ## SERVER_NAME, SERVER_PORT:: When combined with SCRIPT_NAME and PATH_INFO, these variables can be used to complete the URL. Note, however, that HTTP_HOST, if present, should be used in preference to SERVER_NAME for reconstructing the request URL. SERVER_NAME and SERVER_PORT can never be empty strings, and so are always required. - - ## HTTP_ Variables:: Variables corresponding to the - ## client-supplied HTTP request - ## headers (i.e., variables whose - ## names begin with HTTP_). The - ## presence or absence of these - ## variables should correspond with - ## the presence or absence of the - ## appropriate HTTP header in the - ## request. - - ## In addition to this, the Rack environment must include these - ## Rack-specific variables: - - ## rack.version:: The Array [1,0], representing this version of Rack. - ## rack.url_scheme:: +http+ or +https+, depending on the request URL. - ## rack.input:: See below, the input stream. - ## rack.errors:: See below, the error stream. - ## rack.multithread:: true if the application object may be simultaneously invoked by another thread in the same process, false otherwise. - ## rack.multiprocess:: true if an equivalent application object may be simultaneously invoked by another process, false otherwise. - ## rack.run_once:: true if the server expects (but does not guarantee!) that the application will only be invoked this one time during the life of its containing process. Normally, this will only be true for a server based on CGI (or something similar). - ## - - ## Additional environment specifications have approved to - ## standardized middleware APIs. None of these are required to - ## be implemented by the server. - - ## rack.session:: A hash like interface for storing request session data. - ## The store must implement: - if session = env['rack.session'] - ## store(key, value) (aliased as []=); - assert("session #{session.inspect} must respond to store and []=") { - session.respond_to?(:store) && session.respond_to?(:[]=) - } - - ## fetch(key, default = nil) (aliased as []); - assert("session #{session.inspect} must respond to fetch and []") { - session.respond_to?(:fetch) && session.respond_to?(:[]) - } - - ## delete(key); - assert("session #{session.inspect} must respond to delete") { - session.respond_to?(:delete) - } - - ## clear; - assert("session #{session.inspect} must respond to clear") { - session.respond_to?(:clear) - } - end - - ## The server or the application can store their own data in the - ## environment, too. The keys must contain at least one dot, - ## and should be prefixed uniquely. The prefix rack. - ## is reserved for use with the Rack core distribution and other - ## accepted specifications and must not be used otherwise. - ## - - %w[REQUEST_METHOD SERVER_NAME SERVER_PORT - QUERY_STRING - rack.version rack.input rack.errors - rack.multithread rack.multiprocess rack.run_once].each { |header| - assert("env missing required key #{header}") { env.include? header } - } - - ## The environment must not contain the keys - ## HTTP_CONTENT_TYPE or HTTP_CONTENT_LENGTH - ## (use the versions without HTTP_). - %w[HTTP_CONTENT_TYPE HTTP_CONTENT_LENGTH].each { |header| - assert("env contains #{header}, must use #{header[5,-1]}") { - not env.include? header - } - } - - ## The CGI keys (named without a period) must have String values. - env.each { |key, value| - next if key.include? "." # Skip extensions - assert("env variable #{key} has non-string value #{value.inspect}") { - value.instance_of? String - } - } - - ## - ## There are the following restrictions: - - ## * rack.version must be an array of Integers. - assert("rack.version must be an Array, was #{env["rack.version"].class}") { - env["rack.version"].instance_of? Array - } - ## * rack.url_scheme must either be +http+ or +https+. - assert("rack.url_scheme unknown: #{env["rack.url_scheme"].inspect}") { - %w[http https].include? env["rack.url_scheme"] - } - - ## * There must be a valid input stream in rack.input. - check_input env["rack.input"] - ## * There must be a valid error stream in rack.errors. - check_error env["rack.errors"] - - ## * The REQUEST_METHOD must be a valid token. - assert("REQUEST_METHOD unknown: #{env["REQUEST_METHOD"]}") { - env["REQUEST_METHOD"] =~ /\A[0-9A-Za-z!\#$%&'*+.^_`|~-]+\z/ - } - - ## * The SCRIPT_NAME, if non-empty, must start with / - assert("SCRIPT_NAME must start with /") { - !env.include?("SCRIPT_NAME") || - env["SCRIPT_NAME"] == "" || - env["SCRIPT_NAME"] =~ /\A\// - } - ## * The PATH_INFO, if non-empty, must start with / - assert("PATH_INFO must start with /") { - !env.include?("PATH_INFO") || - env["PATH_INFO"] == "" || - env["PATH_INFO"] =~ /\A\// - } - ## * The CONTENT_LENGTH, if given, must consist of digits only. - assert("Invalid CONTENT_LENGTH: #{env["CONTENT_LENGTH"]}") { - !env.include?("CONTENT_LENGTH") || env["CONTENT_LENGTH"] =~ /\A\d+\z/ - } - - ## * One of SCRIPT_NAME or PATH_INFO must be - ## set. PATH_INFO should be / if - ## SCRIPT_NAME is empty. - assert("One of SCRIPT_NAME or PATH_INFO must be set (make PATH_INFO '/' if SCRIPT_NAME is empty)") { - env["SCRIPT_NAME"] || env["PATH_INFO"] - } - ## SCRIPT_NAME never should be /, but instead be empty. - assert("SCRIPT_NAME cannot be '/', make it '' and PATH_INFO '/'") { - env["SCRIPT_NAME"] != "/" - } - end - - ## === The Input Stream - ## - ## The input stream is an IO-like object which contains the raw HTTP - ## POST data. If it is a file then it must be opened in binary mode. - def check_input(input) - ## The input stream must respond to +gets+, +each+, +read+ and +rewind+. - [:gets, :each, :read, :rewind].each { |method| - assert("rack.input #{input} does not respond to ##{method}") { - input.respond_to? method - } - } - end - - class InputWrapper - include Assertion - - def initialize(input) - @input = input - end - - def size - @input.size - end - - ## * +gets+ must be called without arguments and return a string, - ## or +nil+ on EOF. - def gets(*args) - assert("rack.input#gets called with arguments") { args.size == 0 } - v = @input.gets - assert("rack.input#gets didn't return a String") { - v.nil? or v.instance_of? String - } - v - end - - ## * +read+ behaves like IO#read. Its signature is read([length, [buffer]]). - ## If given, +length+ must be an non-negative Integer (>= 0) or +nil+, and +buffer+ must - ## be a String and may not be nil. If +length+ is given and not nil, then this method - ## reads at most +length+ bytes from the input stream. If +length+ is not given or nil, - ## then this method reads all data until EOF. - ## When EOF is reached, this method returns nil if +length+ is given and not nil, or "" - ## if +length+ is not given or is nil. - ## If +buffer+ is given, then the read data will be placed into +buffer+ instead of a - ## newly created String object. - def read(*args) - assert("rack.input#read called with too many arguments") { - args.size <= 2 - } - if args.size >= 1 - assert("rack.input#read called with non-integer and non-nil length") { - args.first.kind_of?(Integer) || args.first.nil? - } - assert("rack.input#read called with a negative length") { - args.first.nil? || args.first >= 0 - } - end - if args.size >= 2 - assert("rack.input#read called with non-String buffer") { - args[1].kind_of?(String) - } - end - - v = @input.read(*args) - - assert("rack.input#read didn't return nil or a String") { - v.nil? or v.instance_of? String - } - if args[0].nil? - assert("rack.input#read(nil) returned nil on EOF") { - !v.nil? - } - end - - v - end - - ## * +each+ must be called without arguments and only yield Strings. - def each(*args) - assert("rack.input#each called with arguments") { args.size == 0 } - @input.each { |line| - assert("rack.input#each didn't yield a String") { - line.instance_of? String - } - yield line - } - end - - ## * +rewind+ must be called without arguments. It rewinds the input - ## stream back to the beginning. It must not raise Errno::ESPIPE: - ## that is, it may not be a pipe or a socket. Therefore, handler - ## developers must buffer the input data into some rewindable object - ## if the underlying input stream is not rewindable. - def rewind(*args) - assert("rack.input#rewind called with arguments") { args.size == 0 } - assert("rack.input#rewind raised Errno::ESPIPE") { - begin - @input.rewind - true - rescue Errno::ESPIPE - false - end - } - end - - ## * +close+ must never be called on the input stream. - def close(*args) - assert("rack.input#close must not be called") { false } - end - end - - ## === The Error Stream - def check_error(error) - ## The error stream must respond to +puts+, +write+ and +flush+. - [:puts, :write, :flush].each { |method| - assert("rack.error #{error} does not respond to ##{method}") { - error.respond_to? method - } - } - end - - class ErrorWrapper - include Assertion - - def initialize(error) - @error = error - end - - ## * +puts+ must be called with a single argument that responds to +to_s+. - def puts(str) - @error.puts str - end - - ## * +write+ must be called with a single argument that is a String. - def write(str) - assert("rack.errors#write not called with a String") { str.instance_of? String } - @error.write str - end - - ## * +flush+ must be called without arguments and must be called - ## in order to make the error appear for sure. - def flush - @error.flush - end - - ## * +close+ must never be called on the error stream. - def close(*args) - assert("rack.errors#close must not be called") { false } - end - end - - ## == The Response - - ## === The Status - def check_status(status) - ## This is an HTTP status. When parsed as integer (+to_i+), it must be - ## greater than or equal to 100. - assert("Status must be >=100 seen as integer") { status.to_i >= 100 } - end - - ## === The Headers - def check_headers(header) - ## The header must respond to +each+, and yield values of key and value. - assert("headers object should respond to #each, but doesn't (got #{header.class} as headers)") { - header.respond_to? :each - } - header.each { |key, value| - ## The header keys must be Strings. - assert("header key must be a string, was #{key.class}") { - key.instance_of? String - } - ## The header must not contain a +Status+ key, - assert("header must not contain Status") { key.downcase != "status" } - ## contain keys with : or newlines in their name, - assert("header names must not contain : or \\n") { key !~ /[:\n]/ } - ## contain keys names that end in - or _, - assert("header names must not end in - or _") { key !~ /[-_]\z/ } - ## but only contain keys that consist of - ## letters, digits, _ or - and start with a letter. - assert("invalid header name: #{key}") { key =~ /\A[a-zA-Z][a-zA-Z0-9_-]*\z/ } - - ## The values of the header must be Strings, - assert("a header value must be a String, but the value of " + - "'#{key}' is a #{value.class}") { value.kind_of? String } - ## consisting of lines (for multiple header values, e.g. multiple - ## Set-Cookie values) seperated by "\n". - value.split("\n").each { |item| - ## The lines must not contain characters below 037. - assert("invalid header value #{key}: #{item.inspect}") { - item !~ /[\000-\037]/ - } - } - } - end - - ## === The Content-Type - def check_content_type(status, headers) - headers.each { |key, value| - ## There must be a Content-Type, except when the - ## +Status+ is 1xx, 204 or 304, in which case there must be none - ## given. - if key.downcase == "content-type" - assert("Content-Type header found in #{status} response, not allowed") { - not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i - } - return - end - } - assert("No Content-Type header found") { - Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i - } - end - - ## === The Content-Length - def check_content_length(status, headers, env) - headers.each { |key, value| - if key.downcase == 'content-length' - ## There must not be a Content-Length header when the - ## +Status+ is 1xx, 204 or 304. - assert("Content-Length header found in #{status} response, not allowed") { - not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i - } - - bytes = 0 - string_body = true - - if @body.respond_to?(:to_ary) - @body.each { |part| - unless part.kind_of?(String) - string_body = false - break - end - - bytes += Rack::Utils.bytesize(part) - } - - if env["REQUEST_METHOD"] == "HEAD" - assert("Response body was given for HEAD request, but should be empty") { - bytes == 0 - } - else - if string_body - assert("Content-Length header was #{value}, but should be #{bytes}") { - value == bytes.to_s - } - end - end - end - - return - end - } - end - - ## === The Body - def each - @closed = false - ## The Body must respond to +each+ - @body.each { |part| - ## and must only yield String values. - assert("Body yielded non-string value #{part.inspect}") { - part.instance_of? String - } - yield part - } - ## - ## The Body itself should not be an instance of String, as this will - ## break in Ruby 1.9. - ## - ## If the Body responds to +close+, it will be called after iteration. - # XXX howto: assert("Body has not been closed") { @closed } - - - ## - ## If the Body responds to +to_path+, it must return a String - ## identifying the location of a file whose contents are identical - ## to that produced by calling +each+; this may be used by the - ## server as an alternative, possibly more efficient way to - ## transport the response. - - if @body.respond_to?(:to_path) - assert("The file identified by body.to_path does not exist") { - ::File.exist? @body.to_path - } - end - - ## - ## The Body commonly is an Array of Strings, the application - ## instance itself, or a File-like object. - end - - def close - @closed = true - @body.close if @body.respond_to?(:close) - end - - # :startdoc: - - end -end - -## == Thanks -## Some parts of this specification are adopted from PEP333: Python -## Web Server Gateway Interface -## v1.0 (http://www.python.org/dev/peps/pep-0333/). I'd like to thank -## everyone involved in that effort. diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lobster.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lobster.rb deleted file mode 100644 index f63f419a49..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lobster.rb +++ /dev/null @@ -1,65 +0,0 @@ -require 'zlib' - -require 'rack/request' -require 'rack/response' - -module Rack - # Paste has a Pony, Rack has a Lobster! - class Lobster - LobsterString = Zlib::Inflate.inflate("eJx9kEEOwyAMBO99xd7MAcytUhPlJyj2 - P6jy9i4k9EQyGAnBarEXeCBqSkntNXsi/ZCvC48zGQoZKikGrFMZvgS5ZHd+aGWVuWwhVF0 - t1drVmiR42HcWNz5w3QanT+2gIvTVCiE1lm1Y0eU4JGmIIbaKwextKn8rvW+p5PIwFl8ZWJ - I8jyiTlhTcYXkekJAzTyYN6E08A+dk8voBkAVTJQ==".delete("\n ").unpack("m*")[0]) - - LambdaLobster = lambda { |env| - if env["QUERY_STRING"].include?("flip") - lobster = LobsterString.split("\n"). - map { |line| line.ljust(42).reverse }. - join("\n") - href = "?" - else - lobster = LobsterString - href = "?flip" - end - - content = ["Lobstericious!", - "
", lobster, "
", - "flip!"] - length = content.inject(0) { |a,e| a+e.size }.to_s - [200, {"Content-Type" => "text/html", "Content-Length" => length}, content] - } - - def call(env) - req = Request.new(env) - if req.GET["flip"] == "left" - lobster = LobsterString.split("\n"). - map { |line| line.ljust(42).reverse }. - join("\n") - href = "?flip=right" - elsif req.GET["flip"] == "crash" - raise "Lobster crashed" - else - lobster = LobsterString - href = "?flip=left" - end - - res = Response.new - res.write "Lobstericious!" - res.write "
"
-      res.write lobster
-      res.write "
" - res.write "

flip!

" - res.write "

crash!

" - res.finish - end - - end -end - -if $0 == __FILE__ - require 'rack' - require 'rack/showexceptions' - Rack::Handler::WEBrick.run \ - Rack::ShowExceptions.new(Rack::Lint.new(Rack::Lobster.new)), - :Port => 9292 -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lock.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lock.rb deleted file mode 100644 index 93238528c4..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lock.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Rack - class Lock - FLAG = 'rack.multithread'.freeze - - def initialize(app, lock = Mutex.new) - @app, @lock = app, lock - end - - def call(env) - old, env[FLAG] = env[FLAG], false - @lock.synchronize { @app.call(env) } - ensure - env[FLAG] = old - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/methodoverride.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/methodoverride.rb deleted file mode 100644 index 0eed29f471..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/methodoverride.rb +++ /dev/null @@ -1,27 +0,0 @@ -module Rack - class MethodOverride - HTTP_METHODS = %w(GET HEAD PUT POST DELETE OPTIONS) - - METHOD_OVERRIDE_PARAM_KEY = "_method".freeze - HTTP_METHOD_OVERRIDE_HEADER = "HTTP_X_HTTP_METHOD_OVERRIDE".freeze - - def initialize(app) - @app = app - end - - def call(env) - if env["REQUEST_METHOD"] == "POST" - req = Request.new(env) - method = req.POST[METHOD_OVERRIDE_PARAM_KEY] || - env[HTTP_METHOD_OVERRIDE_HEADER] - method = method.to_s.upcase - if HTTP_METHODS.include?(method) - env["rack.methodoverride.original_method"] = env["REQUEST_METHOD"] - env["REQUEST_METHOD"] = method - end - end - - @app.call(env) - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mime.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mime.rb deleted file mode 100644 index 5a6a73a97b..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mime.rb +++ /dev/null @@ -1,204 +0,0 @@ -module Rack - module Mime - # Returns String with mime type if found, otherwise use +fallback+. - # +ext+ should be filename extension in the '.ext' format that - # File.extname(file) returns. - # +fallback+ may be any object - # - # Also see the documentation for MIME_TYPES - # - # Usage: - # Rack::Mime.mime_type('.foo') - # - # This is a shortcut for: - # Rack::Mime::MIME_TYPES.fetch('.foo', 'application/octet-stream') - - def mime_type(ext, fallback='application/octet-stream') - MIME_TYPES.fetch(ext, fallback) - end - module_function :mime_type - - # List of most common mime-types, selected various sources - # according to their usefulness in a webserving scope for Ruby - # users. - # - # To amend this list with your local mime.types list you can use: - # - # require 'webrick/httputils' - # list = WEBrick::HTTPUtils.load_mime_types('/etc/mime.types') - # Rack::Mime::MIME_TYPES.merge!(list) - # - # To add the list mongrel provides, use: - # - # require 'mongrel/handlers' - # Rack::Mime::MIME_TYPES.merge!(Mongrel::DirHandler::MIME_TYPES) - - MIME_TYPES = { - ".3gp" => "video/3gpp", - ".a" => "application/octet-stream", - ".ai" => "application/postscript", - ".aif" => "audio/x-aiff", - ".aiff" => "audio/x-aiff", - ".asc" => "application/pgp-signature", - ".asf" => "video/x-ms-asf", - ".asm" => "text/x-asm", - ".asx" => "video/x-ms-asf", - ".atom" => "application/atom+xml", - ".au" => "audio/basic", - ".avi" => "video/x-msvideo", - ".bat" => "application/x-msdownload", - ".bin" => "application/octet-stream", - ".bmp" => "image/bmp", - ".bz2" => "application/x-bzip2", - ".c" => "text/x-c", - ".cab" => "application/vnd.ms-cab-compressed", - ".cc" => "text/x-c", - ".chm" => "application/vnd.ms-htmlhelp", - ".class" => "application/octet-stream", - ".com" => "application/x-msdownload", - ".conf" => "text/plain", - ".cpp" => "text/x-c", - ".crt" => "application/x-x509-ca-cert", - ".css" => "text/css", - ".csv" => "text/csv", - ".cxx" => "text/x-c", - ".deb" => "application/x-debian-package", - ".der" => "application/x-x509-ca-cert", - ".diff" => "text/x-diff", - ".djv" => "image/vnd.djvu", - ".djvu" => "image/vnd.djvu", - ".dll" => "application/x-msdownload", - ".dmg" => "application/octet-stream", - ".doc" => "application/msword", - ".dot" => "application/msword", - ".dtd" => "application/xml-dtd", - ".dvi" => "application/x-dvi", - ".ear" => "application/java-archive", - ".eml" => "message/rfc822", - ".eps" => "application/postscript", - ".exe" => "application/x-msdownload", - ".f" => "text/x-fortran", - ".f77" => "text/x-fortran", - ".f90" => "text/x-fortran", - ".flv" => "video/x-flv", - ".for" => "text/x-fortran", - ".gem" => "application/octet-stream", - ".gemspec" => "text/x-script.ruby", - ".gif" => "image/gif", - ".gz" => "application/x-gzip", - ".h" => "text/x-c", - ".hh" => "text/x-c", - ".htm" => "text/html", - ".html" => "text/html", - ".ico" => "image/vnd.microsoft.icon", - ".ics" => "text/calendar", - ".ifb" => "text/calendar", - ".iso" => "application/octet-stream", - ".jar" => "application/java-archive", - ".java" => "text/x-java-source", - ".jnlp" => "application/x-java-jnlp-file", - ".jpeg" => "image/jpeg", - ".jpg" => "image/jpeg", - ".js" => "application/javascript", - ".json" => "application/json", - ".log" => "text/plain", - ".m3u" => "audio/x-mpegurl", - ".m4v" => "video/mp4", - ".man" => "text/troff", - ".mathml" => "application/mathml+xml", - ".mbox" => "application/mbox", - ".mdoc" => "text/troff", - ".me" => "text/troff", - ".mid" => "audio/midi", - ".midi" => "audio/midi", - ".mime" => "message/rfc822", - ".mml" => "application/mathml+xml", - ".mng" => "video/x-mng", - ".mov" => "video/quicktime", - ".mp3" => "audio/mpeg", - ".mp4" => "video/mp4", - ".mp4v" => "video/mp4", - ".mpeg" => "video/mpeg", - ".mpg" => "video/mpeg", - ".ms" => "text/troff", - ".msi" => "application/x-msdownload", - ".odp" => "application/vnd.oasis.opendocument.presentation", - ".ods" => "application/vnd.oasis.opendocument.spreadsheet", - ".odt" => "application/vnd.oasis.opendocument.text", - ".ogg" => "application/ogg", - ".p" => "text/x-pascal", - ".pas" => "text/x-pascal", - ".pbm" => "image/x-portable-bitmap", - ".pdf" => "application/pdf", - ".pem" => "application/x-x509-ca-cert", - ".pgm" => "image/x-portable-graymap", - ".pgp" => "application/pgp-encrypted", - ".pkg" => "application/octet-stream", - ".pl" => "text/x-script.perl", - ".pm" => "text/x-script.perl-module", - ".png" => "image/png", - ".pnm" => "image/x-portable-anymap", - ".ppm" => "image/x-portable-pixmap", - ".pps" => "application/vnd.ms-powerpoint", - ".ppt" => "application/vnd.ms-powerpoint", - ".ps" => "application/postscript", - ".psd" => "image/vnd.adobe.photoshop", - ".py" => "text/x-script.python", - ".qt" => "video/quicktime", - ".ra" => "audio/x-pn-realaudio", - ".rake" => "text/x-script.ruby", - ".ram" => "audio/x-pn-realaudio", - ".rar" => "application/x-rar-compressed", - ".rb" => "text/x-script.ruby", - ".rdf" => "application/rdf+xml", - ".roff" => "text/troff", - ".rpm" => "application/x-redhat-package-manager", - ".rss" => "application/rss+xml", - ".rtf" => "application/rtf", - ".ru" => "text/x-script.ruby", - ".s" => "text/x-asm", - ".sgm" => "text/sgml", - ".sgml" => "text/sgml", - ".sh" => "application/x-sh", - ".sig" => "application/pgp-signature", - ".snd" => "audio/basic", - ".so" => "application/octet-stream", - ".svg" => "image/svg+xml", - ".svgz" => "image/svg+xml", - ".swf" => "application/x-shockwave-flash", - ".t" => "text/troff", - ".tar" => "application/x-tar", - ".tbz" => "application/x-bzip-compressed-tar", - ".tcl" => "application/x-tcl", - ".tex" => "application/x-tex", - ".texi" => "application/x-texinfo", - ".texinfo" => "application/x-texinfo", - ".text" => "text/plain", - ".tif" => "image/tiff", - ".tiff" => "image/tiff", - ".torrent" => "application/x-bittorrent", - ".tr" => "text/troff", - ".txt" => "text/plain", - ".vcf" => "text/x-vcard", - ".vcs" => "text/x-vcalendar", - ".vrml" => "model/vrml", - ".war" => "application/java-archive", - ".wav" => "audio/x-wav", - ".wma" => "audio/x-ms-wma", - ".wmv" => "video/x-ms-wmv", - ".wmx" => "video/x-ms-wmx", - ".wrl" => "model/vrml", - ".wsdl" => "application/wsdl+xml", - ".xbm" => "image/x-xbitmap", - ".xhtml" => "application/xhtml+xml", - ".xls" => "application/vnd.ms-excel", - ".xml" => "application/xml", - ".xpm" => "image/x-xpixmap", - ".xsl" => "application/xml", - ".xslt" => "application/xslt+xml", - ".yaml" => "text/yaml", - ".yml" => "text/yaml", - ".zip" => "application/zip", - } - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mock.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mock.rb deleted file mode 100644 index fdefb0340a..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mock.rb +++ /dev/null @@ -1,184 +0,0 @@ -require 'uri' -require 'stringio' -require 'rack/lint' -require 'rack/utils' -require 'rack/response' - -module Rack - # Rack::MockRequest helps testing your Rack application without - # actually using HTTP. - # - # After performing a request on a URL with get/post/put/delete, it - # returns a MockResponse with useful helper methods for effective - # testing. - # - # You can pass a hash with additional configuration to the - # get/post/put/delete. - # :input:: A String or IO-like to be used as rack.input. - # :fatal:: Raise a FatalWarning if the app writes to rack.errors. - # :lint:: If true, wrap the application in a Rack::Lint. - - class MockRequest - class FatalWarning < RuntimeError - end - - class FatalWarner - def puts(warning) - raise FatalWarning, warning - end - - def write(warning) - raise FatalWarning, warning - end - - def flush - end - - def string - "" - end - end - - DEFAULT_ENV = { - "rack.version" => [1,0], - "rack.input" => StringIO.new, - "rack.errors" => StringIO.new, - "rack.multithread" => true, - "rack.multiprocess" => true, - "rack.run_once" => false, - } - - def initialize(app) - @app = app - end - - def get(uri, opts={}) request("GET", uri, opts) end - def post(uri, opts={}) request("POST", uri, opts) end - def put(uri, opts={}) request("PUT", uri, opts) end - def delete(uri, opts={}) request("DELETE", uri, opts) end - - def request(method="GET", uri="", opts={}) - env = self.class.env_for(uri, opts.merge(:method => method)) - - if opts[:lint] - app = Rack::Lint.new(@app) - else - app = @app - end - - errors = env["rack.errors"] - MockResponse.new(*(app.call(env) + [errors])) - end - - # Return the Rack environment used for a request to +uri+. - def self.env_for(uri="", opts={}) - uri = URI(uri) - uri.path = "/#{uri.path}" unless uri.path[0] == ?/ - - env = DEFAULT_ENV.dup - - env["REQUEST_METHOD"] = opts[:method] ? opts[:method].to_s.upcase : "GET" - env["SERVER_NAME"] = uri.host || "example.org" - env["SERVER_PORT"] = uri.port ? uri.port.to_s : "80" - env["QUERY_STRING"] = uri.query.to_s - env["PATH_INFO"] = (!uri.path || uri.path.empty?) ? "/" : uri.path - env["rack.url_scheme"] = uri.scheme || "http" - env["HTTPS"] = env["rack.url_scheme"] == "https" ? "on" : "off" - - env["SCRIPT_NAME"] = opts[:script_name] || "" - - if opts[:fatal] - env["rack.errors"] = FatalWarner.new - else - env["rack.errors"] = StringIO.new - end - - if params = opts[:params] - if env["REQUEST_METHOD"] == "GET" - params = Utils.parse_nested_query(params) if params.is_a?(String) - params.update(Utils.parse_nested_query(env["QUERY_STRING"])) - env["QUERY_STRING"] = Utils.build_nested_query(params) - elsif !opts.has_key?(:input) - opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded" - if params.is_a?(Hash) - if data = Utils::Multipart.build_multipart(params) - opts[:input] = data - opts["CONTENT_LENGTH"] ||= data.length.to_s - opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Utils::Multipart::MULTIPART_BOUNDARY}" - else - opts[:input] = Utils.build_nested_query(params) - end - else - opts[:input] = params - end - end - end - - opts[:input] ||= "" - if String === opts[:input] - env["rack.input"] = StringIO.new(opts[:input]) - else - env["rack.input"] = opts[:input] - end - - env["CONTENT_LENGTH"] ||= env["rack.input"].length.to_s - - opts.each { |field, value| - env[field] = value if String === field - } - - env - end - end - - # Rack::MockResponse provides useful helpers for testing your apps. - # Usually, you don't create the MockResponse on your own, but use - # MockRequest. - - class MockResponse - def initialize(status, headers, body, errors=StringIO.new("")) - @status = status.to_i - - @original_headers = headers - @headers = Rack::Utils::HeaderHash.new - headers.each { |field, values| - @headers[field] = values - @headers[field] = "" if values.empty? - } - - @body = "" - body.each { |part| @body << part } - - @errors = errors.string if errors.respond_to?(:string) - end - - # Status - attr_reader :status - - # Headers - attr_reader :headers, :original_headers - - def [](field) - headers[field] - end - - - # Body - attr_reader :body - - def =~(other) - @body =~ other - end - - def match(other) - @body.match other - end - - - # Errors - attr_accessor :errors - - - include Response::Helpers - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/recursive.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/recursive.rb deleted file mode 100644 index bf8b965925..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/recursive.rb +++ /dev/null @@ -1,57 +0,0 @@ -require 'uri' - -module Rack - # Rack::ForwardRequest gets caught by Rack::Recursive and redirects - # the current request to the app at +url+. - # - # raise ForwardRequest.new("/not-found") - # - - class ForwardRequest < Exception - attr_reader :url, :env - - def initialize(url, env={}) - @url = URI(url) - @env = env - - @env["PATH_INFO"] = @url.path - @env["QUERY_STRING"] = @url.query if @url.query - @env["HTTP_HOST"] = @url.host if @url.host - @env["HTTP_PORT"] = @url.port if @url.port - @env["rack.url_scheme"] = @url.scheme if @url.scheme - - super "forwarding to #{url}" - end - end - - # Rack::Recursive allows applications called down the chain to - # include data from other applications (by using - # rack['rack.recursive.include'][...] or raise a - # ForwardRequest to redirect internally. - - class Recursive - def initialize(app) - @app = app - end - - def call(env) - @script_name = env["SCRIPT_NAME"] - @app.call(env.merge('rack.recursive.include' => method(:include))) - rescue ForwardRequest => req - call(env.merge(req.env)) - end - - def include(env, path) - unless path.index(@script_name) == 0 && (path[@script_name.size] == ?/ || - path[@script_name.size].nil?) - raise ArgumentError, "can only include below #{@script_name}, not #{path}" - end - - env = env.merge("PATH_INFO" => path, "SCRIPT_NAME" => @script_name, - "REQUEST_METHOD" => "GET", - "CONTENT_LENGTH" => "0", "CONTENT_TYPE" => "", - "rack.input" => StringIO.new("")) - @app.call(env) - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/reloader.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/reloader.rb deleted file mode 100644 index aa2f060be5..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/reloader.rb +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright (c) 2009 Michael Fellinger m.fellinger@gmail.com -# All files in this distribution are subject to the terms of the Ruby license. - -require 'pathname' - -module Rack - - # High performant source reloader - # - # This class acts as Rack middleware. - # - # What makes it especially suited for use in a production environment is that - # any file will only be checked once and there will only be made one system - # call stat(2). - # - # Please note that this will not reload files in the background, it does so - # only when actively called. - # - # It is performing a check/reload cycle at the start of every request, but - # also respects a cool down time, during which nothing will be done. - class Reloader - def initialize(app, cooldown = 10, backend = Stat) - @app = app - @cooldown = cooldown - @last = (Time.now - cooldown) - @cache = {} - @mtimes = {} - - extend backend - end - - def call(env) - if @cooldown and Time.now > @last + @cooldown - if Thread.list.size > 1 - Thread.exclusive{ reload! } - else - reload! - end - - @last = Time.now - end - - @app.call(env) - end - - def reload!(stderr = $stderr) - rotation do |file, mtime| - previous_mtime = @mtimes[file] ||= mtime - safe_load(file, mtime, stderr) if mtime > previous_mtime - end - end - - # A safe Kernel::load, issuing the hooks depending on the results - def safe_load(file, mtime, stderr = $stderr) - load(file) - stderr.puts "#{self.class}: reloaded `#{file}'" - file - rescue LoadError, SyntaxError => ex - stderr.puts ex - ensure - @mtimes[file] = mtime - end - - module Stat - def rotation - files = [$0, *$LOADED_FEATURES].uniq - paths = ['./', *$LOAD_PATH].uniq - - files.map{|file| - next if file =~ /\.(so|bundle)$/ # cannot reload compiled files - - found, stat = figure_path(file, paths) - next unless found and stat and mtime = stat.mtime - - @cache[file] = found - - yield(found, mtime) - }.compact - end - - # Takes a relative or absolute +file+ name, a couple possible +paths+ that - # the +file+ might reside in. Returns the full path and File::Stat for the - # path. - def figure_path(file, paths) - found = @cache[file] - found = file if !found and Pathname.new(file).absolute? - found, stat = safe_stat(found) - return found, stat if found - - paths.each do |possible_path| - path = ::File.join(possible_path, file) - found, stat = safe_stat(path) - return ::File.expand_path(found), stat if found - end - end - - def safe_stat(file) - return unless file - stat = ::File.stat(file) - return file, stat if stat.file? - rescue Errno::ENOENT, Errno::ENOTDIR - @cache.delete(file) and false - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/request.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/request.rb deleted file mode 100644 index 0bff7af038..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/request.rb +++ /dev/null @@ -1,254 +0,0 @@ -require 'rack/utils' - -module Rack - # Rack::Request provides a convenient interface to a Rack - # environment. It is stateless, the environment +env+ passed to the - # constructor will be directly modified. - # - # req = Rack::Request.new(env) - # req.post? - # req.params["data"] - # - # The environment hash passed will store a reference to the Request object - # instantiated so that it will only instantiate if an instance of the Request - # object doesn't already exist. - - class Request - # The environment of the request. - attr_reader :env - - def self.new(env, *args) - if self == Rack::Request - env["rack.request"] ||= super - else - super - end - end - - def initialize(env) - @env = env - end - - def body; @env["rack.input"] end - def scheme; @env["rack.url_scheme"] end - def script_name; @env["SCRIPT_NAME"].to_s end - def path_info; @env["PATH_INFO"].to_s end - def port; @env["SERVER_PORT"].to_i end - def request_method; @env["REQUEST_METHOD"] end - def query_string; @env["QUERY_STRING"].to_s end - def content_length; @env['CONTENT_LENGTH'] end - def content_type; @env['CONTENT_TYPE'] end - def session; @env['rack.session'] ||= {} end - def session_options; @env['rack.session.options'] ||= {} end - - # The media type (type/subtype) portion of the CONTENT_TYPE header - # without any media type parameters. e.g., when CONTENT_TYPE is - # "text/plain;charset=utf-8", the media-type is "text/plain". - # - # For more information on the use of media types in HTTP, see: - # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7 - def media_type - content_type && content_type.split(/\s*[;,]\s*/, 2).first.downcase - end - - # The media type parameters provided in CONTENT_TYPE as a Hash, or - # an empty Hash if no CONTENT_TYPE or media-type parameters were - # provided. e.g., when the CONTENT_TYPE is "text/plain;charset=utf-8", - # this method responds with the following Hash: - # { 'charset' => 'utf-8' } - def media_type_params - return {} if content_type.nil? - content_type.split(/\s*[;,]\s*/)[1..-1]. - collect { |s| s.split('=', 2) }. - inject({}) { |hash,(k,v)| hash[k.downcase] = v ; hash } - end - - # The character set of the request body if a "charset" media type - # parameter was given, or nil if no "charset" was specified. Note - # that, per RFC2616, text/* media types that specify no explicit - # charset are to be considered ISO-8859-1. - def content_charset - media_type_params['charset'] - end - - def host - # Remove port number. - (@env["HTTP_HOST"] || @env["SERVER_NAME"]).gsub(/:\d+\z/, '') - end - - def script_name=(s); @env["SCRIPT_NAME"] = s.to_s end - def path_info=(s); @env["PATH_INFO"] = s.to_s end - - def get?; request_method == "GET" end - def post?; request_method == "POST" end - def put?; request_method == "PUT" end - def delete?; request_method == "DELETE" end - def head?; request_method == "HEAD" end - - # The set of form-data media-types. Requests that do not indicate - # one of the media types presents in this list will not be eligible - # for form-data / param parsing. - FORM_DATA_MEDIA_TYPES = [ - nil, - 'application/x-www-form-urlencoded', - 'multipart/form-data' - ] - - # The set of media-types. Requests that do not indicate - # one of the media types presents in this list will not be eligible - # for param parsing like soap attachments or generic multiparts - PARSEABLE_DATA_MEDIA_TYPES = [ - 'multipart/related', - 'multipart/mixed' - ] - - # Determine whether the request body contains form-data by checking - # the request media_type against registered form-data media-types: - # "application/x-www-form-urlencoded" and "multipart/form-data". The - # list of form-data media types can be modified through the - # +FORM_DATA_MEDIA_TYPES+ array. - def form_data? - FORM_DATA_MEDIA_TYPES.include?(media_type) - end - - # Determine whether the request body contains data by checking - # the request media_type against registered parse-data media-types - def parseable_data? - PARSEABLE_DATA_MEDIA_TYPES.include?(media_type) - end - - # Returns the data recieved in the query string. - def GET - if @env["rack.request.query_string"] == query_string - @env["rack.request.query_hash"] - else - @env["rack.request.query_string"] = query_string - @env["rack.request.query_hash"] = - Utils.parse_nested_query(query_string) - end - end - - # Returns the data recieved in the request body. - # - # This method support both application/x-www-form-urlencoded and - # multipart/form-data. - def POST - if @env["rack.request.form_input"].eql? @env["rack.input"] - @env["rack.request.form_hash"] - elsif form_data? || parseable_data? - @env["rack.request.form_input"] = @env["rack.input"] - unless @env["rack.request.form_hash"] = - Utils::Multipart.parse_multipart(env) - form_vars = @env["rack.input"].read - - # Fix for Safari Ajax postings that always append \0 - form_vars.sub!(/\0\z/, '') - - @env["rack.request.form_vars"] = form_vars - @env["rack.request.form_hash"] = Utils.parse_nested_query(form_vars) - - @env["rack.input"].rewind - end - @env["rack.request.form_hash"] - else - {} - end - end - - # The union of GET and POST data. - def params - self.put? ? self.GET : self.GET.update(self.POST) - rescue EOFError => e - self.GET - end - - # shortcut for request.params[key] - def [](key) - params[key.to_s] - end - - # shortcut for request.params[key] = value - def []=(key, value) - params[key.to_s] = value - end - - # like Hash#values_at - def values_at(*keys) - keys.map{|key| params[key] } - end - - # the referer of the client or '/' - def referer - @env['HTTP_REFERER'] || '/' - end - alias referrer referer - - - def cookies - return {} unless @env["HTTP_COOKIE"] - - if @env["rack.request.cookie_string"] == @env["HTTP_COOKIE"] - @env["rack.request.cookie_hash"] - else - @env["rack.request.cookie_string"] = @env["HTTP_COOKIE"] - # According to RFC 2109: - # If multiple cookies satisfy the criteria above, they are ordered in - # the Cookie header such that those with more specific Path attributes - # precede those with less specific. Ordering with respect to other - # attributes (e.g., Domain) is unspecified. - @env["rack.request.cookie_hash"] = - Utils.parse_query(@env["rack.request.cookie_string"], ';,').inject({}) {|h,(k,v)| - h[k] = Array === v ? v.first : v - h - } - end - end - - def xhr? - @env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest" - end - - # Tries to return a remake of the original request URL as a string. - def url - url = scheme + "://" - url << host - - if scheme == "https" && port != 443 || - scheme == "http" && port != 80 - url << ":#{port}" - end - - url << fullpath - - url - end - - def path - script_name + path_info - end - - def fullpath - query_string.empty? ? path : "#{path}?#{query_string}" - end - - def accept_encoding - @env["HTTP_ACCEPT_ENCODING"].to_s.split(/,\s*/).map do |part| - m = /^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$/.match(part) # From WEBrick - - if m - [m[1], (m[2] || 1.0).to_f] - else - raise "Invalid value for Accept-Encoding: #{part.inspect}" - end - end - end - - def ip - if addr = @env['HTTP_X_FORWARDED_FOR'] - addr.split(',').last.strip - else - @env['REMOTE_ADDR'] - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/response.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/response.rb deleted file mode 100644 index 28b4d8302f..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/response.rb +++ /dev/null @@ -1,183 +0,0 @@ -require 'rack/request' -require 'rack/utils' - -module Rack - # Rack::Response provides a convenient interface to create a Rack - # response. - # - # It allows setting of headers and cookies, and provides useful - # defaults (a OK response containing HTML). - # - # You can use Response#write to iteratively generate your response, - # but note that this is buffered by Rack::Response until you call - # +finish+. +finish+ however can take a block inside which calls to - # +write+ are syncronous with the Rack response. - # - # Your application's +call+ should end returning Response#finish. - - class Response - attr_accessor :length - - def initialize(body=[], status=200, header={}, &block) - @status = status - @header = Utils::HeaderHash.new({"Content-Type" => "text/html"}. - merge(header)) - - @writer = lambda { |x| @body << x } - @block = nil - @length = 0 - - @body = [] - - if body.respond_to? :to_str - write body.to_str - elsif body.respond_to?(:each) - body.each { |part| - write part.to_s - } - else - raise TypeError, "stringable or iterable required" - end - - yield self if block_given? - end - - attr_reader :header - attr_accessor :status, :body - - def [](key) - header[key] - end - - def []=(key, value) - header[key] = value - end - - def set_cookie(key, value) - case value - when Hash - domain = "; domain=" + value[:domain] if value[:domain] - path = "; path=" + value[:path] if value[:path] - # According to RFC 2109, we need dashes here. - # N.B.: cgi.rb uses spaces... - expires = "; expires=" + value[:expires].clone.gmtime. - strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires] - secure = "; secure" if value[:secure] - httponly = "; HttpOnly" if value[:httponly] - value = value[:value] - end - value = [value] unless Array === value - cookie = Utils.escape(key) + "=" + - value.map { |v| Utils.escape v }.join("&") + - "#{domain}#{path}#{expires}#{secure}#{httponly}" - - case self["Set-Cookie"] - when Array - self["Set-Cookie"] << cookie - when String - self["Set-Cookie"] = [self["Set-Cookie"], cookie] - when nil - self["Set-Cookie"] = cookie - end - end - - def delete_cookie(key, value={}) - unless Array === self["Set-Cookie"] - self["Set-Cookie"] = [self["Set-Cookie"]].compact - end - - self["Set-Cookie"].reject! { |cookie| - cookie =~ /\A#{Utils.escape(key)}=/ - } - - set_cookie(key, - {:value => '', :path => nil, :domain => nil, - :expires => Time.at(0) }.merge(value)) - end - - def redirect(target, status=302) - self.status = status - self["Location"] = target - end - - def finish(&block) - @block = block - - if [204, 304].include?(status.to_i) - header.delete "Content-Type" - [status.to_i, header.to_hash, []] - else - [status.to_i, header.to_hash, self] - end - end - alias to_a finish # For *response - - def each(&callback) - @body.each(&callback) - @writer = callback - @block.call(self) if @block - end - - # Append to body and update Content-Length. - # - # NOTE: Do not mix #write and direct #body access! - # - def write(str) - s = str.to_s - @length += Rack::Utils.bytesize(s) - @writer.call s - - header["Content-Length"] = @length.to_s - str - end - - def close - body.close if body.respond_to?(:close) - end - - def empty? - @block == nil && @body.empty? - end - - alias headers header - - module Helpers - def invalid?; @status < 100 || @status >= 600; end - - def informational?; @status >= 100 && @status < 200; end - def successful?; @status >= 200 && @status < 300; end - def redirection?; @status >= 300 && @status < 400; end - def client_error?; @status >= 400 && @status < 500; end - def server_error?; @status >= 500 && @status < 600; end - - def ok?; @status == 200; end - def forbidden?; @status == 403; end - def not_found?; @status == 404; end - - def redirect?; [301, 302, 303, 307].include? @status; end - def empty?; [201, 204, 304].include? @status; end - - # Headers - attr_reader :headers, :original_headers - - def include?(header) - !!headers[header] - end - - def content_type - headers["Content-Type"] - end - - def content_length - cl = headers["Content-Length"] - cl ? cl.to_i : cl - end - - def location - headers["Location"] - end - end - - include Helpers - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/rewindable_input.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/rewindable_input.rb deleted file mode 100644 index 9e9b21ff99..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/rewindable_input.rb +++ /dev/null @@ -1,98 +0,0 @@ -require 'tempfile' - -module Rack - # Class which can make any IO object rewindable, including non-rewindable ones. It does - # this by buffering the data into a tempfile, which is rewindable. - # - # rack.input is required to be rewindable, so if your input stream IO is non-rewindable - # by nature (e.g. a pipe or a socket) then you can wrap it in an object of this class - # to easily make it rewindable. - # - # Don't forget to call #close when you're done. This frees up temporary resources that - # RewindableInput uses, though it does *not* close the original IO object. - class RewindableInput - def initialize(io) - @io = io - @rewindable_io = nil - @unlinked = false - end - - def gets - make_rewindable unless @rewindable_io - @rewindable_io.gets - end - - def read(*args) - make_rewindable unless @rewindable_io - @rewindable_io.read(*args) - end - - def each(&block) - make_rewindable unless @rewindable_io - @rewindable_io.each(&block) - end - - def rewind - make_rewindable unless @rewindable_io - @rewindable_io.rewind - end - - # Closes this RewindableInput object without closing the originally - # wrapped IO oject. Cleans up any temporary resources that this RewindableInput - # has created. - # - # This method may be called multiple times. It does nothing on subsequent calls. - def close - if @rewindable_io - if @unlinked - @rewindable_io.close - else - @rewindable_io.close! - end - @rewindable_io = nil - end - end - - private - - # Ruby's Tempfile class has a bug. Subclass it and fix it. - class Tempfile < ::Tempfile - def _close - @tmpfile.close if @tmpfile - @data[1] = nil if @data - @tmpfile = nil - end - end - - def make_rewindable - # Buffer all data into a tempfile. Since this tempfile is private to this - # RewindableInput object, we chmod it so that nobody else can read or write - # it. On POSIX filesystems we also unlink the file so that it doesn't - # even have a file entry on the filesystem anymore, though we can still - # access it because we have the file handle open. - @rewindable_io = Tempfile.new('RackRewindableInput') - @rewindable_io.chmod(0000) - if filesystem_has_posix_semantics? - @rewindable_io.unlink - @unlinked = true - end - - buffer = "" - while @io.read(1024 * 4, buffer) - entire_buffer_written_out = false - while !entire_buffer_written_out - written = @rewindable_io.write(buffer) - entire_buffer_written_out = written == buffer.size - if !entire_buffer_written_out - buffer.slice!(0 .. written - 1) - end - end - end - @rewindable_io.rewind - end - - def filesystem_has_posix_semantics? - RUBY_PLATFORM !~ /(mswin|mingw|cygwin|java)/ - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/abstract/id.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/abstract/id.rb deleted file mode 100644 index 218144c17f..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/abstract/id.rb +++ /dev/null @@ -1,142 +0,0 @@ -# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net -# bugrep: Andreas Zehnder - -require 'time' -require 'rack/request' -require 'rack/response' - -module Rack - - module Session - - module Abstract - - # ID sets up a basic framework for implementing an id based sessioning - # service. Cookies sent to the client for maintaining sessions will only - # contain an id reference. Only #get_session and #set_session are - # required to be overwritten. - # - # All parameters are optional. - # * :key determines the name of the cookie, by default it is - # 'rack.session' - # * :path, :domain, :expire_after, :secure, and :httponly set the related - # cookie options as by Rack::Response#add_cookie - # * :defer will not set a cookie in the response. - # * :renew (implementation dependent) will prompt the generation of a new - # session id, and migration of data to be referenced at the new id. If - # :defer is set, it will be overridden and the cookie will be set. - # * :sidbits sets the number of bits in length that a generated session - # id will be. - # - # These options can be set on a per request basis, at the location of - # env['rack.session.options']. Additionally the id of the session can be - # found within the options hash at the key :id. It is highly not - # recommended to change its value. - # - # Is Rack::Utils::Context compatible. - - class ID - DEFAULT_OPTIONS = { - :path => '/', - :domain => nil, - :expire_after => nil, - :secure => false, - :httponly => true, - :defer => false, - :renew => false, - :sidbits => 128 - } - - attr_reader :key, :default_options - def initialize(app, options={}) - @app = app - @key = options[:key] || "rack.session" - @default_options = self.class::DEFAULT_OPTIONS.merge(options) - end - - def call(env) - context(env) - end - - def context(env, app=@app) - load_session(env) - status, headers, body = app.call(env) - commit_session(env, status, headers, body) - end - - private - - # Generate a new session id using Ruby #rand. The size of the - # session id is controlled by the :sidbits option. - # Monkey patch this to use custom methods for session id generation. - - def generate_sid - "%0#{@default_options[:sidbits] / 4}x" % - rand(2**@default_options[:sidbits] - 1) - end - - # Extracts the session id from provided cookies and passes it and the - # environment to #get_session. It then sets the resulting session into - # 'rack.session', and places options and session metadata into - # 'rack.session.options'. - - def load_session(env) - request = Rack::Request.new(env) - session_id = request.cookies[@key] - - begin - session_id, session = get_session(env, session_id) - env['rack.session'] = session - rescue - env['rack.session'] = Hash.new - end - - env['rack.session.options'] = @default_options. - merge(:id => session_id) - end - - # Acquires the session from the environment and the session id from - # the session options and passes them to #set_session. If successful - # and the :defer option is not true, a cookie will be added to the - # response with the session's id. - - def commit_session(env, status, headers, body) - session = env['rack.session'] - options = env['rack.session.options'] - session_id = options[:id] - - if not session_id = set_session(env, session_id, session, options) - env["rack.errors"].puts("Warning! #{self.class.name} failed to save session. Content dropped.") - [status, headers, body] - elsif options[:defer] and not options[:renew] - env["rack.errors"].puts("Defering cookie for #{session_id}") if $VERBOSE - [status, headers, body] - else - cookie = Hash.new - cookie[:value] = session_id - cookie[:expires] = Time.now + options[:expire_after] unless options[:expire_after].nil? - response = Rack::Response.new(body, status, headers) - response.set_cookie(@key, cookie.merge(options)) - response.to_a - end - end - - # All thread safety and session retrival proceedures should occur here. - # Should return [session_id, session]. - # If nil is provided as the session id, generation of a new valid id - # should occur within. - - def get_session(env, sid) - raise '#get_session not implemented.' - end - - # All thread safety and session storage proceedures should occur here. - # Should return true or false dependant on whether or not the session - # was saved or not. - def set_session(env, sid, session, options) - raise '#set_session not implemented.' - end - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/cookie.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/cookie.rb deleted file mode 100644 index eace9bd0c6..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/cookie.rb +++ /dev/null @@ -1,91 +0,0 @@ -require 'openssl' -require 'rack/request' -require 'rack/response' - -module Rack - - module Session - - # Rack::Session::Cookie provides simple cookie based session management. - # The session is a Ruby Hash stored as base64 encoded marshalled data - # set to :key (default: rack.session). - # When the secret key is set, cookie data is checked for data integrity. - # - # Example: - # - # use Rack::Session::Cookie, :key => 'rack.session', - # :domain => 'foo.com', - # :path => '/', - # :expire_after => 2592000, - # :secret => 'change_me' - # - # All parameters are optional. - - class Cookie - - def initialize(app, options={}) - @app = app - @key = options[:key] || "rack.session" - @secret = options[:secret] - @default_options = {:domain => nil, - :path => "/", - :expire_after => nil}.merge(options) - end - - def call(env) - load_session(env) - status, headers, body = @app.call(env) - commit_session(env, status, headers, body) - end - - private - - def load_session(env) - request = Rack::Request.new(env) - session_data = request.cookies[@key] - - if @secret && session_data - session_data, digest = session_data.split("--") - session_data = nil unless digest == generate_hmac(session_data) - end - - begin - session_data = session_data.unpack("m*").first - session_data = Marshal.load(session_data) - env["rack.session"] = session_data - rescue - env["rack.session"] = Hash.new - end - - env["rack.session.options"] = @default_options.dup - end - - def commit_session(env, status, headers, body) - session_data = Marshal.dump(env["rack.session"]) - session_data = [session_data].pack("m*") - - if @secret - session_data = "#{session_data}--#{generate_hmac(session_data)}" - end - - if session_data.size > (4096 - @key.size) - env["rack.errors"].puts("Warning! Rack::Session::Cookie data size exceeds 4K. Content dropped.") - [status, headers, body] - else - options = env["rack.session.options"] - cookie = Hash.new - cookie[:value] = session_data - cookie[:expires] = Time.now + options[:expire_after] unless options[:expire_after].nil? - response = Rack::Response.new(body, status, headers) - response.set_cookie(@key, cookie.merge(options)) - response.to_a - end - end - - def generate_hmac(data) - OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, @secret, data) - end - - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/memcache.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/memcache.rb deleted file mode 100644 index 4a65cbf35d..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/memcache.rb +++ /dev/null @@ -1,109 +0,0 @@ -# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net - -require 'rack/session/abstract/id' -require 'memcache' - -module Rack - module Session - # Rack::Session::Memcache provides simple cookie based session management. - # Session data is stored in memcached. The corresponding session key is - # maintained in the cookie. - # You may treat Session::Memcache as you would Session::Pool with the - # following caveats. - # - # * Setting :expire_after to 0 would note to the Memcache server to hang - # onto the session data until it would drop it according to it's own - # specifications. However, the cookie sent to the client would expire - # immediately. - # - # Note that memcache does drop data before it may be listed to expire. For - # a full description of behaviour, please see memcache's documentation. - - class Memcache < Abstract::ID - attr_reader :mutex, :pool - DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge \ - :namespace => 'rack:session', - :memcache_server => 'localhost:11211' - - def initialize(app, options={}) - super - - @mutex = Mutex.new - @pool = MemCache. - new @default_options[:memcache_server], @default_options - raise 'No memcache servers' unless @pool.servers.any?{|s|s.alive?} - end - - def generate_sid - loop do - sid = super - break sid unless @pool.get(sid, true) - end - end - - def get_session(env, sid) - session = @pool.get(sid) if sid - @mutex.lock if env['rack.multithread'] - unless sid and session - env['rack.errors'].puts("Session '#{sid.inspect}' not found, initializing...") if $VERBOSE and not sid.nil? - session = {} - sid = generate_sid - ret = @pool.add sid, session - raise "Session collision on '#{sid.inspect}'" unless /^STORED/ =~ ret - end - session.instance_variable_set('@old', {}.merge(session)) - return [sid, session] - rescue MemCache::MemCacheError, Errno::ECONNREFUSED # MemCache server cannot be contacted - warn "#{self} is unable to find server." - warn $!.inspect - return [ nil, {} ] - ensure - @mutex.unlock if env['rack.multithread'] - end - - def set_session(env, session_id, new_session, options) - expiry = options[:expire_after] - expiry = expiry.nil? ? 0 : expiry + 1 - - @mutex.lock if env['rack.multithread'] - session = @pool.get(session_id) || {} - if options[:renew] or options[:drop] - @pool.delete session_id - return false if options[:drop] - session_id = generate_sid - @pool.add session_id, 0 # so we don't worry about cache miss on #set - end - old_session = new_session.instance_variable_get('@old') || {} - session = merge_sessions session_id, old_session, new_session, session - @pool.set session_id, session, expiry - return session_id - rescue MemCache::MemCacheError, Errno::ECONNREFUSED # MemCache server cannot be contacted - warn "#{self} is unable to find server." - warn $!.inspect - return false - ensure - @mutex.unlock if env['rack.multithread'] - end - - private - - def merge_sessions sid, old, new, cur=nil - cur ||= {} - unless Hash === old and Hash === new - warn 'Bad old or new sessions provided.' - return cur - end - - delete = old.keys - new.keys - warn "//@#{sid}: delete #{delete*','}" if $VERBOSE and not delete.empty? - delete.each{|k| cur.delete k } - - update = new.keys.select{|k| new[k] != old[k] } - warn "//@#{sid}: update #{update*','}" if $VERBOSE and not update.empty? - update.each{|k| cur[k] = new[k] } - - cur - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/pool.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/pool.rb deleted file mode 100644 index f6f87408bb..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/pool.rb +++ /dev/null @@ -1,100 +0,0 @@ -# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net -# THANKS: -# apeiros, for session id generation, expiry setup, and threadiness -# sergio, threadiness and bugreps - -require 'rack/session/abstract/id' -require 'thread' - -module Rack - module Session - # Rack::Session::Pool provides simple cookie based session management. - # Session data is stored in a hash held by @pool. - # In the context of a multithreaded environment, sessions being - # committed to the pool is done in a merging manner. - # - # The :drop option is available in rack.session.options if you with to - # explicitly remove the session from the session cache. - # - # Example: - # myapp = MyRackApp.new - # sessioned = Rack::Session::Pool.new(myapp, - # :domain => 'foo.com', - # :expire_after => 2592000 - # ) - # Rack::Handler::WEBrick.run sessioned - - class Pool < Abstract::ID - attr_reader :mutex, :pool - DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge :drop => false - - def initialize(app, options={}) - super - @pool = Hash.new - @mutex = Mutex.new - end - - def generate_sid - loop do - sid = super - break sid unless @pool.key? sid - end - end - - def get_session(env, sid) - session = @pool[sid] if sid - @mutex.lock if env['rack.multithread'] - unless sid and session - env['rack.errors'].puts("Session '#{sid.inspect}' not found, initializing...") if $VERBOSE and not sid.nil? - session = {} - sid = generate_sid - @pool.store sid, session - end - session.instance_variable_set('@old', {}.merge(session)) - return [sid, session] - ensure - @mutex.unlock if env['rack.multithread'] - end - - def set_session(env, session_id, new_session, options) - @mutex.lock if env['rack.multithread'] - session = @pool[session_id] - if options[:renew] or options[:drop] - @pool.delete session_id - return false if options[:drop] - session_id = generate_sid - @pool.store session_id, 0 - end - old_session = new_session.instance_variable_get('@old') || {} - session = merge_sessions session_id, old_session, new_session, session - @pool.store session_id, session - return session_id - rescue - warn "#{new_session.inspect} has been lost." - warn $!.inspect - ensure - @mutex.unlock if env['rack.multithread'] - end - - private - - def merge_sessions sid, old, new, cur=nil - cur ||= {} - unless Hash === old and Hash === new - warn 'Bad old or new sessions provided.' - return cur - end - - delete = old.keys - new.keys - warn "//@#{sid}: dropping #{delete*','}" if $DEBUG and not delete.empty? - delete.each{|k| cur.delete k } - - update = new.keys.select{|k| new[k] != old[k] } - warn "//@#{sid}: updating #{update*','}" if $DEBUG and not update.empty? - update.each{|k| cur[k] = new[k] } - - cur - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showexceptions.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showexceptions.rb deleted file mode 100644 index 697bc41fdb..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showexceptions.rb +++ /dev/null @@ -1,349 +0,0 @@ -require 'ostruct' -require 'erb' -require 'rack/request' -require 'rack/utils' - -module Rack - # Rack::ShowExceptions catches all exceptions raised from the app it - # wraps. It shows a useful backtrace with the sourcefile and - # clickable context, the whole Rack environment and the request - # data. - # - # Be careful when you use this on public-facing sites as it could - # reveal information helpful to attackers. - - class ShowExceptions - CONTEXT = 7 - - def initialize(app) - @app = app - @template = ERB.new(TEMPLATE) - end - - def call(env) - @app.call(env) - rescue StandardError, LoadError, SyntaxError => e - backtrace = pretty(env, e) - [500, - {"Content-Type" => "text/html", - "Content-Length" => backtrace.join.size.to_s}, - backtrace] - end - - def pretty(env, exception) - req = Rack::Request.new(env) - path = (req.script_name + req.path_info).squeeze("/") - - frames = exception.backtrace.map { |line| - frame = OpenStruct.new - if line =~ /(.*?):(\d+)(:in `(.*)')?/ - frame.filename = $1 - frame.lineno = $2.to_i - frame.function = $4 - - begin - lineno = frame.lineno-1 - lines = ::File.readlines(frame.filename) - frame.pre_context_lineno = [lineno-CONTEXT, 0].max - frame.pre_context = lines[frame.pre_context_lineno...lineno] - frame.context_line = lines[lineno].chomp - frame.post_context_lineno = [lineno+CONTEXT, lines.size].min - frame.post_context = lines[lineno+1..frame.post_context_lineno] - rescue - end - - frame - else - nil - end - }.compact - - env["rack.errors"].puts "#{exception.class}: #{exception.message}" - env["rack.errors"].puts exception.backtrace.map { |l| "\t" + l } - env["rack.errors"].flush - - [@template.result(binding)] - end - - def h(obj) # :nodoc: - case obj - when String - Utils.escape_html(obj) - else - Utils.escape_html(obj.inspect) - end - end - - # :stopdoc: - -# adapted from Django -# Copyright (c) 2005, the Lawrence Journal-World -# Used under the modified BSD license: -# http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 -TEMPLATE = <<'HTML' - - - - - - <%=h exception.class %> at <%=h path %> - - - - - -
-

<%=h exception.class %> at <%=h path %>

-

<%=h exception.message %>

- - - - - - -
Ruby<%=h frames.first.filename %>: in <%=h frames.first.function %>, line <%=h frames.first.lineno %>
Web<%=h req.request_method %> <%=h(req.host + path)%>
- -

Jump to:

- -
- -
-

Traceback (innermost first)

-
    -<% frames.each { |frame| %> -
  • - <%=h frame.filename %>: in <%=h frame.function %> - - <% if frame.context_line %> -
    - <% if frame.pre_context %> -
      - <% frame.pre_context.each { |line| %> -
    1. <%=h line %>
    2. - <% } %> -
    - <% end %> - -
      -
    1. <%=h frame.context_line %>...
    - - <% if frame.post_context %> -
      - <% frame.post_context.each { |line| %> -
    1. <%=h line %>
    2. - <% } %> -
    - <% end %> -
    - <% end %> -
  • -<% } %> -
-
- -
-

Request information

- -

GET

- <% unless req.GET.empty? %> - - - - - - - - - <% req.GET.sort_by { |k, v| k.to_s }.each { |key, val| %> - - - - - <% } %> - -
VariableValue
<%=h key %>
<%=h val.inspect %>
- <% else %> -

No GET data.

- <% end %> - -

POST

- <% unless req.POST.empty? %> - - - - - - - - - <% req.POST.sort_by { |k, v| k.to_s }.each { |key, val| %> - - - - - <% } %> - -
VariableValue
<%=h key %>
<%=h val.inspect %>
- <% else %> -

No POST data.

- <% end %> - - - - <% unless req.cookies.empty? %> - - - - - - - - - <% req.cookies.each { |key, val| %> - - - - - <% } %> - -
VariableValue
<%=h key %>
<%=h val.inspect %>
- <% else %> -

No cookie data.

- <% end %> - -

Rack ENV

- - - - - - - - - <% env.sort_by { |k, v| k.to_s }.each { |key, val| %> - - - - - <% } %> - -
VariableValue
<%=h key %>
<%=h val %>
- -
- -
-

- You're seeing this error because you use Rack::ShowExceptions. -

-
- - - -HTML - - # :startdoc: - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showstatus.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showstatus.rb deleted file mode 100644 index 28258c7c89..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showstatus.rb +++ /dev/null @@ -1,106 +0,0 @@ -require 'erb' -require 'rack/request' -require 'rack/utils' - -module Rack - # Rack::ShowStatus catches all empty responses the app it wraps and - # replaces them with a site explaining the error. - # - # Additional details can be put into rack.showstatus.detail - # and will be shown as HTML. If such details exist, the error page - # is always rendered, even if the reply was not empty. - - class ShowStatus - def initialize(app) - @app = app - @template = ERB.new(TEMPLATE) - end - - def call(env) - status, headers, body = @app.call(env) - headers = Utils::HeaderHash.new(headers) - empty = headers['Content-Length'].to_i <= 0 - - # client or server error, or explicit message - if (status.to_i >= 400 && empty) || env["rack.showstatus.detail"] - req = Rack::Request.new(env) - message = Rack::Utils::HTTP_STATUS_CODES[status.to_i] || status.to_s - detail = env["rack.showstatus.detail"] || message - body = @template.result(binding) - size = Rack::Utils.bytesize(body) - [status, headers.merge("Content-Type" => "text/html", "Content-Length" => size.to_s), [body]] - else - [status, headers, body] - end - end - - def h(obj) # :nodoc: - case obj - when String - Utils.escape_html(obj) - else - Utils.escape_html(obj.inspect) - end - end - - # :stopdoc: - -# adapted from Django -# Copyright (c) 2005, the Lawrence Journal-World -# Used under the modified BSD license: -# http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 -TEMPLATE = <<'HTML' - - - - - <%=h message %> at <%=h req.script_name + req.path_info %> - - - - -
-

<%=h message %> (<%= status.to_i %>)

- - - - - - - - - -
Request Method:<%=h req.request_method %>
Request URL:<%=h req.url %>
-
-
-

<%= detail %>

-
- -
-

- You're seeing this error because you use Rack::ShowStatus. -

-
- - -HTML - - # :startdoc: - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/static.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/static.rb deleted file mode 100644 index 168e8f83b2..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/static.rb +++ /dev/null @@ -1,38 +0,0 @@ -module Rack - - # The Rack::Static middleware intercepts requests for static files - # (javascript files, images, stylesheets, etc) based on the url prefixes - # passed in the options, and serves them using a Rack::File object. This - # allows a Rack stack to serve both static and dynamic content. - # - # Examples: - # use Rack::Static, :urls => ["/media"] - # will serve all requests beginning with /media from the "media" folder - # located in the current directory (ie media/*). - # - # use Rack::Static, :urls => ["/css", "/images"], :root => "public" - # will serve all requests beginning with /css or /images from the folder - # "public" in the current directory (ie public/css/* and public/images/*) - - class Static - - def initialize(app, options={}) - @app = app - @urls = options[:urls] || ["/favicon.ico"] - root = options[:root] || Dir.pwd - @file_server = Rack::File.new(root) - end - - def call(env) - path = env["PATH_INFO"] - can_serve = @urls.any? { |url| path.index(url) == 0 } - - if can_serve - @file_server.call(env) - else - @app.call(env) - end - end - - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/urlmap.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/urlmap.rb deleted file mode 100644 index fcf6616c58..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/urlmap.rb +++ /dev/null @@ -1,55 +0,0 @@ -module Rack - # Rack::URLMap takes a hash mapping urls or paths to apps, and - # dispatches accordingly. Support for HTTP/1.1 host names exists if - # the URLs start with http:// or https://. - # - # URLMap modifies the SCRIPT_NAME and PATH_INFO such that the part - # relevant for dispatch is in the SCRIPT_NAME, and the rest in the - # PATH_INFO. This should be taken care of when you need to - # reconstruct the URL in order to create links. - # - # URLMap dispatches in such a way that the longest paths are tried - # first, since they are most specific. - - class URLMap - def initialize(map = {}) - remap(map) - end - - def remap(map) - @mapping = map.map { |location, app| - if location =~ %r{\Ahttps?://(.*?)(/.*)} - host, location = $1, $2 - else - host = nil - end - - unless location[0] == ?/ - raise ArgumentError, "paths need to start with /" - end - location = location.chomp('/') - - [host, location, app] - }.sort_by { |(h, l, a)| [h ? -h.size : (-1.0 / 0.0), -l.size] } # Longest path first - end - - def call(env) - path = env["PATH_INFO"].to_s.squeeze("/") - script_name = env['SCRIPT_NAME'] - hHost, sName, sPort = env.values_at('HTTP_HOST','SERVER_NAME','SERVER_PORT') - @mapping.each { |host, location, app| - next unless (hHost == host || sName == host \ - || (host.nil? && (hHost == sName || hHost == sName+':'+sPort))) - next unless location == path[0, location.size] - next unless path[location.size] == nil || path[location.size] == ?/ - - return app.call( - env.merge( - 'SCRIPT_NAME' => (script_name + location), - 'PATH_INFO' => path[location.size..-1])) - } - [404, {"Content-Type" => "text/plain"}, ["Not Found: #{path}"]] - end - end -end - diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/utils.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/utils.rb deleted file mode 100644 index 42e2e698f4..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/utils.rb +++ /dev/null @@ -1,516 +0,0 @@ -# -*- encoding: binary -*- - -require 'set' -require 'tempfile' - -module Rack - # Rack::Utils contains a grab-bag of useful methods for writing web - # applications adopted from all kinds of Ruby libraries. - - module Utils - # Performs URI escaping so that you can construct proper - # query strings faster. Use this rather than the cgi.rb - # version since it's faster. (Stolen from Camping). - def escape(s) - s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) { - '%'+$1.unpack('H2'*$1.size).join('%').upcase - }.tr(' ', '+') - end - module_function :escape - - # Unescapes a URI escaped string. (Stolen from Camping). - def unescape(s) - s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){ - [$1.delete('%')].pack('H*') - } - end - module_function :unescape - - # Stolen from Mongrel, with some small modifications: - # Parses a query string by breaking it up at the '&' - # and ';' characters. You can also use this to parse - # cookies by changing the characters used in the second - # parameter (which defaults to '&;'). - def parse_query(qs, d = '&;') - params = {} - - (qs || '').split(/[#{d}] */n).each do |p| - k, v = unescape(p).split('=', 2) - - if cur = params[k] - if cur.class == Array - params[k] << v - else - params[k] = [cur, v] - end - else - params[k] = v - end - end - - return params - end - module_function :parse_query - - def parse_nested_query(qs, d = '&;') - params = {} - - (qs || '').split(/[#{d}] */n).each do |p| - k, v = unescape(p).split('=', 2) - normalize_params(params, k, v) - end - - return params - end - module_function :parse_nested_query - - def normalize_params(params, name, v = nil) - name =~ %r(\A[\[\]]*([^\[\]]+)\]*) - k = $1 || '' - after = $' || '' - - return if k.empty? - - if after == "" - params[k] = v - elsif after == "[]" - params[k] ||= [] - raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) - params[k] << v - elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$) - child_key = $1 - params[k] ||= [] - raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) - if params[k].last.is_a?(Hash) && !params[k].last.key?(child_key) - normalize_params(params[k].last, child_key, v) - else - params[k] << normalize_params({}, child_key, v) - end - else - params[k] ||= {} - raise TypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Hash) - params[k] = normalize_params(params[k], after, v) - end - - return params - end - module_function :normalize_params - - def build_query(params) - params.map { |k, v| - if v.class == Array - build_query(v.map { |x| [k, x] }) - else - escape(k) + "=" + escape(v) - end - }.join("&") - end - module_function :build_query - - def build_nested_query(value, prefix = nil) - case value - when Array - value.map { |v| - build_nested_query(v, "#{prefix}[]") - }.join("&") - when Hash - value.map { |k, v| - build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k)) - }.join("&") - when String - raise ArgumentError, "value must be a Hash" if prefix.nil? - "#{prefix}=#{escape(value)}" - else - prefix - end - end - module_function :build_nested_query - - # Escape ampersands, brackets and quotes to their HTML/XML entities. - def escape_html(string) - string.to_s.gsub("&", "&"). - gsub("<", "<"). - gsub(">", ">"). - gsub("'", "'"). - gsub('"', """) - end - module_function :escape_html - - def select_best_encoding(available_encodings, accept_encoding) - # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html - - expanded_accept_encoding = - accept_encoding.map { |m, q| - if m == "*" - (available_encodings - accept_encoding.map { |m2, _| m2 }).map { |m2| [m2, q] } - else - [[m, q]] - end - }.inject([]) { |mem, list| - mem + list - } - - encoding_candidates = expanded_accept_encoding.sort_by { |_, q| -q }.map { |m, _| m } - - unless encoding_candidates.include?("identity") - encoding_candidates.push("identity") - end - - expanded_accept_encoding.find_all { |m, q| - q == 0.0 - }.each { |m, _| - encoding_candidates.delete(m) - } - - return (encoding_candidates & available_encodings)[0] - end - module_function :select_best_encoding - - # Return the bytesize of String; uses String#length under Ruby 1.8 and - # String#bytesize under 1.9. - if ''.respond_to?(:bytesize) - def bytesize(string) - string.bytesize - end - else - def bytesize(string) - string.size - end - end - module_function :bytesize - - # Context allows the use of a compatible middleware at different points - # in a request handling stack. A compatible middleware must define - # #context which should take the arguments env and app. The first of which - # would be the request environment. The second of which would be the rack - # application that the request would be forwarded to. - class Context - attr_reader :for, :app - - def initialize(app_f, app_r) - raise 'running context does not respond to #context' unless app_f.respond_to? :context - @for, @app = app_f, app_r - end - - def call(env) - @for.context(env, @app) - end - - def recontext(app) - self.class.new(@for, app) - end - - def context(env, app=@app) - recontext(app).call(env) - end - end - - # A case-insensitive Hash that preserves the original case of a - # header when set. - class HeaderHash < Hash - def initialize(hash={}) - @names = {} - hash.each { |k, v| self[k] = v } - end - - def to_hash - inject({}) do |hash, (k,v)| - if v.respond_to? :to_ary - hash[k] = v.to_ary.join("\n") - else - hash[k] = v - end - hash - end - end - - def [](k) - super @names[k.downcase] - end - - def []=(k, v) - delete k - @names[k.downcase] = k - super k, v - end - - def delete(k) - super @names.delete(k.downcase) - end - - def include?(k) - @names.has_key? k.downcase - end - - alias_method :has_key?, :include? - alias_method :member?, :include? - alias_method :key?, :include? - - def merge!(other) - other.each { |k, v| self[k] = v } - self - end - - def merge(other) - hash = dup - hash.merge! other - end - end - - # Every standard HTTP code mapped to the appropriate message. - # Stolen from Mongrel. - HTTP_STATUS_CODES = { - 100 => 'Continue', - 101 => 'Switching Protocols', - 200 => 'OK', - 201 => 'Created', - 202 => 'Accepted', - 203 => 'Non-Authoritative Information', - 204 => 'No Content', - 205 => 'Reset Content', - 206 => 'Partial Content', - 300 => 'Multiple Choices', - 301 => 'Moved Permanently', - 302 => 'Found', - 303 => 'See Other', - 304 => 'Not Modified', - 305 => 'Use Proxy', - 307 => 'Temporary Redirect', - 400 => 'Bad Request', - 401 => 'Unauthorized', - 402 => 'Payment Required', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Method Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Timeout', - 409 => 'Conflict', - 410 => 'Gone', - 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Large', - 415 => 'Unsupported Media Type', - 416 => 'Requested Range Not Satisfiable', - 417 => 'Expectation Failed', - 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Bad Gateway', - 503 => 'Service Unavailable', - 504 => 'Gateway Timeout', - 505 => 'HTTP Version Not Supported' - } - - # Responses with HTTP status codes that should not have an entity body - STATUS_WITH_NO_ENTITY_BODY = Set.new((100..199).to_a << 204 << 304) - - # A multipart form data parser, adapted from IOWA. - # - # Usually, Rack::Request#POST takes care of calling this. - - module Multipart - class UploadedFile - # The filename, *not* including the path, of the "uploaded" file - attr_reader :original_filename - - # The content type of the "uploaded" file - attr_accessor :content_type - - def initialize(path, content_type = "text/plain", binary = false) - raise "#{path} file does not exist" unless ::File.exist?(path) - @content_type = content_type - @original_filename = ::File.basename(path) - @tempfile = Tempfile.new(@original_filename) - @tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding) - @tempfile.binmode if binary - FileUtils.copy_file(path, @tempfile.path) - end - - def path - @tempfile.path - end - alias_method :local_path, :path - - def method_missing(method_name, *args, &block) #:nodoc: - @tempfile.__send__(method_name, *args, &block) - end - end - - EOL = "\r\n" - MULTIPART_BOUNDARY = "AaB03x" - - def self.parse_multipart(env) - unless env['CONTENT_TYPE'] =~ - %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n - nil - else - boundary = "--#{$1}" - - params = {} - buf = "" - content_length = env['CONTENT_LENGTH'].to_i - input = env['rack.input'] - input.rewind - - boundary_size = Utils.bytesize(boundary) + EOL.size - bufsize = 16384 - - content_length -= boundary_size - - read_buffer = '' - - status = input.read(boundary_size, read_buffer) - raise EOFError, "bad content body" unless status == boundary + EOL - - rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/n - - loop { - head = nil - body = '' - filename = content_type = name = nil - - until head && buf =~ rx - if !head && i = buf.index(EOL+EOL) - head = buf.slice!(0, i+2) # First \r\n - buf.slice!(0, 2) # Second \r\n - - filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1] - content_type = head[/Content-Type: (.*)#{EOL}/ni, 1] - name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1] - - if content_type || filename - body = Tempfile.new("RackMultipart") - body.binmode if body.respond_to?(:binmode) - end - - next - end - - # Save the read body part. - if head && (boundary_size+4 < buf.size) - body << buf.slice!(0, buf.size - (boundary_size+4)) - end - - c = input.read(bufsize < content_length ? bufsize : content_length, read_buffer) - raise EOFError, "bad content body" if c.nil? || c.empty? - buf << c - content_length -= c.size - end - - # Save the rest. - if i = buf.index(rx) - body << buf.slice!(0, i) - buf.slice!(0, boundary_size+2) - - content_length = -1 if $1 == "--" - end - - if filename == "" - # filename is blank which means no file has been selected - data = nil - elsif filename - body.rewind - - # Take the basename of the upload's original filename. - # This handles the full Windows paths given by Internet Explorer - # (and perhaps other broken user agents) without affecting - # those which give the lone filename. - filename =~ /^(?:.*[:\\\/])?(.*)/m - filename = $1 - - data = {:filename => filename, :type => content_type, - :name => name, :tempfile => body, :head => head} - elsif !filename && content_type - body.rewind - - # Generic multipart cases, not coming from a form - data = {:type => content_type, - :name => name, :tempfile => body, :head => head} - else - data = body - end - - Utils.normalize_params(params, name, data) unless data.nil? - - break if buf.empty? || content_length == -1 - } - - input.rewind - - params - end - end - - def self.build_multipart(params, first = true) - if first - unless params.is_a?(Hash) - raise ArgumentError, "value must be a Hash" - end - - multipart = false - query = lambda { |value| - case value - when Array - value.each(&query) - when Hash - value.values.each(&query) - when UploadedFile - multipart = true - end - } - params.values.each(&query) - return nil unless multipart - end - - flattened_params = Hash.new - - params.each do |key, value| - k = first ? key.to_s : "[#{key}]" - - case value - when Array - value.map { |v| - build_multipart(v, false).each { |subkey, subvalue| - flattened_params["#{k}[]#{subkey}"] = subvalue - } - } - when Hash - build_multipart(value, false).each { |subkey, subvalue| - flattened_params[k + subkey] = subvalue - } - else - flattened_params[k] = value - end - end - - if first - flattened_params.map { |name, file| - if file.respond_to?(:original_filename) - ::File.open(file.path, "rb") do |f| - f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding) -<<-EOF ---#{MULTIPART_BOUNDARY}\r -Content-Disposition: form-data; name="#{name}"; filename="#{Utils.escape(file.original_filename)}"\r -Content-Type: #{file.content_type}\r -Content-Length: #{::File.stat(file.path).size}\r -\r -#{f.read}\r -EOF - end - else -<<-EOF ---#{MULTIPART_BOUNDARY}\r -Content-Disposition: form-data; name="#{name}"\r -\r -#{file}\r -EOF - end - }.join + "--#{MULTIPART_BOUNDARY}--\r" - else - flattened_params - end - end - end - end -end -- cgit v1.2.3 From b4068c12eb3c502f97232c60ff24ead761737224 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 31 Aug 2009 15:40:08 -0500 Subject: Restore rack gem dependency --- actionpack/Rakefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index f76c47aff1..1181995436 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -116,7 +116,8 @@ spec = Gem::Specification.new do |s| s.requirements << 'none' s.add_dependency('activesupport', '= 3.0.pre' + PKG_BUILD) - s.add_dependency('rack-test', '~> 0.4.1') + s.add_dependency('rack', '~> 1.0.0') + s.add_dependency('rack-test', '~> 0.4.2') s.require_path = 'lib' s.autorequire = 'action_controller' -- cgit v1.2.3