aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--actionmailer/lib/action_mailer/base.rb65
-rw-r--r--actionmailer/test/abstract_unit.rb1
-rw-r--r--actionmailer/test/mail_service_test.rb26
-rw-r--r--actionpack/Rakefile2
-rw-r--r--actionpack/lib/action_controller.rb98
-rw-r--r--actionpack/lib/action_controller/abstract.rb10
-rw-r--r--actionpack/lib/action_controller/abstract/base.rb41
-rw-r--r--actionpack/lib/action_controller/abstract/callbacks.rb40
-rw-r--r--actionpack/lib/action_controller/abstract/exceptions.rb3
-rw-r--r--actionpack/lib/action_controller/abstract/helpers.rb59
-rw-r--r--actionpack/lib/action_controller/abstract/layouts.rb82
-rw-r--r--actionpack/lib/action_controller/abstract/logger.rb7
-rw-r--r--actionpack/lib/action_controller/abstract/renderer.rb58
-rw-r--r--actionpack/lib/action_controller/base/base.rb (renamed from actionpack/lib/action_controller/base.rb)559
-rw-r--r--actionpack/lib/action_controller/base/chained/benchmarking.rb (renamed from actionpack/lib/action_controller/benchmarking.rb)2
-rw-r--r--actionpack/lib/action_controller/base/chained/filters.rb (renamed from actionpack/lib/action_controller/filters.rb)0
-rw-r--r--actionpack/lib/action_controller/base/chained/flash.rb (renamed from actionpack/lib/action_controller/flash.rb)0
-rw-r--r--actionpack/lib/action_controller/base/cookies.rb (renamed from actionpack/lib/action_controller/cookies.rb)0
-rw-r--r--actionpack/lib/action_controller/base/helpers.rb (renamed from actionpack/lib/action_controller/helpers.rb)0
-rw-r--r--actionpack/lib/action_controller/base/http_authentication.rb (renamed from actionpack/lib/action_controller/http_authentication.rb)0
-rw-r--r--actionpack/lib/action_controller/base/layout.rb (renamed from actionpack/lib/action_controller/layout.rb)151
-rw-r--r--actionpack/lib/action_controller/base/redirect.rb91
-rw-r--r--actionpack/lib/action_controller/base/render.rb390
-rw-r--r--actionpack/lib/action_controller/base/request_forgery_protection.rb (renamed from actionpack/lib/action_controller/request_forgery_protection.rb)0
-rw-r--r--actionpack/lib/action_controller/base/responder.rb42
-rw-r--r--actionpack/lib/action_controller/base/streaming.rb (renamed from actionpack/lib/action_controller/streaming.rb)0
-rw-r--r--actionpack/lib/action_controller/base/verification.rb (renamed from actionpack/lib/action_controller/verification.rb)0
-rw-r--r--actionpack/lib/action_controller/cgi/ext.rb (renamed from actionpack/lib/action_controller/cgi_ext.rb)6
-rw-r--r--actionpack/lib/action_controller/cgi/ext/cookie.rb (renamed from actionpack/lib/action_controller/cgi_ext/cookie.rb)0
-rw-r--r--actionpack/lib/action_controller/cgi/ext/query_extension.rb (renamed from actionpack/lib/action_controller/cgi_ext/query_extension.rb)0
-rw-r--r--actionpack/lib/action_controller/cgi/ext/stdinput.rb (renamed from actionpack/lib/action_controller/cgi_ext/stdinput.rb)0
-rw-r--r--actionpack/lib/action_controller/cgi/process.rb (renamed from actionpack/lib/action_controller/cgi_process.rb)2
-rw-r--r--actionpack/lib/action_controller/dispatch/dispatcher.rb (renamed from actionpack/lib/action_controller/dispatcher.rb)4
-rw-r--r--actionpack/lib/action_controller/dispatch/middlewares.rb (renamed from actionpack/lib/action_controller/middlewares.rb)6
-rw-r--r--actionpack/lib/action_controller/dispatch/rescue.rb (renamed from actionpack/lib/action_controller/rescue.rb)16
-rw-r--r--actionpack/lib/action_controller/dispatch/templates/rescues/_request_and_response.erb (renamed from actionpack/lib/action_controller/templates/rescues/_request_and_response.erb)0
-rw-r--r--actionpack/lib/action_controller/dispatch/templates/rescues/_trace.erb (renamed from actionpack/lib/action_controller/templates/rescues/_trace.erb)0
-rw-r--r--actionpack/lib/action_controller/dispatch/templates/rescues/diagnostics.erb (renamed from actionpack/lib/action_controller/templates/rescues/diagnostics.erb)5
-rw-r--r--actionpack/lib/action_controller/dispatch/templates/rescues/layout.erb (renamed from actionpack/lib/action_controller/templates/rescues/layout.erb)0
-rw-r--r--actionpack/lib/action_controller/dispatch/templates/rescues/missing_template.erb (renamed from actionpack/lib/action_controller/templates/rescues/missing_template.erb)0
-rw-r--r--actionpack/lib/action_controller/dispatch/templates/rescues/routing_error.erb (renamed from actionpack/lib/action_controller/templates/rescues/routing_error.erb)0
-rw-r--r--actionpack/lib/action_controller/dispatch/templates/rescues/template_error.erb (renamed from actionpack/lib/action_controller/templates/rescues/template_error.erb)0
-rw-r--r--actionpack/lib/action_controller/dispatch/templates/rescues/unknown_action.erb (renamed from actionpack/lib/action_controller/templates/rescues/unknown_action.erb)0
-rw-r--r--actionpack/lib/action_controller/mime/responds.rb (renamed from actionpack/lib/action_controller/mime_responds.rb)9
-rw-r--r--actionpack/lib/action_controller/new_base.rb7
-rw-r--r--actionpack/lib/action_controller/new_base/base.rb61
-rw-r--r--actionpack/lib/action_controller/new_base/hide_actions.rb31
-rw-r--r--actionpack/lib/action_controller/new_base/layouts.rb37
-rw-r--r--actionpack/lib/action_controller/new_base/renderer.rb62
-rw-r--r--actionpack/lib/action_controller/new_base/url_for.rb40
-rw-r--r--actionpack/lib/action_controller/record_identifier.rb2
-rw-r--r--actionpack/lib/action_controller/routing/generation/polymorphic_routes.rb (renamed from actionpack/lib/action_controller/polymorphic_routes.rb)0
-rw-r--r--actionpack/lib/action_controller/routing/generation/url_rewriter.rb (renamed from actionpack/lib/action_controller/url_rewriter.rb)0
-rw-r--r--actionpack/lib/action_controller/routing/resources.rb (renamed from actionpack/lib/action_controller/resources.rb)0
-rw-r--r--actionpack/lib/action_controller/routing/route_set.rb2
-rw-r--r--actionpack/lib/action_controller/session/management.rb (renamed from actionpack/lib/action_controller/session_management.rb)2
-rw-r--r--actionpack/lib/action_controller/testing/assertions/dom.rb (renamed from actionpack/lib/action_controller/assertions/dom_assertions.rb)0
-rw-r--r--actionpack/lib/action_controller/testing/assertions/model.rb (renamed from actionpack/lib/action_controller/assertions/model_assertions.rb)0
-rw-r--r--actionpack/lib/action_controller/testing/assertions/response.rb (renamed from actionpack/lib/action_controller/assertions/response_assertions.rb)4
-rw-r--r--actionpack/lib/action_controller/testing/assertions/routing.rb (renamed from actionpack/lib/action_controller/assertions/routing_assertions.rb)0
-rw-r--r--actionpack/lib/action_controller/testing/assertions/selector.rb (renamed from actionpack/lib/action_controller/assertions/selector_assertions.rb)0
-rw-r--r--actionpack/lib/action_controller/testing/assertions/tag.rb (renamed from actionpack/lib/action_controller/assertions/tag_assertions.rb)0
-rw-r--r--actionpack/lib/action_controller/testing/integration.rb (renamed from actionpack/lib/action_controller/integration.rb)6
-rw-r--r--actionpack/lib/action_controller/testing/performance.rb (renamed from actionpack/lib/action_controller/performance_test.rb)0
-rw-r--r--actionpack/lib/action_controller/testing/process.rb (renamed from actionpack/lib/action_controller/test_process.rb)4
-rw-r--r--actionpack/lib/action_controller/testing/test_case.rb (renamed from actionpack/lib/action_controller/test_case.rb)2
-rw-r--r--actionpack/lib/action_dispatch.rb64
-rw-r--r--actionpack/lib/action_dispatch/http/headers.rb (renamed from actionpack/lib/action_controller/headers.rb)2
-rw-r--r--actionpack/lib/action_dispatch/http/mime_type.rb (renamed from actionpack/lib/action_controller/mime_type.rb)14
-rw-r--r--actionpack/lib/action_dispatch/http/mime_types.rb (renamed from actionpack/lib/action_controller/mime_types.rb)0
-rwxr-xr-xactionpack/lib/action_dispatch/http/request.rb (renamed from actionpack/lib/action_controller/request.rb)48
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb (renamed from actionpack/lib/action_controller/response.rb)2
-rw-r--r--actionpack/lib/action_dispatch/http/status_codes.rb (renamed from actionpack/lib/action_controller/status_codes.rb)2
-rw-r--r--actionpack/lib/action_dispatch/middleware/failsafe.rb (renamed from actionpack/lib/action_controller/failsafe.rb)2
-rw-r--r--actionpack/lib/action_dispatch/middleware/params_parser.rb (renamed from actionpack/lib/action_controller/params_parser.rb)2
-rw-r--r--actionpack/lib/action_dispatch/middleware/rewindable_input.rb (renamed from actionpack/lib/action_controller/rewindable_input.rb)2
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/abstract_store.rb (renamed from actionpack/lib/action_controller/session/abstract_store.rb)2
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/cookie_store.rb (renamed from actionpack/lib/action_controller/session/cookie_store.rb)2
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb (renamed from actionpack/lib/action_controller/session/mem_cache_store.rb)2
-rw-r--r--actionpack/lib/action_dispatch/rack.rb3
-rw-r--r--actionpack/lib/action_dispatch/utils/middleware_stack.rb (renamed from actionpack/lib/action_controller/middleware_stack.rb)2
-rw-r--r--actionpack/lib/action_dispatch/utils/uploaded_file.rb (renamed from actionpack/lib/action_controller/uploaded_file.rb)2
-rw-r--r--actionpack/lib/action_view.rb21
-rw-r--r--actionpack/lib/action_view/base.rb94
-rw-r--r--actionpack/lib/action_view/helpers/prototype_helper.rb6
-rw-r--r--actionpack/lib/action_view/paths.rb42
-rw-r--r--actionpack/lib/action_view/reloadable_template.rb117
-rw-r--r--actionpack/lib/action_view/render/partials.rb (renamed from actionpack/lib/action_view/partials.rb)184
-rw-r--r--actionpack/lib/action_view/render/rendering.rb114
-rw-r--r--actionpack/lib/action_view/renderable_partial.rb47
-rw-r--r--actionpack/lib/action_view/template/error.rb (renamed from actionpack/lib/action_view/template_error.rb)0
-rw-r--r--actionpack/lib/action_view/template/handler.rb (renamed from actionpack/lib/action_view/template_handler.rb)0
-rw-r--r--actionpack/lib/action_view/template/handlers.rb (renamed from actionpack/lib/action_view/template_handlers.rb)6
-rw-r--r--actionpack/lib/action_view/template/handlers/builder.rb (renamed from actionpack/lib/action_view/template_handlers/builder.rb)0
-rw-r--r--actionpack/lib/action_view/template/handlers/erb.rb (renamed from actionpack/lib/action_view/template_handlers/erb.rb)2
-rw-r--r--actionpack/lib/action_view/template/handlers/rjs.rb (renamed from actionpack/lib/action_view/template_handlers/rjs.rb)2
-rw-r--r--actionpack/lib/action_view/template/inline.rb (renamed from actionpack/lib/action_view/inline_template.rb)0
-rw-r--r--actionpack/lib/action_view/template/partial.rb18
-rw-r--r--actionpack/lib/action_view/template/renderable.rb (renamed from actionpack/lib/action_view/renderable.rb)42
-rw-r--r--actionpack/lib/action_view/template/template.rb (renamed from actionpack/lib/action_view/template.rb)146
-rw-r--r--actionpack/lib/action_view/template/text.rb9
-rw-r--r--actionpack/lib/action_view/test_case.rb19
-rw-r--r--actionpack/test/abstract_controller/abstract_controller_test.rb226
-rw-r--r--actionpack/test/abstract_controller/callbacks_test.rb197
-rw-r--r--actionpack/test/abstract_controller/helper_test.rb43
-rw-r--r--actionpack/test/abstract_controller/layouts_test.rb232
-rw-r--r--actionpack/test/abstract_controller/test_helper.rb25
-rw-r--r--actionpack/test/abstract_controller/views/abstract_controller/testing/me3/formatted.html.erb1
-rw-r--r--actionpack/test/abstract_controller/views/abstract_controller/testing/me3/index.erb1
-rw-r--r--actionpack/test/abstract_controller/views/abstract_controller/testing/me4/index.erb1
-rw-r--r--actionpack/test/abstract_controller/views/abstract_controller/testing/me5/index.erb1
-rw-r--r--actionpack/test/abstract_controller/views/action_with_ivars.erb1
-rw-r--r--actionpack/test/abstract_controller/views/helper_test.erb1
-rw-r--r--actionpack/test/abstract_controller/views/index.erb1
-rw-r--r--actionpack/test/abstract_controller/views/layouts/abstract_controller/testing/me4.erb1
-rw-r--r--actionpack/test/abstract_controller/views/layouts/application.erb1
-rw-r--r--actionpack/test/abstract_controller/views/naked_render.erb1
-rw-r--r--actionpack/test/abstract_unit.rb7
-rw-r--r--actionpack/test/controller/action_pack_assertions_test.rb2
-rw-r--r--actionpack/test/controller/addresses_render_test.rb1
-rw-r--r--actionpack/test/controller/assert_select_test.rb2
-rw-r--r--actionpack/test/controller/base_test.rb2
-rw-r--r--actionpack/test/controller/benchmark_test.rb1
-rw-r--r--actionpack/test/controller/caching_test.rb4
-rw-r--r--actionpack/test/controller/capture_test.rb1
-rw-r--r--actionpack/test/controller/content_type_test.rb3
-rw-r--r--actionpack/test/controller/cookie_test.rb1
-rw-r--r--actionpack/test/controller/dispatcher_test.rb6
-rw-r--r--actionpack/test/controller/header_test.rb14
-rw-r--r--actionpack/test/controller/layout_test.rb48
-rw-r--r--actionpack/test/controller/logging_test.rb5
-rw-r--r--actionpack/test/controller/mime_responds_test.rb5
-rw-r--r--actionpack/test/controller/render_test.rb45
-rw-r--r--actionpack/test/controller/rescue_test.rb9
-rw-r--r--actionpack/test/controller/send_file_test.rb2
-rw-r--r--actionpack/test/controller/session/cookie_store_test.rb51
-rw-r--r--actionpack/test/controller/session/mem_cache_store_test.rb2
-rw-r--r--actionpack/test/controller/test_test.rb4
-rw-r--r--actionpack/test/controller/view_paths_test.rb4
-rw-r--r--actionpack/test/dispatch/header_test.rb16
-rw-r--r--actionpack/test/dispatch/middleware_stack_test.rb (renamed from actionpack/test/controller/middleware_stack_test.rb)2
-rw-r--r--actionpack/test/dispatch/mime_type_test.rb (renamed from actionpack/test/controller/mime_type_test.rb)51
-rw-r--r--actionpack/test/dispatch/rack_test.rb (renamed from actionpack/test/controller/rack_test.rb)67
-rw-r--r--actionpack/test/dispatch/request/json_params_parsing_test.rb (renamed from actionpack/test/controller/request/json_params_parsing_test.rb)0
-rw-r--r--actionpack/test/dispatch/request/multipart_params_parsing_test.rb (renamed from actionpack/test/controller/request/multipart_params_parsing_test.rb)2
-rw-r--r--actionpack/test/dispatch/request/query_string_parsing_test.rb (renamed from actionpack/test/controller/request/query_string_parsing_test.rb)0
-rw-r--r--actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb (renamed from actionpack/test/controller/request/url_encoded_params_parsing_test.rb)2
-rw-r--r--actionpack/test/dispatch/request/xml_params_parsing_test.rb (renamed from actionpack/test/controller/request/xml_params_parsing_test.rb)0
-rw-r--r--actionpack/test/dispatch/request_test.rb (renamed from actionpack/test/controller/request_test.rb)86
-rw-r--r--actionpack/test/fixtures/happy_path/render_action/hello_world.erb1
-rw-r--r--actionpack/test/fixtures/layout_tests/views/goodbye.rhtml1
-rw-r--r--actionpack/test/fixtures/layouts/default_html.html.erb1
-rw-r--r--actionpack/test/fixtures/test/backup_files/item.html.erb1
-rw-r--r--actionpack/test/fixtures/test/backup_files/item.html.erb.orig1
-rw-r--r--actionpack/test/fixtures/test/basic.html.erb1
-rw-r--r--actionpack/test/fixtures/test/render_implicit_js_template_without_layout.js.erb1
-rw-r--r--actionpack/test/lib/fixture_template.rb35
-rw-r--r--actionpack/test/new_base/base_test.rb90
-rw-r--r--actionpack/test/new_base/render_action_test.rb325
-rw-r--r--actionpack/test/new_base/render_implicit_action_test.rb16
-rw-r--r--actionpack/test/new_base/render_layout_test.rb45
-rw-r--r--actionpack/test/new_base/render_template_test.rb133
-rw-r--r--actionpack/test/new_base/render_text_test.rb144
-rw-r--r--actionpack/test/new_base/test_helper.rb144
-rwxr-xr-xactionpack/test/runner8
-rw-r--r--actionpack/test/template/active_record_helper_test.rb1
-rw-r--r--actionpack/test/template/asset_tag_helper_test.rb2
-rw-r--r--actionpack/test/template/atom_feed_helper_test.rb1
-rw-r--r--actionpack/test/template/compiled_templates_test.rb198
-rw-r--r--actionpack/test/template/form_helper_test.rb1
-rw-r--r--actionpack/test/template/form_tag_helper_test.rb1
-rw-r--r--actionpack/test/template/javascript_helper_test.rb3
-rw-r--r--actionpack/test/template/prototype_helper_test.rb3
-rw-r--r--actionpack/test/template/record_tag_helper_test.rb1
-rw-r--r--actionpack/test/template/render_test.rb82
-rw-r--r--actionpack/test/template/scriptaculous_helper_test.rb1
-rw-r--r--actionpack/test/template/template_test.rb34
-rw-r--r--actionpack/test/template/test_test.rb1
-rw-r--r--actionpack/test/template/text_helper_test.rb1
-rw-r--r--actionpack/test/template/url_helper_test.rb4
-rw-r--r--activerecord/lib/active_record/session_store.rb2
-rw-r--r--activesupport/lib/active_support.rb2
-rw-r--r--activesupport/lib/active_support/buffered_logger.rb16
-rw-r--r--activesupport/lib/active_support/callbacks.rb2
-rw-r--r--activesupport/lib/active_support/concurrent_hash.rb26
-rw-r--r--activesupport/lib/active_support/core_ext/class/attribute_accessors.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/class/delegating_attributes.rb10
-rw-r--r--activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb101
-rw-r--r--activesupport/lib/active_support/core_ext/module.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/module/attribute_accessors.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/module/setup.rb26
-rw-r--r--activesupport/lib/active_support/core_ext/proc.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/string/multibyte.rb6
-rw-r--r--activesupport/lib/active_support/deprecation.rb2
-rw-r--r--activesupport/lib/active_support/memoizable.rb19
-rw-r--r--activesupport/lib/active_support/mini.rb9
-rw-r--r--activesupport/lib/active_support/multibyte/unicode_database.rb10
-rw-r--r--activesupport/lib/active_support/new_callbacks.rb485
-rw-r--r--activesupport/lib/active_support/test_case.rb2
-rw-r--r--activesupport/lib/active_support/testing/declarative.rb49
-rw-r--r--activesupport/lib/active_support/testing/pending.rb43
-rw-r--r--activesupport/lib/active_support/testing/setup_and_teardown.rb4
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb8
-rw-r--r--activesupport/test/memoizable_test.rb9
-rw-r--r--activesupport/test/new_callback_inheritance_test.rb115
-rw-r--r--activesupport/test/new_callbacks_test.rb384
-rw-r--r--ci/cruise_config.rb4
-rw-r--r--railties/environments/production.rb1
-rw-r--r--railties/environments/test.rb1
-rw-r--r--railties/lib/dispatcher.rb2
-rw-r--r--railties/lib/initializer.rb7
-rw-r--r--railties/test/initializer_test.rb8
-rw-r--r--railties/test/rails_info_controller_test.rb2
214 files changed, 5197 insertions, 1688 deletions
diff --git a/.gitignore b/.gitignore
index 5b3bd90098..d86af64569 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,7 @@ railties/pkg
railties/test/500.html
railties/doc/guides/html/images
railties/doc/guides/html/stylesheets
+benches
railties/guides/output
*.rbc
*.swp
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index b77409b64b..06610cf9bd 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -373,6 +373,14 @@ module ActionMailer #:nodoc:
attr_reader :mail
attr_reader :template_name, :default_template_name, :action_name
+ def controller_path
+ self.class.controller_path
+ end
+
+ def formats
+ @template.formats
+ end
+
class << self
attr_writer :mailer_name
@@ -466,7 +474,7 @@ module ActionMailer #:nodoc:
# have not already been specified manually.
if @parts.empty?
Dir.glob("#{template_path}/#{@template}.*").each do |path|
- template = template_root["#{mailer_name}/#{File.basename(path)}"]
+ template = template_root.find_template("#{mailer_name}/#{File.basename(path)}")
# Skip unless template has a multipart format
next unless template && template.multipart?
@@ -475,7 +483,7 @@ module ActionMailer #:nodoc:
:content_type => template.content_type,
:disposition => "inline",
:charset => charset,
- :body => render_message(template, @body)
+ :body => render_template(template, @body)
)
end
unless @parts.empty?
@@ -489,7 +497,7 @@ module ActionMailer #:nodoc:
# normal template exists (or if there were no implicit parts) we render
# it.
template_exists = @parts.empty?
- template_exists ||= template_root["#{mailer_name}/#{@template}"]
+ template_exists ||= template_root.find_template("#{mailer_name}/#{@template}")
@body = render_message(@template, @body) if template_exists
# Finally, if there are other message parts and a textual body exists,
@@ -514,6 +522,7 @@ module ActionMailer #:nodoc:
# no alternate has been given as the parameter, this will fail.
def deliver!(mail = @mail)
raise "no mail object available for delivery!" unless mail
+
unless logger.nil?
logger.info "Sent mail to #{Array(recipients).join(', ')}"
logger.debug "\n#{mail.encoded}"
@@ -545,27 +554,43 @@ module ActionMailer #:nodoc:
@mime_version = @@default_mime_version.dup if @@default_mime_version
end
- def render_message(method_name, body)
- if method_name.respond_to?(:content_type)
- @current_template_content_type = method_name.content_type
+ def render_template(template, body)
+ if template.respond_to?(:content_type)
+ @current_template_content_type = template.content_type
end
+
+ @template = initialize_template_class(body)
+ layout = _pick_layout(layout, true) unless template.exempt_from_layout?
+ @template._render_template_with_layout(template, layout, {})
+ ensure
+ @current_template_content_type = nil
+ end
+
+ def render_message(method_name, body)
render :file => method_name, :body => body
ensure
@current_template_content_type = nil
end
def render(opts)
- body = opts.delete(:body)
- if opts[:file] && (opts[:file] !~ /\// && !opts[:file].respond_to?(:render))
- opts[:file] = "#{mailer_name}/#{opts[:file]}"
- end
-
+ layout, file = opts.delete(:layout), opts[:file]
+
begin
- old_template, @template = @template, initialize_template_class(body)
- layout = respond_to?(:pick_layout, true) ? pick_layout(opts) : false
- @template.render(opts.merge(:layout => layout))
- ensure
- @template = old_template
+ @template = initialize_template_class(opts.delete(:body))
+
+ if file
+ prefix = mailer_name unless file =~ /\//
+ template = view_paths.find_by_parts(file, formats, prefix)
+ end
+
+ layout = _pick_layout(layout,
+ !template || !template.exempt_from_layout?)
+
+ if template
+ @template._render_template_with_layout(template, layout, opts)
+ elsif inline = opts[:inline]
+ @template._render_inline(inline, layout, opts)
+ end
end
end
@@ -577,12 +602,6 @@ module ActionMailer #:nodoc:
end
end
- def candidate_for_layout?(options)
- !self.view_paths.find_template(default_template_name, default_template_format).exempt_from_layout?
- rescue ActionView::MissingTemplate
- return true
- end
-
def template_root
self.class.template_root
end
@@ -597,7 +616,7 @@ module ActionMailer #:nodoc:
def initialize_template_class(assigns)
template = ActionView::Base.new(self.class.view_paths, assigns, self)
- template.template_format = default_template_format
+ template.formats = [default_template_format]
template
end
diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb
index 3e7725570f..51b375fef3 100644
--- a/actionmailer/test/abstract_unit.rb
+++ b/actionmailer/test/abstract_unit.rb
@@ -19,7 +19,6 @@ ActionView::Template.register_template_handler :bak, lambda { |template| "Lame b
$:.unshift "#{File.dirname(__FILE__)}/fixtures/helpers"
-ActionView::Base.cache_template_loading = true
FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
ActionMailer::Base.template_root = FIXTURE_LOAD_PATH
diff --git a/actionmailer/test/mail_service_test.rb b/actionmailer/test/mail_service_test.rb
index 277a91395d..b7d5fd5dd3 100644
--- a/actionmailer/test/mail_service_test.rb
+++ b/actionmailer/test/mail_service_test.rb
@@ -565,13 +565,31 @@ class ActionMailerTest < Test::Unit::TestCase
TestMailer.deliver_signed_up(@recipient)
end
+ class FakeLogger
+ attr_reader :info_contents, :debug_contents
+
+ def initialize
+ @info_contents, @debug_contents = "", ""
+ end
+
+ def info(str)
+ @info_contents << str
+ end
+
+ def debug(str)
+ @debug_contents << str
+ end
+ end
+
def test_delivery_logs_sent_mail
mail = TestMailer.create_signed_up(@recipient)
- logger = mock()
- logger.expects(:info).with("Sent mail to #{@recipient}")
- logger.expects(:debug).with("\n#{mail.encoded}")
- TestMailer.logger = logger
+ # logger = mock()
+ # logger.expects(:info).with("Sent mail to #{@recipient}")
+ # logger.expects(:debug).with("\n#{mail.encoded}")
+ TestMailer.logger = FakeLogger.new
TestMailer.deliver_signed_up(@recipient)
+ assert(TestMailer.logger.info_contents =~ /Sent mail to #{@recipient}/)
+ assert_equal(TestMailer.logger.debug_contents, "\n#{mail.encoded}")
end
def test_unquote_quoted_printable_subject
diff --git a/actionpack/Rakefile b/actionpack/Rakefile
index 6cacdf3c6e..300c2ebf81 100644
--- a/actionpack/Rakefile
+++ b/actionpack/Rakefile
@@ -30,7 +30,7 @@ Rake::TestTask.new(:test_action_pack) do |t|
# make sure we include the tests in alphabetical order as on some systems
# this will not happen automatically and the tests (as a whole) will error
- t.test_files = Dir.glob( "test/[cft]*/**/*_test.rb" ).sort
+ t.test_files = Dir.glob( "test/[cdft]*/**/*_test.rb" ).sort
t.verbose = true
#t.warning = true
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb
index d03f4cb231..e435bdbae1 100644
--- a/actionpack/lib/action_controller.rb
+++ b/actionpack/lib/action_controller.rb
@@ -31,6 +31,8 @@ rescue LoadError
end
end
+require File.join(File.dirname(__FILE__), "action_pack")
+$:.unshift "#{File.dirname(__FILE__)}/action_controller/vendor/rack-1.0"
begin
gem 'rack', '~> 1.0.0'
require 'rack'
@@ -42,75 +44,57 @@ module ActionController
# TODO: Review explicit to see if they will automatically be handled by
# the initilizer if they are really needed.
def self.load_all!
- [Base, CGIHandler, CgiRequest, Request, Response, Http::Headers, UrlRewriter, UrlWriter]
+ [Base, Request, Response, UrlRewriter, UrlWriter]
+ [ActionDispatch::Http::Headers]
end
- autoload :AbstractRequest, 'action_controller/request'
- autoload :Base, 'action_controller/base'
- autoload :Benchmarking, 'action_controller/benchmarking'
+ autoload :Base, 'action_controller/base/base'
+ autoload :Benchmarking, 'action_controller/base/chained/benchmarking'
autoload :Caching, 'action_controller/caching'
- autoload :Cookies, 'action_controller/cookies'
- autoload :Dispatcher, 'action_controller/dispatcher'
- autoload :Failsafe, 'action_controller/failsafe'
- autoload :Filters, 'action_controller/filters'
- autoload :Flash, 'action_controller/flash'
- autoload :Helpers, 'action_controller/helpers'
- autoload :HttpAuthentication, 'action_controller/http_authentication'
- autoload :Integration, 'action_controller/integration'
- autoload :IntegrationTest, 'action_controller/integration'
- autoload :Layout, 'action_controller/layout'
- autoload :MiddlewareStack, 'action_controller/middleware_stack'
- autoload :MimeResponds, 'action_controller/mime_responds'
- autoload :ParamsParser, 'action_controller/params_parser'
- autoload :PolymorphicRoutes, 'action_controller/polymorphic_routes'
+ autoload :Cookies, 'action_controller/base/cookies'
+ autoload :Dispatcher, 'action_controller/dispatch/dispatcher'
+ autoload :Filters, 'action_controller/base/chained/filters'
+ autoload :Flash, 'action_controller/base/chained/flash'
+ autoload :Helpers, 'action_controller/base/helpers'
+ autoload :HttpAuthentication, 'action_controller/base/http_authentication'
+ autoload :Integration, 'action_controller/testing/integration'
+ autoload :IntegrationTest, 'action_controller/testing/integration'
+ autoload :Layout, 'action_controller/base/layout'
+ autoload :MimeResponds, 'action_controller/mime/responds'
+ autoload :PolymorphicRoutes, 'action_controller/routing/generation/polymorphic_routes'
autoload :RecordIdentifier, 'action_controller/record_identifier'
+ autoload :Redirector, 'action_controller/base/redirect'
autoload :Reloader, 'action_controller/reloader'
- autoload :Request, 'action_controller/request'
- autoload :RequestForgeryProtection, 'action_controller/request_forgery_protection'
- autoload :Rescue, 'action_controller/rescue'
- autoload :Resources, 'action_controller/resources'
- autoload :Response, 'action_controller/response'
- autoload :RewindableInput, 'action_controller/rewindable_input'
+ autoload :Renderer, 'action_controller/base/render'
+ autoload :RequestForgeryProtection, 'action_controller/base/request_forgery_protection'
+ autoload :Rescue, 'action_controller/dispatch/rescue'
+ autoload :Resources, 'action_controller/routing/resources'
+ autoload :Responder, 'action_controller/base/responder'
autoload :Routing, 'action_controller/routing'
- autoload :SessionManagement, 'action_controller/session_management'
- autoload :StatusCodes, 'action_controller/status_codes'
- autoload :Streaming, 'action_controller/streaming'
- autoload :TestCase, 'action_controller/test_case'
- autoload :TestProcess, 'action_controller/test_process'
+ autoload :SessionManagement, 'action_controller/session/management'
+ autoload :Streaming, 'action_controller/base/streaming'
+ autoload :TestCase, 'action_controller/testing/test_case'
+ autoload :TestProcess, 'action_controller/testing/process'
autoload :Translation, 'action_controller/translation'
- autoload :UploadedFile, 'action_controller/uploaded_file'
- autoload :UploadedStringIO, 'action_controller/uploaded_file'
- autoload :UploadedTempfile, 'action_controller/uploaded_file'
- autoload :UrlRewriter, 'action_controller/url_rewriter'
- autoload :UrlWriter, 'action_controller/url_rewriter'
- autoload :Verification, 'action_controller/verification'
+ autoload :UrlEncodedPairParser, 'action_controller/dispatch/url_encoded_pair_parser'
+ autoload :UrlRewriter, 'action_controller/routing/generation/url_rewriter'
+ autoload :UrlWriter, 'action_controller/routing/generation/url_rewriter'
+ autoload :Verification, 'action_controller/base/verification'
+ autoload :UploadedFile, 'action_dispatch/utils/uploaded_file'
+ autoload :UploadedStringIO, 'action_dispatch/utils/uploaded_file'
+ autoload :UploadedTempfile, 'action_dispatch/utils/uploaded_file'
module Assertions
- autoload :DomAssertions, 'action_controller/assertions/dom_assertions'
- autoload :ModelAssertions, 'action_controller/assertions/model_assertions'
- autoload :ResponseAssertions, 'action_controller/assertions/response_assertions'
- autoload :RoutingAssertions, 'action_controller/assertions/routing_assertions'
- autoload :SelectorAssertions, 'action_controller/assertions/selector_assertions'
- autoload :TagAssertions, 'action_controller/assertions/tag_assertions'
+ autoload :DomAssertions, 'action_controller/testing/assertions/dom'
+ autoload :ModelAssertions, 'action_controller/testing/assertions/model'
+ autoload :ResponseAssertions, 'action_controller/testing/assertions/response'
+ autoload :RoutingAssertions, 'action_controller/testing/assertions/routing'
+ autoload :SelectorAssertions, 'action_controller/testing/assertions/selector'
+ autoload :TagAssertions, 'action_controller/testing/assertions/tag'
end
-
- module Http
- autoload :Headers, 'action_controller/headers'
- end
-
- module Session
- autoload :AbstractStore, 'action_controller/session/abstract_store'
- autoload :CookieStore, 'action_controller/session/cookie_store'
- autoload :MemCacheStore, 'action_controller/session/mem_cache_store'
- end
-
- # DEPRECATE: Remove CGI support
- autoload :CgiRequest, 'action_controller/cgi_process'
- autoload :CGIHandler, 'action_controller/cgi_process'
end
-autoload :Mime, 'action_controller/mime_type'
-
autoload :HTML, 'action_controller/vendor/html-scanner'
+require 'action_dispatch'
require 'action_view'
diff --git a/actionpack/lib/action_controller/abstract.rb b/actionpack/lib/action_controller/abstract.rb
new file mode 100644
index 0000000000..3f5c4a185f
--- /dev/null
+++ b/actionpack/lib/action_controller/abstract.rb
@@ -0,0 +1,10 @@
+module AbstractController
+ autoload :Base, "action_controller/abstract/base"
+ autoload :Callbacks, "action_controller/abstract/callbacks"
+ autoload :Helpers, "action_controller/abstract/helpers"
+ autoload :Layouts, "action_controller/abstract/layouts"
+ autoload :Logger, "action_controller/abstract/logger"
+ autoload :Renderer, "action_controller/abstract/renderer"
+ # === Exceptions
+ autoload :ActionNotFound, "action_controller/abstract/exceptions"
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/abstract/base.rb b/actionpack/lib/action_controller/abstract/base.rb
new file mode 100644
index 0000000000..ade7719cc0
--- /dev/null
+++ b/actionpack/lib/action_controller/abstract/base.rb
@@ -0,0 +1,41 @@
+module AbstractController
+ class Base
+
+ attr_internal :response_body
+ attr_internal :response_obj
+ attr_internal :action_name
+
+ def self.process(action)
+ new.process(action)
+ end
+
+ def self.inherited(klass)
+ end
+
+ def initialize
+ self.response_obj = {}
+ end
+
+ def process(action_name)
+ unless respond_to_action?(action_name)
+ raise ActionNotFound, "The action '#{action_name}' could not be found"
+ end
+
+ @_action_name = action_name
+ process_action
+ self.response_obj[:body] = self.response_body
+ self
+ end
+
+ private
+
+ def process_action
+ respond_to?(action_name) ? send(action_name) : send(:action_missing, action_name)
+ end
+
+ def respond_to_action?(action_name)
+ respond_to?(action_name) || respond_to?(:action_missing, true)
+ end
+
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/abstract/callbacks.rb b/actionpack/lib/action_controller/abstract/callbacks.rb
new file mode 100644
index 0000000000..c8b509081c
--- /dev/null
+++ b/actionpack/lib/action_controller/abstract/callbacks.rb
@@ -0,0 +1,40 @@
+module AbstractController
+ module Callbacks
+ setup do
+ include ActiveSupport::NewCallbacks
+ define_callbacks :process_action
+ end
+
+ def process_action
+ _run_process_action_callbacks(action_name) do
+ super
+ end
+ end
+
+ module ClassMethods
+ def _normalize_callback_options(options)
+ if only = options[:only]
+ only = Array(only).map {|o| "action_name == :#{o}"}.join(" || ")
+ options[:per_key] = {:if => only}
+ end
+ if except = options[:except]
+ except = Array(except).map {|e| "action_name == :#{e}"}.join(" || ")
+ options[:per_key] = {:unless => except}
+ end
+ end
+
+ [:before, :after, :around].each do |filter|
+ class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
+ def #{filter}_filter(*names, &blk)
+ options = names.last.is_a?(Hash) ? names.pop : {}
+ _normalize_callback_options(options)
+ names.push(blk) if block_given?
+ names.each do |name|
+ process_action_callback(:#{filter}, name, options)
+ end
+ end
+ RUBY_EVAL
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/abstract/exceptions.rb b/actionpack/lib/action_controller/abstract/exceptions.rb
new file mode 100644
index 0000000000..ec4680629b
--- /dev/null
+++ b/actionpack/lib/action_controller/abstract/exceptions.rb
@@ -0,0 +1,3 @@
+module AbstractController
+ class ActionNotFound < StandardError ; end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/abstract/helpers.rb b/actionpack/lib/action_controller/abstract/helpers.rb
new file mode 100644
index 0000000000..1f0b38417b
--- /dev/null
+++ b/actionpack/lib/action_controller/abstract/helpers.rb
@@ -0,0 +1,59 @@
+module AbstractController
+ module Helpers
+ depends_on Renderer
+
+ setup do
+ extlib_inheritable_accessor :master_helper_module
+ self.master_helper_module = Module.new
+ end
+
+ # def self.included(klass)
+ # klass.class_eval do
+ # extlib_inheritable_accessor :master_helper_module
+ # self.master_helper_module = Module.new
+ # end
+ # end
+
+ def _action_view
+ @_action_view ||= begin
+ av = super
+ av.helpers.send(:include, master_helper_module)
+ av
+ end
+ end
+
+ module ClassMethods
+ def inherited(klass)
+ klass.master_helper_module = Module.new
+ klass.master_helper_module.__send__ :include, master_helper_module
+
+ super
+ end
+
+ def add_template_helper(mod)
+ master_helper_module.module_eval { include mod }
+ end
+
+ def helper_method(*meths)
+ meths.flatten.each do |meth|
+ master_helper_module.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1
+ def #{meth}(*args, &blk)
+ controller.send(%(#{meth}), *args, &blk)
+ end
+ ruby_eval
+ end
+ end
+
+ def helper(*args, &blk)
+ args.flatten.each do |arg|
+ case arg
+ when Module
+ add_template_helper(arg)
+ end
+ end
+ master_helper_module.module_eval(&blk) if block_given?
+ end
+ end
+
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb
new file mode 100644
index 0000000000..478b301a26
--- /dev/null
+++ b/actionpack/lib/action_controller/abstract/layouts.rb
@@ -0,0 +1,82 @@
+module AbstractController
+ module Layouts
+
+ depends_on Renderer
+
+ module ClassMethods
+ def layout(layout)
+ unless [String, Symbol, FalseClass, NilClass].include?(layout.class)
+ raise ArgumentError, "Layouts must be specified as a String, Symbol, false, or nil"
+ end
+
+ @_layout = layout || false # Converts nil to false
+ _write_layout_method
+ end
+
+ def _implied_layout_name
+ name.underscore
+ end
+
+ # Takes the specified layout and creates a _layout method to be called
+ # by _default_layout
+ #
+ # If the specified layout is a:
+ # String:: return the string
+ # Symbol:: call the method specified by the symbol
+ # false:: return nil
+ # none:: If a layout is found in the view paths with the controller's
+ # name, return that string. Otherwise, use the superclass'
+ # layout (which might also be implied)
+ def _write_layout_method
+ case @_layout
+ when String
+ self.class_eval %{def _layout() #{@_layout.inspect} end}
+ when Symbol
+ self.class_eval %{def _layout() #{@_layout} end}
+ when false
+ self.class_eval %{def _layout() end}
+ else
+ self.class_eval %{
+ def _layout
+ if view_paths.find_by_parts?("#{_implied_layout_name}", formats, "layouts")
+ "#{_implied_layout_name}"
+ else
+ super
+ end
+ end
+ }
+ end
+ end
+ end
+
+ def _render_template(template, options)
+ _action_view._render_template_with_layout(template, options[:_layout])
+ end
+
+ private
+
+ def _layout() end # This will be overwritten
+
+ def _layout_for_name(name)
+ unless [String, FalseClass, NilClass].include?(name.class)
+ raise ArgumentError, "String, false, or nil expected; you passed #{name.inspect}"
+ end
+
+ name && view_paths.find_by_parts(name, formats, "layouts")
+ end
+
+ def _default_layout(require_layout = false)
+ if require_layout && !_layout
+ raise ArgumentError,
+ "There was no default layout for #{self.class} in #{view_paths.inspect}"
+ end
+
+ begin
+ layout = _layout_for_name(_layout)
+ rescue NameError => e
+ raise NoMethodError,
+ "You specified #{@_layout.inspect} as the layout, but no such method was found"
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/abstract/logger.rb b/actionpack/lib/action_controller/abstract/logger.rb
new file mode 100644
index 0000000000..4117369bd4
--- /dev/null
+++ b/actionpack/lib/action_controller/abstract/logger.rb
@@ -0,0 +1,7 @@
+module AbstractController
+ module Logger
+ setup do
+ cattr_accessor :logger
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/abstract/renderer.rb b/actionpack/lib/action_controller/abstract/renderer.rb
new file mode 100644
index 0000000000..68c3b07b84
--- /dev/null
+++ b/actionpack/lib/action_controller/abstract/renderer.rb
@@ -0,0 +1,58 @@
+require "action_controller/abstract/logger"
+
+module AbstractController
+ module Renderer
+ depends_on AbstractController::Logger
+
+ setup do
+ attr_internal :formats
+
+ extlib_inheritable_accessor :_view_paths
+
+ self._view_paths ||= ActionView::PathSet.new
+ end
+
+ def _action_view
+ @_action_view ||= ActionView::Base.new(self.class.view_paths, {}, self)
+ end
+
+ def render(options = {})
+ self.response_body = render_to_string(options)
+ end
+
+ # Raw rendering of a template.
+ # ====
+ # @option _prefix<String> The template's path prefix
+ # @option _layout<String> The relative path to the layout template to use
+ #
+ # :api: plugin
+ def render_to_string(options = {})
+ name = options[:_template_name] || action_name
+
+ template = options[:_template] || view_paths.find_by_parts(name.to_s, formats, options[:_prefix])
+ _render_template(template, options)
+ end
+
+ def _render_template(template, options)
+ _action_view._render_template_with_layout(template)
+ end
+
+ def view_paths() _view_paths end
+
+ module ClassMethods
+
+ def append_view_path(path)
+ self.view_paths << path
+ end
+
+ def view_paths
+ self._view_paths
+ end
+
+ def view_paths=(paths)
+ self._view_paths = paths.is_a?(ActionView::PathSet) ?
+ paths : ActionView::Base.process_view_paths(paths)
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base/base.rb
index 0b58c38fb5..aea434ffa0 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base/base.rb
@@ -58,22 +58,6 @@ module ActionController #:nodoc:
end
end
- class DoubleRenderError < ActionControllerError #:nodoc:
- DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"."
-
- def initialize(message = nil)
- super(message || DEFAULT_MESSAGE)
- end
- end
-
- class RedirectBackError < ActionControllerError #:nodoc:
- DEFAULT_MESSAGE = 'No HTTP_REFERER was set in the request to this action, so redirect_to :back could not be called successfully. If this is a test, make sure to specify request.env["HTTP_REFERER"].'
-
- def initialize(message = nil)
- super(message || DEFAULT_MESSAGE)
- end
- end
-
class UnknownHttpMethod < ActionControllerError #:nodoc:
end
@@ -247,9 +231,8 @@ module ActionController #:nodoc:
# end
#
class Base
- DEFAULT_RENDER_STATUS_CODE = "200 OK"
- include StatusCodes
+ include ActionDispatch::StatusCodes
cattr_reader :protected_instance_variables
# Controller specific instance variables which will not be accessible inside views.
@@ -301,7 +284,10 @@ module ActionController #:nodoc:
# A YAML parser is also available and can be turned on with:
#
# ActionController::Base.param_parsers[Mime::YAML] = :yaml
- @@param_parsers = {}
+ @@param_parsers = { Mime::MULTIPART_FORM => :multipart_form,
+ Mime::URL_ENCODED_FORM => :url_encoded_form,
+ Mime::XML => :xml_simple,
+ Mime::JSON => :json }
cattr_accessor :param_parsers
# Controls the default charset for all renders.
@@ -381,8 +367,8 @@ module ActionController #:nodoc:
class << self
def call(env)
# HACK: For global rescue to have access to the original request and response
- request = env["action_controller.rescue.request"] ||= Request.new(env)
- response = env["action_controller.rescue.response"] ||= Response.new
+ request = env["action_controller.rescue.request"] ||= ActionDispatch::Request.new(env)
+ response = env["action_controller.rescue.response"] ||= ActionDispatch::Response.new
process(request, response)
end
@@ -514,8 +500,8 @@ module ActionController #:nodoc:
def process(request, response, method = :perform_action, *arguments) #:nodoc:
response.request = request
- initialize_template_class(response)
assign_shortcuts(request, response)
+ initialize_template_class(response)
initialize_current_url
assign_names
@@ -678,371 +664,6 @@ module ActionController #:nodoc:
@template.view_paths.push(*path)
end
- protected
- # Renders the content that will be returned to the browser as the response body.
- #
- # === Rendering an action
- #
- # Action rendering is the most common form and the type used automatically by Action Controller when nothing else is
- # specified. By default, actions are rendered within the current layout (if one exists).
- #
- # # Renders the template for the action "goal" within the current controller
- # render :action => "goal"
- #
- # # Renders the template for the action "short_goal" within the current controller,
- # # but without the current active layout
- # render :action => "short_goal", :layout => false
- #
- # # Renders the template for the action "long_goal" within the current controller,
- # # but with a custom layout
- # render :action => "long_goal", :layout => "spectacular"
- #
- # === Rendering partials
- #
- # Partial rendering in a controller is most commonly used together with Ajax calls that only update one or a few elements on a page
- # without reloading. Rendering of partials from the controller makes it possible to use the same partial template in
- # both the full-page rendering (by calling it from within the template) and when sub-page updates happen (from the
- # controller action responding to Ajax calls). By default, the current layout is not used.
- #
- # # Renders the same partial with a local variable.
- # render :partial => "person", :locals => { :name => "david" }
- #
- # # Renders the partial, making @new_person available through
- # # the local variable 'person'
- # render :partial => "person", :object => @new_person
- #
- # # Renders a collection of the same partial by making each element
- # # of @winners available through the local variable "person" as it
- # # builds the complete response.
- # render :partial => "person", :collection => @winners
- #
- # # Renders a collection of partials but with a custom local variable name
- # render :partial => "admin_person", :collection => @winners, :as => :person
- #
- # # Renders the same collection of partials, but also renders the
- # # person_divider partial between each person partial.
- # render :partial => "person", :collection => @winners, :spacer_template => "person_divider"
- #
- # # Renders a collection of partials located in a view subfolder
- # # outside of our current controller. In this example we will be
- # # rendering app/views/shared/_note.r(html|xml) Inside the partial
- # # each element of @new_notes is available as the local var "note".
- # render :partial => "shared/note", :collection => @new_notes
- #
- # # Renders the partial with a status code of 500 (internal error).
- # render :partial => "broken", :status => 500
- #
- # Note that the partial filename must also be a valid Ruby variable name,
- # so e.g. 2005 and register-user are invalid.
- #
- #
- # == Automatic etagging
- #
- # Rendering will automatically insert the etag header on 200 OK responses. The etag is calculated using MD5 of the
- # response body. If a request comes in that has a matching etag, the response will be changed to a 304 Not Modified
- # and the response body will be set to an empty string. No etag header will be inserted if it's already set.
- #
- # === Rendering a template
- #
- # Template rendering works just like action rendering except that it takes a path relative to the template root.
- # The current layout is automatically applied.
- #
- # # Renders the template located in [TEMPLATE_ROOT]/weblog/show.r(html|xml) (in Rails, app/views/weblog/show.erb)
- # render :template => "weblog/show"
- #
- # # Renders the template with a local variable
- # render :template => "weblog/show", :locals => {:customer => Customer.new}
- #
- # === Rendering a file
- #
- # File rendering works just like action rendering except that it takes a filesystem path. By default, the path
- # is assumed to be absolute, and the current layout is not applied.
- #
- # # Renders the template located at the absolute filesystem path
- # render :file => "/path/to/some/template.erb"
- # render :file => "c:/path/to/some/template.erb"
- #
- # # Renders a template within the current layout, and with a 404 status code
- # render :file => "/path/to/some/template.erb", :layout => true, :status => 404
- # render :file => "c:/path/to/some/template.erb", :layout => true, :status => 404
- #
- # === Rendering text
- #
- # Rendering of text is usually used for tests or for rendering prepared content, such as a cache. By default, text
- # rendering is not done within the active layout.
- #
- # # Renders the clear text "hello world" with status code 200
- # render :text => "hello world!"
- #
- # # Renders the clear text "Explosion!" with status code 500
- # render :text => "Explosion!", :status => 500
- #
- # # Renders the clear text "Hi there!" within the current active layout (if one exists)
- # render :text => "Hi there!", :layout => true
- #
- # # Renders the clear text "Hi there!" within the layout
- # # placed in "app/views/layouts/special.r(html|xml)"
- # render :text => "Hi there!", :layout => "special"
- #
- # === Streaming data and/or controlling the page generation
- #
- # The <tt>:text</tt> option can also accept a Proc object, which can be used to:
- #
- # 1. stream on-the-fly generated data to the browser. Note that you should
- # use the methods provided by ActionController::Steaming instead if you
- # want to stream a buffer or a file.
- # 2. manually control the page generation. This should generally be avoided,
- # as it violates the separation between code and content, and because almost
- # everything that can be done with this method can also be done more cleanly
- # using one of the other rendering methods, most notably templates.
- #
- # Two arguments are passed to the proc, a <tt>response</tt> object and an
- # <tt>output</tt> object. The response object is equivalent to the return
- # value of the ActionController::Base#response method, and can be used to
- # control various things in the HTTP response, such as setting the
- # Content-Type header. The output object is an writable <tt>IO</tt>-like
- # object, so one can call <tt>write</tt> and <tt>flush</tt> on it.
- #
- # The following example demonstrates how one can stream a large amount of
- # on-the-fly generated data to the browser:
- #
- # # Streams about 180 MB of generated data to the browser.
- # render :text => proc { |response, output|
- # 10_000_000.times do |i|
- # output.write("This is line #{i}\n")
- # output.flush
- # end
- # }
- #
- # Another example:
- #
- # # Renders "Hello from code!"
- # render :text => proc { |response, output| output.write("Hello from code!") }
- #
- # === Rendering XML
- #
- # Rendering XML sets the content type to application/xml.
- #
- # # Renders '<name>David</name>'
- # render :xml => {:name => "David"}.to_xml
- #
- # It's not necessary to call <tt>to_xml</tt> on the object you want to render, since <tt>render</tt> will
- # automatically do that for you:
- #
- # # Also renders '<name>David</name>'
- # render :xml => {:name => "David"}
- #
- # === Rendering JSON
- #
- # Rendering JSON sets the content type to application/json and optionally wraps the JSON in a callback. It is expected
- # that the response will be parsed (or eval'd) for use as a data structure.
- #
- # # Renders '{"name": "David"}'
- # render :json => {:name => "David"}.to_json
- #
- # It's not necessary to call <tt>to_json</tt> on the object you want to render, since <tt>render</tt> will
- # automatically do that for you:
- #
- # # Also renders '{"name": "David"}'
- # render :json => {:name => "David"}
- #
- # Sometimes the result isn't handled directly by a script (such as when the request comes from a SCRIPT tag),
- # so the <tt>:callback</tt> option is provided for these cases.
- #
- # # Renders 'show({"name": "David"})'
- # render :json => {:name => "David"}.to_json, :callback => 'show'
- #
- # === Rendering an inline template
- #
- # Rendering of an inline template works as a cross between text and action rendering where the source for the template
- # is supplied inline, like text, but its interpreted with ERb or Builder, like action. By default, ERb is used for rendering
- # and the current layout is not used.
- #
- # # Renders "hello, hello, hello, again"
- # render :inline => "<%= 'hello, ' * 3 + 'again' %>"
- #
- # # Renders "<p>Good seeing you!</p>" using Builder
- # render :inline => "xml.p { 'Good seeing you!' }", :type => :builder
- #
- # # Renders "hello david"
- # render :inline => "<%= 'hello ' + name %>", :locals => { :name => "david" }
- #
- # === Rendering inline JavaScriptGenerator page updates
- #
- # In addition to rendering JavaScriptGenerator page updates with Ajax in RJS templates (see ActionView::Base for details),
- # you can also pass the <tt>:update</tt> parameter to +render+, along with a block, to render page updates inline.
- #
- # render :update do |page|
- # page.replace_html 'user_list', :partial => 'user', :collection => @users
- # page.visual_effect :highlight, 'user_list'
- # end
- #
- # === Rendering vanilla JavaScript
- #
- # In addition to using RJS with render :update, you can also just render vanilla JavaScript with :js.
- #
- # # Renders "alert('hello')" and sets the mime type to text/javascript
- # render :js => "alert('hello')"
- #
- # === Rendering with status and location headers
- # All renders take the <tt>:status</tt> and <tt>:location</tt> options and turn them into headers. They can even be used together:
- #
- # render :xml => post.to_xml, :status => :created, :location => post_url(post)
- def render(options = nil, extra_options = {}, &block) #:doc:
- raise DoubleRenderError, "Can only render or redirect once per action" if performed?
-
- validate_render_arguments(options, extra_options, block_given?)
-
- if options.nil?
- options = { :template => default_template, :layout => true }
- elsif options == :update
- options = extra_options.merge({ :update => true })
- elsif options.is_a?(String) || options.is_a?(Symbol)
- case options.to_s.index('/')
- when 0
- extra_options[:file] = options
- when nil
- extra_options[:action] = options
- else
- extra_options[:template] = options
- end
-
- options = extra_options
- elsif !options.is_a?(Hash)
- extra_options[:partial] = options
- options = extra_options
- end
-
- layout = pick_layout(options)
- response.layout = layout.path_without_format_and_extension if layout
- logger.info("Rendering template within #{layout.path_without_format_and_extension}") if logger && layout
-
- if content_type = options[:content_type]
- response.content_type = content_type.to_s
- end
-
- if location = options[:location]
- response.headers["Location"] = url_for(location)
- end
-
- if options.has_key?(:text)
- text = layout ? @template.render(options.merge(:text => options[:text], :layout => layout)) : options[:text]
- render_for_text(text, options[:status])
-
- else
- if file = options[:file]
- render_for_file(file, options[:status], layout, options[:locals] || {})
-
- elsif template = options[:template]
- render_for_file(template, options[:status], layout, options[:locals] || {})
-
- elsif inline = options[:inline]
- render_for_text(@template.render(options.merge(:layout => layout)), options[:status])
-
- elsif action_name = options[:action]
- render_for_file(default_template(action_name.to_s), options[:status], layout)
-
- elsif xml = options[:xml]
- response.content_type ||= Mime::XML
- render_for_text(xml.respond_to?(:to_xml) ? xml.to_xml : xml, options[:status])
-
- elsif js = options[:js]
- response.content_type ||= Mime::JS
- render_for_text(js, options[:status])
-
- elsif json = options[:json]
- json = json.to_json unless json.is_a?(String)
- json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
- response.content_type ||= Mime::JSON
- render_for_text(json, options[:status])
-
- elsif options[:partial]
- options[:partial] = default_template_name if options[:partial] == true
- if layout
- render_for_text(@template.render(:text => @template.render(options), :layout => layout), options[:status])
- else
- render_for_text(@template.render(options), options[:status])
- end
-
- elsif options[:update]
- @template.send(:_evaluate_assigns_and_ivars)
-
- generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(@template, &block)
- response.content_type = Mime::JS
- render_for_text(generator.to_s, options[:status])
-
- elsif options[:nothing]
- render_for_text(nil, options[:status])
-
- else
- render_for_file(default_template, options[:status], layout)
- end
- end
- end
-
- # Renders according to the same rules as <tt>render</tt>, but returns the result in a string instead
- # of sending it as the response body to the browser.
- def render_to_string(options = nil, &block) #:doc:
- render(options, &block)
- response.body
- ensure
- response.content_type = nil
- erase_render_results
- reset_variables_added_to_assigns
- end
-
- # Return a response that has no content (merely headers). The options
- # argument is interpreted to be a hash of header names and values.
- # This allows you to easily return a response that consists only of
- # significant headers:
- #
- # head :created, :location => person_path(@person)
- #
- # It can also be used to return exceptional conditions:
- #
- # return head(:method_not_allowed) unless request.post?
- # return head(:bad_request) unless valid_request?
- # render
- def head(*args)
- if args.length > 2
- raise ArgumentError, "too many arguments to head"
- elsif args.empty?
- raise ArgumentError, "too few arguments to head"
- end
- options = args.extract_options!
- status = interpret_status(args.shift || options.delete(:status) || :ok)
-
- options.each do |key, value|
- headers[key.to_s.dasherize.split(/-/).map { |v| v.capitalize }.join("-")] = value.to_s
- end
-
- render :nothing => true, :status => status
- end
-
- # Clears the rendered results, allowing for another render to be performed.
- def erase_render_results #:nodoc:
- response.body = []
- @performed_render = false
- end
-
- # Clears the redirected results from the headers, resets the status to 200 and returns
- # the URL that was used to redirect or nil if there was no redirected URL
- # Note that +redirect_to+ will change the body of the response to indicate a redirection.
- # The response body is not reset here, see +erase_render_results+
- def erase_redirect_results #:nodoc:
- @performed_redirect = false
- response.redirected_to = nil
- response.redirected_to_method_params = nil
- response.status = DEFAULT_RENDER_STATUS_CODE
- response.headers.delete('Location')
- end
-
- # Erase both render and redirect results
- def erase_results #:nodoc:
- erase_render_results
- erase_redirect_results
- end
-
def rewrite_options(options) #:nodoc:
if defaults = default_url_options(options)
defaults.merge(options)
@@ -1064,73 +685,6 @@ module ActionController #:nodoc:
def default_url_options(options = nil)
end
- # Redirects the browser to the target specified in +options+. This parameter can take one of three forms:
- #
- # * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.
- # * <tt>Record</tt> - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record.
- # * <tt>String</tt> starting with <tt>protocol://</tt> (like <tt>http://</tt>) - Is passed straight through as the target for redirection.
- # * <tt>String</tt> not containing a protocol - The current protocol and host is prepended to the string.
- # * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
- # Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt>
- #
- # Examples:
- # redirect_to :action => "show", :id => 5
- # redirect_to post
- # redirect_to "http://www.rubyonrails.org"
- # redirect_to "/images/screenshot.jpg"
- # redirect_to articles_url
- # redirect_to :back
- #
- # The redirection happens as a "302 Moved" header unless otherwise specified.
- #
- # Examples:
- # redirect_to post_url(@post), :status=>:found
- # redirect_to :action=>'atom', :status=>:moved_permanently
- # redirect_to post_url(@post), :status=>301
- # redirect_to :action=>'atom', :status=>302
- #
- # When using <tt>redirect_to :back</tt>, if there is no referrer,
- # RedirectBackError will be raised. You may specify some fallback
- # behavior for this case by rescuing RedirectBackError.
- def redirect_to(options = {}, response_status = {}) #:doc:
- raise ActionControllerError.new("Cannot redirect to nil!") if options.nil?
-
- if options.is_a?(Hash) && options[:status]
- status = options.delete(:status)
- elsif response_status[:status]
- status = response_status[:status]
- else
- status = 302
- end
-
- response.redirected_to = options
-
- case options
- # The scheme name consist of a letter followed by any combination of
- # letters, digits, and the plus ("+"), period ("."), or hyphen ("-")
- # characters; and is terminated by a colon (":").
- when %r{^\w[\w\d+.-]*:.*}
- redirect_to_full_url(options, status)
- when String
- redirect_to_full_url(request.protocol + request.host_with_port + options, status)
- when :back
- if referer = request.headers["Referer"]
- redirect_to(referer, :status=>status)
- else
- raise RedirectBackError
- end
- else
- redirect_to_full_url(url_for(options), status)
- end
- end
-
- def redirect_to_full_url(url, status)
- raise DoubleRenderError if performed?
- logger.info("Redirected to #{url}") if logger && logger.info?
- response.redirect(url, interpret_status(status))
- @performed_redirect = true
- end
-
# Sets the etag and/or last_modified on the response and checks it against
# the client request. If the request doesn't match the options provided, the
# request is considered stale and should be generated from scratch. Otherwise,
@@ -1236,40 +790,20 @@ module ActionController #:nodoc:
end
private
- def render_for_file(template_path, status = nil, layout = nil, locals = {}) #:nodoc:
- path = template_path.respond_to?(:path_without_format_and_extension) ? template_path.path_without_format_and_extension : template_path
- logger.info("Rendering #{path}" + (status ? " (#{status})" : '')) if logger
- render_for_text @template.render(:file => template_path, :locals => locals, :layout => layout), status
- end
-
- def render_for_text(text = nil, status = nil, append_response = false) #:nodoc:
- @performed_render = true
-
- response.status = interpret_status(status || DEFAULT_RENDER_STATUS_CODE)
-
- if append_response
- response.body_parts << text.to_s
- else
- response.body = case text
- when Proc then text
- when nil then [" "] # Safari doesn't pass the headers of the return if the response is zero length
- else [text.to_s]
- end
+ def _process_options(options)
+ if content_type = options[:content_type]
+ response.content_type = content_type.to_s
end
- end
- def validate_render_arguments(options, extra_options, has_block)
- if options && (has_block && options != :update) && !options.is_a?(String) && !options.is_a?(Hash) && !options.is_a?(Symbol)
- raise RenderError, "You called render with invalid options : #{options.inspect}"
+ if location = options[:location]
+ response.headers["Location"] = url_for(location)
end
- if !extra_options.is_a?(Hash)
- raise RenderError, "You called render with invalid options : #{options.inspect}, #{extra_options.inspect}"
- end
+ response.status = interpret_status(options[:status] || DEFAULT_RENDER_STATUS_CODE)
end
def initialize_template_class(response)
- response.template = ActionView::Base.new(self.class.view_paths, {}, self)
+ @template = response.template = ActionView::Base.new(self.class.view_paths, {}, self, formats)
response.template.helpers.send :include, self.class.master_helper_module
response.redirected_to = nil
@performed_render = @performed_redirect = false
@@ -1282,7 +816,6 @@ module ActionController #:nodoc:
@_response.session = request.session
@_session = @_response.session
- @template = @_response.template
@_headers = @_response.headers
end
@@ -1318,23 +851,21 @@ module ActionController #:nodoc:
end
def perform_action
- if action_methods.include?(action_name)
- send(action_name)
- default_render unless performed?
- elsif respond_to? :method_missing
- method_missing action_name
- default_render unless performed?
- else
- begin
- default_render
- rescue ActionView::MissingTemplate => e
- # Was the implicit template missing, or was it another template?
- if e.path == default_template_name
- raise UnknownAction, "No action responded to #{action_name}. Actions: #{action_methods.sort.to_sentence(:locale => :en)}", caller
- else
- raise e
- end
- end
+ if called = action_methods.include?(action_name)
+ ret = send(action_name)
+ elsif called = respond_to?(:method_missing)
+ ret = method_missing(action_name)
+ end
+
+ return (performed? ? ret : default_render) if called
+
+ begin
+ default_render
+ rescue ActionView::MissingTemplate => e
+ raise e unless e.action_name == action_name
+ # If the path is the same as the action_name, the action is completely missing
+ raise UnknownAction, "No action responded to #{action_name}. Actions: " +
+ "#{action_methods.sort.to_sentence}", caller
end
end
@@ -1347,23 +878,6 @@ module ActionController #:nodoc:
@action_name = (params['action'] || 'index')
end
- # Returns a set of the methods defined as actions in your controller
- def action_methods
- self.class.action_methods
- end
-
- def self.action_methods
- @action_methods ||=
- # All public instance methods of this class, including ancestors
- public_instance_methods(true).map { |m| m.to_s }.to_set -
- # Except for public instance methods of Base and its ancestors
- Base.public_instance_methods(true).map { |m| m.to_s } +
- # Be sure to include shadowed public instance methods of this class
- public_instance_methods(false).map { |m| m.to_s } -
- # And always exclude explicitly hidden actions
- hidden_actions
- end
-
def reset_variables_added_to_assigns
@template.instance_variable_set("@assigns_added", nil)
end
@@ -1379,6 +893,10 @@ module ActionController #:nodoc:
"#{request.protocol}#{request.host}#{request.request_uri}"
end
+ def close_session
+ # @_session.close if @_session && @_session.respond_to?(:close)
+ end
+
def default_template(action_name = self.action_name)
self.view_paths.find_template(default_template_name(action_name), default_template_format)
end
@@ -1390,7 +908,7 @@ module ActionController #:nodoc:
action_name = strip_out_controller(action_name)
end
end
- "#{self.controller_path}/#{action_name}"
+ "#{controller_path}/#{action_name}"
end
def strip_out_controller(path)
@@ -1402,14 +920,15 @@ module ActionController #:nodoc:
end
def process_cleanup
+ close_session
end
end
Base.class_eval do
- [ Filters, Layout, Benchmarking, Rescue, Flash, MimeResponds, Helpers,
+ [ Filters, Layout, Renderer, Redirector, Responder, Benchmarking, Rescue, Flash, MimeResponds, Helpers,
Cookies, Caching, Verification, Streaming, SessionManagement,
- HttpAuthentication::Basic::ControllerMethods, HttpAuthentication::Digest::ControllerMethods,
- RecordIdentifier, RequestForgeryProtection, Translation
+ HttpAuthentication::Basic::ControllerMethods, HttpAuthentication::Digest::ControllerMethods, RecordIdentifier,
+ RequestForgeryProtection, Translation
].each do |mod|
include mod
end
diff --git a/actionpack/lib/action_controller/benchmarking.rb b/actionpack/lib/action_controller/base/chained/benchmarking.rb
index 47377e5fa9..066150f58a 100644
--- a/actionpack/lib/action_controller/benchmarking.rb
+++ b/actionpack/lib/action_controller/base/chained/benchmarking.rb
@@ -64,7 +64,7 @@ module ActionController #:nodoc:
private
def perform_action_with_benchmark
- if logger
+ if logger && logger.info?
ms = [Benchmark.ms { perform_action_without_benchmark }, 0.01].max
logging_view = defined?(@view_runtime)
logging_active_record = Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected?
diff --git a/actionpack/lib/action_controller/filters.rb b/actionpack/lib/action_controller/base/chained/filters.rb
index 9022b8b279..9022b8b279 100644
--- a/actionpack/lib/action_controller/filters.rb
+++ b/actionpack/lib/action_controller/base/chained/filters.rb
diff --git a/actionpack/lib/action_controller/flash.rb b/actionpack/lib/action_controller/base/chained/flash.rb
index 56ee9c67e2..56ee9c67e2 100644
--- a/actionpack/lib/action_controller/flash.rb
+++ b/actionpack/lib/action_controller/base/chained/flash.rb
diff --git a/actionpack/lib/action_controller/cookies.rb b/actionpack/lib/action_controller/base/cookies.rb
index ca380e98d0..ca380e98d0 100644
--- a/actionpack/lib/action_controller/cookies.rb
+++ b/actionpack/lib/action_controller/base/cookies.rb
diff --git a/actionpack/lib/action_controller/helpers.rb b/actionpack/lib/action_controller/base/helpers.rb
index ba65032f6a..ba65032f6a 100644
--- a/actionpack/lib/action_controller/helpers.rb
+++ b/actionpack/lib/action_controller/base/helpers.rb
diff --git a/actionpack/lib/action_controller/http_authentication.rb b/actionpack/lib/action_controller/base/http_authentication.rb
index b6b5267c66..b6b5267c66 100644
--- a/actionpack/lib/action_controller/http_authentication.rb
+++ b/actionpack/lib/action_controller/base/http_authentication.rb
diff --git a/actionpack/lib/action_controller/layout.rb b/actionpack/lib/action_controller/base/layout.rb
index 6ec0c1b304..88a15aa6ca 100644
--- a/actionpack/lib/action_controller/layout.rb
+++ b/actionpack/lib/action_controller/base/layout.rb
@@ -2,11 +2,7 @@ module ActionController #:nodoc:
module Layout #:nodoc:
def self.included(base)
base.extend(ClassMethods)
- base.class_eval do
- class << self
- alias_method_chain :inherited, :layout
- end
- end
+ base.class_inheritable_accessor :layout_name, :layout_conditions
end
# Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in
@@ -159,123 +155,90 @@ module ActionController #:nodoc:
#
# This will render the help action with the "help" layout instead of the controller-wide "weblog_standard" layout.
module ClassMethods
+ extend ActiveSupport::Memoizable
+
# If a layout is specified, all rendered actions will have their result rendered
# when the layout <tt>yield</tt>s. This layout can itself depend on instance variables assigned during action
# performance and have access to them as any normal template would.
def layout(template_name, conditions = {}, auto = false)
add_layout_conditions(conditions)
- write_inheritable_attribute(:layout, template_name)
- write_inheritable_attribute(:auto_layout, auto)
+ self.layout_name = template_name
+ end
+
+ def memoized_default_layout(formats) #:nodoc:
+ self.layout_name || begin
+ layout = default_layout_name
+ layout.is_a?(String) ? find_layout(layout, formats) : layout
+ rescue ActionView::MissingTemplate
+ end
+ end
+
+ def default_layout(*args)
+ (@_memoized_default_layout ||= ::ActiveSupport::ConcurrentHash.new)[args] ||= memoized_default_layout(*args)
+ end
+
+ def memoized_find_layout(layout, formats) #:nodoc:
+ return layout if layout.nil? || layout.respond_to?(:render)
+ prefix = layout.to_s =~ /layouts\// ? nil : "layouts"
+ view_paths.find_by_parts(layout.to_s, formats, prefix)
end
- def layout_conditions #:nodoc:
- @layout_conditions ||= read_inheritable_attribute(:layout_conditions)
+ def find_layout(*args)
+ (@_memoized_find_layout ||= ::ActiveSupport::ConcurrentHash.new)[args] ||= memoized_find_layout(*args)
end
def layout_list #:nodoc:
Array(view_paths).sum([]) { |path| Dir["#{path.to_str}/layouts/**/*"] }
end
+ memoize :layout_list
- private
- def inherited_with_layout(child)
- inherited_without_layout(child)
- unless child.name.blank?
- layout_match = child.name.underscore.sub(/_controller$/, '').sub(/^controllers\//, '')
- child.layout(layout_match, {}, true) unless child.layout_list.grep(%r{layouts/#{layout_match}(\.[a-z][0-9a-z]*)+$}).empty?
- end
+ def default_layout_name
+ layout_match = name.underscore.sub(/_controller$/, '')
+ if layout_list.grep(%r{layouts/#{layout_match}(\.[a-z][0-9a-z]*)+$}).empty?
+ superclass.default_layout_name if superclass.respond_to?(:default_layout_name)
+ else
+ layout_match
end
+ end
+ memoize :default_layout_name
+ private
def add_layout_conditions(conditions)
- write_inheritable_hash(:layout_conditions, normalize_conditions(conditions))
- end
-
- def normalize_conditions(conditions)
- conditions.inject({}) {|hash, (key, value)| hash.merge(key => [value].flatten.map {|action| action.to_s})}
+ # :except => :foo == :except => [:foo] == :except => "foo" == :except => ["foo"]
+ conditions.each {|k, v| conditions[k] = Array(v).map {|a| a.to_s} }
+ write_inheritable_hash(:layout_conditions, conditions)
end
end
-
- # Returns the name of the active layout. If the layout was specified as a method reference (through a symbol), this method
- # is called and the return value is used. Likewise if the layout was specified as an inline method (through a proc or method
- # object). If the layout was defined without a directory, layouts is assumed. So <tt>layout "weblog/standard"</tt> will return
- # weblog/standard, but <tt>layout "standard"</tt> will return layouts/standard.
- def active_layout(passed_layout = nil, options = {})
- layout = passed_layout || default_layout
- return layout if layout.respond_to?(:render)
-
- active_layout = case layout
- when Symbol then __send__(layout)
- when Proc then layout.call(self)
- else layout
+
+ def active_layout(name)
+ name = self.class.default_layout(formats) if name == true
+
+ layout_name = case name
+ when Symbol then __send__(name)
+ when Proc then name.call(self)
+ else name
end
- find_layout(active_layout, default_template_format, options[:html_fallback]) if active_layout
+ self.class.find_layout(layout_name, formats)
end
- private
- def default_layout #:nodoc:
- layout = self.class.read_inheritable_attribute(:layout)
- return layout unless self.class.read_inheritable_attribute(:auto_layout)
- find_layout(layout, default_template_format)
- rescue ActionView::MissingTemplate
- nil
- end
-
- def find_layout(layout, format, html_fallback=false) #:nodoc:
- view_paths.find_template(layout.to_s =~ /layouts\// ? layout : "layouts/#{layout}", format, html_fallback)
- rescue ActionView::MissingTemplate
- raise if Mime::Type.lookup_by_extension(format.to_s).html?
- end
-
- def pick_layout(options)
- if options.has_key?(:layout)
- case layout = options.delete(:layout)
- when FalseClass
- nil
- when NilClass, TrueClass
- active_layout if action_has_layout? && candidate_for_layout?(:template => default_template_name)
- else
- active_layout(layout, :html_fallback => true)
- end
- else
- active_layout if action_has_layout? && candidate_for_layout?(options)
- end
- end
+ def _pick_layout(layout_name, implicit = false)
+ return unless layout_name || implicit
+ layout_name = true if layout_name.nil?
+ active_layout(layout_name) if action_has_layout? && layout_name
+ end
+ private
def action_has_layout?
if conditions = self.class.layout_conditions
- case
- when only = conditions[:only]
- only.include?(action_name)
- when except = conditions[:except]
- !except.include?(action_name)
- else
- true
+ if only = conditions[:only]
+ return only.include?(action_name)
+ elsif except = conditions[:except]
+ return !except.include?(action_name)
end
- else
- true
end
+ true
end
- def candidate_for_layout?(options)
- template = options[:template] || default_template(options[:action])
- if options.values_at(:text, :xml, :json, :file, :inline, :partial, :nothing, :update).compact.empty?
- begin
- template_object = self.view_paths.find_template(template, default_template_format)
- # this restores the behavior from 2.2.2, where response.template.template_format was reset
- # to :html for :js requests with a matching html template.
- # see v2.2.2, ActionView::Base, lines 328-330
- @real_format = :html if response.template.template_format == :js && template_object.format == "html"
- !template_object.exempt_from_layout?
- rescue ActionView::MissingTemplate
- true
- end
- end
- rescue ActionView::MissingTemplate
- false
- end
-
- def default_template_format
- @real_format || response.template.template_format
- end
end
end
diff --git a/actionpack/lib/action_controller/base/redirect.rb b/actionpack/lib/action_controller/base/redirect.rb
new file mode 100644
index 0000000000..2e92117e7c
--- /dev/null
+++ b/actionpack/lib/action_controller/base/redirect.rb
@@ -0,0 +1,91 @@
+module ActionController
+ class RedirectBackError < ActionControllerError #:nodoc:
+ DEFAULT_MESSAGE = 'No HTTP_REFERER was set in the request to this action, so redirect_to :back could not be called successfully. If this is a test, make sure to specify request.env["HTTP_REFERER"].'
+
+ def initialize(message = nil)
+ super(message || DEFAULT_MESSAGE)
+ end
+ end
+
+ module Redirector
+
+ # Redirects the browser to the target specified in +options+. This parameter can take one of three forms:
+ #
+ # * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.
+ # * <tt>Record</tt> - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record.
+ # * <tt>String</tt> starting with <tt>protocol://</tt> (like <tt>http://</tt>) - Is passed straight through as the target for redirection.
+ # * <tt>String</tt> not containing a protocol - The current protocol and host is prepended to the string.
+ # * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
+ # Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt>
+ #
+ # Examples:
+ # redirect_to :action => "show", :id => 5
+ # redirect_to post
+ # redirect_to "http://www.rubyonrails.org"
+ # redirect_to "/images/screenshot.jpg"
+ # redirect_to articles_url
+ # redirect_to :back
+ #
+ # The redirection happens as a "302 Moved" header unless otherwise specified.
+ #
+ # Examples:
+ # redirect_to post_url(@post), :status=>:found
+ # redirect_to :action=>'atom', :status=>:moved_permanently
+ # redirect_to post_url(@post), :status=>301
+ # redirect_to :action=>'atom', :status=>302
+ #
+ # When using <tt>redirect_to :back</tt>, if there is no referrer,
+ # RedirectBackError will be raised. You may specify some fallback
+ # behavior for this case by rescuing RedirectBackError.
+ def redirect_to(options = {}, response_status = {}) #:doc:
+ raise ActionControllerError.new("Cannot redirect to nil!") if options.nil?
+
+ if options.is_a?(Hash) && options[:status]
+ status = options.delete(:status)
+ elsif response_status[:status]
+ status = response_status[:status]
+ else
+ status = 302
+ end
+
+ response.redirected_to = options
+
+ case options
+ # The scheme name consist of a letter followed by any combination of
+ # letters, digits, and the plus ("+"), period ("."), or hyphen ("-")
+ # characters; and is terminated by a colon (":").
+ when %r{^\w[\w\d+.-]*:.*}
+ redirect_to_full_url(options, status)
+ when String
+ redirect_to_full_url(request.protocol + request.host_with_port + options, status)
+ when :back
+ if referer = request.headers["Referer"]
+ redirect_to(referer, :status=>status)
+ else
+ raise RedirectBackError
+ end
+ else
+ redirect_to_full_url(url_for(options), status)
+ end
+ end
+
+ def redirect_to_full_url(url, status)
+ raise DoubleRenderError if performed?
+ logger.info("Redirected to #{url}") if logger && logger.info?
+ response.redirect(url, interpret_status(status))
+ @performed_redirect = true
+ end
+
+ # Clears the redirected results from the headers, resets the status to 200 and returns
+ # the URL that was used to redirect or nil if there was no redirected URL
+ # Note that +redirect_to+ will change the body of the response to indicate a redirection.
+ # The response body is not reset here, see +erase_render_results+
+ def erase_redirect_results #:nodoc:
+ @performed_redirect = false
+ response.redirected_to = nil
+ response.redirected_to_method_params = nil
+ response.status = DEFAULT_RENDER_STATUS_CODE
+ response.headers.delete('Location')
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/base/render.rb b/actionpack/lib/action_controller/base/render.rb
new file mode 100644
index 0000000000..c4a3725079
--- /dev/null
+++ b/actionpack/lib/action_controller/base/render.rb
@@ -0,0 +1,390 @@
+module ActionController
+ DEFAULT_RENDER_STATUS_CODE = "200 OK"
+
+ class DoubleRenderError < ActionControllerError #:nodoc:
+ DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"."
+
+ def initialize(message = nil)
+ super(message || DEFAULT_MESSAGE)
+ end
+ end
+
+ module Renderer
+
+ protected
+ # Renders the content that will be returned to the browser as the response body.
+ #
+ # === Rendering an action
+ #
+ # Action rendering is the most common form and the type used automatically by Action Controller when nothing else is
+ # specified. By default, actions are rendered within the current layout (if one exists).
+ #
+ # # Renders the template for the action "goal" within the current controller
+ # render :action => "goal"
+ #
+ # # Renders the template for the action "short_goal" within the current controller,
+ # # but without the current active layout
+ # render :action => "short_goal", :layout => false
+ #
+ # # Renders the template for the action "long_goal" within the current controller,
+ # # but with a custom layout
+ # render :action => "long_goal", :layout => "spectacular"
+ #
+ # === Rendering partials
+ #
+ # Partial rendering in a controller is most commonly used together with Ajax calls that only update one or a few elements on a page
+ # without reloading. Rendering of partials from the controller makes it possible to use the same partial template in
+ # both the full-page rendering (by calling it from within the template) and when sub-page updates happen (from the
+ # controller action responding to Ajax calls). By default, the current layout is not used.
+ #
+ # # Renders the same partial with a local variable.
+ # render :partial => "person", :locals => { :name => "david" }
+ #
+ # # Renders the partial, making @new_person available through
+ # # the local variable 'person'
+ # render :partial => "person", :object => @new_person
+ #
+ # # Renders a collection of the same partial by making each element
+ # # of @winners available through the local variable "person" as it
+ # # builds the complete response.
+ # render :partial => "person", :collection => @winners
+ #
+ # # Renders a collection of partials but with a custom local variable name
+ # render :partial => "admin_person", :collection => @winners, :as => :person
+ #
+ # # Renders the same collection of partials, but also renders the
+ # # person_divider partial between each person partial.
+ # render :partial => "person", :collection => @winners, :spacer_template => "person_divider"
+ #
+ # # Renders a collection of partials located in a view subfolder
+ # # outside of our current controller. In this example we will be
+ # # rendering app/views/shared/_note.r(html|xml) Inside the partial
+ # # each element of @new_notes is available as the local var "note".
+ # render :partial => "shared/note", :collection => @new_notes
+ #
+ # # Renders the partial with a status code of 500 (internal error).
+ # render :partial => "broken", :status => 500
+ #
+ # Note that the partial filename must also be a valid Ruby variable name,
+ # so e.g. 2005 and register-user are invalid.
+ #
+ #
+ # == Automatic etagging
+ #
+ # Rendering will automatically insert the etag header on 200 OK responses. The etag is calculated using MD5 of the
+ # response body. If a request comes in that has a matching etag, the response will be changed to a 304 Not Modified
+ # and the response body will be set to an empty string. No etag header will be inserted if it's already set.
+ #
+ # === Rendering a template
+ #
+ # Template rendering works just like action rendering except that it takes a path relative to the template root.
+ # The current layout is automatically applied.
+ #
+ # # Renders the template located in [TEMPLATE_ROOT]/weblog/show.r(html|xml) (in Rails, app/views/weblog/show.erb)
+ # render :template => "weblog/show"
+ #
+ # # Renders the template with a local variable
+ # render :template => "weblog/show", :locals => {:customer => Customer.new}
+ #
+ # === Rendering a file
+ #
+ # File rendering works just like action rendering except that it takes a filesystem path. By default, the path
+ # is assumed to be absolute, and the current layout is not applied.
+ #
+ # # Renders the template located at the absolute filesystem path
+ # render :file => "/path/to/some/template.erb"
+ # render :file => "c:/path/to/some/template.erb"
+ #
+ # # Renders a template within the current layout, and with a 404 status code
+ # render :file => "/path/to/some/template.erb", :layout => true, :status => 404
+ # render :file => "c:/path/to/some/template.erb", :layout => true, :status => 404
+ #
+ # === Rendering text
+ #
+ # Rendering of text is usually used for tests or for rendering prepared content, such as a cache. By default, text
+ # rendering is not done within the active layout.
+ #
+ # # Renders the clear text "hello world" with status code 200
+ # render :text => "hello world!"
+ #
+ # # Renders the clear text "Explosion!" with status code 500
+ # render :text => "Explosion!", :status => 500
+ #
+ # # Renders the clear text "Hi there!" within the current active layout (if one exists)
+ # render :text => "Hi there!", :layout => true
+ #
+ # # Renders the clear text "Hi there!" within the layout
+ # # placed in "app/views/layouts/special.r(html|xml)"
+ # render :text => "Hi there!", :layout => "special"
+ #
+ # The <tt>:text</tt> option can also accept a Proc object, which can be used to manually control the page generation. This should
+ # generally be avoided, as it violates the separation between code and content, and because almost everything that can be
+ # done with this method can also be done more cleanly using one of the other rendering methods, most notably templates.
+ #
+ # # Renders "Hello from code!"
+ # render :text => proc { |response, output| output.write("Hello from code!") }
+ #
+ # === Rendering XML
+ #
+ # Rendering XML sets the content type to application/xml.
+ #
+ # # Renders '<name>David</name>'
+ # render :xml => {:name => "David"}.to_xml
+ #
+ # It's not necessary to call <tt>to_xml</tt> on the object you want to render, since <tt>render</tt> will
+ # automatically do that for you:
+ #
+ # # Also renders '<name>David</name>'
+ # render :xml => {:name => "David"}
+ #
+ # === Rendering JSON
+ #
+ # Rendering JSON sets the content type to application/json and optionally wraps the JSON in a callback. It is expected
+ # that the response will be parsed (or eval'd) for use as a data structure.
+ #
+ # # Renders '{"name": "David"}'
+ # render :json => {:name => "David"}.to_json
+ #
+ # It's not necessary to call <tt>to_json</tt> on the object you want to render, since <tt>render</tt> will
+ # automatically do that for you:
+ #
+ # # Also renders '{"name": "David"}'
+ # render :json => {:name => "David"}
+ #
+ # Sometimes the result isn't handled directly by a script (such as when the request comes from a SCRIPT tag),
+ # so the <tt>:callback</tt> option is provided for these cases.
+ #
+ # # Renders 'show({"name": "David"})'
+ # render :json => {:name => "David"}.to_json, :callback => 'show'
+ #
+ # === Rendering an inline template
+ #
+ # Rendering of an inline template works as a cross between text and action rendering where the source for the template
+ # is supplied inline, like text, but its interpreted with ERb or Builder, like action. By default, ERb is used for rendering
+ # and the current layout is not used.
+ #
+ # # Renders "hello, hello, hello, again"
+ # render :inline => "<%= 'hello, ' * 3 + 'again' %>"
+ #
+ # # Renders "<p>Good seeing you!</p>" using Builder
+ # render :inline => "xml.p { 'Good seeing you!' }", :type => :builder
+ #
+ # # Renders "hello david"
+ # render :inline => "<%= 'hello ' + name %>", :locals => { :name => "david" }
+ #
+ # === Rendering inline JavaScriptGenerator page updates
+ #
+ # In addition to rendering JavaScriptGenerator page updates with Ajax in RJS templates (see ActionView::Base for details),
+ # you can also pass the <tt>:update</tt> parameter to +render+, along with a block, to render page updates inline.
+ #
+ # render :update do |page|
+ # page.replace_html 'user_list', :partial => 'user', :collection => @users
+ # page.visual_effect :highlight, 'user_list'
+ # end
+ #
+ # === Rendering vanilla JavaScript
+ #
+ # In addition to using RJS with render :update, you can also just render vanilla JavaScript with :js.
+ #
+ # # Renders "alert('hello')" and sets the mime type to text/javascript
+ # render :js => "alert('hello')"
+ #
+ # === Rendering with status and location headers
+ # All renders take the <tt>:status</tt> and <tt>:location</tt> options and turn them into headers. They can even be used together:
+ #
+ # render :xml => post.to_xml, :status => :created, :location => post_url(post)
+ def render(options = nil, extra_options = {}, &block) #:doc:
+ raise DoubleRenderError, "Can only render or redirect once per action" if performed?
+
+ options = { :layout => true } if options.nil?
+
+ # This handles render "string", render :symbol, and render object
+ # render string and symbol are handled by render_for_name
+ # render object becomes render :partial => object
+ unless options.is_a?(Hash)
+ if options.is_a?(String) || options.is_a?(Symbol)
+ original, options = options, extra_options
+ else
+ extra_options[:partial], options = options, extra_options
+ end
+ end
+
+ layout_name = options.delete(:layout)
+
+ _process_options(options)
+
+ if block_given?
+ @template.send(:_evaluate_assigns_and_ivars)
+
+ generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(@template, &block)
+ response.content_type = Mime::JS
+ return render_for_text(generator.to_s)
+ end
+
+ if original
+ return render_for_name(original, layout_name, options) unless block_given?
+ end
+
+ if options.key?(:text)
+ return render_for_text(@template._render_text(options[:text],
+ _pick_layout(layout_name), options))
+ end
+
+ file, template = options.values_at(:file, :template)
+ if file || template
+ file = template.sub(/^\//, '') if template
+ return render_for_file(file, [layout_name, !!template], options)
+ end
+
+ if action_option = options[:action]
+ return render_for_action(action_option, [layout_name, true], options)
+ end
+
+ if inline = options[:inline]
+ render_for_text(@template._render_inline(inline, _pick_layout(layout_name), options))
+
+ elsif xml = options[:xml]
+ response.content_type ||= Mime::XML
+ render_for_text(xml.respond_to?(:to_xml) ? xml.to_xml : xml)
+
+ elsif js = options[:js]
+ response.content_type ||= Mime::JS
+ render_for_text(js)
+
+ elsif json = options[:json]
+ json = json.to_json unless json.is_a?(String)
+ json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
+ response.content_type ||= Mime::JSON
+ render_for_text(json)
+
+ elsif partial = options[:partial]
+ if partial == true
+ parts = [action_name_base, formats, controller_name, true]
+ elsif partial.is_a?(String)
+ parts = partial_parts(partial, options)
+ else
+ return render_for_text(@template._render_partial(options))
+ end
+
+ render_for_parts(parts, layout_name, options)
+
+ elsif options[:nothing]
+ render_for_text(nil)
+
+ else
+ render_for_parts([action_name, formats, controller_path], layout_name, options)
+ end
+ end
+
+ def partial_parts(name, options)
+ segments = name.split("/")
+ parts = segments.pop.split(".")
+
+ case parts.size
+ when 1
+ parts
+ when 2, 3
+ extension = parts.delete_at(1).to_sym
+ if formats.include?(extension)
+ self.formats.replace [extension]
+ end
+ parts.pop if parts.size == 2
+ end
+
+ path = parts.join(".")
+ prefix = segments[0..-1].join("/")
+ prefix = prefix.blank? ? controller_path : prefix
+ parts = [path, formats, prefix]
+ parts.push options[:object] || true
+ end
+
+ def formats
+ @_request.formats.map {|f| f.symbol }.compact
+ end
+
+ def action_name_base(name = action_name)
+ (name.is_a?(String) ? name.sub(/^#{controller_path}\//, '') : name).to_s
+ end
+
+ # Renders according to the same rules as <tt>render</tt>, but returns the result in a string instead
+ # of sending it as the response body to the browser.
+ def render_to_string(options = nil, &block) #:doc:
+ render(options, &block)
+ response.body
+ ensure
+ response.content_type = nil
+ erase_render_results
+ reset_variables_added_to_assigns
+ end
+
+ # Clears the rendered results, allowing for another render to be performed.
+ def erase_render_results #:nodoc:
+ response.body = []
+ @performed_render = false
+ end
+
+ # Erase both render and redirect results
+ def erase_results #:nodoc:
+ erase_render_results
+ erase_redirect_results
+ end
+
+ # Return a response that has no content (merely headers). The options
+ # argument is interpreted to be a hash of header names and values.
+ # This allows you to easily return a response that consists only of
+ # significant headers:
+ #
+ # head :created, :location => person_path(@person)
+ #
+ # It can also be used to return exceptional conditions:
+ #
+ # return head(:method_not_allowed) unless request.post?
+ # return head(:bad_request) unless valid_request?
+ # render
+ def head(*args)
+ if args.length > 2
+ raise ArgumentError, "too many arguments to head"
+ elsif args.empty?
+ raise ArgumentError, "too few arguments to head"
+ end
+ options = args.extract_options!
+ status = interpret_status(args.shift || options.delete(:status) || :ok)
+
+ options.each do |key, value|
+ headers[key.to_s.dasherize.split(/-/).map { |v| v.capitalize }.join("-")] = value.to_s
+ end
+
+ render :nothing => true, :status => status
+ end
+
+ private
+ def render_for_name(name, layout, options)
+ case name.to_s.index('/')
+ when 0
+ render_for_file(name, layout, options)
+ when nil
+ render_for_action(name, layout, options)
+ else
+ render_for_file(name.sub(/^\//, ''), [layout, true], options)
+ end
+ end
+
+ def render_for_parts(parts, layout, options = {})
+ tmp = view_paths.find_by_parts(*parts)
+
+ layout = _pick_layout(*layout) unless tmp.exempt_from_layout?
+
+ render_for_text(
+ @template._render_template_with_layout(tmp, layout, options, parts[3]))
+ end
+
+ def render_for_file(file, layout, options)
+ render_for_parts([file, [request.format.to_sym]], layout, options)
+ end
+
+ def render_for_action(name, layout, options)
+ parts = [action_name_base(name), formats, controller_name]
+ render_for_parts(parts, layout, options)
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/request_forgery_protection.rb b/actionpack/lib/action_controller/base/request_forgery_protection.rb
index f3e6288c26..f3e6288c26 100644
--- a/actionpack/lib/action_controller/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/base/request_forgery_protection.rb
diff --git a/actionpack/lib/action_controller/base/responder.rb b/actionpack/lib/action_controller/base/responder.rb
new file mode 100644
index 0000000000..989f82444b
--- /dev/null
+++ b/actionpack/lib/action_controller/base/responder.rb
@@ -0,0 +1,42 @@
+module ActionController
+ module Responder
+ def self.included(klass)
+ klass.extend ClassMethods
+ end
+
+ private
+ def render_for_text(text = nil, append_response = false) #:nodoc:
+ @performed_render = true
+
+ if append_response
+ response.body ||= ''
+ response.body << text.to_s
+ else
+ response.body = case text
+ when Proc then text
+ when nil then " " # Safari doesn't pass the headers of the return if the response is zero length
+ else text.to_s
+ end
+ end
+ end
+
+ # Returns a set of the methods defined as actions in your controller
+ def action_methods
+ self.class.action_methods
+ end
+
+ module ClassMethods
+ def action_methods
+ @action_methods ||=
+ # All public instance methods of this class, including ancestors
+ public_instance_methods(true).map { |m| m.to_s }.to_set -
+ # Except for public instance methods of Base and its ancestors
+ Base.public_instance_methods(true).map { |m| m.to_s } +
+ # Be sure to include shadowed public instance methods of this class
+ public_instance_methods(false).map { |m| m.to_s } -
+ # And always exclude explicitly hidden actions
+ hidden_actions
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/streaming.rb b/actionpack/lib/action_controller/base/streaming.rb
index 9f80f48c3d..9f80f48c3d 100644
--- a/actionpack/lib/action_controller/streaming.rb
+++ b/actionpack/lib/action_controller/base/streaming.rb
diff --git a/actionpack/lib/action_controller/verification.rb b/actionpack/lib/action_controller/base/verification.rb
index c62b81b666..c62b81b666 100644
--- a/actionpack/lib/action_controller/verification.rb
+++ b/actionpack/lib/action_controller/base/verification.rb
diff --git a/actionpack/lib/action_controller/cgi_ext.rb b/actionpack/lib/action_controller/cgi/ext.rb
index 406b6f06d6..558748f4bd 100644
--- a/actionpack/lib/action_controller/cgi_ext.rb
+++ b/actionpack/lib/action_controller/cgi/ext.rb
@@ -1,6 +1,6 @@
-require 'action_controller/cgi_ext/stdinput'
-require 'action_controller/cgi_ext/query_extension'
-require 'action_controller/cgi_ext/cookie'
+require 'action_controller/cgi/ext/stdinput'
+require 'action_controller/cgi/ext/query_extension'
+require 'action_controller/cgi/ext/cookie'
class CGI #:nodoc:
include ActionController::CgiExt::Stdinput
diff --git a/actionpack/lib/action_controller/cgi_ext/cookie.rb b/actionpack/lib/action_controller/cgi/ext/cookie.rb
index 9cd19bb12d..9cd19bb12d 100644
--- a/actionpack/lib/action_controller/cgi_ext/cookie.rb
+++ b/actionpack/lib/action_controller/cgi/ext/cookie.rb
diff --git a/actionpack/lib/action_controller/cgi_ext/query_extension.rb b/actionpack/lib/action_controller/cgi/ext/query_extension.rb
index 9620fd2873..9620fd2873 100644
--- a/actionpack/lib/action_controller/cgi_ext/query_extension.rb
+++ b/actionpack/lib/action_controller/cgi/ext/query_extension.rb
diff --git a/actionpack/lib/action_controller/cgi_ext/stdinput.rb b/actionpack/lib/action_controller/cgi/ext/stdinput.rb
index 5e9b6784af..5e9b6784af 100644
--- a/actionpack/lib/action_controller/cgi_ext/stdinput.rb
+++ b/actionpack/lib/action_controller/cgi/ext/stdinput.rb
diff --git a/actionpack/lib/action_controller/cgi_process.rb b/actionpack/lib/action_controller/cgi/process.rb
index 54ff04cfd2..34b97776f5 100644
--- a/actionpack/lib/action_controller/cgi_process.rb
+++ b/actionpack/lib/action_controller/cgi/process.rb
@@ -1,5 +1,3 @@
-require 'action_controller/cgi_ext'
-
module ActionController #:nodoc:
class CGIHandler
module ProperStream
diff --git a/actionpack/lib/action_controller/dispatcher.rb b/actionpack/lib/action_controller/dispatch/dispatcher.rb
index 07931e4a4a..74c72e1a8b 100644
--- a/actionpack/lib/action_controller/dispatcher.rb
+++ b/actionpack/lib/action_controller/dispatch/dispatcher.rb
@@ -6,7 +6,7 @@ module ActionController
def define_dispatcher_callbacks(cache_classes)
unless cache_classes
unless self.middleware.include?(Reloader)
- self.middleware.insert_after(Failsafe, Reloader)
+ self.middleware.insert_after(ActionDispatch::Failsafe, Reloader)
end
ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false
@@ -68,7 +68,7 @@ module ActionController
end
cattr_accessor :middleware
- self.middleware = MiddlewareStack.new do |middleware|
+ self.middleware = ActionDispatch::MiddlewareStack.new do |middleware|
middlewares = File.join(File.dirname(__FILE__), "middlewares.rb")
middleware.instance_eval(File.read(middlewares))
end
diff --git a/actionpack/lib/action_controller/middlewares.rb b/actionpack/lib/action_controller/dispatch/middlewares.rb
index 371cf6d8f7..b62b4f84a1 100644
--- a/actionpack/lib/action_controller/middlewares.rb
+++ b/actionpack/lib/action_controller/dispatch/middlewares.rb
@@ -2,12 +2,12 @@ use "Rack::Lock", :if => lambda {
!ActionController::Base.allow_concurrency
}
-use "ActionController::Failsafe"
+use "ActionDispatch::Failsafe"
use lambda { ActionController::Base.session_store },
lambda { ActionController::Base.session_options }
-use "ActionController::RewindableInput"
-use "ActionController::ParamsParser"
+use "ActionDispatch::RewindableInput"
+use "ActionDispatch::ParamsParser"
use "Rack::MethodOverride"
use "Rack::Head"
diff --git a/actionpack/lib/action_controller/rescue.rb b/actionpack/lib/action_controller/dispatch/rescue.rb
index 242c8da920..ec9eff65a9 100644
--- a/actionpack/lib/action_controller/rescue.rb
+++ b/actionpack/lib/action_controller/dispatch/rescue.rb
@@ -38,7 +38,7 @@ module ActionController #:nodoc:
'ActionView::TemplateError' => 'template_error'
}
- RESCUES_TEMPLATE_PATH = ActionView::Template::EagerPath.new_and_loaded(
+ RESCUES_TEMPLATE_PATH = ActionView::Template::EagerPath.new(
File.join(File.dirname(__FILE__), "templates"))
def self.included(base) #:nodoc:
@@ -60,8 +60,8 @@ module ActionController #:nodoc:
module ClassMethods
def call_with_exception(env, exception) #:nodoc:
- request = env["action_controller.rescue.request"] ||= Request.new(env)
- response = env["action_controller.rescue.response"] ||= Response.new
+ request = env["action_controller.rescue.request"] ||= ActionDispatch::Request.new(env)
+ response = env["action_controller.rescue.response"] ||= ActionDispatch::Response.new
new.process(request, response, :rescue_action, exception)
end
end
@@ -131,11 +131,13 @@ module ActionController #:nodoc:
@template.instance_variable_set("@exception", exception)
@template.instance_variable_set("@rescues_path", RESCUES_TEMPLATE_PATH)
@template.instance_variable_set("@contents",
- @template.render(:file => template_path_for_local_rescue(exception)))
+ @template._render_template(template_path_for_local_rescue(exception)))
response.content_type = Mime::HTML
- render_for_file(rescues_path("layout"),
- response_code_for_rescue(exception))
+ response.status = interpret_status(response_code_for_rescue(exception))
+
+ content = @template._render_template(rescues_path("layout"))
+ render_for_text(content)
end
def rescue_action_without_handler(exception)
@@ -163,7 +165,7 @@ module ActionController #:nodoc:
end
def rescues_path(template_name)
- RESCUES_TEMPLATE_PATH["rescues/#{template_name}.erb"]
+ RESCUES_TEMPLATE_PATH.find_template("rescues/#{template_name}.erb")
end
def template_path_for_local_rescue(exception)
diff --git a/actionpack/lib/action_controller/templates/rescues/_request_and_response.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/_request_and_response.erb
index 64b34650b1..64b34650b1 100644
--- a/actionpack/lib/action_controller/templates/rescues/_request_and_response.erb
+++ b/actionpack/lib/action_controller/dispatch/templates/rescues/_request_and_response.erb
diff --git a/actionpack/lib/action_controller/templates/rescues/_trace.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/_trace.erb
index bb2d8375bd..bb2d8375bd 100644
--- a/actionpack/lib/action_controller/templates/rescues/_trace.erb
+++ b/actionpack/lib/action_controller/dispatch/templates/rescues/_trace.erb
diff --git a/actionpack/lib/action_controller/templates/rescues/diagnostics.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/diagnostics.erb
index 669da1b26e..95be64511d 100644
--- a/actionpack/lib/action_controller/templates/rescues/diagnostics.erb
+++ b/actionpack/lib/action_controller/dispatch/templates/rescues/diagnostics.erb
@@ -6,6 +6,5 @@
</h1>
<pre><%=h @exception.clean_message %></pre>
-<%= render :file => @rescues_path["rescues/_trace.erb"] %>
-
-<%= render :file => @rescues_path["rescues/_request_and_response.erb"] %>
+<%= @template._render_template(@rescues_path.find_template("rescues/_trace.erb")) %>
+<%= @template._render_template(@rescues_path.find_template("rescues/_request_and_response.erb")) %> \ No newline at end of file
diff --git a/actionpack/lib/action_controller/templates/rescues/layout.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/layout.erb
index 4a04742e40..4a04742e40 100644
--- a/actionpack/lib/action_controller/templates/rescues/layout.erb
+++ b/actionpack/lib/action_controller/dispatch/templates/rescues/layout.erb
diff --git a/actionpack/lib/action_controller/templates/rescues/missing_template.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/missing_template.erb
index dbfdf76947..dbfdf76947 100644
--- a/actionpack/lib/action_controller/templates/rescues/missing_template.erb
+++ b/actionpack/lib/action_controller/dispatch/templates/rescues/missing_template.erb
diff --git a/actionpack/lib/action_controller/templates/rescues/routing_error.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/routing_error.erb
index ccfa858cce..ccfa858cce 100644
--- a/actionpack/lib/action_controller/templates/rescues/routing_error.erb
+++ b/actionpack/lib/action_controller/dispatch/templates/rescues/routing_error.erb
diff --git a/actionpack/lib/action_controller/templates/rescues/template_error.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/template_error.erb
index 2e34e03bd5..2e34e03bd5 100644
--- a/actionpack/lib/action_controller/templates/rescues/template_error.erb
+++ b/actionpack/lib/action_controller/dispatch/templates/rescues/template_error.erb
diff --git a/actionpack/lib/action_controller/templates/rescues/unknown_action.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/unknown_action.erb
index 683379da10..683379da10 100644
--- a/actionpack/lib/action_controller/templates/rescues/unknown_action.erb
+++ b/actionpack/lib/action_controller/dispatch/templates/rescues/unknown_action.erb
diff --git a/actionpack/lib/action_controller/mime_responds.rb b/actionpack/lib/action_controller/mime/responds.rb
index b755363873..bac225ab2a 100644
--- a/actionpack/lib/action_controller/mime_responds.rb
+++ b/actionpack/lib/action_controller/mime/responds.rb
@@ -109,16 +109,13 @@ module ActionController #:nodoc:
end
class Responder #:nodoc:
+
def initialize(controller)
@controller = controller
@request = controller.request
@response = controller.response
- if ActionController::Base.use_accept_header
- @mime_type_priority = Array(Mime::Type.lookup_by_extension(@request.parameters[:format]) || @request.accepts)
- else
- @mime_type_priority = [@request.format]
- end
+ @mime_type_priority = @request.formats
@order = []
@responses = {}
@@ -130,7 +127,7 @@ module ActionController #:nodoc:
@order << mime_type
@responses[mime_type] ||= Proc.new do
- @response.template.template_format = mime_type.to_sym
+ @response.template.formats = [mime_type.to_sym]
@response.content_type = mime_type.to_s
block_given? ? block.call : @controller.send(:render, :action => @controller.action_name)
end
diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb
new file mode 100644
index 0000000000..7c65f1cdc1
--- /dev/null
+++ b/actionpack/lib/action_controller/new_base.rb
@@ -0,0 +1,7 @@
+module ActionController
+ autoload :AbstractBase, "action_controller/new_base/base"
+ autoload :HideActions, "action_controller/new_base/hide_actions"
+ autoload :Layouts, "action_controller/new_base/layouts"
+ autoload :Renderer, "action_controller/new_base/renderer"
+ autoload :UrlFor, "action_controller/new_base/url_for"
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb
new file mode 100644
index 0000000000..0400ddbf7a
--- /dev/null
+++ b/actionpack/lib/action_controller/new_base/base.rb
@@ -0,0 +1,61 @@
+module ActionController
+ class AbstractBase < AbstractController::Base
+
+ # :api: public
+ attr_internal :request, :response, :params
+
+ # :api: public
+ def self.controller_name
+ @controller_name ||= controller_path.split("/").last
+ end
+
+ # :api: public
+ def controller_name() self.class.controller_name end
+
+ # :api: public
+ def self.controller_path
+ @controller_path ||= self.name.sub(/Controller$/, '').underscore
+ end
+
+ # :api: public
+ def controller_path() self.class.controller_path end
+
+ # :api: private
+ def self.action_methods
+ @action_names ||= Set.new(self.public_instance_methods - self::CORE_METHODS)
+ end
+
+ # :api: private
+ def self.action_names() action_methods end
+
+ # :api: private
+ def action_methods() self.class.action_names end
+
+ # :api: private
+ def action_names() action_methods end
+
+ # :api: plugin
+ def self.call(env)
+ controller = new
+ controller.call(env).to_rack
+ end
+
+ # :api: plugin
+ def response_body=(body)
+ @_response["Content-Length"] = body.length
+ @_response.body = body
+ end
+
+ # :api: private
+ def call(env)
+ @_request = ActionDispatch::Request.new(env)
+ @_response = ActionDispatch::Response.new
+ process(@_request.parameters[:action])
+ end
+
+ # :api: private
+ def to_rack
+ response.to_a
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/new_base/hide_actions.rb b/actionpack/lib/action_controller/new_base/hide_actions.rb
new file mode 100644
index 0000000000..473a8ea72b
--- /dev/null
+++ b/actionpack/lib/action_controller/new_base/hide_actions.rb
@@ -0,0 +1,31 @@
+module ActionController
+ module HideActions
+ setup do
+ extlib_inheritable_accessor :hidden_actions
+ self.hidden_actions ||= Set.new
+ end
+
+ def action_methods() self.class.action_names end
+ def action_names() action_methods end
+
+ private
+
+ def respond_to_action?(action_name)
+ !hidden_actions.include?(action_name) && (super || respond_to?(:method_missing))
+ end
+
+ module ClassMethods
+ def hide_action(*args)
+ args.each do |arg|
+ self.hidden_actions << arg.to_s
+ end
+ end
+
+ def action_methods
+ @action_names ||= Set.new(super.reject {|name| self.hidden_actions.include?(name.to_s)})
+ end
+
+ def self.action_names() action_methods end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/new_base/layouts.rb b/actionpack/lib/action_controller/new_base/layouts.rb
new file mode 100644
index 0000000000..149847c968
--- /dev/null
+++ b/actionpack/lib/action_controller/new_base/layouts.rb
@@ -0,0 +1,37 @@
+module ActionController
+ module Layouts
+ depends_on ActionController::Renderer
+ depends_on AbstractController::Layouts
+
+ module ClassMethods
+ def _implied_layout_name
+ controller_path
+ end
+ end
+
+ def render_to_string(options)
+ # render :text => ..., :layout => ...
+ # or
+ # render :anything_else
+ if !options.key?(:text) || options.key?(:layout)
+ options[:_layout] = options.key?(:layout) ? _layout_for_option(options[:layout]) : _default_layout
+ end
+
+ super
+ end
+
+ private
+
+ def _layout_for_option(name)
+ case name
+ when String then _layout_for_name(name)
+ when true then _default_layout(true)
+ when false, nil then nil
+ else
+ raise ArgumentError,
+ "String, true, or false, expected for `layout'; you passed #{name.inspect}"
+ end
+ end
+
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb
new file mode 100644
index 0000000000..044c15f409
--- /dev/null
+++ b/actionpack/lib/action_controller/new_base/renderer.rb
@@ -0,0 +1,62 @@
+module ActionController
+ module Renderer
+ depends_on AbstractController::Renderer
+
+ def initialize(*)
+ self.formats = [:html]
+ super
+ end
+
+ def render(action, options = {})
+ # TODO: Move this into #render_to_string
+ if action.is_a?(Hash)
+ options, action = action, nil
+ else
+ options.merge! :action => action
+ end
+
+ _process_options(options)
+
+ self.response_body = render_to_string(options)
+ end
+
+ def render_to_string(options)
+ unless options.is_a?(Hash)
+ options = {:action => options}
+ end
+
+ if options.key?(:text)
+ options[:_template] = ActionView::TextTemplate.new(_text(options))
+ template = nil
+ elsif options.key?(:template)
+ options[:_template_name] = options[:template]
+ elsif options.key?(:action)
+ options[:_template_name] = options[:action].to_s
+ options[:_prefix] = _prefix
+ end
+
+ super(options)
+ end
+
+ private
+
+ def _prefix
+ controller_path
+ end
+
+ def _text(options)
+ text = options[:text]
+
+ case text
+ when nil then " "
+ else text.to_s
+ end
+ end
+
+ def _process_options(options)
+ if status = options[:status]
+ response.status = status.to_i
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/new_base/url_for.rb b/actionpack/lib/action_controller/new_base/url_for.rb
new file mode 100644
index 0000000000..af5b21012b
--- /dev/null
+++ b/actionpack/lib/action_controller/new_base/url_for.rb
@@ -0,0 +1,40 @@
+module ActionController
+ module UrlFor
+ def initialize_current_url
+ @url = UrlRewriter.new(request, params.clone)
+ end
+
+ # Overwrite to implement a number of default options that all url_for-based methods will use. The default options should come in
+ # the form of a hash, just like the one you would use for url_for directly. Example:
+ #
+ # def default_url_options(options)
+ # { :project => @project.active? ? @project.url_name : "unknown" }
+ # end
+ #
+ # As you can infer from the example, this is mostly useful for situations where you want to centralize dynamic decisions about the
+ # urls as they stem from the business domain. Please note that any individual url_for call can always override the defaults set
+ # by this method.
+ def default_url_options(options = nil)
+ end
+
+ def rewrite_options(options) #:nodoc:
+ if defaults = default_url_options(options)
+ defaults.merge(options)
+ else
+ options
+ end
+ end
+
+ def url_for(options = {})
+ options ||= {}
+ case options
+ when String
+ options
+ when Hash
+ @url.rewrite(rewrite_options(options))
+ else
+ polymorphic_url(options)
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb
index 742d290ad6..6bda27e23a 100644
--- a/actionpack/lib/action_controller/record_identifier.rb
+++ b/actionpack/lib/action_controller/record_identifier.rb
@@ -1,4 +1,4 @@
-module ActionController
+module ActionController
# The record identifier encapsulates a number of naming conventions for dealing with records, like Active Records or
# Active Resources or pretty much any other model type that has an id. These patterns are then used to try elevate
# the view actions to a higher logical level. Example:
diff --git a/actionpack/lib/action_controller/polymorphic_routes.rb b/actionpack/lib/action_controller/routing/generation/polymorphic_routes.rb
index d9b614c237..d9b614c237 100644
--- a/actionpack/lib/action_controller/polymorphic_routes.rb
+++ b/actionpack/lib/action_controller/routing/generation/polymorphic_routes.rb
diff --git a/actionpack/lib/action_controller/url_rewriter.rb b/actionpack/lib/action_controller/routing/generation/url_rewriter.rb
index 16720b915b..16720b915b 100644
--- a/actionpack/lib/action_controller/url_rewriter.rb
+++ b/actionpack/lib/action_controller/routing/generation/url_rewriter.rb
diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/routing/resources.rb
index 86abb7b2f4..86abb7b2f4 100644
--- a/actionpack/lib/action_controller/resources.rb
+++ b/actionpack/lib/action_controller/routing/resources.rb
diff --git a/actionpack/lib/action_controller/routing/route_set.rb b/actionpack/lib/action_controller/routing/route_set.rb
index 044ace7de1..70cd1f642d 100644
--- a/actionpack/lib/action_controller/routing/route_set.rb
+++ b/actionpack/lib/action_controller/routing/route_set.rb
@@ -428,7 +428,7 @@ module ActionController
end
def call(env)
- request = Request.new(env)
+ request = ActionDispatch::Request.new(env)
app = Routing::Routes.recognize(request)
app.call(env).to_a
end
diff --git a/actionpack/lib/action_controller/session_management.rb b/actionpack/lib/action_controller/session/management.rb
index b556f04649..ffce8e1bd1 100644
--- a/actionpack/lib/action_controller/session_management.rb
+++ b/actionpack/lib/action_controller/session/management.rb
@@ -26,7 +26,7 @@ module ActionController #:nodoc:
if defined? @@session_store
@@session_store
else
- Session::CookieStore
+ ActionDispatch::Session::CookieStore
end
end
diff --git a/actionpack/lib/action_controller/assertions/dom_assertions.rb b/actionpack/lib/action_controller/testing/assertions/dom.rb
index 5ffe5f1883..5ffe5f1883 100644
--- a/actionpack/lib/action_controller/assertions/dom_assertions.rb
+++ b/actionpack/lib/action_controller/testing/assertions/dom.rb
diff --git a/actionpack/lib/action_controller/assertions/model_assertions.rb b/actionpack/lib/action_controller/testing/assertions/model.rb
index 3a7b39b106..3a7b39b106 100644
--- a/actionpack/lib/action_controller/assertions/model_assertions.rb
+++ b/actionpack/lib/action_controller/testing/assertions/model.rb
diff --git a/actionpack/lib/action_controller/assertions/response_assertions.rb b/actionpack/lib/action_controller/testing/assertions/response.rb
index 5976090273..ca0a9bbf52 100644
--- a/actionpack/lib/action_controller/assertions/response_assertions.rb
+++ b/actionpack/lib/action_controller/testing/assertions/response.rb
@@ -11,7 +11,7 @@ module ActionController
#
# You can also pass an explicit status number like assert_response(501)
# or its symbolic equivalent assert_response(:not_implemented).
- # See ActionController::StatusCodes for a full list.
+ # See ActionDispatch::StatusCodes for a full list.
#
# ==== Examples
#
@@ -27,7 +27,7 @@ module ActionController
assert_block("") { true } # to count the assertion
elsif type.is_a?(Fixnum) && @response.response_code == type
assert_block("") { true } # to count the assertion
- elsif type.is_a?(Symbol) && @response.response_code == ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE[type]
+ elsif type.is_a?(Symbol) && @response.response_code == ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[type]
assert_block("") { true } # to count the assertion
else
if @response.error?
diff --git a/actionpack/lib/action_controller/assertions/routing_assertions.rb b/actionpack/lib/action_controller/testing/assertions/routing.rb
index 5101751cea..5101751cea 100644
--- a/actionpack/lib/action_controller/assertions/routing_assertions.rb
+++ b/actionpack/lib/action_controller/testing/assertions/routing.rb
diff --git a/actionpack/lib/action_controller/assertions/selector_assertions.rb b/actionpack/lib/action_controller/testing/assertions/selector.rb
index 0d56ea5ef7..0d56ea5ef7 100644
--- a/actionpack/lib/action_controller/assertions/selector_assertions.rb
+++ b/actionpack/lib/action_controller/testing/assertions/selector.rb
diff --git a/actionpack/lib/action_controller/assertions/tag_assertions.rb b/actionpack/lib/action_controller/testing/assertions/tag.rb
index 80249e0e83..80249e0e83 100644
--- a/actionpack/lib/action_controller/assertions/tag_assertions.rb
+++ b/actionpack/lib/action_controller/testing/assertions/tag.rb
diff --git a/actionpack/lib/action_controller/integration.rb b/actionpack/lib/action_controller/testing/integration.rb
index fda6b639d1..d51b9b63ff 100644
--- a/actionpack/lib/action_controller/integration.rb
+++ b/actionpack/lib/action_controller/testing/integration.rb
@@ -323,7 +323,7 @@ module ActionController
@html_document = nil
@status = status.to_i
- @status_message = StatusCodes::STATUS_CODES[@status]
+ @status_message = ActionDispatch::StatusCodes::STATUS_CODES[@status]
@headers = Rack::Utils::HeaderHash.new(headers)
@@ -348,7 +348,7 @@ module ActionController
else
# Decorate responses from Rack Middleware and Rails Metal
# as an Response for the purposes of integration testing
- @response = Response.new
+ @response = ActionDispatch::Response.new
@response.status = status.to_s
@response.headers.replace(@headers)
@response.body = @body_parts
@@ -387,7 +387,7 @@ module ActionController
"SERVER_PORT" => https? ? "443" : "80",
"HTTPS" => https? ? "on" : "off"
}
- UrlRewriter.new(Request.new(env), {})
+ UrlRewriter.new(ActionDispatch::Request.new(env), {})
end
def name_with_prefix(prefix, name)
diff --git a/actionpack/lib/action_controller/performance_test.rb b/actionpack/lib/action_controller/testing/performance.rb
index d88180087d..d88180087d 100644
--- a/actionpack/lib/action_controller/performance_test.rb
+++ b/actionpack/lib/action_controller/testing/performance.rb
diff --git a/actionpack/lib/action_controller/test_process.rb b/actionpack/lib/action_controller/testing/process.rb
index fbc1b519bf..86e193efa9 100644
--- a/actionpack/lib/action_controller/test_process.rb
+++ b/actionpack/lib/action_controller/testing/process.rb
@@ -1,6 +1,6 @@
require 'rack/session/abstract/id'
module ActionController #:nodoc:
- class TestRequest < Request #:nodoc:
+ class TestRequest < ActionDispatch::Request #:nodoc:
attr_accessor :cookies, :session_options
attr_accessor :query_parameters, :path, :session
attr_accessor :host
@@ -283,7 +283,7 @@ module ActionController #:nodoc:
# controller actions.
#
# See Response for more information on controller response objects.
- class TestResponse < Response
+ class TestResponse < ActionDispatch::Response
include TestResponseBehavior
def recycle!
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/testing/test_case.rb
index d2059d51f4..b020b755a0 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/testing/test_case.rb
@@ -1,5 +1,5 @@
require 'active_support/test_case'
-require 'action_controller/test_process'
+require 'action_controller/testing/process'
module ActionController
# Superclass for ActionController functional tests. Functional tests allow you to
diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb
new file mode 100644
index 0000000000..393ccaa795
--- /dev/null
+++ b/actionpack/lib/action_dispatch.rb
@@ -0,0 +1,64 @@
+#--
+# Copyright (c) 2004-2009 David Heinemeier Hansson
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#++
+
+begin
+ require 'active_support'
+rescue LoadError
+ activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
+ if File.directory?(activesupport_path)
+ $:.unshift activesupport_path
+ require 'active_support'
+ end
+end
+
+gem 'rack', '>= 0.9.0'
+require 'rack'
+require 'action_dispatch/rack'
+
+module ActionDispatch
+ autoload :Request, 'action_dispatch/http/request'
+ autoload :Response, 'action_dispatch/http/response'
+ autoload :StatusCodes, 'action_dispatch/http/status_codes'
+
+ autoload :Failsafe, 'action_dispatch/middleware/failsafe'
+ autoload :ParamsParser, 'action_dispatch/middleware/params_parser'
+ autoload :RewindableInput, 'action_dispatch/middleware/rewindable_input'
+
+ autoload :MiddlewareStack, 'action_dispatch/utils/middleware_stack'
+ autoload :UploadedFile, 'action_dispatch/utils/uploaded_file'
+ autoload :UploadedStringIO, 'action_dispatch/utils/uploaded_file'
+ autoload :UploadedTempfile, 'action_dispatch/utils/uploaded_file'
+ autoload :UrlEncodedPairParser, 'action_dispatch/utils/url_encoded_pair_parser'
+
+ module Http
+ autoload :Headers, 'action_dispatch/http/headers'
+ end
+
+ module Session
+ autoload :AbstractStore, 'action_dispatch/middleware/session/abstract_store'
+ autoload :CookieStore, 'action_dispatch/middleware/session/cookie_store'
+ autoload :MemCacheStore, 'action_dispatch/middleware/session/mem_cache_store'
+ end
+end
+
+autoload :Mime, 'action_dispatch/http/mime_type'
diff --git a/actionpack/lib/action_controller/headers.rb b/actionpack/lib/action_dispatch/http/headers.rb
index 139669c66f..2a41b4dbad 100644
--- a/actionpack/lib/action_controller/headers.rb
+++ b/actionpack/lib/action_dispatch/http/headers.rb
@@ -1,6 +1,6 @@
require 'active_support/memoizable'
-module ActionController
+module ActionDispatch
module Http
class Headers < ::Hash
extend ActiveSupport::Memoizable
diff --git a/actionpack/lib/action_controller/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb
index 017626ba27..02ad7f7d94 100644
--- a/actionpack/lib/action_controller/mime_type.rb
+++ b/actionpack/lib/action_dispatch/http/mime_type.rb
@@ -5,6 +5,10 @@ module Mime
EXTENSION_LOOKUP = Hash.new { |h, k| h[k] = Type.new(k) unless k.blank? }
LOOKUP = Hash.new { |h, k| h[k] = Type.new(k) unless k.blank? }
+ def self.[](type)
+ Type.lookup_by_extension(type.to_s)
+ end
+
# Encapsulates the notion of a mime type. Can be used at render time, for example, with:
#
# class PostsController < ActionController::Base
@@ -27,7 +31,7 @@ module Mime
# only needs to protect against these types.
@@browser_generated_types = Set.new [:html, :url_encoded_form, :multipart_form, :text]
cattr_reader :browser_generated_types
-
+ attr_reader :symbol
@@unverifiable_types = Set.new [:text, :json, :csv, :xml, :rss, :atom, :yaml]
def self.unverifiable_types
@@ -187,17 +191,13 @@ module Mime
# Returns true if Action Pack should check requests using this Mime Type for possible request forgery. See
# ActionController::RequestForgeryProtection.
def verify_request?
- browser_generated?
+ @@browser_generated_types.include?(to_sym)
end
def html?
@@html_types.include?(to_sym) || @string =~ /html/
end
- def browser_generated?
- @@browser_generated_types.include?(to_sym)
- end
-
private
def method_missing(method, *args)
if method.to_s =~ /(\w+)\?$/
@@ -209,4 +209,4 @@ module Mime
end
end
-require 'action_controller/mime_types'
+require 'action_dispatch/http/mime_types'
diff --git a/actionpack/lib/action_controller/mime_types.rb b/actionpack/lib/action_dispatch/http/mime_types.rb
index 2d7fba1173..2d7fba1173 100644
--- a/actionpack/lib/action_controller/mime_types.rb
+++ b/actionpack/lib/action_dispatch/http/mime_types.rb
diff --git a/actionpack/lib/action_controller/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index ef223f157c..7d47a1566e 100755
--- a/actionpack/lib/action_controller/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -3,9 +3,8 @@ require 'stringio'
require 'strscan'
require 'active_support/memoizable'
-require 'action_controller/cgi_ext'
-module ActionController
+module ActionDispatch
class Request < Rack::Request
%w[ AUTH_TYPE GATEWAY_INTERFACE
@@ -32,7 +31,7 @@ module ActionController
# <tt>:get</tt>. If the request \method is not listed in the HTTP_METHODS
# constant above, an UnknownHttpMethod exception is raised.
def request_method
- @request_method ||= HTTP_METHOD_LOOKUP[super] || raise(UnknownHttpMethod, "#{super}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}")
+ @request_method ||= HTTP_METHOD_LOOKUP[super] || raise(ActionController::UnknownHttpMethod, "#{super}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}")
end
# Returns the HTTP request \method used for action processing as a
@@ -73,7 +72,7 @@ module ActionController
#
# request.headers["Content-Type"] # => "text/plain"
def headers
- @headers ||= ActionController::Http::Headers.new(@env)
+ Http::Headers.new(@env)
end
# Returns the content length of the request as an integer.
@@ -94,20 +93,26 @@ module ActionController
end
end
end
-
+
# Returns the accepted MIME type for the request.
def accepts
@accepts ||= begin
header = @env['HTTP_ACCEPT'].to_s.strip
+ fallback = xhr? ? Mime::JS : Mime::HTML
+
if header.empty?
- [content_type, Mime::ALL].compact
+ [content_type, fallback, Mime::ALL].compact
else
- Mime::Type.parse(header)
+ ret = Mime::Type.parse(header)
+ if ret.last == Mime::ALL
+ ret.insert(-2, fallback)
+ end
+ ret
end
end
end
-
+
def if_modified_since
if since = env['HTTP_IF_MODIFIED_SINCE']
Time.rfc2822(since) rescue nil
@@ -142,24 +147,33 @@ module ActionController
end
end
+ ONLY_ALL = [Mime::ALL].freeze
+
# Returns the Mime type for the \format used in the request.
#
# GET /posts/5.xml | request.format => Mime::XML
# GET /posts/5.xhtml | request.format => Mime::HTML
# GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first depending on the value of <tt>ActionController::Base.use_accept_header</tt>
- def format
+
+ def format(view_path = [])
@format ||=
if parameters[:format]
- Mime::Type.lookup_by_extension(parameters[:format])
- elsif ActionController::Base.use_accept_header
- accepts.first
- elsif xhr?
- Mime::Type.lookup_by_extension("js")
- else
- Mime::Type.lookup_by_extension("html")
+ Mime[parameters[:format]]
+ elsif ActionController::Base.use_accept_header && !(accepts == ONLY_ALL)
+ accepts.first
+ elsif xhr? then Mime::JS
+ else Mime::HTML
end
end
+ def formats
+ @formats =
+ if ActionController::Base.use_accept_header
+ Array(Mime[parameters[:format]] || accepts)
+ else
+ [format]
+ end
+ end
# Sets the \format by string extension, which can be used to force custom formats
# that are not controlled by the extension.
@@ -226,7 +240,7 @@ module ActionController
if @env.include? 'HTTP_CLIENT_IP'
if ActionController::Base.ip_spoofing_check && remote_ips && !remote_ips.include?(@env['HTTP_CLIENT_IP'])
# We don't know which came from the proxy, and which from the user
- raise ActionControllerError.new(<<EOM)
+ raise ActionController::ActionControllerError.new(<<EOM)
IP spoofing attack?!
HTTP_CLIENT_IP=#{@env['HTTP_CLIENT_IP'].inspect}
HTTP_X_FORWARDED_FOR=#{@env['HTTP_X_FORWARDED_FOR'].inspect}
diff --git a/actionpack/lib/action_controller/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index febe4ccf29..ecf40b8103 100644
--- a/actionpack/lib/action_controller/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -1,6 +1,6 @@
require 'digest/md5'
-module ActionController # :nodoc:
+module ActionDispatch # :nodoc:
# Represents an HTTP response generated by a controller action. One can use
# an ActionController::Response object to retrieve the current state
# of the response, or customize the response. An Response object can
diff --git a/actionpack/lib/action_controller/status_codes.rb b/actionpack/lib/action_dispatch/http/status_codes.rb
index 4977c79491..cec9d2e3a1 100644
--- a/actionpack/lib/action_controller/status_codes.rb
+++ b/actionpack/lib/action_dispatch/http/status_codes.rb
@@ -1,4 +1,4 @@
-module ActionController
+module ActionDispatch
module StatusCodes #:nodoc:
# Defines the standard HTTP status codes, by integer, with their
# corresponding default message texts.
diff --git a/actionpack/lib/action_controller/failsafe.rb b/actionpack/lib/action_dispatch/middleware/failsafe.rb
index 567581142c..7379a696aa 100644
--- a/actionpack/lib/action_controller/failsafe.rb
+++ b/actionpack/lib/action_dispatch/middleware/failsafe.rb
@@ -1,4 +1,4 @@
-module ActionController
+module ActionDispatch
class Failsafe
cattr_accessor :error_file_path
self.error_file_path = Rails.public_path if defined?(Rails.public_path)
diff --git a/actionpack/lib/action_controller/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb
index d269fe07fa..6df572268c 100644
--- a/actionpack/lib/action_controller/params_parser.rb
+++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb
@@ -1,4 +1,4 @@
-module ActionController
+module ActionDispatch
class ParamsParser
ActionController::Base.param_parsers[Mime::XML] = :xml_simple
ActionController::Base.param_parsers[Mime::JSON] = :json
diff --git a/actionpack/lib/action_controller/rewindable_input.rb b/actionpack/lib/action_dispatch/middleware/rewindable_input.rb
index cedfb7fd75..725414efc4 100644
--- a/actionpack/lib/action_controller/rewindable_input.rb
+++ b/actionpack/lib/action_dispatch/middleware/rewindable_input.rb
@@ -1,4 +1,4 @@
-module ActionController
+module ActionDispatch
class RewindableInput
class RewindableIO < ActiveSupport::BasicObject
def initialize(io)
diff --git a/actionpack/lib/action_controller/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
index f6369abf15..6c039cf62d 100644
--- a/actionpack/lib/action_controller/session/abstract_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
@@ -1,6 +1,6 @@
require 'rack/utils'
-module ActionController
+module ActionDispatch
module Session
class AbstractStore
ENV_SESSION_KEY = 'rack.session'.freeze
diff --git a/actionpack/lib/action_controller/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
index a2543c1824..433c4cc070 100644
--- a/actionpack/lib/action_controller/session/cookie_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
@@ -1,4 +1,4 @@
-module ActionController
+module ActionDispatch
module Session
# This cookie-based session store is the Rails default. Sessions typically
# contain at most a user_id and flash message; both fit within the 4K cookie
diff --git a/actionpack/lib/action_controller/session/mem_cache_store.rb b/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb
index f745715a97..8f448970d9 100644
--- a/actionpack/lib/action_controller/session/mem_cache_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb
@@ -1,7 +1,7 @@
begin
require_library_or_gem 'memcache'
- module ActionController
+ module ActionDispatch
module Session
class MemCacheStore < AbstractStore
def initialize(app, options = {})
diff --git a/actionpack/lib/action_dispatch/rack.rb b/actionpack/lib/action_dispatch/rack.rb
new file mode 100644
index 0000000000..89087c124f
--- /dev/null
+++ b/actionpack/lib/action_dispatch/rack.rb
@@ -0,0 +1,3 @@
+# require 'action_dispatch/rack/lock'
+# require 'action_dispatch/rack/multipart'
+# require 'action_dispatch/rack/parse_query'
diff --git a/actionpack/lib/action_controller/middleware_stack.rb b/actionpack/lib/action_dispatch/utils/middleware_stack.rb
index b739a6d72d..ee5f28d5cb 100644
--- a/actionpack/lib/action_controller/middleware_stack.rb
+++ b/actionpack/lib/action_dispatch/utils/middleware_stack.rb
@@ -1,4 +1,4 @@
-module ActionController
+module ActionDispatch
class MiddlewareStack < Array
class Middleware
def self.new(klass, *args, &block)
diff --git a/actionpack/lib/action_controller/uploaded_file.rb b/actionpack/lib/action_dispatch/utils/uploaded_file.rb
index 376ba3621a..97dffa089f 100644
--- a/actionpack/lib/action_controller/uploaded_file.rb
+++ b/actionpack/lib/action_dispatch/utils/uploaded_file.rb
@@ -1,4 +1,4 @@
-module ActionController
+module ActionDispatch
module UploadedFile
def self.included(base)
base.class_eval do
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb
index 1f1ff9dd05..14bd2a1297 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -31,6 +31,8 @@ rescue LoadError
end
end
+require File.join(File.dirname(__FILE__), "action_pack")
+
module ActionView
def self.load_all!
[Base, InlineTemplate, TemplateError]
@@ -38,16 +40,17 @@ module ActionView
autoload :Base, 'action_view/base'
autoload :Helpers, 'action_view/helpers'
- autoload :InlineTemplate, 'action_view/inline_template'
- autoload :Partials, 'action_view/partials'
+ autoload :InlineTemplate, 'action_view/template/inline'
+ autoload :Partials, 'action_view/render/partials'
autoload :PathSet, 'action_view/paths'
- autoload :Renderable, 'action_view/renderable'
- autoload :RenderablePartial, 'action_view/renderable_partial'
- autoload :Template, 'action_view/template'
- autoload :ReloadableTemplate, 'action_view/reloadable_template'
- autoload :TemplateError, 'action_view/template_error'
- autoload :TemplateHandler, 'action_view/template_handler'
- autoload :TemplateHandlers, 'action_view/template_handlers'
+ autoload :Rendering, 'action_view/render/rendering'
+ autoload :Renderable, 'action_view/template/renderable'
+ autoload :RenderablePartial, 'action_view/template/partial'
+ autoload :Template, 'action_view/template/template'
+ autoload :TemplateError, 'action_view/template/error'
+ autoload :TemplateHandler, 'action_view/template/handler'
+ autoload :TemplateHandlers, 'action_view/template/handlers'
+ autoload :TextTemplate, 'action_view/template/text'
autoload :Helpers, 'action_view/helpers'
end
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index 9c0134e7f7..efed19a21d 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -3,10 +3,11 @@ module ActionView #:nodoc:
end
class MissingTemplate < ActionViewError #:nodoc:
- attr_reader :path
+ attr_reader :path, :action_name
def initialize(paths, path, template_format = nil)
@path = path
+ @action_name = path.split("/").last.split(".")[0...-1].join(".")
full_template_path = path.include?('.') ? path : "#{path}.erb"
display_paths = paths.compact.join(":")
template_type = (path =~ /layouts/i) ? 'layout' : 'template'
@@ -160,14 +161,13 @@ module ActionView #:nodoc:
#
# See the ActionView::Helpers::PrototypeHelper::GeneratorMethods documentation for more details.
class Base
- include Helpers, Partials, ::ERB::Util
+ include Helpers, Rendering, Partials, ::ERB::Util
+
extend ActiveSupport::Memoizable
- attr_accessor :base_path, :assigns, :template_extension
+ attr_accessor :base_path, :assigns, :template_extension, :formats
attr_accessor :controller
- attr_writer :template_format
-
attr_accessor :output_buffer
class << self
@@ -193,9 +193,13 @@ module ActionView #:nodoc:
attr_internal :request
+ delegate :controller_path, :to => :controller, :allow_nil => true
+
delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers,
:flash, :logger, :action_name, :controller_name, :to => :controller
+ delegate :find_by_parts, :to => :view_paths
+
module CompiledTemplates #:nodoc:
# holds compiled template code
end
@@ -218,7 +222,8 @@ module ActionView #:nodoc:
end
end
- def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil)#:nodoc:
+ def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil, formats = nil)#:nodoc:
+ @formats = formats || [:html]
@assigns = assigns_for_first_render
@assigns_added = nil
@controller = controller
@@ -233,56 +238,6 @@ module ActionView #:nodoc:
def view_paths=(paths)
@view_paths = self.class.process_view_paths(paths)
- # we might be using ReloadableTemplates, so we need to let them know this a new request
- @view_paths.load!
- end
-
- # Returns the result of a render that's dictated by the options hash. The primary options are:
- #
- # * <tt>:partial</tt> - See ActionView::Partials.
- # * <tt>:update</tt> - Calls update_page with the block given.
- # * <tt>:file</tt> - Renders an explicit template file (this used to be the old default), add :locals to pass in those.
- # * <tt>:inline</tt> - Renders an inline template similar to how it's done in the controller.
- # * <tt>:text</tt> - Renders the text passed in out.
- #
- # If no options hash is passed or :update specified, the default is to render a partial and use the second parameter
- # as the locals hash.
- def render(options = {}, local_assigns = {}, &block) #:nodoc:
- local_assigns ||= {}
-
- case options
- when Hash
- options = options.reverse_merge(:locals => {})
- if options[:layout]
- _render_with_layout(options, local_assigns, &block)
- elsif options[:file]
- template = self.view_paths.find_template(options[:file], template_format)
- template.render_template(self, options[:locals])
- elsif options[:partial]
- render_partial(options)
- elsif options[:inline]
- InlineTemplate.new(options[:inline], options[:type]).render(self, options[:locals])
- elsif options[:text]
- options[:text]
- end
- when :update
- update_page(&block)
- else
- render_partial(:partial => options, :locals => local_assigns)
- end
- end
-
- # The format to be used when choosing between multiple templates with
- # the same name but differing formats. See +Request#template_format+
- # for more details.
- def template_format
- if defined? @template_format
- @template_format
- elsif controller && controller.respond_to?(:request)
- @template_format = controller.request.template_format.to_sym
- else
- @template_format = :html
- end
end
# Access the current template being rendered.
@@ -332,32 +287,5 @@ module ActionView #:nodoc:
controller.response.content_type ||= content_type
end
end
-
- def _render_with_layout(options, local_assigns, &block) #:nodoc:
- partial_layout = options.delete(:layout)
-
- if block_given?
- begin
- @_proc_for_layout = block
- concat(render(options.merge(:partial => partial_layout)))
- ensure
- @_proc_for_layout = nil
- end
- else
- begin
- original_content_for_layout = @content_for_layout if defined?(@content_for_layout)
- @content_for_layout = render(options)
-
- if (options[:inline] || options[:file] || options[:text])
- @cached_content_for_layout = @content_for_layout
- render(:file => partial_layout, :locals => local_assigns)
- else
- render(options.merge(:partial => partial_layout))
- end
- ensure
- @content_for_layout = original_content_for_layout
- end
- end
- end
end
end
diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb
index 91ef72e54b..6bad11e354 100644
--- a/actionpack/lib/action_view/helpers/prototype_helper.rb
+++ b/actionpack/lib/action_view/helpers/prototype_helper.rb
@@ -987,13 +987,13 @@ module ActionView
end
def render(*options_for_render)
- old_format = @context && @context.template_format
- @context.template_format = :html if @context
+ old_formats = @context && @context.formats
+ @context.formats = [:html] if @context
Hash === options_for_render.first ?
@context.render(*options_for_render) :
options_for_render.first.to_s
ensure
- @context.template_format = old_format if @context
+ @context.formats = old_formats if @context
end
def javascript_object_for(object)
diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb
index a0a2f96886..b6bb9942ee 100644
--- a/actionpack/lib/action_view/paths.rb
+++ b/actionpack/lib/action_view/paths.rb
@@ -2,16 +2,16 @@ module ActionView #:nodoc:
class PathSet < Array #:nodoc:
def self.type_cast(obj)
if obj.is_a?(String)
- if Base.cache_template_loading?
- Template::EagerPath.new(obj.to_s)
+ if !Object.const_defined?(:Rails) || Rails.configuration.cache_classes
+ Template::EagerPath.new(obj)
else
- ReloadableTemplate::ReloadablePath.new(obj.to_s)
+ Template::Path.new(obj)
end
else
obj
end
end
-
+
def initialize(*args)
super(*args).map! { |obj| self.class.type_cast(obj) }
end
@@ -35,9 +35,29 @@ module ActionView #:nodoc:
def unshift(*objs)
super(*objs.map { |obj| self.class.type_cast(obj) })
end
+
+ def find_by_parts(path, extension = nil, prefix = nil, partial = false)
+ template_path = path.sub(/^\//, '')
+
+ each do |load_path|
+ if template = load_path.find_by_parts(template_path, extension, prefix, partial)
+ return template
+ end
+ end
+
+ Template.new(path, self)
+ rescue ActionView::MissingTemplate => e
+ extension ||= []
+ raise ActionView::MissingTemplate.new(self, "#{prefix}/#{path}.{#{extension.join(",")}}")
+ end
- def load!
- each(&:load!)
+ def find_by_parts?(path, extension = nil, prefix = nil, partial = false)
+ template_path = path.sub(/^\//, '')
+
+ each do |load_path|
+ return true if template = load_path.find_by_parts(template_path, extension, prefix, partial)
+ end
+ false
end
def find_template(original_template_path, format = nil, html_fallback = true)
@@ -45,13 +65,7 @@ module ActionView #:nodoc:
template_path = original_template_path.sub(/^\//, '')
each do |load_path|
- if format && (template = load_path["#{template_path}.#{I18n.locale}.#{format}"])
- return template
- elsif format && (template = load_path["#{template_path}.#{format}"])
- return template
- elsif template = load_path["#{template_path}.#{I18n.locale}"]
- return template
- elsif template = load_path[template_path]
+ if template = load_path.find_by_parts(template_path, format)
return template
# Try to find html version if the format is javascript
elsif format == :js && html_fallback && template = load_path["#{template_path}.#{I18n.locale}.html"]
@@ -61,7 +75,7 @@ module ActionView #:nodoc:
end
end
- return Template.new(original_template_path) if File.file?(original_template_path)
+ return Template.new(original_template_path, original_template_path.to_s =~ /\A\// ? "" : ".") if File.file?(original_template_path)
raise MissingTemplate.new(self, original_template_path, format)
end
diff --git a/actionpack/lib/action_view/reloadable_template.rb b/actionpack/lib/action_view/reloadable_template.rb
deleted file mode 100644
index 5ef833d75c..0000000000
--- a/actionpack/lib/action_view/reloadable_template.rb
+++ /dev/null
@@ -1,117 +0,0 @@
-module ActionView #:nodoc:
- class ReloadableTemplate < Template
-
- class TemplateDeleted < ActionView::ActionViewError
- end
-
- class ReloadablePath < Template::Path
-
- def initialize(path)
- super
- @paths = {}
- new_request!
- end
-
- def new_request!
- @disk_cache = {}
- end
- alias_method :load!, :new_request!
-
- def [](path)
- if found_template = @paths[path]
- begin
- found_template.reset_cache_if_stale!
- rescue TemplateDeleted
- unregister_template(found_template)
- self[path]
- end
- else
- load_all_templates_from_dir(templates_dir_from_path(path))
- # don't ever hand out a template without running a stale check
- (new_template = @paths[path]) && new_template.reset_cache_if_stale!
- end
- end
-
- private
- def register_template_from_file(template_full_file_path)
- if !@paths[relative_path = relative_path_for_template_file(template_full_file_path)] && File.file?(template_full_file_path)
- register_template(ReloadableTemplate.new(relative_path, self))
- end
- end
-
- def register_template(template)
- template.accessible_paths.each do |path|
- @paths[path] = template
- end
- end
-
- # remove (probably deleted) template from cache
- def unregister_template(template)
- template.accessible_paths.each do |template_path|
- @paths.delete(template_path) if @paths[template_path] == template
- end
- # fill in any newly created gaps
- @paths.values.uniq.each do |template|
- template.accessible_paths.each {|path| @paths[path] ||= template}
- end
- end
-
- # load all templates from the directory of the requested template
- def load_all_templates_from_dir(dir)
- # hit disk only once per template-dir/request
- @disk_cache[dir] ||= template_files_from_dir(dir).each {|template_file| register_template_from_file(template_file)}
- end
-
- def templates_dir_from_path(path)
- dirname = File.dirname(path)
- File.join(@path, dirname == '.' ? '' : dirname)
- end
-
- # get all the template filenames from the dir
- def template_files_from_dir(dir)
- Dir.glob(File.join(dir, '*'))
- end
- end
-
- module Unfreezable
- def freeze; self; end
- end
-
- def initialize(*args)
- super
-
- # we don't ever want to get frozen
- extend Unfreezable
- end
-
- def mtime
- File.mtime(filename)
- end
-
- attr_accessor :previously_last_modified
-
- def stale?
- previously_last_modified.nil? || previously_last_modified < mtime
- rescue Errno::ENOENT => e
- undef_my_compiled_methods!
- raise TemplateDeleted
- end
-
- def reset_cache_if_stale!
- if stale?
- flush_cache 'source', 'compiled_source'
- undef_my_compiled_methods!
- @previously_last_modified = mtime
- end
- self
- end
-
- # remove any compiled methods that look like they might belong to me
- def undef_my_compiled_methods!
- ActionView::Base::CompiledTemplates.public_instance_methods.grep(/#{Regexp.escape(method_name_without_locals)}(?:_locals_)?/).each do |m|
- ActionView::Base::CompiledTemplates.send(:remove_method, m)
- end
- end
-
- end
-end
diff --git a/actionpack/lib/action_view/partials.rb b/actionpack/lib/action_view/render/partials.rb
index 9e5e0f786e..e337dcb63b 100644
--- a/actionpack/lib/action_view/partials.rb
+++ b/actionpack/lib/action_view/render/partials.rb
@@ -172,68 +172,156 @@ module ActionView
module Partials
extend ActiveSupport::Memoizable
+ def _render_partial(options = {}) #:nodoc:
+ options[:locals] ||= {}
+
+ case path = partial = options[:partial]
+ when *_array_like_objects
+ return _render_partial_collection(partial, options)
+ else
+ if partial.is_a?(ActionView::Helpers::FormBuilder)
+ path = partial.class.to_s.demodulize.underscore.sub(/_builder$/, '')
+ options[:locals].merge!(path.to_sym => partial)
+ elsif !partial.is_a?(String)
+ options[:object] = object = partial
+ path = ActionController::RecordIdentifier.partial_path(object, controller_path)
+ end
+ _, _, prefix, object = parts = partial_parts(path, options)
+ template = find_by_parts(*parts)
+ _render_partial_object(template, options, (object unless object == true))
+ end
+ end
+
private
- def render_partial(options = {}) #:nodoc:
- local_assigns = options[:locals] || {}
+ def partial_parts(name, options)
+ segments = name.split("/")
+ parts = segments.pop.split(".")
- case partial_path = options[:partial]
- when String, Symbol, NilClass
- if options.has_key?(:collection)
- render_partial_collection(options)
- else
- _pick_partial_template(partial_path).render_partial(self, options[:object], local_assigns)
+ case parts.size
+ when 1
+ parts
+ when 2, 3
+ extension = parts.delete_at(1).to_sym
+ if formats.include?(extension)
+ self.formats.replace [extension]
end
- when ActionView::Helpers::FormBuilder
- builder_partial_path = partial_path.class.to_s.demodulize.underscore.sub(/_builder$/, '')
- local_assigns.merge!(builder_partial_path.to_sym => partial_path)
- render_partial(:partial => builder_partial_path, :object => options[:object], :locals => local_assigns)
+ parts.pop if parts.size == 2
+ end
+
+ path = parts.join(".")
+ prefix = segments[0..-1].join("/")
+ prefix = prefix.blank? ? controller_path : prefix
+ parts = [path, formats, prefix]
+ parts.push options[:object] || true
+ end
+
+ def _render_partial_with_block(layout, block, options)
+ @_proc_for_layout = block
+ concat(_render_partial(options.merge(:partial => layout)))
+ ensure
+ @_proc_for_layout = nil
+ end
+
+ def _render_partial_with_layout(layout, options)
+ if layout
+ prefix = controller && !layout.include?("/") ? controller.controller_path : nil
+ layout = find_by_parts(layout, formats, prefix, true)
+ end
+ content = _render_partial(options)
+ return _render_content_with_layout(content, layout, options[:locals])
+ end
+
+ def _deprecated_ivar_assign(template)
+ if respond_to?(:controller)
+ ivar = :"@#{template.variable_name}"
+ object =
+ if controller.instance_variable_defined?(ivar)
+ ActiveSupport::Deprecation::DeprecatedObjectProxy.new(
+ controller.instance_variable_get(ivar),
+ "#{ivar} will no longer be implicitly assigned to #{template.variable_name}")
+ end
+ end
+ end
+
+ def _render_partial_with_block(layout, block, options)
+ @_proc_for_layout = block
+ concat(_render_partial(options.merge(:partial => layout)))
+ ensure
+ @_proc_for_layout = nil
+ end
+
+ def _render_partial_with_layout(layout, options)
+ if layout
+ prefix = controller && !layout.include?("/") ? controller.controller_path : nil
+ layout = find_by_parts(layout, formats, prefix, true)
+ end
+ content = _render_partial(options)
+ return _render_content_with_layout(content, layout, options[:locals])
+ end
+
+ def _deprecated_ivar_assign(template)
+ if respond_to?(:controller)
+ ivar = :"@#{template.variable_name}"
+ object =
+ if controller.instance_variable_defined?(ivar)
+ ActiveSupport::Deprecation::DeprecatedObjectProxy.new(
+ controller.instance_variable_get(ivar),
+ "#{ivar} will no longer be implicitly assigned to #{template.variable_name}")
+ end
+ end
+ end
+
+ def _array_like_objects
+ array_like = [Array]
+ if defined?(ActiveRecord)
+ array_like.push(ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope)
+ end
+ array_like
+ end
+
+ def _render_partial_object(template, options, object = nil)
+ if options.key?(:collection)
+ _render_partial_collection(options.delete(:collection), options, template)
else
- if Array === partial_path ||
- (defined?(ActiveRecord) &&
- (ActiveRecord::Associations::AssociationCollection === partial_path ||
- ActiveRecord::NamedScope::Scope === partial_path))
- render_partial_collection(options.except(:partial).merge(:collection => partial_path))
- else
- object = partial_path
- render_partial(
- :partial => ActionController::RecordIdentifier.partial_path(object, controller.class.controller_path),
- :object => object,
- :locals => local_assigns
- )
- end
+ locals = (options[:locals] ||= {})
+ object ||= locals[:object] || locals[template.variable_name]
+
+ _set_locals(object, locals, template, options)
+ _render_template(template, locals)
end
end
- def render_partial_collection(options = {}) #:nodoc:
- return nil if options[:collection].blank?
+ def _set_locals(object, locals, template, options)
+ object ||= _deprecated_ivar_assign(template)
+ locals[:object] = locals[template.variable_name] = object
+ locals[options[:as]] = object if options[:as]
+ end
+
+ def _render_partial_collection(collection, options = {}, passed_template = nil) #:nodoc:
+ return nil if collection.blank?
+
+ spacer = options[:spacer_template] ? _render_partial(:partial => options[:spacer_template]) : ''
- partial = options[:partial]
- spacer = options[:spacer_template] ? render(:partial => options[:spacer_template]) : ''
- local_assigns = options[:locals] ? options[:locals].clone : {}
- as = options[:as]
+ locals = (options[:locals] ||= {})
+ index, @_partial_path = 0, nil
+ collection.map do |object|
+ template = passed_template || begin
+ _partial_path =
+ ActionController::RecordIdentifier.partial_path(object, controller_path)
+ template = _pick_partial_template(_partial_path)
+ end
- index = 0
- options[:collection].map do |object|
- _partial_path ||= partial ||
- ActionController::RecordIdentifier.partial_path(object, controller.class.controller_path)
- template = _pick_partial_template(_partial_path)
- local_assigns[template.counter_name] = index
- result = template.render_partial(self, object, local_assigns.dup, as)
+ _set_locals(object, locals, template, options)
+ locals[template.counter_name] = index
+
index += 1
- result
+ _render_template(template, locals)
end.join(spacer)
end
def _pick_partial_template(partial_path) #:nodoc:
- if partial_path.include?('/')
- path = File.join(File.dirname(partial_path), "_#{File.basename(partial_path)}")
- elsif controller
- path = "#{controller.class.controller_path}/_#{partial_path}"
- else
- path = "_#{partial_path}"
- end
-
- self.view_paths.find_template(path, self.template_format)
+ prefix = controller_path unless partial_path.include?('/')
+ find_by_parts(partial_path, formats, prefix, true)
end
memoize :_pick_partial_template
end
diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb
new file mode 100644
index 0000000000..a9b2acecd5
--- /dev/null
+++ b/actionpack/lib/action_view/render/rendering.rb
@@ -0,0 +1,114 @@
+module ActionView
+ module Rendering
+ # Returns the result of a render that's dictated by the options hash. The primary options are:
+ #
+ # * <tt>:partial</tt> - See ActionView::Partials.
+ # * <tt>:update</tt> - Calls update_page with the block given.
+ # * <tt>:file</tt> - Renders an explicit template file (this used to be the old default), add :locals to pass in those.
+ # * <tt>:inline</tt> - Renders an inline template similar to how it's done in the controller.
+ # * <tt>:text</tt> - Renders the text passed in out.
+ #
+ # If no options hash is passed or :update specified, the default is to render a partial and use the second parameter
+ # as the locals hash.
+ def render(options = {}, local_assigns = {}, &block) #:nodoc:
+ local_assigns ||= {}
+
+ @exempt_from_layout = true
+
+ case options
+ when Hash
+ options[:locals] ||= {}
+ layout = options[:layout]
+
+ return _render_partial_with_layout(layout, options) if options.key?(:partial)
+ return _render_partial_with_block(layout, block, options) if block_given?
+
+ layout = find_by_parts(layout, formats) if layout
+
+ if file = options[:file]
+ template = find_by_parts(file, formats)
+ _render_template_with_layout(template, layout, :locals => options[:locals])
+ elsif inline = options[:inline]
+ _render_inline(inline, layout, options)
+ elsif text = options[:text]
+ _render_text(text, layout, options)
+ end
+ when :update
+ update_page(&block)
+ when String, NilClass
+ _render_partial(:partial => options, :locals => local_assigns)
+ end
+ end
+
+ def _render_content_with_layout(content, layout, locals)
+ return content unless layout
+
+ locals ||= {}
+
+ if controller && layout
+ response.layout = layout.path_without_format_and_extension if controller.respond_to?(:response)
+ logger.info("Rendering template within #{layout.path_without_format_and_extension}") if logger
+ end
+
+ begin
+ original_content_for_layout = @content_for_layout if defined?(@content_for_layout)
+ @content_for_layout = content
+
+ @cached_content_for_layout = @content_for_layout
+ _render_template(layout, locals)
+ ensure
+ @content_for_layout = original_content_for_layout
+ end
+ end
+
+ def _render_template(template, local_assigns = {})
+ with_template(template) do
+ _evaluate_assigns_and_ivars
+ _set_controller_content_type(template.mime_type) if template.respond_to?(:mime_type)
+
+ template.render(self, local_assigns) do |*names|
+ if !instance_variable_defined?(:"@content_for_#{names.first}") &&
+ instance_variable_defined?(:@_proc_for_layout) && (proc = @_proc_for_layout)
+ capture(*names, &proc)
+ elsif instance_variable_defined?(ivar = :"@content_for_#{names.first || :layout}")
+ instance_variable_get(ivar)
+ end
+ end
+ end
+ rescue Exception => e
+ raise e if template.is_a?(InlineTemplate) || !template.filename
+ if TemplateError === e
+ e.sub_template_of(template)
+ raise e
+ else
+ raise TemplateError.new(template, assigns, e)
+ end
+ end
+
+ def _render_inline(inline, layout, options)
+ content = _render_template(InlineTemplate.new(options[:inline], options[:type]), options[:locals] || {})
+ layout ? _render_content_with_layout(content, layout, options[:locals]) : content
+ end
+
+ def _render_text(text, layout, options)
+ layout ? _render_content_with_layout(text, layout, options[:locals]) : text
+ end
+
+ def _render_template_with_layout(template, layout = nil, options = {}, partial = false)
+ if controller && logger
+ logger.info("Rendering #{template.path_without_extension}" +
+ (options[:status] ? " (#{options[:status]})" : ''))
+ end
+
+ content = if partial
+ object = partial unless partial == true
+ _render_partial_object(template, options, object)
+ else
+ _render_template(template, options[:locals] || {})
+ end
+
+ return content unless layout && !template.exempt_from_layout?
+ _render_content_with_layout(content, layout, options[:locals] || {})
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_view/renderable_partial.rb b/actionpack/lib/action_view/renderable_partial.rb
deleted file mode 100644
index 3ea836fa25..0000000000
--- a/actionpack/lib/action_view/renderable_partial.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-module ActionView
- # NOTE: The template that this mixin is being included into is frozen
- # so you cannot set or modify any instance variables
- module RenderablePartial #:nodoc:
- extend ActiveSupport::Memoizable
-
- def variable_name
- name.sub(/\A_/, '').to_sym
- end
- memoize :variable_name
-
- def counter_name
- "#{variable_name}_counter".to_sym
- end
- memoize :counter_name
-
- def render(view, local_assigns = {})
- if defined? ActionController
- ActionController::Base.benchmark("Rendered #{path_without_format_and_extension}", Logger::DEBUG, false) do
- super
- end
- else
- super
- end
- end
-
- def render_partial(view, object = nil, local_assigns = {}, as = nil)
- object ||= local_assigns[:object] || local_assigns[variable_name]
-
- if object.nil? && view.respond_to?(:controller)
- ivar = :"@#{variable_name}"
- object =
- if view.controller.instance_variable_defined?(ivar)
- ActiveSupport::Deprecation::DeprecatedObjectProxy.new(
- view.controller.instance_variable_get(ivar),
- "#{ivar} will no longer be implicitly assigned to #{variable_name}")
- end
- end
-
- # Ensure correct object is reassigned to other accessors
- local_assigns[:object] = local_assigns[variable_name] = object
- local_assigns[as] = object if as
-
- render_template(view, local_assigns)
- end
- end
-end
diff --git a/actionpack/lib/action_view/template_error.rb b/actionpack/lib/action_view/template/error.rb
index 37cb1c7c6c..37cb1c7c6c 100644
--- a/actionpack/lib/action_view/template_error.rb
+++ b/actionpack/lib/action_view/template/error.rb
diff --git a/actionpack/lib/action_view/template_handler.rb b/actionpack/lib/action_view/template/handler.rb
index 672da0ed2b..672da0ed2b 100644
--- a/actionpack/lib/action_view/template_handler.rb
+++ b/actionpack/lib/action_view/template/handler.rb
diff --git a/actionpack/lib/action_view/template_handlers.rb b/actionpack/lib/action_view/template/handlers.rb
index 205f8628f0..fb85f28851 100644
--- a/actionpack/lib/action_view/template_handlers.rb
+++ b/actionpack/lib/action_view/template/handlers.rb
@@ -1,8 +1,8 @@
module ActionView #:nodoc:
module TemplateHandlers #:nodoc:
- autoload :ERB, 'action_view/template_handlers/erb'
- autoload :RJS, 'action_view/template_handlers/rjs'
- autoload :Builder, 'action_view/template_handlers/builder'
+ autoload :ERB, 'action_view/template/handlers/erb'
+ autoload :RJS, 'action_view/template/handlers/rjs'
+ autoload :Builder, 'action_view/template/handlers/builder'
def self.extended(base)
base.register_default_template_handler :erb, TemplateHandlers::ERB
diff --git a/actionpack/lib/action_view/template_handlers/builder.rb b/actionpack/lib/action_view/template/handlers/builder.rb
index 788dc93326..788dc93326 100644
--- a/actionpack/lib/action_view/template_handlers/builder.rb
+++ b/actionpack/lib/action_view/template/handlers/builder.rb
diff --git a/actionpack/lib/action_view/template_handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb
index e3120ba267..a20b1b0cd3 100644
--- a/actionpack/lib/action_view/template_handlers/erb.rb
+++ b/actionpack/lib/action_view/template/handlers/erb.rb
@@ -1,3 +1,5 @@
+require 'erb'
+
module ActionView
module TemplateHandlers
class ERB < TemplateHandler
diff --git a/actionpack/lib/action_view/template_handlers/rjs.rb b/actionpack/lib/action_view/template/handlers/rjs.rb
index 41a1fddb47..802a79b3fc 100644
--- a/actionpack/lib/action_view/template_handlers/rjs.rb
+++ b/actionpack/lib/action_view/template/handlers/rjs.rb
@@ -4,7 +4,7 @@ module ActionView
include Compilable
def compile(template)
- "@template_format = :html;" +
+ "@formats = [:html];" +
"controller.response.content_type ||= Mime::JS;" +
"update_page do |page|;#{template.source}\nend"
end
diff --git a/actionpack/lib/action_view/inline_template.rb b/actionpack/lib/action_view/template/inline.rb
index 54efa543c8..54efa543c8 100644
--- a/actionpack/lib/action_view/inline_template.rb
+++ b/actionpack/lib/action_view/template/inline.rb
diff --git a/actionpack/lib/action_view/template/partial.rb b/actionpack/lib/action_view/template/partial.rb
new file mode 100644
index 0000000000..30dec1dc5b
--- /dev/null
+++ b/actionpack/lib/action_view/template/partial.rb
@@ -0,0 +1,18 @@
+module ActionView
+ # NOTE: The template that this mixin is being included into is frozen
+ # so you cannot set or modify any instance variables
+ module RenderablePartial #:nodoc:
+ extend ActiveSupport::Memoizable
+
+ def variable_name
+ name.sub(/\A_/, '').to_sym
+ end
+ memoize :variable_name
+
+ def counter_name
+ "#{variable_name}_counter".to_sym
+ end
+ memoize :counter_name
+
+ end
+end
diff --git a/actionpack/lib/action_view/renderable.rb b/actionpack/lib/action_view/template/renderable.rb
index ff7bc7d9de..0e8e0c4a38 100644
--- a/actionpack/lib/action_view/renderable.rb
+++ b/actionpack/lib/action_view/template/renderable.rb
@@ -6,6 +6,13 @@ module ActionView
module Renderable #:nodoc:
extend ActiveSupport::Memoizable
+ def render(view, locals)
+ compile(locals)
+ view.send(method_name(locals), locals) {|*args| yield(*args) }
+ end
+
+ private
+
def filename
'compiled-template'
end
@@ -18,30 +25,13 @@ module ActionView
def compiled_source
handler.call(self)
end
+ memoize :compiled_source
def method_name_without_locals
['_run', extension, method_segment].compact.join('_')
end
memoize :method_name_without_locals
- def render(view, local_assigns = {})
- compile(local_assigns)
-
- view.with_template self do
- view.send(:_evaluate_assigns_and_ivars)
- view.send(:_set_controller_content_type, mime_type) if respond_to?(:mime_type)
-
- view.send(method_name(local_assigns), local_assigns) do |*names|
- ivar = :@_proc_for_layout
- if !view.instance_variable_defined?(:"@content_for_#{names.first}") && view.instance_variable_defined?(ivar) && (proc = view.instance_variable_get(ivar))
- view.capture(*names, &proc)
- elsif view.instance_variable_defined?(ivar = :"@content_for_#{names.first || :layout}")
- view.instance_variable_get(ivar)
- end
- end
- end
- end
-
def method_name(local_assigns)
if local_assigns && local_assigns.any?
method_name = method_name_without_locals.dup
@@ -52,16 +42,16 @@ module ActionView
method_name.to_sym
end
- private
- # Compile and evaluate the template's code (if necessary)
- def compile(local_assigns)
- render_symbol = method_name(local_assigns)
+ # Compile and evaluate the template's code (if necessary)
+ def compile(local_assigns)
+ render_symbol = method_name(local_assigns)
- if !Base::CompiledTemplates.method_defined?(render_symbol) || recompile?
- compile!(render_symbol, local_assigns)
- end
+ if !Base::CompiledTemplates.method_defined?(render_symbol) || recompile?
+ compile!(render_symbol, local_assigns)
end
+ end
+ private
def compile!(render_symbol, local_assigns)
locals_code = local_assigns.keys.map { |key| "#{key} = local_assigns[:#{key}];" }.join
@@ -75,8 +65,6 @@ module ActionView
begin
ActionView::Base::CompiledTemplates.module_eval(source, filename, 0)
- rescue Errno::ENOENT => e
- raise e # Missing template file, re-raise for Base to rescue
rescue Exception => e # errors from template code
if logger = defined?(ActionController) && Base.logger
logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}"
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template/template.rb
index a974f2652b..a61c46020f 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template/template.rb
@@ -6,7 +6,7 @@ module ActionView #:nodoc:
def initialize(path)
raise ArgumentError, "path already is a Path class" if path.is_a?(Path)
- @path = (path.ends_with?(File::SEPARATOR) ? path.to(-2) : path).freeze
+ @path = path.freeze
end
def to_s
@@ -38,28 +38,49 @@ module ActionView #:nodoc:
# should not be confused with format extensions +html+, +js+, +xml+,
# etc. A format must be supplied to match a formated file. +hello/index+
# will never match +hello/index.html.erb+.
- def [](path)
+ def find_template(path)
+ templates_in_path do |template|
+ if template.accessible_paths.include?(path)
+ return template
+ end
+ end
+ nil
end
- def load!
- end
+ def find_by_parts(name, extensions = nil, prefix = nil, partial = nil)
+ path = prefix ? "#{prefix}/" : ""
+
+ name = name.to_s.split("/")
+ name[-1] = "_#{name[-1]}" if partial
+
+ path << name.join("/")
+
+ template = nil
- def self.new_and_loaded(path)
- returning new(path) do |path|
- path.load!
+ Array(extensions).each do |extension|
+ extensioned_path = extension ? "#{path}.#{extension}" : path
+ template = find_template(extensioned_path) || find_template(path)
+ break if template
end
+ template || find_template(path)
end
-
+
private
- def relative_path_for_template_file(full_file_path)
- full_file_path.split("#{@path}/").last
+ def templates_in_path
+ (Dir.glob("#{@path}/**/*/**") | Dir.glob("#{@path}/**")).each do |file|
+ yield create_template(file) unless File.directory?(file)
+ end
+ end
+
+ def create_template(file)
+ Template.new(file.split("#{self}/").last, self)
end
end
class EagerPath < Path
- def load!
- return if @loaded
-
+ def initialize(path)
+ super
+
@paths = {}
templates_in_path do |template|
template.load!
@@ -68,24 +89,11 @@ module ActionView #:nodoc:
end
end
@paths.freeze
- @loaded = true
end
- def [](path)
- load! unless @loaded
+ def find_template(path)
@paths[path]
end
-
- private
- def templates_in_path
- (Dir.glob("#{@path}/**/*/**") | Dir.glob("#{@path}/**")).each do |file|
- yield create_template(file) unless File.directory?(file)
- end
- end
-
- def create_template(file)
- Template.new(relative_path_for_template_file(file), self)
- end
end
extend TemplateHandlers
@@ -107,8 +115,9 @@ module ActionView #:nodoc:
attr_accessor :locale, :name, :format, :extension
delegate :to_s, :to => :path
- def initialize(template_path, load_path = nil)
- @template_path, @load_path = template_path.dup, load_path
+ def initialize(template_path, load_paths = [])
+ template_path = template_path.dup
+ @load_path, @filename = find_full_path(template_path, load_paths)
@base_path, @name, @locale, @format, @extension = split(template_path)
@base_path.to_s.gsub!(/\/$/, '') # Push to split method
@@ -179,11 +188,10 @@ module ActionView #:nodoc:
@@exempt_from_layout.any? { |exempted| path =~ exempted }
end
- def filename
- # no load_path means this is an "absolute pathed" template
- load_path ? File.join(load_path, template_path) : template_path
+ def mtime
+ File.mtime(filename)
end
- memoize :filename
+ memoize :mtime
def source
File.read(filename)
@@ -195,20 +203,17 @@ module ActionView #:nodoc:
end
memoize :method_segment
- def render_template(view, local_assigns = {})
- render(view, local_assigns)
- rescue Exception => e
- raise e unless filename
- if TemplateError === e
- e.sub_template_of(self)
- raise e
- else
- raise TemplateError.new(self, view.assigns, e)
- end
+ def stale?
+ File.mtime(filename) > mtime
+ end
+
+ def recompile?
+ !@cached
end
def load!
- freeze
+ @cached = true
+ # freeze
end
private
@@ -217,30 +222,55 @@ module ActionView #:nodoc:
end
def valid_locale?(locale)
- locale && I18n.available_locales.include?(locale.to_sym)
+ I18n.available_locales.include?(locale.to_sym)
+ end
+
+ def find_full_path(path, load_paths)
+ load_paths = Array(load_paths) + [nil]
+ load_paths.each do |load_path|
+ file = load_path ? "#{load_path.to_str}/#{path}" : path
+ return load_path, file if File.file?(file)
+ end
+ raise MissingTemplate.new(load_paths, path)
end
# Returns file split into an array
# [base_path, name, locale, format, extension]
def split(file)
if m = file.to_s.match(/^(.*\/)?([^\.]+)\.(.*)$/)
- [m[1], m[2], *parse_extensions(m[3])]
+ base_path = m[1]
+ name = m[2]
+ extensions = m[3]
+ else
+ return
end
- end
- # returns parsed extensions as an array
- # [locale, format, extension]
- def parse_extensions(extensions)
- exts = extensions.split(".")
-
- if extension = valid_extension?(exts.last) && exts.pop || nil
- locale = valid_locale?(exts.first) && exts.shift || nil
- format = exts.join('.') if exts.any? # join('.') is needed for multipart templates
- else # no extension, just format
- format = exts.last
+ locale = nil
+ format = nil
+ extension = nil
+
+ if m = extensions.split(".")
+ if valid_locale?(m[0]) && m[1] && valid_extension?(m[2]) # All three
+ locale = m[0]
+ format = m[1]
+ extension = m[2]
+ elsif m[0] && m[1] && valid_extension?(m[2]) # Multipart formats
+ format = "#{m[0]}.#{m[1]}"
+ extension = m[2]
+ elsif valid_locale?(m[0]) && valid_extension?(m[1]) # locale and extension
+ locale = m[0]
+ extension = m[1]
+ elsif valid_extension?(m[1]) # format and extension
+ format = m[0]
+ extension = m[1]
+ elsif valid_extension?(m[0]) # Just extension
+ extension = m[0]
+ else # No extension
+ format = m[0]
+ end
end
- [locale, format, extension]
+ [base_path, name, locale, format, extension]
end
end
end
diff --git a/actionpack/lib/action_view/template/text.rb b/actionpack/lib/action_view/template/text.rb
new file mode 100644
index 0000000000..f81174d707
--- /dev/null
+++ b/actionpack/lib/action_view/template/text.rb
@@ -0,0 +1,9 @@
+module ActionView #:nodoc:
+ class TextTemplate < String #:nodoc:
+
+ def render(*) self end
+
+ def exempt_from_layout?() false end
+
+ end
+end
diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb
index ec337bb05b..c8f204046b 100644
--- a/actionpack/lib/action_view/test_case.rb
+++ b/actionpack/lib/action_view/test_case.rb
@@ -7,18 +7,15 @@ module ActionView
@_rendered = { :template => nil, :partials => Hash.new(0) }
initialize_without_template_tracking(*args)
end
- end
-
- module Renderable
- alias_method :render_without_template_tracking, :render
- def render(view, local_assigns = {})
- if respond_to?(:path) && !is_a?(InlineTemplate)
- rendered = view.instance_variable_get(:@_rendered)
- rendered[:partials][self] += 1 if is_a?(RenderablePartial)
- rendered[:template] ||= self
+
+ alias_method :_render_template_without_template_tracking, :_render_template
+ def _render_template(template, local_assigns = {})
+ if template.respond_to?(:path) && !template.is_a?(InlineTemplate)
+ @_rendered[:partials][template] += 1 if template.is_a?(RenderablePartial)
+ @_rendered[:template] ||= template
end
- render_without_template_tracking(view, local_assigns)
- end
+ _render_template_without_template_tracking(template, local_assigns)
+ end
end
class TestCase < ActiveSupport::TestCase
diff --git a/actionpack/test/abstract_controller/abstract_controller_test.rb b/actionpack/test/abstract_controller/abstract_controller_test.rb
new file mode 100644
index 0000000000..6d33888821
--- /dev/null
+++ b/actionpack/test/abstract_controller/abstract_controller_test.rb
@@ -0,0 +1,226 @@
+require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
+
+module AbstractController
+ module Testing
+
+ # Test basic dispatching.
+ # ====
+ # * Call process
+ # * Test that the response_body is set correctly
+ class SimpleController < AbstractController::Base
+ end
+
+ class Me < SimpleController
+ def index
+ self.response_body = "Hello world"
+ "Something else"
+ end
+ end
+
+ class TestBasic < ActiveSupport::TestCase
+ test "dispatching works" do
+ result = Me.process(:index)
+ assert_equal "Hello world", result.response_obj[:body]
+ end
+ end
+
+ # Test Render mixin
+ # ====
+ class RenderingController < AbstractController::Base
+ use Renderer
+
+ def _prefix() end
+
+ def render(options = {})
+ if options.is_a?(String)
+ options = {:_template_name => options}
+ end
+
+ options[:_prefix] = _prefix
+ super
+ end
+
+ append_view_path File.expand_path(File.join(File.dirname(__FILE__), "views"))
+ end
+
+ class Me2 < RenderingController
+ def index
+ render "index.erb"
+ end
+
+ def action_with_ivars
+ @my_ivar = "Hello"
+ render "action_with_ivars.erb"
+ end
+
+ def naked_render
+ render
+ end
+ end
+
+ class TestRenderer < ActiveSupport::TestCase
+ test "rendering templates works" do
+ result = Me2.process(:index)
+ assert_equal "Hello from index.erb", result.response_obj[:body]
+ end
+
+ test "rendering passes ivars to the view" do
+ result = Me2.process(:action_with_ivars)
+ assert_equal "Hello from index_with_ivars.erb", result.response_obj[:body]
+ end
+
+ test "rendering with no template name" do
+ result = Me2.process(:naked_render)
+ assert_equal "Hello from naked_render.erb", result.response_obj[:body]
+ end
+ end
+
+ # Test rendering with prefixes
+ # ====
+ # * self._prefix is used when defined
+ class PrefixedViews < RenderingController
+ private
+ def self.prefix
+ name.underscore
+ end
+
+ def _prefix
+ self.class.prefix
+ end
+ end
+
+ class Me3 < PrefixedViews
+ def index
+ render
+ end
+
+ def formatted
+ self.formats = [:html]
+ render
+ end
+ end
+
+ class TestPrefixedViews < ActiveSupport::TestCase
+ test "templates are located inside their 'prefix' folder" do
+ result = Me3.process(:index)
+ assert_equal "Hello from me3/index.erb", result.response_obj[:body]
+ end
+
+ test "templates included their format" do
+ result = Me3.process(:formatted)
+ assert_equal "Hello from me3/formatted.html.erb", result.response_obj[:body]
+ end
+ end
+
+ # Test rendering with layouts
+ # ====
+ # self._layout is used when defined
+ class WithLayouts < PrefixedViews
+ use Layouts
+
+ private
+ def self.layout(formats)
+ begin
+ view_paths.find_by_parts(name.underscore, formats, "layouts")
+ rescue ActionView::MissingTemplate
+ begin
+ view_paths.find_by_parts("application", formats, "layouts")
+ rescue ActionView::MissingTemplate
+ end
+ end
+ end
+
+ def _layout
+ self.class.layout(formats)
+ end
+
+ def render_to_string(options = {})
+ options[:_layout] = options[:layout] || _layout
+ super
+ end
+ end
+
+ class Me4 < WithLayouts
+ def index
+ render
+ end
+ end
+
+ class Me5 < WithLayouts
+ def index
+ render
+ end
+ end
+
+ class TestLayouts < ActiveSupport::TestCase
+ test "layouts are included" do
+ result = Me4.process(:index)
+ assert_equal "Me4 Enter : Hello from me4/index.erb : Exit", result.response_obj[:body]
+ end
+
+ test "it can fall back to the application layout" do
+ result = Me5.process(:index)
+ assert_equal "Application Enter : Hello from me5/index.erb : Exit", result.response_obj[:body]
+ end
+ end
+
+ # respond_to_action?(action_name)
+ # ====
+ # * A method can be used as an action only if this method
+ # returns true when passed the method name as an argument
+ # * Defaults to true in AbstractController
+ class DefaultRespondToActionController < AbstractController::Base
+ def index() self.response_body = "success" end
+ end
+
+ class ActionMissingRespondToActionController < AbstractController::Base
+ # No actions
+ private
+ def action_missing(action_name)
+ self.response_body = "success"
+ end
+ end
+
+ class RespondToActionController < AbstractController::Base;
+ def index() self.response_body = "success" end
+
+ def fail() self.response_body = "fail" end
+
+ private
+
+ def respond_to_action?(action_name)
+ action_name != :fail
+ end
+
+ end
+
+ class TestRespondToAction < ActiveSupport::TestCase
+
+ def assert_dispatch(klass, body = "success", action = :index)
+ response = klass.process(action).response_obj[:body]
+ assert_equal body, response
+ end
+
+ test "an arbitrary method is available as an action by default" do
+ assert_dispatch DefaultRespondToActionController, "success", :index
+ end
+
+ test "raises ActionNotFound when method does not exist and action_missing is not defined" do
+ assert_raise(ActionNotFound) { DefaultRespondToActionController.process(:fail) }
+ end
+
+ test "dispatches to action_missing when method does not exist and action_missing is defined" do
+ assert_dispatch ActionMissingRespondToActionController, "success", :ohai
+ end
+
+ test "a method is available as an action if respond_to_action? returns true" do
+ assert_dispatch RespondToActionController, "success", :index
+ end
+
+ test "raises ActionNotFound if method is defined but respond_to_action? returns false" do
+ assert_raise(ActionNotFound) { RespondToActionController.process(:fail) }
+ end
+ end
+
+ end
+end \ No newline at end of file
diff --git a/actionpack/test/abstract_controller/callbacks_test.rb b/actionpack/test/abstract_controller/callbacks_test.rb
new file mode 100644
index 0000000000..5fce30f478
--- /dev/null
+++ b/actionpack/test/abstract_controller/callbacks_test.rb
@@ -0,0 +1,197 @@
+require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
+
+module AbstractController
+ module Testing
+
+ class ControllerWithCallbacks < AbstractController::Base
+ use AbstractController::Callbacks
+ end
+
+ class Callback1 < ControllerWithCallbacks
+ process_action_callback :before, :first
+
+ def first
+ @text = "Hello world"
+ end
+
+ def index
+ self.response_body = @text
+ end
+ end
+
+ class TestCallbacks < ActiveSupport::TestCase
+ test "basic callbacks work" do
+ result = Callback1.process(:index)
+ assert_equal "Hello world", result.response_obj[:body]
+ end
+ end
+
+ class Callback2 < ControllerWithCallbacks
+ before_filter :first
+ after_filter :second
+ around_filter :aroundz
+
+ def first
+ @text = "Hello world"
+ end
+
+ def second
+ @second = "Goodbye"
+ end
+
+ def aroundz
+ @aroundz = "FIRST"
+ yield
+ @aroundz << "SECOND"
+ end
+
+ def index
+ self.response_body = @text
+ end
+ end
+
+ class TestCallbacks < ActiveSupport::TestCase
+ test "before_filter works" do
+ result = Callback2.process(:index)
+ assert_equal "Hello world", result.response_obj[:body]
+ end
+
+ test "after_filter works" do
+ result = Callback2.process(:index)
+ assert_equal "Goodbye", result.instance_variable_get("@second")
+ end
+
+ test "around_filter works" do
+ result = Callback2.process(:index)
+ assert_equal "FIRSTSECOND", result.instance_variable_get("@aroundz")
+ end
+ end
+
+ class Callback3 < ControllerWithCallbacks
+ before_filter do |c|
+ c.instance_variable_set("@text", "Hello world")
+ end
+
+ after_filter do |c|
+ c.instance_variable_set("@second", "Goodbye")
+ end
+
+ def index
+ self.response_body = @text
+ end
+ end
+
+ class TestCallbacks < ActiveSupport::TestCase
+ test "before_filter works with procs" do
+ result = Callback3.process(:index)
+ assert_equal "Hello world", result.response_obj[:body]
+ end
+
+ test "after_filter works with procs" do
+ result = Callback3.process(:index)
+ assert_equal "Goodbye", result.instance_variable_get("@second")
+ end
+ end
+
+ class CallbacksWithConditions < ControllerWithCallbacks
+ before_filter :list, :only => :index
+ before_filter :authenticate, :except => :index
+
+ def index
+ self.response_body = @list.join(", ")
+ end
+
+ def sekrit_data
+ self.response_body = (@list + [@authenticated]).join(", ")
+ end
+
+ private
+ def list
+ @list = ["Hello", "World"]
+ end
+
+ def authenticate
+ @list = []
+ @authenticated = "true"
+ end
+ end
+
+ class TestCallbacks < ActiveSupport::TestCase
+ test "when :only is specified, a before filter is triggered on that action" do
+ result = CallbacksWithConditions.process(:index)
+ assert_equal "Hello, World", result.response_obj[:body]
+ end
+
+ test "when :only is specified, a before filter is not triggered on other actions" do
+ result = CallbacksWithConditions.process(:sekrit_data)
+ assert_equal "true", result.response_obj[:body]
+ end
+
+ test "when :except is specified, an after filter is not triggered on that action" do
+ result = CallbacksWithConditions.process(:index)
+ assert_nil result.instance_variable_get("@authenticated")
+ end
+ end
+
+ class CallbacksWithArrayConditions < ControllerWithCallbacks
+ before_filter :list, :only => [:index, :listy]
+ before_filter :authenticate, :except => [:index, :listy]
+
+ def index
+ self.response_body = @list.join(", ")
+ end
+
+ def sekrit_data
+ self.response_body = (@list + [@authenticated]).join(", ")
+ end
+
+ private
+ def list
+ @list = ["Hello", "World"]
+ end
+
+ def authenticate
+ @list = []
+ @authenticated = "true"
+ end
+ end
+
+ class TestCallbacks < ActiveSupport::TestCase
+ test "when :only is specified with an array, a before filter is triggered on that action" do
+ result = CallbacksWithArrayConditions.process(:index)
+ assert_equal "Hello, World", result.response_obj[:body]
+ end
+
+ test "when :only is specified with an array, a before filter is not triggered on other actions" do
+ result = CallbacksWithArrayConditions.process(:sekrit_data)
+ assert_equal "true", result.response_obj[:body]
+ end
+
+ test "when :except is specified with an array, an after filter is not triggered on that action" do
+ result = CallbacksWithArrayConditions.process(:index)
+ assert_nil result.instance_variable_get("@authenticated")
+ end
+ end
+
+ class ChangedConditions < Callback2
+ before_filter :first, :only => :index
+
+ def not_index
+ self.response_body = @text.to_s
+ end
+ end
+
+ class TestCallbacks < ActiveSupport::TestCase
+ test "when a callback is modified in a child with :only, it works for the :only action" do
+ result = ChangedConditions.process(:index)
+ assert_equal "Hello world", result.response_obj[:body]
+ end
+
+ test "when a callback is modified in a child with :only, it does not work for other actions" do
+ result = ChangedConditions.process(:not_index)
+ assert_equal "", result.response_obj[:body]
+ end
+ end
+
+ end
+end \ No newline at end of file
diff --git a/actionpack/test/abstract_controller/helper_test.rb b/actionpack/test/abstract_controller/helper_test.rb
new file mode 100644
index 0000000000..6284fa4f70
--- /dev/null
+++ b/actionpack/test/abstract_controller/helper_test.rb
@@ -0,0 +1,43 @@
+require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
+
+module AbstractController
+ module Testing
+
+ class ControllerWithHelpers < AbstractController::Base
+ use Renderer
+ use Helpers
+
+ def render(string)
+ super(:_template_name => string)
+ end
+
+ append_view_path File.expand_path(File.join(File.dirname(__FILE__), "views"))
+ end
+
+ module HelperyTest
+ def included_method
+ "Included"
+ end
+ end
+
+ class MyHelpers1 < ControllerWithHelpers
+ helper(HelperyTest) do
+ def helpery_test
+ "World"
+ end
+ end
+
+ def index
+ render "helper_test.erb"
+ end
+ end
+
+ class TestHelpers < ActiveSupport::TestCase
+ def test_helpers
+ result = MyHelpers1.process(:index)
+ assert_equal "Hello World : Included", result.response_obj[:body]
+ end
+ end
+
+ end
+end \ No newline at end of file
diff --git a/actionpack/test/abstract_controller/layouts_test.rb b/actionpack/test/abstract_controller/layouts_test.rb
new file mode 100644
index 0000000000..5dd68ec28e
--- /dev/null
+++ b/actionpack/test/abstract_controller/layouts_test.rb
@@ -0,0 +1,232 @@
+require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
+
+module AbstractControllerTests
+ module Layouts
+
+ # Base controller for these tests
+ class Base < AbstractController::Base
+ use AbstractController::Renderer
+ use AbstractController::Layouts
+
+ self.view_paths = [ActionView::FixtureTemplate::FixturePath.new(
+ "layouts/hello.erb" => "With String <%= yield %>",
+ "layouts/hello_override.erb" => "With Override <%= yield %>",
+ "layouts/abstract_controller_tests/layouts/with_string_implied_child.erb" =>
+ "With Implied <%= yield %>",
+ "layouts/omg.erb" => "OMGHI2U <%= yield %>",
+ "layouts/with_false_layout.erb" => "False Layout <%= yield %>"
+ )]
+
+ def self.controller_path
+ @controller_path ||= self.name.sub(/Controller$/, '').underscore
+ end
+
+ def controller_path() self.class.controller_path end
+
+ def render_to_string(options)
+ options[:_layout] = _default_layout
+ super
+ end
+ end
+
+ class Blank < Base
+ self.view_paths = []
+
+ def index
+ render :_template => ActionView::TextTemplate.new("Hello blank!")
+ end
+ end
+
+ class WithString < Base
+ layout "hello"
+
+ def index
+ render :_template => ActionView::TextTemplate.new("Hello string!")
+ end
+ end
+
+ class WithStringChild < WithString
+ end
+
+ class WithStringOverriddenChild < WithString
+ layout "hello_override"
+ end
+
+ class WithNilChild < WithString
+ layout nil
+ end
+
+ class WithStringImpliedChild < WithString
+ end
+
+ class WithChildOfImplied < WithStringImpliedChild
+ end
+
+ class WithSymbol < Base
+ layout :hello
+
+ def index
+ render :_template => ActionView::TextTemplate.new("Hello symbol!")
+ end
+ private
+ def hello
+ "omg"
+ end
+ end
+
+ class WithSymbolReturningString < Base
+ layout :no_hello
+
+ def index
+ render :_template => ActionView::TextTemplate.new("Hello missing symbol!")
+ end
+ private
+ def no_hello
+ nil
+ end
+ end
+
+ class WithSymbolReturningNil < Base
+ layout :nilz
+
+ def index
+ render :_template => ActionView::TextTemplate.new("Hello nilz!")
+ end
+
+ def nilz() end
+ end
+
+ class WithSymbolReturningObj < Base
+ layout :objekt
+
+ def index
+ render :_template => ActionView::TextTemplate.new("Hello nilz!")
+ end
+
+ def objekt
+ Object.new
+ end
+ end
+
+ class WithSymbolAndNoMethod < Base
+ layout :omg_no_method
+
+ def index
+ render :_template => ActionView::TextTemplate.new("Hello boom!")
+ end
+ end
+
+ class WithMissingLayout < Base
+ layout "missing"
+
+ def index
+ render :_template => ActionView::TextTemplate.new("Hello missing!")
+ end
+ end
+
+ class WithFalseLayout < Base
+ layout false
+
+ def index
+ render :_template => ActionView::TextTemplate.new("Hello false!")
+ end
+ end
+
+ class WithNilLayout < Base
+ layout nil
+
+ def index
+ render :_template => ActionView::TextTemplate.new("Hello nil!")
+ end
+ end
+
+ # TODO Move to bootloader
+ AbstractController::Base.subclasses.each do |klass|
+ klass = klass.constantize
+ next unless klass < AbstractController::Layouts
+ klass.class_eval do
+ _write_layout_method
+ end
+ end
+
+ class TestBase < ActiveSupport::TestCase
+ test "when no layout is specified, and no default is available, render without a layout" do
+ result = Blank.process(:index)
+ assert_equal "Hello blank!", result.response_obj[:body]
+ end
+
+ test "when layout is specified as a string, render with that layout" do
+ result = WithString.process(:index)
+ assert_equal "With String Hello string!", result.response_obj[:body]
+ end
+
+ test "when layout is specified as a string, but the layout is missing, raise an exception" do
+ assert_raises(ActionView::MissingTemplate) { WithMissingLayout.process(:index) }
+ end
+
+ test "when layout is specified as false, do not use a layout" do
+ result = WithFalseLayout.process(:index)
+ assert_equal "Hello false!", result.response_obj[:body]
+ end
+
+ test "when layout is specified as nil, do not use a layout" do
+ result = WithNilLayout.process(:index)
+ assert_equal "Hello nil!", result.response_obj[:body]
+ end
+
+ test "when layout is specified as a symbol, call the requested method and use the layout returned" do
+ result = WithSymbol.process(:index)
+ assert_equal "OMGHI2U Hello symbol!", result.response_obj[:body]
+ end
+
+ test "when layout is specified as a symbol and the method returns nil, don't use a layout" do
+ result = WithSymbolReturningNil.process(:index)
+ assert_equal "Hello nilz!", result.response_obj[:body]
+ end
+
+ test "when the layout is specified as a symbol and the method doesn't exist, raise an exception" do
+ assert_raises(NoMethodError, /:nilz/) { WithSymbolAndNoMethod.process(:index) }
+ end
+
+ test "when the layout is specified as a symbol and the method returns something besides a string/false/nil, raise an exception" do
+ assert_raises(ArgumentError) { WithSymbolReturningObj.process(:index) }
+ end
+
+ test "when a child controller does not have a layout, use the parent controller layout" do
+ result = WithStringChild.process(:index)
+ assert_equal "With String Hello string!", result.response_obj[:body]
+ end
+
+ test "when a child controller has specified a layout, use that layout and not the parent controller layout" do
+ result = WithStringOverriddenChild.process(:index)
+ assert_equal "With Override Hello string!", result.response_obj[:body]
+ end
+
+ test "when a child controller has an implied layout, use that layout and not the parent controller layout" do
+ result = WithStringImpliedChild.process(:index)
+ assert_equal "With Implied Hello string!", result.response_obj[:body]
+ end
+
+ test "when a child controller specifies layout nil, do not use the parent layout" do
+ result = WithNilChild.process(:index)
+ assert_equal "Hello string!", result.response_obj[:body]
+ end
+
+ test "when a grandchild has no layout specified, the child has an implied layout, and the " \
+ "parent has specified a layout, use the child controller layout" do
+ result = WithChildOfImplied.process(:index)
+ assert_equal "With Implied Hello string!", result.response_obj[:body]
+ end
+
+ test "raises an exception when specifying layout true" do
+ assert_raises ArgumentError do
+ Object.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
+ class ::BadOmgFailLolLayout < AbstractControllerTests::Layouts::Base
+ layout true
+ end
+ RUBY_EVAL
+ end
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/test/abstract_controller/test_helper.rb b/actionpack/test/abstract_controller/test_helper.rb
new file mode 100644
index 0000000000..b9248c6bbd
--- /dev/null
+++ b/actionpack/test/abstract_controller/test_helper.rb
@@ -0,0 +1,25 @@
+$:.unshift(File.dirname(__FILE__) + '/../../lib')
+$:.unshift(File.dirname(__FILE__) + '/../../../activesupport/lib')
+$:.unshift(File.dirname(__FILE__) + '/../lib')
+
+require 'test/unit'
+require 'active_support'
+require 'active_support/test_case'
+require 'action_controller'
+require 'action_view/base'
+require 'fixture_template'
+
+begin
+ require 'ruby-debug'
+ Debugger.settings[:autoeval] = true
+ Debugger.start
+rescue LoadError
+ # Debugging disabled. `gem install ruby-debug` to enable.
+end
+
+require 'action_controller/abstract'
+# require 'action_controller/abstract/base'
+# require 'action_controller/abstract/renderer'
+# require 'action_controller/abstract/layouts'
+# require 'action_controller/abstract/callbacks'
+# require 'action_controller/abstract/helpers' \ No newline at end of file
diff --git a/actionpack/test/abstract_controller/views/abstract_controller/testing/me3/formatted.html.erb b/actionpack/test/abstract_controller/views/abstract_controller/testing/me3/formatted.html.erb
new file mode 100644
index 0000000000..785bf69191
--- /dev/null
+++ b/actionpack/test/abstract_controller/views/abstract_controller/testing/me3/formatted.html.erb
@@ -0,0 +1 @@
+Hello from me3/formatted.html.erb \ No newline at end of file
diff --git a/actionpack/test/abstract_controller/views/abstract_controller/testing/me3/index.erb b/actionpack/test/abstract_controller/views/abstract_controller/testing/me3/index.erb
new file mode 100644
index 0000000000..f079ad8204
--- /dev/null
+++ b/actionpack/test/abstract_controller/views/abstract_controller/testing/me3/index.erb
@@ -0,0 +1 @@
+Hello from me3/index.erb \ No newline at end of file
diff --git a/actionpack/test/abstract_controller/views/abstract_controller/testing/me4/index.erb b/actionpack/test/abstract_controller/views/abstract_controller/testing/me4/index.erb
new file mode 100644
index 0000000000..89dce12bdc
--- /dev/null
+++ b/actionpack/test/abstract_controller/views/abstract_controller/testing/me4/index.erb
@@ -0,0 +1 @@
+Hello from me4/index.erb \ No newline at end of file
diff --git a/actionpack/test/abstract_controller/views/abstract_controller/testing/me5/index.erb b/actionpack/test/abstract_controller/views/abstract_controller/testing/me5/index.erb
new file mode 100644
index 0000000000..84d0b7417e
--- /dev/null
+++ b/actionpack/test/abstract_controller/views/abstract_controller/testing/me5/index.erb
@@ -0,0 +1 @@
+Hello from me5/index.erb \ No newline at end of file
diff --git a/actionpack/test/abstract_controller/views/action_with_ivars.erb b/actionpack/test/abstract_controller/views/action_with_ivars.erb
new file mode 100644
index 0000000000..8d8ae22fd7
--- /dev/null
+++ b/actionpack/test/abstract_controller/views/action_with_ivars.erb
@@ -0,0 +1 @@
+<%= @my_ivar %> from index_with_ivars.erb \ No newline at end of file
diff --git a/actionpack/test/abstract_controller/views/helper_test.erb b/actionpack/test/abstract_controller/views/helper_test.erb
new file mode 100644
index 0000000000..8ae45cc195
--- /dev/null
+++ b/actionpack/test/abstract_controller/views/helper_test.erb
@@ -0,0 +1 @@
+Hello <%= helpery_test %> : <%= included_method %> \ No newline at end of file
diff --git a/actionpack/test/abstract_controller/views/index.erb b/actionpack/test/abstract_controller/views/index.erb
new file mode 100644
index 0000000000..cc1a8b8c85
--- /dev/null
+++ b/actionpack/test/abstract_controller/views/index.erb
@@ -0,0 +1 @@
+Hello from index.erb \ No newline at end of file
diff --git a/actionpack/test/abstract_controller/views/layouts/abstract_controller/testing/me4.erb b/actionpack/test/abstract_controller/views/layouts/abstract_controller/testing/me4.erb
new file mode 100644
index 0000000000..172dd56569
--- /dev/null
+++ b/actionpack/test/abstract_controller/views/layouts/abstract_controller/testing/me4.erb
@@ -0,0 +1 @@
+Me4 Enter : <%= yield %> : Exit \ No newline at end of file
diff --git a/actionpack/test/abstract_controller/views/layouts/application.erb b/actionpack/test/abstract_controller/views/layouts/application.erb
new file mode 100644
index 0000000000..27317140ad
--- /dev/null
+++ b/actionpack/test/abstract_controller/views/layouts/application.erb
@@ -0,0 +1 @@
+Application Enter : <%= yield %> : Exit \ No newline at end of file
diff --git a/actionpack/test/abstract_controller/views/naked_render.erb b/actionpack/test/abstract_controller/views/naked_render.erb
new file mode 100644
index 0000000000..1b3d03878b
--- /dev/null
+++ b/actionpack/test/abstract_controller/views/naked_render.erb
@@ -0,0 +1 @@
+Hello from naked_render.erb \ No newline at end of file
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index cdeee934d0..b07e6e5f3a 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -20,8 +20,7 @@ rescue LoadError
end
require 'action_controller'
-require 'action_controller/cgi_ext'
-require 'action_controller/test_process'
+require 'action_controller/testing/process'
require 'action_view/test_case'
# Show backtraces for deprecated behavior for quicker cleanup.
@@ -38,8 +37,4 @@ I18n.backend.store_translations 'pt-BR', {}
ORIGINAL_LOCALES = I18n.available_locales.map(&:to_s).sort
FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
-ActionView::Base.cache_template_loading = true
ActionController::Base.view_paths = FIXTURE_LOAD_PATH
-CACHED_VIEW_PATHS = ActionView::Base.cache_template_loading? ?
- ActionController::Base.view_paths :
- ActionController::Base.view_paths.map {|path| ActionView::Template::EagerPath.new(path.to_s)}
diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb
index cb7922efd2..96f7a42c9b 100644
--- a/actionpack/test/controller/action_pack_assertions_test.rb
+++ b/actionpack/test/controller/action_pack_assertions_test.rb
@@ -168,11 +168,13 @@ end
class ActionPackAssertionsControllerTest < ActionController::TestCase
# let's get this party started
def setup
+ super
ActionController::Routing::Routes.reload
ActionController::Routing.use_controllers!(%w(action_pack_assertions admin/inner_module user content admin/user))
end
def teardown
+ super
ActionController::Routing::Routes.reload
end
diff --git a/actionpack/test/controller/addresses_render_test.rb b/actionpack/test/controller/addresses_render_test.rb
index 556b0593ea..2f092b6731 100644
--- a/actionpack/test/controller/addresses_render_test.rb
+++ b/actionpack/test/controller/addresses_render_test.rb
@@ -23,6 +23,7 @@ class AddressesTest < ActionController::TestCase
tests AddressesTestController
def setup
+ super
# enable a logger so that (e.g.) the benchmarking stuff runs, so we can get
# a more accurate simulation of what happens in "real life".
@controller.logger = Logger.new(nil)
diff --git a/actionpack/test/controller/assert_select_test.rb b/actionpack/test/controller/assert_select_test.rb
index 298c7e4db3..ad17d1288b 100644
--- a/actionpack/test/controller/assert_select_test.rb
+++ b/actionpack/test/controller/assert_select_test.rb
@@ -66,12 +66,14 @@ class AssertSelectTest < ActionController::TestCase
tests AssertSelectController
def setup
+ super
ActionMailer::Base.delivery_method = :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries = []
end
def teardown
+ super
ActionMailer::Base.deliveries.clear
end
diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb
index 9523189f41..f4517d06c4 100644
--- a/actionpack/test/controller/base_test.rb
+++ b/actionpack/test/controller/base_test.rb
@@ -170,6 +170,7 @@ class DefaultUrlOptionsTest < ActionController::TestCase
tests DefaultUrlOptionsController
def setup
+ super
@request.host = 'www.example.com'
rescue_action_in_public!
end
@@ -193,6 +194,7 @@ class EmptyUrlOptionsTest < ActionController::TestCase
tests NonEmptyController
def setup
+ super
@request.host = 'www.example.com'
rescue_action_in_public!
end
diff --git a/actionpack/test/controller/benchmark_test.rb b/actionpack/test/controller/benchmark_test.rb
index f9100a2313..66ebfcf20a 100644
--- a/actionpack/test/controller/benchmark_test.rb
+++ b/actionpack/test/controller/benchmark_test.rb
@@ -20,6 +20,7 @@ class BenchmarkTest < ActionController::TestCase
end
def setup
+ super
# benchmark doesn't do anything unless a logger is set
@controller.logger = MockLogger.new
@request.host = "test.actioncontroller.i"
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index 86dafd9221..b61a58dd09 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -44,6 +44,7 @@ end
class PageCachingTest < ActionController::TestCase
def setup
+ super
ActionController::Base.perform_caching = true
ActionController::Routing::Routes.draw do |map|
@@ -222,6 +223,7 @@ end
class ActionCacheTest < ActionController::TestCase
def setup
+ super
reset!
FileUtils.mkdir_p(FILE_STORE_PATH)
@path_class = ActionController::Caching::Actions::ActionCachePath
@@ -483,6 +485,7 @@ end
class FragmentCachingTest < ActionController::TestCase
def setup
+ super
ActionController::Base.perform_caching = true
@store = ActiveSupport::Cache::MemoryStore.new
ActionController::Base.cache_store = @store
@@ -615,6 +618,7 @@ end
class FunctionalFragmentCachingTest < ActionController::TestCase
def setup
+ super
ActionController::Base.perform_caching = true
@store = ActiveSupport::Cache::MemoryStore.new
ActionController::Base.cache_store = @store
diff --git a/actionpack/test/controller/capture_test.rb b/actionpack/test/controller/capture_test.rb
index 6dfa0995eb..9a0976ca9f 100644
--- a/actionpack/test/controller/capture_test.rb
+++ b/actionpack/test/controller/capture_test.rb
@@ -27,6 +27,7 @@ class CaptureTest < ActionController::TestCase
tests CaptureController
def setup
+ super
# enable a logger so that (e.g.) the benchmarking stuff runs, so we can get
# a more accurate simulation of what happens in "real life".
@controller.logger = Logger.new(nil)
diff --git a/actionpack/test/controller/content_type_test.rb b/actionpack/test/controller/content_type_test.rb
index 32c1757ef9..7377546631 100644
--- a/actionpack/test/controller/content_type_test.rb
+++ b/actionpack/test/controller/content_type_test.rb
@@ -54,6 +54,7 @@ class ContentTypeTest < ActionController::TestCase
tests ContentTypeController
def setup
+ super
# enable a logger so that (e.g.) the benchmarking stuff runs, so we can get
# a more accurate simulation of what happens in "real life".
@controller.logger = Logger.new(nil)
@@ -136,10 +137,12 @@ class AcceptBasedContentTypeTest < ActionController::TestCase
tests ContentTypeController
def setup
+ super
ActionController::Base.use_accept_header = true
end
def teardown
+ super
ActionController::Base.use_accept_header = false
end
diff --git a/actionpack/test/controller/cookie_test.rb b/actionpack/test/controller/cookie_test.rb
index f7d97e160a..c861982698 100644
--- a/actionpack/test/controller/cookie_test.rb
+++ b/actionpack/test/controller/cookie_test.rb
@@ -48,6 +48,7 @@ class CookieTest < ActionController::TestCase
tests TestController
def setup
+ super
@request.host = "www.nextangle.com"
end
diff --git a/actionpack/test/controller/dispatcher_test.rb b/actionpack/test/controller/dispatcher_test.rb
index 7887b7110c..031a10975d 100644
--- a/actionpack/test/controller/dispatcher_test.rb
+++ b/actionpack/test/controller/dispatcher_test.rb
@@ -6,8 +6,8 @@ class DispatcherTest < Test::Unit::TestCase
def setup
ENV['REQUEST_METHOD'] = 'GET'
- Dispatcher.middleware = ActionController::MiddlewareStack.new do |middleware|
- middlewares = File.expand_path(File.join(File.dirname(__FILE__), "../../lib/action_controller/middlewares.rb"))
+ 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
@@ -47,7 +47,7 @@ class DispatcherTest < Test::Unit::TestCase
def test_failsafe_response
Dispatcher.any_instance.expects(:dispatch).raises('b00m')
- ActionController::Failsafe.any_instance.expects(:log_failsafe_exception)
+ ActionDispatch::Failsafe.any_instance.expects(:log_failsafe_exception)
assert_nothing_raised do
assert_equal [
diff --git a/actionpack/test/controller/header_test.rb b/actionpack/test/controller/header_test.rb
deleted file mode 100644
index 33c14a187c..0000000000
--- a/actionpack/test/controller/header_test.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-require 'abstract_unit'
-
-class HeaderTest < Test::Unit::TestCase
- def setup
- @headers = ActionController::Http::Headers.new("HTTP_CONTENT_TYPE"=>"text/plain")
- end
-
- def test_content_type_works
- assert_equal "text/plain", @headers["Content-Type"]
- assert_equal "text/plain", @headers["content-type"]
- assert_equal "text/plain", @headers["CONTENT_TYPE"]
- assert_equal "text/plain", @headers["HTTP_CONTENT_TYPE"]
- end
-end
diff --git a/actionpack/test/controller/layout_test.rb b/actionpack/test/controller/layout_test.rb
index 1575674e18..f2721e274d 100644
--- a/actionpack/test/controller/layout_test.rb
+++ b/actionpack/test/controller/layout_test.rb
@@ -37,6 +37,7 @@ end
class LayoutAutoDiscoveryTest < ActionController::TestCase
def setup
+ super
@request.host = "www.nextangle.com"
end
@@ -55,7 +56,7 @@ class LayoutAutoDiscoveryTest < ActionController::TestCase
def test_third_party_template_library_auto_discovers_layout
@controller = ThirdPartyTemplateLibraryController.new
get :hello
- assert_equal 'layouts/third_party_template_library.mab', @controller.active_layout.to_s
+ assert_equal 'layouts/third_party_template_library.mab', @controller.active_layout(true).to_s
assert_equal 'layouts/third_party_template_library', @response.layout
assert_response :success
assert_equal 'Mab', @response.body
@@ -64,14 +65,14 @@ class LayoutAutoDiscoveryTest < ActionController::TestCase
def test_namespaced_controllers_auto_detect_layouts
@controller = ControllerNameSpace::NestedController.new
get :hello
- assert_equal 'layouts/controller_name_space/nested', @controller.active_layout.to_s
+ assert_equal 'layouts/controller_name_space/nested', @controller.active_layout(true).to_s
assert_equal 'controller_name_space/nested.rhtml hello.rhtml', @response.body
end
def test_namespaced_controllers_auto_detect_layouts
@controller = MultipleExtensions.new
get :hello
- assert_equal 'layouts/multiple_extensions.html.erb', @controller.active_layout.to_s
+ assert_equal 'layouts/multiple_extensions.html.erb', @controller.active_layout(true).to_s
assert_equal 'multiple_extensions.html.erb hello.rhtml', @response.body.strip
end
end
@@ -94,6 +95,14 @@ class PrependsViewPathController < LayoutTest
end
end
+class OnlyLayoutController < LayoutTest
+ layout 'item', :only => "hello"
+end
+
+class ExceptLayoutController < LayoutTest
+ layout 'item', :except => "goodbye"
+end
+
class SetsLayoutInRenderController < LayoutTest
def hello
render :layout => 'third_party_template_library'
@@ -118,6 +127,30 @@ class LayoutSetInResponseTest < ActionController::TestCase
get :hello
assert_equal 'layouts/item', @response.layout
end
+
+ def test_layout_only_exception_when_included
+ @controller = OnlyLayoutController.new
+ get :hello
+ assert_equal 'layouts/item', @response.layout
+ end
+
+ def test_layout_only_exception_when_excepted
+ @controller = OnlyLayoutController.new
+ get :goodbye
+ assert_equal nil, @response.layout
+ end
+
+ def test_layout_except_exception_when_included
+ @controller = ExceptLayoutController.new
+ get :hello
+ assert_equal 'layouts/item', @response.layout
+ end
+
+ def test_layout_except_exception_when_excepted
+ @controller = ExceptLayoutController.new
+ get :goodbye
+ assert_equal nil, @response.layout
+ end
def test_layout_set_when_using_render
@controller = SetsLayoutInRenderController.new
@@ -143,9 +176,11 @@ class LayoutSetInResponseTest < ActionController::TestCase
end
def test_layout_is_picked_from_the_controller_instances_view_path
- @controller = PrependsViewPathController.new
- get :hello
- assert_equal 'layouts/alt', @response.layout
+ pending do
+ @controller = PrependsViewPathController.new
+ get :hello
+ assert_equal 'layouts/alt', @response.layout
+ end
end
def test_absolute_pathed_layout
@@ -201,4 +236,3 @@ unless RUBY_PLATFORM =~ /(:?mswin|mingw|bccwin)/
end
end
end
-
diff --git a/actionpack/test/controller/logging_test.rb b/actionpack/test/controller/logging_test.rb
index 3c936854dd..1f3ff4ef52 100644
--- a/actionpack/test/controller/logging_test.rb
+++ b/actionpack/test/controller/logging_test.rb
@@ -18,7 +18,10 @@ class LoggingTest < ActionController::TestCase
end
end
- setup :set_logger
+ def setup
+ super
+ set_logger
+ end
def test_logging_without_parameters
get :show
diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb
index edd7162325..1c81989d9b 100644
--- a/actionpack/test/controller/mime_responds_test.rb
+++ b/actionpack/test/controller/mime_responds_test.rb
@@ -166,11 +166,13 @@ class MimeControllerTest < ActionController::TestCase
tests RespondToController
def setup
+ super
ActionController::Base.use_accept_header = true
@request.host = "www.example.com"
end
def teardown
+ super
ActionController::Base.use_accept_header = false
end
@@ -437,7 +439,7 @@ class MimeControllerTest < ActionController::TestCase
unless args.empty?
@action = args.first[:action]
end
- response.body = "#{@action} - #{@template.template_format}"
+ response.body = "#{@action} - #{@template.formats}"
end
end
@@ -511,6 +513,7 @@ class MimeControllerLayoutsTest < ActionController::TestCase
tests PostController
def setup
+ super
@request.host = "www.example.com"
end
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index a52931565d..9a34bcebe6 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -315,13 +315,6 @@ class TestController < ActionController::Base
def render_implicit_html_template_from_xhr_request
end
- def render_implicit_js_template_without_layout
- end
-
- def render_html_explicit_template_and_layout
- render :template => 'test/render_implicit_html_template_from_xhr_request', :layout => 'layouts/default_html'
- end
-
def formatted_html_erb
end
@@ -390,7 +383,7 @@ class TestController < ActionController::Base
end
def accessing_params_in_template_with_layout
- render :layout => nil, :inline => "Hello: <%= params[:name] %>"
+ render :layout => true, :inline => "Hello: <%= params[:name] %>"
end
def render_with_explicit_template
@@ -737,8 +730,6 @@ class TestController < ActionController::Base
"delete_with_js", "update_page", "update_page_with_instance_variables"
"layouts/standard"
- when "render_implicit_js_template_without_layout"
- "layouts/default_html"
when "action_talk_to_layout", "layout_overriding_layout"
"layouts/talk_from_action"
when "render_implicit_html_template_from_xhr_request"
@@ -753,6 +744,7 @@ class RenderTest < ActionController::TestCase
def setup
# enable a logger so that (e.g.) the benchmarking stuff runs, so we can get
# a more accurate simulation of what happens in "real life".
+ super
@controller.logger = Logger.new(nil)
@request.host = "www.nextangle.com"
@@ -836,11 +828,6 @@ class RenderTest < ActionController::TestCase
assert_equal "<html>hello world, I'm here!</html>", @response.body
end
- def test_xhr_with_render_text_and_layout
- xhr :get, :render_text_hello_world_with_layout
- assert_equal "<html>hello world, I'm here!</html>", @response.body
- end
-
def test_do_with_render_action_and_layout_false
get :hello_world_with_layout_false
assert_equal 'Hello world!', @response.body
@@ -1081,18 +1068,17 @@ class RenderTest < ActionController::TestCase
end
def test_should_implicitly_render_html_template_from_xhr_request
- xhr :get, :render_implicit_html_template_from_xhr_request
- assert_equal "XHR!\nHello HTML!", @response.body
- end
-
- def test_should_render_explicit_html_template_with_html_layout
- xhr :get, :render_html_explicit_template_and_layout
- assert_equal "<html>Hello HTML!</html>\n", @response.body
+ pending do
+ xhr :get, :render_implicit_html_template_from_xhr_request
+ assert_equal "XHR!\nHello HTML!", @response.body
+ end
end
def test_should_implicitly_render_js_template_without_layout
- get :render_implicit_js_template_without_layout, :format => :js
- assert_no_match /<html>/, @response.body
+ pending do
+ get :render_implicit_js_template_without_layout, :format => :js
+ assert_no_match %r{<html>}, @response.body
+ end
end
def test_should_render_formatted_template
@@ -1308,7 +1294,7 @@ class RenderTest < ActionController::TestCase
assert !@response.headers.include?('Content-Length')
assert_response :no_content
- ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE.each do |status, code|
+ ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE.each do |status, code|
get :head_with_symbolic_status, :status => status.to_s
assert_equal code, @response.response_code
assert_response status
@@ -1316,7 +1302,7 @@ class RenderTest < ActionController::TestCase
end
def test_head_with_integer_status
- ActionController::StatusCodes::STATUS_CODES.each do |code, message|
+ ActionDispatch::StatusCodes::STATUS_CODES.each do |code, message|
get :head_with_integer_status, :status => code.to_s
assert_equal message, @response.message
end
@@ -1574,6 +1560,7 @@ class EtagRenderTest < ActionController::TestCase
tests TestController
def setup
+ super
@request.host = "www.nextangle.com"
@expected_bang_etag = etag_for(expand_key([:foo, 123]))
end
@@ -1684,6 +1671,7 @@ class LastModifiedRenderTest < ActionController::TestCase
tests TestController
def setup
+ super
@request.host = "www.nextangle.com"
@last_modified = Time.now.utc.beginning_of_day.httpdate
end
@@ -1739,6 +1727,7 @@ class RenderingLoggingTest < ActionController::TestCase
tests TestController
def setup
+ super
@request.host = "www.nextangle.com"
end
@@ -1746,7 +1735,7 @@ class RenderingLoggingTest < ActionController::TestCase
@controller.logger = MockLogger.new
get :layout_test
logged = @controller.logger.logged.find_all {|l| l =~ /render/i }
- assert_equal "Rendering template within layouts/standard", logged[0]
- assert_equal "Rendering test/hello_world", logged[1]
+ assert_equal "Rendering test/hello_world", logged[0]
+ assert_equal "Rendering template within layouts/standard", logged[1]
end
end
diff --git a/actionpack/test/controller/rescue_test.rb b/actionpack/test/controller/rescue_test.rb
index 5709f37e05..741b01caa8 100644
--- a/actionpack/test/controller/rescue_test.rb
+++ b/actionpack/test/controller/rescue_test.rb
@@ -141,8 +141,11 @@ end
class RescueControllerTest < ActionController::TestCase
FIXTURE_PUBLIC = "#{File.dirname(__FILE__)}/../fixtures".freeze
- setup :set_all_requests_local
- setup :populate_exception_object
+ def setup
+ super
+ set_all_requests_local
+ populate_exception_object
+ end
def set_all_requests_local
RescueController.consider_all_requests_local = true
@@ -409,7 +412,7 @@ class RescueControllerTest < ActionController::TestCase
def test_rescue_dispatcher_exceptions_without_request_set
@request.env['REQUEST_URI'] = '/no_way'
response = RescueController.call_with_exception(@request.env, ActionController::RoutingError.new("Route not found"))
- assert_kind_of ActionController::Response, response
+ assert_kind_of ActionDispatch::Response, response
assert_equal "no way", response.body
end
diff --git a/actionpack/test/controller/send_file_test.rb b/actionpack/test/controller/send_file_test.rb
index 3d1904fee9..2e14a0a32c 100644
--- a/actionpack/test/controller/send_file_test.rb
+++ b/actionpack/test/controller/send_file_test.rb
@@ -155,7 +155,7 @@ class SendFileTest < ActionController::TestCase
define_method "test_default_send_#{method}_status" do
@controller.options = { :stream => false }
assert_nothing_raised { assert_not_nil process(method) }
- assert_equal ActionController::Base::DEFAULT_RENDER_STATUS_CODE, @response.status
+ assert_equal ActionController::DEFAULT_RENDER_STATUS_CODE, @response.status
end
end
end
diff --git a/actionpack/test/controller/session/cookie_store_test.rb b/actionpack/test/controller/session/cookie_store_test.rb
index 40fcd56846..9b3f9afb0d 100644
--- a/actionpack/test/controller/session/cookie_store_test.rb
+++ b/actionpack/test/controller/session/cookie_store_test.rb
@@ -6,7 +6,8 @@ class CookieStoreTest < ActionController::IntegrationTest
SessionSecret = 'b3c631c314c0bbca50c1b2843150fe33'
DispatcherApp = ActionController::Dispatcher.new
- CookieStoreApp = ActionController::Session::CookieStore.new(DispatcherApp, :key => SessionKey, :secret => SessionSecret)
+ CookieStoreApp = ActionDispatch::Session::CookieStore.new(DispatcherApp,
+ :key => SessionKey, :secret => SessionSecret)
Verifier = ActiveSupport::MessageVerifier.new(SessionSecret, 'SHA1')
@@ -53,41 +54,41 @@ class CookieStoreTest < ActionController::IntegrationTest
def test_raises_argument_error_if_missing_session_key
assert_raise(ArgumentError, nil.inspect) {
- ActionController::Session::CookieStore.new(nil,
+ ActionDispatch::Session::CookieStore.new(nil,
:key => nil, :secret => SessionSecret)
}
assert_raise(ArgumentError, ''.inspect) {
- ActionController::Session::CookieStore.new(nil,
+ ActionDispatch::Session::CookieStore.new(nil,
:key => '', :secret => SessionSecret)
}
end
def test_raises_argument_error_if_missing_secret
assert_raise(ArgumentError, nil.inspect) {
- ActionController::Session::CookieStore.new(nil,
+ ActionDispatch::Session::CookieStore.new(nil,
:key => SessionKey, :secret => nil)
}
assert_raise(ArgumentError, ''.inspect) {
- ActionController::Session::CookieStore.new(nil,
+ ActionDispatch::Session::CookieStore.new(nil,
:key => SessionKey, :secret => '')
}
end
def test_raises_argument_error_if_secret_is_probably_insecure
assert_raise(ArgumentError, "password".inspect) {
- ActionController::Session::CookieStore.new(nil,
+ ActionDispatch::Session::CookieStore.new(nil,
:key => SessionKey, :secret => "password")
}
assert_raise(ArgumentError, "secret".inspect) {
- ActionController::Session::CookieStore.new(nil,
+ ActionDispatch::Session::CookieStore.new(nil,
:key => SessionKey, :secret => "secret")
}
assert_raise(ArgumentError, "12345678901234567890123456789".inspect) {
- ActionController::Session::CookieStore.new(nil,
+ ActionDispatch::Session::CookieStore.new(nil,
:key => SessionKey, :secret => "12345678901234567890123456789")
}
end
@@ -135,7 +136,7 @@ class CookieStoreTest < ActionController::IntegrationTest
def test_close_raises_when_data_overflows
with_test_route_set do
- assert_raise(ActionController::Session::CookieStore::CookieOverflow) {
+ assert_raise(ActionDispatch::Session::CookieStore::CookieOverflow) {
get '/raise_data_overflow'
}
end
@@ -193,6 +194,38 @@ class CookieStoreTest < ActionController::IntegrationTest
end
end
+ def test_session_store_with_expire_after
+ app = ActionDispatch::Session::CookieStore.new(DispatcherApp, :key => SessionKey, :secret => SessionSecret, :expire_after => 5.hours)
+ @integration_session = open_session(app)
+
+ with_test_route_set do
+ # First request accesses the session
+ time = Time.local(2008, 4, 24)
+ Time.stubs(:now).returns(time)
+ expected_expiry = (time + 5.hours).gmtime.strftime("%a, %d-%b-%Y %H:%M:%S GMT")
+
+ cookies[SessionKey] = SignedBar
+
+ get '/set_session_value'
+ assert_response :success
+
+ cookie_body = response.body
+ assert_equal "_myapp_session=#{cookie_body}; path=/; expires=#{expected_expiry}; HttpOnly",
+ headers['Set-Cookie']
+
+ # Second request does not access the session
+ time = Time.local(2008, 4, 25)
+ Time.stubs(:now).returns(time)
+ expected_expiry = (time + 5.hours).gmtime.strftime("%a, %d-%b-%Y %H:%M:%S GMT")
+
+ get '/no_session_access'
+ assert_response :success
+
+ assert_equal "_myapp_session=#{cookie_body}; path=/; expires=#{expected_expiry}; HttpOnly",
+ headers['Set-Cookie']
+ end
+ end
+
private
def with_test_route_set
with_routing do |set|
diff --git a/actionpack/test/controller/session/mem_cache_store_test.rb b/actionpack/test/controller/session/mem_cache_store_test.rb
index 2f80a3c7c2..7561c93e4a 100644
--- a/actionpack/test/controller/session/mem_cache_store_test.rb
+++ b/actionpack/test/controller/session/mem_cache_store_test.rb
@@ -33,7 +33,7 @@ class MemCacheStoreTest < ActionController::IntegrationTest
begin
DispatcherApp = ActionController::Dispatcher.new
- MemCacheStoreApp = ActionController::Session::MemCacheStore.new(
+ MemCacheStoreApp = ActionDispatch::Session::MemCacheStore.new(
DispatcherApp, :key => '_session_id')
diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb
index 3924b282d4..124e259ef6 100644
--- a/actionpack/test/controller/test_test.rb
+++ b/actionpack/test/controller/test_test.rb
@@ -119,6 +119,7 @@ XML
end
def setup
+ super
@controller = TestController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@@ -127,6 +128,7 @@ XML
end
def teardown
+ super
ActionController::Routing::Routes.reload
end
@@ -643,7 +645,7 @@ class CleanBacktraceTest < ActionController::TestCase
end
def test_should_clean_assertion_lines_from_backtrace
- path = File.expand_path("#{File.dirname(__FILE__)}/../../lib/action_controller")
+ path = File.expand_path("#{File.dirname(__FILE__)}/../../lib/action_controller/testing")
exception = ActiveSupport::TestCase::Assertion.new('message')
exception.set_backtrace ["#{path}/abc", "#{path}/assertions/def"]
clean_backtrace { raise exception }
diff --git a/actionpack/test/controller/view_paths_test.rb b/actionpack/test/controller/view_paths_test.rb
index 8ea13fbe98..1539f8f506 100644
--- a/actionpack/test/controller/view_paths_test.rb
+++ b/actionpack/test/controller/view_paths_test.rb
@@ -29,8 +29,8 @@ class ViewLoadPathsTest < ActionController::TestCase
@controller = TestController.new
# Following is needed in order to setup @controller.template object properly
- @controller.send :initialize_template_class, @response
@controller.send :assign_shortcuts, @request, @response
+ @controller.send :initialize_template_class, @response
# Track the last warning.
@old_behavior = ActiveSupport::Deprecation.behavior
@@ -41,7 +41,7 @@ class ViewLoadPathsTest < ActionController::TestCase
def teardown
ActiveSupport::Deprecation.behavior = @old_behavior
end
-
+
def test_template_load_path_was_set_correctly
assert_equal [FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
end
diff --git a/actionpack/test/dispatch/header_test.rb b/actionpack/test/dispatch/header_test.rb
new file mode 100644
index 0000000000..ec6ba494dc
--- /dev/null
+++ b/actionpack/test/dispatch/header_test.rb
@@ -0,0 +1,16 @@
+require 'abstract_unit'
+
+class HeaderTest < ActiveSupport::TestCase
+ def setup
+ @headers = ActionDispatch::Http::Headers.new(
+ "HTTP_CONTENT_TYPE" => "text/plain"
+ )
+ end
+
+ test "content type" do
+ assert_equal "text/plain", @headers["Content-Type"]
+ assert_equal "text/plain", @headers["content-type"]
+ assert_equal "text/plain", @headers["CONTENT_TYPE"]
+ assert_equal "text/plain", @headers["HTTP_CONTENT_TYPE"]
+ end
+end
diff --git a/actionpack/test/controller/middleware_stack_test.rb b/actionpack/test/dispatch/middleware_stack_test.rb
index 918231013a..f4e18308ae 100644
--- a/actionpack/test/controller/middleware_stack_test.rb
+++ b/actionpack/test/dispatch/middleware_stack_test.rb
@@ -6,7 +6,7 @@ class MiddlewareStackTest < ActiveSupport::TestCase
class BazMiddleware; end
def setup
- @stack = ActionController::MiddlewareStack.new
+ @stack = ActionDispatch::MiddlewareStack.new
@stack.use FooMiddleware
@stack.use BarMiddleware
end
diff --git a/actionpack/test/controller/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb
index c7faa621d9..2fdf4819bb 100644
--- a/actionpack/test/controller/mime_type_test.rb
+++ b/actionpack/test/dispatch/mime_type_test.rb
@@ -1,57 +1,60 @@
require 'abstract_unit'
-class MimeTypeTest < Test::Unit::TestCase
- Mime::Type.register "image/png", :png
- Mime::Type.register "application/pdf", :pdf
+class MimeTypeTest < ActiveSupport::TestCase
+ Mime::Type.register "image/png", :png unless defined? Mime::PNG
+ Mime::Type.register "application/pdf", :pdf unless defined? Mime::PDF
- def test_parse_single
+ test "parse single" do
Mime::LOOKUP.keys.each do |mime_type|
assert_equal [Mime::Type.lookup(mime_type)], Mime::Type.parse(mime_type)
end
end
- def test_parse_without_q
+ test "parse without q" do
accept = "text/xml,application/xhtml+xml,text/yaml,application/xml,text/html,image/png,text/plain,application/pdf,*/*"
expect = [Mime::HTML, Mime::XML, Mime::YAML, Mime::PNG, Mime::TEXT, Mime::PDF, Mime::ALL]
assert_equal expect, Mime::Type.parse(accept)
end
- def test_parse_with_q
+ test "parse with q" do
accept = "text/xml,application/xhtml+xml,text/yaml; q=0.3,application/xml,text/html; q=0.8,image/png,text/plain; q=0.5,application/pdf,*/*; q=0.2"
expect = [Mime::HTML, Mime::XML, Mime::PNG, Mime::PDF, Mime::TEXT, Mime::YAML, Mime::ALL]
assert_equal expect, Mime::Type.parse(accept)
end
-
+
# Accept header send with user HTTP_USER_AGENT: Sunrise/0.42j (Windows XP)
- def test_parse_crappy_broken_acceptlines
+ test "parse crappy broken acceptlines" do
accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/*,,*/*;q=0.5"
expect = [Mime::HTML, Mime::XML, "image/*", Mime::TEXT, Mime::ALL]
assert_equal expect, Mime::Type.parse(accept).collect { |c| c.to_s }
end
- # Accept header send with user HTTP_USER_AGENT: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; InfoPath.1)
- def test_parse_crappy_broken_acceptlines2
+ # Accept header send with user HTTP_USER_AGENT: Mozilla/4.0
+ # (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; InfoPath.1)
+ test "parse crappy broken acceptlines2" do
accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, , pronto/1.00.00, sslvpn/1.00.00.00, */*"
expect = ['image/gif', 'image/x-xbitmap', 'image/jpeg','image/pjpeg', 'application/x-shockwave-flash', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint', 'application/msword', 'pronto/1.00.00', 'sslvpn/1.00.00.00', Mime::ALL ]
assert_equal expect, Mime::Type.parse(accept).collect { |c| c.to_s }
end
-
- def test_custom_type
- Mime::Type.register("image/gif", :gif)
- assert_nothing_raised do
- Mime::GIF
- assert_equal Mime::GIF, Mime::SET.last
+
+ test "custom type" do
+ begin
+ Mime::Type.register("image/gif", :gif)
+ assert_nothing_raised do
+ Mime::GIF
+ assert_equal Mime::GIF, Mime::SET.last
+ end
+ ensure
+ Mime.module_eval { remove_const :GIF if const_defined?(:GIF) }
end
- ensure
- Mime.module_eval { remove_const :GIF if const_defined?(:GIF) }
end
-
- def test_type_should_be_equal_to_symbol
+
+ test "type should be equal to symbol" do
assert_equal Mime::HTML, 'application/xhtml+xml'
assert_equal Mime::HTML, :html
end
- def test_type_convenience_methods
+ test "type convenience methods" do
# Don't test Mime::ALL, since it Mime::ALL#html? == true
types = Mime::SET.to_a.map(&:to_sym).uniq - [:all]
@@ -67,12 +70,12 @@ class MimeTypeTest < Test::Unit::TestCase
end
end
- def test_mime_all_is_html
+ test "mime all is html" do
assert Mime::ALL.all?, "Mime::ALL is not all?"
assert Mime::ALL.html?, "Mime::ALL is not html?"
end
- def test_verifiable_mime_types
+ test "verifiable mime types" do
all_types = Mime::SET.to_a.map(&:to_sym)
all_types.uniq!
# Remove custom Mime::Type instances set in other tests, like Mime::GIF and Mime::IPHONE
@@ -82,7 +85,7 @@ class MimeTypeTest < Test::Unit::TestCase
assert unverified.each { |type| assert !Mime.const_get(type.to_s.upcase).verify_request?, "Nonverifiable Mime Type is verified: #{type.inspect}" }
end
- def test_regexp_matcher
+ test "regexp matcher" do
assert Mime::JS =~ "text/javascript"
assert Mime::JS =~ "application/javascript"
assert Mime::JS !~ "text/html"
diff --git a/actionpack/test/controller/rack_test.rb b/actionpack/test/dispatch/rack_test.rb
index 89bf4fdacc..9fad4b22ee 100644
--- a/actionpack/test/controller/rack_test.rb
+++ b/actionpack/test/dispatch/rack_test.rb
@@ -1,6 +1,8 @@
require 'abstract_unit'
-class BaseRackTest < Test::Unit::TestCase
+# TODO: Merge these tests into RequestTest
+
+class BaseRackTest < ActiveSupport::TestCase
def setup
@env = {
"HTTP_MAX_FORWARDS" => "10",
@@ -43,30 +45,27 @@ class BaseRackTest < Test::Unit::TestCase
"REDIRECT_STATUS" => "200",
"REQUEST_METHOD" => "GET"
}
- @request = ActionController::Request.new(@env)
+ @request = ActionDispatch::Request.new(@env)
# some Nokia phone browsers omit the space after the semicolon separator.
# some developers have grown accustomed to using comma in cookie values.
- @alt_cookie_fmt_request = ActionController::Request.new(@env.merge({"HTTP_COOKIE"=>"_session_id=c84ace847,96670c052c6ceb2451fb0f2;is_admin=yes"}))
+ @alt_cookie_fmt_request = ActionDispatch::Request.new(@env.merge({"HTTP_COOKIE"=>"_session_id=c84ace847,96670c052c6ceb2451fb0f2;is_admin=yes"}))
end
- def default_test; end
-
private
-
- def set_content_data(data)
- @request.env['REQUEST_METHOD'] = 'POST'
- @request.env['CONTENT_LENGTH'] = data.length
- @request.env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=utf-8'
- @request.env['rack.input'] = StringIO.new(data)
- end
+ def set_content_data(data)
+ @request.env['REQUEST_METHOD'] = 'POST'
+ @request.env['CONTENT_LENGTH'] = data.length
+ @request.env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=utf-8'
+ @request.env['rack.input'] = StringIO.new(data)
+ end
end
class RackRequestTest < BaseRackTest
- def test_proxy_request
+ test "proxy request" do
assert_equal 'glu.ttono.us', @request.host_with_port
end
- def test_http_host
+ test "http host" do
@env.delete "HTTP_X_FORWARDED_HOST"
@env['HTTP_HOST'] = "rubyonrails.org:8080"
assert_equal "rubyonrails.org", @request.host
@@ -76,19 +75,19 @@ class RackRequestTest < BaseRackTest
assert_equal "www.secondhost.org", @request.host
end
- def test_http_host_with_default_port_overrides_server_port
+ test "http host with default port overrides server port" do
@env.delete "HTTP_X_FORWARDED_HOST"
@env['HTTP_HOST'] = "rubyonrails.org"
assert_equal "rubyonrails.org", @request.host_with_port
end
- def test_host_with_port_defaults_to_server_name_if_no_host_headers
+ test "host with port defaults to server name if no host headers" do
@env.delete "HTTP_X_FORWARDED_HOST"
@env.delete "HTTP_HOST"
assert_equal "glu.ttono.us:8007", @request.host_with_port
end
- def test_host_with_port_falls_back_to_server_addr_if_necessary
+ test "host with port falls back to server addr if necessary" do
@env.delete "HTTP_X_FORWARDED_HOST"
@env.delete "HTTP_HOST"
@env.delete "SERVER_NAME"
@@ -97,30 +96,30 @@ class RackRequestTest < BaseRackTest
assert_equal "207.7.108.53:8007", @request.host_with_port
end
- def test_host_with_port_if_http_standard_port_is_specified
+ test "host with port if http standard port is specified" do
@env['HTTP_X_FORWARDED_HOST'] = "glu.ttono.us:80"
assert_equal "glu.ttono.us", @request.host_with_port
end
- def test_host_with_port_if_https_standard_port_is_specified
+ test "host with port if https standard port is specified" do
@env['HTTP_X_FORWARDED_PROTO'] = "https"
@env['HTTP_X_FORWARDED_HOST'] = "glu.ttono.us:443"
assert_equal "glu.ttono.us", @request.host_with_port
end
- def test_host_if_ipv6_reference
+ test "host if ipv6 reference" do
@env.delete "HTTP_X_FORWARDED_HOST"
@env['HTTP_HOST'] = "[2001:1234:5678:9abc:def0::dead:beef]"
assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", @request.host
end
- def test_host_if_ipv6_reference_with_port
+ test "host if ipv6 reference with port" do
@env.delete "HTTP_X_FORWARDED_HOST"
@env['HTTP_HOST'] = "[2001:1234:5678:9abc:def0::dead:beef]:8008"
assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", @request.host
end
- def test_cgi_environment_variables
+ test "cgi environment variables" do
assert_equal "Basic", @request.auth_type
assert_equal 0, @request.content_length
assert_equal nil, @request.content_type
@@ -151,7 +150,7 @@ class RackRequestTest < BaseRackTest
assert_equal "lighttpd", @request.server_software
end
- def test_cookie_syntax_resilience
+ test "cookie syntax resilience" do
cookies = @request.cookies
assert_equal "c84ace84796670c052c6ceb2451fb0f2", cookies["_session_id"], cookies.inspect
assert_equal "yes", cookies["is_admin"], cookies.inspect
@@ -163,39 +162,39 @@ class RackRequestTest < BaseRackTest
end
class RackRequestParamsParsingTest < BaseRackTest
- def test_doesnt_break_when_content_type_has_charset
+ test "doesnt break when content type has charset" do
set_content_data 'flamenco=love'
assert_equal({"flamenco"=> "love"}, @request.request_parameters)
end
- def test_doesnt_interpret_request_uri_as_query_string_when_missing
+ test "doesnt interpret request uri as query string when missing" do
@request.env['REQUEST_URI'] = 'foo'
assert_equal({}, @request.query_parameters)
end
end
class RackRequestContentTypeTest < BaseRackTest
- def test_html_content_type_verification
+ test "html content type verification" do
@request.env['CONTENT_TYPE'] = Mime::HTML.to_s
assert @request.content_type.verify_request?
end
- def test_xml_content_type_verification
+ test "xml content type verification" do
@request.env['CONTENT_TYPE'] = Mime::XML.to_s
assert !@request.content_type.verify_request?
end
end
class RackRequestNeedsRewoundTest < BaseRackTest
- def test_body_should_be_rewound
+ test "body should be rewound" do
data = 'foo'
@env['rack.input'] = StringIO.new(data)
@env['CONTENT_LENGTH'] = data.length
@env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=utf-8'
# Read the request body by parsing params.
- request = ActionController::Request.new(@env)
+ request = ActionDispatch::Request.new(@env)
request.request_parameters
# Should have rewound the body.
@@ -206,10 +205,10 @@ end
class RackResponseTest < BaseRackTest
def setup
super
- @response = ActionController::Response.new
+ @response = ActionDispatch::Response.new
end
- def test_simple_output
+ test "simple output" do
@response.body = "Hello, World!"
@response.prepare!
@@ -266,11 +265,11 @@ end
class RackResponseHeadersTest < BaseRackTest
def setup
super
- @response = ActionController::Response.new
+ @response = ActionDispatch::Response.new
@response.status = "200 OK"
end
- def test_content_type
+ test "content type" do
[204, 304].each do |c|
@response.status = c.to_s
assert !response_headers.has_key?("Content-Type"), "#{c} should not have Content-Type header"
@@ -282,7 +281,7 @@ class RackResponseHeadersTest < BaseRackTest
end
end
- def test_status
+ test "status" do
assert !response_headers.has_key?('Status')
end
diff --git a/actionpack/test/controller/request/json_params_parsing_test.rb b/actionpack/test/dispatch/request/json_params_parsing_test.rb
index a3dde72c4e..a3dde72c4e 100644
--- a/actionpack/test/controller/request/json_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/json_params_parsing_test.rb
diff --git a/actionpack/test/controller/request/multipart_params_parsing_test.rb b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb
index b812072ef4..2f409f020d 100644
--- a/actionpack/test/controller/request/multipart_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb
@@ -215,7 +215,7 @@ class MultipartParamsParsingTest < ActionController::IntegrationTest
def with_muck_middleware
original_middleware = ActionController::Dispatcher.middleware
middleware = original_middleware.dup
- middleware.insert_after ActionController::RewindableInput, MuckMiddleware
+ middleware.insert_after ActionDispatch::RewindableInput, MuckMiddleware
ActionController::Dispatcher.middleware = middleware
yield
ActionController::Dispatcher.middleware = original_middleware
diff --git a/actionpack/test/controller/request/query_string_parsing_test.rb b/actionpack/test/dispatch/request/query_string_parsing_test.rb
index a31e326ddf..a31e326ddf 100644
--- a/actionpack/test/controller/request/query_string_parsing_test.rb
+++ b/actionpack/test/dispatch/request/query_string_parsing_test.rb
diff --git a/actionpack/test/controller/request/url_encoded_params_parsing_test.rb b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb
index 7e6099a041..51a660f614 100644
--- a/actionpack/test/controller/request/url_encoded_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb
@@ -159,7 +159,7 @@ class UrlEncodedParamsParsingTest < ActionController::IntegrationTest
def with_muck_middleware
original_middleware = ActionController::Dispatcher.middleware
middleware = original_middleware.dup
- middleware.insert_after ActionController::RewindableInput, MuckMiddleware
+ middleware.insert_after ActionDispatch::RewindableInput, MuckMiddleware
ActionController::Dispatcher.middleware = middleware
yield
ActionController::Dispatcher.middleware = original_middleware
diff --git a/actionpack/test/controller/request/xml_params_parsing_test.rb b/actionpack/test/dispatch/request/xml_params_parsing_test.rb
index ee764e726e..ee764e726e 100644
--- a/actionpack/test/controller/request/xml_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/xml_params_parsing_test.rb
diff --git a/actionpack/test/controller/request_test.rb b/actionpack/test/dispatch/request_test.rb
index c4cc63e628..d57a2a611f 100644
--- a/actionpack/test/controller/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -9,7 +9,7 @@ class RequestTest < ActiveSupport::TestCase
ActionController::Base.relative_url_root = nil
end
- def test_remote_ip
+ test "remote ip" do
request = stub_request 'REMOTE_ADDR' => '1.2.3.4'
assert_equal '1.2.3.4', request.remote_ip
@@ -72,7 +72,7 @@ class RequestTest < ActiveSupport::TestCase
assert_equal '9.9.9.9', request.remote_ip
end
- def test_domains
+ test "domains" do
request = stub_request 'HTTP_HOST' => 'www.rubyonrails.org'
assert_equal "rubyonrails.org", request.domain
@@ -89,7 +89,7 @@ class RequestTest < ActiveSupport::TestCase
assert_equal "200.com", request.domain
end
- def test_subdomains
+ test "subdomains" do
request = stub_request 'HTTP_HOST' => "www.rubyonrails.org"
assert_equal %w( www ), request.subdomains
@@ -115,7 +115,7 @@ class RequestTest < ActiveSupport::TestCase
assert_equal [], request.subdomains
end
- def test_port_string
+ test "port string" do
request = stub_request 'HTTP_HOST' => 'www.example.org:80'
assert_equal "", request.port_string
@@ -123,7 +123,7 @@ class RequestTest < ActiveSupport::TestCase
assert_equal ":8080", request.port_string
end
- def test_request_uri
+ test "request uri" do
request = stub_request 'REQUEST_URI' => "http://www.rubyonrails.org/path/of/some/uri?mapped=1"
assert_equal "/path/of/some/uri?mapped=1", request.request_uri
assert_equal "/path/of/some/uri", request.path
@@ -223,17 +223,18 @@ class RequestTest < ActiveSupport::TestCase
assert_equal "/some/path", request.path
end
- def test_host_with_default_port
+
+ test "host with default port" do
request = stub_request 'HTTP_HOST' => 'rubyonrails.org:80'
assert_equal "rubyonrails.org", request.host_with_port
end
- def test_host_with_non_default_port
+ test "host with non default port" do
request = stub_request 'HTTP_HOST' => 'rubyonrails.org:81'
assert_equal "rubyonrails.org:81", request.host_with_port
end
- def test_server_software
+ test "server software" do
request = stub_request
assert_equal nil, request.server_software
@@ -244,7 +245,7 @@ class RequestTest < ActiveSupport::TestCase
assert_equal 'lighttpd', request.server_software
end
- def test_xml_http_request
+ test "xml http request" do
request = stub_request
assert !request.xml_http_request?
@@ -259,7 +260,7 @@ class RequestTest < ActiveSupport::TestCase
assert request.xhr?
end
- def test_reports_ssl
+ test "reports ssl" do
request = stub_request
assert !request.ssl?
@@ -267,7 +268,7 @@ class RequestTest < ActiveSupport::TestCase
assert request.ssl?
end
- def test_reports_ssl_when_proxied_via_lighttpd
+ test "reports ssl when proxied via lighttpd" do
request = stub_request
assert !request.ssl?
@@ -275,28 +276,35 @@ class RequestTest < ActiveSupport::TestCase
assert request.ssl?
end
- def test_symbolized_request_methods
+ test "symbolized request methods" do
[:get, :post, :put, :delete].each do |method|
request = stub_request 'REQUEST_METHOD' => method.to_s.upcase
assert_equal method, request.method
end
end
- def test_invalid_http_method_raises_exception
+ test "invalid http method raises exception" do
assert_raise(ActionController::UnknownHttpMethod) do
request = stub_request 'REQUEST_METHOD' => 'RANDOM_METHOD'
request.request_method
end
end
- def test_allow_method_hacking_on_post
+ test "allow method hacking on post" do
[:get, :head, :options, :put, :post, :delete].each do |method|
- request = stub_request 'REQUEST_METHOD' => method.to_s.upcase
+ request = stub_request "REQUEST_METHOD" => method.to_s.upcase
assert_equal(method == :head ? :get : method, request.method)
end
end
- def test_restrict_method_hacking
+ test "invalid method hacking on post raises exception" do
+ assert_raise(ActionController::UnknownHttpMethod) do
+ request = stub_request "REQUEST_METHOD" => "_RANDOM_METHOD"
+ request.request_method
+ end
+ end
+
+ test "restrict method hacking" do
[:get, :put, :delete].each do |method|
request = stub_request 'REQUEST_METHOD' => method.to_s.upcase,
'action_controller.request.request_parameters' => { :_method => 'put' }
@@ -304,49 +312,51 @@ class RequestTest < ActiveSupport::TestCase
end
end
- def test_head_masquerading_as_get
+ test "head masquerading as get" do
request = stub_request 'REQUEST_METHOD' => 'HEAD'
assert_equal :get, request.method
assert request.get?
assert request.head?
end
- def test_xml_format
+ test "xml format" do
request = stub_request
request.expects(:parameters).at_least_once.returns({ :format => 'xml' })
assert_equal Mime::XML, request.format
end
- def test_xhtml_format
+ test "xhtml format" do
request = stub_request
request.expects(:parameters).at_least_once.returns({ :format => 'xhtml' })
assert_equal Mime::HTML, request.format
end
- def test_txt_format
+ test "txt format" do
request = stub_request
request.expects(:parameters).at_least_once.returns({ :format => 'txt' })
assert_equal Mime::TEXT, request.format
end
- def test_xml_http_request
- ActionController::Base.use_accept_header, old =
- false, ActionController::Base.use_accept_header
-
- request = stub_request 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'
- request.expects(:parameters).at_least_once.returns({})
- assert request.xhr?
- assert_equal Mime::JS, request.format
- ensure
- ActionController::Base.use_accept_header = old
+ test "XMLHttpRequest" do
+ begin
+ ActionController::Base.use_accept_header, old =
+ false, ActionController::Base.use_accept_header
+
+ request = stub_request 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'
+ request.expects(:parameters).at_least_once.returns({})
+ assert request.xhr?
+ assert_equal Mime::JS, request.format
+ ensure
+ ActionController::Base.use_accept_header = old
+ end
end
- def test_content_type
+ test "content type" do
request = stub_request 'CONTENT_TYPE' => 'text/html'
assert_equal Mime::HTML, request.content_type
end
- def test_can_override_format_with_parameter
+ test "can override format with parameter" do
request = stub_request
request.expects(:parameters).at_least_once.returns({ :format => :txt })
assert !request.format.xml?
@@ -356,27 +366,27 @@ class RequestTest < ActiveSupport::TestCase
assert request.format.xml?
end
- def test_content_no_type
+ test "no content type" do
request = stub_request
assert_equal nil, request.content_type
end
- def test_content_type_xml
+ test "content type is XML" do
request = stub_request 'CONTENT_TYPE' => 'application/xml'
assert_equal Mime::XML, request.content_type
end
- def test_content_type_with_charset
+ test "content type with charset" do
request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8'
assert_equal Mime::XML, request.content_type
end
- def test_user_agent
+ test "user agent" do
request = stub_request 'HTTP_USER_AGENT' => 'TestAgent'
assert_equal 'TestAgent', request.user_agent
end
- def test_parameters
+ test "parameters" do
request = stub_request
request.stubs(:request_parameters).returns({ "foo" => 1 })
request.stubs(:query_parameters).returns({ "bar" => 2 })
@@ -389,7 +399,7 @@ class RequestTest < ActiveSupport::TestCase
protected
def stub_request(env={})
- ActionController::Request.new(env)
+ ActionDispatch::Request.new(env)
end
end
diff --git a/actionpack/test/fixtures/happy_path/render_action/hello_world.erb b/actionpack/test/fixtures/happy_path/render_action/hello_world.erb
new file mode 100644
index 0000000000..6769dd60bd
--- /dev/null
+++ b/actionpack/test/fixtures/happy_path/render_action/hello_world.erb
@@ -0,0 +1 @@
+Hello world! \ No newline at end of file
diff --git a/actionpack/test/fixtures/layout_tests/views/goodbye.rhtml b/actionpack/test/fixtures/layout_tests/views/goodbye.rhtml
new file mode 100644
index 0000000000..bbccf0913e
--- /dev/null
+++ b/actionpack/test/fixtures/layout_tests/views/goodbye.rhtml
@@ -0,0 +1 @@
+hello.rhtml \ No newline at end of file
diff --git a/actionpack/test/fixtures/layouts/default_html.html.erb b/actionpack/test/fixtures/layouts/default_html.html.erb
deleted file mode 100644
index edd719111c..0000000000
--- a/actionpack/test/fixtures/layouts/default_html.html.erb
+++ /dev/null
@@ -1 +0,0 @@
-<html><%= @content_for_layout %></html>
diff --git a/actionpack/test/fixtures/test/backup_files/item.html.erb b/actionpack/test/fixtures/test/backup_files/item.html.erb
deleted file mode 100644
index aaac0a2160..0000000000
--- a/actionpack/test/fixtures/test/backup_files/item.html.erb
+++ /dev/null
@@ -1 +0,0 @@
-The correct item.erb was loaded.
diff --git a/actionpack/test/fixtures/test/backup_files/item.html.erb.orig b/actionpack/test/fixtures/test/backup_files/item.html.erb.orig
deleted file mode 100644
index a2b153e5a2..0000000000
--- a/actionpack/test/fixtures/test/backup_files/item.html.erb.orig
+++ /dev/null
@@ -1 +0,0 @@
-This is an editor backup file and should never be loaded!
diff --git a/actionpack/test/fixtures/test/basic.html.erb b/actionpack/test/fixtures/test/basic.html.erb
new file mode 100644
index 0000000000..ea696d7e01
--- /dev/null
+++ b/actionpack/test/fixtures/test/basic.html.erb
@@ -0,0 +1 @@
+Hello from basic.html.erb \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/render_implicit_js_template_without_layout.js.erb b/actionpack/test/fixtures/test/render_implicit_js_template_without_layout.js.erb
deleted file mode 100644
index d5b94af505..0000000000
--- a/actionpack/test/fixtures/test/render_implicit_js_template_without_layout.js.erb
+++ /dev/null
@@ -1 +0,0 @@
-alert('hello');
diff --git a/actionpack/test/lib/fixture_template.rb b/actionpack/test/lib/fixture_template.rb
new file mode 100644
index 0000000000..26f6ec2d0c
--- /dev/null
+++ b/actionpack/test/lib/fixture_template.rb
@@ -0,0 +1,35 @@
+module ActionView #:nodoc:
+ class FixtureTemplate < Template
+ class FixturePath < Template::Path
+ def initialize(hash = {})
+ @hash = {}
+
+ hash.each do |k, v|
+ @hash[k.sub(/\.\w+$/, '')] = FixtureTemplate.new(v, k.split("/").last, self)
+ end
+
+ super("fixtures://root")
+ end
+
+ def find_template(path)
+ @hash[path]
+ end
+ end
+
+ def initialize(body, *args)
+ @body = body
+ super(*args)
+ end
+
+ def source
+ @body
+ end
+
+ private
+
+ def find_full_path(path, load_paths)
+ return '/', path
+ end
+
+ end
+end \ No newline at end of file
diff --git a/actionpack/test/new_base/base_test.rb b/actionpack/test/new_base/base_test.rb
new file mode 100644
index 0000000000..4f46cb6492
--- /dev/null
+++ b/actionpack/test/new_base/base_test.rb
@@ -0,0 +1,90 @@
+require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
+
+# Tests the controller dispatching happy path
+module HappyPath
+ class SimpleDispatchController < ActionController::Base2
+ def index
+ render :text => "success"
+ end
+
+ def modify_response_body
+ self.response_body = "success"
+ end
+
+ def modify_response_body_twice
+ ret = (self.response_body = "success")
+ self.response_body = "#{ret}!"
+ end
+
+ def modify_response_headers
+
+ end
+ end
+
+ class TestSimpleDispatch < SimpleRouteCase
+
+ get "/happy_path/simple_dispatch/index"
+
+ test "sets the body" do
+ assert_body "success"
+ end
+
+ test "sets the status code" do
+ assert_status 200
+ end
+
+ test "sets the content type" do
+ assert_content_type Mime::HTML
+ end
+
+ test "sets the content length" do
+ assert_header "Content-Length", 7
+ end
+
+ end
+
+ # :api: plugin
+ class TestDirectResponseMod < SimpleRouteCase
+ get "/happy_path/simple_dispatch/modify_response_body"
+
+ test "sets the body" do
+ assert_body "success"
+ end
+
+ test "setting the body manually sets the content length" do
+ assert_header "Content-Length", 7
+ end
+ end
+
+ # :api: plugin
+ class TestDirectResponseModTwice < SimpleRouteCase
+ get "/happy_path/simple_dispatch/modify_response_body_twice"
+
+ test "self.response_body= returns the body being set" do
+ assert_body "success!"
+ end
+
+ test "updating the response body updates the content length" do
+ assert_header "Content-Length", 8
+ end
+ end
+end
+
+
+class EmptyController < ActionController::Base2 ; end
+module Submodule
+ class ContainedEmptyController < ActionController::Base2 ; end
+end
+
+class ControllerClassTests < Test::Unit::TestCase
+ def test_controller_path
+ assert_equal 'empty', EmptyController.controller_path
+ assert_equal EmptyController.controller_path, EmptyController.new.controller_path
+ assert_equal 'submodule/contained_empty', Submodule::ContainedEmptyController.controller_path
+ assert_equal Submodule::ContainedEmptyController.controller_path, Submodule::ContainedEmptyController.new.controller_path
+ end
+ def test_controller_name
+ assert_equal 'empty', EmptyController.controller_name
+ assert_equal 'contained_empty', Submodule::ContainedEmptyController.controller_name
+ end
+end \ No newline at end of file
diff --git a/actionpack/test/new_base/render_action_test.rb b/actionpack/test/new_base/render_action_test.rb
new file mode 100644
index 0000000000..2bfb374a31
--- /dev/null
+++ b/actionpack/test/new_base/render_action_test.rb
@@ -0,0 +1,325 @@
+require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
+
+module RenderAction
+
+ # This has no layout and it works
+ class BasicController < ActionController::Base2
+
+ self.view_paths = [ActionView::FixtureTemplate::FixturePath.new(
+ "render_action/basic/hello_world.html.erb" => "Hello world!"
+ )]
+
+ def hello_world
+ render :action => "hello_world"
+ end
+
+ def hello_world_as_string
+ render "hello_world"
+ end
+
+ def hello_world_as_string_with_options
+ render "hello_world", :status => 404
+ end
+
+ def hello_world_as_symbol
+ render :hello_world
+ end
+
+ def hello_world_with_symbol
+ render :action => :hello_world
+ end
+
+ def hello_world_with_layout
+ render :action => "hello_world", :layout => true
+ end
+
+ def hello_world_with_layout_false
+ render :action => "hello_world", :layout => false
+ end
+
+ def hello_world_with_layout_nil
+ render :action => "hello_world", :layout => nil
+ end
+
+ def hello_world_with_custom_layout
+ render :action => "hello_world", :layout => "greetings"
+ end
+
+ end
+
+ class TestBasic < SimpleRouteCase
+ describe "Rendering an action using :action => <String>"
+
+ get "/render_action/basic/hello_world"
+ assert_body "Hello world!"
+ assert_status 200
+ end
+
+ class TestWithString < SimpleRouteCase
+ describe "Render an action using 'hello_world'"
+
+ get "/render_action/basic/hello_world_as_string"
+ assert_body "Hello world!"
+ assert_status 200
+ end
+
+ class TestWithStringAndOptions < SimpleRouteCase
+ describe "Render an action using 'hello_world'"
+
+ get "/render_action/basic/hello_world_as_string_with_options"
+ assert_body "Hello world!"
+ assert_status 404
+ end
+
+ class TestAsSymbol < SimpleRouteCase
+ describe "Render an action using :hello_world"
+
+ get "/render_action/basic/hello_world_as_symbol"
+ assert_body "Hello world!"
+ assert_status 200
+ end
+
+ class TestWithSymbol < SimpleRouteCase
+ describe "Render an action using :action => :hello_world"
+
+ get "/render_action/basic/hello_world_with_symbol"
+ assert_body "Hello world!"
+ assert_status 200
+ end
+
+ class TestLayoutTrue < SimpleRouteCase
+ describe "rendering a normal template with full path with layout => true"
+
+ test "raises an exception when requesting a layout and none exist" do
+ assert_raise(ArgumentError, /no default layout for RenderAction::BasicController in/) do
+ get "/render_action/basic/hello_world_with_layout"
+ end
+ end
+ end
+
+ class TestLayoutFalse < SimpleRouteCase
+ describe "rendering a normal template with full path with layout => false"
+
+ get "/render_action/basic/hello_world_with_layout_false"
+ assert_body "Hello world!"
+ assert_status 200
+ end
+
+ class TestLayoutNil < SimpleRouteCase
+ describe "rendering a normal template with full path with layout => :nil"
+
+ get "/render_action/basic/hello_world_with_layout_nil"
+ assert_body "Hello world!"
+ assert_status 200
+ end
+
+ class TestCustomLayout < SimpleRouteCase
+ describe "rendering a normal template with full path with layout => 'greetings'"
+
+ test "raises an exception when requesting a layout that does not exist" do
+ assert_raise(ActionView::MissingTemplate) { get "/render_action/basic/hello_world_with_custom_layout" }
+ end
+ end
+
+end
+
+module RenderActionWithApplicationLayout
+
+ # # ==== Render actions with layouts ====
+
+ class BasicController < ::ApplicationController
+ # Set the view path to an application view structure with layouts
+ self.view_paths = self.view_paths = [ActionView::FixtureTemplate::FixturePath.new(
+ "render_action_with_application_layout/basic/hello_world.html.erb" => "Hello World!",
+ "layouts/application.html.erb" => "OHAI <%= yield %> KTHXBAI",
+ "layouts/greetings.html.erb" => "Greetings <%= yield %> Bai"
+ )]
+
+ def hello_world
+ render :action => "hello_world"
+ end
+
+ def hello_world_with_layout
+ render :action => "hello_world", :layout => true
+ end
+
+ def hello_world_with_layout_false
+ render :action => "hello_world", :layout => false
+ end
+
+ def hello_world_with_layout_nil
+ render :action => "hello_world", :layout => nil
+ end
+
+ def hello_world_with_custom_layout
+ render :action => "hello_world", :layout => "greetings"
+ end
+ end
+
+ class TestDefaultLayout < SimpleRouteCase
+ describe %(
+ Render hello_world and implicitly use application.html.erb as a layout if
+ no layout is specified and no controller layout is present
+ )
+
+ get "/render_action_with_application_layout/basic/hello_world"
+ assert_body "OHAI Hello World! KTHXBAI"
+ assert_status 200
+ end
+
+ class TestLayoutTrue < SimpleRouteCase
+ describe "rendering a normal template with full path with layout => true"
+
+ get "/render_action_with_application_layout/basic/hello_world_with_layout"
+ assert_body "OHAI Hello World! KTHXBAI"
+ assert_status 200
+ end
+
+ class TestLayoutFalse < SimpleRouteCase
+ describe "rendering a normal template with full path with layout => false"
+
+ get "/render_action_with_application_layout/basic/hello_world_with_layout_false"
+ assert_body "Hello World!"
+ assert_status 200
+ end
+
+ class TestLayoutNil < SimpleRouteCase
+ describe "rendering a normal template with full path with layout => :nil"
+
+ get "/render_action_with_application_layout/basic/hello_world_with_layout_nil"
+ assert_body "Hello World!"
+ assert_status 200
+ end
+
+ class TestCustomLayout < SimpleRouteCase
+ describe "rendering a normal template with full path with layout => 'greetings'"
+
+ get "/render_action_with_application_layout/basic/hello_world_with_custom_layout"
+ assert_body "Greetings Hello World! Bai"
+ assert_status 200
+ end
+
+end
+
+module RenderActionWithControllerLayout
+
+ class BasicController < ActionController::Base2
+ self.view_paths = self.view_paths = [ActionView::FixtureTemplate::FixturePath.new(
+ "render_action_with_controller_layout/basic/hello_world.html.erb" => "Hello World!",
+ "layouts/render_action_with_controller_layout/basic.html.erb" => "With Controller Layout! <%= yield %> KTHXBAI"
+ )]
+
+ def hello_world
+ render :action => "hello_world"
+ end
+
+ def hello_world_with_layout
+ render :action => "hello_world", :layout => true
+ end
+
+ def hello_world_with_layout_false
+ render :action => "hello_world", :layout => false
+ end
+
+ def hello_world_with_layout_nil
+ render :action => "hello_world", :layout => nil
+ end
+
+ def hello_world_with_custom_layout
+ render :action => "hello_world", :layout => "greetings"
+ end
+ end
+
+ class TestControllerLayout < SimpleRouteCase
+ describe "Render hello_world and implicitly use <controller_path>.html.erb as a layout."
+
+ get "/render_action_with_controller_layout/basic/hello_world"
+ assert_body "With Controller Layout! Hello World! KTHXBAI"
+ assert_status 200
+ end
+
+ class TestLayoutTrue < SimpleRouteCase
+ describe "rendering a normal template with full path with layout => true"
+
+ get "/render_action_with_controller_layout/basic/hello_world_with_layout"
+ assert_body "With Controller Layout! Hello World! KTHXBAI"
+ assert_status 200
+ end
+
+ class TestLayoutFalse < SimpleRouteCase
+ describe "rendering a normal template with full path with layout => false"
+
+ get "/render_action_with_controller_layout/basic/hello_world_with_layout_false"
+ assert_body "Hello World!"
+ assert_status 200
+ end
+
+ class TestLayoutNil < SimpleRouteCase
+ describe "rendering a normal template with full path with layout => :nil"
+
+ get "/render_action_with_controller_layout/basic/hello_world_with_layout_nil"
+ assert_body "Hello World!"
+ assert_status 200
+ end
+
+end
+
+module RenderActionWithBothLayouts
+
+ class BasicController < ActionController::Base2
+ self.view_paths = [ActionView::FixtureTemplate::FixturePath.new({
+ "render_action_with_both_layouts/basic/hello_world.html.erb" => "Hello World!",
+ "layouts/application.html.erb" => "OHAI <%= yield %> KTHXBAI",
+ "layouts/render_action_with_both_layouts/basic.html.erb" => "With Controller Layout! <%= yield %> KTHXBAI"
+ })]
+
+ def hello_world
+ render :action => "hello_world"
+ end
+
+ def hello_world_with_layout
+ render :action => "hello_world", :layout => true
+ end
+
+ def hello_world_with_layout_false
+ render :action => "hello_world", :layout => false
+ end
+
+ def hello_world_with_layout_nil
+ render :action => "hello_world", :layout => nil
+ end
+ end
+
+ class TestControllerLayoutFirst < SimpleRouteCase
+ describe "Render hello_world and implicitly use <controller_path>.html.erb over application.html.erb as a layout"
+
+ get "/render_action_with_both_layouts/basic/hello_world"
+ assert_body "With Controller Layout! Hello World! KTHXBAI"
+ assert_status 200
+ end
+
+ class TestLayoutTrue < SimpleRouteCase
+ describe "rendering a normal template with full path with layout => true"
+
+ get "/render_action_with_both_layouts/basic/hello_world_with_layout"
+ assert_body "With Controller Layout! Hello World! KTHXBAI"
+ assert_status 200
+ end
+
+ class TestLayoutFalse < SimpleRouteCase
+ describe "rendering a normal template with full path with layout => false"
+
+ get "/render_action_with_both_layouts/basic/hello_world_with_layout_false"
+ assert_body "Hello World!"
+ assert_status 200
+ end
+
+ class TestLayoutNil < SimpleRouteCase
+ describe "rendering a normal template with full path with layout => :nil"
+
+ get "/render_action_with_both_layouts/basic/hello_world_with_layout_nil"
+ assert_body "Hello World!"
+ assert_status 200
+ end
+
+end \ No newline at end of file
diff --git a/actionpack/test/new_base/render_implicit_action_test.rb b/actionpack/test/new_base/render_implicit_action_test.rb
new file mode 100644
index 0000000000..798505b539
--- /dev/null
+++ b/actionpack/test/new_base/render_implicit_action_test.rb
@@ -0,0 +1,16 @@
+require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
+
+module HappyPath
+
+ class RenderImplicitActionController < ActionController::Base2
+ # No actions yet, they are implicit
+ end
+
+ class TestRendersActionImplicitly < SimpleRouteCase
+
+ test "renders action implicitly" do
+ assert true
+ end
+
+ end
+end \ No newline at end of file
diff --git a/actionpack/test/new_base/render_layout_test.rb b/actionpack/test/new_base/render_layout_test.rb
new file mode 100644
index 0000000000..facf67ea85
--- /dev/null
+++ b/actionpack/test/new_base/render_layout_test.rb
@@ -0,0 +1,45 @@
+require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
+
+module ControllerLayouts
+ class ImplicitController < ::ApplicationController
+
+ self.view_paths = [ActionView::FixtureTemplate::FixturePath.new(
+ "layouts/application.html.erb" => "OMG <%= yield %> KTHXBAI",
+ "basic.html.erb" => "Hello world!"
+ )]
+
+ def index
+ render :template => "basic"
+ end
+ end
+
+ class TestImplicitLayout < SimpleRouteCase
+ describe "rendering a normal template, but using the implicit layout"
+
+ get "/controller_layouts/implicit/index"
+ assert_body "OMG Hello world! KTHXBAI"
+ assert_status 200
+ end
+
+ class ImplicitNameController < ::ApplicationController
+
+ self.view_paths = [ActionView::FixtureTemplate::FixturePath.new(
+ "layouts/controller_layouts/implicit_name.html.erb" => "OMGIMPLICIT <%= yield %> KTHXBAI",
+ "basic.html.erb" => "Hello world!"
+ )]
+
+ def index
+ render :template => "basic"
+ end
+ end
+
+ class TestImplicitNamedLayout < SimpleRouteCase
+ describe "rendering a normal template, but using an implicit NAMED layout"
+
+ get "/controller_layouts/implicit_name/index"
+ assert_body "OMGIMPLICIT Hello world! KTHXBAI"
+ assert_status 200
+ end
+
+
+end \ No newline at end of file
diff --git a/actionpack/test/new_base/render_template_test.rb b/actionpack/test/new_base/render_template_test.rb
new file mode 100644
index 0000000000..c6c0269b40
--- /dev/null
+++ b/actionpack/test/new_base/render_template_test.rb
@@ -0,0 +1,133 @@
+require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
+
+module HappyPath
+
+ class RenderTemplateWithoutLayoutController < ActionController::Base2
+
+ self.view_paths = [ActionView::FixtureTemplate::FixturePath.new(
+ "test/basic.html.erb" => "Hello from basic.html.erb",
+ "shared.html.erb" => "Elastica"
+ )]
+
+ def render_hello_world
+ render :template => "test/basic"
+ end
+
+ def render_hello_world_with_forward_slash
+ render :template => "/test/basic"
+ end
+
+ def render_template_in_top_directory
+ render :template => 'shared'
+ end
+
+ def render_template_in_top_directory_with_slash
+ render :template => '/shared'
+ end
+ end
+
+ class TestTemplateRenderWithoutLayout < SimpleRouteCase
+ describe "rendering a normal template with full path without layout"
+
+ get "/happy_path/render_template_without_layout/render_hello_world"
+ assert_body "Hello from basic.html.erb"
+ assert_status 200
+ end
+
+ class TestTemplateRenderWithForwardSlash < SimpleRouteCase
+ describe "rendering a normal template with full path starting with a leading slash"
+
+ get "/happy_path/render_template_without_layout/render_hello_world_with_forward_slash"
+ assert_body "Hello from basic.html.erb"
+ assert_status 200
+ end
+
+ class TestTemplateRenderInTopDirectory < SimpleRouteCase
+ describe "rendering a template not in a subdirectory"
+
+ get "/happy_path/render_template_without_layout/render_template_in_top_directory"
+ assert_body "Elastica"
+ assert_status 200
+ end
+
+ class TestTemplateRenderInTopDirectoryWithSlash < SimpleRouteCase
+ describe "rendering a template not in a subdirectory with a leading slash"
+
+ get "/happy_path/render_template_without_layout/render_template_in_top_directory_with_slash"
+ assert_body "Elastica"
+ assert_status 200
+ end
+
+ class RenderTemplateWithLayoutController < ::ApplicationController
+
+ self.view_paths = [ActionView::FixtureTemplate::FixturePath.new(
+ "test/basic.html.erb" => "Hello from basic.html.erb",
+ "shared.html.erb" => "Elastica",
+ "layouts/application.html.erb" => "<%= yield %>, I'm here!",
+ "layouts/greetings.html.erb" => "<%= yield %>, I wish thee well."
+ )]
+
+ def render_hello_world
+ render :template => "test/basic"
+ end
+
+ def render_hello_world_with_layout
+ render :template => "test/basic", :layout => true
+ end
+
+ def render_hello_world_with_layout_false
+ render :template => "test/basic", :layout => false
+ end
+
+ def render_hello_world_with_layout_nil
+ render :template => "test/basic", :layout => nil
+ end
+
+ def render_hello_world_with_custom_layout
+ render :template => "test/basic", :layout => "greetings"
+ end
+ end
+
+ class TestTemplateRenderWithLayout < SimpleRouteCase
+ describe "rendering a normal template with full path with layout"
+
+ get "/happy_path/render_template_with_layout/render_hello_world"
+ assert_body "Hello from basic.html.erb, I'm here!"
+ assert_status 200
+ end
+
+ class TestTemplateRenderWithLayoutTrue < SimpleRouteCase
+ describe "rendering a normal template with full path with layout => :true"
+
+ get "/happy_path/render_template_with_layout/render_hello_world_with_layout"
+ assert_body "Hello from basic.html.erb, I'm here!"
+ assert_status 200
+ end
+
+ class TestTemplateRenderWithLayoutFalse < SimpleRouteCase
+ describe "rendering a normal template with full path with layout => :false"
+
+ get "/happy_path/render_template_with_layout/render_hello_world_with_layout_false"
+ assert_body "Hello from basic.html.erb"
+ assert_status 200
+ end
+
+ class TestTemplateRenderWithLayoutNil < SimpleRouteCase
+ describe "rendering a normal template with full path with layout => :nil"
+
+ get "/happy_path/render_template_with_layout/render_hello_world_with_layout_nil"
+ assert_body "Hello from basic.html.erb"
+ assert_status 200
+ end
+
+ class TestTemplateRenderWithCustomLayout < SimpleRouteCase
+ describe "rendering a normal template with full path with layout => 'greetings'"
+
+ get "/happy_path/render_template_with_layout/render_hello_world_with_custom_layout"
+ assert_body "Hello from basic.html.erb, I wish thee well."
+ assert_status 200
+ end
+
+
+
+end \ No newline at end of file
diff --git a/actionpack/test/new_base/render_text_test.rb b/actionpack/test/new_base/render_text_test.rb
new file mode 100644
index 0000000000..a20ca5fb8c
--- /dev/null
+++ b/actionpack/test/new_base/render_text_test.rb
@@ -0,0 +1,144 @@
+require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
+
+class ApplicationController < ActionController::Base2
+end
+
+module HappyPath
+
+ class RenderTextWithoutLayoutsController < ActionController::Base2
+ self.view_paths = [ActionView::FixtureTemplate::FixturePath.new]
+
+ def render_hello_world
+ render :text => "hello david"
+ end
+ end
+
+ class RenderTextWithLayoutsController < ::ApplicationController
+ self.view_paths = [ActionView::FixtureTemplate::FixturePath.new(
+ "layouts/application.html.erb" => "<%= yield %>, I'm here!",
+ "layouts/greetings.html.erb" => "<%= yield %>, I wish thee well."
+ )]
+
+ def render_hello_world
+ render :text => "hello david"
+ end
+
+ def render_custom_code
+ render :text => "hello world", :status => 404
+ end
+
+ def render_with_custom_code_as_string
+ render :text => "hello world", :status => "404 Not Found"
+ end
+
+ def render_text_with_nil
+ render :text => nil
+ end
+
+ def render_text_with_nil_and_status
+ render :text => nil, :status => 403
+ end
+
+ def render_text_with_false
+ render :text => false
+ end
+
+ def render_text_with_layout
+ render :text => "hello world", :layout => true
+ end
+
+ def render_text_with_layout_false
+ render :text => "hello world", :layout => false
+ end
+
+ def render_text_with_layout_nil
+ render :text => "hello world", :layout => nil
+ end
+
+ def render_text_with_custom_layout
+ render :text => "hello world", :layout => "greetings"
+ end
+ end
+
+ class TestSimpleTextRenderWithNoLayout < SimpleRouteCase
+ describe "Rendering text from a action with default options renders the text with the layout"
+
+ get "/happy_path/render_text_without_layouts/render_hello_world"
+ assert_body "hello david"
+ assert_status 200
+ end
+
+ class TestSimpleTextRenderWithLayout < SimpleRouteCase
+ describe "Rendering text from a action with default options renders the text without the layout"
+
+ get "/happy_path/render_text_with_layouts/render_hello_world"
+ assert_body "hello david"
+ assert_status 200
+ end
+
+ class TestTextRenderWithStatus < SimpleRouteCase
+ describe "Rendering text, while also providing a custom status code"
+
+ get "/happy_path/render_text_with_layouts/render_custom_code"
+ assert_body "hello world"
+ assert_status 404
+ end
+
+ class TestTextRenderWithNil < SimpleRouteCase
+ describe "Rendering text with nil returns a single space character"
+
+ get "/happy_path/render_text_with_layouts/render_text_with_nil"
+ assert_body " "
+ assert_status 200
+ end
+
+ class TestTextRenderWithNilAndStatus < SimpleRouteCase
+ describe "Rendering text with nil and custom status code returns a single space character with the status"
+
+ get "/happy_path/render_text_with_layouts/render_text_with_nil_and_status"
+ assert_body " "
+ assert_status 403
+ end
+
+ class TestTextRenderWithFalse < SimpleRouteCase
+ describe "Rendering text with false returns the string 'false'"
+
+ get "/happy_path/render_text_with_layouts/render_text_with_false"
+ assert_body "false"
+ assert_status 200
+ end
+
+ class TestTextRenderWithLayoutTrue < SimpleRouteCase
+ describe "Rendering text with :layout => true"
+
+ get "/happy_path/render_text_with_layouts/render_text_with_layout"
+ assert_body "hello world, I'm here!"
+ assert_status 200
+ end
+
+ class TestTextRenderWithCustomLayout < SimpleRouteCase
+ describe "Rendering text with :layout => 'greetings'"
+
+ get "/happy_path/render_text_with_layouts/render_text_with_custom_layout"
+ assert_body "hello world, I wish thee well."
+ assert_status 200
+ end
+
+ class TestTextRenderWithLayoutFalse < SimpleRouteCase
+ describe "Rendering text with :layout => false"
+
+ get "/happy_path/render_text_with_layouts/render_text_with_layout_false"
+ assert_body "hello world"
+ assert_status 200
+ end
+
+ class TestTextRenderWithLayoutNil < SimpleRouteCase
+ describe "Rendering text with :layout => nil"
+
+ get "/happy_path/render_text_with_layouts/render_text_with_layout_nil"
+ assert_body "hello world"
+ assert_status 200
+ end
+end
+
+ActionController::Base2.app_loaded! \ No newline at end of file
diff --git a/actionpack/test/new_base/test_helper.rb b/actionpack/test/new_base/test_helper.rb
new file mode 100644
index 0000000000..d29449ddc1
--- /dev/null
+++ b/actionpack/test/new_base/test_helper.rb
@@ -0,0 +1,144 @@
+$:.unshift(File.dirname(__FILE__) + '/../../lib')
+$:.unshift(File.dirname(__FILE__) + '/../../../activesupport/lib')
+$:.unshift(File.dirname(__FILE__) + '/../lib')
+
+require 'test/unit'
+require 'active_support'
+require 'active_support/test_case'
+require 'action_controller'
+require 'action_view/base'
+require 'fixture_template'
+
+begin
+ require 'ruby-debug'
+ Debugger.settings[:autoeval] = true
+ Debugger.start
+rescue LoadError
+ # Debugging disabled. `gem install ruby-debug` to enable.
+end
+
+require 'action_controller/abstract'
+require 'action_controller/new_base'
+require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late
+
+require 'rubygems'
+require 'rack/test'
+
+module ActionController
+ class Base2 < AbstractBase
+ use AbstractController::Callbacks
+ use AbstractController::Helpers
+ use AbstractController::Logger
+
+ use ActionController::HideActions
+ use ActionController::UrlFor
+ use ActionController::Renderer
+ use ActionController::Layouts
+
+ def self.inherited(klass)
+ ::ActionController::Base2.subclasses << klass.to_s
+ super
+ end
+
+ def self.subclasses
+ @subclasses ||= []
+ end
+
+ def self.app_loaded!
+ @subclasses.each do |subclass|
+ subclass.constantize._write_layout_method
+ end
+ end
+
+ # append_view_path File.join(File.dirname(__FILE__), '..', 'fixtures')
+
+ CORE_METHODS = self.public_instance_methods
+ end
+end
+
+# Temporary base class
+class Rack::TestCase < ActiveSupport::TestCase
+ include Rack::Test::Methods
+
+ setup do
+ ActionController::Base.session_options[:key] = "abc"
+ ActionController::Base.session_options[:secret] = ("*" * 30)
+
+ controllers = ActionController::Base2.subclasses.map do |k|
+ k.underscore.sub(/_controller$/, '')
+ end
+
+ ActionController::Routing.use_controllers!(controllers)
+
+ # Move into a bootloader
+ AbstractController::Base.subclasses.each do |klass|
+ klass = klass.constantize
+ next unless klass < AbstractController::Layouts
+ klass.class_eval do
+ _write_layout_method
+ end
+ end
+ end
+
+ def app
+ @app ||= ActionController::Dispatcher.new
+ end
+
+ def self.get(url)
+ setup do |test|
+ test.get url
+ end
+ end
+
+ def assert_body(body)
+ assert_equal [body], last_response.body
+ end
+
+ def self.assert_body(body)
+ test "body is set to '#{body}'" do
+ assert_body body
+ end
+ end
+
+ def assert_status(code)
+ assert_equal code, last_response.status
+ end
+
+ def self.assert_status(code)
+ test "status code is set to #{code}" do
+ assert_status code
+ end
+ end
+
+ def assert_content_type(type)
+ assert_equal type, last_response.headers["Content-Type"]
+ end
+
+ def self.assert_content_type(type)
+ test "content type is set to #{type}" do
+ assert_content_type(type)
+ end
+ end
+
+ def assert_header(name, value)
+ assert_equal value, last_response.headers[name]
+ end
+
+ def self.assert_header(name, value)
+ test "'#{name}' header is set to #{value.inspect}" do
+ assert_header(name, value)
+ end
+ end
+
+end
+
+class ::ApplicationController < ActionController::Base2
+end
+
+class SimpleRouteCase < Rack::TestCase
+ setup do
+ ActionController::Routing::Routes.draw do |map|
+ map.connect ':controller/:action/:id'
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/test/runner b/actionpack/test/runner
new file mode 100755
index 0000000000..c2bbe63c75
--- /dev/null
+++ b/actionpack/test/runner
@@ -0,0 +1,8 @@
+#!/usr/bin/env ruby
+
+
+ARGV.each do |arg|
+ Dir["#{Dir.pwd}/#{arg}/**/*_test.rb"].each do |file|
+ require file
+ end
+end \ 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 83c028b5f2..b4b8cbe074 100644
--- a/actionpack/test/template/active_record_helper_test.rb
+++ b/actionpack/test/template/active_record_helper_test.rb
@@ -112,6 +112,7 @@ class ActiveRecordHelperTest < ActionView::TestCase
attr_accessor :request_forgery_protection_token, :form_authenticity_token
def setup
+ super
setup_post
setup_user
diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb
index 32ad87c12d..76ceff8d6c 100644
--- a/actionpack/test/template/asset_tag_helper_test.rb
+++ b/actionpack/test/template/asset_tag_helper_test.rb
@@ -4,6 +4,7 @@ class AssetTagHelperTest < ActionView::TestCase
tests ActionView::Helpers::AssetTagHelper
def setup
+ super
silence_warnings do
ActionView::Helpers::AssetTagHelper.send(
:const_set,
@@ -627,6 +628,7 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase
tests ActionView::Helpers::AssetTagHelper
def setup
+ super
ActionController::Base.relative_url_root = "/collaboration/hieraki"
@controller = Class.new do
diff --git a/actionpack/test/template/atom_feed_helper_test.rb b/actionpack/test/template/atom_feed_helper_test.rb
index 8a00a397ca..bd97caf5d7 100644
--- a/actionpack/test/template/atom_feed_helper_test.rb
+++ b/actionpack/test/template/atom_feed_helper_test.rb
@@ -170,6 +170,7 @@ class AtomFeedTest < ActionController::TestCase
tests ScrollsController
def setup
+ super
@request.host = "www.nextangle.com"
end
diff --git a/actionpack/test/template/compiled_templates_test.rb b/actionpack/test/template/compiled_templates_test.rb
index 7d1d7634a8..a7ed13cf57 100644
--- a/actionpack/test/template/compiled_templates_test.rb
+++ b/actionpack/test/template/compiled_templates_test.rb
@@ -2,7 +2,6 @@ require 'abstract_unit'
require 'controller/fake_models'
class CompiledTemplatesTest < Test::Unit::TestCase
-
def setup
@compiled_templates = ActionView::Base::CompiledTemplates
@compiled_templates.instance_methods.each do |m|
@@ -11,193 +10,76 @@ class CompiledTemplatesTest < Test::Unit::TestCase
end
def test_template_gets_compiled
- with_caching(true) do
- assert_equal 0, @compiled_templates.instance_methods.size
- assert_equal "Hello world!", render(:file => "test/hello_world.erb")
- assert_equal 1, @compiled_templates.instance_methods.size
- end
+ assert_equal 0, @compiled_templates.instance_methods.size
+ assert_equal "Hello world!", render(:file => "test/hello_world.erb")
+ assert_equal 1, @compiled_templates.instance_methods.size
end
def test_template_gets_recompiled_when_using_different_keys_in_local_assigns
- with_caching(true) do
- assert_equal 0, @compiled_templates.instance_methods.size
- assert_equal "Hello world!", render(:file => "test/hello_world.erb")
- assert_equal "Hello world!", render(:file => "test/hello_world.erb", :locals => {:foo => "bar"})
- assert_equal 2, @compiled_templates.instance_methods.size
- end
+ assert_equal 0, @compiled_templates.instance_methods.size
+ assert_equal "Hello world!", render(:file => "test/hello_world.erb")
+ assert_equal "Hello world!", render(:file => "test/hello_world.erb", :locals => {:foo => "bar"})
+ assert_equal 2, @compiled_templates.instance_methods.size
end
def test_compiled_template_will_not_be_recompiled_when_rendered_with_identical_local_assigns
- with_caching(true) do
- assert_equal 0, @compiled_templates.instance_methods.size
- assert_equal "Hello world!", render(:file => "test/hello_world.erb")
- ActionView::Template.any_instance.expects(:compile!).never
- assert_equal "Hello world!", render(:file => "test/hello_world.erb")
- end
- end
-
- def test_template_changes_are_not_reflected_with_cached_template_loading
- with_caching(true) do
- with_reloading(false) do
- assert_equal "Hello world!", render(:file => "test/hello_world.erb")
- modify_template "test/hello_world.erb", "Goodbye world!" do
- assert_equal "Hello world!", render(:file => "test/hello_world.erb")
- end
- assert_equal "Hello world!", render(:file => "test/hello_world.erb")
- end
- end
- end
-
- def test_template_changes_are_reflected_without_cached_template_loading
- with_caching(true) do
- with_reloading(true) do
- assert_equal "Hello world!", render(:file => "test/hello_world.erb")
- modify_template "test/hello_world.erb", "Goodbye world!" do
- assert_equal "Goodbye world!", render(:file => "test/hello_world.erb")
- end
- assert_equal "Hello world!", render(:file => "test/hello_world.erb")
- end
- end
+ assert_equal 0, @compiled_templates.instance_methods.size
+ assert_equal "Hello world!", render(:file => "test/hello_world.erb")
+ ActionView::Template.any_instance.expects(:compile!).never
+ assert_equal "Hello world!", render(:file => "test/hello_world.erb")
end
- def test_template_becomes_missing_if_deleted_without_cached_template_loading
- with_reloading(true) do
- assert_equal 'Hello world!', render(:file => 'test/hello_world.erb')
- delete_template 'test/hello_world.erb' do
- assert_raise(ActionView::MissingTemplate) { render(:file => 'test/hello_world.erb') }
- end
- assert_equal 'Hello world!', render(:file => 'test/hello_world.erb')
- end
- end
-
- def test_swapping_template_handler_is_working_without_cached_template_loading
- with_reloading(true) do
- assert_equal 'Hello world!', render(:file => 'test/hello_world')
- delete_template 'test/hello_world.erb' do
- rename_template 'test/hello_world_from_rxml.builder', 'test/hello_world.builder' do
- assert_equal "<html>\n <p>Hello</p>\n</html>\n", render(:file => 'test/hello_world')
- end
- end
- assert_equal 'Hello world!', render(:file => 'test/hello_world')
- end
+ def test_compiled_template_will_always_be_recompiled_when_template_is_not_cached
+ ActionView::Template.any_instance.expects(:recompile?).times(3).returns(true)
+ assert_equal 0, @compiled_templates.instance_methods.size
+ assert_equal "Hello world!", render(:file => "#{FIXTURE_LOAD_PATH}/test/hello_world.erb")
+ ActionView::Template.any_instance.expects(:compile!).times(3)
+ 3.times { assert_equal "Hello world!", render(:file => "#{FIXTURE_LOAD_PATH}/test/hello_world.erb") }
+ assert_equal 1, @compiled_templates.instance_methods.size
end
- def test_adding_localized_template_will_take_precedence_without_cached_template_loading
- with_reloading(true) do
- assert_equal 'Hello world!', render(:file => 'test/hello_world')
- rename_template 'test/hello_world.da.html.erb', 'test/hello_world.en.html.erb' do
- assert_equal 'Hey verden', render(:file => 'test/hello_world')
- end
+ def test_template_changes_are_not_reflected_with_cached_templates
+ assert_equal "Hello world!", render(:file => "test/hello_world.erb")
+ modify_template "test/hello_world.erb", "Goodbye world!" do
+ assert_equal "Hello world!", render(:file => "test/hello_world.erb")
end
+ assert_equal "Hello world!", render(:file => "test/hello_world.erb")
end
- def test_deleting_localized_template_will_fall_back_to_non_localized_template_without_cached_template_loading
- with_reloading(true) do
- rename_template 'test/hello_world.da.html.erb', 'test/hello_world.en.html.erb' do
- assert_equal 'Hey verden', render(:file => 'test/hello_world')
- delete_template 'test/hello_world.en.html.erb' do
- assert_equal 'Hello world!', render(:file => 'test/hello_world')
- end
- assert_equal 'Hey verden', render(:file => 'test/hello_world')
- end
- end
- end
-
- def test_parallel_reloadable_view_paths_are_working
- with_reloading(true) do
- view_paths_copy = new_reloadable_view_paths
- assert_equal 'Hello world!', render(:file => 'test/hello_world')
- with_view_paths(view_paths_copy, new_reloadable_view_paths) do
- assert_equal 'Hello world!', render(:file => 'test/hello_world')
- end
- modify_template 'test/hello_world.erb', 'Goodbye world!' do
- assert_equal 'Goodbye world!', render(:file => 'test/hello_world')
- modify_template 'test/hello_world.erb', 'So long, world!' do
- with_view_paths(view_paths_copy, new_reloadable_view_paths) do
- assert_equal 'So long, world!', render(:file => 'test/hello_world')
- end
- assert_equal 'So long, world!', render(:file => 'test/hello_world')
- end
- end
+ def test_template_changes_are_reflected_with_uncached_templates
+ assert_equal "Hello world!", render_without_cache(:file => "test/hello_world.erb")
+ modify_template "test/hello_world.erb", "Goodbye world!" do
+ assert_equal "Goodbye world!", render_without_cache(:file => "test/hello_world.erb")
end
+ assert_equal "Hello world!", render_without_cache(:file => "test/hello_world.erb")
end
private
def render(*args)
- view_paths = @explicit_view_paths || ActionController::Base.view_paths
- ActionView::Base.new(view_paths, {}).render(*args)
+ render_with_cache(*args)
end
- def with_view_paths(*args)
- args.each do |view_paths|
- begin
- @explicit_view_paths = view_paths
- yield
- ensure
- @explicit_view_paths = nil
- end
- end
+ def render_with_cache(*args)
+ view_paths = ActionController::Base.view_paths
+ assert_equal ActionView::Template::EagerPath, view_paths.first.class
+ ActionView::Base.new(view_paths, {}).render(*args)
end
- def reset_mtime_of(template_name, view_paths_to_use)
- view_paths_to_use.find_template(template_name).previously_last_modified = 10.seconds.ago unless ActionView::Base.cache_template_loading?
+ def render_without_cache(*args)
+ path = ActionView::Template::Path.new(FIXTURE_LOAD_PATH)
+ view_paths = ActionView::Base.process_view_paths(path)
+ assert_equal ActionView::Template::Path, view_paths.first.class
+ ActionView::Base.new(view_paths, {}).render(*args)
end
- def modify_template(template, content, view_paths_to_use = ActionController::Base.view_paths)
- filename = filename_for(template)
+ def modify_template(template, content)
+ filename = "#{FIXTURE_LOAD_PATH}/#{template}"
old_content = File.read(filename)
begin
File.open(filename, "wb+") { |f| f.write(content) }
- reset_mtime_of(template, view_paths_to_use)
yield
ensure
File.open(filename, "wb+") { |f| f.write(old_content) }
- reset_mtime_of(template, view_paths_to_use)
end
end
-
- def filename_for(template)
- File.join(FIXTURE_LOAD_PATH, template)
- end
-
- def rename_template(old_name, new_name)
- File.rename(filename_for(old_name), filename_for(new_name))
- yield
- ensure
- File.rename(filename_for(new_name), filename_for(old_name))
- end
-
- def delete_template(template, &block)
- rename_template(template, File.join(File.dirname(template), "__#{File.basename(template)}"), &block)
- end
-
- def with_caching(perform_caching)
- old_perform_caching = ActionController::Base.perform_caching
- begin
- ActionController::Base.perform_caching = perform_caching
- yield
- ensure
- ActionController::Base.perform_caching = old_perform_caching
- end
- end
-
- def with_reloading(reload_templates, view_paths_owner = ActionController::Base)
- old_view_paths, old_cache_templates = view_paths_owner.view_paths, ActionView::Base.cache_template_loading
- begin
- ActionView::Base.cache_template_loading = !reload_templates
- view_paths_owner.view_paths = view_paths_for(reload_templates)
- yield
- ensure
- view_paths_owner.view_paths, ActionView::Base.cache_template_loading = old_view_paths, old_cache_templates
- end
- end
-
- def new_reloadable_view_paths
- ActionView::PathSet.new(CACHED_VIEW_PATHS.map(&:to_s))
- end
-
- def view_paths_for(reload_templates)
- # reloadable paths are cheap to create
- reload_templates ? new_reloadable_view_paths : CACHED_VIEW_PATHS
- end
end
diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb
index 654eee40a3..104649deac 100644
--- a/actionpack/test/template/form_helper_test.rb
+++ b/actionpack/test/template/form_helper_test.rb
@@ -45,6 +45,7 @@ class FormHelperTest < ActionView::TestCase
tests ActionView::Helpers::FormHelper
def setup
+ super
@post = Post.new
@comment = Comment.new
def @post.errors()
diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb
index c713b8da8e..ea0be4a27a 100644
--- a/actionpack/test/template/form_tag_helper_test.rb
+++ b/actionpack/test/template/form_tag_helper_test.rb
@@ -4,6 +4,7 @@ class FormTagHelperTest < ActionView::TestCase
tests ActionView::Helpers::FormTagHelper
def setup
+ super
@controller = Class.new do
def url_for(options)
"http://www.example.com"
diff --git a/actionpack/test/template/javascript_helper_test.rb b/actionpack/test/template/javascript_helper_test.rb
index d2fb24e36e..f9bc92c7c9 100644
--- a/actionpack/test/template/javascript_helper_test.rb
+++ b/actionpack/test/template/javascript_helper_test.rb
@@ -3,9 +3,10 @@ require 'abstract_unit'
class JavaScriptHelperTest < ActionView::TestCase
tests ActionView::Helpers::JavaScriptHelper
- attr_accessor :template_format, :output_buffer
+ attr_accessor :formats, :output_buffer
def setup
+ super
@template = self
end
diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb
index d6b86a3964..cd6ee6ea11 100644
--- a/actionpack/test/template/prototype_helper_test.rb
+++ b/actionpack/test/template/prototype_helper_test.rb
@@ -25,9 +25,10 @@ class Author::Nested < Author; end
class PrototypeHelperBaseTest < ActionView::TestCase
- attr_accessor :template_format, :output_buffer
+ attr_accessor :formats, :output_buffer
def setup
+ super
@template = self
@controller = Class.new do
def url_for(options)
diff --git a/actionpack/test/template/record_tag_helper_test.rb b/actionpack/test/template/record_tag_helper_test.rb
index 67aa047745..809ed6d6af 100644
--- a/actionpack/test/template/record_tag_helper_test.rb
+++ b/actionpack/test/template/record_tag_helper_test.rb
@@ -13,6 +13,7 @@ class RecordTagHelperTest < ActionView::TestCase
tests ActionView::Helpers::RecordTagHelper
def setup
+ super
@post = Post.new
end
diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb
index 80fd549fd7..8bad866ce3 100644
--- a/actionpack/test/template/render_test.rb
+++ b/actionpack/test/template/render_test.rb
@@ -29,38 +29,48 @@ module RenderTestCases
end
def test_render_file_with_localization
- old_locale = I18n.locale
- I18n.locale = :da
- assert_equal "Hey verden", @view.render(:file => "test/hello_world")
- ensure
- I18n.locale = old_locale
+ pending do
+ begin
+ old_locale = I18n.locale
+ I18n.locale = :da
+ assert_equal "Hey verden", @view.render(:file => "test/hello_world")
+ ensure
+ I18n.locale = old_locale
+ end
+ end
end
def test_render_file_with_dashed_locale
old_locale = I18n.locale
- I18n.locale = :"pt-BR"
- assert_equal "Ola mundo", @view.render(:file => "test/hello_world")
+ pending do
+ I18n.locale = :"pt-BR"
+ assert_equal "Ola mundo", @view.render(:file => "test/hello_world")
+ end
ensure
I18n.locale = old_locale
end
def test_render_implicit_html_template_from_xhr_request
- old_format = @view.template_format
- @view.template_format = :js
- assert_equal "Hello HTML!", @view.render(:file => "test/render_implicit_html_template_from_xhr_request")
+ old_format = @view.formats
+ pending do
+ @view.formats = [:js]
+ assert_equal "Hello HTML!", @view.render(:file => "test/render_implicit_html_template_from_xhr_request")
+ end
ensure
- @view.template_format = old_format
+ @view.formats = old_format
end
def test_render_implicit_html_template_from_xhr_request_with_localization
old_locale = I18n.locale
- old_format = @view.template_format
- I18n.locale = :da
- @view.template_format = :js
- assert_equal "Hey HTML!\n", @view.render(:file => "test/render_implicit_html_template_from_xhr_request")
+ old_format = @view.formats
+ pending do
+ I18n.locale = :da
+ @view.formats = [:js]
+ assert_equal "Hey HTML!\n", @view.render(:file => "test/render_implicit_html_template_from_xhr_request")
+ end
ensure
I18n.locale = old_locale
- @view.template_format = old_format
+ @view.formats = old_format
end
def test_render_file_at_top_level
@@ -186,7 +196,7 @@ module RenderTestCases
# TODO: The reason for this test is unclear, improve documentation
def test_render_missing_xml_partial_and_raise_missing_template
- @view.template_format = :xml
+ @view.formats = [:xml]
assert_raise(ActionView::MissingTemplate) { @view.render(:partial => "test/layout_for_partial") }
end
@@ -255,42 +265,28 @@ module RenderTestCases
assert_equal Encoding::UTF_8, result.encoding
end
end
-
- def test_render_with_backup_files
- result = @view.render :file => "/test/backup_files/item"
- assert_equal "The correct item.erb was loaded.\n", result
- end
-
end
-module TemplatesSetupTeardown
- def setup_view_paths_for(new_cache_template_loading)
- @previous_cache_template_loading, ActionView::Base.cache_template_loading = ActionView::Base.cache_template_loading, new_cache_template_loading
- view_paths = new_cache_template_loading ? CACHED_VIEW_PATHS : ActionView::Base.process_view_paths(CACHED_VIEW_PATHS.map(&:to_s))
- assert_equal(new_cache_template_loading ? ActionView::Template::EagerPath : ActionView::ReloadableTemplate::ReloadablePath, view_paths.first.class)
- setup_view(view_paths)
- end
-
- def teardown
- ActionView::Base.cache_template_loading = @previous_cache_template_loading
- end
-end
-
-class CachedRenderTest < Test::Unit::TestCase
- include TemplatesSetupTeardown
+class CachedViewRenderTest < ActiveSupport::TestCase
include RenderTestCases
+ # Ensure view path cache is primed
def setup
- setup_view_paths_for(cache_templates = true)
+ view_paths = ActionController::Base.view_paths
+ assert_equal ActionView::Template::EagerPath, view_paths.first.class
+ setup_view(view_paths)
end
end
-class ReloadableRenderTest < Test::Unit::TestCase
- include TemplatesSetupTeardown
+class LazyViewRenderTest < ActiveSupport::TestCase
include RenderTestCases
+ # Test the same thing as above, but make sure the view path
+ # is not eager loaded
def setup
- setup_view_paths_for(cache_templates = false)
+ path = ActionView::Template::Path.new(FIXTURE_LOAD_PATH)
+ view_paths = ActionView::Base.process_view_paths(path)
+ assert_equal ActionView::Template::Path, view_paths.first.class
+ setup_view(view_paths)
end
end
-
diff --git a/actionpack/test/template/scriptaculous_helper_test.rb b/actionpack/test/template/scriptaculous_helper_test.rb
index 690a7751b5..bebc3cb9f4 100644
--- a/actionpack/test/template/scriptaculous_helper_test.rb
+++ b/actionpack/test/template/scriptaculous_helper_test.rb
@@ -4,6 +4,7 @@ class ScriptaculousHelperTest < ActionView::TestCase
tests ActionView::Helpers::ScriptaculousHelper
def setup
+ super
@controller = Class.new do
def url_for(options)
url = "http://www.example.com/"
diff --git a/actionpack/test/template/template_test.rb b/actionpack/test/template/template_test.rb
deleted file mode 100644
index 5c6523201b..0000000000
--- a/actionpack/test/template/template_test.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require 'abstract_unit'
-
-class TemplateTest < Test::Unit::TestCase
- def test_template_path_parsing
- with_options :base_path => nil, :name => 'abc', :locale => nil, :format => 'html', :extension => 'erb' do |t|
- t.assert_parses_template_path 'abc.en.html.erb', :locale => 'en'
- t.assert_parses_template_path 'abc.en.plain.html.erb', :locale => 'en', :format => 'plain.html'
- t.assert_parses_template_path 'abc.html.erb'
- t.assert_parses_template_path 'abc.plain.html.erb', :format => 'plain.html'
- t.assert_parses_template_path 'abc.erb', :format => nil
- t.assert_parses_template_path 'abc.html', :extension => nil
-
- t.assert_parses_template_path '_abc.html.erb', :name => '_abc'
-
- t.assert_parses_template_path 'test/abc.html.erb', :base_path => 'test'
- t.assert_parses_template_path './test/abc.html.erb', :base_path => './test'
- t.assert_parses_template_path '../test/abc.html.erb', :base_path => '../test'
-
- t.assert_parses_template_path 'abc', :extension => nil, :format => nil, :name => nil
- t.assert_parses_template_path 'abc.xxx', :extension => nil, :format => 'xxx', :name => 'abc'
- t.assert_parses_template_path 'abc.html.xxx', :extension => nil, :format => 'xxx', :name => 'abc'
-
- t.assert_parses_template_path 'abc.html.erb.orig', :format => 'orig', :extension => nil
- end
- end
-
- private
- def assert_parses_template_path(path, parse_results)
- template = ActionView::Template.new(path, '')
- parse_results.each_pair do |k, v|
- assert_block(%Q{Expected template to parse #{k.inspect} from "#{path}" as #{v.inspect}, but got #{template.send(k).inspect}}) { v == template.send(k) }
- end
- end
-end
diff --git a/actionpack/test/template/test_test.rb b/actionpack/test/template/test_test.rb
index ccd299f46a..dd07a6d438 100644
--- a/actionpack/test/template/test_test.rb
+++ b/actionpack/test/template/test_test.rb
@@ -20,6 +20,7 @@ end
class PeopleHelperTest < ActionView::TestCase
def setup
+ super
ActionController::Routing::Routes.draw do |map|
map.people 'people', :controller => 'people', :action => 'index'
map.connect ':controller/:action/:id'
diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb
index a370f1458f..be7163888e 100644
--- a/actionpack/test/template/text_helper_test.rb
+++ b/actionpack/test/template/text_helper_test.rb
@@ -6,6 +6,7 @@ class TextHelperTest < ActionView::TestCase
include TestingSandbox
def setup
+ super
# This simulates the fact that instance variables are reset every time
# a view is rendered. The cycle helper depends on this behavior.
@_cycles = nil if (defined? @_cycles)
diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb
index 5900709d81..f3d2f87b4a 100644
--- a/actionpack/test/template/url_helper_test.rb
+++ b/actionpack/test/template/url_helper_test.rb
@@ -7,6 +7,7 @@ class UrlHelperTest < ActionView::TestCase
tests ActionView::Helpers::UrlHelper
def setup
+ super
@controller = Class.new do
attr_accessor :url, :request
def url_for(options)
@@ -380,6 +381,7 @@ class UrlHelperWithControllerTest < ActionView::TestCase
tests ActionView::Helpers::UrlHelper
def setup
+ super
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@controller = UrlHelperController.new
@@ -458,6 +460,7 @@ class LinkToUnlessCurrentWithControllerTest < ActionView::TestCase
tests ActionView::Helpers::UrlHelper
def setup
+ super
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@controller = TasksController.new
@@ -560,6 +563,7 @@ class PolymorphicControllerTest < ActionView::TestCase
tests ActionView::Helpers::UrlHelper
def setup
+ super
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end
diff --git a/activerecord/lib/active_record/session_store.rb b/activerecord/lib/active_record/session_store.rb
index 8fc5c9e7a6..21471da419 100644
--- a/activerecord/lib/active_record/session_store.rb
+++ b/activerecord/lib/active_record/session_store.rb
@@ -40,7 +40,7 @@ module ActiveRecord
#
# The example SqlBypass class is a generic SQL session store. You may
# use it as a basis for high-performance database-specific stores.
- class SessionStore < ActionController::Session::AbstractStore
+ class SessionStore < ActionDispatch::Session::AbstractStore
# The default Active Record class.
class Session < ActiveRecord::Base
##
diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb
index 7ebb3c48e0..dbd30f9271 100644
--- a/activesupport/lib/active_support.rb
+++ b/activesupport/lib/active_support.rb
@@ -32,6 +32,8 @@ module ActiveSupport
autoload :BufferedLogger, 'active_support/buffered_logger'
autoload :Cache, 'active_support/cache'
autoload :Callbacks, 'active_support/callbacks'
+ autoload :NewCallbacks, 'active_support/new_callbacks'
+ autoload :ConcurrentHash, 'active_support/concurrent_hash'
autoload :Deprecation, 'active_support/deprecation'
autoload :Duration, 'active_support/duration'
autoload :Gzip, 'active_support/gzip'
diff --git a/activesupport/lib/active_support/buffered_logger.rb b/activesupport/lib/active_support/buffered_logger.rb
index 33bcf327f8..568c596f91 100644
--- a/activesupport/lib/active_support/buffered_logger.rb
+++ b/activesupport/lib/active_support/buffered_logger.rb
@@ -67,14 +67,14 @@ module ActiveSupport
end
for severity in Severity.constants
- class_eval <<-EOT, __FILE__, __LINE__
- def #{severity.downcase}(message = nil, progname = nil, &block) # def debug(message = nil, progname = nil, &block)
- add(#{severity}, message, progname, &block) # add(DEBUG, message, progname, &block)
- end # end
- #
- def #{severity.downcase}? # def debug?
- #{severity} >= @level # DEBUG >= @level
- end # end
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
+ def #{severity.downcase}(message = nil, progname = nil, &block) # def debug(message = nil, progname = nil, &block)
+ add(#{severity}, message, progname, &block) # add(DEBUG, message, progname, &block)
+ end # end
+
+ def #{severity.downcase}? # def debug?
+ #{severity} >= @level # DEBUG >= @level
+ end # end
EOT
end
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index 86e66e0588..4bac8292e2 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -204,7 +204,7 @@ module ActiveSupport
module ClassMethods
def define_callbacks(*callbacks)
callbacks.each do |callback|
- class_eval <<-"end_eval"
+ class_eval <<-"end_eval", __FILE__, __LINE__ + 1
def self.#{callback}(*methods, &block) # def self.before_save(*methods, &block)
callbacks = CallbackChain.build(:#{callback}, *methods, &block) # callbacks = CallbackChain.build(:before_save, *methods, &block)
@#{callback}_callbacks ||= CallbackChain.new # @before_save_callbacks ||= CallbackChain.new
diff --git a/activesupport/lib/active_support/concurrent_hash.rb b/activesupport/lib/active_support/concurrent_hash.rb
new file mode 100644
index 0000000000..c9f9b16da3
--- /dev/null
+++ b/activesupport/lib/active_support/concurrent_hash.rb
@@ -0,0 +1,26 @@
+module ActiveSupport
+ class ConcurrentHash
+ def initialize(hash = {})
+ @backup_cache = hash.dup
+ @frozen_cache = hash.dup.freeze
+ @mutex = Mutex.new
+ end
+
+ def []=(k,v)
+ @mutex.synchronize { @backup_cache[k] = v }
+ @frozen_cache = @backup_cache.dup.freeze
+ end
+
+ def [](k)
+ if @frozen_cache.key?(k)
+ @frozen_cache[k]
+ else
+ @mutex.synchronize { @backup_cache[k] }
+ end
+ end
+
+ def empty?
+ @backup_cache.empty?
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb
index c795871474..75e481fc54 100644
--- a/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb
+++ b/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb
@@ -10,7 +10,7 @@ class Class
def cattr_reader(*syms)
syms.flatten.each do |sym|
next if sym.is_a?(Hash)
- class_eval(<<-EOS, __FILE__, __LINE__)
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
unless defined? @@#{sym} # unless defined? @@hair_colors
@@#{sym} = nil # @@hair_colors = nil
end # end
@@ -29,7 +29,7 @@ class Class
def cattr_writer(*syms)
options = syms.extract_options!
syms.flatten.each do |sym|
- class_eval(<<-EOS, __FILE__, __LINE__)
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
unless defined? @@#{sym} # unless defined? @@hair_colors
@@#{sym} = nil # @@hair_colors = nil
end # end
diff --git a/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb b/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb
index 000ccf4d55..d893818695 100644
--- a/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb
+++ b/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb
@@ -8,7 +8,7 @@ class Class
def superclass_delegating_reader(*names)
class_name_to_stop_searching_on = self.superclass.name.blank? ? "Object" : self.superclass.name
names.each do |name|
- class_eval <<-EOS
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def self.#{name} # def self.only_reader
if defined?(@#{name}) # if defined?(@only_reader)
@#{name} # @only_reader
@@ -32,10 +32,10 @@ class Class
def superclass_delegating_writer(*names)
names.each do |name|
- class_eval <<-EOS
- def self.#{name}=(value) # def self.only_writer=(value)
- @#{name} = value # @only_writer = value
- end # end
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
+ def self.#{name}=(value) # def self.property=(value)
+ @#{name} = value # @property = value
+ end # end
EOS
end
end
diff --git a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
index 1794afe77c..2f18666ab9 100644
--- a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
+++ b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
@@ -10,14 +10,14 @@ class Class # :nodoc:
def class_inheritable_reader(*syms)
syms.each do |sym|
next if sym.is_a?(Hash)
- class_eval <<-EOS
- def self.#{sym} # def self.before_add_for_comments
- read_inheritable_attribute(:#{sym}) # read_inheritable_attribute(:before_add_for_comments)
- end # end
- #
- def #{sym} # def before_add_for_comments
- self.class.#{sym} # self.class.before_add_for_comments
- end # end
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
+ def self.#{sym} # def self.after_add
+ read_inheritable_attribute(:#{sym}) # read_inheritable_attribute(:after_add)
+ end # end
+
+ def #{sym} # def after_add
+ self.class.#{sym} # self.class.after_add
+ end # end
EOS
end
end
@@ -25,7 +25,7 @@ class Class # :nodoc:
def class_inheritable_writer(*syms)
options = syms.extract_options!
syms.each do |sym|
- class_eval <<-EOS
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def self.#{sym}=(obj) # def self.color=(obj)
write_inheritable_attribute(:#{sym}, obj) # write_inheritable_attribute(:color, obj)
end # end
@@ -42,7 +42,7 @@ class Class # :nodoc:
def class_inheritable_array_writer(*syms)
options = syms.extract_options!
syms.each do |sym|
- class_eval <<-EOS
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def self.#{sym}=(obj) # def self.levels=(obj)
write_inheritable_array(:#{sym}, obj) # write_inheritable_array(:levels, obj)
end # end
@@ -59,7 +59,7 @@ class Class # :nodoc:
def class_inheritable_hash_writer(*syms)
options = syms.extract_options!
syms.each do |sym|
- class_eval <<-EOS
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def self.#{sym}=(obj) # def self.nicknames=(obj)
write_inheritable_hash(:#{sym}, obj) # write_inheritable_hash(:nicknames, obj)
end # end
@@ -138,3 +138,82 @@ class Class # :nodoc:
alias inherited_without_inheritable_attributes inherited
alias inherited inherited_with_inheritable_attributes
end
+
+class Class
+ # Defines class-level inheritable attribute reader. Attributes are available to subclasses,
+ # each subclass has a copy of parent's attribute.
+ #
+ # @param *syms<Array[#to_s]> Array of attributes to define inheritable reader for.
+ # @return <Array[#to_s]> Array of attributes converted into inheritable_readers.
+ #
+ # @api public
+ #
+ # @todo Do we want to block instance_reader via :instance_reader => false
+ # @todo It would be preferable that we do something with a Hash passed in
+ # (error out or do the same as other methods above) instead of silently
+ # moving on). In particular, this makes the return value of this function
+ # less useful.
+ def extlib_inheritable_reader(*ivars)
+ instance_reader = ivars.pop[:reader] if ivars.last.is_a?(Hash)
+
+ ivars.each do |ivar|
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def self.#{ivar}
+ return @#{ivar} if self.object_id == #{self.object_id} || defined?(@#{ivar})
+ ivar = superclass.#{ivar}
+ return nil if ivar.nil? && !#{self}.instance_variable_defined?("@#{ivar}")
+ @#{ivar} = ivar && !ivar.is_a?(Module) && !ivar.is_a?(Numeric) && !ivar.is_a?(TrueClass) && !ivar.is_a?(FalseClass) ? ivar.dup : ivar
+ end
+ RUBY
+ unless instance_reader == false
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def #{ivar}
+ self.class.#{ivar}
+ end
+ RUBY
+ end
+ end
+ end
+
+ # Defines class-level inheritable attribute writer. Attributes are available to subclasses,
+ # each subclass has a copy of parent's attribute.
+ #
+ # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
+ # define inheritable writer for.
+ # @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
+ # @return <Array[#to_s]> An Array of the attributes that were made into inheritable writers.
+ #
+ # @api public
+ #
+ # @todo We need a style for class_eval <<-HEREDOC. I'd like to make it
+ # class_eval(<<-RUBY, __FILE__, __LINE__), but we should codify it somewhere.
+ def extlib_inheritable_writer(*ivars)
+ instance_writer = ivars.pop[:writer] if ivars.last.is_a?(Hash)
+ ivars.each do |ivar|
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def self.#{ivar}=(obj)
+ @#{ivar} = obj
+ end
+ RUBY
+ unless instance_writer == false
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def #{ivar}=(obj) self.class.#{ivar} = obj end
+ RUBY
+ end
+ end
+ end
+
+ # Defines class-level inheritable attribute accessor. Attributes are available to subclasses,
+ # each subclass has a copy of parent's attribute.
+ #
+ # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
+ # define inheritable accessor for.
+ # @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
+ # @return <Array[#to_s]> An Array of attributes turned into inheritable accessors.
+ #
+ # @api public
+ def extlib_inheritable_accessor(*syms)
+ extlib_inheritable_reader(*syms)
+ extlib_inheritable_writer(*syms)
+ end
+end \ No newline at end of file
diff --git a/activesupport/lib/active_support/core_ext/module.rb b/activesupport/lib/active_support/core_ext/module.rb
index da8d28ec13..cb31437094 100644
--- a/activesupport/lib/active_support/core_ext/module.rb
+++ b/activesupport/lib/active_support/core_ext/module.rb
@@ -8,6 +8,7 @@ require 'active_support/core_ext/module/loading'
require 'active_support/core_ext/module/aliasing'
require 'active_support/core_ext/module/model_naming'
require 'active_support/core_ext/module/synchronization'
+require 'active_support/core_ext/module/setup'
module ActiveSupport
module CoreExtensions
diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
index 9402cb8534..137590d286 100644
--- a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
+++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
@@ -14,7 +14,7 @@ class Module
def mattr_reader(*syms)
syms.each do |sym|
next if sym.is_a?(Hash)
- class_eval(<<-EOS, __FILE__, __LINE__)
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
unless defined? @@#{sym} # unless defined? @@pagination_options
@@#{sym} = nil # @@pagination_options = nil
end # end
@@ -33,7 +33,7 @@ class Module
def mattr_writer(*syms)
options = syms.extract_options!
syms.each do |sym|
- class_eval(<<-EOS, __FILE__, __LINE__)
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
unless defined? @@#{sym} # unless defined? @@pagination_options
@@#{sym} = nil # @@pagination_options = nil
end # end
diff --git a/activesupport/lib/active_support/core_ext/module/setup.rb b/activesupport/lib/active_support/core_ext/module/setup.rb
new file mode 100644
index 0000000000..e6dfd0cf56
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/module/setup.rb
@@ -0,0 +1,26 @@
+class Module
+ attr_accessor :_setup_block
+ attr_accessor :_dependencies
+
+ def setup(&blk)
+ @_setup_block = blk
+ end
+
+ def use(mod)
+ return if self < mod
+
+ (mod._dependencies || []).each do |dep|
+ use dep
+ end
+ # raise "Circular dependencies" if self < mod
+ include mod
+ extend mod.const_get("ClassMethods") if mod.const_defined?("ClassMethods")
+ class_eval(&mod._setup_block) if mod._setup_block
+ end
+
+ def depends_on(mod)
+ return if self < mod
+ @_dependencies ||= []
+ @_dependencies << mod
+ end
+end \ No newline at end of file
diff --git a/activesupport/lib/active_support/core_ext/proc.rb b/activesupport/lib/active_support/core_ext/proc.rb
index 2ca23f62ef..5c29cc32a2 100644
--- a/activesupport/lib/active_support/core_ext/proc.rb
+++ b/activesupport/lib/active_support/core_ext/proc.rb
@@ -3,9 +3,9 @@ class Proc #:nodoc:
block, time = self, Time.now
(class << object; self end).class_eval do
method_name = "__bind_#{time.to_i}_#{time.usec}"
- define_method(method_name, &block)
- method = instance_method(method_name)
- remove_method(method_name)
+ define_method(method_name, &block) # define_method("__bind_1230458026_720454", &block)
+ method = instance_method(method_name) # method = instance_method("__bind_1230458026_720454")
+ remove_method(method_name) # remove_method("__bind_1230458026_720454")
method
end.bind(object)
end
diff --git a/activesupport/lib/active_support/core_ext/string/multibyte.rb b/activesupport/lib/active_support/core_ext/string/multibyte.rb
index a4caa83b74..8f8f0968fd 100644
--- a/activesupport/lib/active_support/core_ext/string/multibyte.rb
+++ b/activesupport/lib/active_support/core_ext/string/multibyte.rb
@@ -55,7 +55,11 @@ module ActiveSupport #:nodoc:
unless '1.8.7 and later'.respond_to?(:chars)
def chars
- ActiveSupport::Deprecation.warn('String#chars has been deprecated in favor of String#mb_chars.', caller)
+ # FIXME:
+ # ActiveSupport::Deprecation refers to RAILS_ENV
+ # and is a show stopper for 3rd party applications
+ # that only want ActiveSupport
+ ActiveSupport::Deprecation.warn('String#chars has been deprecated in favor of String#mb_chars.', caller) if defined?(ActiveSupport::Deprecation)
mb_chars
end
end
diff --git a/activesupport/lib/active_support/deprecation.rb b/activesupport/lib/active_support/deprecation.rb
index d20151661b..202b46ce7a 100644
--- a/activesupport/lib/active_support/deprecation.rb
+++ b/activesupport/lib/active_support/deprecation.rb
@@ -89,7 +89,7 @@ module ActiveSupport
method_names = method_names + options.keys
method_names.each do |method_name|
alias_method_chain(method_name, :deprecation) do |target, punctuation|
- class_eval(<<-EOS, __FILE__, __LINE__)
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def #{target}_with_deprecation#{punctuation}(*args, &block) # def generate_secret_with_deprecation(*args, &block)
::ActiveSupport::Deprecation.warn( # ::ActiveSupport::Deprecation.warn(
self.class.deprecated_method_warning( # self.class.deprecated_method_warning(
diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb
index 71cfe61739..2b85fd7be4 100644
--- a/activesupport/lib/active_support/memoizable.rb
+++ b/activesupport/lib/active_support/memoizable.rb
@@ -1,4 +1,17 @@
module ActiveSupport
+ module SafelyMemoizable
+ def safely_memoize(*symbols)
+ symbols.each do |symbol|
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def #{symbol}(*args)
+ memoized = @_memoized_#{symbol} || ::ActiveSupport::ConcurrentHash.new
+ memoized[args] ||= memoized_#{symbol}(*args)
+ end
+ RUBY
+ end
+ end
+ end
+
module Memoizable
def self.memoized_ivar_for(symbol)
"@_memoized_#{symbol.to_s.sub(/\?\Z/, '_query').sub(/!\Z/, '_bang')}".to_sym
@@ -58,7 +71,7 @@ module ActiveSupport
original_method = :"_unmemoized_#{symbol}"
memoized_ivar = ActiveSupport::Memoizable.memoized_ivar_for(symbol)
- class_eval <<-EOS, __FILE__, __LINE__
+ class_eval <<-EOS, __FILE__, __LINE__ + 1
include InstanceMethods # include InstanceMethods
#
if method_defined?(:#{original_method}) # if method_defined?(:_unmemoized_mime_type)
@@ -69,7 +82,7 @@ module ActiveSupport
if instance_method(:#{symbol}).arity == 0 # if instance_method(:mime_type).arity == 0
def #{symbol}(reload = false) # def mime_type(reload = false)
if reload || !defined?(#{memoized_ivar}) || #{memoized_ivar}.empty? # if reload || !defined?(@_memoized_mime_type) || @_memoized_mime_type.empty?
- #{memoized_ivar} = [#{original_method}.freeze] # @_memoized_mime_type = [_unmemoized_mime_type.freeze]
+ #{memoized_ivar} = [#{original_method}] # @_memoized_mime_type = [_unmemoized_mime_type]
end # end
#{memoized_ivar}[0] # @_memoized_mime_type[0]
end # end
@@ -82,7 +95,7 @@ module ActiveSupport
if !reload && #{memoized_ivar}.has_key?(args) # if !reload && @_memoized_mime_type.has_key?(args)
#{memoized_ivar}[args] # @_memoized_mime_type[args]
elsif #{memoized_ivar} # elsif @_memoized_mime_type
- #{memoized_ivar}[args] = #{original_method}(*args).freeze # @_memoized_mime_type[args] = _unmemoized_mime_type(*args).freeze
+ #{memoized_ivar}[args] = #{original_method}(*args) # @_memoized_mime_type[args] = _unmemoized_mime_type(*args)
end # end
else # else
#{original_method}(*args) # _unmemoized_mime_type(*args)
diff --git a/activesupport/lib/active_support/mini.rb b/activesupport/lib/active_support/mini.rb
new file mode 100644
index 0000000000..fe7ba48e58
--- /dev/null
+++ b/activesupport/lib/active_support/mini.rb
@@ -0,0 +1,9 @@
+$LOAD_PATH.unshift File.dirname(__FILE__)
+
+require "core_ext/blank"
+# whole object.rb pulls up rarely used introspection extensions
+require "core_ext/object/metaclass"
+require 'core_ext/array'
+require 'core_ext/hash'
+require 'core_ext/module/attribute_accessors'
+require 'core_ext/string/inflections' \ No newline at end of file
diff --git a/activesupport/lib/active_support/multibyte/unicode_database.rb b/activesupport/lib/active_support/multibyte/unicode_database.rb
index a08f38cdbb..074ad8613a 100644
--- a/activesupport/lib/active_support/multibyte/unicode_database.rb
+++ b/activesupport/lib/active_support/multibyte/unicode_database.rb
@@ -23,11 +23,11 @@ module ActiveSupport #:nodoc:
# Lazy load the Unicode database so it's only loaded when it's actually used
ATTRIBUTES.each do |attr_name|
- class_eval(<<-EOS, __FILE__, __LINE__)
- def #{attr_name} # def codepoints
- load # load
- @#{attr_name} # @codepoints
- end # end
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
+ def #{attr_name} # def codepoints
+ load # load
+ @#{attr_name} # @codepoints
+ end # end
EOS
end
diff --git a/activesupport/lib/active_support/new_callbacks.rb b/activesupport/lib/active_support/new_callbacks.rb
new file mode 100644
index 0000000000..b93057fe27
--- /dev/null
+++ b/activesupport/lib/active_support/new_callbacks.rb
@@ -0,0 +1,485 @@
+module ActiveSupport
+ # Callbacks are hooks into the lifecycle of an object that allow you to trigger logic
+ # before or after an alteration of the object state.
+ #
+ # Mixing in this module allows you to define callbacks in your class.
+ #
+ # Example:
+ # class Storage
+ # include ActiveSupport::Callbacks
+ #
+ # define_callbacks :save
+ # end
+ #
+ # class ConfigStorage < Storage
+ # save_callback :before, :saving_message
+ # def saving_message
+ # puts "saving..."
+ # end
+ #
+ # save_callback :after do |object|
+ # puts "saved"
+ # end
+ #
+ # def save
+ # _run_save_callbacks do
+ # puts "- save"
+ # end
+ # end
+ # end
+ #
+ # config = ConfigStorage.new
+ # config.save
+ #
+ # Output:
+ # saving...
+ # - save
+ # saved
+ #
+ # Callbacks from parent classes are inherited.
+ #
+ # Example:
+ # class Storage
+ # include ActiveSupport::Callbacks
+ #
+ # define_callbacks :save
+ #
+ # save_callback :before, :prepare
+ # def prepare
+ # puts "preparing save"
+ # end
+ # end
+ #
+ # class ConfigStorage < Storage
+ # save_callback :before, :saving_message
+ # def saving_message
+ # puts "saving..."
+ # end
+ #
+ # save_callback :after do |object|
+ # puts "saved"
+ # end
+ #
+ # def save
+ # _run_save_callbacks do
+ # puts "- save"
+ # end
+ # end
+ # end
+ #
+ # config = ConfigStorage.new
+ # config.save
+ #
+ # Output:
+ # preparing save
+ # saving...
+ # - save
+ # saved
+ module NewCallbacks
+ def self.included(klass)
+ klass.extend ClassMethods
+ end
+
+ def run_callbacks(kind, options = {}, &blk)
+ send("_run_#{kind}_callbacks", &blk)
+ end
+
+ class Callback
+ @@_callback_sequence = 0
+
+ attr_accessor :filter, :kind, :name, :options, :per_key, :klass
+ def initialize(filter, kind, options, klass, name)
+ @kind, @klass = kind, klass
+ @name = name
+
+ normalize_options!(options)
+
+ @per_key = options.delete(:per_key)
+ @raw_filter, @options = filter, options
+ @filter = _compile_filter(filter)
+ @compiled_options = _compile_options(options)
+ @callback_id = next_id
+
+ _compile_per_key_options
+ end
+
+ def clone(klass)
+ obj = super()
+ obj.klass = klass
+ obj.per_key = @per_key.dup
+ obj.options = @options.dup
+ obj.per_key[:if] = @per_key[:if].dup
+ obj.per_key[:unless] = @per_key[:unless].dup
+ obj.options[:if] = @options[:if].dup
+ obj.options[:unless] = @options[:unless].dup
+ obj
+ end
+
+ def normalize_options!(options)
+ options[:if] = Array(options[:if])
+ options[:unless] = Array(options[:unless])
+
+ options[:per_key] ||= {}
+ options[:per_key][:if] = Array(options[:per_key][:if])
+ options[:per_key][:unless] = Array(options[:per_key][:unless])
+ end
+
+ def next_id
+ @@_callback_sequence += 1
+ end
+
+ def matches?(_kind, _name, _filter)
+ @kind == _kind &&
+ @name == _name &&
+ @filter == _filter
+ end
+
+ def _update_filter(filter_options, new_options)
+ filter_options[:if].push(new_options[:unless]) if new_options.key?(:unless)
+ filter_options[:unless].push(new_options[:if]) if new_options.key?(:if)
+ end
+
+ def recompile!(_options, _per_key)
+ _update_filter(self.options, _options)
+ _update_filter(self.per_key, _per_key)
+
+ @callback_id = next_id
+ @filter = _compile_filter(@raw_filter)
+ @compiled_options = _compile_options(@options)
+ _compile_per_key_options
+ end
+
+ def _compile_per_key_options
+ key_options = _compile_options(@per_key)
+
+ @klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
+ def _one_time_conditions_valid_#{@callback_id}?
+ true #{key_options[0]}
+ end
+ RUBY_EVAL
+ end
+
+ # This will supply contents for before and around filters, and no
+ # contents for after filters (for the forward pass).
+ def start(key = nil, options = {})
+ object, terminator = (options || {}).values_at(:object, :terminator)
+
+ return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?")
+
+ terminator ||= false
+
+ # options[0] is the compiled form of supplied conditions
+ # options[1] is the "end" for the conditional
+
+ if @kind == :before || @kind == :around
+ if @kind == :before
+ # if condition # before_save :filter_name, :if => :condition
+ # filter_name
+ # end
+ filter = <<-RUBY_EVAL
+ unless halted
+ result = #{@filter}
+ halted ||= (#{terminator})
+ end
+ RUBY_EVAL
+ [@compiled_options[0], filter, @compiled_options[1]].compact.join("\n")
+ else
+ # Compile around filters with conditions into proxy methods
+ # that contain the conditions.
+ #
+ # For `around_save :filter_name, :if => :condition':
+ #
+ # def _conditional_callback_save_17
+ # if condition
+ # filter_name do
+ # yield self
+ # end
+ # else
+ # yield self
+ # end
+ # end
+
+ name = "_conditional_callback_#{@kind}_#{next_id}"
+ txt = <<-RUBY_EVAL
+ def #{name}(halted)
+ #{@compiled_options[0] || "if true"} && !halted
+ #{@filter} do
+ yield self
+ end
+ else
+ yield self
+ end
+ end
+ RUBY_EVAL
+ @klass.class_eval(txt)
+ "#{name}(halted) do"
+ end
+ end
+ end
+
+ # This will supply contents for around and after filters, but not
+ # before filters (for the backward pass).
+ def end(key = nil, options = {})
+ object = (options || {})[:object]
+
+ return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?")
+
+ if @kind == :around || @kind == :after
+ # if condition # after_save :filter_name, :if => :condition
+ # filter_name
+ # end
+ if @kind == :after
+ [@compiled_options[0], @filter, @compiled_options[1]].compact.join("\n")
+ else
+ "end"
+ end
+ end
+ end
+
+ private
+ # Options support the same options as filters themselves (and support
+ # symbols, string, procs, and objects), so compile a conditional
+ # expression based on the options
+ def _compile_options(options)
+ return [] if options[:if].empty? && options[:unless].empty?
+
+ conditions = []
+
+ unless options[:if].empty?
+ conditions << Array(_compile_filter(options[:if]))
+ end
+
+ unless options[:unless].empty?
+ conditions << Array(_compile_filter(options[:unless])).map {|f| "!#{f}"}
+ end
+
+ ["if #{conditions.flatten.join(" && ")}", "end"]
+ end
+
+ # Filters support:
+ # Arrays:: Used in conditions. This is used to specify
+ # multiple conditions. Used internally to
+ # merge conditions from skip_* filters
+ # Symbols:: A method to call
+ # Strings:: Some content to evaluate
+ # Procs:: A proc to call with the object
+ # Objects:: An object with a before_foo method on it to call
+ #
+ # All of these objects are compiled into methods and handled
+ # the same after this point:
+ # Arrays:: Merged together into a single filter
+ # Symbols:: Already methods
+ # Strings:: class_eval'ed into methods
+ # Procs:: define_method'ed into methods
+ # Objects::
+ # a method is created that calls the before_foo method
+ # on the object.
+ def _compile_filter(filter)
+ method_name = "_callback_#{@kind}_#{next_id}"
+ case filter
+ when Array
+ filter.map {|f| _compile_filter(f)}
+ when Symbol
+ filter
+ when Proc
+ @klass.send(:define_method, method_name, &filter)
+ method_name << (filter.arity == 1 ? "(self)" : "")
+ when String
+ @klass.class_eval <<-RUBY_EVAL
+ def #{method_name}
+ #{filter}
+ end
+ RUBY_EVAL
+ method_name
+ else
+ kind, name = @kind, @name
+ @klass.send(:define_method, method_name) do
+ filter.send("#{kind}_#{name}", self)
+ end
+ method_name
+ end
+ end
+ end
+
+ # This method_missing is supplied to catch callbacks with keys and create
+ # the appropriate callback for future use.
+ def method_missing(meth, *args, &blk)
+ if meth.to_s =~ /_run__([\w:]+)__(\w+)__(\w+)__callbacks/
+ return self.class._create_and_run_keyed_callback($1, $2.to_sym, $3.to_sym, self, &blk)
+ end
+ super
+ end
+
+ # An Array with a compile method
+ class CallbackChain < Array
+ def initialize(symbol)
+ @symbol = symbol
+ end
+
+ def compile(key = nil, options = {})
+ method = []
+ method << "halted = false"
+ each do |callback|
+ method << callback.start(key, options)
+ end
+ method << "yield self if block_given?"
+ reverse_each do |callback|
+ method << callback.end(key, options)
+ end
+ method.compact.join("\n")
+ end
+
+ def clone(klass)
+ chain = CallbackChain.new(@symbol)
+ chain.push(*map {|c| c.clone(klass)})
+ end
+ end
+
+ module ClassMethods
+ CHAINS = {:before => :before, :around => :before, :after => :after}
+
+ # Make the _run_save_callbacks method. The generated method takes
+ # a block that it'll yield to. It'll call the before and around filters
+ # in order, yield the block, and then run the after filters.
+ #
+ # _run_save_callbacks do
+ # save
+ # end
+ #
+ # The _run_save_callbacks method can optionally take a key, which
+ # will be used to compile an optimized callback method for each
+ # key. See #define_callbacks for more information.
+ def _define_runner(symbol, str, options)
+ str = <<-RUBY_EVAL
+ def _run_#{symbol}_callbacks(key = nil)
+ if key
+ name = "_run__\#{self.class.name.split("::").last}__#{symbol}__\#{key}__callbacks"
+
+ if respond_to?(name)
+ send(name) { yield if block_given? }
+ else
+ self.class._create_and_run_keyed_callback(
+ self.class.name.split("::").last,
+ :#{symbol}, key, self) { yield if block_given? }
+ end
+ else
+ #{str}
+ end
+ end
+ RUBY_EVAL
+
+ class_eval str, __FILE__, __LINE__ + 1
+
+ before_name, around_name, after_name =
+ options.values_at(:before, :after, :around)
+ end
+
+ # This is called the first time a callback is called with a particular
+ # key. It creates a new callback method for the key, calculating
+ # which callbacks can be omitted because of per_key conditions.
+ def _create_and_run_keyed_callback(klass, kind, key, obj, &blk)
+ @_keyed_callbacks ||= {}
+ @_keyed_callbacks[[kind, key]] ||= begin
+ str = self.send("_#{kind}_callbacks").compile(key, :object => obj, :terminator => self.send("_#{kind}_terminator"))
+
+ self.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
+ def _run__#{klass.split("::").last}__#{kind}__#{key}__callbacks
+ #{str}
+ end
+ RUBY_EVAL
+
+ true
+ end
+
+ obj.send("_run__#{klass.split("::").last}__#{kind}__#{key}__callbacks", &blk)
+ end
+
+ # Define callbacks.
+ #
+ # Creates a <name>_callback method that you can use to add callbacks.
+ #
+ # Syntax:
+ # save_callback :before, :before_meth
+ # save_callback :after, :after_meth, :if => :condition
+ # save_callback :around {|r| stuff; yield; stuff }
+ #
+ # The <name>_callback method also updates the _run_<name>_callbacks
+ # method, which is the public API to run the callbacks.
+ #
+ # Also creates a skip_<name>_callback method that you can use to skip
+ # callbacks.
+ #
+ # When creating or skipping callbacks, you can specify conditions that
+ # are always the same for a given key. For instance, in ActionPack,
+ # we convert :only and :except conditions into per-key conditions.
+ #
+ # before_filter :authenticate, :except => "index"
+ # becomes
+ # dispatch_callback :before, :authenticate, :per_key => {:unless => proc {|c| c.action_name == "index"}}
+ #
+ # Per-Key conditions are evaluated only once per use of a given key.
+ # In the case of the above example, you would do:
+ #
+ # run_dispatch_callbacks(action_name) { ... dispatch stuff ... }
+ #
+ # In that case, each action_name would get its own compiled callback
+ # method that took into consideration the per_key conditions. This
+ # is a speed improvement for ActionPack.
+ def define_callbacks(*symbols)
+ terminator = symbols.pop if symbols.last.is_a?(String)
+ symbols.each do |symbol|
+ self.extlib_inheritable_accessor("_#{symbol}_terminator")
+ self.send("_#{symbol}_terminator=", terminator)
+ self.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
+ extlib_inheritable_accessor :_#{symbol}_callbacks
+ self._#{symbol}_callbacks = CallbackChain.new(:#{symbol})
+
+ def self.#{symbol}_callback(*filters, &blk)
+ type = [:before, :after, :around].include?(filters.first) ? filters.shift : :before
+ options = filters.last.is_a?(Hash) ? filters.pop : {}
+ filters.unshift(blk) if block_given?
+
+ filters.map! do |filter|
+ # overrides parent class
+ self._#{symbol}_callbacks.delete_if {|c| c.matches?(type, :#{symbol}, filter)}
+ Callback.new(filter, type, options.dup, self, :#{symbol})
+ end
+ self._#{symbol}_callbacks.push(*filters)
+ _define_runner(:#{symbol},
+ self._#{symbol}_callbacks.compile(nil, :terminator => _#{symbol}_terminator),
+ options)
+ end
+
+ def self.skip_#{symbol}_callback(*filters, &blk)
+ type = [:before, :after, :around].include?(filters.first) ? filters.shift : :before
+ options = filters.last.is_a?(Hash) ? filters.pop : {}
+ filters.unshift(blk) if block_given?
+ filters.each do |filter|
+ self._#{symbol}_callbacks = self._#{symbol}_callbacks.clone(self)
+
+ filter = self._#{symbol}_callbacks.find {|c| c.matches?(type, :#{symbol}, filter) }
+ per_key = options[:per_key] || {}
+ if filter
+ filter.recompile!(options, per_key)
+ else
+ self._#{symbol}_callbacks.delete(filter)
+ end
+ _define_runner(:#{symbol},
+ self._#{symbol}_callbacks.compile(nil, :terminator => _#{symbol}_terminator),
+ options)
+ end
+
+ end
+
+ def self.reset_#{symbol}_callbacks
+ self._#{symbol}_callbacks = CallbackChain.new(:#{symbol})
+ _define_runner(:#{symbol}, self._#{symbol}_callbacks.compile, {})
+ end
+
+ self.#{symbol}_callback(:before)
+ RUBY_EVAL
+ end
+ end
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb
index f05d4098fc..50e25ef740 100644
--- a/activesupport/lib/active_support/test_case.rb
+++ b/activesupport/lib/active_support/test_case.rb
@@ -12,6 +12,7 @@ require 'active_support/testing/setup_and_teardown'
require 'active_support/testing/assertions'
require 'active_support/testing/deprecation'
require 'active_support/testing/declarative'
+require 'active_support/testing/pending'
module ActiveSupport
class TestCase < ::Test::Unit::TestCase
@@ -34,6 +35,7 @@ module ActiveSupport
include ActiveSupport::Testing::SetupAndTeardown
include ActiveSupport::Testing::Assertions
include ActiveSupport::Testing::Deprecation
+ include ActiveSupport::Testing::Pending
extend ActiveSupport::Testing::Declarative
end
end
diff --git a/activesupport/lib/active_support/testing/declarative.rb b/activesupport/lib/active_support/testing/declarative.rb
index cb6a5844eb..a7af7f4224 100644
--- a/activesupport/lib/active_support/testing/declarative.rb
+++ b/activesupport/lib/active_support/testing/declarative.rb
@@ -1,18 +1,43 @@
module ActiveSupport
module Testing
module Declarative
- # test "verify something" do
- # ...
- # end
- def test(name, &block)
- test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
- defined = instance_method(test_name) rescue false
- raise "#{test_name} is already defined in #{self}" if defined
- if block_given?
- define_method(test_name, &block)
- else
- define_method(test_name) do
- flunk "No implementation provided for #{name}"
+
+ def self.extended(klass)
+ klass.class_eval do
+
+ unless method_defined?(:describe)
+ def self.describe(text)
+ class_eval <<-RUBY_EVAL
+ def self.name
+ "#{text}"
+ end
+ RUBY_EVAL
+ end
+ end
+
+ if defined?(Spec)
+ class << self
+ alias_method :test, :it
+ end
+ end
+
+ end
+ end
+
+ unless defined?(Spec)
+ # test "verify something" do
+ # ...
+ # end
+ def test(name, &block)
+ test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
+ defined = instance_method(test_name) rescue false
+ raise "#{test_name} is already defined in #{self}" if defined
+ if block_given?
+ define_method(test_name, &block)
+ else
+ define_method(test_name) do
+ flunk "No implementation provided for #{name}"
+ end
end
end
end
diff --git a/activesupport/lib/active_support/testing/pending.rb b/activesupport/lib/active_support/testing/pending.rb
new file mode 100644
index 0000000000..b6905ddccd
--- /dev/null
+++ b/activesupport/lib/active_support/testing/pending.rb
@@ -0,0 +1,43 @@
+# Some code from jeremymcanally's "pending"
+# http://github.com/jeremymcanally/pending/tree/master
+
+module ActiveSupport
+ module Testing
+ module Pending
+
+ unless defined?(Spec)
+
+ @@pending_cases = []
+ @@at_exit = false
+
+ def pending(description = "", &block)
+ if block_given?
+ failed = false
+
+ begin
+ block.call
+ rescue
+ failed = true
+ end
+
+ flunk("<#{description}> did not fail.") unless failed
+ end
+
+ caller[0] =~ (/(.*):(.*):in `(.*)'/)
+ @@pending_cases << "#{$3} at #{$1}, line #{$2}"
+ print "P"
+
+ @@at_exit ||= begin
+ at_exit do
+ puts "\nPending Cases:"
+ @@pending_cases.each do |test_case|
+ puts test_case
+ end
+ end
+ end
+ end
+ end
+
+ end
+ end
+end \ No newline at end of file
diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb
index aaf9f8f42c..4537c30e9c 100644
--- a/activesupport/lib/active_support/testing/setup_and_teardown.rb
+++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb
@@ -10,6 +10,8 @@ module ActiveSupport
if defined?(MiniTest::Assertions) && TestCase < MiniTest::Assertions
include ForMiniTest
+ elsif defined? Spec
+ include ForRspec
else
include ForClassicTestUnit
end
@@ -34,7 +36,7 @@ module ActiveSupport
result
end
end
-
+
module ForClassicTestUnit
# For compatibility with Ruby < 1.8.6
PASSTHROUGH_EXCEPTIONS = Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS rescue [NoMemoryError, SignalException, Interrupt, SystemExit]
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index 2574f4e88e..9068afef2e 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -243,10 +243,10 @@ module ActiveSupport
end
%w(year mon month day mday wday yday hour min sec to_date).each do |method_name|
- class_eval <<-EOV
- def #{method_name} # def year
- time.#{method_name} # time.year
- end # end
+ class_eval <<-EOV, __FILE__, __LINE__ + 1
+ def #{method_name} # def month
+ time.#{method_name} # time.month
+ end # end
EOV
end
diff --git a/activesupport/test/memoizable_test.rb b/activesupport/test/memoizable_test.rb
index 39420c5a3a..b03178900f 100644
--- a/activesupport/test/memoizable_test.rb
+++ b/activesupport/test/memoizable_test.rb
@@ -125,8 +125,13 @@ class MemoizableTest < Test::Unit::TestCase
end
def test_memorized_results_are_immutable
- assert_equal "Josh", @person.name
- assert_raise(ActiveSupport::FrozenObjectError) { @person.name.gsub!("Josh", "Gosh") }
+ # This is purely a performance enhancement that we can revisit once the rest of
+ # the code is in place. Ideally, we'd be able to do memoization in a freeze-friendly
+ # way without amc hacks
+ pending do
+ assert_equal "Josh", @person.name
+ assert_raise(ActiveSupport::FrozenObjectError) { @person.name.gsub!("Josh", "Gosh") }
+ end
end
def test_reloadable
diff --git a/activesupport/test/new_callback_inheritance_test.rb b/activesupport/test/new_callback_inheritance_test.rb
new file mode 100644
index 0000000000..95020389b0
--- /dev/null
+++ b/activesupport/test/new_callback_inheritance_test.rb
@@ -0,0 +1,115 @@
+require 'test/unit'
+$:.unshift "#{File.dirname(__FILE__)}/../lib"
+require 'active_support'
+
+class GrandParent
+ include ActiveSupport::NewCallbacks
+
+ attr_reader :log, :action_name
+ def initialize(action_name)
+ @action_name, @log = action_name, []
+ end
+
+ define_callbacks :dispatch
+ dispatch_callback :before, :before1, :before2, :per_key => {:if => proc {|c| c.action_name == "index" || c.action_name == "update" }}
+ dispatch_callback :after, :after1, :after2, :per_key => {:if => proc {|c| c.action_name == "update" || c.action_name == "delete" }}
+
+ def before1
+ @log << "before1"
+ end
+
+ def before2
+ @log << "before2"
+ end
+
+ def after1
+ @log << "after1"
+ end
+
+ def after2
+ @log << "after2"
+ end
+
+ def dispatch
+ _run_dispatch_callbacks(action_name) do
+ @log << action_name
+ end
+ self
+ end
+end
+
+class Parent < GrandParent
+ skip_dispatch_callback :before, :before2, :per_key => {:unless => proc {|c| c.action_name == "update" }}
+ skip_dispatch_callback :after, :after2, :per_key => {:unless => proc {|c| c.action_name == "delete" }}
+end
+
+class Child < GrandParent
+ skip_dispatch_callback :before, :before2, :per_key => {:unless => proc {|c| c.action_name == "update" }}, :if => :state_open?
+
+ def state_open?
+ @state == :open
+ end
+
+ def initialize(action_name, state)
+ super(action_name)
+ @state = state
+ end
+end
+
+
+class BasicCallbacksTest < Test::Unit::TestCase
+ def setup
+ @index = GrandParent.new("index").dispatch
+ @update = GrandParent.new("update").dispatch
+ @delete = GrandParent.new("delete").dispatch
+ @unknown = GrandParent.new("unknown").dispatch
+ end
+
+ def test_basic_per_key1
+ assert_equal %w(before1 before2 index), @index.log
+ end
+
+ def test_basic_per_key2
+ assert_equal %w(before1 before2 update after2 after1), @update.log
+ end
+
+ def test_basic_per_key3
+ assert_equal %w(delete after2 after1), @delete.log
+ end
+end
+
+class InheritedCallbacksTest < Test::Unit::TestCase
+ def setup
+ @index = Parent.new("index").dispatch
+ @update = Parent.new("update").dispatch
+ @delete = Parent.new("delete").dispatch
+ @unknown = Parent.new("unknown").dispatch
+ end
+
+ def test_inherited_excluded
+ assert_equal %w(before1 index), @index.log
+ end
+
+ def test_inherited_not_excluded
+ assert_equal %w(before1 before2 update after1), @update.log
+ end
+
+ def test_partially_excluded
+ assert_equal %w(delete after2 after1), @delete.log
+ end
+end
+
+class InheritedCallbacksTest2 < Test::Unit::TestCase
+ def setup
+ @update1 = Child.new("update", :open).dispatch
+ @update2 = Child.new("update", :closed).dispatch
+ end
+
+ def test_crazy_mix_on
+ assert_equal %w(before1 update after2 after1), @update1.log
+ end
+
+ def test_crazy_mix_off
+ assert_equal %w(before1 before2 update after2 after1), @update2.log
+ end
+end \ No newline at end of file
diff --git a/activesupport/test/new_callbacks_test.rb b/activesupport/test/new_callbacks_test.rb
new file mode 100644
index 0000000000..5cde078b65
--- /dev/null
+++ b/activesupport/test/new_callbacks_test.rb
@@ -0,0 +1,384 @@
+# require 'abstract_unit'
+require 'test/unit'
+$:.unshift "#{File.dirname(__FILE__)}/../lib"
+require 'active_support'
+
+module NewCallbacksTest
+ class Record
+ include ActiveSupport::NewCallbacks
+
+ define_callbacks :save
+
+ def self.before_save(*filters, &blk)
+ save_callback(:before, *filters, &blk)
+ end
+
+ def self.after_save(*filters, &blk)
+ save_callback(:after, *filters, &blk)
+ end
+
+ class << self
+ def callback_symbol(callback_method)
+ returning(:"#{callback_method}_method") do |method_name|
+ define_method(method_name) do
+ history << [callback_method, :symbol]
+ end
+ end
+ end
+
+ def callback_string(callback_method)
+ "history << [#{callback_method.to_sym.inspect}, :string]"
+ end
+
+ def callback_proc(callback_method)
+ Proc.new { |model| model.history << [callback_method, :proc] }
+ end
+
+ def callback_object(callback_method)
+ klass = Class.new
+ klass.send(:define_method, callback_method) do |model|
+ model.history << [callback_method, :object]
+ end
+ klass.new
+ end
+ end
+
+ def history
+ @history ||= []
+ end
+ end
+
+ class Person < Record
+ [:before_save, :after_save].each do |callback_method|
+ callback_method_sym = callback_method.to_sym
+ send(callback_method, callback_symbol(callback_method_sym))
+ send(callback_method, callback_string(callback_method_sym))
+ send(callback_method, callback_proc(callback_method_sym))
+ send(callback_method, callback_object(callback_method_sym))
+ send(callback_method) { |model| model.history << [callback_method_sym, :block] }
+ end
+
+ def save
+ _run_save_callbacks {}
+ end
+ end
+
+ class PersonSkipper < Person
+ skip_save_callback :before, :before_save_method, :if => :yes
+ skip_save_callback :after, :before_save_method, :unless => :yes
+ skip_save_callback :after, :before_save_method, :if => :no
+ skip_save_callback :before, :before_save_method, :unless => :no
+ def yes; true; end
+ def no; false; end
+ end
+
+ class ParentController
+ include ActiveSupport::NewCallbacks
+
+ define_callbacks :dispatch
+
+ dispatch_callback :before, :log, :per_key => {:unless => proc {|c| c.action_name == :index || c.action_name == :show }}
+ dispatch_callback :after, :log2
+
+ attr_reader :action_name, :logger
+ def initialize(action_name)
+ @action_name, @logger = action_name, []
+ end
+
+ def log
+ @logger << action_name
+ end
+
+ def log2
+ @logger << action_name
+ end
+
+ def dispatch
+ _run_dispatch_callbacks(action_name) {
+ @logger << "Done"
+ }
+ self
+ end
+ end
+
+ class Child < ParentController
+ skip_dispatch_callback :before, :log, :per_key => {:if => proc {|c| c.action_name == :update} }
+ skip_dispatch_callback :after, :log2
+ end
+
+ class OneTimeCompile < Record
+ @@starts_true, @@starts_false = true, false
+
+ def initialize
+ super
+ end
+
+ before_save Proc.new {|r| r.history << [:before_save, :starts_true, :if] }, :per_key => {:if => :starts_true}
+ before_save Proc.new {|r| r.history << [:before_save, :starts_false, :if] }, :per_key => {:if => :starts_false}
+ before_save Proc.new {|r| r.history << [:before_save, :starts_true, :unless] }, :per_key => {:unless => :starts_true}
+ before_save Proc.new {|r| r.history << [:before_save, :starts_false, :unless] }, :per_key => {:unless => :starts_false}
+
+ def starts_true
+ if @@starts_true
+ @@starts_true = false
+ return true
+ end
+ @@starts_true
+ end
+
+ def starts_false
+ unless @@starts_false
+ @@starts_false = true
+ return false
+ end
+ @@starts_false
+ end
+
+ def save
+ _run_save_callbacks(:action) {}
+ end
+ end
+
+ class OneTimeCompileTest < Test::Unit::TestCase
+ def test_optimized_first_compile
+ around = OneTimeCompile.new
+ around.save
+ assert_equal [
+ [:before_save, :starts_true, :if],
+ [:before_save, :starts_true, :unless]
+ ], around.history
+ end
+ end
+
+ class ConditionalPerson < Record
+ # proc
+ before_save Proc.new { |r| r.history << [:before_save, :proc] }, :if => Proc.new { |r| true }
+ before_save Proc.new { |r| r.history << "b00m" }, :if => Proc.new { |r| false }
+ before_save Proc.new { |r| r.history << [:before_save, :proc] }, :unless => Proc.new { |r| false }
+ before_save Proc.new { |r| r.history << "b00m" }, :unless => Proc.new { |r| true }
+ # symbol
+ before_save Proc.new { |r| r.history << [:before_save, :symbol] }, :if => :yes
+ before_save Proc.new { |r| r.history << "b00m" }, :if => :no
+ before_save Proc.new { |r| r.history << [:before_save, :symbol] }, :unless => :no
+ before_save Proc.new { |r| r.history << "b00m" }, :unless => :yes
+ # string
+ before_save Proc.new { |r| r.history << [:before_save, :string] }, :if => 'yes'
+ before_save Proc.new { |r| r.history << "b00m" }, :if => 'no'
+ before_save Proc.new { |r| r.history << [:before_save, :string] }, :unless => 'no'
+ before_save Proc.new { |r| r.history << "b00m" }, :unless => 'yes'
+ # Combined if and unless
+ before_save Proc.new { |r| r.history << [:before_save, :combined_symbol] }, :if => :yes, :unless => :no
+ before_save Proc.new { |r| r.history << "b00m" }, :if => :yes, :unless => :yes
+
+ def yes; true; end
+ def other_yes; true; end
+ def no; false; end
+ def other_no; false; end
+
+ def save
+ _run_save_callbacks {}
+ end
+ end
+
+ class MySuper
+ include ActiveSupport::NewCallbacks
+ define_callbacks :save
+ end
+
+ class AroundPerson < MySuper
+ attr_reader :history
+
+ save_callback :before, :nope, :if => :no
+ save_callback :before, :nope, :unless => :yes
+ save_callback :after, :tweedle
+ save_callback :before, "tweedle_dee"
+ save_callback :before, proc {|m| m.history << "yup" }
+ save_callback :before, :nope, :if => proc { false }
+ save_callback :before, :nope, :unless => proc { true }
+ save_callback :before, :yup, :if => proc { true }
+ save_callback :before, :yup, :unless => proc { false }
+ save_callback :around, :tweedle_dum
+ save_callback :around, :w0tyes, :if => :yes
+ save_callback :around, :w0tno, :if => :no
+ save_callback :around, :tweedle_deedle
+
+ def no; false; end
+ def yes; true; end
+
+ def nope
+ @history << "boom"
+ end
+
+ def yup
+ @history << "yup"
+ end
+
+ def w0tyes
+ @history << "w0tyes before"
+ yield
+ @history << "w0tyes after"
+ end
+
+ def w0tno
+ @history << "boom"
+ yield
+ end
+
+ def tweedle_dee
+ @history << "tweedle dee"
+ end
+
+ def tweedle_dum
+ @history << "tweedle dum pre"
+ yield
+ @history << "tweedle dum post"
+ end
+
+ def tweedle
+ @history << "tweedle"
+ end
+
+ def tweedle_deedle
+ @history << "tweedle deedle pre"
+ yield
+ @history << "tweedle deedle post"
+ end
+
+ def initialize
+ @history = []
+ end
+
+ def save
+ _run_save_callbacks do
+ @history << "running"
+ end
+ end
+ end
+
+ class AroundCallbacksTest < Test::Unit::TestCase
+ def test_save_around
+ around = AroundPerson.new
+ around.save
+ assert_equal [
+ "tweedle dee",
+ "yup", "yup",
+ "tweedle dum pre",
+ "w0tyes before",
+ "tweedle deedle pre",
+ "running",
+ "tweedle deedle post",
+ "w0tyes after",
+ "tweedle dum post",
+ "tweedle"
+ ], around.history
+ end
+ end
+
+ class SkipCallbacksTest < Test::Unit::TestCase
+ def test_skip_person
+ person = PersonSkipper.new
+ assert_equal [], person.history
+ person.save
+ assert_equal [
+ [:before_save, :string],
+ [:before_save, :proc],
+ [:before_save, :object],
+ [:before_save, :block],
+ [:after_save, :block],
+ [:after_save, :object],
+ [:after_save, :proc],
+ [:after_save, :string],
+ [:after_save, :symbol]
+ ], person.history
+ end
+ end
+
+ class CallbacksTest < Test::Unit::TestCase
+ def test_save_person
+ person = Person.new
+ assert_equal [], person.history
+ person.save
+ assert_equal [
+ [:before_save, :symbol],
+ [:before_save, :string],
+ [:before_save, :proc],
+ [:before_save, :object],
+ [:before_save, :block],
+ [:after_save, :block],
+ [:after_save, :object],
+ [:after_save, :proc],
+ [:after_save, :string],
+ [:after_save, :symbol]
+ ], person.history
+ end
+ end
+
+ class ConditionalCallbackTest < Test::Unit::TestCase
+ def test_save_conditional_person
+ person = ConditionalPerson.new
+ person.save
+ assert_equal [
+ [:before_save, :proc],
+ [:before_save, :proc],
+ [:before_save, :symbol],
+ [:before_save, :symbol],
+ [:before_save, :string],
+ [:before_save, :string],
+ [:before_save, :combined_symbol],
+ ], person.history
+ end
+ end
+
+ class CallbackTerminator
+ include ActiveSupport::NewCallbacks
+
+ define_callbacks :save, "result == :halt"
+
+ save_callback :before, :first
+ save_callback :before, :second
+ save_callback :around, :around_it
+ save_callback :before, :third
+ save_callback :after, :first
+ save_callback :around, :around_it
+ save_callback :after, :second
+ save_callback :around, :around_it
+ save_callback :after, :third
+
+
+ attr_reader :history
+ def initialize
+ @history = []
+ end
+
+ def around_it
+ @history << "around1"
+ yield
+ @history << "around2"
+ end
+
+ def first
+ @history << "first"
+ end
+
+ def second
+ @history << "second"
+ :halt
+ end
+
+ def third
+ @history << "third"
+ end
+
+ def save
+ _run_save_callbacks
+ end
+ end
+
+ class CallbackTerminatorTest < Test::Unit::TestCase
+ def test_termination
+ terminator = CallbackTerminator.new
+ terminator.save
+ assert_equal ["first", "second", "third", "second", "first"], terminator.history
+ end
+ end
+end \ No newline at end of file
diff --git a/ci/cruise_config.rb b/ci/cruise_config.rb
index 325c21397e..7985e3c8df 100644
--- a/ci/cruise_config.rb
+++ b/ci/cruise_config.rb
@@ -1,6 +1,6 @@
Project.configure do |project|
project.build_command = 'ruby ci/ci_build.rb'
-# project.email_notifier.emails = ['thewoolleyman@gmail.com']
- project.email_notifier.emails = ['thewoolleyman@gmail.com','michael@koziarski.com', 'david@loudthinking.com', 'jeremy@bitsweat.net', 'josh@joshpeek.com', 'pratiknaik@gmail.com', 'wycats@gmail.com']
+ project.email_notifier.emails = ['thewoolleyman@gmail.com']
+# project.email_notifier.emails = ['thewoolleyman@gmail.com','michael@koziarski.com', 'david@loudthinking.com', 'jeremy@bitsweat.net', 'josh@joshpeek.com', 'pratiknaik@gmail.com', 'wycats@gmail.com']
project.email_notifier.from = 'thewoolleyman+railsci@gmail.com'
end
diff --git a/railties/environments/production.rb b/railties/environments/production.rb
index 27119d2d18..1fc9f6b923 100644
--- a/railties/environments/production.rb
+++ b/railties/environments/production.rb
@@ -7,7 +7,6 @@ config.cache_classes = true
# Full error reports are disabled and caching is turned on
config.action_controller.consider_all_requests_local = false
config.action_controller.perform_caching = true
-config.action_view.cache_template_loading = true
# See everything in the log (default is :info)
# config.log_level = :debug
diff --git a/railties/environments/test.rb b/railties/environments/test.rb
index d6f80a4080..496eb9572b 100644
--- a/railties/environments/test.rb
+++ b/railties/environments/test.rb
@@ -12,7 +12,6 @@ config.whiny_nils = true
# Show full error reports and disable caching
config.action_controller.consider_all_requests_local = true
config.action_controller.perform_caching = false
-config.action_view.cache_template_loading = true
# Disable request forgery protection in test environment
config.action_controller.allow_forgery_protection = false
diff --git a/railties/lib/dispatcher.rb b/railties/lib/dispatcher.rb
index 9f8b59aa3d..7f9a6221d9 100644
--- a/railties/lib/dispatcher.rb
+++ b/railties/lib/dispatcher.rb
@@ -20,5 +20,5 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
-require 'action_controller/dispatcher'
+require 'action_controller/dispatch/dispatcher'
Dispatcher = ActionController::Dispatcher
diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb
index a04405a7c2..8eb4212737 100644
--- a/railties/lib/initializer.rb
+++ b/railties/lib/initializer.rb
@@ -378,8 +378,11 @@ Run `rake gems:install` to install the missing gems.
def load_view_paths
if configuration.frameworks.include?(:action_view)
- ActionController::Base.view_paths.load! if configuration.frameworks.include?(:action_controller)
- ActionMailer::Base.view_paths.load! if configuration.frameworks.include?(:action_mailer)
+ if configuration.cache_classes
+ view_path = ActionView::Template::EagerPath.new(configuration.view_path)
+ ActionController::Base.view_paths = view_path if configuration.frameworks.include?(:action_controller)
+ ActionMailer::Base.template_root = view_path if configuration.frameworks.include?(:action_mailer)
+ end
end
end
diff --git a/railties/test/initializer_test.rb b/railties/test/initializer_test.rb
index 561f7b8b54..d77a045e56 100644
--- a/railties/test/initializer_test.rb
+++ b/railties/test/initializer_test.rb
@@ -351,7 +351,7 @@ class InitializerDatabaseMiddlewareTest < Test::Unit::TestCase
def test_database_middleware_doesnt_initialize_when_session_store_is_not_active_record
store = ActionController::Base.session_store
- ActionController::Base.session_store = ActionController::Session::CookieStore
+ ActionController::Base.session_store = ActionDispatch::Session::CookieStore
# Define the class, so we don't have to actually make it load
eval("class ActiveRecord::ConnectionAdapters::ConnectionManagement; end")
@@ -380,12 +380,6 @@ class InitializerViewPathsTest < Test::Unit::TestCase
ActionMailer::Base.view_paths.expects(:load!).never
Rails::Initializer.run(:load_view_paths, @config)
end
-
- def test_load_view_paths_loads_view_paths
- ActionController::Base.view_paths.expects(:load!)
- ActionMailer::Base.view_paths.expects(:load!)
- Rails::Initializer.run(:load_view_paths, @config)
- end
end
class RailsRootTest < Test::Unit::TestCase
diff --git a/railties/test/rails_info_controller_test.rb b/railties/test/rails_info_controller_test.rb
index 607ece99a9..ab31f3a487 100644
--- a/railties/test/rails_info_controller_test.rb
+++ b/railties/test/rails_info_controller_test.rb
@@ -1,6 +1,6 @@
require 'abstract_unit'
require 'action_controller'
-require 'action_controller/test_process'
+require 'action_controller/testing/process'
require 'rails/info'
require 'rails/info_controller'