diff options
Diffstat (limited to 'actionpack')
53 files changed, 937 insertions, 562 deletions
diff --git a/actionpack/Gemfile b/actionpack/Gemfile index b1579b427b..7d99e0601b 100644 --- a/actionpack/Gemfile +++ b/actionpack/Gemfile @@ -1,7 +1,7 @@ rails_root = Pathname.new(File.dirname(__FILE__)).join("..") gem "rack", "~> 1.0.0" -gem "rack-test", "~> 0.4.2" +gem "rack-test", "~> 0.5.0" gem "activesupport", "3.0.pre", :vendored_at => rails_root.join("activesupport") gem "activemodel", "3.0.pre", :vendored_at => rails_root.join("activemodel") diff --git a/actionpack/Rakefile b/actionpack/Rakefile index cc7b4b0043..af39175047 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -34,7 +34,7 @@ end desc "Run all unit tests" task :test => [:test_action_pack, :test_active_record_integration] -TESTS_GLOB = "test/{abstract,controller,dispatch,new_base,template,html-scanner}/**/*_test.rb" +TESTS_GLOB = "test/{abstract,controller,dispatch,new_base,template,html-scanner,view}/**/*_test.rb" Rake::TestTask.new(:test_action_pack) do |t| t.libs << 'test' @@ -77,50 +77,14 @@ Rake::RDocTask.new { |rdoc| end } -# Create compressed packages -dist_dirs = [ "lib", "test" ] +spec = eval(File.read('actionpack.gemspec')) -spec = Gem::Specification.new do |s| - s.platform = Gem::Platform::RUBY - s.name = PKG_NAME - s.version = PKG_VERSION - s.summary = "Web-flow and rendering framework putting the VC in MVC." - s.description = %q{Eases web-request routing, handling, and response as a half-way front, half-way page controller. Implemented with specific emphasis on enabling easy unit/integration testing that doesn't require a browser.} #' - - s.author = "David Heinemeier Hansson" - s.email = "david@loudthinking.com" - s.rubyforge_project = "actionpack" - s.homepage = "http://www.rubyonrails.org" - - s.has_rdoc = true - s.requirements << 'none' - - s.add_dependency('activesupport', '= 3.0.pre' + PKG_BUILD) - s.add_dependency('activemodel', '= 3.0.pre' + PKG_BUILD) - s.add_dependency('rack', '~> 1.0.0') - s.add_dependency('rack-test', '~> 0.4.2') - - s.require_path = 'lib' - s.autorequire = 'action_controller' - - s.files = [ "Rakefile", "install.rb", "README", "RUNNING_UNIT_TESTS", "CHANGELOG", "MIT-LICENSE" ] - dist_dirs.each do |dir| - s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) } - end -end - Rake::GemPackageTask.new(spec) do |p| p.gem_spec = spec p.need_tar = true p.need_zip = true end -task :gemspec do - File.open(File.join(File.dirname(__FILE__), "#{spec.name}.gemspec"), "w") do |file| - file.puts spec.to_ruby - end -end - task :lines do lines, codelines, total_lines, total_codelines = 0, 0, 0, 0 diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index b91993a12e..1930416358 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -1,42 +1,24 @@ -# -*- encoding: utf-8 -*- - Gem::Specification.new do |s| - s.name = %q{actionpack} - s.version = "3.0.pre" + s.platform = Gem::Platform::RUBY + s.name = 'actionpack' + s.version = '3.0.pre' + s.summary = "Web-flow and rendering framework putting the VC in MVC." + s.description = %q{Eases web-request routing, handling, and response as a half-way front, half-way page controller. Implemented with specific emphasis on enabling easy unit/integration testing that doesn't require a browser.} #' + + s.author = "David Heinemeier Hansson" + s.email = "david@loudthinking.com" + s.rubyforge_project = "actionpack" + s.homepage = "http://www.rubyonrails.org" - s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= - s.authors = ["David Heinemeier Hansson"] - s.autorequire = %q{action_controller} - s.date = %q{2009-09-01} - s.description = %q{Eases web-request routing, handling, and response as a half-way front, half-way page controller. Implemented with specific emphasis on enabling easy unit/integration testing that doesn't require a browser.} - s.email = %q{david@loudthinking.com} - s.files = ["Rakefile", "install.rb", "README", "RUNNING_UNIT_TESTS", "CHANGELOG", "MIT-LICENSE", "lib/abstract_controller", "lib/abstract_controller/base.rb", "lib/abstract_controller/benchmarker.rb", "lib/abstract_controller/callbacks.rb", "lib/abstract_controller/exceptions.rb", "lib/abstract_controller/helpers.rb", "lib/abstract_controller/layouts.rb", "lib/abstract_controller/logger.rb", "lib/abstract_controller/rendering_controller.rb", "lib/abstract_controller.rb", "lib/action_controller", "lib/action_controller/base.rb", "lib/action_controller/caching", "lib/action_controller/caching/actions.rb", "lib/action_controller/caching/fragments.rb", "lib/action_controller/caching/pages.rb", "lib/action_controller/caching/sweeping.rb", "lib/action_controller/caching.rb", "lib/action_controller/deprecated.rb", "lib/action_controller/dispatch", "lib/action_controller/dispatch/dispatcher.rb", "lib/action_controller/dispatch/middlewares.rb", "lib/action_controller/legacy", "lib/action_controller/legacy/layout.rb", "lib/action_controller/metal", "lib/action_controller/metal/compatibility.rb", "lib/action_controller/metal/conditional_get.rb", "lib/action_controller/metal/cookies.rb", "lib/action_controller/metal/exceptions.rb", "lib/action_controller/metal/filter_parameter_logging.rb", "lib/action_controller/metal/flash.rb", "lib/action_controller/metal/helpers.rb", "lib/action_controller/metal/hide_actions.rb", "lib/action_controller/metal/http_authentication.rb", "lib/action_controller/metal/layouts.rb", "lib/action_controller/metal/mime_responds.rb", "lib/action_controller/metal/rack_convenience.rb", "lib/action_controller/metal/redirector.rb", "lib/action_controller/metal/render_options.rb", "lib/action_controller/metal/rendering_controller.rb", "lib/action_controller/metal/request_forgery_protection.rb", "lib/action_controller/metal/rescuable.rb", "lib/action_controller/metal/responder.rb", "lib/action_controller/metal/session.rb", "lib/action_controller/metal/session_management.rb", "lib/action_controller/metal/streaming.rb", "lib/action_controller/metal/testing.rb", "lib/action_controller/metal/url_for.rb", "lib/action_controller/metal/verification.rb", "lib/action_controller/metal.rb", "lib/action_controller/middleware.rb", "lib/action_controller/record_identifier.rb", "lib/action_controller/routing", "lib/action_controller/routing/builder.rb", "lib/action_controller/routing/generation", "lib/action_controller/routing/generation/polymorphic_routes.rb", "lib/action_controller/routing/generation/url_rewriter.rb", "lib/action_controller/routing/optimisations.rb", "lib/action_controller/routing/recognition_optimisation.rb", "lib/action_controller/routing/resources.rb", "lib/action_controller/routing/route.rb", "lib/action_controller/routing/route_set.rb", "lib/action_controller/routing/routing_ext.rb", "lib/action_controller/routing/segments.rb", "lib/action_controller/routing.rb", "lib/action_controller/testing", "lib/action_controller/testing/integration.rb", "lib/action_controller/testing/performance_test.rb", "lib/action_controller/testing/process.rb", "lib/action_controller/testing/test_case.rb", "lib/action_controller/translation.rb", "lib/action_controller/vendor", "lib/action_controller/vendor/html-scanner", "lib/action_controller/vendor/html-scanner/html", "lib/action_controller/vendor/html-scanner/html/document.rb", "lib/action_controller/vendor/html-scanner/html/node.rb", "lib/action_controller/vendor/html-scanner/html/sanitizer.rb", "lib/action_controller/vendor/html-scanner/html/selector.rb", "lib/action_controller/vendor/html-scanner/html/tokenizer.rb", "lib/action_controller/vendor/html-scanner/html/version.rb", "lib/action_controller/vendor/html-scanner.rb", "lib/action_controller.rb", "lib/action_dispatch", "lib/action_dispatch/http", "lib/action_dispatch/http/headers.rb", "lib/action_dispatch/http/mime_type.rb", "lib/action_dispatch/http/mime_types.rb", "lib/action_dispatch/http/request.rb", "lib/action_dispatch/http/response.rb", "lib/action_dispatch/http/status_codes.rb", "lib/action_dispatch/middleware", "lib/action_dispatch/middleware/callbacks.rb", "lib/action_dispatch/middleware/params_parser.rb", "lib/action_dispatch/middleware/rescue.rb", "lib/action_dispatch/middleware/session", "lib/action_dispatch/middleware/session/abstract_store.rb", "lib/action_dispatch/middleware/session/cookie_store.rb", "lib/action_dispatch/middleware/session/mem_cache_store.rb", "lib/action_dispatch/middleware/show_exceptions.rb", "lib/action_dispatch/middleware/stack.rb", "lib/action_dispatch/middleware/templates", "lib/action_dispatch/middleware/templates/rescues", "lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb", "lib/action_dispatch/middleware/templates/rescues/_trace.erb", "lib/action_dispatch/middleware/templates/rescues/diagnostics.erb", "lib/action_dispatch/middleware/templates/rescues/layout.erb", "lib/action_dispatch/middleware/templates/rescues/missing_template.erb", "lib/action_dispatch/middleware/templates/rescues/routing_error.erb", "lib/action_dispatch/middleware/templates/rescues/template_error.erb", "lib/action_dispatch/middleware/templates/rescues/unknown_action.erb", "lib/action_dispatch/testing", "lib/action_dispatch/testing/assertions", "lib/action_dispatch/testing/assertions/dom.rb", "lib/action_dispatch/testing/assertions/model.rb", "lib/action_dispatch/testing/assertions/response.rb", "lib/action_dispatch/testing/assertions/routing.rb", "lib/action_dispatch/testing/assertions/selector.rb", "lib/action_dispatch/testing/assertions/tag.rb", "lib/action_dispatch/testing/assertions.rb", "lib/action_dispatch/testing/test_request.rb", "lib/action_dispatch/testing/test_response.rb", "lib/action_dispatch/vendor", "lib/action_dispatch/vendor/rack-1.1.pre", "lib/action_dispatch/vendor/rack-test", "lib/action_dispatch/vendor/rack-test/rack", "lib/action_dispatch.rb", "lib/action_pack", "lib/action_pack/version.rb", "lib/action_pack.rb", "lib/action_view", "lib/action_view/base.rb", "lib/action_view/context.rb", "lib/action_view/erb", "lib/action_view/erb/util.rb", "lib/action_view/helpers", "lib/action_view/helpers/active_model_helper.rb", "lib/action_view/helpers/ajax_helper.rb", "lib/action_view/helpers/asset_tag_helper.rb", "lib/action_view/helpers/atom_feed_helper.rb", "lib/action_view/helpers/benchmark_helper.rb", "lib/action_view/helpers/cache_helper.rb", "lib/action_view/helpers/capture_helper.rb", "lib/action_view/helpers/date_helper.rb", "lib/action_view/helpers/debug_helper.rb", "lib/action_view/helpers/form_helper.rb", "lib/action_view/helpers/form_options_helper.rb", "lib/action_view/helpers/form_tag_helper.rb", "lib/action_view/helpers/javascript_helper.rb", "lib/action_view/helpers/number_helper.rb", "lib/action_view/helpers/prototype_helper.rb", "lib/action_view/helpers/record_identification_helper.rb", "lib/action_view/helpers/record_tag_helper.rb", "lib/action_view/helpers/sanitize_helper.rb", "lib/action_view/helpers/scriptaculous_helper.rb", "lib/action_view/helpers/tag_helper.rb", "lib/action_view/helpers/text_helper.rb", "lib/action_view/helpers/translation_helper.rb", "lib/action_view/helpers/url_helper.rb", "lib/action_view/helpers.rb", "lib/action_view/locale", "lib/action_view/locale/en.yml", "lib/action_view/paths.rb", "lib/action_view/render", "lib/action_view/render/partials.rb", "lib/action_view/render/rendering.rb", "lib/action_view/template", "lib/action_view/template/error.rb", "lib/action_view/template/handler.rb", "lib/action_view/template/handlers", "lib/action_view/template/handlers/builder.rb", "lib/action_view/template/handlers/erb.rb", "lib/action_view/template/handlers/rjs.rb", "lib/action_view/template/handlers.rb", "lib/action_view/template/inline.rb", "lib/action_view/template/partial.rb", "lib/action_view/template/renderable.rb", "lib/action_view/template/resolver.rb", "lib/action_view/template/template.rb", "lib/action_view/template/text.rb", "lib/action_view/test_case.rb", "lib/action_view.rb", "lib/actionpack.rb", "test/abstract_controller", "test/abstract_controller/abstract_controller_test.rb", "test/abstract_controller/callbacks_test.rb", "test/abstract_controller/helper_test.rb", "test/abstract_controller/layouts_test.rb", "test/abstract_controller/test_helper.rb", "test/abstract_controller/views", "test/abstract_controller/views/abstract_controller", "test/abstract_controller/views/abstract_controller/testing", "test/abstract_controller/views/abstract_controller/testing/me3", "test/abstract_controller/views/abstract_controller/testing/me3/formatted.html.erb", "test/abstract_controller/views/abstract_controller/testing/me3/index.erb", "test/abstract_controller/views/abstract_controller/testing/me4", "test/abstract_controller/views/abstract_controller/testing/me4/index.erb", "test/abstract_controller/views/abstract_controller/testing/me5", "test/abstract_controller/views/abstract_controller/testing/me5/index.erb", "test/abstract_controller/views/action_with_ivars.erb", "test/abstract_controller/views/helper_test.erb", "test/abstract_controller/views/index.erb", "test/abstract_controller/views/layouts", "test/abstract_controller/views/layouts/abstract_controller", "test/abstract_controller/views/layouts/abstract_controller/testing", "test/abstract_controller/views/layouts/abstract_controller/testing/me4.erb", "test/abstract_controller/views/layouts/application.erb", "test/abstract_controller/views/naked_render.erb", "test/abstract_unit.rb", "test/activerecord", "test/activerecord/active_record_store_test.rb", "test/activerecord/polymorphic_routes_test.rb", "test/activerecord/render_partial_with_record_identification_test.rb", "test/controller", "test/controller/action_pack_assertions_test.rb", "test/controller/addresses_render_test.rb", "test/controller/assert_select_test.rb", "test/controller/base_test.rb", "test/controller/benchmark_test.rb", "test/controller/caching_test.rb", "test/controller/capture_test.rb", "test/controller/content_type_test.rb", "test/controller/controller_fixtures", "test/controller/controller_fixtures/app", "test/controller/controller_fixtures/app/controllers", "test/controller/controller_fixtures/app/controllers/admin", "test/controller/controller_fixtures/app/controllers/admin/user_controller.rb", "test/controller/controller_fixtures/app/controllers/user_controller.rb", "test/controller/controller_fixtures/vendor", "test/controller/controller_fixtures/vendor/plugins", "test/controller/controller_fixtures/vendor/plugins/bad_plugin", "test/controller/controller_fixtures/vendor/plugins/bad_plugin/lib", "test/controller/controller_fixtures/vendor/plugins/bad_plugin/lib/plugin_controller.rb", "test/controller/cookie_test.rb", "test/controller/deprecation", "test/controller/deprecation/deprecated_base_methods_test.rb", "test/controller/dispatcher_test.rb", "test/controller/filter_params_test.rb", "test/controller/filters_test.rb", "test/controller/flash_test.rb", "test/controller/helper_test.rb", "test/controller/http_basic_authentication_test.rb", "test/controller/http_digest_authentication_test.rb", "test/controller/integration_test.rb", "test/controller/layout_test.rb", "test/controller/logging_test.rb", "test/controller/mime_responds_test.rb", "test/controller/record_identifier_test.rb", "test/controller/redirect_test.rb", "test/controller/render_js_test.rb", "test/controller/render_json_test.rb", "test/controller/render_other_test.rb", "test/controller/render_test.rb", "test/controller/render_xml_test.rb", "test/controller/request", "test/controller/request/test_request_test.rb", "test/controller/request_forgery_protection_test.rb", "test/controller/rescue_test.rb", "test/controller/resources_test.rb", "test/controller/routing_test.rb", "test/controller/selector_test.rb", "test/controller/send_file_test.rb", "test/controller/test_test.rb", "test/controller/translation_test.rb", "test/controller/url_rewriter_test.rb", "test/controller/verification_test.rb", "test/controller/view_paths_test.rb", "test/controller/webservice_test.rb", "test/dispatch", "test/dispatch/header_test.rb", "test/dispatch/middleware_stack_test.rb", "test/dispatch/mime_type_test.rb", "test/dispatch/rack_test.rb", "test/dispatch/request", "test/dispatch/request/json_params_parsing_test.rb", "test/dispatch/request/multipart_params_parsing_test.rb", "test/dispatch/request/query_string_parsing_test.rb", "test/dispatch/request/url_encoded_params_parsing_test.rb", "test/dispatch/request/xml_params_parsing_test.rb", "test/dispatch/request_test.rb", "test/dispatch/response_test.rb", "test/dispatch/session", "test/dispatch/session/cookie_store_test.rb", "test/dispatch/session/mem_cache_store_test.rb", "test/dispatch/session/test_session_test.rb", "test/dispatch/show_exceptions_test.rb", "test/dispatch/test_request_test.rb", "test/fixtures", "test/fixtures/_top_level_partial.html.erb", "test/fixtures/_top_level_partial_only.erb", "test/fixtures/addresses", "test/fixtures/addresses/list.erb", "test/fixtures/alternate_helpers", "test/fixtures/alternate_helpers/foo_helper.rb", "test/fixtures/bad_customers", "test/fixtures/bad_customers/_bad_customer.html.erb", "test/fixtures/companies.yml", "test/fixtures/company.rb", "test/fixtures/content_type", "test/fixtures/content_type/render_default_content_types_for_respond_to.xml.erb", "test/fixtures/content_type/render_default_for_rhtml.rhtml", "test/fixtures/content_type/render_default_for_rjs.rjs", "test/fixtures/content_type/render_default_for_rxml.rxml", "test/fixtures/customers", "test/fixtures/customers/_customer.html.erb", "test/fixtures/db_definitions", "test/fixtures/db_definitions/sqlite.sql", "test/fixtures/developer.rb", "test/fixtures/developers", "test/fixtures/developers/_developer.erb", "test/fixtures/developers.yml", "test/fixtures/developers_projects.yml", "test/fixtures/fun", "test/fixtures/fun/games", "test/fixtures/fun/games/_game.erb", "test/fixtures/fun/games/hello_world.erb", "test/fixtures/fun/serious", "test/fixtures/fun/serious/games", "test/fixtures/fun/serious/games/_game.erb", "test/fixtures/functional_caching", "test/fixtures/functional_caching/_partial.erb", "test/fixtures/functional_caching/formatted_fragment_cached.html.erb", "test/fixtures/functional_caching/formatted_fragment_cached.js.rjs", "test/fixtures/functional_caching/formatted_fragment_cached.xml.builder", "test/fixtures/functional_caching/fragment_cached.html.erb", "test/fixtures/functional_caching/html_fragment_cached_with_partial.html.erb", "test/fixtures/functional_caching/inline_fragment_cached.html.erb", "test/fixtures/functional_caching/js_fragment_cached_with_partial.js.rjs", "test/fixtures/good_customers", "test/fixtures/good_customers/_good_customer.html.erb", "test/fixtures/happy_path", "test/fixtures/happy_path/render_action", "test/fixtures/happy_path/render_action/hello_world.erb", "test/fixtures/helpers", "test/fixtures/helpers/abc_helper.rb", "test/fixtures/helpers/fun", "test/fixtures/helpers/fun/games_helper.rb", "test/fixtures/helpers/fun/pdf_helper.rb", "test/fixtures/layout_tests", "test/fixtures/layout_tests/alt", "test/fixtures/layout_tests/alt/hello.rhtml", "test/fixtures/layout_tests/alt/layouts", "test/fixtures/layout_tests/alt/layouts/alt.rhtml", "test/fixtures/layout_tests/layouts", "test/fixtures/layout_tests/layouts/controller_name_space", "test/fixtures/layout_tests/layouts/controller_name_space/nested.rhtml", "test/fixtures/layout_tests/layouts/item.rhtml", "test/fixtures/layout_tests/layouts/layout_test.rhtml", "test/fixtures/layout_tests/layouts/multiple_extensions.html.erb", "test/fixtures/layout_tests/layouts/symlinked", "test/fixtures/layout_tests/layouts/third_party_template_library.mab", "test/fixtures/layout_tests/views", "test/fixtures/layout_tests/views/goodbye.rhtml", "test/fixtures/layout_tests/views/hello.rhtml", "test/fixtures/layouts", "test/fixtures/layouts/_column.html.erb", "test/fixtures/layouts/block_with_layout.erb", "test/fixtures/layouts/builder.builder", "test/fixtures/layouts/partial_with_layout.erb", "test/fixtures/layouts/standard.html.erb", "test/fixtures/layouts/talk_from_action.erb", "test/fixtures/layouts/xhr.html.erb", "test/fixtures/layouts/yield.erb", "test/fixtures/mascot.rb", "test/fixtures/mascots", "test/fixtures/mascots/_mascot.html.erb", "test/fixtures/mascots.yml", "test/fixtures/multipart", "test/fixtures/multipart/binary_file", "test/fixtures/multipart/boundary_problem_file", "test/fixtures/multipart/bracketed_param", "test/fixtures/multipart/empty", "test/fixtures/multipart/hello.txt", "test/fixtures/multipart/large_text_file", "test/fixtures/multipart/mixed_files", "test/fixtures/multipart/mona_lisa.jpg", "test/fixtures/multipart/none", "test/fixtures/multipart/single_parameter", "test/fixtures/multipart/text_file", "test/fixtures/override", "test/fixtures/override/test", "test/fixtures/override/test/hello_world.erb", "test/fixtures/override2", "test/fixtures/override2/layouts", "test/fixtures/override2/layouts/test", "test/fixtures/override2/layouts/test/sub.erb", "test/fixtures/post_test", "test/fixtures/post_test/layouts", "test/fixtures/post_test/layouts/post.html.erb", "test/fixtures/post_test/layouts/super_post.iphone.erb", "test/fixtures/post_test/post", "test/fixtures/post_test/post/index.html.erb", "test/fixtures/post_test/post/index.iphone.erb", "test/fixtures/post_test/super_post", "test/fixtures/post_test/super_post/index.html.erb", "test/fixtures/post_test/super_post/index.iphone.erb", "test/fixtures/project.rb", "test/fixtures/projects", "test/fixtures/projects/_project.erb", "test/fixtures/projects.yml", "test/fixtures/public", "test/fixtures/public/404.html", "test/fixtures/public/500.da.html", "test/fixtures/public/500.html", "test/fixtures/public/absolute", "test/fixtures/public/absolute/test.css", "test/fixtures/public/absolute/test.js", "test/fixtures/public/elsewhere", "test/fixtures/public/elsewhere/cools.js", "test/fixtures/public/elsewhere/file.css", "test/fixtures/public/images", "test/fixtures/public/images/rails.png", "test/fixtures/public/javascripts", "test/fixtures/public/javascripts/application.js", "test/fixtures/public/javascripts/bank.js", "test/fixtures/public/javascripts/cache", "test/fixtures/public/javascripts/common.javascript", "test/fixtures/public/javascripts/controls.js", "test/fixtures/public/javascripts/dragdrop.js", "test/fixtures/public/javascripts/effects.js", "test/fixtures/public/javascripts/prototype.js", "test/fixtures/public/javascripts/robber.js", "test/fixtures/public/javascripts/subdir", "test/fixtures/public/javascripts/subdir/subdir.js", "test/fixtures/public/javascripts/version.1.0.js", "test/fixtures/public/stylesheets", "test/fixtures/public/stylesheets/bank.css", "test/fixtures/public/stylesheets/random.styles", "test/fixtures/public/stylesheets/robber.css", "test/fixtures/public/stylesheets/subdir", "test/fixtures/public/stylesheets/subdir/subdir.css", "test/fixtures/public/stylesheets/version.1.0.css", "test/fixtures/quiz", "test/fixtures/quiz/questions", "test/fixtures/quiz/questions/_question.html.erb", "test/fixtures/replies", "test/fixtures/replies/_reply.erb", "test/fixtures/replies.yml", "test/fixtures/reply.rb", "test/fixtures/respond_to", "test/fixtures/respond_to/all_types_with_layout.html.erb", "test/fixtures/respond_to/all_types_with_layout.js.rjs", "test/fixtures/respond_to/custom_constant_handling_without_block.mobile.erb", "test/fixtures/respond_to/iphone_with_html_response_type.html.erb", "test/fixtures/respond_to/iphone_with_html_response_type.iphone.erb", "test/fixtures/respond_to/layouts", "test/fixtures/respond_to/layouts/missing.html.erb", "test/fixtures/respond_to/layouts/standard.html.erb", "test/fixtures/respond_to/layouts/standard.iphone.erb", "test/fixtures/respond_to/using_defaults.html.erb", "test/fixtures/respond_to/using_defaults.js.rjs", "test/fixtures/respond_to/using_defaults.xml.builder", "test/fixtures/respond_to/using_defaults_with_type_list.html.erb", "test/fixtures/respond_to/using_defaults_with_type_list.js.rjs", "test/fixtures/respond_to/using_defaults_with_type_list.xml.builder", "test/fixtures/respond_with", "test/fixtures/respond_with/edit.html.erb", "test/fixtures/respond_with/new.html.erb", "test/fixtures/respond_with/using_defaults.html.erb", "test/fixtures/respond_with/using_defaults.js.rjs", "test/fixtures/respond_with/using_defaults_with_type_list.js.rjs", "test/fixtures/respond_with/using_defaults_with_type_list.xml.builder", "test/fixtures/respond_with/using_resource.js.rjs", "test/fixtures/scope", "test/fixtures/scope/test", "test/fixtures/scope/test/modgreet.erb", "test/fixtures/shared.html.erb", "test/fixtures/symlink_parent", "test/fixtures/symlink_parent/symlinked_layout.erb", "test/fixtures/test", "test/fixtures/test/_counter.html.erb", "test/fixtures/test/_customer.erb", "test/fixtures/test/_customer_counter.erb", "test/fixtures/test/_customer_greeting.erb", "test/fixtures/test/_customer_with_var.erb", "test/fixtures/test/_form.erb", "test/fixtures/test/_hash_greeting.erb", "test/fixtures/test/_hash_object.erb", "test/fixtures/test/_hello.builder", "test/fixtures/test/_labelling_form.erb", "test/fixtures/test/_layout_for_block_with_args.html.erb", "test/fixtures/test/_layout_for_partial.html.erb", "test/fixtures/test/_local_inspector.html.erb", "test/fixtures/test/_one.html.erb", "test/fixtures/test/_partial.erb", "test/fixtures/test/_partial.html.erb", "test/fixtures/test/_partial.js.erb", "test/fixtures/test/_partial_for_use_in_layout.html.erb", "test/fixtures/test/_partial_only.erb", "test/fixtures/test/_partial_with_only_html_version.html.erb", "test/fixtures/test/_person.erb", "test/fixtures/test/_raise.html.erb", "test/fixtures/test/_two.html.erb", "test/fixtures/test/action_talk_to_layout.erb", "test/fixtures/test/basic.html.erb", "test/fixtures/test/calling_partial_with_layout.html.erb", "test/fixtures/test/capturing.erb", "test/fixtures/test/content_for.erb", "test/fixtures/test/content_for_concatenated.erb", "test/fixtures/test/content_for_with_parameter.erb", "test/fixtures/test/delete_with_js.rjs", "test/fixtures/test/dont_pick_me", "test/fixtures/test/dot.directory", "test/fixtures/test/dot.directory/render_file_with_ivar.erb", "test/fixtures/test/enum_rjs_test.rjs", "test/fixtures/test/formatted_html_erb.html.erb", "test/fixtures/test/formatted_xml_erb.builder", "test/fixtures/test/formatted_xml_erb.html.erb", "test/fixtures/test/formatted_xml_erb.xml.erb", "test/fixtures/test/greeting.html.erb", "test/fixtures/test/greeting.js.rjs", "test/fixtures/test/greeting.xml.erb", "test/fixtures/test/hello.builder", "test/fixtures/test/hello_world.da.html.erb", "test/fixtures/test/hello_world.erb", "test/fixtures/test/hello_world.erb~", "test/fixtures/test/hello_world.pt-BR.html.erb", "test/fixtures/test/hello_world_container.builder", "test/fixtures/test/hello_world_from_rxml.builder", "test/fixtures/test/hello_world_with_layout_false.erb", "test/fixtures/test/hello_xml_world.builder", "test/fixtures/test/hyphen-ated.erb", "test/fixtures/test/implicit_content_type.atom.builder", "test/fixtures/test/list.erb", "test/fixtures/test/malformed", "test/fixtures/test/malformed/malformed.en.html.erb~", "test/fixtures/test/malformed/malformed.erb~", "test/fixtures/test/malformed/malformed.html.erb~", "test/fixtures/test/nested_layout.erb", "test/fixtures/test/non_erb_block_content_for.builder", "test/fixtures/test/potential_conflicts.erb", "test/fixtures/test/render_explicit_html_template.js.rjs", "test/fixtures/test/render_file_from_template.html.erb", "test/fixtures/test/render_file_with_ivar.erb", "test/fixtures/test/render_file_with_locals.erb", "test/fixtures/test/render_file_with_locals_and_default.erb", "test/fixtures/test/render_implicit_html_template.js.rjs", "test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb", "test/fixtures/test/render_implicit_html_template_from_xhr_request.html.erb", "test/fixtures/test/render_implicit_js_template_without_layout.js.erb", "test/fixtures/test/render_to_string_test.erb", "test/fixtures/test/sub_template_raise.html.erb", "test/fixtures/test/template.erb", "test/fixtures/test/update_element_with_capture.erb", "test/fixtures/test/using_layout_around_block.html.erb", "test/fixtures/test/utf8.html.erb", "test/fixtures/test/utf8_magic.html.erb", "test/fixtures/topic.rb", "test/fixtures/topics", "test/fixtures/topics/_topic.html.erb", "test/fixtures/topics.yml", "test/html-scanner", "test/html-scanner/cdata_node_test.rb", "test/html-scanner/document_test.rb", "test/html-scanner/node_test.rb", "test/html-scanner/sanitizer_test.rb", "test/html-scanner/tag_node_test.rb", "test/html-scanner/text_node_test.rb", "test/html-scanner/tokenizer_test.rb", "test/javascript", "test/javascript/ajax_test.rb", "test/lib", "test/lib/active_record_unit.rb", "test/lib/controller", "test/lib/controller/fake_controllers.rb", "test/lib/controller/fake_models.rb", "test/lib/fixture_template.rb", "test/lib/testing_sandbox.rb", "test/new_base", "test/new_base/base_test.rb", "test/new_base/content_type_test.rb", "test/new_base/etag_test.rb", "test/new_base/metal_test.rb", "test/new_base/redirect_test.rb", "test/new_base/render_action_test.rb", "test/new_base/render_file_test.rb", "test/new_base/render_implicit_action_test.rb", "test/new_base/render_layout_test.rb", "test/new_base/render_partial_test.rb", "test/new_base/render_rjs_test.rb", "test/new_base/render_template_test.rb", "test/new_base/render_test.rb", "test/new_base/render_text_test.rb", "test/new_base/render_xml_test.rb", "test/new_base/test_helper.rb", "test/old_base", "test/old_base/abstract_unit.rb", "test/runner", "test/template", "test/template/active_record_helper_i18n_test.rb", "test/template/active_record_helper_test.rb", "test/template/asset_tag_helper_test.rb", "test/template/atom_feed_helper_test.rb", "test/template/benchmark_helper_test.rb", "test/template/body_parts_test.rb", "test/template/capture_helper_test.rb", "test/template/compiled_templates_test.rb", "test/template/date_helper_i18n_test.rb", "test/template/date_helper_test.rb", "test/template/erb_util_test.rb", "test/template/form_helper_test.rb", "test/template/form_options_helper_i18n_test.rb", "test/template/form_options_helper_test.rb", "test/template/form_tag_helper_test.rb", "test/template/javascript_helper_test.rb", "test/template/number_helper_i18n_test.rb", "test/template/number_helper_test.rb", "test/template/output_buffer_test.rb", "test/template/prototype_helper_test.rb", "test/template/record_tag_helper_test.rb", "test/template/render_test.rb", "test/template/sanitize_helper_test.rb", "test/template/scriptaculous_helper_test.rb", "test/template/tag_helper_test.rb", "test/template/test_test.rb", "test/template/text_helper_test.rb", "test/template/translation_helper_test.rb", "test/template/url_helper_test.rb", "test/tmp", "test/view", "test/view/test_case_test.rb"] - s.homepage = %q{http://www.rubyonrails.org} - s.require_paths = ["lib"] - s.requirements = ["none"] - s.rubyforge_project = %q{actionpack} - s.rubygems_version = %q{1.3.5} - s.summary = %q{Web-flow and rendering framework putting the VC in MVC.} + s.files = Dir['CHANGELOG', 'README', 'MIT-LICENSE', 'lib/**/*'] + s.has_rdoc = true + s.requirements << 'none' - if s.respond_to? :specification_version then - current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION - s.specification_version = 3 + s.add_dependency('activesupport', '= 3.0.pre') + s.add_dependency('activemodel', '= 3.0.pre') + s.add_dependency('rack', '~> 1.0.0') + s.add_dependency('rack-test', '~> 0.5.0') - if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then - s.add_runtime_dependency(%q<activesupport>, ["= 3.0.pre"]) - s.add_runtime_dependency(%q<activemodel>, ["= 3.0.pre"]) - s.add_runtime_dependency(%q<rack>, ["~> 1.0.0"]) - s.add_runtime_dependency(%q<rack-test>, ["~> 0.4.2"]) - else - s.add_dependency(%q<activesupport>, ["= 3.0.pre"]) - s.add_dependency(%q<activemodel>, ["= 3.0.pre"]) - s.add_dependency(%q<rack>, ["~> 1.0.0"]) - s.add_dependency(%q<rack-test>, ["~> 0.4.2"]) - end - else - s.add_dependency(%q<activesupport>, ["= 3.0.pre"]) - s.add_dependency(%q<activemodel>, ["= 3.0.pre"]) - s.add_dependency(%q<rack>, ["~> 1.0.0"]) - s.add_dependency(%q<rack-test>, ["~> 0.4.2"]) - end + s.require_path = 'lib' + s.autorequire = 'action_controller' end diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index 634206e065..6702cb47f8 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -1,10 +1,12 @@ module ActionController autoload :Base, "action_controller/base" + autoload :Benchmarking, "action_controller/metal/benchmarking" autoload :ConditionalGet, "action_controller/metal/conditional_get" + autoload :Helpers, "action_controller/metal/helpers" autoload :HideActions, "action_controller/metal/hide_actions" + autoload :Layouts, "action_controller/metal/layouts" 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" autoload :Redirector, "action_controller/metal/redirector" @@ -12,17 +14,18 @@ module ActionController autoload :RenderOptions, "action_controller/metal/render_options" autoload :Rescue, "action_controller/metal/rescuable" autoload :Responder, "action_controller/metal/responder" + autoload :Session, "action_controller/metal/session" autoload :Testing, "action_controller/metal/testing" autoload :UrlFor, "action_controller/metal/url_for" - autoload :Session, "action_controller/metal/session" - autoload :Helpers, "action_controller/metal/helpers" # Ported modules # require 'action_controller/routing' autoload :Caching, 'action_controller/caching' autoload :Dispatcher, 'action_controller/dispatch/dispatcher' - autoload :Integration, 'action_controller/testing/integration' + autoload :Integration, 'action_controller/deprecated/integration_test' + autoload :IntegrationTest, 'action_controller/deprecated/integration_test' autoload :MimeResponds, 'action_controller/metal/mime_responds' + autoload :PerformanceTest, 'action_controller/deprecated/performance_test' autoload :PolymorphicRoutes, 'action_controller/routing/generation/polymorphic_routes' autoload :RecordIdentifier, 'action_controller/record_identifier' autoload :Resources, 'action_controller/routing/resources' @@ -42,7 +45,6 @@ module ActionController autoload :Cookies, 'action_controller/metal/cookies' autoload :ActionControllerError, 'action_controller/metal/exceptions' - autoload :SessionRestoreError, 'action_controller/metal/exceptions' autoload :RenderError, 'action_controller/metal/exceptions' autoload :RoutingError, 'action_controller/metal/exceptions' autoload :MethodNotAllowed, 'action_controller/metal/exceptions' diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index f5bd0a00a1..5338a70104 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -14,6 +14,7 @@ module ActionController include ActionController::Layouts include ActionController::ConditionalGet include ActionController::RackConvenience + include ActionController::Benchmarking # Legacy modules include SessionManagement diff --git a/actionpack/lib/action_controller/deprecated/integration_test.rb b/actionpack/lib/action_controller/deprecated/integration_test.rb new file mode 100644 index 0000000000..86336b6bc4 --- /dev/null +++ b/actionpack/lib/action_controller/deprecated/integration_test.rb @@ -0,0 +1,2 @@ +ActionController::Integration = ActionDispatch::Integration +ActionController::IntegrationTest = ActionDispatch::IntegrationTest diff --git a/actionpack/lib/action_controller/deprecated/performance_test.rb b/actionpack/lib/action_controller/deprecated/performance_test.rb new file mode 100644 index 0000000000..fcf47d31a7 --- /dev/null +++ b/actionpack/lib/action_controller/deprecated/performance_test.rb @@ -0,0 +1 @@ +ActionController::PerformanceTest = ActionDispatch::PerformanceTest diff --git a/actionpack/lib/action_controller/dispatch/dispatcher.rb b/actionpack/lib/action_controller/dispatch/dispatcher.rb index ba316b9e63..e04da42637 100644 --- a/actionpack/lib/action_controller/dispatch/dispatcher.rb +++ b/actionpack/lib/action_controller/dispatch/dispatcher.rb @@ -7,15 +7,6 @@ module ActionController cattr_accessor :prepare_each_request self.prepare_each_request = false - cattr_accessor :router - self.router = Routing::Routes - - cattr_accessor :middleware - self.middleware = ActionDispatch::MiddlewareStack.new do |middleware| - middlewares = File.join(File.dirname(__FILE__), "middlewares.rb") - middleware.instance_eval(File.read(middlewares), middlewares, 1) - end - class << self def define_dispatcher_callbacks(cache_classes) unless cache_classes @@ -24,7 +15,7 @@ module ActionController # Development mode callbacks ActionDispatch::Callbacks.before_dispatch do |app| - ActionController::Dispatcher.router.reload + ActionController::Routing::Routes.reload end ActionDispatch::Callbacks.after_dispatch do @@ -58,7 +49,8 @@ module ActionController :to => ActionDispatch::Callbacks def new - @@middleware.build(@@router) + # DEPRECATE Rails application fallback + Rails.application end end end diff --git a/actionpack/lib/action_controller/dispatch/middlewares.rb b/actionpack/lib/action_controller/dispatch/middlewares.rb deleted file mode 100644 index 5641b3cb8d..0000000000 --- a/actionpack/lib/action_controller/dispatch/middlewares.rb +++ /dev/null @@ -1,16 +0,0 @@ -use "Rack::Lock", :if => lambda { - !ActionController::Base.allow_concurrency -} - -use "ActionDispatch::ShowExceptions", lambda { ActionController::Base.consider_all_requests_local } -use "ActionDispatch::Callbacks", lambda { ActionController::Dispatcher.prepare_each_request } - -# TODO: Redirect global exceptions somewhere? -# use "ActionDispatch::Rescue" - -use lambda { ActionController::Base.session_store }, - lambda { ActionController::Base.session_options } - -use "ActionDispatch::ParamsParser" -use "Rack::MethodOverride" -use "Rack::Head" diff --git a/actionpack/lib/action_controller/metal/benchmarking.rb b/actionpack/lib/action_controller/metal/benchmarking.rb new file mode 100644 index 0000000000..d4cb1e122d --- /dev/null +++ b/actionpack/lib/action_controller/metal/benchmarking.rb @@ -0,0 +1,92 @@ +require 'benchmark' + +module ActionController #:nodoc: + # The benchmarking module times the performance of actions and reports to the logger. If the Active Record + # package has been included, a separate timing section for database calls will be added as well. + module Benchmarking #:nodoc: + extend ActiveSupport::Concern + + module ClassMethods + # Log and benchmark the workings of a single block and silence whatever logging that may have happened inside it + # (unless <tt>use_silence</tt> is set to false). + # + # The benchmark is only recorded if the current level of the logger matches the <tt>log_level</tt>, which makes it + # easy to include benchmarking statements in production software that will remain inexpensive because the benchmark + # will only be conducted if the log level is low enough. + def benchmark(title, log_level = Logger::DEBUG, use_silence = true) + if logger && logger.level == log_level + result = nil + ms = Benchmark.ms { result = use_silence ? silence { yield } : yield } + logger.add(log_level, "#{title} (#{('%.1f' % ms)}ms)") + result + else + yield + end + end + end + + protected + def render(*args, &block) + if logger + if Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected? + db_runtime = ActiveRecord::Base.connection.reset_runtime + end + + render_output = nil + @view_runtime = Benchmark.ms { render_output = super } + + if Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected? + @db_rt_before_render = db_runtime + @db_rt_after_render = ActiveRecord::Base.connection.reset_runtime + @view_runtime -= @db_rt_after_render + end + + render_output + else + super + end + end + + private + def process_action(*args) + if logger + ms = [Benchmark.ms { super }, 0.01].max + logging_view = defined?(@view_runtime) + logging_active_record = Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected? + + log_message = 'Completed in %.0fms' % ms + + if logging_view || logging_active_record + log_message << " (" + log_message << view_runtime if logging_view + + if logging_active_record + log_message << ", " if logging_view + log_message << active_record_runtime + ")" + else + ")" + end + end + + log_message << " | #{response.status}" + log_message << " [#{complete_request_uri rescue "unknown"}]" + + logger.info(log_message) + response.headers["X-Runtime"] = "%.0f" % ms + else + super + end + end + + def view_runtime + "View: %.0f" % @view_runtime + end + + def active_record_runtime + db_runtime = ActiveRecord::Base.connection.reset_runtime + db_runtime += @db_rt_before_render if @db_rt_before_render + db_runtime += @db_rt_after_render if @db_rt_after_render + "DB: %.0f" % db_runtime + end + end +end diff --git a/actionpack/lib/action_controller/metal/exceptions.rb b/actionpack/lib/action_controller/metal/exceptions.rb index d0811254cb..b9d23da3e0 100644 --- a/actionpack/lib/action_controller/metal/exceptions.rb +++ b/actionpack/lib/action_controller/metal/exceptions.rb @@ -2,9 +2,6 @@ module ActionController class ActionControllerError < StandardError #:nodoc: end - class SessionRestoreError < ActionControllerError #:nodoc: - end - class RenderError < ActionControllerError #:nodoc: end diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 2fccf01040..bbc7f3c8f9 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -1,78 +1,7 @@ -require 'action_dispatch' -require 'rack/session/abstract/id' require 'active_support/core_ext/object/conversions' +require "rack/test" module ActionController #:nodoc: - class TestRequest < ActionDispatch::TestRequest #:nodoc: - def initialize(env = {}) - super - - self.session = TestSession.new - self.session_options = TestSession::DEFAULT_OPTIONS.merge(:id => ActiveSupport::SecureRandom.hex(16)) - end - - def assign_parameters(controller_path, action, parameters) - parameters = parameters.symbolize_keys.merge(:controller => controller_path, :action => action) - extra_keys = ActionController::Routing::Routes.extra_keys(parameters) - non_path_parameters = get? ? query_parameters : request_parameters - parameters.each do |key, value| - if value.is_a? Fixnum - value = value.to_s - elsif value.is_a? Array - value = ActionController::Routing::PathSegment::Result.new(value) - end - - if extra_keys.include?(key.to_sym) - non_path_parameters[key] = value - else - path_parameters[key.to_s] = value - end - end - - params = self.request_parameters.dup - - %w(controller action only_path).each do |k| - params.delete(k) - params.delete(k.to_sym) - end - - data = params.to_query - @env['CONTENT_LENGTH'] = data.length.to_s - @env['rack.input'] = StringIO.new(data) - end - - def recycle! - @formats = nil - @env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ } - @env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ } - @env['action_dispatch.request.query_parameters'] = {} - end - end - - class TestResponse < ActionDispatch::TestResponse - def recycle! - @status = 200 - @header = {} - @writer = lambda { |x| @body << x } - @block = nil - @length = 0 - @body = [] - @charset = nil - @content_type = nil - - @request = @template = nil - end - end - - class TestSession < ActionDispatch::Session::AbstractStore::SessionHash #:nodoc: - DEFAULT_OPTIONS = ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS - - def initialize(session = {}) - replace(session.stringify_keys) - @loaded = true - end - end - # Essentially generates a modified Tempfile object similar to the object # you'd get from the standard library CGI module in a multipart # request. This means you can use an ActionController::TestUploadedFile @@ -87,75 +16,6 @@ module ActionController #:nodoc: TestUploadedFile = Rack::Test::UploadedFile module TestProcess - def self.included(base) - # Executes a request simulating GET HTTP method and set/volley the response - def get(action, parameters = nil, session = nil, flash = nil) - process(action, parameters, session, flash, "GET") - end - - # Executes a request simulating POST HTTP method and set/volley the response - def post(action, parameters = nil, session = nil, flash = nil) - process(action, parameters, session, flash, "POST") - end - - # Executes a request simulating PUT HTTP method and set/volley the response - def put(action, parameters = nil, session = nil, flash = nil) - process(action, parameters, session, flash, "PUT") - end - - # Executes a request simulating DELETE HTTP method and set/volley the response - def delete(action, parameters = nil, session = nil, flash = nil) - process(action, parameters, session, flash, "DELETE") - end - - # Executes a request simulating HEAD HTTP method and set/volley the response - def head(action, parameters = nil, session = nil, flash = nil) - process(action, parameters, session, flash, "HEAD") - end - end - - def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET') - # Sanity check for required instance variables so we can give an - # understandable error message. - %w(@controller @request @response).each do |iv_name| - if !(instance_variable_names.include?(iv_name) || instance_variable_names.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil? - raise "#{iv_name} is nil: make sure you set it in your test's setup method." - end - end - - @request.recycle! - @response.recycle! - @controller.response_body = nil - @controller.formats = nil - @controller.params = nil - - @html_document = nil - @request.env['REQUEST_METHOD'] = http_method - - parameters ||= {} - @request.assign_parameters(@controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters) - - @request.session = ActionController::TestSession.new(session) unless session.nil? - @request.session["flash"] = ActionController::Flash::FlashHash.new.update(flash) if flash - - @controller.request = @request - @controller.params.merge!(parameters) - build_request_uri(action, parameters) - Base.class_eval { include Testing } - @controller.process_with_new_base_test(@request, @response) - @response - end - - 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(', ') - returning __send__(request_method, action, parameters, session, flash) do - @request.env.delete 'HTTP_X_REQUESTED_WITH' - @request.env.delete 'HTTP_ACCEPT' - end - end - alias xhr :xml_http_request - def assigns(key = nil) assigns = {} @controller.instance_variable_names.each do |ivar| @@ -182,16 +42,6 @@ module ActionController #:nodoc: @response.redirect_url end - def build_request_uri(action, parameters) - unless @request.env['REQUEST_URI'] - options = @controller.__send__(:rewrite_options, parameters) - options.update(:only_path => true, :action => action) - - url = ActionController::UrlRewriter.new(@request, parameters) - @request.request_uri = url.rewrite(options) - end - end - def html_document xml = @response.content_type =~ /xml$/ @html_document ||= HTML::Document.new(@response.body, false, xml) @@ -249,7 +99,6 @@ 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 @@ -257,7 +106,6 @@ 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 diff --git a/actionpack/lib/action_controller/testing/test_case.rb b/actionpack/lib/action_controller/testing/test_case.rb index b66a4c15ff..178e3477a6 100644 --- a/actionpack/lib/action_controller/testing/test_case.rb +++ b/actionpack/lib/action_controller/testing/test_case.rb @@ -1,7 +1,77 @@ require 'active_support/test_case' -require 'action_controller/testing/process' +require 'rack/session/abstract/id' module ActionController + class TestRequest < ActionDispatch::TestRequest #:nodoc: + def initialize(env = {}) + super + + self.session = TestSession.new + self.session_options = TestSession::DEFAULT_OPTIONS.merge(:id => ActiveSupport::SecureRandom.hex(16)) + end + + def assign_parameters(controller_path, action, parameters = {}) + parameters = parameters.symbolize_keys.merge(:controller => controller_path, :action => action) + extra_keys = ActionController::Routing::Routes.extra_keys(parameters) + non_path_parameters = get? ? query_parameters : request_parameters + parameters.each do |key, value| + if value.is_a? Fixnum + value = value.to_s + elsif value.is_a? Array + value = ActionController::Routing::PathSegment::Result.new(value) + end + + if extra_keys.include?(key.to_sym) + non_path_parameters[key] = value + else + path_parameters[key.to_s] = value + end + end + + params = self.request_parameters.dup + + %w(controller action only_path).each do |k| + params.delete(k) + params.delete(k.to_sym) + end + + data = params.to_query + @env['CONTENT_LENGTH'] = data.length.to_s + @env['rack.input'] = StringIO.new(data) + end + + def recycle! + @formats = nil + @env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ } + @env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ } + @env['action_dispatch.request.query_parameters'] = {} + end + end + + class TestResponse < ActionDispatch::TestResponse + def recycle! + @status = 200 + @header = {} + @writer = lambda { |x| @body << x } + @block = nil + @length = 0 + @body = [] + @charset = nil + @content_type = nil + + @request = @template = nil + end + end + + class TestSession < ActionDispatch::Session::AbstractStore::SessionHash #:nodoc: + DEFAULT_OPTIONS = ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS + + def initialize(session = {}) + replace(session.stringify_keys) + @loaded = true + end + end + # Superclass for ActionController functional tests. Functional tests allow you to # test a single controller action per test method. This should not be confused with # integration tests (see ActionController::IntegrationTest), which are more like @@ -105,6 +175,73 @@ module ActionController class TestCase < ActiveSupport::TestCase include TestProcess + # Executes a request simulating GET HTTP method and set/volley the response + def get(action, parameters = nil, session = nil, flash = nil) + process(action, parameters, session, flash, "GET") + end + + # Executes a request simulating POST HTTP method and set/volley the response + def post(action, parameters = nil, session = nil, flash = nil) + process(action, parameters, session, flash, "POST") + end + + # Executes a request simulating PUT HTTP method and set/volley the response + def put(action, parameters = nil, session = nil, flash = nil) + process(action, parameters, session, flash, "PUT") + end + + # Executes a request simulating DELETE HTTP method and set/volley the response + def delete(action, parameters = nil, session = nil, flash = nil) + process(action, parameters, session, flash, "DELETE") + end + + # Executes a request simulating HEAD HTTP method and set/volley the response + def head(action, parameters = nil, session = nil, flash = nil) + process(action, parameters, session, flash, "HEAD") + end + + 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(', ') + returning __send__(request_method, action, parameters, session, flash) do + @request.env.delete 'HTTP_X_REQUESTED_WITH' + @request.env.delete 'HTTP_ACCEPT' + end + end + alias xhr :xml_http_request + + def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET') + # Sanity check for required instance variables so we can give an + # understandable error message. + %w(@controller @request @response).each do |iv_name| + if !(instance_variable_names.include?(iv_name) || instance_variable_names.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil? + raise "#{iv_name} is nil: make sure you set it in your test's setup method." + end + end + + @request.recycle! + @response.recycle! + @controller.response_body = nil + @controller.formats = nil + @controller.params = nil + + @html_document = nil + @request.env['REQUEST_METHOD'] = http_method + + parameters ||= {} + @request.assign_parameters(@controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters) + + @request.session = ActionController::TestSession.new(session) unless session.nil? + @request.session["flash"] = ActionController::Flash::FlashHash.new.update(flash) if flash + + @controller.request = @request + @controller.params.merge!(parameters) + build_request_uri(action, parameters) + Base.class_eval { include Testing } + @controller.process_with_new_base_test(@request, @response) + @response + end + include ActionDispatch::Assertions # When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline @@ -186,5 +323,16 @@ module ActionController def rescue_action_in_public! @request.remote_addr = '208.77.188.166' # example.com end + + private + def build_request_uri(action, parameters) + unless @request.env['REQUEST_URI'] + options = @controller.__send__(:rewrite_options, parameters) + options.update(:only_path => true, :action => action) + + url = ActionController::UrlRewriter.new(@request, parameters) + @request.request_uri = url.rewrite(options) + end + end end end diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 5bcd2143a3..38aaa6146e 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -31,18 +31,24 @@ module ActionDispatch autoload :Request, 'action_dispatch/http/request' autoload :Response, 'action_dispatch/http/response' autoload :StatusCodes, 'action_dispatch/http/status_codes' + autoload :Utils, 'action_dispatch/http/utils' autoload :Callbacks, 'action_dispatch/middleware/callbacks' + autoload :MiddlewareStack, 'action_dispatch/middleware/stack' autoload :ParamsParser, 'action_dispatch/middleware/params_parser' autoload :Rescue, 'action_dispatch/middleware/rescue' autoload :ShowExceptions, 'action_dispatch/middleware/show_exceptions' - autoload :MiddlewareStack, 'action_dispatch/middleware/stack' + autoload :Static, 'action_dispatch/middleware/static' - autoload :HTML, 'action_controller/vendor/html-scanner' autoload :Assertions, 'action_dispatch/testing/assertions' + autoload :Integration, 'action_dispatch/testing/integration' + autoload :IntegrationTest, 'action_dispatch/testing/integration' + autoload :PerformanceTest, 'action_dispatch/testing/performance_test' autoload :TestRequest, 'action_dispatch/testing/test_request' autoload :TestResponse, 'action_dispatch/testing/test_response' + autoload :HTML, 'action_controller/vendor/html-scanner' + module Http autoload :Headers, 'action_dispatch/http/headers' end diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index e457450059..3e3b473178 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -3,7 +3,7 @@ require 'active_support/core_ext/module/delegation' module ActionDispatch # :nodoc: # Represents an HTTP response generated by a controller action. One can use - # an ActionController::Response object to retrieve the current state + # an ActionDispatch::Response object to retrieve the current state # of the response, or customize the response. An Response object can # either represent a "real" HTTP response (i.e. one that is meant to be sent # back to the web browser) or a test response (i.e. one that is generated @@ -18,14 +18,14 @@ module ActionDispatch # :nodoc: # Nevertheless, integration tests may want to inspect controller responses in # more detail, and that's when Response can be useful for application # developers. Integration test methods such as - # ActionController::Integration::Session#get and - # ActionController::Integration::Session#post return objects of type + # ActionDispatch::Integration::Session#get and + # ActionDispatch::Integration::Session#post return objects of type # TestResponse (which are of course also of type Response). # # For example, the following demo integration "test" prints the body of the # controller response to the console: # - # class DemoControllerTest < ActionController::IntegrationTest + # class DemoControllerTest < ActionDispatch::IntegrationTest # def test_print_root_path_to_console # get('/') # puts @response.body diff --git a/actionpack/lib/action_dispatch/http/utils.rb b/actionpack/lib/action_dispatch/http/utils.rb new file mode 100644 index 0000000000..e04a39935e --- /dev/null +++ b/actionpack/lib/action_dispatch/http/utils.rb @@ -0,0 +1,20 @@ +module ActionDispatch + module Utils + # TODO: Pull this into rack core + # http://github.com/halorgium/rack/commit/feaf071c1de743fbd10bc316830180a9af607278 + def parse_config(config) + if config =~ /\.ru$/ + cfgfile = ::File.read(config) + if cfgfile[/^#\\(.*)/] + opts.parse! $1.split(/\s+/) + end + inner_app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app", + nil, config + else + require config + inner_app = Object.const_get(::File.basename(config, '.rb').capitalize) + end + end + module_function :parse_config + end +end diff --git a/actionpack/lib/action_dispatch/middleware/callbacks.rb b/actionpack/lib/action_dispatch/middleware/callbacks.rb index 2f86a382c2..56d6da1706 100644 --- a/actionpack/lib/action_dispatch/middleware/callbacks.rb +++ b/actionpack/lib/action_dispatch/middleware/callbacks.rb @@ -2,7 +2,7 @@ module ActionDispatch class Callbacks include ActiveSupport::NewCallbacks - define_callbacks :call, :terminator => "result == false", :scope => :kind + define_callbacks :call, :terminator => "result == false", :rescuable => true define_callbacks :prepare, :scope => :name # Add a preparation callback. Preparation callbacks are run before every @@ -25,10 +25,6 @@ module ActionDispatch set_callback(:call, :before, *args, &block) end - def self.around(*args, &block) - set_callback(:call, :around, *args, &block) - end - def self.after(*args, &block) set_callback(:call, :after, *args, &block) end @@ -36,7 +32,6 @@ module ActionDispatch class << self # DEPRECATED alias_method :before_dispatch, :before - alias_method :around_dispatch, :around alias_method :after_dispatch, :after end diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb index a8768633cc..c5c06f74a2 100644 --- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb @@ -2,6 +2,9 @@ require 'rack/utils' module ActionDispatch module Session + class SessionRestoreError < StandardError #:nodoc: + end + class AbstractStore ENV_SESSION_KEY = 'rack.session'.freeze ENV_SESSION_OPTIONS_KEY = 'rack.session.options'.freeze @@ -19,7 +22,7 @@ module ActionDispatch def session_id ActiveSupport::Deprecation.warn( - "ActionController::Session::AbstractStore::SessionHash#session_id " + + "ActionDispatch::Session::AbstractStore::SessionHash#session_id " + "has been deprecated. Please use request.session_options[:id] instead.", caller) @env[ENV_SESSION_OPTIONS_KEY][:id] end @@ -62,7 +65,7 @@ module ActionDispatch def data ActiveSupport::Deprecation.warn( - "ActionController::Session::AbstractStore::SessionHash#data " + + "ActionDispatch::Session::AbstractStore::SessionHash#data " + "has been deprecated. Please use #to_hash instead.", caller) to_hash end @@ -98,7 +101,7 @@ module ActionDispatch # Note that the regexp does not allow $1 to end with a ':' $1.constantize rescue LoadError, NameError => const_error - raise ActionController::SessionRestoreError, "Session contains objects whose class definition isn't available.\nRemember to require the classes for all objects kept in the session.\n(Original exception: #{const_error.message} [#{const_error.class}])\n" + raise ActionDispatch::SessionRestoreError, "Session contains objects whose class definition isn't available.\nRemember to require the classes for all objects kept in the session.\n(Original exception: #{const_error.message} [#{const_error.class}])\n" end retry diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb new file mode 100644 index 0000000000..d7e88a54e4 --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/static.rb @@ -0,0 +1,44 @@ +require 'rack/utils' + +module ActionDispatch + class Static + FILE_METHODS = %w(GET HEAD).freeze + + def initialize(app, root) + @app = app + @file_server = ::Rack::File.new(root) + end + + def call(env) + path = env['PATH_INFO'].chomp('/') + method = env['REQUEST_METHOD'] + + if FILE_METHODS.include?(method) + if file_exist?(path) + return @file_server.call(env) + else + cached_path = directory_exist?(path) ? "#{path}/index" : path + cached_path += ::ActionController::Base.page_cache_extension + + if file_exist?(cached_path) + env['PATH_INFO'] = cached_path + return @file_server.call(env) + end + end + end + + @app.call(env) + end + + private + def file_exist?(path) + full_path = File.join(@file_server.root, ::Rack::Utils.unescape(path)) + File.file?(full_path) && File.readable?(full_path) + end + + def directory_exist?(path) + full_path = File.join(@file_server.root, ::Rack::Utils.unescape(path)) + File.directory?(full_path) && File.readable?(full_path) + end + end +end diff --git a/actionpack/lib/action_controller/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 791f936f51..2c4a3a356d 100644 --- a/actionpack/lib/action_controller/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -2,9 +2,11 @@ require 'stringio' require 'uri' require 'active_support/test_case' require 'active_support/core_ext/object/metaclass' -require 'rack/test' -module ActionController +# TODO: Remove circular dependency on ActionController +require 'action_controller/testing/process' + +module ActionDispatch module Integration #:nodoc: module RequestHelpers # Performs a GET request with the given parameters. @@ -21,7 +23,7 @@ module ActionController # # This method returns an Response object, which one can use to # inspect the details of the response. Furthermore, if this method was - # called from an ActionController::IntegrationTest object, then that + # called from an ActionDispatch::IntegrationTest object, then that # object's <tt>@response</tt> instance variable will point to the same # response object. # @@ -166,8 +168,8 @@ module ActionController attr_accessor :request_count # Create and initialize a new Session instance. - def initialize(app = nil) - @app = app || ActionController::Dispatcher.new + def initialize(app) + @app = app reset! end @@ -191,11 +193,11 @@ module ActionController unless defined? @named_routes_configured # install the named routes in this session instance. klass = metaclass - Routing::Routes.install_helpers(klass) + ActionController::Routing::Routes.install_helpers(klass) # the helpers are made protected by default--we make them public for # easier access during testing and troubleshooting. - klass.module_eval { public *Routing::Routes.named_routes.helpers } + klass.module_eval { public *ActionController::Routing::Routes.named_routes.helpers } @named_routes_configured = true end end @@ -293,7 +295,7 @@ module ActionController "SERVER_PORT" => https? ? "443" : "80", "HTTPS" => https? ? "on" : "off" } - UrlRewriter.new(ActionDispatch::Request.new(env), {}) + ActionController::UrlRewriter.new(ActionDispatch::Request.new(env), {}) end end @@ -323,6 +325,10 @@ module ActionController end module Runner + def app + @app + end + # Reset the current session. This is useful for testing multiple sessions # in a single test case. def reset! @@ -352,7 +358,7 @@ module ActionController # can use this method to open multiple sessions that ought to be tested # simultaneously. def open_session(app = nil) - session = Integration::Session.new(app) + session = Integration::Session.new(app || self.app) # delegate the fixture accessors back to the test instance extras = Module.new { attr_accessor :delegate, :test_result } @@ -474,5 +480,21 @@ module ActionController # end class IntegrationTest < ActiveSupport::TestCase include Integration::Runner + + @@app = nil + + def self.app + # DEPRECATE Rails application fallback + # This should be set by the initializer + @@app || (defined?(Rails.application) && Rails.application.new) || nil + end + + def self.app=(app) + @@app = app + end + + def app + super || self.class.app + end end end diff --git a/actionpack/lib/action_controller/testing/performance_test.rb b/actionpack/lib/action_dispatch/testing/performance_test.rb index d88180087d..b1ed9d31f4 100644 --- a/actionpack/lib/action_controller/testing/performance_test.rb +++ b/actionpack/lib/action_dispatch/testing/performance_test.rb @@ -1,14 +1,14 @@ require 'active_support/testing/performance' require 'active_support/testing/default' -module ActionController +module ActionDispatch # An integration test that runs a code profiler on your test methods. # Profiling output for combinations of each test method, measurement, and # output format are written to your tmp/performance directory. # # By default, process_time is measured and both flat and graph_html output # formats are written, so you'll have two output files per test method. - class PerformanceTest < ActionController::IntegrationTest + class PerformanceTest < ActionDispatch::IntegrationTest include ActiveSupport::Testing::Performance include ActiveSupport::Testing::Default end diff --git a/actionpack/lib/action_dispatch/testing/test_response.rb b/actionpack/lib/action_dispatch/testing/test_response.rb index c35982e075..6d019023ce 100644 --- a/actionpack/lib/action_dispatch/testing/test_response.rb +++ b/actionpack/lib/action_dispatch/testing/test_response.rb @@ -1,6 +1,6 @@ module ActionDispatch - # Integration test methods such as ActionController::Integration::Session#get - # and ActionController::Integration::Session#post return objects of class + # Integration test methods such as ActionDispatch::Integration::Session#get + # and ActionDispatch::Integration::Session#post return objects of class # TestResponse, which represent the HTTP response results of the requested # controller actions. # diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb index 332743d55b..8a7a870b99 100644 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -26,8 +26,10 @@ module ActionView # 47 hrs, 59 mins, 29 secs <-> 29 days, 23 hrs, 59 mins, 29 secs # => [2..29] days # 29 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs # => about 1 month # 59 days, 23 hrs, 59 mins, 30 secs <-> 1 yr minus 1 sec # => [2..12] months - # 1 yr <-> 2 yrs minus 1 secs # => about 1 year - # 2 yrs <-> max time or date # => over [2..X] years + # 1 yr <-> 1 yr, 3 months # => about 1 year + # 1 yr, 3 months <-> 1 yr, 9 months # => over 1 year + # 1 yr, 9 months <-> 2 yr minus 1 sec # => almost 2 years + # 2 yrs <-> max time or date # => (same rules as 1 yr) # # With <tt>include_seconds</tt> = true and the difference < 1 minute 29 seconds: # 0-4 secs # => less than 5 seconds @@ -43,17 +45,18 @@ module ActionView # distance_of_time_in_words(from_time, 50.minutes.from_now) # => about 1 hour # distance_of_time_in_words(from_time, from_time + 15.seconds) # => less than a minute # distance_of_time_in_words(from_time, from_time + 15.seconds, true) # => less than 20 seconds - # distance_of_time_in_words(from_time, 3.years.from_now) # => over 3 years + # distance_of_time_in_words(from_time, 3.years.from_now) # => about 3 years # distance_of_time_in_words(from_time, from_time + 60.hours) # => about 3 days # distance_of_time_in_words(from_time, from_time + 45.seconds, true) # => less than a minute # distance_of_time_in_words(from_time, from_time - 45.seconds, true) # => less than a minute # distance_of_time_in_words(from_time, 76.seconds.from_now) # => 1 minute # distance_of_time_in_words(from_time, from_time + 1.year + 3.days) # => about 1 year - # distance_of_time_in_words(from_time, from_time + 4.years + 9.days + 30.minutes + 5.seconds) # => over 4 years + # distance_of_time_in_words(from_time, from_time + 3.years + 6.months) # => over 3 years + # distance_of_time_in_words(from_time, from_time + 4.years + 9.days + 30.minutes + 5.seconds) # => about 4 years # # to_time = Time.now + 6.years + 19.days - # distance_of_time_in_words(from_time, to_time, true) # => over 6 years - # distance_of_time_in_words(to_time, from_time, true) # => over 6 years + # distance_of_time_in_words(from_time, to_time, true) # => about 6 years + # distance_of_time_in_words(to_time, from_time, true) # => about 6 years # distance_of_time_in_words(Time.now, Time.now) # => less than a minute # def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false, options = {}) @@ -81,12 +84,21 @@ module ActionView when 2..44 then locale.t :x_minutes, :count => distance_in_minutes when 45..89 then locale.t :about_x_hours, :count => 1 when 90..1439 then locale.t :about_x_hours, :count => (distance_in_minutes.to_f / 60.0).round - when 1440..2879 then locale.t :x_days, :count => 1 - when 2880..43199 then locale.t :x_days, :count => (distance_in_minutes / 1440).round + when 1440..2529 then locale.t :x_days, :count => 1 + when 2530..43199 then locale.t :x_days, :count => (distance_in_minutes.to_f / 1440.0).round when 43200..86399 then locale.t :about_x_months, :count => 1 - when 86400..525599 then locale.t :x_months, :count => (distance_in_minutes / 43200).round - when 525600..1051199 then locale.t :about_x_years, :count => 1 - else locale.t :over_x_years, :count => (distance_in_minutes / 525600).round + when 86400..525599 then locale.t :x_months, :count => (distance_in_minutes.to_f / 43200.0).round + else + distance_in_years = distance_in_minutes / 525600 + minute_offset_for_leap_year = (distance_in_years / 4) * 1440 + remainder = ((distance_in_minutes - minute_offset_for_leap_year) % 525600) + if remainder < 131400 + locale.t(:about_x_years, :count => distance_in_years) + elsif remainder < 394200 + locale.t(:over_x_years, :count => distance_in_years) + else + locale.t(:almost_x_years, :count => distance_in_years + 1) + end end end end diff --git a/actionpack/lib/action_view/locale/en.yml b/actionpack/lib/action_view/locale/en.yml index c82cd07ec2..84d94fd700 100644 --- a/actionpack/lib/action_view/locale/en.yml +++ b/actionpack/lib/action_view/locale/en.yml @@ -91,6 +91,9 @@ over_x_years: one: "over 1 year" other: "over {{count}} years" + almost_x_years: + one: "almost 1 year" + other: "almost {{count}} years" prompts: year: "Year" month: "Month" diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index b0b75918b7..0cab035ede 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -89,6 +89,7 @@ module ActionView def _render_text(text, layout, options) text = layout.render(self, options[:locals]) { text } if layout + text end # This is the API to render a ViewContext's template from a controller. @@ -105,7 +106,7 @@ module ActionView def _render_template(template, layout = nil, options = {}, partial = nil) logger && logger.info do - msg = "Rendering #{template.identifier}" + msg = "Rendering #{template.inspect}" msg << " (#{options[:status]})" if options[:status] msg end @@ -123,7 +124,7 @@ module ActionView if layout @_layout = layout.identifier - logger.info("Rendering template within #{layout.identifier}") if logger + logger.info("Rendering template within #{layout.inspect}") if logger content = layout.render(self, locals) {|*name| _layout_for(*name) } end content diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb index 6e5093c5bd..aa21606f76 100644 --- a/actionpack/lib/action_view/template/error.rb +++ b/actionpack/lib/action_view/template/error.rb @@ -32,7 +32,7 @@ module ActionView def sub_template_message if @sub_templates "Trace of template inclusion: " + - @sub_templates.collect { |template| template.identifier }.join(", ") + @sub_templates.collect { |template| template.inspect }.join(", ") else "" end diff --git a/actionpack/lib/action_view/template/handlers/builder.rb b/actionpack/lib/action_view/template/handlers/builder.rb index ba0d17b5af..5f381f7bf0 100644 --- a/actionpack/lib/action_view/template/handlers/builder.rb +++ b/actionpack/lib/action_view/template/handlers/builder.rb @@ -6,7 +6,7 @@ module ActionView self.default_format = Mime::XML def compile(template) - require 'active_support/vendor/builder' + require 'builder' "xml = ::Builder::XmlMarkup.new(:indent => 2);" + "self.output_buffer = xml.target!;" + template.source + diff --git a/actionpack/lib/action_view/template/template.rb b/actionpack/lib/action_view/template/template.rb index 80c1bab7d5..0f64c23649 100644 --- a/actionpack/lib/action_view/template/template.rb +++ b/actionpack/lib/action_view/template/template.rb @@ -8,7 +8,7 @@ module ActionView class Template extend TemplateHandlers attr_reader :source, :identifier, :handler, :mime_type, :formats, :details - + def initialize(source, identifier, handler, details) @source = source @identifier = identifier @@ -25,7 +25,7 @@ module ActionView @formats << :html if format == :js @details[:formats] = Array.wrap(format.to_sym) end - + def render(view, locals, &block) ActiveSupport::Orchestra.instrument(:render_template, :identifier => identifier) do method_name = compile(locals, view) @@ -39,7 +39,7 @@ module ActionView raise TemplateError.new(self, view.assigns, e) end end - + # TODO: Figure out how to abstract this def variable_name @variable_name ||= identifier[%r'_?(\w+)(\.\w+)*$', 1].to_sym @@ -49,76 +49,83 @@ module ActionView def counter_name @counter_name ||= "#{variable_name}_counter".to_sym end - + # TODO: kill hax def partial? @details[:partial] end - private + def inspect + if defined?(Rails.root) + identifier.sub("#{Rails.root}/", '') + else + identifier + end + end - def compile(locals, view) - method_name = build_method_name(locals) - - return method_name if view.respond_to?(method_name) - - locals_code = locals.keys.map! { |key| "#{key} = local_assigns[:#{key}];" }.join + private + def compile(locals, view) + method_name = build_method_name(locals) - code = @handler.call(self) - if code.sub!(/\A(#.*coding.*)\n/, '') - encoding_comment = $1 - elsif defined?(Encoding) && Encoding.respond_to?(:default_external) - encoding_comment = "#coding:#{Encoding.default_external}" - end + return method_name if view.respond_to?(method_name) - source = <<-end_src - def #{method_name}(local_assigns) - old_output_buffer = output_buffer;#{locals_code};#{code} - ensure - self.output_buffer = old_output_buffer - end - end_src + locals_code = locals.keys.map! { |key| "#{key} = local_assigns[:#{key}];" }.join - if encoding_comment - source = "#{encoding_comment}\n#{source}" - line = -1 - else - line = 0 - end + code = @handler.call(self) + if code.sub!(/\A(#.*coding.*)\n/, '') + encoding_comment = $1 + elsif defined?(Encoding) && Encoding.respond_to?(:default_external) + encoding_comment = "#coding:#{Encoding.default_external}" + end - begin - ActionView::CompiledTemplates.module_eval(source, identifier, line) - method_name - rescue Exception => e # errors from template code - if logger = (view && view.logger) - logger.debug "ERROR: compiling #{method_name} RAISED #{e}" - logger.debug "Function body: #{source}" - logger.debug "Backtrace: #{e.backtrace.join("\n")}" + source = <<-end_src + def #{method_name}(local_assigns) + old_output_buffer = output_buffer;#{locals_code};#{code} + ensure + self.output_buffer = old_output_buffer + end + end_src + + if encoding_comment + source = "#{encoding_comment}\n#{source}" + line = -1 + else + line = 0 end - raise ActionView::TemplateError.new(self, {}, e) + begin + ActionView::CompiledTemplates.module_eval(source, identifier, line) + method_name + rescue Exception => e # errors from template code + if logger = (view && view.logger) + logger.debug "ERROR: compiling #{method_name} RAISED #{e}" + logger.debug "Function body: #{source}" + logger.debug "Backtrace: #{e.backtrace.join("\n")}" + end + + raise ActionView::TemplateError.new(self, {}, e) + end end - end - class LocalsKey - @hash_keys = Hash.new {|h,k| h[k] = Hash.new {|h,k| h[k] = {} } } + 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 + def self.get(*locals) + @hash_keys[*locals] ||= new(klass, format, locale) + end - attr_accessor :hash - def initialize(klass, format, locale) - @hash = locals.hash - end + attr_accessor :hash + def initialize(klass, format, locale) + @hash = locals.hash + end - alias_method :eql?, :equal? - end + alias_method :eql?, :equal? + end - def build_method_name(locals) - # TODO: is locals.keys.hash reliably the same? - @method_names[locals.keys.hash] ||= - "_render_template_#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_") - end + def build_method_name(locals) + # TODO: is locals.keys.hash reliably the same? + @method_names[locals.keys.hash] ||= + "_render_template_#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_") + end end end diff --git a/actionpack/lib/action_view/template/text.rb b/actionpack/lib/action_view/template/text.rb index 9f12e5e0a8..f7d0df5ba0 100644 --- a/actionpack/lib/action_view/template/text.rb +++ b/actionpack/lib/action_view/template/text.rb @@ -1,6 +1,5 @@ module ActionView #:nodoc: class TextTemplate < String #:nodoc: - def initialize(string, content_type = Mime[:html]) super(string.to_s) @content_type = Mime[content_type] || content_type @@ -10,14 +9,28 @@ module ActionView #:nodoc: {:formats => [@content_type.to_sym]} end - def identifier() self end - - def render(*) self end - - def mime_type() @content_type end + def identifier + self + end + + def inspect + 'inline template' + end + + def render(*args) + self + end - def formats() [mime_type] end + def mime_type + @content_type + end - def partial?() false end + def formats + [mime_type] + end + + def partial? + false + end end end diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index c2ccd1d3a5..441f462bc9 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -1,4 +1,5 @@ require 'active_support/test_case' +require 'action_controller/testing/test_case' module ActionView class Base @@ -23,12 +24,52 @@ module ActionView end class TestCase < ActiveSupport::TestCase + class TestController < ActionController::Base + attr_accessor :request, :response, :params + + def self.controller_path + '' + end + + def initialize + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + + @params = {} + end + end + include ActionDispatch::Assertions include ActionController::TestProcess include ActionView::Context + include ActionController::PolymorphicRoutes + include ActionController::RecordIdentifier + + include ActionView::Helpers + include ActionController::Helpers + class_inheritable_accessor :helper_class - @@helper_class = nil + attr_accessor :controller, :output_buffer, :rendered + + setup :setup_with_controller + def setup_with_controller + @controller = TestController.new + @output_buffer = '' + @rendered = '' + + self.class.send(:include_helper_modules!) + make_test_case_available_to_view! + end + + def render(options = {}, local_assigns = {}, &block) + @rendered << output = _view.render(options, local_assigns, &block) + output + end + + def protect_against_forgery? + false + end class << self def tests(helper_class) @@ -48,41 +89,75 @@ module ActionView rescue NameError nil end - end - include ActionView::Helpers - include ActionController::PolymorphicRoutes - include ActionController::RecordIdentifier - - setup :setup_with_helper_class - - def setup_with_helper_class - if helper_class && !self.class.ancestors.include?(helper_class) - self.class.send(:include, helper_class) + def helper_method(*methods) + # Almost a duplicate from ActionController::Helpers + methods.flatten.each do |method| + _helpers.module_eval <<-end_eval + def #{method}(*args, &block) # def current_user(*args, &block) + _test_case.send(%(#{method}), *args, &block) # test_case.send(%(current_user), *args, &block) + end # end + end_eval + end end - self.output_buffer = '' + private + def include_helper_modules! + helper(helper_class) if helper_class + include _helpers + end end - class TestController < ActionController::Base - attr_accessor :request, :response, :params + private + def make_test_case_available_to_view! + test_case_instance = self + _helpers.module_eval do + define_method(:_test_case) { test_case_instance } + private :_test_case + end + end - def initialize - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new + def _view + view = ActionView::Base.new(ActionController::Base.view_paths, _assigns, @controller) + view.class.send :include, _helpers + view + end - @params = {} + # Support the selector assertions + # + # Need to experiment if this priority is the best one: rendered => output_buffer + def response_from_page_or_rjs + HTML::Document.new(rendered.blank? ? output_buffer : rendered).root + end + + EXCLUDE_IVARS = %w{ + @output_buffer + @fixture_cache + @method_name + @_result + @loaded_fixtures + @test_passed + @view + } + + def _instance_variables + instance_variables - EXCLUDE_IVARS end - end - protected - attr_accessor :output_buffer + def _assigns + _instance_variables.inject({}) do |hash, var| + name = var[1..-1].to_sym + hash[name] = instance_variable_get(var) + hash + end + end - private def method_missing(selector, *args) - controller = TestController.new - return controller.__send__(selector, *args) if ActionController::Routing::Routes.named_routes.helpers.include?(selector) - super + if ActionController::Routing::Routes.named_routes.helpers.include?(selector) + @controller.__send__(selector, *args) + else + super + end end end end diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index b9293ffb9f..aef3dd6165 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -27,8 +27,6 @@ require 'action_view/base' require 'action_dispatch' require 'active_model' require 'fixture_template' -require 'action_controller/testing/process' -require 'action_controller/testing/integration' require 'action_view/test_case' require 'active_support/dependencies' @@ -54,6 +52,15 @@ ORIGINAL_LOCALES = I18n.available_locales.map {|locale| locale.to_s }.sort FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures') +class ActionController::IntegrationTest < ActiveSupport::TestCase + @@app = ActionDispatch::MiddlewareStack.new { |middleware| + middleware.use "ActionDispatch::ShowExceptions" + middleware.use "ActionDispatch::Callbacks" + middleware.use "ActionDispatch::ParamsParser" + middleware.use "Rack::Head" + }.build(ActionController::Routing::Routes) +end + module ActionView class TestCase setup do @@ -71,10 +78,6 @@ class Rack::TestCase < ActionController::IntegrationTest ActionController::Base.session_options[:secret] = ("*" * 30) end - def app - @app ||= ActionController::Dispatcher.new - end - def self.testing(klass = nil) if klass @testing = "/#{klass.name.underscore}".sub!(/_controller$/, '') @@ -120,12 +123,6 @@ class ::ApplicationController < ActionController::Base end module ActionController - Base.session = { - :key => '_testing_session', - :secret => '8273f16463985e2b3747dc25e30f2528' - } - Base.session_store = nil - class << Routing def possible_controllers @@possible_controllers ||= [] diff --git a/actionpack/test/activerecord/active_record_store_test.rb b/actionpack/test/activerecord/active_record_store_test.rb index 19d9c955a5..102b9cffdd 100644 --- a/actionpack/test/activerecord/active_record_store_test.rb +++ b/actionpack/test/activerecord/active_record_store_test.rb @@ -33,7 +33,6 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest def setup ActiveRecord::SessionStore.session_class.create_table! - reset_app! end def teardown @@ -120,21 +119,15 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest reset! - get '/set_session_value', :_session_id => session_id, :foo => "baz" - assert_response :success - assert_equal nil, cookies['_session_id'] - get '/get_session_value', :_session_id => session_id assert_response :success assert_equal 'foo: nil', response.body - assert_equal nil, cookies['_session_id'] + assert_not_equal session_id, cookies['_session_id'] end end def test_allows_session_fixation - with_test_route_set do - reset_with_fixation! - + with_test_route_set(:cookie_only => false) do get '/set_session_value' assert_response :success assert cookies['_session_id'] @@ -145,7 +138,7 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest session_id = cookies['_session_id'] assert session_id - reset_with_fixation! + reset! get '/set_session_value', :_session_id => session_id, :foo => "baz" assert_response :success @@ -159,24 +152,13 @@ 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 + def with_test_route_set(options = {}) with_routing do |set| set.draw do |map| - map.with_options :controller => "active_record_store_test/test" do |c| - c.connect "/:action" - end + map.connect "/:action", :controller => "active_record_store_test/test" end - reset_app! + @app = ActiveRecord::SessionStore.new(set, options.reverse_merge(:key => '_session_id')) + reset! yield end end diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index bd17df73c7..1a9f95e5e9 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -631,9 +631,8 @@ class FragmentCachingTest < ActionController::TestCase buffer = 'generated till now -> ' @controller.fragment_for(buffer, 'expensive') { fragment_computed = true } - assert_equal 2, listener.size - assert_equal :fragment_exist?, listener[0].name - assert_equal :write_fragment, listener[1].name + assert_equal 1, listener.count { |e| e.name == :fragment_exist? } + assert_equal 1, listener.count { |e| e.name == :write_fragment } assert fragment_computed assert_equal 'generated till now -> ', buffer diff --git a/actionpack/test/controller/dispatcher_test.rb b/actionpack/test/controller/dispatcher_test.rb index 150fc83cde..622d67287d 100644 --- a/actionpack/test/controller/dispatcher_test.rb +++ b/actionpack/test/controller/dispatcher_test.rb @@ -14,15 +14,12 @@ class DispatcherTest < Test::Unit::TestCase ActionDispatch::Callbacks.reset_callbacks(:prepare) ActionDispatch::Callbacks.reset_callbacks(:call) - @old_router, Dispatcher.router = Dispatcher.router, mock() - Dispatcher.router.stubs(:call).returns([200, {}, 'response']) - Dispatcher.router.stubs(:reload) + ActionController::Routing::Routes.stubs(:call).returns([200, {}, 'response']) + ActionController::Routing::Routes.stubs(:reload) Dispatcher.stubs(:require_dependency) end def teardown - Dispatcher.router = @old_router - @dispatcher = nil ENV.delete 'REQUEST_METHOD' end @@ -32,27 +29,22 @@ class DispatcherTest < Test::Unit::TestCase end def test_reloads_routes_before_dispatch_if_in_loading_mode - Dispatcher.router.expects(:reload).once + ActionController::Routing::Routes.expects(:reload).once dispatch(false) end def test_leaves_dependencies_after_dispatch_if_not_in_loading_mode - Dispatcher.router.expects(:reload).never + ActionController::Routing::Routes.expects(:reload).never ActiveSupport::Dependencies.expects(:clear).never dispatch end - # Stub out dispatch error logger - class << Dispatcher - def log_failsafe_exception(status, exception); end - end - def test_prepare_callbacks a = b = c = nil - Dispatcher.to_prepare { |*args| a = b = c = 1 } - Dispatcher.to_prepare { |*args| b = c = 2 } - Dispatcher.to_prepare { |*args| c = 3 } + ActionDispatch::Callbacks.to_prepare { |*args| a = b = c = 1 } + ActionDispatch::Callbacks.to_prepare { |*args| b = c = 2 } + ActionDispatch::Callbacks.to_prepare { |*args| c = 3 } # Ensure to_prepare callbacks are not run when defined assert_nil a || b || c @@ -71,8 +63,8 @@ class DispatcherTest < Test::Unit::TestCase end def test_to_prepare_with_identifier_replaces - Dispatcher.to_prepare(:unique_id) { |*args| Foo.a, Foo.b = 1, 1 } - Dispatcher.to_prepare(:unique_id) { |*args| Foo.a = 2 } + ActionDispatch::Callbacks.to_prepare(:unique_id) { |*args| Foo.a, Foo.b = 1, 1 } + ActionDispatch::Callbacks.to_prepare(:unique_id) { |*args| Foo.a = 2 } dispatch assert_equal 2, Foo.a @@ -83,12 +75,8 @@ class DispatcherTest < Test::Unit::TestCase def dispatch(cache_classes = true) ActionController::Dispatcher.prepare_each_request = false Dispatcher.define_dispatcher_callbacks(cache_classes) - Dispatcher.middleware = ActionDispatch::MiddlewareStack.new do |middleware| - middlewares = File.expand_path(File.join(File.dirname(__FILE__), "../../lib/action_controller/dispatch/middlewares.rb")) - middleware.instance_eval(File.read(middlewares)) - end - @dispatcher ||= Dispatcher.new + @dispatcher ||= ActionDispatch::Callbacks.new(ActionController::Routing::Routes) @dispatcher.call({'rack.input' => StringIO.new(''), 'action_dispatch.show_exceptions' => false}) end diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index 9f56bbfd46..0e4ca21143 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -1,4 +1,5 @@ require 'abstract_unit' +require 'controller/fake_controllers' require 'action_controller/vendor/html-scanner' class SessionTest < Test::Unit::TestCase @@ -363,6 +364,10 @@ class IntegrationProcessTest < ActionController::IntegrationTest end end + def test_generate_url_with_controller + assert_equal 'http://www.example.com/foo', url_for(:controller => "foo") + end + private def with_test_route_set with_routing do |set| @@ -389,7 +394,7 @@ class MetalIntegrationTest < ActionController::IntegrationTest end def setup - @integration_session = ActionController::Integration::Session.new(Poller) + @app = Poller end def test_successful_get @@ -406,4 +411,8 @@ class MetalIntegrationTest < ActionController::IntegrationTest assert_response :not_found assert_equal '', response.body end + + def test_generate_url_without_controller + assert_equal 'http://www.example.com/foo', url_for(:controller => "foo") + end end diff --git a/actionpack/test/controller/logging_test.rb b/actionpack/test/controller/logging_test.rb index 98ffbc3813..2b5e8d8bde 100644 --- a/actionpack/test/controller/logging_test.rb +++ b/actionpack/test/controller/logging_test.rb @@ -12,11 +12,11 @@ class LoggingTest < ActionController::TestCase class MockLogger attr_reader :logged attr_accessor :level - + def initialize @level = Logger::DEBUG end - + def method_missing(method, *args, &blk) @logged ||= [] @logged << args.first @@ -31,25 +31,24 @@ class LoggingTest < ActionController::TestCase def test_logging_without_parameters get :show - assert_equal 2, logs.size + assert_equal 3, logs.size assert_nil logs.detect {|l| l =~ /Parameters/ } end def test_logging_with_parameters get :show, :id => '10' - assert_equal 3, logs.size + assert_equal 4, logs.size params = logs.detect {|l| l =~ /Parameters/ } assert_equal 'Parameters: {"id"=>"10"}', params end - + private + def set_logger + @controller.logger = MockLogger.new + end - def set_logger - @controller.logger = MockLogger.new - end - - def logs - @logs ||= @controller.logger.logged.compact.map {|l| l.to_s.strip} - end + def logs + @logs ||= @controller.logger.logged.compact.map {|l| l.to_s.strip} + end end diff --git a/actionpack/test/controller/rescue_test.rb b/actionpack/test/controller/rescue_test.rb index 09eddfe4a7..6ad708bba1 100644 --- a/actionpack/test/controller/rescue_test.rb +++ b/actionpack/test/controller/rescue_test.rb @@ -326,19 +326,16 @@ class RescueTest < ActionController::IntegrationTest end test 'rescue routing exceptions' do - app = ActionDispatch::Rescue.new(ActionController::Routing::Routes) do + @app = ActionDispatch::Rescue.new(ActionController::Routing::Routes) do rescue_from ActionController::RoutingError, lambda { |env| [200, {"Content-Type" => "text/html"}, "Gotcha!"] } end - @integration_session = open_session(app) get '/b00m' assert_equal "Gotcha!", response.body end test 'unrescued exception' do - app = ActionDispatch::Rescue.new(ActionController::Routing::Routes) - @integration_session = open_session(app) - + @app = ActionDispatch::Rescue.new(ActionController::Routing::Routes) assert_raise(ActionController::RoutingError) { get '/b00m' } end diff --git a/actionpack/test/controller/webservice_test.rb b/actionpack/test/controller/webservice_test.rb index 916124e221..c04d20fbad 100644 --- a/actionpack/test/controller/webservice_test.rb +++ b/actionpack/test/controller/webservice_test.rb @@ -245,8 +245,8 @@ class WebServiceTest < ActionController::IntegrationTest private def with_params_parsers(parsers = {}) old_session = @integration_session - app = ActionDispatch::ParamsParser.new(ActionController::Routing::Routes, parsers) - @integration_session = open_session(app) + @app = ActionDispatch::ParamsParser.new(ActionController::Routing::Routes, parsers) + reset! yield ensure @integration_session = old_session diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb index d695be0be4..6241c79829 100644 --- a/actionpack/test/dispatch/session/cookie_store_test.rb +++ b/actionpack/test/dispatch/session/cookie_store_test.rb @@ -5,9 +5,6 @@ class CookieStoreTest < ActionController::IntegrationTest SessionKey = '_myapp_session' SessionSecret = 'b3c631c314c0bbca50c1b2843150fe33' - # Make sure Session middleware doesnt get included in the middleware stack - ActionController::Base.session_store = nil - Verifier = ActiveSupport::MessageVerifier.new(SessionSecret, 'SHA1') SignedBar = Verifier.generate(:foo => "bar", :session_id => ActiveSupport::SecureRandom.hex(16)) @@ -46,10 +43,6 @@ class CookieStoreTest < ActionController::IntegrationTest def rescue_action(e) raise end end - def setup - reset_app! - end - def test_raises_argument_error_if_missing_session_key assert_raise(ArgumentError, nil.inspect) { ActionDispatch::Session::CookieStore.new(nil, @@ -193,10 +186,7 @@ class CookieStoreTest < ActionController::IntegrationTest end def test_session_store_with_expire_after - 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) - + with_test_route_set(:expire_after => 5.hours) do # First request accesses the session time = Time.local(2008, 4, 24) Time.stubs(:now).returns(time) @@ -226,20 +216,14 @@ 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 + def with_test_route_set(options = {}) with_routing do |set| set.draw do |map| - map.with_options :controller => "cookie_store_test/test" do |c| - c.connect "/:action" - end + map.connect "/:action", :controller => "cookie_store_test/test" end - reset_app! + options = {:key => SessionKey, :secret => SessionSecret}.merge(options) + @app = ActionDispatch::Session::CookieStore.new(set, options) + reset! 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 1588918be7..c2d40ae24a 100644 --- a/actionpack/test/dispatch/session/mem_cache_store_test.rb +++ b/actionpack/test/dispatch/session/mem_cache_store_test.rb @@ -32,7 +32,9 @@ class MemCacheStoreTest < ActionController::IntegrationTest end begin - App = ActionDispatch::Session::MemCacheStore.new(ActionController::Dispatcher.new, :key => '_session_id') + require 'memcache' + memcache = MemCache.new('localhost:11211') + memcache.set('ping', '') def test_setting_and_getting_session_value with_test_route_set do @@ -99,7 +101,7 @@ class MemCacheStoreTest < ActionController::IntegrationTest get '/set_session_value', :_session_id => session_id assert_response :success - assert_equal nil, cookies['_session_id'] + assert_not_equal session_id, cookies['_session_id'] end end rescue LoadError, RuntimeError @@ -107,20 +109,13 @@ 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| - map.with_options :controller => "mem_cache_store_test/test" do |c| - c.connect "/:action" - end + map.connect "/:action", :controller => "mem_cache_store_test/test" end - reset_app! + @app = ActionDispatch::Session::MemCacheStore.new(set, :key => '_session_id') + reset! yield end end diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb index d4800e4edb..9f6a93756c 100644 --- a/actionpack/test/dispatch/show_exceptions_test.rb +++ b/actionpack/test/dispatch/show_exceptions_test.rb @@ -35,7 +35,7 @@ class ShowExceptionsTest < ActionController::IntegrationTest DevelopmentApp = ActionDispatch::ShowExceptions.new(Boomer, true) test "rescue in public from a remote ip" do - @integration_session = open_session(ProductionApp) + @app = ProductionApp self.remote_addr = '208.77.188.166' get "/" @@ -52,7 +52,7 @@ class ShowExceptionsTest < ActionController::IntegrationTest end test "rescue locally from a local request" do - @integration_session = open_session(ProductionApp) + @app = ProductionApp self.remote_addr = '127.0.0.1' get "/" @@ -73,7 +73,7 @@ class ShowExceptionsTest < ActionController::IntegrationTest old_locale, I18n.locale = I18n.locale, :da begin - @integration_session = open_session(ProductionApp) + @app = ProductionApp self.remote_addr = '208.77.188.166' get "/" @@ -89,7 +89,7 @@ class ShowExceptionsTest < ActionController::IntegrationTest end test "always rescue locally in development mode" do - @integration_session = open_session(DevelopmentApp) + @app = DevelopmentApp self.remote_addr = '208.77.188.166' get "/" diff --git a/actionpack/test/dispatch/static_test.rb b/actionpack/test/dispatch/static_test.rb new file mode 100644 index 0000000000..e6957bb0ea --- /dev/null +++ b/actionpack/test/dispatch/static_test.rb @@ -0,0 +1,35 @@ +require 'abstract_unit' + +class StaticTest < ActiveSupport::TestCase + DummyApp = lambda { |env| + [200, {"Content-Type" => "text/plain"}, ["Hello, World!"]] + } + App = ActionDispatch::Static.new(DummyApp, "#{FIXTURE_LOAD_PATH}/public") + + test "serves dynamic content" do + assert_equal "Hello, World!", get("/nofile") + end + + test "serves static index at root" do + assert_equal "/index.html", get("/index.html") + assert_equal "/index.html", get("/index") + assert_equal "/index.html", get("/") + end + + test "serves static file in directory" do + assert_equal "/foo/bar.html", get("/foo/bar.html") + assert_equal "/foo/bar.html", get("/foo/bar/") + assert_equal "/foo/bar.html", get("/foo/bar") + end + + test "serves static index file in directory" do + assert_equal "/foo/index.html", get("/foo/index.html") + assert_equal "/foo/index.html", get("/foo/") + assert_equal "/foo/index.html", get("/foo") + end + + private + def get(path) + Rack::MockRequest.new(App).request("GET", path).body + end +end diff --git a/actionpack/test/fixtures/public/foo/bar.html b/actionpack/test/fixtures/public/foo/bar.html new file mode 100644 index 0000000000..9a35646205 --- /dev/null +++ b/actionpack/test/fixtures/public/foo/bar.html @@ -0,0 +1 @@ +/foo/bar.html
\ No newline at end of file diff --git a/actionpack/test/fixtures/public/foo/index.html b/actionpack/test/fixtures/public/foo/index.html new file mode 100644 index 0000000000..497a2e898f --- /dev/null +++ b/actionpack/test/fixtures/public/foo/index.html @@ -0,0 +1 @@ +/foo/index.html
\ No newline at end of file diff --git a/actionpack/test/fixtures/public/index.html b/actionpack/test/fixtures/public/index.html new file mode 100644 index 0000000000..525950ba6b --- /dev/null +++ b/actionpack/test/fixtures/public/index.html @@ -0,0 +1 @@ +/index.html
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/_from_helper.erb b/actionpack/test/fixtures/test/_from_helper.erb new file mode 100644 index 0000000000..16de7c0f8a --- /dev/null +++ b/actionpack/test/fixtures/test/_from_helper.erb @@ -0,0 +1 @@ +<%= render_from_helper %>
\ No newline at end of file diff --git a/actionpack/test/template/active_record_helper_test.rb b/actionpack/test/template/active_record_helper_test.rb index ec3384f15d..c149070f2a 100644 --- a/actionpack/test/template/active_record_helper_test.rb +++ b/actionpack/test/template/active_record_helper_test.rb @@ -185,7 +185,7 @@ class ActiveRecordHelperTest < ActionView::TestCase end def test_form_with_action_option - @response.body = form("post", :action => "sign") + output_buffer << form("post", :action => "sign") assert_select "form[action=sign]" do |form| assert_select "input[type=submit][value=Sign]" end diff --git a/actionpack/test/template/benchmark_helper_test.rb b/actionpack/test/template/benchmark_helper_test.rb index 5d2af7cdd9..ac31fc6503 100644 --- a/actionpack/test/template/benchmark_helper_test.rb +++ b/actionpack/test/template/benchmark_helper_test.rb @@ -4,14 +4,14 @@ require 'action_view/helpers/benchmark_helper' class BenchmarkHelperTest < ActionView::TestCase tests ActionView::Helpers::BenchmarkHelper - def teardown - controller.logger.send(:clear_buffer) + def setup + super + controller.logger = ActiveSupport::BufferedLogger.new(StringIO.new) + controller.logger.auto_flushing = false end - def controller - logger = ActiveSupport::BufferedLogger.new(StringIO.new) - logger.auto_flushing = false - @controller ||= Struct.new(:logger).new(logger) + def teardown + controller.logger.send(:clear_buffer) end def test_without_block diff --git a/actionpack/test/template/date_helper_i18n_test.rb b/actionpack/test/template/date_helper_i18n_test.rb index bc011f59b8..b69a449617 100644 --- a/actionpack/test/template/date_helper_i18n_test.rb +++ b/actionpack/test/template/date_helper_i18n_test.rb @@ -20,15 +20,16 @@ class DateHelperDistanceOfTimeInWordsI18nTests < Test::Unit::TestCase [60.seconds, true] => [:'x_minutes', 1], # without include_seconds - [29.seconds, false] => [:'less_than_x_minutes', 1], - [60.seconds, false] => [:'x_minutes', 1], - [44.minutes, false] => [:'x_minutes', 44], - [61.minutes, false] => [:'about_x_hours', 1], - [24.hours, false] => [:'x_days', 1], - [30.days, false] => [:'about_x_months', 1], - [60.days, false] => [:'x_months', 2], - [1.year, false] => [:'about_x_years', 1], - [3.years, false] => [:'over_x_years', 3] + [29.seconds, false] => [:'less_than_x_minutes', 1], + [60.seconds, false] => [:'x_minutes', 1], + [44.minutes, false] => [:'x_minutes', 44], + [61.minutes, false] => [:'about_x_hours', 1], + [24.hours, false] => [:'x_days', 1], + [30.days, false] => [:'about_x_months', 1], + [60.days, false] => [:'x_months', 2], + [1.year, false] => [:'about_x_years', 1], + [3.years + 6.months, false] => [:'over_x_years', 3], + [3.years + 10.months, false] => [:'almost_x_years', 4] }.each do |passed, expected| assert_distance_of_time_in_words_translates_key passed, expected diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb index 2e4763f446..9fb2080f77 100644 --- a/actionpack/test/template/date_helper_test.rb +++ b/actionpack/test/template/date_helper_test.rb @@ -53,13 +53,14 @@ class DateHelperTest < ActionView::TestCase assert_equal "about 2 hours", distance_of_time_in_words(from, to + 89.minutes + 30.seconds) assert_equal "about 24 hours", distance_of_time_in_words(from, to + 23.hours + 59.minutes + 29.seconds) - # 1440..2879 + # 1440..2529 assert_equal "1 day", distance_of_time_in_words(from, to + 23.hours + 59.minutes + 30.seconds) - assert_equal "1 day", distance_of_time_in_words(from, to + 47.hours + 59.minutes + 29.seconds) + assert_equal "1 day", distance_of_time_in_words(from, to + 41.hours + 59.minutes + 29.seconds) - # 2880..43199 - assert_equal "2 days", distance_of_time_in_words(from, to + 47.hours + 59.minutes + 30.seconds) - assert_equal "29 days", distance_of_time_in_words(from, to + 29.days + 23.hours + 59.minutes + 29.seconds) + # 2530..43199 + assert_equal "2 days", distance_of_time_in_words(from, to + 42.hours + 59.minutes + 30.seconds) + assert_equal "3 days", distance_of_time_in_words(from, to + 2.days + 12.hours) + assert_equal "30 days", distance_of_time_in_words(from, to + 29.days + 23.hours + 59.minutes + 29.seconds) # 43200..86399 assert_equal "about 1 month", distance_of_time_in_words(from, to + 29.days + 23.hours + 59.minutes + 30.seconds) @@ -69,13 +70,28 @@ class DateHelperTest < ActionView::TestCase assert_equal "2 months", distance_of_time_in_words(from, to + 59.days + 23.hours + 59.minutes + 30.seconds) assert_equal "12 months", distance_of_time_in_words(from, to + 1.years - 31.seconds) - # 525600..1051199 - assert_equal "about 1 year", distance_of_time_in_words(from, to + 1.years - 30.seconds) - assert_equal "about 1 year", distance_of_time_in_words(from, to + 2.years - 31.seconds) - - # > 1051199 - assert_equal "over 2 years", distance_of_time_in_words(from, to + 2.years + 30.seconds) - assert_equal "over 10 years", distance_of_time_in_words(from, to + 10.years) + # > 525599 + assert_equal "about 1 year", distance_of_time_in_words(from, to + 1.years - 30.seconds) + assert_equal "about 1 year", distance_of_time_in_words(from, to + 1.years + 3.months - 1.day) + assert_equal "over 1 year", distance_of_time_in_words(from, to + 1.years + 6.months) + + assert_equal "almost 2 years", distance_of_time_in_words(from, to + 2.years - 3.months + 1.day) + assert_equal "about 2 years", distance_of_time_in_words(from, to + 2.years + 3.months - 1.day) + assert_equal "over 2 years", distance_of_time_in_words(from, to + 2.years + 3.months + 1.day) + assert_equal "over 2 years", distance_of_time_in_words(from, to + 2.years + 9.months - 1.day) + assert_equal "almost 3 years", distance_of_time_in_words(from, to + 2.years + 9.months + 1.day) + + assert_equal "almost 5 years", distance_of_time_in_words(from, to + 5.years - 3.months + 1.day) + assert_equal "about 5 years", distance_of_time_in_words(from, to + 5.years + 3.months - 1.day) + assert_equal "over 5 years", distance_of_time_in_words(from, to + 5.years + 3.months + 1.day) + assert_equal "over 5 years", distance_of_time_in_words(from, to + 5.years + 9.months - 1.day) + assert_equal "almost 6 years", distance_of_time_in_words(from, to + 5.years + 9.months + 1.day) + + assert_equal "almost 10 years", distance_of_time_in_words(from, to + 10.years - 3.months + 1.day) + assert_equal "about 10 years", distance_of_time_in_words(from, to + 10.years + 3.months - 1.day) + assert_equal "over 10 years", distance_of_time_in_words(from, to + 10.years + 3.months + 1.day) + assert_equal "over 10 years", distance_of_time_in_words(from, to + 10.years + 9.months - 1.day) + assert_equal "almost 11 years", distance_of_time_in_words(from, to + 10.years + 9.months + 1.day) # test to < from assert_equal "about 4 hours", distance_of_time_in_words(from + 4.hours, to) @@ -104,7 +120,7 @@ class DateHelperTest < ActionView::TestCase def test_distance_in_words_with_dates start_date = Date.new 1975, 1, 31 end_date = Date.new 1977, 1, 31 - assert_equal("over 2 years", distance_of_time_in_words(start_date, end_date)) + assert_equal("about 2 years", distance_of_time_in_words(start_date, end_date)) end def test_distance_in_words_with_integers diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb index f3cdab05bf..aa40e46aa8 100644 --- a/actionpack/test/template/form_options_helper_test.rb +++ b/actionpack/test/template/form_options_helper_test.rb @@ -1,5 +1,5 @@ require 'abstract_unit' -require 'active_support/vendor/tzinfo' +require 'tzinfo' TZInfo::Timezone.cattr_reader :loaded_zones diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index 447d520ef1..ce99482078 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -5,8 +5,6 @@ require 'controller/fake_controllers' RequestMock = Struct.new("Request", :request_uri, :protocol, :host_with_port, :env) class UrlHelperTest < ActionView::TestCase - tests ActionView::Helpers::UrlHelper - def setup super @controller = Class.new do @@ -386,9 +384,7 @@ class UrlHelperController < ActionController::Base def rescue_action(e) raise e end end -class UrlHelperWithControllerTest < ActionView::TestCase - tests ActionView::Helpers::UrlHelper - +class UrlHelperWithControllerTest < ActionController::TestCase def setup super @request = ActionController::TestRequest.new @@ -463,9 +459,7 @@ class TasksController < ActionController::Base end end -class LinkToUnlessCurrentWithControllerTest < ActionView::TestCase - tests ActionView::Helpers::UrlHelper - +class LinkToUnlessCurrentWithControllerTest < ActionController::TestCase def setup super @request = ActionController::TestRequest.new @@ -566,9 +560,7 @@ class SessionsController < ActionController::Base def rescue_action(e) raise e end end -class PolymorphicControllerTest < ActionView::TestCase - tests ActionView::Helpers::UrlHelper - +class PolymorphicControllerTest < ActionController::TestCase def setup super @request = ActionController::TestRequest.new diff --git a/actionpack/test/view/test_case_test.rb b/actionpack/test/view/test_case_test.rb index 9124198b28..3e974b87f7 100644 --- a/actionpack/test/view/test_case_test.rb +++ b/actionpack/test/view/test_case_test.rb @@ -1,8 +1,171 @@ require 'abstract_unit' -class TestCaseTest < ActionView::TestCase - def test_should_have_current_url - controller = TestController.new - assert_nothing_raised(NoMethodError){ controller.url_for({:controller => "foo", :action => "index"}) } +module ActionView + class TestCase + module ATestHelper + end + + module AnotherTestHelper + def from_another_helper + 'Howdy!' + end + end + + module ASharedTestHelper + def from_shared_helper + 'Holla!' + end + end + helper ASharedTestHelper + + module SharedTests + def self.included(test_case) + test_case.class_eval do + test "helpers defined on ActionView::TestCase are available" do + assert test_case.ancestors.include?(ASharedTestHelper) + assert 'Holla!', from_shared_helper + end + end + end + end + + class GeneralViewTest < ActionView::TestCase + include SharedTests + test_case = self + + test "works without testing a helper module" do + assert_equal 'Eloy', render('developers/developer', :developer => stub(:name => 'Eloy')) + end + + helper AnotherTestHelper + test "additional helper classes can be specified as in a controller" do + assert test_case.ancestors.include?(AnotherTestHelper) + assert 'Howdy!', from_another_helper + end + end + + class ClassMethodsTest < ActionView::TestCase + include SharedTests + test_case = self + + tests ATestHelper + test "tests the specified helper module" do + assert_equal ATestHelper, test_case.helper_class + assert test_case.ancestors.include?(ATestHelper) + end + + helper AnotherTestHelper + test "additional helper classes can be specified as in a controller" do + assert test_case.ancestors.include?(AnotherTestHelper) + assert 'Howdy!', from_another_helper + + test_case.helper_class.module_eval do + def render_from_helper + from_another_helper + end + end + assert 'Howdy!', render(:partial => 'test/from_helper') + end + end + + class ATestHelperTest < ActionView::TestCase + include SharedTests + test_case = self + + test "inflects the name of the helper module to test from the test case class" do + assert_equal ATestHelper, test_case.helper_class + assert test_case.ancestors.include?(ATestHelper) + end + + test "a configured test controller is available" do + assert_kind_of ActionController::Base, controller + assert_equal '', controller.controller_path + end + + test "helper class that is being tested is always included in view instance" do + self.class.helper_class.module_eval do + def render_from_helper + render :partial => 'customer', :collection => @customers + end + end + + TestController.stubs(:controller_path).returns('test') + + @customers = [stub(:name => 'Eloy'), stub(:name => 'Manfred')] + assert_match /Hello: EloyHello: Manfred/, render(:partial => 'test/from_helper') + end + + test "no additional helpers should shared across test cases" do + assert !test_case.ancestors.include?(AnotherTestHelper) + assert_raise(NoMethodError) { send :from_another_helper } + end + + test "is able to use routes" do + controller.request.assign_parameters('foo', 'index') + assert_equal '/foo', url_for + assert_equal '/bar', url_for(:controller => 'bar') + end + + test "is able to use named routes" do + with_routing do |set| + set.draw { |map| map.resources :contents } + assert_equal 'http://test.host/contents/new', new_content_url + assert_equal 'http://test.host/contents/1', content_url(:id => 1) + end + end + + test "named routes can be used from helper included in view" do + with_routing do |set| + set.draw { |map| map.resources :contents } + _helpers.module_eval do + def render_from_helper + new_content_url + end + end + + assert_equal 'http://test.host/contents/new', render(:partial => 'test/from_helper') + end + end + + test "is able to render partials with local variables" do + assert_equal 'Eloy', render('developers/developer', :developer => stub(:name => 'Eloy')) + assert_equal 'Eloy', render(:partial => 'developers/developer', + :locals => { :developer => stub(:name => 'Eloy') }) + end + + test "is able to render partials from templates and also use instance variables" do + TestController.stubs(:controller_path).returns('test') + + @customers = [stub(:name => 'Eloy'), stub(:name => 'Manfred')] + assert_match /Hello: EloyHello: Manfred/, render(:file => 'test/list') + end + + test "is able to make methods available to the view" do + _helpers.module_eval do + def render_from_helper; from_test_case end + end + assert_equal 'Word!', render(:partial => 'test/from_helper') + end + + def from_test_case; 'Word!'; end + helper_method :from_test_case + end + + class AssertionsTest < ActionView::TestCase + def render_from_helper + form_tag('/foo') do + concat render(:text => '<ul><li>foo</li></ul>') + end + end + helper_method :render_from_helper + + test "uses the output_buffer for assert_select" do + render(:partial => 'test/from_helper') + + assert_select 'form' do + assert_select 'li', :text => 'foo' + end + end + end end end |