aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore8
-rw-r--r--.gitmodules6
-rw-r--r--Gemfile15
-rw-r--r--Rakefile15
-rw-r--r--actionmailer/CHANGELOG9
-rw-r--r--actionmailer/Rakefile1
-rw-r--r--actionmailer/lib/action_mailer.rb39
-rw-r--r--actionmailer/lib/action_mailer/adv_attr_accessor.rb32
-rw-r--r--actionmailer/lib/action_mailer/base.rb234
-rw-r--r--actionmailer/lib/action_mailer/delivery_method.rb5
-rw-r--r--actionmailer/lib/action_mailer/delivery_method/file.rb2
-rw-r--r--actionmailer/lib/action_mailer/delivery_method/smtp.rb4
-rw-r--r--actionmailer/lib/action_mailer/deprecated_body.rb8
-rw-r--r--actionmailer/lib/action_mailer/mail_helper.rb33
-rw-r--r--actionmailer/lib/action_mailer/rails.rb24
-rw-r--r--actionmailer/lib/action_mailer/test_case.rb1
-rw-r--r--actionmailer/test/abstract_unit.rb7
-rw-r--r--actionmailer/test/adv_attr_test.rb32
-rw-r--r--actionmailer/test/asset_host_test.rb6
-rw-r--r--actionmailer/test/mail_helper_test.rb2
-rw-r--r--actionmailer/test/mail_layout_test.rb22
-rw-r--r--actionmailer/test/mail_render_test.rb57
-rw-r--r--actionmailer/test/mail_service_test.rb96
-rw-r--r--actionmailer/test/mail_test.rb (renamed from actionmailer/test/tmail_test.rb)6
-rw-r--r--actionmailer/test/quoting_test.rb2
-rw-r--r--actionmailer/test/test_helper_test.rb6
-rw-r--r--actionmailer/test/url_test.rb54
-rw-r--r--actionpack/CHANGELOG14
-rw-r--r--actionpack/Rakefile2
-rw-r--r--actionpack/actionpack.gemspec4
-rw-r--r--actionpack/lib/abstract_controller.rb28
-rw-r--r--actionpack/lib/abstract_controller/base.rb15
-rw-r--r--actionpack/lib/abstract_controller/exceptions.rb12
-rw-r--r--actionpack/lib/abstract_controller/helpers.rb2
-rw-r--r--actionpack/lib/abstract_controller/layouts.rb2
-rw-r--r--actionpack/lib/abstract_controller/logger.rb28
-rw-r--r--actionpack/lib/abstract_controller/rendering.rb (renamed from actionpack/lib/abstract_controller/rendering_controller.rb)37
-rw-r--r--actionpack/lib/action_controller.rb122
-rw-r--r--actionpack/lib/action_controller/base.rb72
-rw-r--r--actionpack/lib/action_controller/caching.rb13
-rw-r--r--actionpack/lib/action_controller/dispatch/dispatcher.rb5
-rw-r--r--actionpack/lib/action_controller/metal.rb9
-rw-r--r--actionpack/lib/action_controller/metal/benchmarking.rb1
-rw-r--r--actionpack/lib/action_controller/metal/compatibility.rb7
-rw-r--r--actionpack/lib/action_controller/metal/conditional_get.rb2
-rw-r--r--actionpack/lib/action_controller/metal/cookies.rb170
-rw-r--r--actionpack/lib/action_controller/metal/exceptions.rb11
-rw-r--r--actionpack/lib/action_controller/metal/flash.rb58
-rw-r--r--actionpack/lib/action_controller/metal/head.rb7
-rw-r--r--actionpack/lib/action_controller/metal/helpers.rb2
-rw-r--r--actionpack/lib/action_controller/metal/layouts.rb2
-rw-r--r--actionpack/lib/action_controller/metal/logger.rb34
-rw-r--r--actionpack/lib/action_controller/metal/rack_delegation.rb (renamed from actionpack/lib/action_controller/metal/rack_convenience.rb)10
-rw-r--r--actionpack/lib/action_controller/metal/redirecting.rb90
-rw-r--r--actionpack/lib/action_controller/metal/redirector.rb22
-rw-r--r--actionpack/lib/action_controller/metal/render_options.rb103
-rw-r--r--actionpack/lib/action_controller/metal/renderers.rb91
-rw-r--r--actionpack/lib/action_controller/metal/rendering.rb (renamed from actionpack/lib/action_controller/metal/rendering_controller.rb)4
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb32
-rw-r--r--actionpack/lib/action_controller/metal/rescue.rb (renamed from actionpack/lib/action_controller/metal/rescuable.rb)0
-rw-r--r--actionpack/lib/action_controller/metal/responder.rb20
-rw-r--r--actionpack/lib/action_controller/metal/session.rb15
-rw-r--r--actionpack/lib/action_controller/metal/streaming.rb2
-rw-r--r--actionpack/lib/action_controller/metal/testing.rb2
-rw-r--r--actionpack/lib/action_controller/metal/url_for.rb2
-rw-r--r--actionpack/lib/action_controller/metal/verification.rb70
-rw-r--r--actionpack/lib/action_controller/notifications.rb10
-rw-r--r--actionpack/lib/action_controller/rails.rb102
-rw-r--r--actionpack/lib/action_controller/test_case.rb (renamed from actionpack/lib/action_controller/testing/test_case.rb)3
-rw-r--r--actionpack/lib/action_controller/testing/process.rb111
-rw-r--r--actionpack/lib/action_controller/vendor/html-scanner.rb28
-rw-r--r--actionpack/lib/action_dispatch.rb55
-rwxr-xr-xactionpack/lib/action_dispatch/http/request.rb14
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb41
-rw-r--r--actionpack/lib/action_dispatch/http/status_codes.rb42
-rw-r--r--actionpack/lib/action_dispatch/http/utils.rb20
-rw-r--r--actionpack/lib/action_dispatch/middleware/cascade.rb29
-rw-r--r--actionpack/lib/action_dispatch/middleware/params_parser.rb47
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/abstract_store.rb1
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/cookie_store.rb9
-rw-r--r--actionpack/lib/action_dispatch/middleware/show_exceptions.rb16
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb2
-rw-r--r--actionpack/lib/action_dispatch/routing.rb107
-rw-r--r--actionpack/lib/action_dispatch/routing/deprecated_mapper.rb5
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb616
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb201
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/dom.rb4
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/response.rb2
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/routing.rb48
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/selector.rb22
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/tag.rb21
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb12
-rw-r--r--actionpack/lib/action_dispatch/testing/performance_test.rb24
-rw-r--r--actionpack/lib/action_dispatch/testing/test_process.rb42
-rw-r--r--actionpack/lib/action_view.rb56
-rw-r--r--actionpack/lib/action_view/base.rb2
-rw-r--r--actionpack/lib/action_view/helpers/sanitize_helper.rb1
-rw-r--r--actionpack/lib/action_view/helpers/translation_helper.rb2
-rw-r--r--actionpack/lib/action_view/paths.rb2
-rw-r--r--actionpack/lib/action_view/render/partials.rb20
-rw-r--r--actionpack/lib/action_view/render/rendering.rb22
-rw-r--r--actionpack/lib/action_view/safe_buffer.rb1
-rw-r--r--actionpack/lib/action_view/template.rb (renamed from actionpack/lib/action_view/template/template.rb)32
-rw-r--r--actionpack/lib/action_view/template/error.rb156
-rw-r--r--actionpack/lib/action_view/template/handler.rb47
-rw-r--r--actionpack/lib/action_view/template/handlers.rb96
-rw-r--r--actionpack/lib/action_view/template/handlers/builder.rb4
-rw-r--r--actionpack/lib/action_view/template/handlers/erb.rb7
-rw-r--r--actionpack/lib/action_view/template/handlers/rjs.rb4
-rw-r--r--actionpack/lib/action_view/template/resolver.rb6
-rw-r--r--actionpack/lib/action_view/template/text.rb70
-rw-r--r--actionpack/lib/action_view/test_case.rb5
-rw-r--r--actionpack/test/abstract/abstract_controller_test.rb2
-rw-r--r--actionpack/test/abstract/helper_test.rb2
-rw-r--r--actionpack/test/abstract/layouts_test.rb28
-rw-r--r--actionpack/test/abstract/localized_cache_test.rb2
-rw-r--r--actionpack/test/abstract/render_test.rb4
-rw-r--r--actionpack/test/abstract_unit.rb31
-rw-r--r--actionpack/test/active_record_unit.rb8
-rw-r--r--actionpack/test/activerecord/active_record_store_test.rb2
-rw-r--r--actionpack/test/controller/action_pack_assertions_test.rb22
-rw-r--r--actionpack/test/controller/base_test.rb6
-rw-r--r--actionpack/test/controller/caching_test.rb12
-rw-r--r--actionpack/test/controller/cookie_test.rb35
-rw-r--r--actionpack/test/controller/dispatcher_test.rb13
-rw-r--r--actionpack/test/controller/flash_test.rb45
-rw-r--r--actionpack/test/controller/helper_test.rb2
-rw-r--r--actionpack/test/controller/layout_test.rb2
-rw-r--r--actionpack/test/controller/mime_responds_test.rb67
-rw-r--r--actionpack/test/controller/redirect_test.rb4
-rw-r--r--actionpack/test/controller/render_other_test.rb14
-rw-r--r--actionpack/test/controller/render_test.rb36
-rw-r--r--actionpack/test/controller/render_xml_test.rb4
-rw-r--r--actionpack/test/controller/resources_test.rb8
-rw-r--r--actionpack/test/controller/routing_test.rb336
-rw-r--r--actionpack/test/controller/test_test.rb25
-rw-r--r--actionpack/test/controller/url_rewriter_test.rb10
-rw-r--r--actionpack/test/controller/webservice_test.rb4
-rw-r--r--actionpack/test/dispatch/request/multipart_params_parsing_test.rb2
-rw-r--r--actionpack/test/dispatch/response_test.rb121
-rw-r--r--actionpack/test/dispatch/routing_test.rb165
-rw-r--r--actionpack/test/dispatch/test_request_test.rb2
-rw-r--r--actionpack/test/lib/controller/fake_controllers.rb13
-rw-r--r--actionpack/test/template/ajax_test.rb12
-rw-r--r--actionpack/test/template/atom_feed_helper_test.rb12
-rw-r--r--actionpack/test/template/render_test.rb8
-rw-r--r--actionpack/test/template/test_case_test.rb4
-rw-r--r--actionpack/test/template/translation_helper_test.rb4
-rw-r--r--actionpack/test/template/url_helper_test.rb51
-rwxr-xr-xactivemodel/Rakefile1
-rw-r--r--activemodel/lib/active_model.rb48
-rw-r--r--activemodel/lib/active_model/attribute_methods.rb4
-rw-r--r--activemodel/lib/active_model/validations.rb1
-rw-r--r--activemodel/test/cases/helper.rb7
-rw-r--r--activemodel/test/cases/tests_database.rb1
-rw-r--r--activerecord/CHANGELOG60
-rw-r--r--activerecord/lib/active_record.rb141
-rwxr-xr-xactiverecord/lib/active_record/associations.rb14
-rw-r--r--activerecord/lib/active_record/associations/association_collection.rb19
-rw-r--r--activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb2
-rw-r--r--activerecord/lib/active_record/associations/has_many_association.rb2
-rw-r--r--activerecord/lib/active_record/autosave_association.rb4
-rwxr-xr-xactiverecord/lib/active_record/base.rb179
-rw-r--r--activerecord/lib/active_record/calculations.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql_adapter.rb15
-rw-r--r--activerecord/lib/active_record/named_scope.rb38
-rw-r--r--activerecord/lib/active_record/notifications.rb5
-rw-r--r--activerecord/lib/active_record/rails.rb59
-rw-r--r--activerecord/lib/active_record/relation.rb253
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb1
-rw-r--r--activerecord/test/cases/associations/has_many_through_associations_test.rb8
-rw-r--r--activerecord/test/cases/associations_test.rb10
-rwxr-xr-xactiverecord/test/cases/base_test.rb18
-rw-r--r--activerecord/test/cases/batches_test.rb2
-rw-r--r--activerecord/test/cases/dirty_test.rb2
-rw-r--r--activerecord/test/cases/finder_test.rb59
-rw-r--r--activerecord/test/cases/helper.rb6
-rw-r--r--activerecord/test/cases/migration_test.rb47
-rw-r--r--activerecord/test/cases/named_scope_test.rb4
-rw-r--r--activerecord/test/cases/relations_test.rb231
-rw-r--r--activerecord/test/cases/yaml_serialization_test.rb11
-rw-r--r--activeresource/Rakefile3
-rw-r--r--activeresource/lib/active_resource.rb28
-rw-r--r--activeresource/lib/active_resource/base.rb143
-rw-r--r--activeresource/lib/active_resource/schema.rb55
-rw-r--r--activeresource/test/abstract_unit.rb9
-rw-r--r--activeresource/test/cases/base/schema_test.rb420
-rw-r--r--activeresource/test/cases/base_test.rb6
-rw-r--r--activesupport/CHANGELOG2
-rw-r--r--activesupport/Rakefile1
-rw-r--r--activesupport/lib/active_support.rb36
-rw-r--r--activesupport/lib/active_support/autoload.rb28
-rw-r--r--activesupport/lib/active_support/core_ext/class/removal.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/date/calculations.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/date/conversions.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/conversions.rb15
-rw-r--r--activesupport/lib/active_support/core_ext/enumerable.rb5
-rw-r--r--activesupport/lib/active_support/core_ext/logger.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/object/extending.rb73
-rw-r--r--activesupport/lib/active_support/core_ext/object/to_param.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/object/to_query.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb36
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb1
-rw-r--r--activesupport/lib/active_support/dependencies/autoload.rb49
-rw-r--r--activesupport/lib/active_support/json/encoding.rb13
-rw-r--r--activesupport/lib/active_support/notifications.rb168
-rw-r--r--activesupport/lib/active_support/notifications/fanout.rb101
-rw-r--r--activesupport/lib/active_support/notifications/instrumenter.rb47
-rw-r--r--activesupport/lib/active_support/ruby/shim.rb1
-rw-r--r--activesupport/lib/active_support/testing/isolation.rb15
-rw-r--r--activesupport/lib/active_support/testing/performance.rb678
-rw-r--r--activesupport/lib/active_support/vendor.rb2
-rwxr-xr-xactivesupport/lib/active_support/vendor/i18n-0.1.3/MIT-LICENSE20
-rw-r--r--activesupport/lib/active_support/vendor/i18n-0.1.3/README.textile20
-rw-r--r--activesupport/lib/active_support/vendor/i18n-0.1.3/Rakefile5
-rw-r--r--activesupport/lib/active_support/vendor/i18n-0.1.3/i18n.gemspec27
-rwxr-xr-xactivesupport/lib/active_support/vendor/i18n-0.1.3/lib/i18n.rb204
-rw-r--r--activesupport/lib/active_support/vendor/i18n-0.1.3/lib/i18n/backend/simple.rb215
-rw-r--r--activesupport/lib/active_support/vendor/i18n-0.1.3/lib/i18n/exceptions.rb53
-rw-r--r--activesupport/lib/active_support/vendor/i18n-0.1.3/test/all.rb5
-rw-r--r--activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_exceptions_test.rb99
-rw-r--r--activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_test.rb124
-rw-r--r--activesupport/lib/active_support/vendor/i18n-0.1.3/test/locale/en.rb1
-rw-r--r--activesupport/lib/active_support/vendor/i18n-0.1.3/test/locale/en.yml3
-rw-r--r--activesupport/lib/active_support/vendor/i18n-0.1.3/test/simple_backend_test.rb567
-rw-r--r--activesupport/lib/active_support/whiny_nil.rb5
-rw-r--r--activesupport/test/autoload.rb80
-rw-r--r--activesupport/test/core_ext/date_time_ext_test.rb4
-rw-r--r--activesupport/test/core_ext/enumerable_test.rb5
-rw-r--r--activesupport/test/core_ext/object/to_query_test.rb8
-rw-r--r--activesupport/test/core_ext/time_with_zone_test.rb6
-rw-r--r--activesupport/test/deprecation_test.rb2
-rw-r--r--activesupport/test/fixtures/autoload/another_class.rb2
-rw-r--r--activesupport/test/fixtures/autoload/some_class.rb2
-rw-r--r--activesupport/test/json/encoding_test.rb4
-rw-r--r--activesupport/test/notifications_test.rb293
-rw-r--r--activesupport/test/whiny_nil_test.rb13
-rw-r--r--ci/geminstaller.yml2
m---------rack0
m---------rack-mount0
-rw-r--r--rails.gemspec (renamed from railties/rails.gemspec)12
-rw-r--r--railties/CHANGELOG18
-rw-r--r--railties/Rakefile9
-rwxr-xr-xrailties/bin/rails7
-rw-r--r--railties/builtin/routes.rb3
-rw-r--r--railties/lib/rails.rb20
-rw-r--r--railties/lib/rails/application.rb280
-rw-r--r--railties/lib/rails/commands/console.rb89
-rw-r--r--railties/lib/rails/commands/dbconsole.rb171
-rw-r--r--railties/lib/rails/commands/server.rb119
-rw-r--r--railties/lib/rails/configuration.rb97
-rw-r--r--railties/lib/rails/console_app.rb2
-rw-r--r--railties/lib/rails/core.rb34
-rw-r--r--railties/lib/rails/generators.rb7
-rw-r--r--railties/lib/rails/generators/actions.rb6
-rw-r--r--railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb2
-rw-r--r--railties/lib/rails/generators/rails/app/app_generator.rb20
-rwxr-xr-xrailties/lib/rails/generators/rails/app/templates/Rakefile2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb8
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config.ru2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/application.rb62
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environment.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/development.rb17
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt19
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/production.rb31
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt33
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/test.rb27
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt29
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/cookie_verification_secret.rb.tt7
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/routes.rb57
-rwxr-xr-xrailties/lib/rails/generators/rails/app/templates/script/console.tt (renamed from railties/lib/rails/generators/rails/app/templates/script/console)1
-rwxr-xr-xrailties/lib/rails/generators/rails/app/templates/script/dbconsole.tt (renamed from railties/lib/rails/generators/rails/app/templates/script/dbconsole)1
-rwxr-xr-xrailties/lib/rails/generators/rails/app/templates/script/server2
-rwxr-xr-xrailties/lib/rails/generators/rails/app/templates/script/server.tt5
-rw-r--r--railties/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt2
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/Rakefile1
-rw-r--r--railties/lib/rails/generators/rails/resource/resource_generator.rb2
-rw-r--r--railties/lib/rails/generators/rails/scaffold/USAGE2
-rw-r--r--railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb6
-rw-r--r--railties/lib/rails/generators/test_unit/model/templates/fixtures.yml14
-rw-r--r--railties/lib/rails/initializable.rb27
-rw-r--r--railties/lib/rails/initializer.rb4
-rw-r--r--railties/lib/rails/plugin.rb27
-rw-r--r--railties/lib/rails/rack/log_tailer.rb4
-rw-r--r--railties/lib/rails/tasks.rb5
-rw-r--r--railties/lib/rails/tasks/framework.rake8
-rw-r--r--railties/lib/rails/tasks/misc.rake4
-rw-r--r--railties/lib/rails/tasks/testing.rake11
-rw-r--r--railties/lib/rails/test_help.rb10
-rw-r--r--railties/lib/rails/vendor/thor-0.12.0/lib/thor/version.rb3
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/CHANGELOG.rdoc (renamed from railties/lib/rails/vendor/thor-0.12.0/CHANGELOG.rdoc)4
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/LICENSE (renamed from railties/lib/rails/vendor/thor-0.12.0/LICENSE)0
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/README.rdoc (renamed from railties/lib/rails/vendor/thor-0.12.0/README.rdoc)20
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/Thorfile (renamed from railties/lib/rails/vendor/thor-0.12.0/Thorfile)2
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor.rb)0
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/actions.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/actions.rb)4
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/actions/create_file.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/actions/create_file.rb)0
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/actions/directory.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/actions/directory.rb)6
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/actions/empty_directory.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/actions/empty_directory.rb)0
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/actions/file_manipulation.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/actions/file_manipulation.rb)12
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/actions/inject_into_file.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/actions/inject_into_file.rb)2
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/base.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/base.rb)0
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/core_ext/hash_with_indifferent_access.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/core_ext/hash_with_indifferent_access.rb)2
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/core_ext/ordered_hash.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/core_ext/ordered_hash.rb)0
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/error.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/error.rb)0
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/group.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/group.rb)2
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/invocation.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/invocation.rb)0
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/parser.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/parser.rb)0
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/parser/argument.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/parser/argument.rb)0
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/parser/arguments.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/parser/arguments.rb)0
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/parser/option.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/parser/option.rb)2
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/parser/options.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/parser/options.rb)0
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/rake_compat.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/rake_compat.rb)0
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/runner.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/runner.rb)2
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/shell.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/shell.rb)0
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/shell/basic.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/shell/basic.rb)2
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/shell/color.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/shell/color.rb)0
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/task.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/task.rb)0
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/util.rb (renamed from railties/lib/rails/vendor/thor-0.12.0/lib/thor/util.rb)0
-rw-r--r--railties/lib/rails/vendor/thor-0.12.1/lib/thor/version.rb3
-rw-r--r--railties/railties.gemspec28
-rw-r--r--railties/test/application/configuration_test.rb69
-rw-r--r--railties/test/application/generators_test.rb44
-rw-r--r--railties/test/application/initializer_test.rb175
-rw-r--r--railties/test/application/load_test.rb30
-rw-r--r--railties/test/application/notifications_test.rb28
-rw-r--r--railties/test/application/routing_test.rb180
-rw-r--r--railties/test/fixtures/plugins/engines/engine/config/routes.rb2
-rw-r--r--railties/test/generators/actions_test.rb2
-rw-r--r--railties/test/generators/resource_generator_test.rb6
-rw-r--r--railties/test/generators/scaffold_generator_test.rb4
-rw-r--r--railties/test/initializable_test.rb10
-rw-r--r--railties/test/initializer/check_ruby_version_test.rb7
-rw-r--r--railties/test/initializer/initialize_i18n_test.rb11
-rw-r--r--railties/test/initializer/path_test.rb8
-rw-r--r--railties/test/isolation/abstract_unit.rb17
-rw-r--r--railties/test/paths_test.rb3
-rw-r--r--railties/test/plugins/configuration_test.rb36
-rw-r--r--railties/test/plugins/framework_extension_test.rb18
-rw-r--r--railties/test/rails_info_controller_test.rb8
340 files changed, 6374 insertions, 5815 deletions
diff --git a/.gitignore b/.gitignore
index 70b7c0057a..9a65e4996f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,16 +7,9 @@ activerecord/doc
actionpack/doc
actionmailer/doc
activesupport/doc
-activemodel/pkg
-activeresource/pkg
-activerecord/pkg
-actionpack/pkg
activemodel/test/fixtures/fixture_database.sqlite3
-actionmailer/pkg
-activesupport/pkg
actionpack/test/tmp
activesupport/test/fixtures/isolation_test
-railties/pkg
railties/test/500.html
railties/test/fixtures/tmp
railties/test/initializer/root/log
@@ -31,3 +24,4 @@ railties/guides/output
bin
vendor/gems/
railties/tmp
+pkg
diff --git a/.gitmodules b/.gitmodules
index 20ed3ed9c9..d0be7ff194 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,6 @@
[submodule "arel"]
path = arel
url = git://github.com/rails/arel.git
-[submodule "rack-mount"]
- path = rack-mount
- url = git://github.com/rails/rack-mount.git
+[submodule "rack"]
+ path = rack
+ url = git://github.com/rails/rack.git
diff --git a/Gemfile b/Gemfile
index 87bf43b786..8e420b1c64 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,11 +1,17 @@
gem "rake", ">= 0.8.7"
gem "mocha", ">= 0.9.8"
-gem "rails", "3.0.pre", :vendored_at => "railties"
+gem "rails", "3.0.pre", :path => "railties"
%w(activesupport activemodel actionpack actionmailer activerecord activeresource).each do |lib|
- gem lib, '3.0.pre', :vendored_at => lib
+ gem lib, '3.0.pre', :path => lib
end
+# AS
+gem "i18n", ">= 0.3.0"
+
+# AM
+gem "mail", ">= 1.4.2"
+
# AR
gem "arel", "0.2.pre", :git => "git://github.com/rails/arel.git"
gem "sqlite3-ruby", ">= 1.2.5"
@@ -13,7 +19,8 @@ gem "pg", ">= 0.8.0"
gem "mysql", ">= 2.8.1"
# AP
-gem "rack", "1.0.1", :git => "git://github.com/rails/rack.git"
+gem "rack", "1.1.0", :git => "git://github.com/rack/rack.git"
+gem "rack-test", "0.5.3"
gem "RedCloth", ">= 4.2.2"
if ENV['CI']
@@ -30,3 +37,5 @@ if ENV['CI']
gem "test-unit", ">= 2.0.5"
end
end
+
+disable_system_gems
diff --git a/Rakefile b/Rakefile
index 6aa8f61028..cda01d7d57 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,9 +1,10 @@
require 'rake'
require 'rake/rdoctask'
+require 'rake/gempackagetask'
env = %(PKG_BUILD="#{ENV['PKG_BUILD']}") if ENV['PKG_BUILD']
-PROJECTS = %w(activesupport actionpack actionmailer activeresource activerecord activemodel railties)
+PROJECTS = %w(activesupport activemodel actionpack actionmailer activeresource activerecord railties)
Dir["#{File.dirname(__FILE__)}/*/lib/*/version.rb"].each do |version_path|
require version_path
@@ -23,11 +24,21 @@ task :default => %w(test test:isolated)
end
end
+spec = eval(File.read('rails.gemspec'))
+
+Rake::GemPackageTask.new(spec) do |pkg|
+ pkg.gem_spec = spec
+end
+
task :install => :gem do
+ system %(cd arel && gem build arel.gemspec && gem install arel-0.2.pre.gem --no-ri --no-rdoc --ignore-dependencies)
+ system %(cd rack && rake gem VERSION=1.0.2.pre && gem install rack-1.0.2.pre.gem --no-ri --no-rdoc --ignore-dependencies)
(PROJECTS - ["railties"]).each do |project|
+ puts "INSTALLING #{project}"
system("gem install #{project}/pkg/#{project}-#{ActionPack::VERSION::STRING}.gem --no-ri --no-rdoc")
end
- system("gem install railties/pkg/rails-#{ActionPack::VERSION::STRING}.gem --no-ri --no-rdoc")
+ system("gem install railties/pkg/railties-#{ActionPack::VERSION::STRING}.gem --no-ri --no-rdoc")
+ system("gem install pkg/rails-#{ActionPack::VERSION::STRING}.gem --no-ri --no-rdoc")
end
desc "Generate documentation for the Rails framework"
diff --git a/actionmailer/CHANGELOG b/actionmailer/CHANGELOG
index 9b07686b64..dc2d5f7314 100644
--- a/actionmailer/CHANGELOG
+++ b/actionmailer/CHANGELOG
@@ -1,10 +1,17 @@
*Mail Integration
+* ActionMailer::Base :default_implicit_parts_order now is in the sequence of the order you want, no
+reversing of ordering takes place. The default order now is text/plain, then text/enriched, then
+text/html and then any other part that is not one of these three.
+
* Mail does not have "quoted_body", "quoted_subject" etc. All of these are accessed via body.encoded,
subject.encoded etc
* Every part of a Mail object returns an object, never a string. So Mail.body returns a Mail::Body
- class object, need to call #encoded or #decoded to get the string you want
+ class object, need to call #encoded or #decoded to get the string you want.
+
+* By default, a field will return the #decoded value when you send it :to_s and any object that
+ is a container (like header, body etc) will return #encoded value when you send it :to_s
* Mail::Message#set_content_type does not exist, it is simply Mail::Message#content_type
diff --git a/actionmailer/Rakefile b/actionmailer/Rakefile
index 1a7ece5068..6c19371514 100644
--- a/actionmailer/Rakefile
+++ b/actionmailer/Rakefile
@@ -23,7 +23,6 @@ task :default => [ :test ]
Rake::TestTask.new { |t|
t.libs << "test"
t.pattern = 'test/*_test.rb'
- t.verbose = true
t.warning = true
}
diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb
index 0ca08e4d1f..55ddbb24f4 100644
--- a/actionmailer/lib/action_mailer.rb
+++ b/actionmailer/lib/action_mailer.rb
@@ -21,36 +21,27 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
-actionpack_path = "#{File.dirname(__FILE__)}/../../actionpack/lib"
-$:.unshift(actionpack_path) if File.directory?(actionpack_path)
+actionpack_path = File.expand_path('../../../actionpack/lib', __FILE__)
+$:.unshift(actionpack_path) if File.directory?(actionpack_path) && !$:.include?(actionpack_path)
+
require 'action_controller'
require 'action_view'
module ActionMailer
- def self.load_all!
- [Base, Part, ::Text::Format, ::Net::SMTP]
- end
-
- autoload :AdvAttrAccessor, 'action_mailer/adv_attr_accessor'
- autoload :DeprecatedBody, 'action_mailer/deprecated_body'
- autoload :Base, 'action_mailer/base'
- autoload :DeliveryMethod, 'action_mailer/delivery_method'
- autoload :Part, 'action_mailer/part'
- autoload :PartContainer, 'action_mailer/part_container'
- autoload :Quoting, 'action_mailer/quoting'
- autoload :TestCase, 'action_mailer/test_case'
- autoload :TestHelper, 'action_mailer/test_helper'
-
+ extend ::ActiveSupport::Autoload
+
+ autoload :AdvAttrAccessor
+ autoload :Base
+ autoload :DeliveryMethod
+ autoload :DeprecatedBody
+ autoload :MailHelper
+ autoload :Quoting
+ autoload :TestCase
+ autoload :TestHelper
end
module Text
- autoload :Format, 'action_mailer/vendor/text_format'
-end
+ extend ActiveSupport::Autoload
-module Net
- autoload :SMTP, 'net/smtp'
+ autoload :Format, 'action_mailer/vendor/text_format'
end
-
-autoload :MailHelper, 'action_mailer/mail_helper'
-
-require 'mail'
diff --git a/actionmailer/lib/action_mailer/adv_attr_accessor.rb b/actionmailer/lib/action_mailer/adv_attr_accessor.rb
index e77029afdd..be6b1feca9 100644
--- a/actionmailer/lib/action_mailer/adv_attr_accessor.rb
+++ b/actionmailer/lib/action_mailer/adv_attr_accessor.rb
@@ -1,29 +1,25 @@
module ActionMailer
module AdvAttrAccessor #:nodoc:
- def self.included(base)
- base.extend(ClassMethods)
- end
-
- module ClassMethods #:nodoc:
- def adv_attr_accessor(*names)
- names.each do |name|
- ivar = "@#{name}"
+ def adv_attr_accessor(*names)
+ names.each do |name|
+ ivar = "@#{name}"
- define_method("#{name}=") do |value|
- instance_variable_set(ivar, value)
+ class_eval <<-ACCESSORS, __FILE__, __LINE__ + 1
+ def #{name}=(value)
+ #{ivar} = value
end
- define_method(name) do |*parameters|
- raise ArgumentError, "expected 0 or 1 parameters" unless parameters.length <= 1
- if parameters.empty?
- if instance_variable_names.include?(ivar)
- instance_variable_get(ivar)
- end
+ def #{name}(*args)
+ raise ArgumentError, "expected 0 or 1 parameters" unless args.length <= 1
+ if args.empty?
+ #{ivar} if instance_variable_names.include?(#{ivar.inspect})
else
- instance_variable_set(ivar, parameters.first)
+ #{ivar} = args.first
end
end
- end
+ ACCESSORS
+
+ self.protected_instance_variables << ivar if self.respond_to?(:protected_instance_variables)
end
end
end
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index 3639992ce9..aea2498d4d 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -1,9 +1,9 @@
require 'active_support/core_ext/class'
+require 'mail'
module ActionMailer #:nodoc:
# Action Mailer allows you to send email from your application using a mailer model and views.
#
- #
# = Mailer Models
#
# To use Action Mailer, you need to create a mailer model.
@@ -22,7 +22,8 @@ module ActionMailer #:nodoc:
# bcc ["bcc@example.com", "Order Watcher <watcher@example.com>"]
# from "system@example.com"
# subject "New account information"
- # body :account => recipient
+ #
+ # @account = recipient
# end
# end
#
@@ -42,13 +43,6 @@ module ActionMailer #:nodoc:
# address. Setting this is useful when you want delivery notifications sent to a different address than
# the one in <tt>from</tt>.
#
- # The <tt>body</tt> method has special behavior. It takes a hash which generates an instance variable
- # named after each key in the hash containing the value that that key points to.
- #
- # So, for example, <tt>body :account => recipient</tt> would result
- # in an instance variable <tt>@account</tt> with the value of <tt>recipient</tt> being accessible in the
- # view.
- #
#
# = Mailer views
#
@@ -68,7 +62,12 @@ module ActionMailer #:nodoc:
# You can even use Action Pack helpers in these views. For example:
#
# You got a new note!
- # <%= truncate(note.body, 25) %>
+ # <%= truncate(@note.body, 25) %>
+ #
+ # If you need to access the subject, from or the recipients in the view, you can do that through mailer object:
+ #
+ # You got a new note from <%= mailer.from %>!
+ # <%= truncate(@note.body, 25) %>
#
#
# = Generating URLs
@@ -250,29 +249,22 @@ module ActionMailer #:nodoc:
# <tt>["text/html", "text/enriched", "text/plain"]</tt>. Items that appear first in the array have higher priority in the mail client
# and appear last in the mime encoded message. You can also pick a different order from inside a method with
# +implicit_parts_order+.
- class Base
- include AdvAttrAccessor, Quoting
+ class Base < AbstractController::Base
+ include Quoting
+ extend AdvAttrAccessor
- include AbstractController::RenderingController
+ include AbstractController::Rendering
include AbstractController::LocalizedCache
include AbstractController::Layouts
-
include AbstractController::Helpers
- helper MailHelper
- if Object.const_defined?(:ActionController)
- include ActionController::UrlWriter
- end
+ helper ActionMailer::MailHelper
+ include ActionController::UrlWriter
include ActionMailer::DeprecatedBody
private_class_method :new #:nodoc:
- class_inheritable_accessor :view_paths
- self.view_paths = []
-
- cattr_accessor :logger
-
@@raise_delivery_errors = true
cattr_accessor :raise_delivery_errors
@@ -291,10 +283,16 @@ module ActionMailer #:nodoc:
@@default_mime_version = "1.0"
cattr_accessor :default_mime_version
- @@default_implicit_parts_order = [ "text/html", "text/enriched", "text/plain" ]
+ # This specifies the order that the parts of a multipart email will be. Usually you put
+ # text/plain at the top so someone without a MIME capable email reader can read the plain
+ # text of your email first.
+ #
+ # Any content type that is not listed here will be inserted in the order you add them to
+ # the email after the content types you list here.
+ @@default_implicit_parts_order = [ "text/plain", "text/enriched", "text/html" ]
cattr_accessor :default_implicit_parts_order
- @@protected_instance_variables = []
+ @@protected_instance_variables = %w(@parts @mail)
cattr_reader :protected_instance_variables
# Specify the BCC addresses for the message
@@ -344,57 +342,17 @@ module ActionMailer #:nodoc:
# have multiple mailer methods share the same template.
adv_attr_accessor :template
- # The mail and action_name instances referenced by this mailer.
- attr_reader :mail, :action_name
-
- # Where the response body is stored.
- attr_internal :response_body
-
# Override the mailer name, which defaults to an inflected version of the
# mailer's class name. If you want to use a template in a non-standard
# location, you can use this to specify that location.
- attr_writer :mailer_name
+ adv_attr_accessor :mailer_name
- def mailer_name(value = nil)
- if value
- @mailer_name = value
- else
- @mailer_name || self.class.mailer_name
- end
- end
+ # Expose the internal mail
+ attr_reader :mail
# Alias controller_path to mailer_name so render :partial in views work.
alias :controller_path :mailer_name
- # Add a part to a multipart message, with the given content-type. The
- # part itself is yielded to the block so that other properties (charset,
- # body, headers, etc.) can be set on it.
- def part(params)
- params = {:content_type => params} if String === params
- if custom_headers = params.delete(:headers)
- ActiveSupport::Deprecation.warn('Passing custom headers with :headers => {} is deprecated. ' <<
- 'Please just pass in custom headers directly.', caller[0,10])
- params.merge!(custom_headers)
- end
- part = Mail::Part.new(params)
- yield part if block_given?
- @parts << part
- end
-
- # Add an attachment to a multipart message. This is simply a part with the
- # content-disposition set to "attachment".
- def attachment(params, &block)
- params = { :content_type => params } if String === params
- params = { :content_disposition => "attachment",
- :content_transfer_encoding => "base64" }.merge(params)
- if params[:body]
- ActiveSupport::Deprecation.warn('attachment :body => "string" is deprecated. To set the body of an attachment ' <<
- 'please use :data instead, like attachment :data => "string".', caller[0,10])
- params[:data] = params.delete(:body)
- end
- part(params, &block)
- end
-
class << self
attr_writer :mailer_name
@@ -475,21 +433,47 @@ module ActionMailer #:nodoc:
superclass_delegating_reader :delivery_method
self.delivery_method = :smtp
+ # Add a part to a multipart message, with the given content-type. The
+ # part itself is yielded to the block so that other properties (charset,
+ # body, headers, etc.) can be set on it.
+ def part(params)
+ params = {:content_type => params} if String === params
+ if custom_headers = params.delete(:headers)
+ ActiveSupport::Deprecation.warn('Passing custom headers with :headers => {} is deprecated. ' <<
+ 'Please just pass in custom headers directly.', caller[0,10])
+ params.merge!(custom_headers)
+ end
+ part = Mail::Part.new(params)
+ yield part if block_given?
+ @parts << part
+ end
+
+ # Add an attachment to a multipart message. This is simply a part with the
+ # content-disposition set to "attachment".
+ def attachment(params, &block)
+ super # Run deprecation hooks
+
+ params = { :content_type => params } if String === params
+ params = { :content_disposition => "attachment",
+ :content_transfer_encoding => "base64" }.merge(params)
+
+ part(params, &block)
+ end
+
# Instantiate a new mailer object. If +method_name+ is not +nil+, the mailer
# will be initialized according to the named method. If not, the mailer will
# remain uninitialized (useful when you only need to invoke the "receive"
# method, for instance).
- def initialize(method_name=nil, *parameters) #:nodoc:
- @_response_body = nil
+ def initialize(method_name=nil, *args)
super()
- create!(method_name, *parameters) if method_name
+ process(method_name, *args) if method_name
end
- # Initialize the mailer via the given +method_name+. The body will be
+ # Process the mailer via the given +method_name+. The body will be
# rendered and a new Mail object created.
- def create!(method_name, *parameters) #:nodoc:
+ def process(method_name, *args)
initialize_defaults(method_name)
- __send__(method_name, *parameters)
+ super
# Create e-mail parts
create_parts
@@ -498,8 +482,8 @@ module ActionMailer #:nodoc:
@subject ||= I18n.t(:subject, :scope => [:actionmailer, mailer_name, method_name],
:default => method_name.humanize)
- # build the mail object itself
- @mail = create_mail
+ # Build the mail object itself
+ create_mail
end
# Delivers a Mail object. By default, it delivers the cached mail
@@ -513,7 +497,7 @@ module ActionMailer #:nodoc:
logger.debug "\n#{mail.encoded}"
end
- ActiveSupport::Notifications.instrument(:deliver_mail, :mail => @mail) do
+ ActiveSupport::Notifications.instrument(:deliver_mail, :mail => mail) do
begin
self.delivery_method.perform_delivery(mail) if perform_deliveries
rescue Exception => e # Net::SMTP errors or sendmail pipe errors
@@ -529,15 +513,14 @@ module ActionMailer #:nodoc:
# Set up the default values for the various instance variables of this
# mailer. Subclasses may override this method to provide different
# defaults.
- def initialize_defaults(method_name)
+ def initialize_defaults(method_name) #:nodoc:
@charset ||= @@default_charset.dup
@content_type ||= @@default_content_type.dup
@implicit_parts_order ||= @@default_implicit_parts_order.dup
@mime_version ||= @@default_mime_version.dup if @@default_mime_version
- @mailer_name ||= self.class.mailer_name
+ @mailer_name ||= self.class.mailer_name.dup
@template ||= method_name
- @action_name = @template
@parts ||= []
@headers ||= {}
@@ -546,29 +529,18 @@ module ActionMailer #:nodoc:
super # Run deprecation hooks
end
- def create_parts
+ def create_parts #:nodoc:
super # Run deprecation hooks
if String === response_body
- @parts.unshift Mail::Part.new(
- :content_type => ["text", "plain", {:charset => charset}],
- :content_disposition => "inline",
- :body => response_body
- )
+ @parts.unshift create_inline_part(response_body)
else
- self.class.template_root.find_all(@template, {}, mailer_name).each do |template|
- ct = template.mime_type ? template.mime_type.to_s : "text/plain"
- main_type, sub_type = ct.split("/")
- @parts << Mail::Part.new(
- :content_type => [main_type, sub_type, {:charset => charset}],
- :content_disposition => "inline",
- :body => render_to_body(:_template => template)
- )
+ self.class.template_root.find_all(@template, {}, @mailer_name).each do |template|
+ @parts << create_inline_part(render_to_body(:_template => template), template.mime_type)
end
if @parts.size > 1
@content_type = "multipart/alternative" if @content_type !~ /^multipart/
- @parts = sort_parts(@parts, @implicit_parts_order)
end
# If this is a multipart e-mail add the mime_version if it is not
@@ -577,36 +549,18 @@ module ActionMailer #:nodoc:
end
end
- def sort_parts(parts, order = [])
- order = order.collect { |s| s.downcase }
-
- parts = parts.sort do |a, b|
- a_ct = a.content_type.string.downcase
- b_ct = b.content_type.string.downcase
-
- a_in = order.include? a_ct
- b_in = order.include? b_ct
-
- s = case
- when a_in && b_in
- order.index(a_ct) <=> order.index(b_ct)
- when a_in
- -1
- when b_in
- 1
- else
- a_ct <=> b_ct
- end
+ def create_inline_part(body, mime_type=nil) #:nodoc:
+ ct = mime_type || "text/plain"
+ main_type, sub_type = split_content_type(ct.to_s)
- # reverse the ordering because parts that come last are displayed
- # first in mail clients
- (s * -1)
- end
-
- parts
+ Mail::Part.new(
+ :content_type => [main_type, sub_type, {:charset => charset}],
+ :content_disposition => "inline",
+ :body => body
+ )
end
- def create_mail
+ def create_mail #:nodoc:
m = Mail.new
m.subject, = quote_any_if_necessary(charset, subject)
@@ -620,13 +574,9 @@ module ActionMailer #:nodoc:
headers.each { |k, v| m[k] = v }
real_content_type, ctype_attrs = parse_content_type
-
- if @parts.empty?
- main_type, sub_type = split_content_type(real_content_type)
- m.content_type([main_type, sub_type, ctype_attrs])
- m.body = body
- elsif @parts.size == 1 && @parts.first.parts.empty?
- main_type, sub_type = split_content_type(real_content_type)
+ main_type, sub_type = split_content_type(real_content_type)
+
+ if @parts.size == 1 && @parts.first.parts.empty?
m.content_type([main_type, sub_type, ctype_attrs])
m.body = @parts.first.body.encoded
else
@@ -634,31 +584,33 @@ module ActionMailer #:nodoc:
m.add_part(p)
end
+ m.body.set_sort_order(@implicit_parts_order)
+ m.body.sort_parts!
+
if real_content_type =~ /multipart/
ctype_attrs.delete "charset"
- main_type, sub_type = split_content_type(real_content_type)
m.content_type([main_type, sub_type, ctype_attrs])
end
end
+ m.content_transfer_encoding = '8bit' unless m.body.only_us_ascii?
+
@mail = m
end
- def split_content_type(ct)
+ def split_content_type(ct) #:nodoc:
ct.to_s.split("/")
end
- def parse_content_type(defaults=nil)
- if content_type.blank?
- return defaults ?
- [ defaults.content_type, { 'charset' => defaults.charset } ] :
- [ nil, {} ]
- end
- ctype, *attrs = content_type.split(/;\s*/)
- attrs = attrs.inject({}) { |h,s| k,v = s.split(/=/, 2); h[k] = v; h }
- [ctype, {"charset" => charset || defaults && defaults.charset}.merge(attrs)]
+ def parse_content_type(defaults=nil) #:nodoc:
+ if @content_type.blank?
+ [ nil, {} ]
+ else
+ ctype, *attrs = @content_type.split(/;\s*/)
+ attrs = attrs.inject({}) { |h,s| k,v = s.split(/\=/, 2); h[k] = v; h }
+ [ctype, {"charset" => @charset}.merge(attrs)]
+ end
end
-
end
end
diff --git a/actionmailer/lib/action_mailer/delivery_method.rb b/actionmailer/lib/action_mailer/delivery_method.rb
index 29a51afdc3..4f7d3afc3c 100644
--- a/actionmailer/lib/action_mailer/delivery_method.rb
+++ b/actionmailer/lib/action_mailer/delivery_method.rb
@@ -1,7 +1,7 @@
-require "active_support/core_ext/class"
+require 'active_support/core_ext/class'
+
module ActionMailer
module DeliveryMethod
-
autoload :File, 'action_mailer/delivery_method/file'
autoload :Sendmail, 'action_mailer/delivery_method/sendmail'
autoload :Smtp, 'action_mailer/delivery_method/smtp'
@@ -52,6 +52,5 @@ module ActionMailer
superclass_delegating_accessor :settings
self.settings = {}
end
-
end
end
diff --git a/actionmailer/lib/action_mailer/delivery_method/file.rb b/actionmailer/lib/action_mailer/delivery_method/file.rb
index 99ef5bc76d..571e32df49 100644
--- a/actionmailer/lib/action_mailer/delivery_method/file.rb
+++ b/actionmailer/lib/action_mailer/delivery_method/file.rb
@@ -6,7 +6,7 @@ module ActionMailer
# A delivery method implementation which writes all mails to a file.
class File < Method
self.settings = {
- :location => defined?(Rails) ? "#{Rails.root}/tmp/mails" : "#{Dir.tmpdir}/mails"
+ :location => defined?(Rails.root) ? "#{Rails.root}/tmp/mails" : "#{Dir.tmpdir}/mails"
}
def perform_delivery(mail)
diff --git a/actionmailer/lib/action_mailer/delivery_method/smtp.rb b/actionmailer/lib/action_mailer/delivery_method/smtp.rb
index 9622dbb93a..af30c498b5 100644
--- a/actionmailer/lib/action_mailer/delivery_method/smtp.rb
+++ b/actionmailer/lib/action_mailer/delivery_method/smtp.rb
@@ -1,8 +1,9 @@
+require 'net/smtp'
+
module ActionMailer
module DeliveryMethod
# A delivery method implementation which sends via smtp.
class Smtp < Method
-
self.settings = {
:address => "localhost",
:port => 25,
@@ -25,6 +26,5 @@ module ActionMailer
end
end
end
-
end
end
diff --git a/actionmailer/lib/action_mailer/deprecated_body.rb b/actionmailer/lib/action_mailer/deprecated_body.rb
index 50ff262432..20b0989a85 100644
--- a/actionmailer/lib/action_mailer/deprecated_body.rb
+++ b/actionmailer/lib/action_mailer/deprecated_body.rb
@@ -15,6 +15,14 @@ module ActionMailer
@body ||= {}
end
+ def attachment(params, &block)
+ if params[:body]
+ ActiveSupport::Deprecation.warn('attachment :body => "string" is deprecated. To set the body of an attachment ' <<
+ 'please use :data instead, like attachment :data => "string".', caller[0,10])
+ params[:data] = params.delete(:body)
+ end
+ end
+
def create_parts
if String === @body
ActiveSupport::Deprecation.warn('body is deprecated. To set the body with a text ' <<
diff --git a/actionmailer/lib/action_mailer/mail_helper.rb b/actionmailer/lib/action_mailer/mail_helper.rb
index 351b966abe..701dc34431 100644
--- a/actionmailer/lib/action_mailer/mail_helper.rb
+++ b/actionmailer/lib/action_mailer/mail_helper.rb
@@ -1,17 +1,24 @@
-module MailHelper
- # Uses Text::Format to take the text and format it, indented two spaces for
- # each line, and wrapped at 72 columns.
- def block_format(text)
- formatted = text.split(/\n\r\n/).collect { |paragraph|
- Text::Format.new(
- :columns => 72, :first_indent => 2, :body_indent => 2, :text => paragraph
- ).format
- }.join("\n")
+module ActionMailer
+ module MailHelper
+ # Uses Text::Format to take the text and format it, indented two spaces for
+ # each line, and wrapped at 72 columns.
+ def block_format(text)
+ formatted = text.split(/\n\r\n/).collect { |paragraph|
+ Text::Format.new(
+ :columns => 72, :first_indent => 2, :body_indent => 2, :text => paragraph
+ ).format
+ }.join("\n")
- # Make list points stand on their own line
- formatted.gsub!(/[ ]*([*]+) ([^*]*)/) { |s| " #{$1} #{$2.strip}\n" }
- formatted.gsub!(/[ ]*([#]+) ([^#]*)/) { |s| " #{$1} #{$2.strip}\n" }
+ # Make list points stand on their own line
+ formatted.gsub!(/[ ]*([*]+) ([^*]*)/) { |s| " #{$1} #{$2.strip}\n" }
+ formatted.gsub!(/[ ]*([#]+) ([^#]*)/) { |s| " #{$1} #{$2.strip}\n" }
+
+ formatted
+ end
- formatted
+ # Access the mailer instance.
+ def mailer #:nodoc:
+ @controller
+ end
end
end
diff --git a/actionmailer/lib/action_mailer/rails.rb b/actionmailer/lib/action_mailer/rails.rb
new file mode 100644
index 0000000000..a3573cdea7
--- /dev/null
+++ b/actionmailer/lib/action_mailer/rails.rb
@@ -0,0 +1,24 @@
+require "action_mailer"
+
+module ActionMailer
+ class Plugin < Rails::Plugin
+ plugin_name :action_mailer
+
+ initializer "action_mailer.set_configs" do |app|
+ app.config.action_mailer.each do |k,v|
+ ActionMailer::Base.send "#{k}=", v
+ end
+ end
+
+ # TODO: ActionController::Base.logger should delegate to its own config.logger
+ initializer "action_mailer.logger" do
+ ActionMailer::Base.logger ||= Rails.logger
+ end
+
+ initializer "action_mailer.view_paths" do |app|
+ # TODO: this should be combined with the logic for default config.action_mailer.view_paths
+ view_path = ActionView::PathSet.type_cast(app.config.view_path, app.config.cache_classes)
+ ActionMailer::Base.template_root = view_path if ActionMailer::Base.view_paths.blank?
+ end
+ end
+end \ No newline at end of file
diff --git a/actionmailer/lib/action_mailer/test_case.rb b/actionmailer/lib/action_mailer/test_case.rb
index 49f6d680a2..445abd0b89 100644
--- a/actionmailer/lib/action_mailer/test_case.rb
+++ b/actionmailer/lib/action_mailer/test_case.rb
@@ -1,4 +1,5 @@
require 'active_support/test_case'
+require 'mail'
module ActionMailer
class NonInferrableMailerError < ::StandardError
diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb
index e84b3b0d23..af6f1bc92e 100644
--- a/actionmailer/test/abstract_unit.rb
+++ b/actionmailer/test/abstract_unit.rb
@@ -1,12 +1,9 @@
-root = File.expand_path('../../..', __FILE__)
begin
- require "#{root}/vendor/gems/environment"
+ require File.expand_path('../../../vendor/gems/environment', __FILE__)
rescue LoadError
- $:.unshift("#{root}/activesupport/lib")
- $:.unshift("#{root}/actionpack/lib")
end
-lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
+lib = File.expand_path('../../lib', __FILE__)
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
require 'rubygems'
diff --git a/actionmailer/test/adv_attr_test.rb b/actionmailer/test/adv_attr_test.rb
index fd909a5627..f22d733bc5 100644
--- a/actionmailer/test/adv_attr_test.rb
+++ b/actionmailer/test/adv_attr_test.rb
@@ -1,18 +1,36 @@
require 'abstract_unit'
require 'action_mailer/adv_attr_accessor'
-class AdvAttrTest < Test::Unit::TestCase
+class AdvAttrTest < ActiveSupport::TestCase
class Person
- include ActionMailer::AdvAttrAccessor
+ cattr_reader :protected_instance_variables
+ @@protected_instance_variables = []
+
+ extend ActionMailer::AdvAttrAccessor
adv_attr_accessor :name
end
+ def setup
+ @person = Person.new
+ end
+
def test_adv_attr
- bob = Person.new
- assert_nil bob.name
- bob.name 'Bob'
- assert_equal 'Bob', bob.name
+ assert_nil @person.name
+ @person.name 'Bob'
+ assert_equal 'Bob', @person.name
+ end
+
+ def test_adv_attr_writer
+ assert_nil @person.name
+ @person.name = 'Bob'
+ assert_equal 'Bob', @person.name
+ end
+
+ def test_raise_an_error_with_multiple_args
+ assert_raise(ArgumentError) { @person.name('x', 'y') }
+ end
- assert_raise(ArgumentError) {bob.name 'x', 'y'}
+ def test_ivar_is_added_to_protected_instnace_variables
+ assert Person.protected_instance_variables.include?('@name')
end
end
diff --git a/actionmailer/test/asset_host_test.rb b/actionmailer/test/asset_host_test.rb
index 0b74fe8c24..f3383e5608 100644
--- a/actionmailer/test/asset_host_test.rb
+++ b/actionmailer/test/asset_host_test.rb
@@ -24,7 +24,7 @@ class AssetHostTest < Test::Unit::TestCase
def test_asset_host_as_string
ActionController::Base.asset_host = "http://www.example.com"
mail = AssetHostMailer.deliver_email_with_asset(@recipient)
- assert_equal "<img alt=\"Somelogo\" src=\"http://www.example.com/images/somelogo.png\" />", mail.body.decoded.strip
+ assert_equal "<img alt=\"Somelogo\" src=\"http://www.example.com/images/somelogo.png\" />", mail.body.to_s.strip
end
def test_asset_host_as_one_arguement_proc
@@ -36,7 +36,7 @@ class AssetHostTest < Test::Unit::TestCase
end
}
mail = AssetHostMailer.deliver_email_with_asset(@recipient)
- assert_equal "<img alt=\"Somelogo\" src=\"http://images.example.com/images/somelogo.png\" />", mail.body.decoded.strip
+ assert_equal "<img alt=\"Somelogo\" src=\"http://images.example.com/images/somelogo.png\" />", mail.body.to_s.strip
end
def test_asset_host_as_two_arguement_proc
@@ -49,6 +49,6 @@ class AssetHostTest < Test::Unit::TestCase
}
mail = nil
assert_nothing_raised { mail = AssetHostMailer.deliver_email_with_asset(@recipient) }
- assert_equal "<img alt=\"Somelogo\" src=\"http://www.example.com/images/somelogo.png\" />", mail.body.decoded.strip
+ assert_equal "<img alt=\"Somelogo\" src=\"http://www.example.com/images/somelogo.png\" />", mail.body.to_s.strip
end
end \ No newline at end of file
diff --git a/actionmailer/test/mail_helper_test.rb b/actionmailer/test/mail_helper_test.rb
index d04215171d..2d3565d159 100644
--- a/actionmailer/test/mail_helper_test.rb
+++ b/actionmailer/test/mail_helper_test.rb
@@ -56,7 +56,7 @@ end
class MailerHelperTest < Test::Unit::TestCase
def new_mail( charset="utf-8" )
mail = Mail.new
- mail.content_type(["text", "plain", { "charset" => charset }])
+ mail.set_content_type "text", "plain", { "charset" => charset } if charset
mail
end
diff --git a/actionmailer/test/mail_layout_test.rb b/actionmailer/test/mail_layout_test.rb
index 4775545039..84f13a6d3c 100644
--- a/actionmailer/test/mail_layout_test.rb
+++ b/actionmailer/test/mail_layout_test.rb
@@ -65,7 +65,7 @@ class LayoutMailerTest < Test::Unit::TestCase
def test_should_pickup_default_layout
mail = AutoLayoutMailer.create_hello(@recipient)
- assert_equal "Hello from layout Inside", mail.body.decoded.strip
+ assert_equal "Hello from layout Inside", mail.body.to_s.strip
end
def test_should_pickup_multipart_layout
@@ -81,7 +81,7 @@ class LayoutMailerTest < Test::Unit::TestCase
# CHANGED: body returns an object
# assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body
- assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body.decoded
+ assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body.to_s
# CHANGED: content_type returns an object
# assert_equal 'text/html', mail.parts.last.content_type
@@ -89,7 +89,7 @@ class LayoutMailerTest < Test::Unit::TestCase
# CHANGED: body returns an object
# assert_equal "Hello from layout text/html multipart", mail.parts.last.body
- assert_equal "Hello from layout text/html multipart", mail.parts.last.body.decoded
+ assert_equal "Hello from layout text/html multipart", mail.parts.last.body.to_s
end
def test_should_pickup_multipartmixed_layout
@@ -104,14 +104,14 @@ class LayoutMailerTest < Test::Unit::TestCase
assert_equal 'text/plain', mail.parts.first.content_type.string
# CHANGED: body returns an object
# assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body
- assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body.decoded
+ assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body.to_s
# CHANGED: content_type returns an object
# assert_equal 'text/html', mail.parts.last.content_type
assert_equal 'text/html', mail.parts.last.content_type.string
# CHANGED: body returns an object
# assert_equal "Hello from layout text/html multipart", mail.parts.last.body
- assert_equal "Hello from layout text/html multipart", mail.parts.last.body.decoded
+ assert_equal "Hello from layout text/html multipart", mail.parts.last.body.to_s
end
def test_should_fix_multipart_layout
@@ -120,30 +120,30 @@ class LayoutMailerTest < Test::Unit::TestCase
assert_equal 2, mail.parts.size
assert_equal 'text/plain', mail.parts.first.content_type.string
- assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body.decoded
+ assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body.to_s
assert_equal 'text/html', mail.parts.last.content_type.string
- assert_equal "Hello from layout text/html multipart", mail.parts.last.body.decoded
+ assert_equal "Hello from layout text/html multipart", mail.parts.last.body.to_s
end
def test_should_pickup_layout_given_to_render
mail = AutoLayoutMailer.create_spam(@recipient)
- assert_equal "Spammer layout Hello, Earth", mail.body.decoded.strip
+ assert_equal "Spammer layout Hello, Earth", mail.body.to_s.strip
end
def test_should_respect_layout_false
mail = AutoLayoutMailer.create_nolayout(@recipient)
- assert_equal "Hello, Earth", mail.body.decoded.strip
+ assert_equal "Hello, Earth", mail.body.to_s.strip
end
def test_explicit_class_layout
mail = ExplicitLayoutMailer.create_signup(@recipient)
- assert_equal "Spammer layout We do not spam", mail.body.decoded.strip
+ assert_equal "Spammer layout We do not spam", mail.body.to_s.strip
end
def test_explicit_layout_exceptions
mail = ExplicitLayoutMailer.create_logout(@recipient)
- assert_equal "You logged out", mail.body.decoded.strip
+ assert_equal "You logged out", mail.body.to_s.strip
end
end
diff --git a/actionmailer/test/mail_render_test.rb b/actionmailer/test/mail_render_test.rb
index 3c97ad2a03..09ce5e4854 100644
--- a/actionmailer/test/mail_render_test.rb
+++ b/actionmailer/test/mail_render_test.rb
@@ -40,13 +40,22 @@ class RenderMailer < ActionMailer::Base
from "tester@example.com"
end
- def included_old_subtemplate(recipient)
+ def mailer_accessor(recipient)
recipients recipient
- subject "Including another template in the one being rendered"
+ subject "Mailer Accessor"
from "tester@example.com"
- @world = "Earth"
- render :inline => "Hello, <%= render \"subtemplate\" %>"
+ render :inline => "Look, <%= mailer.subject %>!"
+ end
+
+ def no_instance_variable(recipient)
+ recipients recipient
+ subject "No Instance Variable"
+ from "tester@example.com"
+
+ silence_warnings do
+ render :inline => "Look, subject.nil? is <%= @subject.nil? %>!"
+ end
end
def initialize_defaults(method_name)
@@ -71,6 +80,8 @@ class SecondMailer < ActionMailer::Base
end
end
+# CHANGED: Those tests were changed because body returns an object now
+# Instead of mail.body.strip, we should mail.body.to_s.strip
class RenderHelperTest < Test::Unit::TestCase
def setup
set_delivery_method :test
@@ -86,37 +97,37 @@ class RenderHelperTest < Test::Unit::TestCase
def test_implicit_body
mail = RenderMailer.create_implicit_body(@recipient)
- # CHANGED: body returns an object now
- # assert_equal "Hello there, \n\nMr. test@localhost", mail.body.strip
- assert_equal "Hello there, \n\nMr. test@localhost", mail.body.decoded.strip
+ assert_equal "Hello there, \n\nMr. test@localhost", mail.body.to_s.strip
end
def test_inline_template
mail = RenderMailer.create_inline_template(@recipient)
- # CHANGED: body returns an object now
- # assert_equal "Hello, Earth", mail.body.strip
- assert_equal "Hello, Earth", mail.body.decoded.strip
+ assert_equal "Hello, Earth", mail.body.to_s.strip
end
def test_file_template
mail = RenderMailer.create_file_template(@recipient)
- # CHANGED: body returns an object now
- # assert_equal "Hello there, \n\nMr. test@localhost", mail.body.strip
- assert_equal "Hello there, \n\nMr. test@localhost", mail.body.decoded.strip
+ assert_equal "Hello there, \n\nMr. test@localhost", mail.body.to_s.strip
end
def test_rxml_template
mail = RenderMailer.deliver_rxml_template(@recipient)
- # CHANGED: body returns an object now
- # assert_equal "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test/>", mail.body.strip
- assert_equal "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test/>", mail.body.decoded.strip
+ assert_equal "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test/>", mail.body.to_s.strip
end
def test_included_subtemplate
mail = RenderMailer.deliver_included_subtemplate(@recipient)
- # CHANGED: body returns an object now
- # assert_equal "Hey Ho, let's go!", mail.body.strip
- assert_equal "Hey Ho, let's go!", mail.body.decoded.strip
+ assert_equal "Hey Ho, let's go!", mail.body.to_s.strip
+ end
+
+ def test_mailer_accessor
+ mail = RenderMailer.deliver_mailer_accessor(@recipient)
+ assert_equal "Look, Mailer Accessor!", mail.body.to_s.strip
+ end
+
+ def test_no_instance_variable
+ mail = RenderMailer.deliver_no_instance_variable(@recipient)
+ assert_equal "Look, subject.nil? is true!", mail.body.to_s.strip
end
end
@@ -135,12 +146,12 @@ class FirstSecondHelperTest < Test::Unit::TestCase
def test_ordering
mail = FirstMailer.create_share(@recipient)
- assert_equal "first mail", mail.body.decoded.strip
+ assert_equal "first mail", mail.body.to_s.strip
mail = SecondMailer.create_share(@recipient)
- assert_equal "second mail", mail.body.decoded.strip
+ assert_equal "second mail", mail.body.to_s.strip
mail = FirstMailer.create_share(@recipient)
- assert_equal "first mail", mail.body.decoded.strip
+ assert_equal "first mail", mail.body.to_s.strip
mail = SecondMailer.create_share(@recipient)
- assert_equal "second mail", mail.body.decoded.strip
+ assert_equal "second mail", mail.body.to_s.strip
end
end
diff --git a/actionmailer/test/mail_service_test.rb b/actionmailer/test/mail_service_test.rb
index 7a47a654cd..152900259d 100644
--- a/actionmailer/test/mail_service_test.rb
+++ b/actionmailer/test/mail_service_test.rb
@@ -31,6 +31,18 @@ class TestMailer < ActionMailer::Base
render :text => "Goodbye, Mr. #{recipient}"
end
+ def from_with_name
+ from "System <system@loudthinking.com>"
+ recipients "root@loudthinking.com"
+ render :text => "Nothing to see here."
+ end
+
+ def from_without_name
+ from "system@loudthinking.com"
+ recipients "root@loudthinking.com"
+ render :text => "Nothing to see here."
+ end
+
def cc_bcc(recipient)
recipients recipient
subject "testing bcc/cc"
@@ -95,7 +107,7 @@ class TestMailer < ActionMailer::Base
cc "Foo áëô îü <extended@example.net>"
bcc "Foo áëô îü <extended@example.net>"
charset "utf-8"
-
+
render :text => "åœö blah"
end
@@ -227,7 +239,7 @@ class TestMailer < ActionMailer::Base
from "test@example.com"
content_type "multipart/mixed"
- part :content_type => "multipart/alternative", :content_disposition => "inline", :headers => { "foo" => "bar" } do |p|
+ part :content_type => "multipart/alternative", :content_disposition => "inline", "foo" => "bar" do |p|
p.part :content_type => "text/plain", :body => "test text\nline #2"
p.part :content_type => "text/html", :body => "<b>test</b> HTML<br/>\nline #2"
end
@@ -252,7 +264,7 @@ class TestMailer < ActionMailer::Base
from "test@example.com"
content_type "multipart/related"
part :content_type => "text/html", :body => 'yo'
- attachment :content_type => "image/jpeg", :filename => File.join(File.dirname(__FILE__), "fixtures", "attachments", "test.jpg"), :data => "i am not a real picture", :headers => { 'Content-ID' => '<test@test.com>' }
+ attachment :content_type => "image/jpeg", :filename => File.join(File.dirname(__FILE__), "fixtures", "attachments", "test.jpg"), :data => "i am not a real picture", 'Content-ID' => '<test@test.com>'
end
def unnamed_attachment(recipient)
@@ -289,6 +301,7 @@ class TestMailer < ActionMailer::Base
render :text => "testing"
end
+ # This tests body calls accepeting a hash, which is deprecated.
def body_ivar(recipient)
recipients recipient
subject "Body as a local variable"
@@ -351,7 +364,7 @@ class ActionMailerTest < Test::Unit::TestCase
assert_equal "multipart/mixed", created.content_type.string
assert_equal "multipart/alternative", created.parts[0].content_type.string
- assert_equal "bar", created.parts[0].header['foo'].decoded
+ assert_equal "bar", created.parts[0].header['foo'].to_s
assert_nil created.parts[0].charset
assert_equal "text/plain", created.parts[0].parts[0].content_type.string
assert_equal "text/html", created.parts[0].parts[1].content_type.string
@@ -370,9 +383,9 @@ class ActionMailerTest < Test::Unit::TestCase
assert_equal "multipart/mixed", created.content_type.string
assert_equal "multipart/alternative", created.parts.first.content_type.string
assert_equal "text/plain", created.parts.first.parts.first.content_type.string
- assert_equal "Nothing to see here.", created.parts.first.parts.first.body.decoded
+ assert_equal "Nothing to see here.", created.parts.first.parts.first.body.to_s
assert_equal "text/html", created.parts.first.parts.second.content_type.string
- assert_equal "<b>test</b> HTML<br/>", created.parts.first.parts.second.body.decoded
+ assert_equal "<b>test</b> HTML<br/>", created.parts.first.parts.second.body.to_s
end
def test_attachment_with_custom_header
@@ -413,11 +426,11 @@ class ActionMailerTest < Test::Unit::TestCase
def test_subject_with_i18n
assert_nothing_raised { TestMailer.deliver_subject_with_i18n(@recipient) }
- assert_equal "Subject with i18n", ActionMailer::Base.deliveries.first.subject.decoded
+ assert_equal "Subject with i18n", ActionMailer::Base.deliveries.first.subject.to_s
I18n.backend.store_translations('en', :actionmailer => {:test_mailer => {:subject_with_i18n => {:subject => "New Subject!"}}})
assert_nothing_raised { TestMailer.deliver_subject_with_i18n(@recipient) }
- assert_equal "New Subject!", ActionMailer::Base.deliveries.last.subject.decoded
+ assert_equal "New Subject!", ActionMailer::Base.deliveries.last.subject.to_s
end
def test_custom_template
@@ -514,6 +527,28 @@ class ActionMailerTest < Test::Unit::TestCase
assert_equal expected.encoded, delivered.encoded
end
+ def test_from_without_name_for_smtp
+ ActionMailer::Base.delivery_method = :smtp
+ TestMailer.deliver_from_without_name
+
+ mail = MockSMTP.deliveries.first
+ assert_not_nil mail
+ mail, from, to = mail
+
+ assert_equal 'system@loudthinking.com', from.to_s
+ end
+
+ def test_from_with_name_for_smtp
+ ActionMailer::Base.delivery_method = :smtp
+ TestMailer.deliver_from_with_name
+
+ mail = MockSMTP.deliveries.first
+ assert_not_nil mail
+ mail, from, to = mail
+
+ assert_equal 'system@loudthinking.com', from.addresses.first
+ end
+
def test_reply_to
expected = new_mail
@@ -696,7 +731,7 @@ Content-Type: text/plain; charset=iso-8859-1
The body
EOF
mail = Mail.new(msg)
- assert_equal "testing testing \326\244", mail.subject.decoded
+ assert_equal "testing testing \326\244", mail.subject.to_s
assert_equal "Subject: =?utf-8?Q?testing_testing_=D6=A4?=\r\n", mail.subject.encoded
end
@@ -709,7 +744,7 @@ Content-Type: text/plain; charset=iso-8859-1
The body
EOF
mail = Mail.new(msg)
- assert_equal "this == working?", mail.subject.decoded
+ assert_equal "this == working?", mail.subject.to_s
assert_equal "Subject: this == working?\r\n", mail.subject.encoded
end
@@ -723,7 +758,7 @@ Content-Transfer-Encoding: 7bit
The=3Dbody
EOF
mail = Mail.new(msg)
- assert_equal "The=3Dbody", mail.body.decoded.strip
+ assert_equal "The=3Dbody", mail.body.to_s.strip
assert_equal "The=3Dbody", mail.body.encoded.strip
end
@@ -737,7 +772,7 @@ Content-Transfer-Encoding: quoted-printable
The=3Dbody
EOF
mail = Mail.new(msg)
- assert_equal "The=body", mail.body.decoded.strip
+ assert_equal "The=body", mail.body.to_s.strip
assert_equal "The=3Dbody", mail.body.encoded.strip
end
@@ -751,7 +786,7 @@ Content-Transfer-Encoding: base64
VGhlIGJvZHk=
EOF
mail = Mail.new(msg)
- assert_equal "The body", mail.body.decoded.strip
+ assert_equal "The body", mail.body.to_s.strip
assert_equal "VGhlIGJvZHk=", mail.body.encoded.strip
end
@@ -825,7 +860,7 @@ EOF
def test_receive_decodes_base64_encoded_mail
fixture = File.read(File.dirname(__FILE__) + "/fixtures/raw_email")
TestMailer.receive(fixture)
- assert_match(/Jamis/, TestMailer.received_body.decoded)
+ assert_match(/Jamis/, TestMailer.received_body.to_s)
end
def test_receive_attachments
@@ -895,7 +930,6 @@ EOF
mail = TestMailer.create_explicitly_multipart_example(@recipient)
assert_equal 3, mail.parts.length
assert_equal 'multipart/mixed', mail.content_type.string
-
assert_equal "text/plain", mail.parts[0].content_type.string
assert_equal "text/html", mail.parts[1].content_type.string
@@ -903,7 +937,6 @@ EOF
assert_equal "image/jpeg", mail.parts[2].content_type.string
assert_equal "attachment", mail.parts[2].content_disposition.disposition_type
-
assert_equal "foo.jpg", mail.parts[2].content_disposition.filename
assert_equal "foo.jpg", mail.parts[2].content_type.filename
assert_nil mail.parts[2].charset
@@ -926,13 +959,13 @@ EOF
mail = TestMailer.create_implicitly_multipart_example(@recipient)
assert_equal 3, mail.parts.length
- assert_equal "1.0", mail.mime_version.decoded
+ assert_equal "1.0", mail.mime_version.to_s
assert_equal "multipart/alternative", mail.content_type.string
- assert_equal "application/x-yaml", mail.parts[0].content_type.string
+ assert_equal "text/plain", mail.parts[0].content_type.string
assert_equal "utf-8", mail.parts[0].charset
- assert_equal "text/plain", mail.parts[1].content_type.string
+ assert_equal "text/html", mail.parts[1].content_type.string
assert_equal "utf-8", mail.parts[1].charset
- assert_equal "text/html", mail.parts[2].content_type.string
+ assert_equal "application/x-yaml", mail.parts[2].content_type.string
assert_equal "utf-8", mail.parts[2].charset
end
@@ -941,9 +974,9 @@ EOF
mail = TestMailer.create_implicitly_multipart_example(@recipient, nil, ["application/x-yaml", "text/plain"])
assert_equal 3, mail.parts.length
- assert_equal "text/html", mail.parts[0].content_type.string
+ assert_equal "application/x-yaml", mail.parts[0].content_type.string
assert_equal "text/plain", mail.parts[1].content_type.string
- assert_equal "application/x-yaml", mail.parts[2].content_type.string
+ assert_equal "text/html", mail.parts[2].content_type.string
end
def test_implicitly_multipart_messages_with_charset
@@ -963,19 +996,19 @@ EOF
def test_html_mail_with_underscores
mail = TestMailer.create_html_mail_with_underscores(@recipient)
- assert_equal %{<a href="http://google.com" target="_blank">_Google</a>}, mail.body.decoded
+ assert_equal %{<a href="http://google.com" target="_blank">_Google</a>}, mail.body.to_s
end
def test_various_newlines
mail = TestMailer.create_various_newlines(@recipient)
assert_equal("line #1\nline #2\nline #3\nline #4\n\n" +
- "line #5\n\nline#6\n\nline #7", mail.body.decoded)
+ "line #5\n\nline#6\n\nline #7", mail.body.to_s)
end
def test_various_newlines_multipart
mail = TestMailer.create_various_newlines_multipart(@recipient)
- assert_equal "line #1\nline #2\nline #3\nline #4\n\n", mail.parts[0].body.decoded
- assert_equal "<p>line #1</p>\n<p>line #2</p>\n<p>line #3</p>\n<p>line #4</p>\n\n", mail.parts[1].body.decoded
+ assert_equal "line #1\nline #2\nline #3\nline #4\n\n", mail.parts[0].body.to_s
+ assert_equal "<p>line #1</p>\n<p>line #2</p>\n<p>line #3</p>\n<p>line #4</p>\n\n", mail.parts[1].body.to_s
assert_equal "line #1\r\nline #2\r\nline #3\r\nline #4\r\n\r\n", mail.parts[0].body.encoded
assert_equal "<p>line #1</p>\r\n<p>line #2</p>\r\n<p>line #3</p>\r\n<p>line #4</p>\r\n\r\n", mail.parts[1].body.encoded
end
@@ -1008,7 +1041,7 @@ EOF
mail = Mail.new(fixture)
assert_equal(2, mail.parts.length)
assert_equal(4, mail.parts.first.parts.length)
- assert_equal("This is the first part.", mail.parts.first.parts.first.body.decoded)
+ assert_equal("This is the first part.", mail.parts.first.parts.first.body.to_s)
assert_equal("test.rb", mail.parts.first.parts.second.filename)
assert_equal("flowed", mail.parts.first.parts.fourth.content_type.parameters[:format])
assert_equal('smime.p7s', mail.parts.second.filename)
@@ -1074,7 +1107,7 @@ EOF
def test_return_path_with_create
mail = TestMailer.create_return_path
- assert_equal "another@somewhere.test", mail['return-path'].decoded.to_s
+ assert_equal "another@somewhere.test", mail['return-path'].to_s
end
def test_return_path_with_deliver
@@ -1085,8 +1118,9 @@ EOF
end
def test_body_is_stored_as_an_ivar
- mail = TestMailer.create_body_ivar(@recipient)
- assert_equal "body: foo\nbar: baz", mail.body.decoded
+ mail = nil
+ ActiveSupport::Deprecation.silence { mail = TestMailer.create_body_ivar(@recipient) }
+ assert_equal "body: foo\nbar: baz", mail.body.to_s
end
def test_starttls_is_enabled_if_supported
@@ -1215,6 +1249,6 @@ class RespondToTest < Test::Unit::TestCase
RespondToMailer.not_a_method
end
- assert_match /undefined method.*not_a_method/, error.message
+ assert_match(/undefined method.*not_a_method/, error.message)
end
end
diff --git a/actionmailer/test/tmail_test.rb b/actionmailer/test/mail_test.rb
index 5d895f3790..ea6f25d157 100644
--- a/actionmailer/test/tmail_test.rb
+++ b/actionmailer/test/mail_test.rb
@@ -1,6 +1,6 @@
require 'abstract_unit'
-class TMailMailTest < Test::Unit::TestCase
+class MailTest < Test::Unit::TestCase
def test_body
m = Mail.new
expected = 'something_with_underscores'
@@ -8,8 +8,8 @@ class TMailMailTest < Test::Unit::TestCase
quoted_body = [expected].pack('*M')
m.body = quoted_body
assert_equal "something_with_underscores=\r\n", m.body.encoded
- # CHANGED: body returns object, not string, Changed m.body to m.body.decoded
- assert_equal expected, m.body.decoded
+ # CHANGED: body returns object, not string, Changed m.body to m.body.to_s
+ assert_equal expected, m.body.to_s
end
def test_nested_attachments_are_recognized_correctly
diff --git a/actionmailer/test/quoting_test.rb b/actionmailer/test/quoting_test.rb
index 32f34f6028..b16d160805 100644
--- a/actionmailer/test/quoting_test.rb
+++ b/actionmailer/test/quoting_test.rb
@@ -71,7 +71,7 @@ class QuotingTest < Test::Unit::TestCase
mail = Mail.new(IO.read("#{File.dirname(__FILE__)}/fixtures/raw_email_quoted_with_0d0a"))
# CHANGED: subject returns an object now
# assert_match %r{Elapsed time}, mail.body
- assert_match %r{Elapsed time}, mail.body.decoded
+ assert_match %r{Elapsed time}, mail.body.to_s
end
def test_email_with_partially_quoted_subject
diff --git a/actionmailer/test/test_helper_test.rb b/actionmailer/test/test_helper_test.rb
index 8e4254411c..86d22da9bf 100644
--- a/actionmailer/test/test_helper_test.rb
+++ b/actionmailer/test/test_helper_test.rb
@@ -92,7 +92,7 @@ class TestHelperMailerTest < ActionMailer::TestCase
end
end
- assert_match /2 .* but 1/, error.message
+ assert_match(/2 .* but 1/, error.message)
end
def test_assert_emails_too_many_sent
@@ -103,7 +103,7 @@ class TestHelperMailerTest < ActionMailer::TestCase
end
end
- assert_match /1 .* but 2/, error.message
+ assert_match(/1 .* but 2/, error.message)
end
def test_assert_no_emails_failure
@@ -113,7 +113,7 @@ class TestHelperMailerTest < ActionMailer::TestCase
end
end
- assert_match /0 .* but 1/, error.message
+ assert_match(/0 .* but 1/, error.message)
end
end
diff --git a/actionmailer/test/url_test.rb b/actionmailer/test/url_test.rb
index 427833b36c..12bf609dce 100644
--- a/actionmailer/test/url_test.rb
+++ b/actionmailer/test/url_test.rb
@@ -1,7 +1,9 @@
require 'abstract_unit'
-class TestMailer < ActionMailer::Base
+class WelcomeController < ActionController::Base
+end
+class TestMailer < ActionMailer::Base
default_url_options[:host] = 'www.basecamphq.com'
def signed_up_with_url(recipient)
@@ -10,8 +12,8 @@ class TestMailer < ActionMailer::Base
@from = "system@loudthinking.com"
@sent_on = Time.local(2004, 12, 12)
- @body["recipient"] = recipient
- @body["welcome_url"] = url_for :host => "example.com", :controller => "welcome", :action => "greeting"
+ @recipient = recipient
+ @welcome_url = url_for :host => "example.com", :controller => "welcome", :action => "greeting"
end
class <<self
@@ -52,27 +54,31 @@ class ActionMailerUrlTest < Test::Unit::TestCase
end
def test_signed_up_with_url
- ActionController::Routing.use_controllers! ['welcome'] do
- ActionController::Routing::Routes.draw do |map|
- map.connect ':controller/:action/:id'
- map.welcome 'welcome', :controller=>"foo", :action=>"bar"
- end
-
- expected = new_mail
- expected.to = @recipient
- expected.subject = "[Signed up] Welcome #{@recipient}"
- expected.body = "Hello there, \n\nMr. #{@recipient}. Please see our greeting at http://example.com/welcome/greeting http://www.basecamphq.com/welcome\n\n<img alt=\"Somelogo\" src=\"/images/somelogo.png\" />"
- expected.from = "system@loudthinking.com"
- expected.date = Time.local(2004, 12, 12)
-
- created = nil
- assert_nothing_raised { created = TestMailer.create_signed_up_with_url(@recipient) }
- assert_not_nil created
- assert_equal expected.encoded, created.encoded
-
- assert_nothing_raised { TestMailer.deliver_signed_up_with_url(@recipient) }
- assert_not_nil ActionMailer::Base.deliveries.first
- assert_equal expected.encoded, ActionMailer::Base.deliveries.first.encoded
+ ActionController::Routing::Routes.draw do |map|
+ map.connect ':controller/:action/:id'
+ map.welcome 'welcome', :controller=>"foo", :action=>"bar"
end
+
+ expected = new_mail
+ expected.to = @recipient
+ expected.subject = "[Signed up] Welcome #{@recipient}"
+ expected.body = "Hello there, \n\nMr. #{@recipient}. Please see our greeting at http://example.com/welcome/greeting http://www.basecamphq.com/welcome\n\n<img alt=\"Somelogo\" src=\"/images/somelogo.png\" />"
+ expected.from = "system@loudthinking.com"
+ expected.date = Time.local(2004, 12, 12)
+
+ created = nil
+ assert_nothing_raised { created = TestMailer.create_signed_up_with_url(@recipient) }
+ assert_not_nil created
+
+ expected.message_id = '<123@456>'
+ created.message_id = '<123@456>'
+ assert_equal expected.encoded, created.encoded
+
+ assert_nothing_raised { TestMailer.deliver_signed_up_with_url(@recipient) }
+ assert_not_nil ActionMailer::Base.deliveries.first
+ delivered = ActionMailer::Base.deliveries.first
+
+ delivered.message_id = '<123@456>'
+ assert_equal expected.encoded, delivered.encoded
end
end
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 30f3f31563..782b4229fb 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,19 @@
*Edge*
+* Added ActionDispatch::Request#authorization to access the http authentication header regardless of its proxy hiding [DHH]
+
+* Added :alert, :notice, and :flash as options to ActionController::Base#redirect_to that'll automatically set the proper flash before the redirection [DHH]. Examples:
+
+ flash[:notice] = 'Post was created'
+ redirect_to(@post)
+
+ ...becomes:
+
+ redirect_to(@post, :notice => 'Post was created')
+
+* Added ActionController::Base#notice/= and ActionController::Base#alert/= as a convenience accessors in both the controller and the view for flash[:notice]/= and flash[:alert]/= [DHH]
+
+
* Introduce grouped_collection_select helper. #1249 [Dan Codeape, Erik Ostrom]
* Make sure javascript_include_tag/stylesheet_link_tag does not append ".js" or ".css" onto external urls. #1664 [Matthew Rudy Jacobs]
diff --git a/actionpack/Rakefile b/actionpack/Rakefile
index 99bdcc95fa..863daa4b44 100644
--- a/actionpack/Rakefile
+++ b/actionpack/Rakefile
@@ -31,7 +31,6 @@ Rake::TestTask.new(:test_action_pack) do |t|
# this will not happen automatically and the tests (as a whole) will error
t.test_files = Dir.glob('test/{abstract,controller,dispatch,template}/**/*_test.rb').sort
- t.verbose = true
# t.warning = true
end
@@ -45,7 +44,6 @@ desc 'ActiveRecord Integration Tests'
Rake::TestTask.new(:test_active_record_integration) do |t|
t.libs << 'test'
t.test_files = Dir.glob("test/activerecord/*_test.rb")
- t.verbose = true
end
# Genereate the RDoc documentation
diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec
index 78286f6747..dc91fba64d 100644
--- a/actionpack/actionpack.gemspec
+++ b/actionpack/actionpack.gemspec
@@ -16,9 +16,9 @@ Gem::Specification.new do |s|
s.add_dependency('activesupport', '= 3.0.pre')
s.add_dependency('activemodel', '= 3.0.pre')
- s.add_dependency('rack', '~> 1.0.1')
+ s.add_dependency('rack', '~> 1.1.0')
s.add_dependency('rack-test', '~> 0.5.0')
- s.add_dependency('rack-mount', '~> 0.2')
+ s.add_dependency('rack-mount', '~> 0.4.0')
s.add_dependency('erubis', '~> 2.6.5')
s.require_path = 'lib'
diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb
index 1a6c4278c9..237ab577ba 100644
--- a/actionpack/lib/abstract_controller.rb
+++ b/actionpack/lib/abstract_controller.rb
@@ -1,16 +1,18 @@
-require "active_support/core_ext/module/attr_internal"
-require "active_support/core_ext/module/delegation"
+activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
+$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
+
+require 'active_support/ruby/shim'
+require 'active_support/core_ext/module/attr_internal'
+require 'active_support/core_ext/module/delegation'
module AbstractController
- autoload :Base, "abstract_controller/base"
- autoload :Callbacks, "abstract_controller/callbacks"
- autoload :Helpers, "abstract_controller/helpers"
- autoload :Layouts, "abstract_controller/layouts"
- autoload :LocalizedCache, "abstract_controller/localized_cache"
- autoload :Logger, "abstract_controller/logger"
- autoload :RenderingController, "abstract_controller/rendering_controller"
- # === Exceptions
- autoload :ActionNotFound, "abstract_controller/exceptions"
- autoload :DoubleRenderError, "abstract_controller/exceptions"
- autoload :Error, "abstract_controller/exceptions"
+ extend ActiveSupport::Autoload
+
+ autoload :Base
+ autoload :Callbacks
+ autoload :Helpers
+ autoload :Layouts
+ autoload :LocalizedCache
+ autoload :Logger
+ autoload :Rendering
end
diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb
index f5b1c9e4d1..efea81aa71 100644
--- a/actionpack/lib/abstract_controller/base.rb
+++ b/actionpack/lib/abstract_controller/base.rb
@@ -1,8 +1,11 @@
module AbstractController
+ class Error < StandardError; end
+ class ActionNotFound < StandardError; end
class Base
attr_internal :response_body
attr_internal :action_name
+ attr_internal :formats
class << self
attr_reader :abstract
@@ -74,21 +77,23 @@ module AbstractController
abstract!
# Calls the action going through the entire action dispatch stack.
- #
+ #
# The actual method that is called is determined by calling
# #method_for_action. If no method can handle the action, then an
# ActionNotFound error is raised.
#
# ==== Returns
# self
- def process(action)
+ def process(action, *args)
@_action_name = action_name = action.to_s
unless action_name = method_for_action(action_name)
raise ActionNotFound, "The action '#{action}' could not be found"
end
- process_action(action_name)
+ @_response_body = nil
+
+ process_action(action_name, *args)
end
private
@@ -108,8 +113,8 @@ module AbstractController
# Call the action. Override this in a subclass to modify the
# behavior around processing an action. This, and not #process,
# is the intended way to override action dispatching.
- def process_action(method_name)
- send_action(method_name)
+ def process_action(method_name, *args)
+ send_action(method_name, *args)
end
# Actually call the method associated with the action. Override
diff --git a/actionpack/lib/abstract_controller/exceptions.rb b/actionpack/lib/abstract_controller/exceptions.rb
deleted file mode 100644
index b671516de1..0000000000
--- a/actionpack/lib/abstract_controller/exceptions.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-module AbstractController
- class Error < StandardError; end
- class ActionNotFound < StandardError; end
-
- class DoubleRenderError < Error
- 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
-end
diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb
index d3b492ad09..1d898d1a4c 100644
--- a/actionpack/lib/abstract_controller/helpers.rb
+++ b/actionpack/lib/abstract_controller/helpers.rb
@@ -4,7 +4,7 @@ module AbstractController
module Helpers
extend ActiveSupport::Concern
- include RenderingController
+ include Rendering
def self.next_serial
@helper_serial ||= 0
diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb
index c71cef42b2..46760bba7c 100644
--- a/actionpack/lib/abstract_controller/layouts.rb
+++ b/actionpack/lib/abstract_controller/layouts.rb
@@ -2,7 +2,7 @@ module AbstractController
module Layouts
extend ActiveSupport::Concern
- include RenderingController
+ include Rendering
included do
extlib_inheritable_accessor(:_layout_conditions) { Hash.new }
diff --git a/actionpack/lib/abstract_controller/logger.rb b/actionpack/lib/abstract_controller/logger.rb
index 27ba5be45f..e3bcd28da7 100644
--- a/actionpack/lib/abstract_controller/logger.rb
+++ b/actionpack/lib/abstract_controller/logger.rb
@@ -29,33 +29,5 @@ module AbstractController
@str.send(*args, &block)
end
end
-
- # Override process_action in the AbstractController::Base
- # to log details about the method.
- def process_action(action)
- result = ActiveSupport::Notifications.instrument(:process_action,
- :controller => self, :action => action) do
- super
- end
-
- if logger
- log = DelayedLog.new do
- "\n\nProcessing #{self.class.name}\##{action_name} " \
- "to #{request.formats} (for #{request_origin}) " \
- "[#{request.method.to_s.upcase}]"
- end
-
- logger.info(log)
- end
-
- result
- end
-
- private
- # Returns the request origin with the IP and time. This needs to be cached,
- # otherwise we would get different results for each time it calls.
- def request_origin
- @request_origin ||= "#{request.remote_ip} at #{Time.now.to_s(:db)}"
- end
end
end
diff --git a/actionpack/lib/abstract_controller/rendering_controller.rb b/actionpack/lib/abstract_controller/rendering.rb
index 7054b9cf26..64a8a5f241 100644
--- a/actionpack/lib/abstract_controller/rendering_controller.rb
+++ b/actionpack/lib/abstract_controller/rendering.rb
@@ -1,13 +1,21 @@
+require "abstract_controller/base"
require "abstract_controller/logger"
module AbstractController
- module RenderingController
+ class DoubleRenderError < Error
+ 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 Rendering
extend ActiveSupport::Concern
include AbstractController::Logger
included do
- attr_internal :formats
extlib_inheritable_accessor :_view_paths
self._view_paths ||= ActionView::PathSet.new
end
@@ -21,7 +29,7 @@ module AbstractController
# An instance of a view class. The default view class is ActionView::Base
#
# The view class must have the following methods:
- # View.for_controller[controller] Create a new ActionView instance for a
+ # View.for_controller[controller] Create a new ActionView instance for a
# controller
# View#render_partial[options]
# - responsible for setting options[:_template]
@@ -71,7 +79,7 @@ module AbstractController
#
# :api: plugin
def render_to_string(options = {})
- AbstractController::RenderingController.body_to_s(render_to_body(options))
+ AbstractController::Rendering.body_to_s(render_to_body(options))
end
# Renders the template from an object.
@@ -115,10 +123,10 @@ module AbstractController
# _partial<TrueClass, FalseClass>:: Whether or not the file to look up is a partial
def _determine_template(options)
if options.key?(:text)
- options[:_template] = ActionView::TextTemplate.new(options[:text], format_for_text)
+ options[:_template] = ActionView::Template::Text.new(options[:text], format_for_text)
elsif options.key?(:inline)
- handler = ActionView::Template.handler_class_for_extension(options[:type] || "erb")
- template = ActionView::Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {})
+ handler = ActionView::Template.handler_class_for_extension(options[:type] || "erb")
+ template = ActionView::Template.new(options[:inline], "inline template", handler, {})
options[:_template] = template
elsif options.key?(:template)
options[:_template_name] = options[:template]
@@ -152,12 +160,12 @@ module AbstractController
module ClassMethods
def clear_template_caches!
end
-
+
# Append a path to the list of view paths for this controller.
#
# ==== Parameters
- # path<String, ViewPath>:: If a String is provided, it gets converted into
- # the default view path. You may also provide a custom view path
+ # path<String, ViewPath>:: If a String is provided, it gets converted into
+ # the default view path. You may also provide a custom view path
# (see ActionView::ViewPathSet for more information)
def append_view_path(path)
self.view_paths << path
@@ -166,8 +174,8 @@ module AbstractController
# Prepend a path to the list of view paths for this controller.
#
# ==== Parameters
- # path<String, ViewPath>:: If a String is provided, it gets converted into
- # the default view path. You may also provide a custom view path
+ # path<String, ViewPath>:: If a String is provided, it gets converted into
+ # the default view path. You may also provide a custom view path
# (see ActionView::ViewPathSet for more information)
def prepend_view_path(path)
clear_template_caches!
@@ -186,9 +194,8 @@ module AbstractController
# otherwise, process the parameter into a ViewPathSet.
def view_paths=(paths)
clear_template_caches!
- self._view_paths = paths.is_a?(ActionView::PathSet) ?
- paths : ActionView::Base.process_view_paths(paths)
+ self._view_paths = paths.is_a?(ActionView::PathSet) ? paths : ActionView::Base.process_view_paths(paths)
end
end
end
-end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb
index 03a40e4fce..26a85d4de8 100644
--- a/actionpack/lib/action_controller.rb
+++ b/actionpack/lib/action_controller.rb
@@ -1,66 +1,78 @@
+activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
+$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
+require 'active_support/ruby/shim'
+
module ActionController
- autoload :Base, "action_controller/base"
- autoload :Benchmarking, "action_controller/metal/benchmarking"
- autoload :ConditionalGet, "action_controller/metal/conditional_get"
- autoload :Configuration, "action_controller/metal/configuration"
- autoload :Head, "action_controller/metal/head"
- autoload :Helpers, "action_controller/metal/helpers"
- autoload :HideActions, "action_controller/metal/hide_actions"
- autoload :Layouts, "action_controller/metal/layouts"
- autoload :Metal, "action_controller/metal"
- autoload :Middleware, "action_controller/middleware"
- autoload :RackConvenience, "action_controller/metal/rack_convenience"
- autoload :Rails2Compatibility, "action_controller/metal/compatibility"
- autoload :Redirector, "action_controller/metal/redirector"
- autoload :RenderingController, "action_controller/metal/rendering_controller"
- autoload :RenderOptions, "action_controller/metal/render_options"
- autoload :Rescue, "action_controller/metal/rescuable"
- autoload :Responder, "action_controller/metal/responder"
- autoload :Session, "action_controller/metal/session"
- autoload :Testing, "action_controller/metal/testing"
- autoload :UrlFor, "action_controller/metal/url_for"
+ extend ActiveSupport::Autoload
- autoload :Caching, 'action_controller/caching'
- autoload :Dispatcher, 'action_controller/dispatch/dispatcher'
- autoload :Integration, 'action_controller/deprecated/integration_test'
- autoload :IntegrationTest, 'action_controller/deprecated/integration_test'
- autoload :MimeResponds, 'action_controller/metal/mime_responds'
- autoload :PerformanceTest, 'action_controller/deprecated/performance_test'
- autoload :PolymorphicRoutes, 'action_controller/polymorphic_routes'
- autoload :RecordIdentifier, 'action_controller/record_identifier'
- autoload :Routing, 'action_controller/deprecated'
- autoload :SessionManagement, 'action_controller/metal/session_management'
- autoload :TestCase, 'action_controller/testing/test_case'
- autoload :TestProcess, 'action_controller/testing/process'
- autoload :UrlRewriter, 'action_controller/url_rewriter'
- autoload :UrlWriter, 'action_controller/url_rewriter'
+ autoload :Base
+ autoload :Caching
+ autoload :PolymorphicRoutes
+ autoload :Translation
+ autoload :Metal
+ autoload :Middleware
- autoload :Verification, 'action_controller/metal/verification'
- autoload :Flash, 'action_controller/metal/flash'
- autoload :RequestForgeryProtection, 'action_controller/metal/request_forgery_protection'
- autoload :Streaming, 'action_controller/metal/streaming'
- autoload :HttpAuthentication, 'action_controller/metal/http_authentication'
- autoload :FilterParameterLogging, 'action_controller/metal/filter_parameter_logging'
- autoload :Translation, 'action_controller/translation'
- autoload :Cookies, 'action_controller/metal/cookies'
+ autoload_under "metal" do
+ autoload :Benchmarking
+ autoload :ConditionalGet
+ autoload :Configuration
+ autoload :Head
+ autoload :Helpers
+ autoload :HideActions
+ autoload :Layouts
+ autoload :Logger
+ autoload :MimeResponds
+ autoload :RackDelegation
+ autoload :Compatibility
+ autoload :Redirecting
+ autoload :Rendering
+ autoload :Renderers
+ autoload :Rescue
+ autoload :Responder
+ autoload :SessionManagement
+ autoload :UrlFor
+ autoload :Verification
+ autoload :Flash
+ autoload :RequestForgeryProtection
+ autoload :Streaming
+ autoload :HttpAuthentication
+ autoload :FilterParameterLogging
+ autoload :Cookies
+ end
- autoload :ActionControllerError, 'action_controller/metal/exceptions'
- autoload :RenderError, 'action_controller/metal/exceptions'
- autoload :RoutingError, 'action_controller/metal/exceptions'
- autoload :MethodNotAllowed, 'action_controller/metal/exceptions'
- autoload :NotImplemented, 'action_controller/metal/exceptions'
- autoload :UnknownController, 'action_controller/metal/exceptions'
- autoload :MissingFile, 'action_controller/metal/exceptions'
- autoload :RenderError, 'action_controller/metal/exceptions'
- autoload :SessionOverflowError, 'action_controller/metal/exceptions'
- autoload :UnknownHttpMethod, 'action_controller/metal/exceptions'
-end
+ autoload :Dispatcher, 'action_controller/dispatch/dispatcher'
+ autoload :PerformanceTest, 'action_controller/deprecated/performance_test'
+ autoload :Routing, 'action_controller/deprecated'
+ autoload :Integration, 'action_controller/deprecated/integration_test'
+ autoload :IntegrationTest, 'action_controller/deprecated/integration_test'
-autoload :HTML, 'action_controller/vendor/html-scanner'
-autoload :AbstractController, 'abstract_controller'
+ eager_autoload do
+ autoload :RecordIdentifier
+ autoload :UrlRewriter
+ autoload :UrlWriter, 'action_controller/url_rewriter'
+
+ # TODO: Don't autoload exceptions, setup explicit
+ # requires for files that need them
+ autoload_at "action_controller/metal/exceptions" do
+ autoload :ActionControllerError
+ autoload :RenderError
+ autoload :RoutingError
+ autoload :MethodNotAllowed
+ autoload :NotImplemented
+ autoload :UnknownController
+ autoload :MissingFile
+ autoload :RenderError
+ autoload :SessionOverflowError
+ autoload :UnknownHttpMethod
+ end
+ end
+end
+# All of these simply register additional autoloads
+require 'abstract_controller'
require 'action_dispatch'
require 'action_view'
+require 'action_controller/vendor/html-scanner'
# Common ActiveSupport usage in ActionController
require "active_support/concern"
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 4c026fe5f7..dbba69f637 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -8,26 +8,25 @@ module ActionController
include ActionController::Helpers
include ActionController::HideActions
include ActionController::UrlFor
- include ActionController::Redirector
- include ActionController::RenderingController
- include ActionController::RenderOptions::All
+ include ActionController::Redirecting
+ include ActionController::Rendering
+ include ActionController::Renderers::All
include ActionController::Layouts
include ActionController::ConditionalGet
- include ActionController::RackConvenience
+ include ActionController::RackDelegation
+ include ActionController::Logger
include ActionController::Benchmarking
include ActionController::Configuration
# Legacy modules
include SessionManagement
- include ActionDispatch::StatusCodes
include ActionController::Caching
include ActionController::MimeResponds
# Rails 2.x compatibility
- include ActionController::Rails2Compatibility
+ include ActionController::Compatibility
include ActionController::Cookies
- include ActionController::Session
include ActionController::Flash
include ActionController::Verification
include ActionController::RequestForgeryProtection
@@ -91,7 +90,7 @@ module ActionController
end
if options[:status]
- options[:status] = interpret_status(options[:status]).to_i
+ options[:status] = Rack::Utils.status_code(options[:status])
end
options[:update] = blk if block_given?
@@ -107,62 +106,5 @@ module ActionController
options = _normalize_options(action, options, &blk)
super(options)
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?
-
- status = if options.is_a?(Hash) && options.key?(:status)
- interpret_status(options.delete(:status))
- elsif response_status.key?(:status)
- interpret_status(response_status[:status])
- else
- 302
- end
-
- url = 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+.-]*:.*}
- options
- when String
- request.protocol + request.host_with_port + options
- when :back
- raise RedirectBackError unless refer = request.headers["Referer"]
- refer
- else
- url_for(options)
- end
-
- super(url, status)
- end
end
end
diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb
index 3caf759032..d784138ebe 100644
--- a/actionpack/lib/action_controller/caching.rb
+++ b/actionpack/lib/action_controller/caching.rb
@@ -30,12 +30,15 @@ module ActionController #:nodoc:
# config.action_controller.cache_store = MyOwnStore.new("parameter")
module Caching
extend ActiveSupport::Concern
+ extend ActiveSupport::Autoload
- autoload :Actions, 'action_controller/caching/actions'
- autoload :Fragments, 'action_controller/caching/fragments'
- autoload :Pages, 'action_controller/caching/pages'
- autoload :Sweeper, 'action_controller/caching/sweeping'
- autoload :Sweeping, 'action_controller/caching/sweeping'
+ eager_autoload do
+ autoload :Actions
+ autoload :Fragments
+ autoload :Pages
+ autoload :Sweeper, 'action_controller/caching/sweeping'
+ autoload :Sweeping, 'action_controller/caching/sweeping'
+ end
included do
@@cache_store = nil
diff --git a/actionpack/lib/action_controller/dispatch/dispatcher.rb b/actionpack/lib/action_controller/dispatch/dispatcher.rb
index e04da42637..cf02757cf6 100644
--- a/actionpack/lib/action_controller/dispatch/dispatcher.rb
+++ b/actionpack/lib/action_controller/dispatch/dispatcher.rb
@@ -13,11 +13,6 @@ module ActionController
# Run prepare callbacks before every request in development mode
self.prepare_each_request = true
- # Development mode callbacks
- ActionDispatch::Callbacks.before_dispatch do |app|
- ActionController::Routing::Routes.reload
- end
-
ActionDispatch::Callbacks.after_dispatch do
# Cleanup the application before processing the current request.
ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb
index 60b3f9a89b..b436de9878 100644
--- a/actionpack/lib/action_controller/metal.rb
+++ b/actionpack/lib/action_controller/metal.rb
@@ -45,7 +45,7 @@ module ActionController
# The details below can be overridden to support a specific
# Request and Response object. The default ActionController::Base
- # implementation includes RackConvenience, which makes a request
+ # implementation includes RackDelegation, which makes a request
# and response object available. You might wish to control the
# environment and response manually for performance reasons.
@@ -57,7 +57,7 @@ module ActionController
end
# Basic implementations for content_type=, location=, and headers are
- # provided to reduce the dependency on the RackConvenience module
+ # provided to reduce the dependency on the RackDelegation module
# in Renderer and Redirector.
def content_type=(type)
@@ -68,6 +68,10 @@ module ActionController
headers["Location"] = url
end
+ def status=(status)
+ @_status = Rack::Utils.status_code(status)
+ end
+
# :api: private
def dispatch(name, env)
@_env = env
@@ -92,6 +96,7 @@ module ActionController
def initialize(controller, action)
@controller, @action = controller, action
+ @_formats = [Mime::HTML]
end
def call(env)
diff --git a/actionpack/lib/action_controller/metal/benchmarking.rb b/actionpack/lib/action_controller/metal/benchmarking.rb
index e58df69172..f73f635b0d 100644
--- a/actionpack/lib/action_controller/metal/benchmarking.rb
+++ b/actionpack/lib/action_controller/metal/benchmarking.rb
@@ -53,7 +53,6 @@ module ActionController #:nodoc:
log_message << " [#{complete_request_uri rescue "unknown"}]"
logger.info(log_message)
- response.headers["X-Runtime"] = "%.0f" % ms
else
super
end
diff --git a/actionpack/lib/action_controller/metal/compatibility.rb b/actionpack/lib/action_controller/metal/compatibility.rb
index c251d79f4e..a90f798cd5 100644
--- a/actionpack/lib/action_controller/metal/compatibility.rb
+++ b/actionpack/lib/action_controller/metal/compatibility.rb
@@ -1,5 +1,5 @@
module ActionController
- module Rails2Compatibility
+ module Compatibility
extend ActiveSupport::Concern
class ::ActionController::ActionControllerError < StandardError #:nodoc:
@@ -46,11 +46,8 @@ module ActionController
cattr_accessor :use_accept_header
self.use_accept_header = true
- cattr_accessor :page_cache_directory
self.page_cache_directory = defined?(Rails.public_path) ? Rails.public_path : ""
- cattr_reader :cache_store
-
cattr_accessor :consider_all_requests_local
self.consider_all_requests_local = true
@@ -116,7 +113,7 @@ module ActionController
details[:prefix] = nil if name =~ /\blayouts/
super
end
-
+
# Move this into a "don't run in production" module
def _default_layout(details, require_layout = false)
super
diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb
index 5156fbc1d5..61e7ece90d 100644
--- a/actionpack/lib/action_controller/metal/conditional_get.rb
+++ b/actionpack/lib/action_controller/metal/conditional_get.rb
@@ -2,7 +2,7 @@ module ActionController
module ConditionalGet
extend ActiveSupport::Concern
- include RackConvenience
+ include RackDelegation
include Head
# Sets the etag, last_modified, or both on the response and renders a
diff --git a/actionpack/lib/action_controller/metal/cookies.rb b/actionpack/lib/action_controller/metal/cookies.rb
index 6855ca1478..8d5f0d7199 100644
--- a/actionpack/lib/action_controller/metal/cookies.rb
+++ b/actionpack/lib/action_controller/metal/cookies.rb
@@ -46,60 +46,152 @@ module ActionController #:nodoc:
module Cookies
extend ActiveSupport::Concern
- include RackConvenience
+ include RackDelegation
included do
helper_method :cookies
+ cattr_accessor :cookie_verifier_secret
end
- protected
- # Returns the cookie container, which operates as described above.
- def cookies
- @cookies ||= CookieJar.build(request, response)
+ protected
+ # Returns the cookie container, which operates as described above.
+ def cookies
+ @cookies ||= CookieJar.build(request, response)
+ end
end
- end
- class CookieJar < Hash #:nodoc:
- def self.build(request, response)
- new.tap do |hash|
- hash.update(request.cookies)
- hash.response = response
+ class CookieJar < Hash #:nodoc:
+ def self.build(request, response)
+ new.tap do |hash|
+ hash.update(request.cookies)
+ hash.response = response
+ end
end
- end
- attr_accessor :response
+ attr_accessor :response
- # Returns the value of the cookie by +name+, or +nil+ if no such cookie exists.
- def [](name)
- super(name.to_s)
- end
+ # Returns the value of the cookie by +name+, or +nil+ if no such cookie exists.
+ def [](name)
+ super(name.to_s)
+ end
+
+ # Sets the cookie named +name+. The second argument may be the very cookie
+ # value, or a hash of options as documented above.
+ def []=(key, options)
+ if options.is_a?(Hash)
+ options.symbolize_keys!
+ value = options[:value]
+ else
+ value = options
+ options = { :value => value }
+ end
- # Sets the cookie named +name+. The second argument may be the very cookie
- # value, or a hash of options as documented above.
- def []=(key, options)
- if options.is_a?(Hash)
+ super(key.to_s, value)
+
+ options[:path] ||= "/"
+ response.set_cookie(key, options)
+ end
+
+ # Removes the cookie on the client machine by setting the value to an empty string
+ # and setting its expiration date into the past. Like <tt>[]=</tt>, you can pass in
+ # an options hash to delete cookies with extra data such as a <tt>:path</tt>.
+ def delete(key, options = {})
options.symbolize_keys!
- value = options[:value]
- else
- value = options
- options = { :value => value }
+ options[:path] ||= "/"
+ value = super(key.to_s)
+ response.delete_cookie(key, options)
+ value
end
- super(key.to_s, value)
-
- options[:path] ||= "/"
- response.set_cookie(key, options)
+ # Returns a jar that'll automatically set the assigned cookies to have an expiration date 20 years from now. Example:
+ #
+ # cookies.permanent[:prefers_open_id] = true
+ # # => Set-Cookie: prefers_open_id=true; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
+ #
+ # This jar is only meant for writing. You'll read permanent cookies through the regular accessor.
+ #
+ # This jar allows chaining with the signed jar as well, so you can set permanent, signed cookies. Examples:
+ #
+ # cookies.permanent.signed[:remember_me] = current_user.id
+ # # => Set-Cookie: discount=BAhU--848956038e692d7046deab32b7131856ab20e14e; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
+ def permanent
+ @permanent ||= PermanentCookieJar.new(self)
+ end
+
+ # Returns a jar that'll automatically generate a signed representation of cookie value and verify it when reading from
+ # the cookie again. This is useful for creating cookies with values that the user is not supposed to change. If a signed
+ # cookie was tampered with by the user (or a 3rd party), an ActiveSupport::MessageVerifier::InvalidSignature exception will
+ # be raised.
+ #
+ # This jar requires that you set a suitable secret for the verification on ActionController::Base.cookie_verifier_secret.
+ #
+ # Example:
+ #
+ # cookies.signed[:discount] = 45
+ # # => Set-Cookie: discount=BAhpMg==--2c1c6906c90a3bc4fd54a51ffb41dffa4bf6b5f7; path=/
+ #
+ # cookies.signed[:discount] # => 45
+ def signed
+ @signed ||= SignedCookieJar.new(self)
+ end
end
-
- # Removes the cookie on the client machine by setting the value to an empty string
- # and setting its expiration date into the past. Like <tt>[]=</tt>, you can pass in
- # an options hash to delete cookies with extra data such as a <tt>:path</tt>.
- def delete(key, options = {})
- options.symbolize_keys!
- options[:path] ||= "/"
- value = super(key.to_s)
- response.delete_cookie(key, options)
- value
+
+ class PermanentCookieJar < CookieJar #:nodoc:
+ def initialize(parent_jar)
+ @parent_jar = parent_jar
+ end
+
+ def []=(key, options)
+ if options.is_a?(Hash)
+ options.symbolize_keys!
+ else
+ options = { :value => options }
+ end
+
+ options[:expires] = 20.years.from_now
+ @parent_jar[key] = options
+ end
+
+ def signed
+ @signed ||= SignedCookieJar.new(self)
+ end
+
+ def controller
+ @parent_jar.controller
+ end
+
+ def method_missing(method, *arguments, &block)
+ @parent_jar.send(method, *arguments, &block)
+ end
end
+
+ class SignedCookieJar < CookieJar #:nodoc:
+ def initialize(parent_jar)
+ unless ActionController::Base.cookie_verifier_secret
+ raise "You must set ActionController::Base.cookie_verifier_secret to use signed cookies"
+ end
+
+ @parent_jar = parent_jar
+ @verifier = ActiveSupport::MessageVerifier.new(ActionController::Base.cookie_verifier_secret)
+ end
+
+ def [](name)
+ @verifier.verify(@parent_jar[name])
+ end
+
+ def []=(key, options)
+ if options.is_a?(Hash)
+ options.symbolize_keys!
+ options[:value] = @verifier.generate(options[:value])
+ else
+ options = { :value => @verifier.generate(options) }
+ end
+
+ @parent_jar[key] = options
+ end
+
+ def method_missing(method, *arguments, &block)
+ @parent_jar.send(method, *arguments, &block)
+ end
end
end
diff --git a/actionpack/lib/action_controller/metal/exceptions.rb b/actionpack/lib/action_controller/metal/exceptions.rb
index b9d23da3e0..07024d0a9a 100644
--- a/actionpack/lib/action_controller/metal/exceptions.rb
+++ b/actionpack/lib/action_controller/metal/exceptions.rb
@@ -18,18 +18,9 @@ module ActionController
def initialize(*allowed_methods)
super("Only #{allowed_methods.to_sentence(:locale => :en)} requests are allowed.")
- @allowed_methods = allowed_methods
- end
-
- def allowed_methods_header
- allowed_methods.map { |method_symbol| method_symbol.to_s.upcase } * ', '
- end
-
- def handle_response!(response)
- response.headers['Allow'] ||= allowed_methods_header
end
end
-
+
class NotImplemented < MethodNotAllowed #:nodoc:
end
diff --git a/actionpack/lib/action_controller/metal/flash.rb b/actionpack/lib/action_controller/metal/flash.rb
index f43900faa0..581ff6109e 100644
--- a/actionpack/lib/action_controller/metal/flash.rb
+++ b/actionpack/lib/action_controller/metal/flash.rb
@@ -28,7 +28,9 @@ module ActionController #:nodoc:
module Flash
extend ActiveSupport::Concern
- include Session
+ included do
+ helper_method :alert, :notice
+ end
class FlashNow #:nodoc:
def initialize(flash)
@@ -133,10 +135,44 @@ module ActionController #:nodoc:
Array(key || keys).each { |k| used ? @used << k : @used.delete(k) }
return key ? self[key] : self
end
+ end
+
+ # Access the contents of the flash. Use <tt>flash["notice"]</tt> to
+ # read a notice you put there or <tt>flash["notice"] = "hello"</tt>
+ # to put a new one.
+ def flash #:doc:
+ unless @_flash
+ @_flash = session["flash"] || FlashHash.new
+ @_flash.sweep
end
+ @_flash
+ end
+
+ # Convenience accessor for flash[:alert]
+ def alert
+ flash[:alert]
+ end
+
+ # Convenience accessor for flash[:alert]=
+ def alert=(message)
+ flash[:alert] = message
+ end
+
+ # Convenience accessor for flash[:notice]
+ def notice
+ flash[:notice]
+ end
+
+ # Convenience accessor for flash[:notice]=
+ def notice=(message)
+ flash[:notice] = message
+ end
+
+
protected
def process_action(method_name)
+ @_flash = nil
super
@_flash.store(session) if @_flash
@_flash = nil
@@ -147,16 +183,20 @@ module ActionController #:nodoc:
@_flash = nil
end
- # Access the contents of the flash. Use <tt>flash["notice"]</tt> to
- # read a notice you put there or <tt>flash["notice"] = "hello"</tt>
- # to put a new one.
- def flash #:doc:
- unless @_flash
- @_flash = session["flash"] || FlashHash.new
- @_flash.sweep
+ def redirect_to(options = {}, response_status_and_flash = {}) #:doc:
+ if alert = response_status_and_flash.delete(:alert)
+ flash[:alert] = alert
+ end
+
+ if notice = response_status_and_flash.delete(:notice)
+ flash[:notice] = notice
+ end
+
+ if other_flashes = response_status_and_flash.delete(:flash)
+ flash.update(other_flashes)
end
- @_flash
+ super(options, response_status_and_flash)
end
end
end
diff --git a/actionpack/lib/action_controller/metal/head.rb b/actionpack/lib/action_controller/metal/head.rb
index 68fa0a0402..c82d9cf369 100644
--- a/actionpack/lib/action_controller/metal/head.rb
+++ b/actionpack/lib/action_controller/metal/head.rb
@@ -1,5 +1,7 @@
module ActionController
module Head
+ include UrlFor
+
# 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
@@ -21,7 +23,10 @@ module ActionController
headers[key.to_s.dasherize.split(/-/).map { |v| v.capitalize }.join("-")] = value.to_s
end
- render :nothing => true, :status => status, :location => location
+ self.status = status
+ self.location = url_for(location) if location
+ self.content_type = Mime[formats.first]
+ self.response_body = " "
end
end
end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb
index b4325e24ad..d0402e5bad 100644
--- a/actionpack/lib/action_controller/metal/helpers.rb
+++ b/actionpack/lib/action_controller/metal/helpers.rb
@@ -52,7 +52,7 @@ module ActionController
included do
# Set the default directory for helpers
extlib_inheritable_accessor(:helpers_dir) do
- defined?(Rails) ? "#{Rails.root}/app/helpers" : "app/helpers"
+ defined?(Rails.root) ? "#{Rails.root}/app/helpers" : "app/helpers"
end
end
diff --git a/actionpack/lib/action_controller/metal/layouts.rb b/actionpack/lib/action_controller/metal/layouts.rb
index cc7088248a..f44498a884 100644
--- a/actionpack/lib/action_controller/metal/layouts.rb
+++ b/actionpack/lib/action_controller/metal/layouts.rb
@@ -158,7 +158,7 @@ module ActionController
module Layouts
extend ActiveSupport::Concern
- include ActionController::RenderingController
+ include ActionController::Rendering
include AbstractController::Layouts
module ClassMethods
diff --git a/actionpack/lib/action_controller/metal/logger.rb b/actionpack/lib/action_controller/metal/logger.rb
new file mode 100644
index 0000000000..956d7dd371
--- /dev/null
+++ b/actionpack/lib/action_controller/metal/logger.rb
@@ -0,0 +1,34 @@
+require 'abstract_controller/logger'
+
+module ActionController
+ module Logger
+ # Override process_action in the AbstractController::Base
+ # to log details about the method.
+ def process_action(action)
+ result = ActiveSupport::Notifications.instrument(:process_action,
+ :controller => self, :action => action) do
+ super
+ end
+
+ if logger
+ log = AbstractController::Logger::DelayedLog.new do
+ "\n\nProcessing #{self.class.name}\##{action_name} " \
+ "to #{request.formats} (for #{request_origin}) " \
+ "[#{request.method.to_s.upcase}]"
+ end
+
+ logger.info(log)
+ end
+
+ result
+ end
+
+ private
+
+ # Returns the request origin with the IP and time. This needs to be cached,
+ # otherwise we would get different results for each time it calls.
+ def request_origin
+ @request_origin ||= "#{request.remote_ip} at #{Time.now.to_s(:db)}"
+ end
+ end
+end
diff --git a/actionpack/lib/action_controller/metal/rack_convenience.rb b/actionpack/lib/action_controller/metal/rack_delegation.rb
index 131d20114d..bb55383631 100644
--- a/actionpack/lib/action_controller/metal/rack_convenience.rb
+++ b/actionpack/lib/action_controller/metal/rack_delegation.rb
@@ -1,8 +1,12 @@
+require 'action_dispatch/http/request'
+require 'action_dispatch/http/response'
+
module ActionController
- module RackConvenience
+ module RackDelegation
extend ActiveSupport::Concern
included do
+ delegate :session, :to => "@_request"
delegate :headers, :status=, :location=, :content_type=,
:status, :location, :content_type, :to => "@_response"
attr_internal :request
@@ -23,5 +27,9 @@ module ActionController
response.body = body if response
super
end
+
+ def reset_session
+ @_request.reset_session
+ end
end
end
diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb
new file mode 100644
index 0000000000..7a2f9a6fc5
--- /dev/null
+++ b/actionpack/lib/action_controller/metal/redirecting.rb
@@ -0,0 +1,90 @@
+module ActionController
+ class RedirectBackError < AbstractController::Error #: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 Redirecting
+ extend ActiveSupport::Concern
+ include AbstractController::Logger
+
+ # 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
+ #
+ # It is also possible to assign a flash message as part of the redirection. There are two special accessors for commonly used the flash names
+ # +alert+ and +notice+ as well as a general purpose +flash+ bucket.
+ #
+ # Examples:
+ # redirect_to post_url(@post), :alert => "Watch it, mister!"
+ # redirect_to post_url(@post), :status=> :found, :notice => "Pay attention to the road"
+ # redirect_to post_url(@post), :status => 301, :flash => { :updated_post_id => @post.id }
+ # redirect_to { :action=>'atom' }, :alert => "Something serious happened"
+ #
+ # 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?
+ raise AbstractController::DoubleRenderError if response_body
+
+ self.status = _extract_redirect_to_status(options, response_status)
+ self.location = _compute_redirect_to_location(options)
+ self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.h(location)}\">redirected</a>.</body></html>"
+
+ logger.info("Redirected to #{location}") if logger && logger.info?
+ end
+
+ private
+ def _extract_redirect_to_status(options, response_status)
+ status = if options.is_a?(Hash) && options.key?(:status)
+ Rack::Utils.status_code(options.delete(:status))
+ elsif response_status.key?(:status)
+ Rack::Utils.status_code(response_status[:status])
+ else
+ 302
+ end
+ end
+
+ def _compute_redirect_to_location(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+.-]*:.*}
+ options
+ when String
+ request.protocol + request.host_with_port + options
+ when :back
+ raise RedirectBackError unless refer = request.headers["Referer"]
+ refer
+ else
+ url_for(options)
+ end.gsub(/[\r\n]/, '')
+ end
+ end
+end
diff --git a/actionpack/lib/action_controller/metal/redirector.rb b/actionpack/lib/action_controller/metal/redirector.rb
deleted file mode 100644
index b55f5e7bfc..0000000000
--- a/actionpack/lib/action_controller/metal/redirector.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-module ActionController
- class RedirectBackError < AbstractController::Error #: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
- extend ActiveSupport::Concern
- include AbstractController::Logger
-
- def redirect_to(url, status) #:doc:
- raise AbstractController::DoubleRenderError if response_body
- logger.info("Redirected to #{url}") if logger && logger.info?
- self.status = status
- self.location = url.gsub(/[\r\n]/, '')
- self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.h(url)}\">redirected</a>.</body></html>"
- end
- end
-end
diff --git a/actionpack/lib/action_controller/metal/render_options.rb b/actionpack/lib/action_controller/metal/render_options.rb
deleted file mode 100644
index 0d69ca10df..0000000000
--- a/actionpack/lib/action_controller/metal/render_options.rb
+++ /dev/null
@@ -1,103 +0,0 @@
-module ActionController
- module RenderOptions
- extend ActiveSupport::Concern
-
- included do
- extlib_inheritable_accessor :_renderers
- self._renderers = []
- end
-
- module ClassMethods
- def _write_render_options
- renderers = _renderers.map do |r|
- <<-RUBY_EVAL
- if options.key?(:#{r})
- _process_options(options)
- return render_#{r}(options[:#{r}], options)
- end
- RUBY_EVAL
- end
-
- class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
- def _handle_render_options(options)
- #{renderers.join}
- end
- RUBY_EVAL
- end
-
- def _add_render_option(name)
- _renderers << name
- _write_render_options
- end
- end
-
- def render_to_body(options)
- _handle_render_options(options) || super
- end
- end
-
- module RenderOption #:nodoc:
- def self.extended(base)
- base.extend ActiveSupport::Concern
- base.send :include, ::ActionController::RenderOptions
-
- def base.register_renderer(name)
- included { _add_render_option(name) }
- end
- end
- end
-
- module RenderOptions
- module Json
- extend RenderOption
- register_renderer :json
-
- def render_json(json, options)
- json = ActiveSupport::JSON.encode(json) unless json.respond_to?(:to_str)
- json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
- self.content_type ||= Mime::JSON
- self.response_body = json
- end
- end
-
- module Js
- extend RenderOption
- register_renderer :js
-
- def render_js(js, options)
- self.content_type ||= Mime::JS
- self.response_body = js.respond_to?(:to_js) ? js.to_js : js
- end
- end
-
- module Xml
- extend RenderOption
- register_renderer :xml
-
- def render_xml(xml, options)
- self.content_type ||= Mime::XML
- self.response_body = xml.respond_to?(:to_xml) ? xml.to_xml : xml
- end
- end
-
- module RJS
- extend RenderOption
- register_renderer :update
-
- def render_update(proc, options)
- generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(view_context, &proc)
- self.content_type = Mime::JS
- self.response_body = generator.to_s
- end
- end
-
- module All
- extend ActiveSupport::Concern
-
- include ActionController::RenderOptions::Json
- include ActionController::RenderOptions::Js
- include ActionController::RenderOptions::Xml
- include ActionController::RenderOptions::RJS
- end
- end
-end
diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb
new file mode 100644
index 0000000000..c1ba47927a
--- /dev/null
+++ b/actionpack/lib/action_controller/metal/renderers.rb
@@ -0,0 +1,91 @@
+module ActionController
+ def self.add_renderer(key, &block)
+ Renderers.add(key, &block)
+ end
+
+ module Renderers
+ extend ActiveSupport::Concern
+
+ included do
+ extlib_inheritable_accessor :_renderers
+ self._renderers = {}
+ end
+
+ module ClassMethods
+ def _write_render_options
+ renderers = _renderers.map do |name, value|
+ <<-RUBY_EVAL
+ if options.key?(:#{name})
+ _process_options(options)
+ return _render_option_#{name}(options[:#{name}], options)
+ end
+ RUBY_EVAL
+ end
+
+ class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
+ def _handle_render_options(options)
+ #{renderers.join}
+ end
+ RUBY_EVAL
+ end
+
+ def use_renderers(*args)
+ args.each do |key|
+ _renderers[key] = RENDERERS[key]
+ end
+ _write_render_options
+ end
+ alias use_renderer use_renderers
+ end
+
+ def render_to_body(options)
+ _handle_render_options(options) || super
+ end
+
+ RENDERERS = {}
+ def self.add(key, &block)
+ define_method("_render_option_#{key}", &block)
+ RENDERERS[key] = block
+ All._write_render_options
+ end
+
+ module All
+ extend ActiveSupport::Concern
+ include Renderers
+
+ INCLUDED = []
+ included do
+ self._renderers = RENDERERS
+ _write_render_options
+ INCLUDED << self
+ end
+
+ def self._write_render_options
+ INCLUDED.each(&:_write_render_options)
+ end
+ end
+
+ add :json do |json, options|
+ json = ActiveSupport::JSON.encode(json) unless json.respond_to?(:to_str)
+ json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
+ self.content_type ||= Mime::JSON
+ self.response_body = json
+ end
+
+ add :js do |js, options|
+ self.content_type ||= Mime::JS
+ self.response_body = js.respond_to?(:to_js) ? js.to_js : js
+ end
+
+ add :xml do |xml, options|
+ self.content_type ||= Mime::XML
+ self.response_body = xml.respond_to?(:to_xml) ? xml.to_xml : xml
+ end
+
+ add :update do |proc, options|
+ generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(view_context, &proc)
+ self.content_type = Mime::JS
+ self.response_body = generator.to_s
+ end
+ end
+end
diff --git a/actionpack/lib/action_controller/metal/rendering_controller.rb b/actionpack/lib/action_controller/metal/rendering.rb
index 237299cd30..20eb524e50 100644
--- a/actionpack/lib/action_controller/metal/rendering_controller.rb
+++ b/actionpack/lib/action_controller/metal/rendering.rb
@@ -1,9 +1,9 @@
module ActionController
- module RenderingController
+ module Rendering
extend ActiveSupport::Concern
included do
- include AbstractController::RenderingController
+ include AbstractController::Rendering
include AbstractController::LocalizedCache
end
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index 173df79ee7..2826b1e34c 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -5,7 +5,7 @@ module ActionController #:nodoc:
module RequestForgeryProtection
extend ActiveSupport::Concern
- include AbstractController::Helpers, Session
+ include AbstractController::Helpers
included do
# Sets the token parameter name for RequestForgery. Calling +protect_from_forgery+
@@ -19,31 +19,31 @@ module ActionController #:nodoc:
helper_method :form_authenticity_token
helper_method :protect_against_forgery?
end
-
- # Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current
- # web application, not a forged link from another site, is done by embedding a token based on a random
+
+ # Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current
+ # web application, not a forged link from another site, is done by embedding a token based on a random
# string stored in the session (which an attacker wouldn't know) in all forms and Ajax requests generated
- # by Rails and then verifying the authenticity of that token in the controller. Only HTML/JavaScript
- # requests are checked, so this will not protect your XML API (presumably you'll have a different
- # authentication scheme there anyway). Also, GET requests are not protected as these should be
+ # by Rails and then verifying the authenticity of that token in the controller. Only HTML/JavaScript
+ # requests are checked, so this will not protect your XML API (presumably you'll have a different
+ # authentication scheme there anyway). Also, GET requests are not protected as these should be
# idempotent anyway.
#
# This is turned on with the <tt>protect_from_forgery</tt> method, which will check the token and raise an
- # ActionController::InvalidAuthenticityToken if it doesn't match what was expected. You can customize the
+ # ActionController::InvalidAuthenticityToken if it doesn't match what was expected. You can customize the
# error message in production by editing public/422.html. A call to this method in ApplicationController is
# generated by default in post-Rails 2.0 applications.
#
- # The token parameter is named <tt>authenticity_token</tt> by default. If you are generating an HTML form
- # manually (without the use of Rails' <tt>form_for</tt>, <tt>form_tag</tt> or other helpers), you have to
- # include a hidden field named like that and set its value to what is returned by
+ # The token parameter is named <tt>authenticity_token</tt> by default. If you are generating an HTML form
+ # manually (without the use of Rails' <tt>form_for</tt>, <tt>form_tag</tt> or other helpers), you have to
+ # include a hidden field named like that and set its value to what is returned by
# <tt>form_authenticity_token</tt>.
#
- # Request forgery protection is disabled by default in test environment. If you are upgrading from Rails
+ # Request forgery protection is disabled by default in test environment. If you are upgrading from Rails
# 1.x, add this to config/environments/test.rb:
#
# # Disable request forgery protection in test environment
# config.action_controller.allow_forgery_protection = false
- #
+ #
# == Learn more about CSRF (Cross-Site Request Forgery) attacks
#
# Here are some resources:
@@ -52,11 +52,11 @@ module ActionController #:nodoc:
#
# Keep in mind, this is NOT a silver-bullet, plug 'n' play, warm security blanket for your rails application.
# There are a few guidelines you should follow:
- #
+ #
# * Keep your GET requests safe and idempotent. More reading material:
# * http://www.xml.com/pub/a/2002/04/24/deviant.html
# * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
- # * Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look
+ # * Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look
# for "Expires: at end of session"
#
module ClassMethods
@@ -92,7 +92,7 @@ module ActionController #:nodoc:
# * is it a GET request? Gets should be safe and idempotent
# * Does the form_authenticity_token match the given token value from the params?
def verified_request?
- !protect_against_forgery? || request.forgery_whitelisted? ||
+ !protect_against_forgery? || request.forgery_whitelisted? ||
form_authenticity_token == params[request_forgery_protection_token]
end
diff --git a/actionpack/lib/action_controller/metal/rescuable.rb b/actionpack/lib/action_controller/metal/rescue.rb
index bbca1b2179..bbca1b2179 100644
--- a/actionpack/lib/action_controller/metal/rescuable.rb
+++ b/actionpack/lib/action_controller/metal/rescue.rb
diff --git a/actionpack/lib/action_controller/metal/responder.rb b/actionpack/lib/action_controller/metal/responder.rb
index e8e88e7479..cb0e600871 100644
--- a/actionpack/lib/action_controller/metal/responder.rb
+++ b/actionpack/lib/action_controller/metal/responder.rb
@@ -80,6 +80,11 @@ module ActionController #:nodoc:
class Responder
attr_reader :controller, :request, :format, :resource, :resources, :options
+ ACTIONS_FOR_VERBS = {
+ :post => :new,
+ :put => :edit
+ }
+
def initialize(controller, resources, options={})
@controller = controller
@request = controller.request
@@ -102,9 +107,14 @@ module ActionController #:nodoc:
# not defined, call to_format.
#
def self.call(*args)
- responder = new(*args)
- method = :"to_#{responder.format}"
- responder.respond_to?(method) ? responder.send(method) : responder.to_format
+ new(*args).respond
+ end
+
+ # Main entry point for responder responsible to dispatch to the proper format.
+ #
+ def respond
+ method = :"to_#{format}"
+ respond_to?(method) ? send(method) : to_format
end
# HTML format does not render the resource, it always attempt to render a
@@ -133,7 +143,7 @@ module ActionController #:nodoc:
def navigation_behavior(error)
if get?
raise error
- elsif has_errors?
+ elsif has_errors? && default_action
render :action => default_action
else
redirect_to resource_location
@@ -204,7 +214,7 @@ module ActionController #:nodoc:
# the verb is post.
#
def default_action
- @action || (request.post? ? :new : :edit)
+ @action ||= ACTIONS_FOR_VERBS[request.method]
end
end
end
diff --git a/actionpack/lib/action_controller/metal/session.rb b/actionpack/lib/action_controller/metal/session.rb
deleted file mode 100644
index bcedd6e1c7..0000000000
--- a/actionpack/lib/action_controller/metal/session.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-module ActionController
- module Session
- extend ActiveSupport::Concern
-
- include RackConvenience
-
- def session
- @_request.session
- end
-
- def reset_session
- @_request.reset_session
- end
- end
-end
diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb
index 43c661bef4..288b5d7c99 100644
--- a/actionpack/lib/action_controller/metal/streaming.rb
+++ b/actionpack/lib/action_controller/metal/streaming.rb
@@ -4,7 +4,7 @@ module ActionController #:nodoc:
module Streaming
extend ActiveSupport::Concern
- include ActionController::RenderingController
+ include ActionController::Rendering
DEFAULT_SEND_FILE_OPTIONS = {
:type => 'application/octet-stream'.freeze,
diff --git a/actionpack/lib/action_controller/metal/testing.rb b/actionpack/lib/action_controller/metal/testing.rb
index a4a1116d9e..c193a5eff4 100644
--- a/actionpack/lib/action_controller/metal/testing.rb
+++ b/actionpack/lib/action_controller/metal/testing.rb
@@ -2,7 +2,7 @@ module ActionController
module Testing
extend ActiveSupport::Concern
- include RackConvenience
+ include RackDelegation
# OMG MEGA HAX
def process_with_new_base_test(request, response)
diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb
index 14c6523045..8c3810ebcb 100644
--- a/actionpack/lib/action_controller/metal/url_for.rb
+++ b/actionpack/lib/action_controller/metal/url_for.rb
@@ -2,7 +2,7 @@ module ActionController
module UrlFor
extend ActiveSupport::Concern
- include RackConvenience
+ include RackDelegation
# 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:
diff --git a/actionpack/lib/action_controller/metal/verification.rb b/actionpack/lib/action_controller/metal/verification.rb
index 500cced539..bce942b588 100644
--- a/actionpack/lib/action_controller/metal/verification.rb
+++ b/actionpack/lib/action_controller/metal/verification.rb
@@ -2,7 +2,7 @@ module ActionController #:nodoc:
module Verification #:nodoc:
extend ActiveSupport::Concern
- include AbstractController::Callbacks, Session, Flash, RenderingController
+ include AbstractController::Callbacks, Flash, Rendering
# This module provides a class-level method for specifying that certain
# actions are guarded against being called without certain prerequisites
@@ -35,7 +35,7 @@ module ActionController #:nodoc:
# :add_flash => { "alert" => "Failed to create your message" },
# :redirect_to => :category_url
#
- # Note that these prerequisites are not business rules. They do not examine
+ # Note that these prerequisites are not business rules. They do not examine
# the content of the session or the parameters. That level of validation should
# be encapsulated by your domain model or helper methods in the controller.
module ClassMethods
@@ -43,40 +43,40 @@ module ActionController #:nodoc:
# the user is redirected to a different action. The +options+ parameter
# is a hash consisting of the following key/value pairs:
#
- # <tt>:params</tt>::
- # a single key or an array of keys that must be in the <tt>params</tt>
+ # <tt>:params</tt>::
+ # a single key or an array of keys that must be in the <tt>params</tt>
# hash in order for the action(s) to be safely called.
- # <tt>:session</tt>::
- # a single key or an array of keys that must be in the <tt>session</tt>
+ # <tt>:session</tt>::
+ # a single key or an array of keys that must be in the <tt>session</tt>
# in order for the action(s) to be safely called.
- # <tt>:flash</tt>::
- # a single key or an array of keys that must be in the flash in order
+ # <tt>:flash</tt>::
+ # a single key or an array of keys that must be in the flash in order
# for the action(s) to be safely called.
- # <tt>:method</tt>::
- # a single key or an array of keys--any one of which must match the
- # current request method in order for the action(s) to be safely called.
- # (The key should be a symbol: <tt>:get</tt> or <tt>:post</tt>, for
+ # <tt>:method</tt>::
+ # a single key or an array of keys--any one of which must match the
+ # current request method in order for the action(s) to be safely called.
+ # (The key should be a symbol: <tt>:get</tt> or <tt>:post</tt>, for
# example.)
- # <tt>:xhr</tt>::
- # true/false option to ensure that the request is coming from an Ajax
- # call or not.
- # <tt>:add_flash</tt>::
- # a hash of name/value pairs that should be merged into the session's
+ # <tt>:xhr</tt>::
+ # true/false option to ensure that the request is coming from an Ajax
+ # call or not.
+ # <tt>:add_flash</tt>::
+ # a hash of name/value pairs that should be merged into the session's
# flash if the prerequisites cannot be satisfied.
- # <tt>:add_headers</tt>::
- # a hash of name/value pairs that should be merged into the response's
+ # <tt>:add_headers</tt>::
+ # a hash of name/value pairs that should be merged into the response's
# headers hash if the prerequisites cannot be satisfied.
- # <tt>:redirect_to</tt>::
- # the redirection parameters to be used when redirecting if the
- # prerequisites cannot be satisfied. You can redirect either to named
+ # <tt>:redirect_to</tt>::
+ # the redirection parameters to be used when redirecting if the
+ # prerequisites cannot be satisfied. You can redirect either to named
# route or to the action in some controller.
- # <tt>:render</tt>::
+ # <tt>:render</tt>::
# the render parameters to be used when the prerequisites cannot be satisfied.
- # <tt>:only</tt>::
- # only apply this verification to the actions specified in the associated
+ # <tt>:only</tt>::
+ # only apply this verification to the actions specified in the associated
# array (may also be a single value).
- # <tt>:except</tt>::
- # do not apply this verification to the actions specified in the associated
+ # <tt>:except</tt>::
+ # do not apply this verification to the actions specified in the associated
# array (may also be a single value).
def verify(options={})
before_filter :only => options[:only], :except => options[:except] do
@@ -94,31 +94,31 @@ module ActionController #:nodoc:
apply_remaining_actions(options) unless performed?
end
end
-
+
def prereqs_invalid?(options) # :nodoc:
- verify_presence_of_keys_in_hash_flash_or_params(options) ||
- verify_method(options) ||
+ verify_presence_of_keys_in_hash_flash_or_params(options) ||
+ verify_method(options) ||
verify_request_xhr_status(options)
end
-
+
def verify_presence_of_keys_in_hash_flash_or_params(options) # :nodoc:
[*options[:params] ].find { |v| v && params[v.to_sym].nil? } ||
[*options[:session]].find { |v| session[v].nil? } ||
[*options[:flash] ].find { |v| flash[v].nil? }
end
-
+
def verify_method(options) # :nodoc:
[*options[:method]].all? { |v| request.method != v.to_sym } if options[:method]
end
-
+
def verify_request_xhr_status(options) # :nodoc:
request.xhr? != options[:xhr] unless options[:xhr].nil?
end
-
+
def apply_redirect_to(redirect_to_option) # :nodoc:
(redirect_to_option.is_a?(Symbol) && redirect_to_option != :back) ? self.__send__(redirect_to_option) : redirect_to_option
end
-
+
def apply_remaining_actions(options) # :nodoc:
case
when options[:render] ; render(options[:render])
diff --git a/actionpack/lib/action_controller/notifications.rb b/actionpack/lib/action_controller/notifications.rb
deleted file mode 100644
index 1a4f29e0e2..0000000000
--- a/actionpack/lib/action_controller/notifications.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require 'active_support/notifications'
-
-ActiveSupport::Notifications.subscribe(/(read|write|cache|expire|exist)_(fragment|page)\??/) do |*args|
- event = ActiveSupport::Notifications::Event.new(*args)
-
- if logger = ActionController::Base.logger
- human_name = event.name.to_s.humanize
- logger.info("#{human_name} (%.1fms)" % event.duration)
- end
-end
diff --git a/actionpack/lib/action_controller/rails.rb b/actionpack/lib/action_controller/rails.rb
new file mode 100644
index 0000000000..36a52b3149
--- /dev/null
+++ b/actionpack/lib/action_controller/rails.rb
@@ -0,0 +1,102 @@
+module ActionController
+ class Plugin < Rails::Plugin
+ plugin_name :action_controller
+
+ initializer "action_controller.set_configs" do |app|
+ app.config.action_controller.each do |k,v|
+ ActionController::Base.send "#{k}=", v
+ end
+ end
+
+ # TODO: ActionController::Base.logger should delegate to its own config.logger
+ initializer "action_controller.logger" do
+ ActionController::Base.logger ||= Rails.logger
+ end
+
+ # Routing must be initialized after plugins to allow the former to extend the routes
+ # ---
+ # If Action Controller is not one of the loaded frameworks (Configuration#frameworks)
+ # this does nothing. Otherwise, it loads the routing definitions and sets up
+ # loading module used to lazily load controllers (Configuration#controller_paths).
+ initializer "action_controller.initialize_routing" do |app|
+ app.route_configuration_files << app.config.routes_configuration_file
+ app.route_configuration_files << app.config.builtin_routes_configuration_file
+ app.reload_routes!
+ end
+
+ # Include middleware to serve up static assets
+ initializer "action_controller.initialize_static_server" do |app|
+ if app.config.serve_static_assets
+ app.config.middleware.use(ActionDispatch::Static, Rails.public_path)
+ end
+ end
+
+ initializer "action_controller.initialize_middleware_stack" do |app|
+ middleware = app.config.middleware
+ middleware.use(::Rack::Lock, :if => lambda { ActionController::Base.allow_concurrency })
+ middleware.use(::Rack::Runtime)
+ middleware.use(ActionDispatch::ShowExceptions, lambda { ActionController::Base.consider_all_requests_local })
+ middleware.use(ActionDispatch::Callbacks, lambda { ActionController::Dispatcher.prepare_each_request })
+ middleware.use(lambda { ActionController::Base.session_store }, lambda { ActionController::Base.session_options })
+ middleware.use(ActionDispatch::ParamsParser)
+ middleware.use(::Rack::MethodOverride)
+ middleware.use(::Rack::Head)
+ middleware.use(ActionDispatch::StringCoercion)
+ end
+
+ initializer "action_controller.initialize_framework_caches" do
+ ActionController::Base.cache_store ||= RAILS_CACHE
+ end
+
+ # Sets +ActionController::Base#view_paths+ and +ActionMailer::Base#template_root+
+ # (but only for those frameworks that are to be loaded). If the framework's
+ # paths have already been set, it is not changed, otherwise it is
+ # set to use Configuration#view_path.
+ initializer "action_controller.initialize_framework_views" do |app|
+ # TODO: this should be combined with the logic for default config.action_controller.view_paths
+ view_path = ActionView::PathSet.type_cast(app.config.view_path, app.config.cache_classes)
+ ActionController::Base.view_paths = view_path if ActionController::Base.view_paths.blank?
+ end
+
+ initializer "action_controller.initialize_metal" do |app|
+ Rails::Rack::Metal.requested_metals = app.config.metals
+
+ app.config.middleware.insert_before(:"ActionDispatch::ParamsParser",
+ Rails::Rack::Metal, :if => Rails::Rack::Metal.metals.any?)
+ end
+
+ # # Prepare dispatcher callbacks and run 'prepare' callbacks
+ initializer "action_controller.prepare_dispatcher" do |app|
+ # TODO: This used to say unless defined?(Dispatcher). Find out why and fix.
+ require 'rails/dispatcher'
+
+ Dispatcher.define_dispatcher_callbacks(app.config.cache_classes)
+
+ unless app.config.cache_classes
+ # Setup dev mode route reloading
+ routes_last_modified = app.routes_changed_at
+ reload_routes = lambda do
+ unless app.routes_changed_at == routes_last_modified
+ routes_last_modified = app.routes_changed_at
+ app.reload_routes!
+ end
+ end
+ ActionDispatch::Callbacks.before_dispatch { |callbacks| reload_routes.call }
+ end
+ end
+
+ initializer "action_controller.notifications" do |app|
+ require 'active_support/notifications'
+
+ ActiveSupport::Notifications.subscribe(/(read|write|cache|expire|exist)_(fragment|page)\??/) do |*args|
+ event = ActiveSupport::Notifications::Event.new(*args)
+
+ if logger = ActionController::Base.logger
+ human_name = event.name.to_s.humanize
+ logger.info("#{human_name} (%.1fms)" % event.duration)
+ end
+ end
+ end
+
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/testing/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 01a55fe930..398ea52495 100644
--- a/actionpack/lib/action_controller/testing/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -1,5 +1,6 @@
require 'active_support/test_case'
require 'rack/session/abstract/id'
+require 'action_controller/metal/testing'
module ActionController
class TestRequest < ActionDispatch::TestRequest #:nodoc:
@@ -180,7 +181,7 @@ module ActionController
#
# assert_redirected_to page_url(:title => 'foo')
class TestCase < ActiveSupport::TestCase
- include TestProcess
+ include ActionDispatch::TestProcess
# Executes a request simulating GET HTTP method and set/volley the response
def get(action, parameters = nil, session = nil, flash = nil)
diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb
deleted file mode 100644
index 323cce6a2f..0000000000
--- a/actionpack/lib/action_controller/testing/process.rb
+++ /dev/null
@@ -1,111 +0,0 @@
-require 'active_support/core_ext/object/conversions'
-require "rack/test"
-
-module ActionController #:nodoc:
- # Essentially generates a modified Tempfile object similar to the object
- # you'd get from the standard library CGI module in a multipart
- # request. This means you can use an ActionController::TestUploadedFile
- # object in the params of a test request in order to simulate
- # a file upload.
- #
- # Usage example, within a functional test:
- # post :change_avatar, :avatar => ActionController::TestUploadedFile.new(ActionController::TestCase.fixture_path + '/files/spongebob.png', 'image/png')
- #
- # Pass a true third parameter to ensure the uploaded file is opened in binary mode (only required for Windows):
- # post :change_avatar, :avatar => ActionController::TestUploadedFile.new(ActionController::TestCase.fixture_path + '/files/spongebob.png', 'image/png', :binary)
- TestUploadedFile = Rack::Test::UploadedFile
-
- module TestProcess
- def assigns(key = nil)
- assigns = {}
- @controller.instance_variable_names.each do |ivar|
- next if ActionController::Base.protected_instance_variables.include?(ivar)
- assigns[ivar[1..-1]] = @controller.instance_variable_get(ivar)
- end
-
- key.nil? ? assigns : assigns[key.to_s]
- end
-
- def session
- @request.session
- end
-
- def flash
- @request.flash
- end
-
- def cookies
- @request.cookies.merge(@response.cookies)
- end
-
- def redirect_to_url
- @response.redirect_url
- end
-
- def html_document
- xml = @response.content_type =~ /xml$/
- @html_document ||= HTML::Document.new(@response.body, false, xml)
- end
-
- def find_tag(conditions)
- html_document.find(conditions)
- end
-
- def find_all_tag(conditions)
- html_document.find_all(conditions)
- end
-
- def method_missing(selector, *args, &block)
- if @controller && ActionController::Routing::Routes.named_routes.helpers.include?(selector)
- @controller.send(selector, *args, &block)
- else
- super
- end
- end
-
- # Shortcut for <tt>ActionController::TestUploadedFile.new(ActionController::TestCase.fixture_path + path, type)</tt>:
- #
- # post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png')
- #
- # To upload binary files on Windows, pass <tt>:binary</tt> as the last parameter.
- # This will not affect other platforms:
- #
- # post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png', :binary)
- def fixture_file_upload(path, mime_type = nil, binary = false)
- fixture_path = ActionController::TestCase.send(:fixture_path) if ActionController::TestCase.respond_to?(:fixture_path)
- ActionController::TestUploadedFile.new("#{fixture_path}#{path}", mime_type, binary)
- end
-
- # A helper to make it easier to test different route configurations.
- # This method temporarily replaces ActionController::Routing::Routes
- # with a new RouteSet instance.
- #
- # The new instance is yielded to the passed block. Typically the block
- # will create some routes using <tt>map.draw { map.connect ... }</tt>:
- #
- # with_routing do |set|
- # set.draw do |map|
- # map.connect ':controller/:action/:id'
- # assert_equal(
- # ['/content/10/show', {}],
- # map.generate(:controller => 'content', :id => 10, :action => 'show')
- # end
- # end
- # end
- #
- def with_routing
- real_routes = ActionController::Routing::Routes
- ActionController::Routing.module_eval { remove_const :Routes }
-
- temporary_routes = ActionController::Routing::RouteSet.new
- ActionController::Routing.module_eval { const_set :Routes, temporary_routes }
-
- yield temporary_routes
- ensure
- if ActionController::Routing.const_defined? :Routes
- ActionController::Routing.module_eval { remove_const :Routes }
- end
- ActionController::Routing.const_set(:Routes, real_routes) if real_routes
- end
- end
-end
diff --git a/actionpack/lib/action_controller/vendor/html-scanner.rb b/actionpack/lib/action_controller/vendor/html-scanner.rb
index f622d195ee..879b31e60e 100644
--- a/actionpack/lib/action_controller/vendor/html-scanner.rb
+++ b/actionpack/lib/action_controller/vendor/html-scanner.rb
@@ -1,16 +1,20 @@
$LOAD_PATH << "#{File.dirname(__FILE__)}/html-scanner"
module HTML
- autoload :CDATA, 'html/node'
- autoload :Document, 'html/document'
- autoload :FullSanitizer, 'html/sanitizer'
- autoload :LinkSanitizer, 'html/sanitizer'
- autoload :Node, 'html/node'
- autoload :Sanitizer, 'html/sanitizer'
- autoload :Selector, 'html/selector'
- autoload :Tag, 'html/node'
- autoload :Text, 'html/node'
- autoload :Tokenizer, 'html/tokenizer'
- autoload :Version, 'html/version'
- autoload :WhiteListSanitizer, 'html/sanitizer'
+ extend ActiveSupport::Autoload
+
+ eager_autoload do
+ autoload :CDATA, 'html/node'
+ autoload :Document, 'html/document'
+ autoload :FullSanitizer, 'html/sanitizer'
+ autoload :LinkSanitizer, 'html/sanitizer'
+ autoload :Node, 'html/node'
+ autoload :Sanitizer, 'html/sanitizer'
+ autoload :Selector, 'html/selector'
+ autoload :Tag, 'html/node'
+ autoload :Text, 'html/node'
+ autoload :Tokenizer, 'html/tokenizer'
+ autoload :Version, 'html/version'
+ autoload :WhiteListSanitizer, 'html/sanitizer'
+ end
end
diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb
index 259814a322..0696cb017c 100644
--- a/actionpack/lib/action_dispatch.rb
+++ b/actionpack/lib/action_dispatch.rb
@@ -21,6 +21,10 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
+activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
+$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
+require 'active_support/ruby/shim'
+
require 'rack'
module Rack
@@ -28,29 +32,25 @@ module Rack
end
module ActionDispatch
- autoload :Request, 'action_dispatch/http/request'
- autoload :Response, 'action_dispatch/http/response'
- autoload :StatusCodes, 'action_dispatch/http/status_codes'
- autoload :Utils, 'action_dispatch/http/utils'
-
- autoload :Callbacks, 'action_dispatch/middleware/callbacks'
- autoload :MiddlewareStack, 'action_dispatch/middleware/stack'
- autoload :ParamsParser, 'action_dispatch/middleware/params_parser'
- autoload :Rescue, 'action_dispatch/middleware/rescue'
- autoload :ShowExceptions, 'action_dispatch/middleware/show_exceptions'
- autoload :Static, 'action_dispatch/middleware/static'
- autoload :StringCoercion, 'action_dispatch/middleware/string_coercion'
+ extend ActiveSupport::Autoload
- autoload :Routing, 'action_dispatch/routing'
+ autoload_under 'http' do
+ autoload :Request
+ autoload :Response
+ end
- autoload :Assertions, 'action_dispatch/testing/assertions'
- autoload :Integration, 'action_dispatch/testing/integration'
- autoload :IntegrationTest, 'action_dispatch/testing/integration'
- autoload :PerformanceTest, 'action_dispatch/testing/performance_test'
- autoload :TestRequest, 'action_dispatch/testing/test_request'
- autoload :TestResponse, 'action_dispatch/testing/test_response'
+ autoload_under 'middleware' do
+ autoload :Callbacks
+ autoload :Cascade
+ autoload :ParamsParser
+ autoload :Rescue
+ autoload :ShowExceptions
+ autoload :Static
+ autoload :StringCoercion
+ end
- autoload :HTML, 'action_controller/vendor/html-scanner'
+ autoload :MiddlewareStack, 'action_dispatch/middleware/stack'
+ autoload :Routing
module Http
autoload :Headers, 'action_dispatch/http/headers'
@@ -58,13 +58,18 @@ module ActionDispatch
module Session
autoload :AbstractStore, 'action_dispatch/middleware/session/abstract_store'
- autoload :CookieStore, 'action_dispatch/middleware/session/cookie_store'
+ autoload :CookieStore, 'action_dispatch/middleware/session/cookie_store'
autoload :MemCacheStore, 'action_dispatch/middleware/session/mem_cache_store'
end
+
+ autoload_under 'testing' do
+ autoload :Assertions
+ autoload :Integration
+ autoload :PerformanceTest
+ autoload :TestProcess
+ autoload :TestRequest
+ autoload :TestResponse
+ end
end
autoload :Mime, 'action_dispatch/http/mime_type'
-
-activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
-$:.unshift activesupport_path if File.directory?(activesupport_path)
-require 'active_support'
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 6a52854961..6e8a5dcb8a 100755
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -6,6 +6,7 @@ require 'active_support/memoizable'
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/hash/indifferent_access'
require 'active_support/core_ext/string/access'
+require 'action_dispatch/http/headers'
module ActionDispatch
class Request < Rack::Request
@@ -17,7 +18,7 @@ module ActionDispatch
HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM
- HTTP_NEGOTIATE HTTP_PRAGMA HTTP_REFERER HTTP_USER_AGENT ].each do |env|
+ HTTP_NEGOTIATE HTTP_PRAGMA ].each do |env|
define_method(env.sub(/^HTTP_/n, '').downcase) do
@env[env]
end
@@ -117,7 +118,7 @@ module ActionDispatch
end
end
end
-
+
def if_modified_since
if since = env['HTTP_IF_MODIFIED_SINCE']
Time.rfc2822(since) rescue nil
@@ -464,6 +465,15 @@ EOM
session['flash'] || {}
end
+ # Returns the authorization header regardless of whether it was specified directly or through one of the
+ # proxy alternatives.
+ def authorization
+ @env['HTTP_AUTHORIZATION'] ||
+ @env['X-HTTP_AUTHORIZATION'] ||
+ @env['X_HTTP_AUTHORIZATION'] ||
+ @env['REDIRECT_X_HTTP_AUTHORIZATION']
+ end
+
# Receives an array of mimes and return the first user sent mime that
# matches the order array.
#
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index b3ed7c9d1a..8524bbd993 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -33,7 +33,6 @@ module ActionDispatch # :nodoc:
# end
class Response < Rack::Response
attr_accessor :request, :blank
- attr_reader :cache_control
attr_writer :header, :sending_file
alias_method :headers=, :header=
@@ -50,6 +49,9 @@ module ActionDispatch # :nodoc:
@body, @cookie = [], []
@sending_file = false
+ @blank = false
+ @etag = nil
+
yield self if block_given?
end
@@ -57,14 +59,8 @@ module ActionDispatch # :nodoc:
@cache_control ||= {}
end
- def write(str)
- s = str.to_s
- @writer.call s
- str
- end
-
def status=(status)
- @status = status.to_i
+ @status = Rack::Utils.status_code(status)
end
# The response code of the request
@@ -78,7 +74,7 @@ module ActionDispatch # :nodoc:
end
def message
- StatusCodes::STATUS_CODES[@status]
+ Rack::Utils::HTTP_STATUS_CODES[@status]
end
alias_method :status_message, :message
@@ -149,18 +145,6 @@ module ActionDispatch # :nodoc:
cattr_accessor(:default_charset) { "utf-8" }
- def assign_default_content_type_and_charset!
- return if headers[CONTENT_TYPE].present?
-
- @content_type ||= Mime::HTML
- @charset ||= self.class.default_charset
-
- type = @content_type.to_s.dup
- type << "; charset=#{@charset}" unless @sending_file
-
- headers[CONTENT_TYPE] = type
- end
-
def to_a
assign_default_content_type_and_charset!
handle_conditional_get!
@@ -263,6 +247,18 @@ module ActionDispatch # :nodoc:
!@blank && @body.respond_to?(:all?) && @body.all? { |part| part.is_a?(String) }
end
+ def assign_default_content_type_and_charset!
+ return if headers[CONTENT_TYPE].present?
+
+ @content_type ||= Mime::HTML
+ @charset ||= self.class.default_charset
+
+ type = @content_type.to_s.dup
+ type << "; charset=#{@charset}" unless @sending_file
+
+ headers[CONTENT_TYPE] = type
+ end
+
DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate"
def set_conditional_cache_control!
@@ -277,14 +273,13 @@ module ActionDispatch # :nodoc:
max_age = control[:max_age]
options = []
- options << "max-age=#{max_age}" if max_age
+ options << "max-age=#{max_age.to_i}" if max_age
options << (control[:public] ? "public" : "private")
options << "must-revalidate" if control[:must_revalidate]
options.concat(extras) if extras
headers["Cache-Control"] = options.join(", ")
end
-
end
end
end
diff --git a/actionpack/lib/action_dispatch/http/status_codes.rb b/actionpack/lib/action_dispatch/http/status_codes.rb
deleted file mode 100644
index 5bac842ec1..0000000000
--- a/actionpack/lib/action_dispatch/http/status_codes.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-require 'active_support/inflector'
-
-module ActionDispatch
- module StatusCodes #:nodoc:
- STATUS_CODES = Rack::Utils::HTTP_STATUS_CODES.merge({
- 102 => "Processing",
- 207 => "Multi-Status",
- 226 => "IM Used",
- 422 => "Unprocessable Entity",
- 423 => "Locked",
- 424 => "Failed Dependency",
- 426 => "Upgrade Required",
- 507 => "Insufficient Storage",
- 510 => "Not Extended"
- }).freeze
-
- # Provides a symbol-to-fixnum lookup for converting a symbol (like
- # :created or :not_implemented) into its corresponding HTTP status
- # code (like 200 or 501).
- SYMBOL_TO_STATUS_CODE = STATUS_CODES.inject({}) { |hash, (code, message)|
- hash[ActiveSupport::Inflector.underscore(message.gsub(/ /, "")).to_sym] = code
- hash
- }.freeze
-
- private
- # Given a status parameter, determine whether it needs to be converted
- # to a string. If it is a fixnum, use the STATUS_CODES hash to lookup
- # the default message. If it is a symbol, use the SYMBOL_TO_STATUS_CODE
- # hash to convert it.
- def interpret_status(status)
- case status
- when Fixnum then
- "#{status} #{STATUS_CODES[status]}".strip
- when Symbol then
- interpret_status(SYMBOL_TO_STATUS_CODE[status] ||
- "500 Unknown Status #{status.inspect}")
- else
- status.to_s
- end
- end
- end
-end
diff --git a/actionpack/lib/action_dispatch/http/utils.rb b/actionpack/lib/action_dispatch/http/utils.rb
deleted file mode 100644
index e04a39935e..0000000000
--- a/actionpack/lib/action_dispatch/http/utils.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-module ActionDispatch
- module Utils
- # TODO: Pull this into rack core
- # http://github.com/halorgium/rack/commit/feaf071c1de743fbd10bc316830180a9af607278
- def parse_config(config)
- if config =~ /\.ru$/
- cfgfile = ::File.read(config)
- if cfgfile[/^#\\(.*)/]
- opts.parse! $1.split(/\s+/)
- end
- inner_app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app",
- nil, config
- else
- require config
- inner_app = Object.const_get(::File.basename(config, '.rb').capitalize)
- end
- end
- module_function :parse_config
- end
-end
diff --git a/actionpack/lib/action_dispatch/middleware/cascade.rb b/actionpack/lib/action_dispatch/middleware/cascade.rb
new file mode 100644
index 0000000000..9f5c9891f0
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/cascade.rb
@@ -0,0 +1,29 @@
+module ActionDispatch
+ class Cascade
+ def self.new(*apps)
+ apps = apps.flatten
+
+ case apps.length
+ when 0
+ raise ArgumentError, "app is required"
+ when 1
+ apps.first
+ else
+ super(apps)
+ end
+ end
+
+ def initialize(apps)
+ @apps = apps
+ end
+
+ def call(env)
+ result = nil
+ @apps.each do |app|
+ result = app.call(env)
+ break unless result[1]["X-Cascade"] == "pass"
+ end
+ result
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb
index 32ccb5c931..534390d4aa 100644
--- a/actionpack/lib/action_dispatch/middleware/params_parser.rb
+++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb
@@ -1,4 +1,5 @@
require 'active_support/json'
+require 'action_dispatch/http/request'
module ActionDispatch
class ParamsParser
@@ -31,41 +32,39 @@ module ActionDispatch
return false unless strategy
case strategy
- when Proc
- strategy.call(request.raw_post)
- when :xml_simple, :xml_node
- request.body.size == 0 ? {} : Hash.from_xml(request.body).with_indifferent_access
- when :yaml
- YAML.load(request.body)
- when :json
- if request.body.size == 0
- {}
- else
- data = ActiveSupport::JSON.decode(request.body)
- data = {:_json => data} unless data.is_a?(Hash)
- data.with_indifferent_access
- end
+ when Proc
+ strategy.call(request.raw_post)
+ when :xml_simple, :xml_node
+ request.body.size == 0 ? {} : Hash.from_xml(request.body).with_indifferent_access
+ when :yaml
+ YAML.load(request.body)
+ when :json
+ if request.body.size == 0
+ {}
else
- false
+ data = ActiveSupport::JSON.decode(request.body)
+ data = {:_json => data} unless data.is_a?(Hash)
+ data.with_indifferent_access
+ end
+ else
+ false
end
rescue Exception => e # YAML, XML or Ruby code block errors
logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{request.raw_post}"
raise
- { "body" => request.raw_post,
- "content_type" => request.content_type,
+ { "body" => request.raw_post,
+ "content_type" => request.content_type,
"content_length" => request.content_length,
- "exception" => "#{e.message} (#{e.class})",
- "backtrace" => e.backtrace }
+ "exception" => "#{e.message} (#{e.class})",
+ "backtrace" => e.backtrace }
end
def content_type_from_legacy_post_data_format_header(env)
if x_post_format = env['HTTP_X_POST_DATA_FORMAT']
case x_post_format.to_s.downcase
- when 'yaml'
- return Mime::YAML
- when 'xml'
- return Mime::XML
+ when 'yaml' then return Mime::YAML
+ when 'xml' then return Mime::XML
end
end
@@ -76,4 +75,4 @@ module ActionDispatch
defined?(Rails.logger) ? Rails.logger : Logger.new($stderr)
end
end
-end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
index c5c06f74a2..7d4f0998ce 100644
--- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
@@ -1,4 +1,5 @@
require 'rack/utils'
+require 'rack/request'
module ActionDispatch
module Session
diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
index bd552b458a..f27f22c7e7 100644
--- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
@@ -1,4 +1,5 @@
-require "active_support/core_ext/hash/keys"
+require 'active_support/core_ext/hash/keys'
+require 'rack/request'
module ActionDispatch
module Session
@@ -49,7 +50,7 @@ module ActionDispatch
:expire_after => nil,
:httponly => true
}.freeze
-
+
class OptionsHash < Hash
def initialize(by, env, default_options)
@session_data = env[CookieStore::ENV_SESSION_KEY]
@@ -60,7 +61,7 @@ module ActionDispatch
key == :id ? @session_data[:session_id] : super(key)
end
end
-
+
ENV_SESSION_KEY = "rack.session".freeze
ENV_SESSION_OPTIONS_KEY = "rack.session.options".freeze
HTTP_SET_COOKIE = "Set-Cookie".freeze
@@ -102,7 +103,7 @@ module ActionDispatch
def call(env)
env[ENV_SESSION_KEY] = AbstractStore::SessionHash.new(self, env)
env[ENV_SESSION_OPTIONS_KEY] = OptionsHash.new(self, env, @default_options)
-
+
status, headers, body = @app.call(env)
session_data = env[ENV_SESSION_KEY]
diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
index 036deec6d2..4ebc8a2ab9 100644
--- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
@@ -1,9 +1,8 @@
-require "active_support/core_ext/exception"
+require 'active_support/core_ext/exception'
+require 'action_dispatch/http/request'
module ActionDispatch
class ShowExceptions
- include StatusCodes
-
LOCALHOST = '127.0.0.1'.freeze
RESCUES_TEMPLATE_PATH = File.join(File.dirname(__FILE__), 'templates')
@@ -12,8 +11,7 @@ module ActionDispatch
@@rescue_responses = Hash.new(:internal_server_error)
@@rescue_responses.update({
'ActionController::RoutingError' => :not_found,
- # TODO: Clean this up after the switch
- ActionController::UnknownAction.name => :not_found,
+ 'AbstractController::ActionNotFound' => :not_found,
'ActiveRecord::RecordNotFound' => :not_found,
'ActiveRecord::StaleObjectError' => :conflict,
'ActiveRecord::RecordInvalid' => :unprocessable_entity,
@@ -28,8 +26,8 @@ module ActionDispatch
@@rescue_templates.update({
'ActionView::MissingTemplate' => 'missing_template',
'ActionController::RoutingError' => 'routing_error',
- ActionController::UnknownAction.name => 'unknown_action',
- 'ActionView::TemplateError' => 'template_error'
+ 'AbstractController::ActionNotFound' => 'unknown_action',
+ 'ActionView::Template::Error' => 'template_error'
})
FAILSAFE_RESPONSE = [500, {'Content-Type' => 'text/html'},
@@ -104,7 +102,7 @@ module ActionDispatch
end
def status_code(exception)
- interpret_status(@@rescue_responses[exception.class.name]).to_i
+ Rack::Utils.status_code(@@rescue_responses[exception.class.name])
end
def render(status, body)
@@ -119,7 +117,7 @@ module ActionDispatch
return unless logger
ActiveSupport::Deprecation.silence do
- if ActionView::TemplateError === exception
+ if ActionView::Template::Error === exception
logger.fatal(exception.to_s)
else
logger.fatal(
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb
index f8f6b424ca..07b4919934 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb
@@ -7,7 +7,7 @@
names = traces.collect {|name, trace| name}
%>
-<p><code>RAILS_ROOT: <%= defined?(RAILS_ROOT) ? RAILS_ROOT : "unset" %></code></p>
+<p><code>Rails.root: <%= defined?(Rails) && Rails.respond_to?(:root) ? Rails.root : "unset" %></code></p>
<div id="traces">
<% names.each do |name| %>
diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb
index 68ed1e3340..e99f979197 100644
--- a/actionpack/lib/action_dispatch/routing.rb
+++ b/actionpack/lib/action_dispatch/routing.rb
@@ -264,118 +264,11 @@ module ActionDispatch
autoload :RouteSet, 'action_dispatch/routing/route_set'
SEPARATORS = %w( / . ? )
-
HTTP_METHODS = [:get, :head, :post, :put, :delete, :options]
- ALLOWED_REQUIREMENTS_FOR_OPTIMISATION = [:controller, :action].to_set
-
- # The root paths which may contain controller files
- mattr_accessor :controller_paths
- self.controller_paths = []
-
# A helper module to hold URL related helpers.
module Helpers
include ActionController::PolymorphicRoutes
end
-
- class << self
- # Expects an array of controller names as the first argument.
- # Executes the passed block with only the named controllers named available.
- # This method is used in internal Rails testing.
- def with_controllers(names)
- prior_controllers = @possible_controllers
- use_controllers! names
- yield
- ensure
- use_controllers! prior_controllers
- end
-
- # Returns an array of paths, cleaned of double-slashes and relative path references.
- # * "\\\" and "//" become "\\" or "/".
- # * "/foo/bar/../config" becomes "/foo/config".
- # The returned array is sorted by length, descending.
- def normalize_paths(paths)
- # do the hokey-pokey of path normalization...
- paths = paths.collect do |path|
- path = path.
- gsub("//", "/"). # replace double / chars with a single
- gsub("\\\\", "\\"). # replace double \ chars with a single
- gsub(%r{(.)[\\/]$}, '\1') # drop final / or \ if path ends with it
-
- # eliminate .. paths where possible
- re = %r{[^/\\]+[/\\]\.\.[/\\]}
- path.gsub!(re, "") while path.match(re)
- path
- end
-
- # start with longest path, first
- paths = paths.uniq.sort_by { |path| - path.length }
- end
-
- # Returns the array of controller names currently available to ActionController::Routing.
- def possible_controllers
- unless @possible_controllers
- @possible_controllers = []
-
- paths = controller_paths.select { |path| File.directory?(path) && path != "." }
-
- seen_paths = Hash.new {|h, k| h[k] = true; false}
- normalize_paths(paths).each do |load_path|
- Dir["#{load_path}/**/*_controller.rb"].collect do |path|
- next if seen_paths[path.gsub(%r{^\.[/\\]}, "")]
-
- controller_name = path[(load_path.length + 1)..-1]
-
- controller_name.gsub!(/_controller\.rb\Z/, '')
- @possible_controllers << controller_name
- end
- end
-
- # remove duplicates
- @possible_controllers.uniq!
- end
- @possible_controllers
- end
-
- # Replaces the internal list of controllers available to ActionController::Routing with the passed argument.
- # ActionController::Routing.use_controllers!([ "posts", "comments", "admin/comments" ])
- def use_controllers!(controller_names)
- @possible_controllers = controller_names
- end
-
- # Returns a controller path for a new +controller+ based on a +previous+ controller path.
- # Handles 4 scenarios:
- #
- # * stay in the previous controller:
- # controller_relative_to( nil, "groups/discussion" ) # => "groups/discussion"
- #
- # * stay in the previous namespace:
- # controller_relative_to( "posts", "groups/discussion" ) # => "groups/posts"
- #
- # * forced move to the root namespace:
- # controller_relative_to( "/posts", "groups/discussion" ) # => "posts"
- #
- # * previous namespace is root:
- # controller_relative_to( "posts", "anything_with_no_slashes" ) # =>"posts"
- #
- def controller_relative_to(controller, previous)
- if controller.nil? then previous
- elsif controller[0] == ?/ then controller[1..-1]
- elsif %r{^(.*)/} =~ previous then "#{$1}/#{controller}"
- else controller
- end
- end
- end
-
- ActiveSupport::Inflector.module_eval do
- # Ensures that routes are reloaded when Rails inflections are updated.
- def inflections_with_route_reloading(&block)
- returning(inflections_without_route_reloading(&block)) {
- ActionDispatch::Routing::Routes.reload! if block_given?
- }
- end
-
- alias_method_chain :inflections, :route_reloading
- end
end
end
diff --git a/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb b/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb
index 0564ba9797..8ce6b2f6d5 100644
--- a/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb
@@ -113,8 +113,7 @@ module ActionDispatch
end
end
- possible_names = Routing.possible_controllers.collect { |n| Regexp.escape(n) }
- requirements[:controller] ||= Regexp.union(*possible_names)
+ requirements[:controller] ||= @set.controller_constraints
if defaults[:controller]
defaults[:action] ||= 'index'
@@ -176,7 +175,7 @@ module ActionDispatch
optional = false
elsif segment =~ /^:(\w+)$/
if defaults.has_key?($1.to_sym)
- defaults.delete($1.to_sym)
+ defaults.delete($1.to_sym) if defaults[$1.to_sym].nil?
else
optional = false
end
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 6e112c9b54..e655d6a708 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -1,153 +1,247 @@
module ActionDispatch
module Routing
class Mapper
- module Resources
- def resource(*resources, &block)
- options = resources.last.is_a?(Hash) ? resources.pop : {}
-
- if resources.length > 1
- raise ArgumentError if block_given?
- resources.each { |r| resource(r, options) }
- return self
+ class Constraints
+ def self.new(app, constraints = [])
+ if constraints.any?
+ super(app, constraints)
+ else
+ app
end
+ end
- resource = resources.pop
+ def initialize(app, constraints = [])
+ @app, @constraints = app, constraints
+ end
- if @scope[:scope_level] == :resources
- member do
- resource(resource, options, &block)
+ def call(env)
+ req = Rack::Request.new(env)
+
+ @constraints.each { |constraint|
+ if constraint.respond_to?(:matches?) && !constraint.matches?(req)
+ return [ 404, {'X-Cascade' => 'pass'}, [] ]
+ elsif constraint.respond_to?(:call) && !constraint.call(req)
+ return [ 404, {'X-Cascade' => 'pass'}, [] ]
end
- return self
- end
+ }
+
+ @app.call(env)
+ end
+ end
- singular = resource.to_s
- plural = singular.pluralize
+ class Mapping
+ def initialize(set, scope, args)
+ @set, @scope = set, scope
+ @path, @options = extract_path_and_options(args)
+ end
- controller(plural) do
- namespace(resource) do
- with_scope_level(:resource) do
- yield if block_given?
+ def to_route
+ [ app, conditions, requirements, defaults, @options[:as] ]
+ end
- get "", :to => :show, :as => "#{singular}"
- post "", :to => :create
- put "", :to => :update
- delete "", :to => :destroy
- get "new", :to => :new, :as => "new_#{singular}"
- get "edit", :to => :edit, :as => "edit_#{singular}"
- end
+ private
+ def extract_path_and_options(args)
+ options = args.extract_options!
+
+ if args.empty?
+ path, to = options.find { |name, value| name.is_a?(String) }
+ options.merge!(:to => to).delete(path) if path
+ else
+ path = args.first
end
+
+ [ normalize_path(path), options ]
end
- self
- end
+ def normalize_path(path)
+ path = nil if path == ""
+ path = "#{@scope[:path]}#{path}" if @scope[:path]
+ path = Rack::Mount::Utils.normalize_path(path) if path
- def resources(*resources, &block)
- options = resources.last.is_a?(Hash) ? resources.pop : {}
+ raise ArgumentError, "path is required" unless path
- if resources.length > 1
- raise ArgumentError if block_given?
- resources.each { |r| resources(r, options) }
- return self
+ path
end
- resource = resources.pop
- plural = resource.to_s
- singular = plural.singularize
+ def app
+ Constraints.new(
+ to.respond_to?(:call) ? to : Routing::RouteSet::Dispatcher.new(:defaults => defaults),
+ blocks
+ )
+ end
- if @scope[:scope_level] == :resources
- parent_resource = @scope[:scope_level_options][:name]
- with_scope_level(:member) do
- scope(":#{parent_resource}_id", :name_prefix => parent_resource) do
- resources(resource, options, &block)
- end
- end
- return self
+ def conditions
+ { :path_info => @path }.merge(constraints).merge(request_method_condition)
end
- if @scope[:options] && (prefix = @scope[:options][:name_prefix])
- plural = "#{prefix}_#{plural}"
- singular = "#{prefix}_#{singular}"
+ def requirements
+ @requirements ||= returning(@options[:constraints] || {}) do |requirements|
+ requirements.reverse_merge!(@scope[:constraints]) if @scope[:constraints]
+ @options.each { |k, v| requirements[k] = v if v.is_a?(Regexp) }
+ requirements[:controller] ||= @set.controller_constraints
+ end
end
- controller(resource) do
- namespace(resource) do
- with_scope_level(:resources, :name => singular) do
- yield if block_given?
+ def defaults
+ @defaults ||= if to.respond_to?(:call)
+ { }
+ else
+ defaults = case to
+ when String
+ controller, action = to.split('#')
+ { :controller => controller, :action => action }
+ when Symbol
+ { :action => to.to_s }.merge(default_controller ? { :controller => default_controller } : {})
+ else
+ default_controller ? { :controller => default_controller } : {}
+ end
- member do
- get "", :to => :show, :as => singular
- put "", :to => :update
- delete "", :to => :destroy
- get "edit", :to => :edit, :as => "edit_#{singular}"
- end
+ if defaults[:controller].blank? && segment_keys.exclude?("controller")
+ raise ArgumentError, "missing :controller"
+ end
- collection do
- get "", :to => :index, :as => plural
- post "", :to => :create
- get "new", :to => :new, :as => "new_#{singular}"
- end
+ if defaults[:action].blank? && segment_keys.exclude?("action")
+ raise ArgumentError, "missing :action"
end
+
+ defaults
end
end
- self
- end
- def collection
- unless @scope[:scope_level] == :resources
- raise ArgumentError, "can't use collection outside resources scope"
- end
+ def blocks
+ if @options[:constraints].present? && !@options[:constraints].is_a?(Hash)
+ block = @options[:constraints]
+ else
+ block = nil
+ end
- with_scope_level(:collection) do
- yield
+ ((@scope[:blocks] || []) + [ block ]).compact
end
- end
- def member
- unless @scope[:scope_level] == :resources
- raise ArgumentError, "can't use member outside resources scope"
+ def constraints
+ @constraints ||= requirements.reject { |k, v| segment_keys.include?(k.to_s) || k == :controller }
end
- with_scope_level(:member) do
- scope(":id") do
- yield
+ def request_method_condition
+ if via = @options[:via]
+ via = Array(via).map { |m| m.to_s.upcase }
+ { :request_method => Regexp.union(*via) }
+ else
+ { }
end
end
+
+ def segment_keys
+ @segment_keys ||= Rack::Mount::RegexpWithNamedGroups.new(
+ Rack::Mount::Strexp.compile(@path, requirements, SEPARATORS)
+ ).names
+ end
+
+ def to
+ @options[:to]
+ end
+
+ def default_controller
+ @scope[:controller].to_s if @scope[:controller]
+ end
+ end
+
+ module Base
+ def initialize(set)
+ @set = set
+ end
+
+ def root(options = {})
+ match '/', options.reverse_merge(:as => :root)
end
def match(*args)
+ @set.add_route(*Mapping.new(@set, @scope, args).to_route)
+ self
+ end
+ end
+
+ module HttpHelpers
+ def get(*args, &block)
+ map_method(:get, *args, &block)
+ end
+
+ def post(*args, &block)
+ map_method(:post, *args, &block)
+ end
+
+ def put(*args, &block)
+ map_method(:put, *args, &block)
+ end
+
+ def delete(*args, &block)
+ map_method(:delete, *args, &block)
+ end
+
+ def redirect(*args, &block)
options = args.last.is_a?(Hash) ? args.pop : {}
- args.push(options)
- case options.delete(:on)
- when :collection
- return collection { match(*args) }
- when :member
- return member { match(*args) }
- end
+ path = args.shift || block
+ path_proc = path.is_a?(Proc) ? path : proc { |params| path % params }
+ status = options[:status] || 301
- if @scope[:scope_level] == :resources
- raise ArgumentError, "can't define route directly in resources scope"
- end
+ lambda do |env|
+ req = Rack::Request.new(env)
+ params = path_proc.call(env["action_dispatch.request.path_parameters"])
+ url = req.scheme + '://' + req.host + params
- super
+ [ status, {'Location' => url, 'Content-Type' => 'text/html'}, ['Moved Permanently'] ]
+ end
end
private
- def with_scope_level(kind, options = {})
- old, @scope[:scope_level] = @scope[:scope_level], kind
- old_options, @scope[:scope_level_options] = @scope[:scope_level_options], options
- yield
- ensure
- @scope[:scope_level] = old
- @scope[:scope_level_options] = old_options
+ def map_method(method, *args, &block)
+ options = args.extract_options!
+ options[:via] = method
+ args.push(options)
+ match(*args, &block)
+ self
end
end
module Scoping
+ def initialize(*args)
+ @scope = {}
+ super
+ end
+
def scope(*args)
- options = args.last.is_a?(Hash) ? args.pop : {}
+ options = args.extract_options!
+
+ case args.first
+ when String
+ options[:path] = args.first
+ when Symbol
+ options[:controller] = args.first
+ end
+
+ if path = options.delete(:path)
+ path_set = true
+ path, @scope[:path] = @scope[:path], Rack::Mount::Utils.normalize_path(@scope[:path].to_s + path.to_s)
+ else
+ path_set = false
+ end
+
+ if name_prefix = options.delete(:name_prefix)
+ name_prefix_set = true
+ name_prefix, @scope[:name_prefix] = @scope[:name_prefix], (@scope[:name_prefix] ? "#{@scope[:name_prefix]}_#{name_prefix}" : name_prefix)
+ else
+ name_prefix_set = false
+ end
+
+ if controller = options.delete(:controller)
+ controller_set = true
+ controller, @scope[:controller] = @scope[:controller], controller
+ else
+ controller_set = false
+ end
constraints = options.delete(:constraints) || {}
unless constraints.is_a?(Hash)
@@ -158,27 +252,15 @@ module ActionDispatch
options, @scope[:options] = @scope[:options], (@scope[:options] || {}).merge(options)
- path_set = controller_set = false
-
- case args.first
- when String
- path_set = true
- path = args.first
- path, @scope[:path] = @scope[:path], "#{@scope[:path]}#{Rack::Mount::Utils.normalize_path(path)}"
- when Symbol
- controller_set = true
- controller = args.first
- controller, @scope[:controller] = @scope[:controller], controller
- end
-
yield
self
ensure
- @scope[:path] = path if path_set
- @scope[:controller] = controller if controller_set
- @scope[:options] = options
- @scope[:blocks] = blocks
+ @scope[:path] = path if path_set
+ @scope[:name_prefix] = name_prefix if name_prefix_set
+ @scope[:controller] = controller if controller_set
+ @scope[:options] = options
+ @scope[:blocks] = blocks
@scope[:constraints] = constraints
end
@@ -187,151 +269,255 @@ module ActionDispatch
end
def namespace(path)
- scope(path.to_s) { yield }
+ scope("/#{path}") { yield }
end
def constraints(constraints = {})
scope(:constraints => constraints) { yield }
end
- end
- class Constraints
- def initialize(app, constraints = [])
- @app, @constraints = app, constraints
- end
+ def match(*args)
+ options = args.extract_options!
- def call(env)
- req = Rack::Request.new(env)
+ options = (@scope[:options] || {}).merge(options)
- @constraints.each { |constraint|
- if constraint.respond_to?(:matches?) && !constraint.matches?(req)
- return [417, {}, []]
- elsif constraint.respond_to?(:call) && !constraint.call(req)
- return [417, {}, []]
- end
- }
+ if @scope[:name_prefix] && !options[:as].blank?
+ options[:as] = "#{@scope[:name_prefix]}_#{options[:as]}"
+ elsif @scope[:name_prefix] && options[:as] == ""
+ options[:as] = @scope[:name_prefix].to_s
+ end
- @app.call(env)
+ args.push(options)
+ super(*args)
end
end
- def initialize(set)
- @set = set
- @scope = {}
-
- extend Scoping
- extend Resources
- end
+ module Resources
+ class Resource #:nodoc:
+ attr_reader :plural, :singular
- def get(*args, &block)
- map_method(:get, *args, &block)
- end
+ def initialize(entities, options = {})
+ entities = entities.to_s
- def post(*args, &block)
- map_method(:post, *args, &block)
- end
+ @plural = entities.pluralize
+ @singular = entities.singularize
+ end
- def put(*args, &block)
- map_method(:put, *args, &block)
- end
+ def name
+ plural
+ end
- def delete(*args, &block)
- map_method(:delete, *args, &block)
- end
+ def controller
+ plural
+ end
- def root(options = {})
- match '/', options.merge(:as => :root)
- end
+ def member_name
+ singular
+ end
- def match(*args)
- options = args.last.is_a?(Hash) ? args.pop : {}
+ def collection_name
+ plural
+ end
- if args.length > 1
- args.each { |path| match(path, options) }
- return self
+ def id_segment
+ ":#{singular}_id"
+ end
end
- if args.first.is_a?(Symbol)
- return match(args.first.to_s, options.merge(:to => args.first.to_sym))
+ class SingletonResource < Resource #:nodoc:
+ def initialize(entity, options = {})
+ super
+ end
+
+ def name
+ singular
+ end
end
- path = args.first
+ def resource(*resources, &block)
+ options = resources.extract_options!
+
+ if resources.length > 1
+ raise ArgumentError if block_given?
+ resources.each { |r| resource(r, options) }
+ return self
+ end
+
+ resource = SingletonResource.new(resources.pop)
- options = (@scope[:options] || {}).merge(options)
- conditions, defaults = {}, {}
+ if @scope[:scope_level] == :resources
+ nested do
+ resource(resource.name, options, &block)
+ end
+ return self
+ end
- path = nil if path == ""
- path = Rack::Mount::Utils.normalize_path(path) if path
- path = "#{@scope[:path]}#{path}" if @scope[:path]
+ scope(:path => "/#{resource.name}", :controller => resource.controller) do
+ with_scope_level(:resource, resource) do
+ yield if block_given?
- raise ArgumentError, "path is required" unless path
+ get "(.:format)", :to => :show, :as => resource.member_name
+ post "(.:format)", :to => :create
+ put "(.:format)", :to => :update
+ delete "(.:format)", :to => :destroy
+ get "/new(.:format)", :to => :new, :as => "new_#{resource.singular}"
+ get "/edit(.:format)", :to => :edit, :as => "edit_#{resource.singular}"
+ end
+ end
- constraints = options[:constraints] || {}
- unless constraints.is_a?(Hash)
- block, constraints = constraints, {}
+ self
end
- blocks = ((@scope[:blocks] || []) + [block]).compact
- constraints = (@scope[:constraints] || {}).merge(constraints)
- options.each { |k, v| constraints[k] = v if v.is_a?(Regexp) }
- conditions[:path_info] = path
- requirements = constraints.dup
+ def resources(*resources, &block)
+ options = resources.extract_options!
+
+ if resources.length > 1
+ raise ArgumentError if block_given?
+ resources.each { |r| resources(r, options) }
+ return self
+ end
+
+ resource = Resource.new(resources.pop)
+
+ if @scope[:scope_level] == :resources
+ nested do
+ resources(resource.name, options, &block)
+ end
+ return self
+ end
+
+ scope(:path => "/#{resource.name}", :controller => resource.controller) do
+ with_scope_level(:resources, resource) do
+ yield if block_given?
+
+ with_scope_level(:collection) do
+ get "(.:format)", :to => :index, :as => resource.collection_name
+ post "(.:format)", :to => :create
+
+ with_exclusive_name_prefix :new do
+ get "/new(.:format)", :to => :new, :as => resource.singular
+ end
+ end
+
+ with_scope_level(:member) do
+ scope("/:id") do
+ get "(.:format)", :to => :show, :as => resource.member_name
+ put "(.:format)", :to => :update
+ delete "(.:format)", :to => :destroy
+
+ with_exclusive_name_prefix :edit do
+ get "/edit(.:format)", :to => :edit, :as => resource.singular
+ end
+ end
+ end
+ end
+ end
+
+ self
+ end
- path_regexp = Rack::Mount::Strexp.compile(path, constraints, SEPARATORS)
- segment_keys = Rack::Mount::RegexpWithNamedGroups.new(path_regexp).names
- constraints.reject! { |k, v| segment_keys.include?(k.to_s) }
- conditions.merge!(constraints)
+ def collection
+ unless @scope[:scope_level] == :resources
+ raise ArgumentError, "can't use collection outside resources scope"
+ end
- if via = options[:via]
- via = Array(via).map { |m| m.to_s.upcase }
- conditions[:request_method] = Regexp.union(*via)
+ with_scope_level(:collection) do
+ scope(:name_prefix => parent_resource.collection_name, :as => "") do
+ yield
+ end
+ end
end
- defaults[:controller] = @scope[:controller].to_s if @scope[:controller]
+ def member
+ unless @scope[:scope_level] == :resources
+ raise ArgumentError, "can't use member outside resources scope"
+ end
- if options[:to].respond_to?(:call)
- app = options[:to]
- defaults.delete(:controller)
- defaults.delete(:action)
- elsif options[:to].is_a?(String)
- defaults[:controller], defaults[:action] = options[:to].split('#')
- elsif options[:to].is_a?(Symbol)
- defaults[:action] = options[:to].to_s
+ with_scope_level(:member) do
+ scope("/:id", :name_prefix => parent_resource.member_name, :as => "") do
+ yield
+ end
+ end
end
- app ||= Routing::RouteSet::Dispatcher.new(:defaults => defaults)
- if app.is_a?(Routing::RouteSet::Dispatcher)
- unless defaults.include?(:controller) || segment_keys.include?("controller")
- raise ArgumentError, "missing :controller"
+ def nested
+ unless @scope[:scope_level] == :resources
+ raise ArgumentError, "can't use nested outside resources scope"
end
- unless defaults.include?(:action) || segment_keys.include?("action")
- raise ArgumentError, "missing :action"
+
+ with_scope_level(:nested) do
+ scope("/#{parent_resource.id_segment}", :name_prefix => parent_resource.member_name) do
+ yield
+ end
end
end
- app = Constraints.new(app, blocks) if blocks.any?
- @set.add_route(app, conditions, requirements, defaults, options[:as])
+ def match(*args)
+ options = args.extract_options!
- self
- end
+ if args.length > 1
+ args.each { |path| match(path, options) }
+ return self
+ end
- def redirect(path, options = {})
- status = options[:status] || 301
- lambda { |env|
- req = Rack::Request.new(env)
- url = req.scheme + '://' + req.host + path
- [status, {'Location' => url, 'Content-Type' => 'text/html'}, ['Moved Permanently']]
- }
- end
+ if args.first.is_a?(Symbol)
+ with_exclusive_name_prefix(args.first) do
+ return match("/#{args.first}(.:format)", options.merge(:to => args.first.to_sym))
+ end
+ end
- private
- def map_method(method, *args, &block)
- options = args.last.is_a?(Hash) ? args.pop : {}
- options[:via] = method
args.push(options)
- match(*args, &block)
- self
+
+ case options.delete(:on)
+ when :collection
+ return collection { match(*args) }
+ when :member
+ return member { match(*args) }
+ end
+
+ if @scope[:scope_level] == :resources
+ raise ArgumentError, "can't define route directly in resources scope"
+ end
+
+ super
end
+
+ protected
+ def parent_resource
+ @scope[:scope_level_resource]
+ end
+
+ private
+ def with_exclusive_name_prefix(prefix)
+ begin
+ old_name_prefix = @scope[:name_prefix]
+
+ if !old_name_prefix.blank?
+ @scope[:name_prefix] = "#{prefix}_#{@scope[:name_prefix]}"
+ else
+ @scope[:name_prefix] = prefix.to_s
+ end
+
+ yield
+ ensure
+ @scope[:name_prefix] = old_name_prefix
+ end
+ end
+
+ def with_scope_level(kind, resource = parent_resource)
+ old, @scope[:scope_level] = @scope[:scope_level], kind
+ old_resource, @scope[:scope_level_resource] = @scope[:scope_level_resource], resource
+ yield
+ ensure
+ @scope[:scope_level] = old
+ @scope[:scope_level_resource] = old_resource
+ end
+ end
+
+ include Base
+ include HttpHelpers
+ include Scoping
+ include Resources
end
end
end
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index c15aaceb5b..bd397432ce 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -5,7 +5,7 @@ module ActionDispatch
module Routing
class RouteSet #:nodoc:
NotFound = lambda { |env|
- raise ActionController::RoutingError, "No route matches #{env['PATH_INFO'].inspect} with #{env.inspect}"
+ raise ActionController::RoutingError, "No route matches #{env['PATH_INFO'].inspect}"
}
PARAMETERS_KEY = 'action_dispatch.request.path_parameters'
@@ -18,31 +18,37 @@ module ActionDispatch
def call(env)
params = env[PARAMETERS_KEY]
+ prepare_params!(params)
+
+ unless controller = controller(params)
+ return [404, {'X-Cascade' => 'pass'}, []]
+ end
+
+ controller.action(params[:action]).call(env)
+ end
+
+ def prepare_params!(params)
merge_default_action!(params)
split_glob_param!(params) if @glob_param
+
params.each do |key, value|
if value.is_a?(String)
value = value.dup.force_encoding(Encoding::BINARY) if value.respond_to?(:force_encoding)
params[key] = URI.unescape(value)
end
end
+ end
- if env['action_controller.recognize']
- [200, {}, params]
- else
- controller = controller(params)
- controller.action(params[:action]).call(env)
+ def controller(params)
+ if params && params.has_key?(:controller)
+ controller = "#{params[:controller].camelize}Controller"
+ ActiveSupport::Inflector.constantize(controller)
end
+ rescue NameError
+ nil
end
private
- def controller(params)
- if params && params.has_key?(:controller)
- controller = "#{params[:controller].camelize}Controller"
- ActiveSupport::Inflector.constantize(controller)
- end
- end
-
def merge_default_action!(params)
params[:action] ||= 'index'
end
@@ -197,26 +203,40 @@ module ActionDispatch
end
end
- attr_accessor :routes, :named_routes, :configuration_files
+ attr_accessor :routes, :named_routes
+ attr_accessor :disable_clear_and_finalize
def initialize
- self.configuration_files = []
-
self.routes = []
self.named_routes = NamedRouteCollection.new
- clear!
+ @disable_clear_and_finalize = false
end
def draw(&block)
- clear!
- Mapper.new(self).instance_exec(DeprecatedMapper.new(self), &block)
+ clear! unless @disable_clear_and_finalize
+
+ mapper = Mapper.new(self)
+ if block.arity == 1
+ mapper.instance_exec(DeprecatedMapper.new(self), &block)
+ else
+ mapper.instance_exec(&block)
+ end
+
+ finalize! unless @disable_clear_and_finalize
+
+ nil
+ end
+
+ def finalize!
@set.add_route(NotFound)
install_helpers
@set.freeze
end
def clear!
+ # Clear the controller cache so we may discover new ones
+ @controller_constraints = nil
routes.clear
named_routes.clear
@set = ::Rack::Mount::RouteSet.new(:parameters_key => PARAMETERS_KEY)
@@ -231,63 +251,38 @@ module ActionDispatch
routes.empty?
end
- def add_configuration_file(path)
- self.configuration_files << path
- end
-
- # Deprecated accessor
- def configuration_file=(path)
- add_configuration_file(path)
- end
-
- # Deprecated accessor
- def configuration_file
- configuration_files
- end
-
- def load!
- Routing.use_controllers!(nil) # Clear the controller cache so we may discover new ones
- load_routes!
- end
-
- # reload! will always force a reload whereas load checks the timestamp first
- alias reload! load!
-
- def reload
- if configuration_files.any? && @routes_last_modified
- if routes_changed_at == @routes_last_modified
- return # routes didn't change, don't reload
- else
- @routes_last_modified = routes_changed_at
- end
- end
+ CONTROLLER_REGEXP = /[_a-zA-Z0-9]+/
- load!
- end
-
- def load_routes!
- if configuration_files.any?
- configuration_files.each { |config| load(config) }
- @routes_last_modified = routes_changed_at
- else
- draw do |map|
- map.connect ":controller/:action/:id"
- end
+ def controller_constraints
+ @controller_constraints ||= begin
+ source = controller_namespaces.map { |ns| "#{Regexp.escape(ns)}/#{CONTROLLER_REGEXP.source}" }
+ source << CONTROLLER_REGEXP.source
+ Regexp.compile(source.sort.reverse.join('|'))
end
end
- def routes_changed_at
- routes_changed_at = nil
+ def controller_namespaces
+ namespaces = Set.new
- configuration_files.each do |config|
- config_changed_at = File.stat(config).mtime
+ # Find any nested controllers already in memory
+ ActionController::Base.subclasses.each do |klass|
+ controller_name = klass.underscore
+ namespaces << controller_name.split('/')[0...-1].join('/')
+ end
- if routes_changed_at.nil? || config_changed_at > routes_changed_at
- routes_changed_at = config_changed_at
+ # TODO: Move this into Railties
+ if defined?(Rails.application)
+ # Find namespaces in controllers/ directory
+ Rails.application.config.controller_paths.each do |load_path|
+ load_path = File.expand_path(load_path)
+ Dir["#{load_path}/**/*_controller.rb"].collect do |path|
+ namespaces << File.dirname(path).sub(/#{load_path}\/?/, '')
+ end
end
end
- routes_changed_at
+ namespaces.delete('')
+ namespaces
end
def add_route(app, conditions = {}, requirements = {}, defaults = {}, name = nil)
@@ -372,7 +367,8 @@ module ActionDispatch
end
recall[:action] = options.delete(:action) if options[:action] == 'index'
- parameterize = lambda { |name, value|
+ opts = {}
+ opts[:parameterize] = lambda { |name, value|
if name == :controller
value
elsif value.is_a?(Array)
@@ -382,14 +378,23 @@ module ActionDispatch
end
}
- path = @set.url(named_route, options, recall, :parameterize => parameterize)
+ unless result = @set.generate(:path_info, named_route, options, recall, opts)
+ raise ActionController::RoutingError, "No route matches #{options.inspect}"
+ end
+
+ path, params = result
+ params.each do |k, v|
+ if v
+ params[k] = v
+ else
+ params.delete(k)
+ end
+ end
+
if path && method == :generate_extras
- uri = URI(path)
- extras = uri.query ?
- Rack::Utils.parse_nested_query(uri.query).keys.map { |k| k.to_sym } :
- []
- [uri.path, extras]
+ [path, params.keys]
elsif path
+ path << "?#{params.to_query}" if params.any?
path
else
raise ActionController::RoutingError, "No route matches #{options.inspect}"
@@ -400,37 +405,11 @@ module ActionDispatch
def call(env)
@set.call(env)
- rescue ActionController::RoutingError => e
- raise e if env['action_controller.rescue_error'] == false
-
- method, path = env['REQUEST_METHOD'].downcase.to_sym, env['PATH_INFO']
-
- # Route was not recognized. Try to find out why (maybe wrong verb).
- allows = HTTP_METHODS.select { |verb|
- begin
- recognize_path(path, {:method => verb}, false)
- rescue ActionController::RoutingError
- nil
- end
- }
-
- if !HTTP_METHODS.include?(method)
- raise ActionController::NotImplemented.new(*allows)
- elsif !allows.empty?
- raise ActionController::MethodNotAllowed.new(*allows)
- else
- raise e
- end
- end
-
- def recognize(request)
- params = recognize_path(request.path, extract_request_environment(request))
- request.path_parameters = params.with_indifferent_access
- "#{params[:controller].to_s.camelize}Controller".constantize
end
- def recognize_path(path, environment = {}, rescue_error = true)
+ def recognize_path(path, environment = {})
method = (environment[:method] || "GET").to_s.upcase
+ path = Rack::Mount::Utils.normalize_path(path)
begin
env = Rack::MockRequest.env_for(path, {:method => method})
@@ -438,16 +417,16 @@ module ActionDispatch
raise ActionController::RoutingError, e.message
end
- env['action_controller.recognize'] = true
- env['action_controller.rescue_error'] = rescue_error
- status, headers, body = call(env)
- body
- end
+ req = Rack::Request.new(env)
+ @set.recognize(req) do |route, params|
+ dispatcher = route.app
+ if dispatcher.is_a?(Dispatcher) && dispatcher.controller(params)
+ dispatcher.prepare_params!(params)
+ return params
+ end
+ end
- # Subclasses and plugins may override this method to extract further attributes
- # from the request, for use by route conditions and such.
- def extract_request_environment(request)
- { :method => request.method }
+ raise ActionController::RoutingError, "No route matches #{path.inspect}"
end
end
end
diff --git a/actionpack/lib/action_dispatch/testing/assertions/dom.rb b/actionpack/lib/action_dispatch/testing/assertions/dom.rb
index 9a917f704a..9c215de743 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/dom.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/dom.rb
@@ -1,3 +1,5 @@
+require 'action_controller/vendor/html-scanner'
+
module ActionDispatch
module Assertions
module DomAssertions
@@ -15,7 +17,7 @@ module ActionDispatch
assert_block(full_message) { expected_dom == actual_dom }
end
-
+
# The negated form of +assert_dom_equivalent+.
#
# ==== Examples
diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb
index 501a7c4dfb..5686bbdbde 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/response.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb
@@ -28,7 +28,7 @@ module ActionDispatch
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 == ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[type]
+ elsif type.is_a?(Symbol) && @response.response_code == Rack::Utils::SYMBOL_TO_STATUS_CODE[type]
assert_block("") { true } # to count the assertion
else
assert_block(build_message(message, "Expected response to be a <?>, but was <?>", type, @response.response_code)) { false }
diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
index e6d6b5a3ef..fc477afb17 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
@@ -46,7 +46,6 @@ module ActionDispatch
request_method = nil
end
- ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty?
request = recognized_request_for(path, request_method)
expected_options = expected_options.clone
@@ -80,7 +79,6 @@ module ActionDispatch
def assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)
expected_path = "/#{expected_path}" unless expected_path[0] == ?/
# Load routes.rb if it hasn't been loaded.
- ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty?
generated_path, extra_keys = ActionController::Routing::Routes.generate_extras(options, defaults)
found_extras = options.reject {|k, v| ! extra_keys.include? k}
@@ -126,6 +124,46 @@ module ActionDispatch
assert_generates(path.is_a?(Hash) ? path[:path] : path, options, defaults, extras, message)
end
+ # A helper to make it easier to test different route configurations.
+ # This method temporarily replaces ActionController::Routing::Routes
+ # with a new RouteSet instance.
+ #
+ # The new instance is yielded to the passed block. Typically the block
+ # will create some routes using <tt>map.draw { map.connect ... }</tt>:
+ #
+ # with_routing do |set|
+ # set.draw do |map|
+ # map.connect ':controller/:action/:id'
+ # assert_equal(
+ # ['/content/10/show', {}],
+ # map.generate(:controller => 'content', :id => 10, :action => 'show')
+ # end
+ # end
+ # end
+ #
+ def with_routing
+ real_routes = ActionController::Routing::Routes
+ ActionController::Routing.module_eval { remove_const :Routes }
+
+ temporary_routes = ActionController::Routing::RouteSet.new
+ ActionController::Routing.module_eval { const_set :Routes, temporary_routes }
+
+ yield temporary_routes
+ ensure
+ if ActionController::Routing.const_defined? :Routes
+ ActionController::Routing.module_eval { remove_const :Routes }
+ end
+ ActionController::Routing.const_set(:Routes, real_routes) if real_routes
+ end
+
+ def method_missing(selector, *args, &block)
+ if @controller && ActionController::Routing::Routes.named_routes.helpers.include?(selector)
+ @controller.send(selector, *args, &block)
+ else
+ super
+ end
+ end
+
private
# Recognizes the route for a given path.
def recognized_request_for(path, request_method = nil)
@@ -134,9 +172,11 @@ module ActionDispatch
# Assume given controller
request = ActionController::TestRequest.new
request.env["REQUEST_METHOD"] = request_method.to_s.upcase if request_method
- request.path = path
+ request.path = path
+
+ params = ActionController::Routing::Routes.recognize_path(path, { :method => request.method })
+ request.path_parameters = params.with_indifferent_access
- ActionController::Routing::Routes.recognize(request)
request
end
end
diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb
index d22adfa749..c2dc591ff7 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb
@@ -1,3 +1,5 @@
+require 'action_controller/vendor/html-scanner'
+
#--
# Copyright (c) 2006 Assaf Arkin (http://labnotes.org)
# Under MIT and/or CC By license.
@@ -16,7 +18,7 @@ module ActionDispatch
#
# Use +css_select+ to select elements without making an assertions, either
# from the response HTML or elements selected by the enclosing assertion.
- #
+ #
# In addition to HTML responses, you can make the following assertions:
# * +assert_select_rjs+ - Assertions on HTML content of RJS update and insertion operations.
# * +assert_select_encoded+ - Assertions on HTML encoded inside XML, for example for dealing with feed item descriptions.
@@ -53,8 +55,8 @@ module ActionDispatch
# end
#
# # Selects all list items in unordered lists
- # items = css_select("ul>li")
- #
+ # items = css_select("ul>li")
+ #
# # Selects all form tags and then all inputs inside the form
# forms = css_select("form")
# forms.each do |form|
@@ -212,7 +214,7 @@ module ActionDispatch
# Otherwise just operate on the response document.
root = response_from_page_or_rjs
end
-
+
# First or second argument is the selector: string and we pass
# all remaining arguments. Array and we pass the argument. Also
# accepts selector itself.
@@ -225,7 +227,7 @@ module ActionDispatch
selector = arg
else raise ArgumentError, "Expecting a selector as the first argument"
end
-
+
# Next argument is used for equality tests.
equals = {}
case arg = args.shift
@@ -315,10 +317,10 @@ module ActionDispatch
# Returns all matches elements.
matches
end
-
+
def count_description(min, max) #:nodoc:
pluralize = lambda {|word, quantity| word << (quantity == 1 ? '' : 's')}
-
+
if min && max && (max != min)
"between #{min} and #{max} elements"
elsif min && !(min == 1 && max == 1)
@@ -327,7 +329,7 @@ module ActionDispatch
"at most #{max} #{pluralize['element', max]}"
end
end
-
+
# :call-seq:
# assert_select_rjs(id?) { |elements| ... }
# assert_select_rjs(statement, id?) { |elements| ... }
@@ -344,7 +346,7 @@ module ActionDispatch
# that update or insert an element with that identifier.
#
# Use the first argument to narrow down assertions to only statements
- # of that type. Possible values are <tt>:replace</tt>, <tt>:replace_html</tt>,
+ # of that type. Possible values are <tt>:replace</tt>, <tt>:replace_html</tt>,
# <tt>:show</tt>, <tt>:hide</tt>, <tt>:toggle</tt>, <tt>:remove</tta>,
# <tt>:insert_html</tt> and <tt>:redirect</tt>.
#
@@ -494,7 +496,7 @@ module ActionDispatch
# end
# end
# end
- #
+ #
#
# # Selects all paragraph tags from within the description of an RSS feed
# assert_select_feed :rss, 2.0 do
diff --git a/actionpack/lib/action_dispatch/testing/assertions/tag.rb b/actionpack/lib/action_dispatch/testing/assertions/tag.rb
index ef6867576e..5c735e61b2 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/tag.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/tag.rb
@@ -1,3 +1,5 @@
+require 'action_controller/vendor/html-scanner'
+
module ActionDispatch
module Assertions
# Pair of assertions to testing elements in the HTML output of the response.
@@ -76,10 +78,10 @@ module ActionDispatch
# # Assert that there is a "span" containing between 2 and 4 "em" tags
# # as immediate children
# assert_tag :tag => "span",
- # :children => { :count => 2..4, :only => { :tag => "em" } }
+ # :children => { :count => 2..4, :only => { :tag => "em" } }
#
# # Get funky: assert that there is a "div", with an "ul" ancestor
- # # and an "li" parent (with "class" = "enum"), and containing a
+ # # and an "li" parent (with "class" = "enum"), and containing a
# # "span" descendant that contains text matching /hello world/
# assert_tag :tag => "div",
# :ancestor => { :tag => "ul" },
@@ -98,7 +100,7 @@ module ActionDispatch
tag = find_tag(opts)
assert tag, "expected tag, but no tag found matching #{opts.inspect} in:\n#{@response.body.inspect}"
end
-
+
# Identical to +assert_tag+, but asserts that a matching tag does _not_
# exist. (See +assert_tag+ for a full discussion of the syntax.)
#
@@ -118,6 +120,19 @@ module ActionDispatch
tag = find_tag(opts)
assert !tag, "expected no tag, but found tag matching #{opts.inspect} in:\n#{@response.body.inspect}"
end
+
+ def find_tag(conditions)
+ html_document.find(conditions)
+ end
+
+ def find_all_tag(conditions)
+ html_document.find_all(conditions)
+ end
+
+ def html_document
+ xml = @response.content_type =~ /xml$/
+ @html_document ||= HTML::Document.new(@response.body, false, xml)
+ end
end
end
end
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 40d6f97b2a..2a5f5dcd5c 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -2,9 +2,7 @@ require 'stringio'
require 'uri'
require 'active_support/test_case'
require 'active_support/core_ext/object/metaclass'
-
-# TODO: Remove circular dependency on ActionController
-require 'action_controller/testing/process'
+require 'rack/test'
module ActionDispatch
module Integration #:nodoc:
@@ -128,9 +126,7 @@ module ActionDispatch
DEFAULT_HOST = "www.example.com"
include Test::Unit::Assertions
- include ActionDispatch::Assertions
- include ActionController::TestProcess
- include RequestHelpers
+ include TestProcess, RequestHelpers, Assertions
%w( status status_message headers body redirect? ).each do |method|
delegate method, :to => :response, :allow_nil => true
@@ -415,7 +411,7 @@ module ActionDispatch
# At its simplest, you simply extend IntegrationTest and write your tests
# using the get/post methods:
#
- # require "#{File.dirname(__FILE__)}/test_helper"
+ # require "test_helper"
#
# class ExampleTest < ActionController::IntegrationTest
# fixtures :people
@@ -439,7 +435,7 @@ module ActionDispatch
# powerful testing DSL that is specific for your application. You can even
# reference any named routes you happen to have defined!
#
- # require "#{File.dirname(__FILE__)}/test_helper"
+ # require "test_helper"
#
# class AdvancedTest < ActionController::IntegrationTest
# fixtures :people, :rooms
diff --git a/actionpack/lib/action_dispatch/testing/performance_test.rb b/actionpack/lib/action_dispatch/testing/performance_test.rb
index b1ed9d31f4..1b9a6c18b7 100644
--- a/actionpack/lib/action_dispatch/testing/performance_test.rb
+++ b/actionpack/lib/action_dispatch/testing/performance_test.rb
@@ -1,15 +1,17 @@
require 'active_support/testing/performance'
require 'active_support/testing/default'
-module ActionDispatch
- # An integration test that runs a code profiler on your test methods.
- # Profiling output for combinations of each test method, measurement, and
- # output format are written to your tmp/performance directory.
- #
- # By default, process_time is measured and both flat and graph_html output
- # formats are written, so you'll have two output files per test method.
- class PerformanceTest < ActionDispatch::IntegrationTest
- include ActiveSupport::Testing::Performance
- include ActiveSupport::Testing::Default
+if defined?(ActiveSupport::Testing::Performance)
+ module ActionDispatch
+ # An integration test that runs a code profiler on your test methods.
+ # Profiling output for combinations of each test method, measurement, and
+ # output format are written to your tmp/performance directory.
+ #
+ # By default, process_time is measured and both flat and graph_html output
+ # formats are written, so you'll have two output files per test method.
+ class PerformanceTest < ActionDispatch::IntegrationTest
+ include ActiveSupport::Testing::Performance
+ include ActiveSupport::Testing::Default
+ end
end
-end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_dispatch/testing/test_process.rb b/actionpack/lib/action_dispatch/testing/test_process.rb
new file mode 100644
index 0000000000..eae703e1b6
--- /dev/null
+++ b/actionpack/lib/action_dispatch/testing/test_process.rb
@@ -0,0 +1,42 @@
+module ActionDispatch
+ module TestProcess
+ def assigns(key = nil)
+ assigns = {}
+ @controller.instance_variable_names.each do |ivar|
+ next if ActionController::Base.protected_instance_variables.include?(ivar)
+ assigns[ivar[1..-1]] = @controller.instance_variable_get(ivar)
+ end
+
+ key.nil? ? assigns : assigns[key.to_s]
+ end
+
+ def session
+ @request.session
+ end
+
+ def flash
+ @request.flash
+ end
+
+ def cookies
+ @request.cookies.merge(@response.cookies)
+ end
+
+ def redirect_to_url
+ @response.redirect_url
+ end
+
+ # Shortcut for <tt>ARack::Test::UploadedFile.new(ActionController::TestCase.fixture_path + path, type)</tt>:
+ #
+ # post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png')
+ #
+ # To upload binary files on Windows, pass <tt>:binary</tt> as the last parameter.
+ # This will not affect other platforms:
+ #
+ # post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png', :binary)
+ def fixture_file_upload(path, mime_type = nil, binary = false)
+ fixture_path = ActionController::TestCase.send(:fixture_path) if ActionController::TestCase.respond_to?(:fixture_path)
+ Rack::Test::UploadedFile.new("#{fixture_path}#{path}", mime_type, binary)
+ end
+ end
+end
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb
index e95e84aeb5..8ce6e82524 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -21,38 +21,40 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
-require File.join(File.dirname(__FILE__), "action_pack")
+activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
+$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
+require 'active_support/ruby/shim'
+require 'active_support/core_ext/class/attribute_accessors'
+
+require 'action_pack'
module ActionView
- def self.load_all!
- [Context, Base, InlineTemplate, TemplateError]
- end
+ extend ActiveSupport::Autoload
+
+ eager_autoload do
+ autoload :Context
+ autoload :Template
+ autoload :Helpers
+ autoload :SafeBuffer
+
+ autoload_under "render" do
+ autoload :Partials
+ autoload :Rendering
+ end
- autoload :Base, 'action_view/base'
- autoload :Context, 'action_view/context'
- autoload :Helpers, 'action_view/helpers'
- autoload :MissingTemplate, 'action_view/base'
- autoload :Partials, 'action_view/render/partials'
- autoload :Resolver, 'action_view/template/resolver'
- autoload :PathResolver, 'action_view/template/resolver'
- autoload :PathSet, 'action_view/paths'
- autoload :Rendering, 'action_view/render/rendering'
- 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'
- autoload :FileSystemResolverWithFallback, 'action_view/template/resolver'
- autoload :SafeBuffer, 'action_view/safe_buffer'
+ autoload :MissingTemplate, 'action_view/base'
+ autoload :Resolver, 'action_view/template/resolver'
+ autoload :PathResolver, 'action_view/template/resolver'
+ autoload :PathSet, 'action_view/paths'
+ autoload :FileSystemResolverWithFallback, 'action_view/template/resolver'
+
+ autoload :TemplateError, 'action_view/template/error'
+ autoload :TemplateHandler, 'action_view/template'
+ autoload :TemplateHandlers, 'action_view/template'
+ end
end
require 'action_view/erb/util'
-
+require 'action_view/base'
I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml"
-
-activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
-$:.unshift activesupport_path if File.directory?(activesupport_path)
-require 'active_support'
-require 'active_support/core_ext/class/attribute_accessors'
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index c33695770f..d69e5109fa 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -196,7 +196,7 @@ module ActionView #:nodoc:
end
class << self
- delegate :erb_trim_mode=, :to => 'ActionView::TemplateHandlers::ERB'
+ delegate :erb_trim_mode=, :to => 'ActionView::Template::Handlers::ERB'
delegate :logger, :to => 'ActionController::Base', :allow_nil => true
end
diff --git a/actionpack/lib/action_view/helpers/sanitize_helper.rb b/actionpack/lib/action_view/helpers/sanitize_helper.rb
index 69d0d0fb67..f03ffe5ef4 100644
--- a/actionpack/lib/action_view/helpers/sanitize_helper.rb
+++ b/actionpack/lib/action_view/helpers/sanitize_helper.rb
@@ -1,3 +1,4 @@
+require 'action_controller/vendor/html-scanner'
require 'action_view/helpers/tag_helper'
module ActionView
diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb
index 564f12c955..35c431d78d 100644
--- a/actionpack/lib/action_view/helpers/translation_helper.rb
+++ b/actionpack/lib/action_view/helpers/translation_helper.rb
@@ -12,7 +12,7 @@ module ActionView
# prepend the key with a period, nothing is converted.
def translate(key, options = {})
options[:raise] = true
- I18n.translate(scope_key_by_partial(key), options)
+ I18n.translate(scope_key_by_partial(key), options).html_safe!
rescue I18n::MissingTranslationData => e
keys = I18n.send(:normalize_translation_keys, e.locale, e.key, e.options[:scope])
content_tag('span', keys.join(', '), :class => 'translation_missing')
diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb
index 23bde61f9c..0059b79e5f 100644
--- a/actionpack/lib/action_view/paths.rb
+++ b/actionpack/lib/action_view/paths.rb
@@ -4,7 +4,7 @@ module ActionView #:nodoc:
# TODO: Clean this up
if obj.is_a?(String)
if cache.nil?
- cache = !defined?(Rails) || Rails.application.config.cache_classes
+ cache = !defined?(Rails.application) || Rails.application.config.cache_classes
end
FileSystemResolverWithFallback.new(obj, :cache => cache)
else
diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb
index 2eb88ae3e5..aeaf1ee4ff 100644
--- a/actionpack/lib/action_view/render/partials.rb
+++ b/actionpack/lib/action_view/render/partials.rb
@@ -181,20 +181,20 @@ module ActionView
def initialize(view_context, options, block)
@view = view_context
@partial_names = PARTIAL_NAMES[@view.controller.class]
-
+
key = Thread.current[:format_locale_key]
@templates = TEMPLATES[key] if key
-
+
setup(options, block)
end
-
+
def setup(options, block)
partial = options[:partial]
-
+
@options = options
@locals = options[:locals] || {}
@block = block
-
+
if String === partial
@object = options[:object]
@path = partial
@@ -240,7 +240,7 @@ module ActionView
segments << template.render(@view, locals)
end
-
+
@template = template
segments
end
@@ -294,7 +294,7 @@ module ActionView
path && @templates[path] ||= _find_template(path)
end
end
-
+
def _find_template(path)
if controller = @view.controller
prefix = controller.controller_path unless path.include?(?/)
@@ -319,7 +319,7 @@ module ActionView
_evaluate_assigns_and_ivars
details = options[:_details]
-
+
# Is this needed
self.formats = details[:formats] if details
renderer = PartialRenderer.new(self, options, nil)
@@ -329,12 +329,12 @@ module ActionView
end
def _render_partial(options, &block) #:nodoc:
- if @renderer
+ if defined? @renderer
@renderer.setup(options, block)
else
@renderer = PartialRenderer.new(self, options, block)
end
-
+
@renderer.render
end
diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb
index 7006a5b968..d4d16b4d98 100644
--- a/actionpack/lib/action_view/render/rendering.rb
+++ b/actionpack/lib/action_view/render/rendering.rb
@@ -78,12 +78,12 @@ module ActionView
end
def _render_inline(inline, layout, options)
- handler = Template.handler_class_for_extension(options[:type] || "erb")
- template = Template.new(options[:inline],
- "inline #{options[:inline].inspect}", handler, {})
+ handler = Template.handler_class_for_extension(options[:type] || "erb")
+ template = Template.new(options[:inline], "inline template", handler, {})
- locals = options[:locals]
+ locals = options[:locals]
content = template.render(self, locals)
+
_render_text(content, layout, locals)
end
@@ -91,6 +91,7 @@ module ActionView
content = layout.render(self, locals) do |*name|
_layout_for(*name) { content }
end if layout
+
content
end
@@ -113,21 +114,16 @@ module ActionView
msg
end
- locals = options[:locals] || {}
-
- content = if partial
- _render_partial_object(template, options)
- else
- template.render(self, locals)
- end
-
+ locals = options[:locals] || {}
+ content = partial ? _render_partial_object(template, options) : template.render(self, locals)
@_content_for[:layout] = content
if layout
@_layout = layout.identifier
logger.info("Rendering template within #{layout.inspect}") if logger
- content = layout.render(self, locals) {|*name| _layout_for(*name) }
+ content = layout.render(self, locals) { |*name| _layout_for(*name) }
end
+
content
end
end
diff --git a/actionpack/lib/action_view/safe_buffer.rb b/actionpack/lib/action_view/safe_buffer.rb
index 09f44ab26f..6be05b9e1e 100644
--- a/actionpack/lib/action_view/safe_buffer.rb
+++ b/actionpack/lib/action_view/safe_buffer.rb
@@ -1,4 +1,3 @@
-
module ActionView #:nodoc:
class SafeBuffer < String
def <<(value)
diff --git a/actionpack/lib/action_view/template/template.rb b/actionpack/lib/action_view/template.rb
index d1970ca3c7..d46c989d11 100644
--- a/actionpack/lib/action_view/template/template.rb
+++ b/actionpack/lib/action_view/template.rb
@@ -6,7 +6,16 @@ require "action_view/template/resolver"
module ActionView
class Template
- extend TemplateHandlers
+ extend ActiveSupport::Autoload
+
+ eager_autoload do
+ autoload :Error
+ autoload :Handler
+ autoload :Handlers
+ autoload :Text
+ end
+
+ extend Template::Handlers
attr_reader :source, :identifier, :handler, :mime_type, :formats, :details
def initialize(source, identifier, handler, details)
@@ -32,11 +41,11 @@ module ActionView
view.send(method_name, locals, &block)
end
rescue Exception => e
- if e.is_a?(TemplateError)
+ if e.is_a?(Template::Error)
e.sub_template_of(self)
raise e
else
- raise TemplateError.new(self, view.assigns, e)
+ raise Template::Error.new(self, view.assigns, e)
end
end
@@ -103,23 +112,8 @@ module ActionView
logger.debug "Backtrace: #{e.backtrace.join("\n")}"
end
- raise ActionView::TemplateError.new(self, {}, e)
- end
- end
-
- class LocalsKey
- @hash_keys = Hash.new {|h,k| h[k] = Hash.new {|h,k| h[k] = {} } }
-
- def self.get(*locals)
- @hash_keys[*locals] ||= new(klass, format, locale)
+ raise ActionView::Template::Error.new(self, {}, e)
end
-
- attr_accessor :hash
- def initialize(klass, format, locale)
- @hash = locals.hash
- end
-
- alias_method :eql?, :equal?
end
def build_method_name(locals)
diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb
index aa21606f76..648f708d3d 100644
--- a/actionpack/lib/action_view/template/error.rb
+++ b/actionpack/lib/action_view/template/error.rb
@@ -1,101 +1,105 @@
require "active_support/core_ext/enumerable"
module ActionView
- # The TemplateError exception is raised when the compilation of the template fails. This exception then gathers a
- # bunch of intimate details and uses it to report a very precise exception message.
- class TemplateError < ActionViewError #:nodoc:
- SOURCE_CODE_RADIUS = 3
+ class Template
+ # The Template::Error exception is raised when the compilation of the template fails. This exception then gathers a
+ # bunch of intimate details and uses it to report a very precise exception message.
+ class Error < ActionViewError #:nodoc:
+ SOURCE_CODE_RADIUS = 3
- attr_reader :original_exception
+ attr_reader :original_exception
- def initialize(template, assigns, original_exception)
- @template, @assigns, @original_exception = template, assigns.dup, original_exception
- @backtrace = compute_backtrace
- end
+ def initialize(template, assigns, original_exception)
+ @template, @assigns, @original_exception = template, assigns.dup, original_exception
+ @backtrace = compute_backtrace
+ end
- def file_name
- @template.identifier
- end
+ def file_name
+ @template.identifier
+ end
- def message
- ActiveSupport::Deprecation.silence { original_exception.message }
- end
+ def message
+ ActiveSupport::Deprecation.silence { original_exception.message }
+ end
- def clean_backtrace
- if defined?(Rails) && Rails.respond_to?(:backtrace_cleaner)
- Rails.backtrace_cleaner.clean(original_exception.backtrace)
- else
- original_exception.backtrace
+ def clean_backtrace
+ if defined?(Rails) && Rails.respond_to?(:backtrace_cleaner)
+ Rails.backtrace_cleaner.clean(original_exception.backtrace)
+ else
+ original_exception.backtrace
+ end
end
- end
- def sub_template_message
- if @sub_templates
- "Trace of template inclusion: " +
- @sub_templates.collect { |template| template.inspect }.join(", ")
- else
- ""
+ def sub_template_message
+ if @sub_templates
+ "Trace of template inclusion: " +
+ @sub_templates.collect { |template| template.inspect }.join(", ")
+ else
+ ""
+ end
end
- end
- def source_extract(indentation = 0)
- return unless num = line_number
- num = num.to_i
+ def source_extract(indentation = 0)
+ return unless num = line_number
+ num = num.to_i
- source_code = @template.source.split("\n")
+ source_code = @template.source.split("\n")
- start_on_line = [ num - SOURCE_CODE_RADIUS - 1, 0 ].max
- end_on_line = [ num + SOURCE_CODE_RADIUS - 1, source_code.length].min
+ start_on_line = [ num - SOURCE_CODE_RADIUS - 1, 0 ].max
+ end_on_line = [ num + SOURCE_CODE_RADIUS - 1, source_code.length].min
- indent = ' ' * indentation
- line_counter = start_on_line
- return unless source_code = source_code[start_on_line..end_on_line]
+ indent = ' ' * indentation
+ line_counter = start_on_line
+ return unless source_code = source_code[start_on_line..end_on_line]
- source_code.sum do |line|
- line_counter += 1
- "#{indent}#{line_counter}: #{line}\n"
+ source_code.sum do |line|
+ line_counter += 1
+ "#{indent}#{line_counter}: #{line}\n"
+ end
end
- end
-
- def sub_template_of(template_path)
- @sub_templates ||= []
- @sub_templates << template_path
- end
-
- def line_number
- @line_number ||=
- if file_name
- regexp = /#{Regexp.escape File.basename(file_name)}:(\d+)/
- $1 if message =~ regexp or clean_backtrace.find { |line| line =~ regexp }
- end
- end
+ def sub_template_of(template_path)
+ @sub_templates ||= []
+ @sub_templates << template_path
+ end
- def to_s
- "\n#{self.class} (#{message}) #{source_location}:\n" +
- "#{source_extract}\n #{clean_backtrace.join("\n ")}\n\n"
- end
+ def line_number
+ @line_number ||=
+ if file_name
+ regexp = /#{Regexp.escape File.basename(file_name)}:(\d+)/
- # don't do anything nontrivial here. Any raised exception from here becomes fatal
- # (and can't be rescued).
- def backtrace
- @backtrace
- end
+ $1 if message =~ regexp or clean_backtrace.find { |line| line =~ regexp }
+ end
+ end
- private
- def compute_backtrace
- [
- "#{source_location.capitalize}\n\n#{source_extract(4)}\n " +
- clean_backtrace.join("\n ")
- ]
+ def to_s
+ "\n#{self.class} (#{message}) #{source_location}:\n" +
+ "#{source_extract}\n #{clean_backtrace.join("\n ")}\n\n"
end
- def source_location
- if line_number
- "on line ##{line_number} of "
- else
- 'in '
- end + file_name
+ # don't do anything nontrivial here. Any raised exception from here becomes fatal
+ # (and can't be rescued).
+ def backtrace
+ @backtrace
end
+
+ private
+ def compute_backtrace
+ [
+ "#{source_location.capitalize}\n\n#{source_extract(4)}\n " +
+ clean_backtrace.join("\n ")
+ ]
+ end
+
+ def source_location
+ if line_number
+ "on line ##{line_number} of "
+ else
+ 'in '
+ end + file_name
+ end
+ end
end
-end \ No newline at end of file
+
+ TemplateError = Template::Error
+end
diff --git a/actionpack/lib/action_view/template/handler.rb b/actionpack/lib/action_view/template/handler.rb
index 4bf58b9fa8..5a46a27893 100644
--- a/actionpack/lib/action_view/template/handler.rb
+++ b/actionpack/lib/action_view/template/handler.rb
@@ -3,34 +3,39 @@ require "action_dispatch/http/mime_type"
# Legacy TemplateHandler stub
module ActionView
- module TemplateHandlers #:nodoc:
- module Compilable
- def self.included(base)
- base.extend(ClassMethods)
- end
+ class Template
+ module Handlers #:nodoc:
+ module Compilable
+ def self.included(base)
+ base.extend(ClassMethods)
+ end
- module ClassMethods
- def call(template)
- new.compile(template)
+ module ClassMethods
+ def call(template)
+ new.compile(template)
+ end
end
- end
- def compile(template)
- raise "Need to implement #{self.class.name}#compile(template)"
- end
+ def compile(template)
+ raise "Need to implement #{self.class.name}#compile(template)"
+ end
+ end
end
- end
- class TemplateHandler
- extlib_inheritable_accessor :default_format
- self.default_format = Mime::HTML
+ class Template::Handler
+ extlib_inheritable_accessor :default_format
+ self.default_format = Mime::HTML
- def self.call(template)
- raise "Need to implement #{self.class.name}#call(template)"
- end
+ def self.call(template)
+ raise "Need to implement #{self.class.name}#call(template)"
+ end
- def render(template, local_assigns)
- raise "Need to implement #{self.class.name}#render(template, local_assigns)"
+ def render(template, local_assigns)
+ raise "Need to implement #{self.class.name}#render(template, local_assigns)"
+ end
end
end
+
+ TemplateHandlers = Template::Handlers
+ TemplateHandler = Template::Handler
end
diff --git a/actionpack/lib/action_view/template/handlers.rb b/actionpack/lib/action_view/template/handlers.rb
index faf54b9fe5..35488c0391 100644
--- a/actionpack/lib/action_view/template/handlers.rb
+++ b/actionpack/lib/action_view/template/handlers.rb
@@ -1,52 +1,54 @@
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'
-
- def self.extended(base)
- base.register_default_template_handler :erb, TemplateHandlers::ERB
- base.register_template_handler :rjs, TemplateHandlers::RJS
- base.register_template_handler :builder, TemplateHandlers::Builder
-
- # TODO: Depreciate old template extensions
- base.register_template_handler :rhtml, TemplateHandlers::ERB
- base.register_template_handler :rxml, TemplateHandlers::Builder
- end
-
- @@template_handlers = {}
- @@default_template_handlers = nil
+ class Template
+ module Handlers #:nodoc:
+ 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, ERB
+ base.register_template_handler :rjs, RJS
+ base.register_template_handler :builder, Builder
+
+ # TODO: Depreciate old template extensions
+ base.register_template_handler :rhtml, ERB
+ base.register_template_handler :rxml, Builder
+ end
+
+ @@template_handlers = {}
+ @@default_template_handlers = nil
- def self.extensions
- @@template_handlers.keys
- end
-
- # Register a class that knows how to handle template files with the given
- # extension. This can be used to implement new template types.
- # The constructor for the class must take the ActiveView::Base instance
- # as a parameter, and the class must implement a +render+ method that
- # takes the contents of the template to render as well as the Hash of
- # local assigns available to the template. The +render+ method ought to
- # return the rendered template as a string.
- def register_template_handler(extension, klass)
- @@template_handlers[extension.to_sym] = klass
- end
-
- def template_handler_extensions
- @@template_handlers.keys.map {|key| key.to_s }.sort
- end
-
- def registered_template_handler(extension)
- extension && @@template_handlers[extension.to_sym]
- end
-
- def register_default_template_handler(extension, klass)
- register_template_handler(extension, klass)
- @@default_template_handlers = klass
- end
-
- def handler_class_for_extension(extension)
- (extension && registered_template_handler(extension.to_sym)) || @@default_template_handlers
+ def self.extensions
+ @@template_handlers.keys
+ end
+
+ # Register a class that knows how to handle template files with the given
+ # extension. This can be used to implement new template types.
+ # The constructor for the class must take the ActiveView::Base instance
+ # as a parameter, and the class must implement a +render+ method that
+ # takes the contents of the template to render as well as the Hash of
+ # local assigns available to the template. The +render+ method ought to
+ # return the rendered template as a string.
+ def register_template_handler(extension, klass)
+ @@template_handlers[extension.to_sym] = klass
+ end
+
+ def template_handler_extensions
+ @@template_handlers.keys.map {|key| key.to_s }.sort
+ end
+
+ def registered_template_handler(extension)
+ extension && @@template_handlers[extension.to_sym]
+ end
+
+ def register_default_template_handler(extension, klass)
+ register_template_handler(extension, klass)
+ @@default_template_handlers = klass
+ end
+
+ def handler_class_for_extension(extension)
+ (extension && registered_template_handler(extension.to_sym)) || @@default_template_handlers
+ end
end
end
end
diff --git a/actionpack/lib/action_view/template/handlers/builder.rb b/actionpack/lib/action_view/template/handlers/builder.rb
index 5f381f7bf0..a93cfca8aa 100644
--- a/actionpack/lib/action_view/template/handlers/builder.rb
+++ b/actionpack/lib/action_view/template/handlers/builder.rb
@@ -1,6 +1,6 @@
module ActionView
- module TemplateHandlers
- class Builder < TemplateHandler
+ module Template::Handlers
+ class Builder < Template::Handler
include Compilable
self.default_format = Mime::XML
diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb
index 88aeb4b053..93a4315108 100644
--- a/actionpack/lib/action_view/template/handlers/erb.rb
+++ b/actionpack/lib/action_view/template/handlers/erb.rb
@@ -3,14 +3,15 @@ require 'active_support/core_ext/string/output_safety'
require 'erubis'
module ActionView
- module TemplateHandlers
+ module Template::Handlers
class Erubis < ::Erubis::Eruby
def add_preamble(src)
src << "@output_buffer = ActionView::SafeBuffer.new;"
end
def add_text(src, text)
- src << "@output_buffer << ('" << escape_text(text) << "'.html_safe!);"
+ return if text.empty?
+ src << "@output_buffer.safe_concat('" << escape_text(text) << "');"
end
def add_expr_literal(src, code)
@@ -26,7 +27,7 @@ module ActionView
end
end
- class ERB < TemplateHandler
+ class ERB < Template::Handler
include Compilable
##
diff --git a/actionpack/lib/action_view/template/handlers/rjs.rb b/actionpack/lib/action_view/template/handlers/rjs.rb
index b1d15dc209..63e7dc0902 100644
--- a/actionpack/lib/action_view/template/handlers/rjs.rb
+++ b/actionpack/lib/action_view/template/handlers/rjs.rb
@@ -1,6 +1,6 @@
module ActionView
- module TemplateHandlers
- class RJS < TemplateHandler
+ module Template::Handlers
+ class RJS < Template::Handler
include Compilable
self.default_format = Mime::JS
diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb
index 7336114e1b..a2f4ab2ef5 100644
--- a/actionpack/lib/action_view/template/resolver.rb
+++ b/actionpack/lib/action_view/template/resolver.rb
@@ -1,6 +1,6 @@
require "pathname"
require "active_support/core_ext/class"
-require "action_view/template/template"
+require "action_view/template"
module ActionView
# Abstract superclass
@@ -20,7 +20,7 @@ module ActionView
register_detail(:locale) { [I18n.locale] }
register_detail(:formats) { Mime::SET.symbols }
register_detail(:handlers, :allow_nil => false) do
- TemplateHandlers.extensions
+ Template::Handlers.extensions
end
def initialize(options = {})
@@ -65,7 +65,7 @@ module ActionView
# as well as incorrectly putting part of the path in the template
# name instead of the prefix.
def normalize_name(name, prefix)
- handlers = TemplateHandlers.extensions.join('|')
+ handlers = Template::Handlers.extensions.join('|')
name = name.to_s.gsub(/\.(?:#{handlers})$/, '')
parts = name.split('/')
diff --git a/actionpack/lib/action_view/template/text.rb b/actionpack/lib/action_view/template/text.rb
index f6e011a5ab..67e086d8bd 100644
--- a/actionpack/lib/action_view/template/text.rb
+++ b/actionpack/lib/action_view/template/text.rb
@@ -1,38 +1,40 @@
module ActionView #:nodoc:
- class TextTemplate < String #:nodoc:
- HTML = Mime[:html]
-
- def initialize(string, content_type = HTML)
- super(string.to_s)
- @content_type = Mime[content_type] || content_type
- end
-
- def details
- {:formats => [@content_type.to_sym]}
- end
-
- def identifier
- self
- end
-
- def inspect
- 'text template'
- end
-
- def render(*args)
- to_s
- end
-
- def mime_type
- @content_type
- end
-
- def formats
- [mime_type]
- end
-
- def partial?
- false
+ class Template
+ class Text < String #:nodoc:
+ HTML = Mime[:html]
+
+ def initialize(string, content_type = HTML)
+ super(string.to_s)
+ @content_type = Mime[content_type] || content_type
+ end
+
+ def details
+ {:formats => [@content_type.to_sym]}
+ end
+
+ def identifier
+ self
+ end
+
+ def inspect
+ 'text template'
+ end
+
+ def render(*args)
+ to_s
+ end
+
+ def mime_type
+ @content_type
+ end
+
+ def formats
+ [mime_type]
+ end
+
+ def partial?
+ false
+ end
end
end
end
diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb
index 86bbad822d..be9a2ed50d 100644
--- a/actionpack/lib/action_view/test_case.rb
+++ b/actionpack/lib/action_view/test_case.rb
@@ -1,5 +1,5 @@
require 'active_support/test_case'
-require 'action_controller/testing/test_case'
+require 'action_controller/test_case'
module ActionView
class Base
@@ -39,8 +39,7 @@ module ActionView
end
end
- include ActionDispatch::Assertions
- include ActionController::TestProcess
+ include ActionDispatch::Assertions, ActionDispatch::TestProcess
include ActionView::Context
include ActionController::PolymorphicRoutes
diff --git a/actionpack/test/abstract/abstract_controller_test.rb b/actionpack/test/abstract/abstract_controller_test.rb
index 524381509d..4ad87d9762 100644
--- a/actionpack/test/abstract/abstract_controller_test.rb
+++ b/actionpack/test/abstract/abstract_controller_test.rb
@@ -28,7 +28,7 @@ module AbstractController
# Test Render mixin
# ====
class RenderingController < AbstractController::Base
- include ::AbstractController::RenderingController
+ include ::AbstractController::Rendering
def _prefix() end
diff --git a/actionpack/test/abstract/helper_test.rb b/actionpack/test/abstract/helper_test.rb
index efcd68e5c8..ade29140ba 100644
--- a/actionpack/test/abstract/helper_test.rb
+++ b/actionpack/test/abstract/helper_test.rb
@@ -6,7 +6,7 @@ module AbstractController
module Testing
class ControllerWithHelpers < AbstractController::Base
- include AbstractController::RenderingController
+ include AbstractController::Rendering
include Helpers
def with_module
diff --git a/actionpack/test/abstract/layouts_test.rb b/actionpack/test/abstract/layouts_test.rb
index ae2f1bf1f2..df73d948f0 100644
--- a/actionpack/test/abstract/layouts_test.rb
+++ b/actionpack/test/abstract/layouts_test.rb
@@ -6,7 +6,7 @@ module AbstractControllerTests
# Base controller for these tests
class Base < AbstractController::Base
- include AbstractController::RenderingController
+ include AbstractController::Rendering
include AbstractController::Layouts
self.view_paths = [ActionView::FixtureResolver.new(
@@ -23,7 +23,7 @@ module AbstractControllerTests
self.view_paths = []
def index
- render :_template => ActionView::TextTemplate.new("Hello blank!")
+ render :_template => ActionView::Template::Text.new("Hello blank!")
end
end
@@ -31,19 +31,19 @@ module AbstractControllerTests
layout "hello"
def index
- render :_template => ActionView::TextTemplate.new("Hello string!")
+ render :_template => ActionView::Template::Text.new("Hello string!")
end
def overwrite_default
- render :_template => ActionView::TextTemplate.new("Hello string!"), :layout => :default
+ render :_template => ActionView::Template::Text.new("Hello string!"), :layout => :default
end
def overwrite_false
- render :_template => ActionView::TextTemplate.new("Hello string!"), :layout => false
+ render :_template => ActionView::Template::Text.new("Hello string!"), :layout => false
end
def overwrite_string
- render :_template => ActionView::TextTemplate.new("Hello string!"), :layout => "omg"
+ render :_template => ActionView::Template::Text.new("Hello string!"), :layout => "omg"
end
def overwrite_skip
@@ -72,7 +72,7 @@ module AbstractControllerTests
layout :hello
def index
- render :_template => ActionView::TextTemplate.new("Hello symbol!")
+ render :_template => ActionView::Template::Text.new("Hello symbol!")
end
private
def hello
@@ -84,7 +84,7 @@ module AbstractControllerTests
layout :no_hello
def index
- render :_template => ActionView::TextTemplate.new("Hello missing symbol!")
+ render :_template => ActionView::Template::Text.new("Hello missing symbol!")
end
private
def no_hello
@@ -96,7 +96,7 @@ module AbstractControllerTests
layout :nilz
def index
- render :_template => ActionView::TextTemplate.new("Hello nilz!")
+ render :_template => ActionView::Template::Text.new("Hello nilz!")
end
def nilz() end
@@ -106,7 +106,7 @@ module AbstractControllerTests
layout :objekt
def index
- render :_template => ActionView::TextTemplate.new("Hello nilz!")
+ render :_template => ActionView::Template::Text.new("Hello nilz!")
end
def objekt
@@ -118,7 +118,7 @@ module AbstractControllerTests
layout :omg_no_method
def index
- render :_template => ActionView::TextTemplate.new("Hello boom!")
+ render :_template => ActionView::Template::Text.new("Hello boom!")
end
end
@@ -126,7 +126,7 @@ module AbstractControllerTests
layout "missing"
def index
- render :_template => ActionView::TextTemplate.new("Hello missing!")
+ render :_template => ActionView::Template::Text.new("Hello missing!")
end
end
@@ -134,7 +134,7 @@ module AbstractControllerTests
layout false
def index
- render :_template => ActionView::TextTemplate.new("Hello false!")
+ render :_template => ActionView::Template::Text.new("Hello false!")
end
end
@@ -142,7 +142,7 @@ module AbstractControllerTests
layout nil
def index
- render :_template => ActionView::TextTemplate.new("Hello nil!")
+ render :_template => ActionView::Template::Text.new("Hello nil!")
end
end
diff --git a/actionpack/test/abstract/localized_cache_test.rb b/actionpack/test/abstract/localized_cache_test.rb
index 6f9bb693f7..8b0b0fff03 100644
--- a/actionpack/test/abstract/localized_cache_test.rb
+++ b/actionpack/test/abstract/localized_cache_test.rb
@@ -4,7 +4,7 @@ module AbstractController
module Testing
class CachedController < AbstractController::Base
- include AbstractController::RenderingController
+ include AbstractController::Rendering
include AbstractController::LocalizedCache
self.view_paths = [ActionView::FixtureResolver.new(
diff --git a/actionpack/test/abstract/render_test.rb b/actionpack/test/abstract/render_test.rb
index 45a4763fe4..be0478b638 100644
--- a/actionpack/test/abstract/render_test.rb
+++ b/actionpack/test/abstract/render_test.rb
@@ -4,7 +4,7 @@ module AbstractController
module Testing
class ControllerRenderer < AbstractController::Base
- include AbstractController::RenderingController
+ include AbstractController::Rendering
self.view_paths = [ActionView::FixtureResolver.new(
"default.erb" => "With Default",
@@ -38,7 +38,7 @@ module AbstractController
end
def object
- render :_template => ActionView::TextTemplate.new("With Object")
+ render :_template => ActionView::Template::Text.new("With Object")
end
end
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 775cfc82bf..a9341b60df 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -1,12 +1,9 @@
-root = File.expand_path('../../..', __FILE__)
begin
- require "#{root}/vendor/gems/environment"
+ require File.expand_path('../../../vendor/gems/environment', __FILE__)
rescue LoadError
- $:.unshift "#{root}/activesupport/lib"
- $:.unshift "#{root}/activemodel/lib"
end
-lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
+lib = File.expand_path('../../lib', __FILE__)
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
$:.unshift(File.dirname(__FILE__) + '/lib')
@@ -16,18 +13,20 @@ $:.unshift(File.dirname(__FILE__) + '/fixtures/alternate_helpers')
ENV['TMPDIR'] = File.join(File.dirname(__FILE__), 'tmp')
require 'test/unit'
-require 'active_support'
-require 'active_support/test_case'
require 'abstract_controller'
require 'action_controller'
require 'action_view'
require 'action_view/base'
require 'action_dispatch'
-require 'active_model'
require 'fixture_template'
+require 'active_support/test_case'
require 'action_view/test_case'
require 'active_support/dependencies'
+activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__)
+$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path)
+require 'active_model'
+
begin
require 'ruby-debug'
Debugger.settings[:autoeval] = true
@@ -83,7 +82,7 @@ class ActiveSupport::TestCase
# have been loaded.
setup_once do
ActionController::Routing::Routes.draw do |map|
- map.connect ':controller/:action/:id'
+ match ':controller(/:action(/:id))'
end
end
end
@@ -191,26 +190,14 @@ class ::ApplicationController < ActionController::Base
end
module ActionController
- module Routing
- def self.possible_controllers
- @@possible_controllers ||= []
- end
- end
-
class Base
include ActionController::Testing
-
- def self.inherited(klass)
- name = klass.name.underscore.sub(/_controller$/, '')
- ActionController::Routing.possible_controllers << name unless name.blank?
- super
- end
end
Base.view_paths = FIXTURE_LOAD_PATH
class TestCase
- include TestProcess
+ include ActionDispatch::TestProcess
def assert_template(options = {}, message = nil)
validate_request!
diff --git a/actionpack/test/active_record_unit.rb b/actionpack/test/active_record_unit.rb
index 9e0c66055d..9a094cf66b 100644
--- a/actionpack/test/active_record_unit.rb
+++ b/actionpack/test/active_record_unit.rb
@@ -11,19 +11,15 @@ class ActiveRecordTestConnector
end
# Try to grab AR
-if defined?(ActiveRecord) && defined?(Fixtures)
- $stderr.puts 'Active Record is already loaded, running tests'
-else
- $stderr.print 'Attempting to load Active Record... '
+unless defined?(ActiveRecord) && defined?(Fixtures)
begin
PATH_TO_AR = "#{File.dirname(__FILE__)}/../../activerecord/lib"
raise LoadError, "#{PATH_TO_AR} doesn't exist" unless File.directory?(PATH_TO_AR)
$LOAD_PATH.unshift PATH_TO_AR
require 'active_record'
require 'active_record/fixtures'
- $stderr.puts 'success'
rescue LoadError => e
- $stderr.print "failed. Skipping Active Record assertion tests: #{e}"
+ $stderr.print "Failed to load Active Record. Skipping Active Record assertion tests: #{e}"
ActiveRecordTestConnector.able_to_connect = false
end
end
diff --git a/actionpack/test/activerecord/active_record_store_test.rb b/actionpack/test/activerecord/active_record_store_test.rb
index c6c079f88c..61bee1b66c 100644
--- a/actionpack/test/activerecord/active_record_store_test.rb
+++ b/actionpack/test/activerecord/active_record_store_test.rb
@@ -155,7 +155,7 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest
def with_test_route_set(options = {})
with_routing do |set|
set.draw do |map|
- map.connect "/:action", :controller => "active_record_store_test/test"
+ match ':action', :to => 'active_record_store_test/test'
end
@app = ActiveRecord::SessionStore.new(set, options.reverse_merge(:key => '_session_id'))
yield
diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb
index 901cb940ea..d54be9bdc0 100644
--- a/actionpack/test/controller/action_pack_assertions_test.rb
+++ b/actionpack/test/controller/action_pack_assertions_test.rb
@@ -221,8 +221,8 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase
def test_assert_redirect_to_named_route
with_routing do |set|
set.draw do |map|
- map.route_one 'route_one', :controller => 'action_pack_assertions', :action => 'nothing'
- map.connect ':controller/:action/:id'
+ match 'route_one', :to => 'action_pack_assertions#nothing', :as => :route_one
+ match ':controller/:action'
end
set.install_helpers
@@ -235,9 +235,9 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase
def test_assert_redirect_to_named_route_failure
with_routing do |set|
set.draw do |map|
- map.route_one 'route_one', :controller => 'action_pack_assertions', :action => 'nothing', :id => 'one'
- map.route_two 'route_two', :controller => 'action_pack_assertions', :action => 'nothing', :id => 'two'
- map.connect ':controller/:action/:id'
+ match 'route_one', :to => 'action_pack_assertions#nothing', :as => :route_one
+ match 'route_two', :to => 'action_pack_assertions#nothing', :id => 'two', :as => :route_two
+ match ':controller/:action'
end
process :redirect_to_named_route
assert_raise(ActiveSupport::TestCase::Assertion) do
@@ -255,8 +255,8 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase
def test_assert_redirect_to_nested_named_route
with_routing do |set|
set.draw do |map|
- map.admin_inner_module 'admin/inner_module', :controller => 'admin/inner_module', :action => 'index'
- map.connect ':controller/:action/:id'
+ match 'admin/inner_module', :to => 'admin/inner_module#index', :as => :admin_inner_module
+ match ':controller/:action'
end
@controller = Admin::InnerModuleController.new
process :redirect_to_index
@@ -268,8 +268,8 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase
def test_assert_redirected_to_top_level_named_route_from_nested_controller
with_routing do |set|
set.draw do |map|
- map.top_level '/action_pack_assertions/:id', :controller => 'action_pack_assertions', :action => 'index'
- map.connect ':controller/:action/:id'
+ match '/action_pack_assertions/:id', :to => 'action_pack_assertions#index', :as => :top_level
+ match ':controller/:action'
end
@controller = Admin::InnerModuleController.new
process :redirect_to_top_level_named_route
@@ -282,8 +282,8 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase
with_routing do |set|
set.draw do |map|
# this controller exists in the admin namespace as well which is the only difference from previous test
- map.top_level '/user/:id', :controller => 'user', :action => 'index'
- map.connect ':controller/:action/:id'
+ match '/user/:id', :to => 'user#index', :as => :top_level
+ match ':controller/:action'
end
@controller = Admin::InnerModuleController.new
process :redirect_to_top_level_named_route
diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb
index b57550a69a..8f8ada8d8c 100644
--- a/actionpack/test/controller/base_test.rb
+++ b/actionpack/test/controller/base_test.rb
@@ -179,8 +179,8 @@ class DefaultUrlOptionsTest < ActionController::TestCase
def test_default_url_options_are_used_if_set
with_routing do |set|
set.draw do |map|
- map.default_url_options 'default_url_options', :controller => 'default_url_options'
- map.connect ':controller/:action/:id'
+ match 'default_url_options', :to => 'default_url_options#default_url_options_action', :as => :default_url_options
+ match ':controller/:action'
end
get :default_url_options_action # Make a dummy request so that the controller is initialized properly.
@@ -210,7 +210,7 @@ class EnsureNamedRoutesWorksTicket22BugTest < ActionController::TestCase
def test_named_routes_still_work
with_routing do |set|
set.draw do |map|
- map.resources :things
+ resources :things
end
EmptyController.send :include, ActionController::UrlWriter
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index 3ce90b6ccf..4ea2e57741 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -70,8 +70,8 @@ class PageCachingTest < ActionController::TestCase
def test_page_caching_resources_saves_to_correct_path_with_extension_even_if_default_route
with_routing do |set|
set.draw do |map|
- map.main '', :controller => 'posts', :format => nil
- map.formatted_posts 'posts.:format', :controller => 'posts'
+ match 'posts.:format', :to => 'posts#index', :as => :formatted_posts
+ match '/', :to => 'posts#index', :as => :main
end
@params[:format] = 'rss'
assert_equal '/posts.rss', @rewriter.rewrite(@params)
@@ -422,8 +422,7 @@ class ActionCacheTest < ActionController::TestCase
def test_xml_version_of_resource_is_treated_as_different_cache
with_routing do |set|
set.draw do |map|
- map.connect ':controller/:action.:format'
- map.connect ':controller/:action'
+ match ':controller(/:action(.:format))'
end
get :index, :format => 'xml'
@@ -632,13 +631,16 @@ class FragmentCachingTest < ActionController::TestCase
def test_fragment_for_logging
fragment_computed = false
- ActiveSupport::Notifications.queue.expects(:publish).times(2)
+ events = []
+ ActiveSupport::Notifications.subscribe { |*args| events << args }
buffer = 'generated till now -> '
@controller.fragment_for(buffer, 'expensive') { fragment_computed = true }
assert fragment_computed
assert_equal 'generated till now -> ', buffer
+ ActiveSupport::Notifications.notifier.wait
+ assert_equal [:fragment_exist?, :write_fragment], events.map(&:first)
end
end
diff --git a/actionpack/test/controller/cookie_test.rb b/actionpack/test/controller/cookie_test.rb
index 53d4364576..84d5ce6ad4 100644
--- a/actionpack/test/controller/cookie_test.rb
+++ b/actionpack/test/controller/cookie_test.rb
@@ -1,5 +1,7 @@
require 'abstract_unit'
+ActionController::Base.cookie_verifier_secret = "thisISverySECRET123"
+
class CookieTest < ActionController::TestCase
class TestController < ActionController::Base
def authenticate
@@ -47,6 +49,21 @@ class CookieTest < ActionController::TestCase
cookies["user_name"] = { :value => "david", :httponly => true }
head :ok
end
+
+ def set_permanent_cookie
+ cookies.permanent[:user_name] = "Jamie"
+ head :ok
+ end
+
+ def set_signed_cookie
+ cookies.signed[:user_id] = 45
+ head :ok
+ end
+
+ def set_permanent_signed_cookie
+ cookies.permanent.signed[:remember_me] = 100
+ head :ok
+ end
end
tests TestController
@@ -134,6 +151,24 @@ class CookieTest < ActionController::TestCase
response = get :authenticate
assert response.headers["Set-Cookie"] =~ /user_name=david/
end
+
+ def test_permanent_cookie
+ get :set_permanent_cookie
+ assert_match /Jamie/, @response.headers["Set-Cookie"]
+ assert_match %r(#{20.years.from_now.year}), @response.headers["Set-Cookie"]
+ end
+
+ def test_signed_cookie
+ get :set_signed_cookie
+ assert_equal 45, @controller.send(:cookies).signed[:user_id]
+ end
+
+ def test_permanent_signed_cookie
+ get :set_permanent_signed_cookie
+ assert_match %r(#{20.years.from_now.year}), @response.headers["Set-Cookie"]
+ assert_equal 100, @controller.send(:cookies).signed[:remember_me]
+ end
+
private
def assert_cookie_header(expected)
diff --git a/actionpack/test/controller/dispatcher_test.rb b/actionpack/test/controller/dispatcher_test.rb
index 622d67287d..64f1ad7610 100644
--- a/actionpack/test/controller/dispatcher_test.rb
+++ b/actionpack/test/controller/dispatcher_test.rb
@@ -15,7 +15,6 @@ class DispatcherTest < Test::Unit::TestCase
ActionDispatch::Callbacks.reset_callbacks(:call)
ActionController::Routing::Routes.stubs(:call).returns([200, {}, 'response'])
- ActionController::Routing::Routes.stubs(:reload)
Dispatcher.stubs(:require_dependency)
end
@@ -28,18 +27,6 @@ class DispatcherTest < Test::Unit::TestCase
dispatch(false)
end
- def test_reloads_routes_before_dispatch_if_in_loading_mode
- ActionController::Routing::Routes.expects(:reload).once
- dispatch(false)
- end
-
- def test_leaves_dependencies_after_dispatch_if_not_in_loading_mode
- ActionController::Routing::Routes.expects(:reload).never
- ActiveSupport::Dependencies.expects(:clear).never
-
- dispatch
- end
-
def test_prepare_callbacks
a = b = c = nil
ActionDispatch::Callbacks.to_prepare { |*args| a = b = c = 1 }
diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb
index c448f36cb3..a9b60386f1 100644
--- a/actionpack/test/controller/flash_test.rb
+++ b/actionpack/test/controller/flash_test.rb
@@ -34,7 +34,7 @@ class FlashTest < ActionController::TestCase
flash.keep
render :inline => "hello"
end
-
+
def use_flash_and_update_it
flash.update("this" => "hello again")
@flash_copy = {}.update flash
@@ -72,6 +72,18 @@ class FlashTest < ActionController::TestCase
redirect_to :action => "std_action"
@flash_copy = {}.update(flash)
end
+
+ def redirect_with_alert
+ redirect_to '/nowhere', :alert => "Beware the nowheres!"
+ end
+
+ def redirect_with_notice
+ redirect_to '/somewhere', :notice => "Good luck in the somewheres!"
+ end
+
+ def redirect_with_other_flashes
+ redirect_to '/wonderland', :flash => { :joyride => "Horses!" }
+ end
end
tests TestController
@@ -89,7 +101,7 @@ class FlashTest < ActionController::TestCase
def test_keep_flash
get :set_flash
-
+
get :use_flash_and_keep_it
assert_equal "hello", assigns["flash_copy"]["that"]
assert_equal "hello", assigns["flashy"]
@@ -100,7 +112,7 @@ class FlashTest < ActionController::TestCase
get :use_flash
assert_nil assigns["flash_copy"]["that"], "On third flash"
end
-
+
def test_flash_now
get :set_flash_now
assert_equal "hello", assigns["flash_copy"]["that"]
@@ -111,8 +123,8 @@ class FlashTest < ActionController::TestCase
assert_nil assigns["flash_copy"]["that"]
assert_nil assigns["flash_copy"]["foo"]
assert_nil assigns["flashy"]
- end
-
+ end
+
def test_update_flash
get :set_flash
get :use_flash_and_update_it
@@ -128,7 +140,7 @@ class FlashTest < ActionController::TestCase
assert_equal "hello", assigns["flashy_that"]
assert_equal "good-bye", assigns["flashy_this"]
assert_nil assigns["flashy_that_reset"]
- end
+ end
def test_does_not_set_the_session_if_the_flash_is_empty
get :std_action
@@ -153,11 +165,26 @@ class FlashTest < ActionController::TestCase
assert_equal(:foo_indeed, flash.discard(:foo)) # valid key passed
assert_nil flash.discard(:unknown) # non existant key passed
assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.discard()) # nothing passed
- assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.discard(nil)) # nothing passed
+ assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.discard(nil)) # nothing passed
assert_equal(:foo_indeed, flash.keep(:foo)) # valid key passed
assert_nil flash.keep(:unknown) # non existant key passed
assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.keep()) # nothing passed
- assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.keep(nil)) # nothing passed
+ assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.keep(nil)) # nothing passed
+ end
+
+ def test_redirect_to_with_alert
+ get :redirect_with_alert
+ assert_equal "Beware the nowheres!", @controller.send(:flash)[:alert]
+ end
+
+ def test_redirect_to_with_notice
+ get :redirect_with_notice
+ assert_equal "Good luck in the somewheres!", @controller.send(:flash)[:notice]
+ end
+
+ def test_redirect_to_with_other_flashes
+ get :redirect_with_other_flashes
+ assert_equal "Horses!", @controller.send(:flash)[:joyride]
end
-end
+end \ No newline at end of file
diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb
index b9be163904..9030e562bb 100644
--- a/actionpack/test/controller/helper_test.rb
+++ b/actionpack/test/controller/helper_test.rb
@@ -191,7 +191,7 @@ class IsolatedHelpersTest < Test::Unit::TestCase
end
def test_helper_in_a
- assert_raise(ActionView::TemplateError) { call_controller(A, "index") }
+ assert_raise(ActionView::Template::Error) { call_controller(A, "index") }
end
def test_helper_in_b
diff --git a/actionpack/test/controller/layout_test.rb b/actionpack/test/controller/layout_test.rb
index feb2f81cc1..f635253156 100644
--- a/actionpack/test/controller/layout_test.rb
+++ b/actionpack/test/controller/layout_test.rb
@@ -115,7 +115,7 @@ class RendersNoLayoutController < LayoutTest
end
class LayoutSetInResponseTest < ActionController::TestCase
- include ActionView::TemplateHandlers
+ include ActionView::Template::Handlers
def test_layout_set_when_using_default_layout
@controller = DefaultLayoutController.new
diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb
index fee9cf46f9..6b9cace9cd 100644
--- a/actionpack/test/controller/mime_responds_test.rb
+++ b/actionpack/test/controller/mime_responds_test.rb
@@ -507,6 +507,13 @@ class RespondWithController < ActionController::Base
end
end
+ def using_responder_with_respond
+ responder = Class.new(ActionController::Responder) do
+ def respond; @controller.render :text => "respond #{format}"; end
+ end
+ respond_with(Customer.new("david", 13), :responder => responder)
+ end
+
protected
def _render_js(js, options)
@@ -592,14 +599,18 @@ class RespondWithControllerTest < ActionController::TestCase
end
end
- def test_using_resource_for_post_with_html
+ def test_using_resource_for_post_with_html_redirects_on_success
with_test_route_set do
post :using_resource
assert_equal "text/html", @response.content_type
assert_equal 302, @response.status
assert_equal "http://www.example.com/customers/13", @response.location
assert @response.redirect?
+ end
+ end
+ def test_using_resource_for_post_with_html_rerender_on_failure
+ with_test_route_set do
errors = { :name => :invalid }
Customer.any_instance.stubs(:errors).returns(errors)
post :using_resource
@@ -610,16 +621,20 @@ class RespondWithControllerTest < ActionController::TestCase
end
end
- def test_using_resource_for_post_with_xml
+ def test_using_resource_for_post_with_xml_yields_created_on_success
with_test_route_set do
@request.accept = "application/xml"
-
post :using_resource
assert_equal "application/xml", @response.content_type
assert_equal 201, @response.status
assert_equal "<name>david</name>", @response.body
assert_equal "http://www.example.com/customers/13", @response.location
+ end
+ end
+ def test_using_resource_for_post_with_xml_yields_unprocessable_entity_on_failure
+ with_test_route_set do
+ @request.accept = "application/xml"
errors = { :name => :invalid }
Customer.any_instance.stubs(:errors).returns(errors)
post :using_resource
@@ -630,14 +645,18 @@ class RespondWithControllerTest < ActionController::TestCase
end
end
- def test_using_resource_for_put_with_html
+ def test_using_resource_for_put_with_html_redirects_on_success
with_test_route_set do
put :using_resource
assert_equal "text/html", @response.content_type
assert_equal 302, @response.status
assert_equal "http://www.example.com/customers/13", @response.location
assert @response.redirect?
+ end
+ end
+ def test_using_resource_for_put_with_html_rerender_on_failure
+ with_test_route_set do
errors = { :name => :invalid }
Customer.any_instance.stubs(:errors).returns(errors)
put :using_resource
@@ -648,14 +667,16 @@ class RespondWithControllerTest < ActionController::TestCase
end
end
- def test_using_resource_for_put_with_xml
+ def test_using_resource_for_put_with_xml_yields_ok_on_success
@request.accept = "application/xml"
-
put :using_resource
assert_equal "application/xml", @response.content_type
assert_equal 200, @response.status
assert_equal " ", @response.body
+ end
+ def test_using_resource_for_put_with_xml_yields_unprocessable_entity_on_failure
+ @request.accept = "application/xml"
errors = { :name => :invalid }
Customer.any_instance.stubs(:errors).returns(errors)
put :using_resource
@@ -665,7 +686,7 @@ class RespondWithControllerTest < ActionController::TestCase
assert_nil @response.location
end
- def test_using_resource_for_delete_with_html
+ def test_using_resource_for_delete_with_html_redirects_on_success
with_test_route_set do
Customer.any_instance.stubs(:destroyed?).returns(true)
delete :using_resource
@@ -675,7 +696,7 @@ class RespondWithControllerTest < ActionController::TestCase
end
end
- def test_using_resource_for_delete_with_xml
+ def test_using_resource_for_delete_with_xml_yields_ok_on_success
Customer.any_instance.stubs(:destroyed?).returns(true)
@request.accept = "application/xml"
delete :using_resource
@@ -684,6 +705,18 @@ class RespondWithControllerTest < ActionController::TestCase
assert_equal " ", @response.body
end
+ def test_using_resource_for_delete_with_html_redirects_on_failure
+ with_test_route_set do
+ errors = { :name => :invalid }
+ Customer.any_instance.stubs(:errors).returns(errors)
+ Customer.any_instance.stubs(:destroyed?).returns(false)
+ delete :using_resource
+ assert_equal "text/html", @response.content_type
+ assert_equal 302, @response.status
+ assert_equal "http://www.example.com/customers/13", @response.location
+ end
+ end
+
def test_using_resource_with_parent_for_get
@request.accept = "application/xml"
get :using_resource_with_parent
@@ -735,6 +768,16 @@ class RespondWithControllerTest < ActionController::TestCase
assert_equal "foo - #{[:html].to_s}", @controller.response_body
end
+ def test_respond_as_responder_entry_point
+ @request.accept = "text/html"
+ get :using_responder_with_respond
+ assert_equal "respond html", @response.body
+
+ @request.accept = "application/xml"
+ get :using_responder_with_respond
+ assert_equal "respond xml", @response.body
+ end
+
def test_clear_respond_to
@controller = InheritedRespondWithController.new
@request.accept = "text/html"
@@ -810,9 +853,11 @@ class RespondWithControllerTest < ActionController::TestCase
def with_test_route_set
with_routing do |set|
set.draw do |map|
- map.resources :customers
- map.resources :quiz_stores, :has_many => :customers
- map.connect ":controller/:action/:id"
+ resources :customers
+ resources :quiz_stores do
+ resources :customers
+ end
+ match ":controller/:action"
end
yield
end
diff --git a/actionpack/test/controller/redirect_test.rb b/actionpack/test/controller/redirect_test.rb
index ea278fd8f0..570ff4a41b 100644
--- a/actionpack/test/controller/redirect_test.rb
+++ b/actionpack/test/controller/redirect_test.rb
@@ -233,8 +233,8 @@ class RedirectTest < ActionController::TestCase
def test_redirect_to_record
with_routing do |set|
set.draw do |map|
- map.resources :workshops
- map.connect ':controller/:action/:id'
+ resources :workshops
+ match ':controller/:action'
end
get :redirect_to_existing_record
diff --git a/actionpack/test/controller/render_other_test.rb b/actionpack/test/controller/render_other_test.rb
index 51c3c55545..dfc4f2db8c 100644
--- a/actionpack/test/controller/render_other_test.rb
+++ b/actionpack/test/controller/render_other_test.rb
@@ -2,6 +2,11 @@ require 'abstract_unit'
require 'controller/fake_models'
require 'pathname'
+ActionController.add_renderer :simon do |says, options|
+ self.content_type = Mime::TEXT
+ self.response_body = "Simon says: #{says}"
+end
+
class RenderOtherTest < ActionController::TestCase
class TestController < ActionController::Base
protect_from_forgery
@@ -109,6 +114,10 @@ class RenderOtherTest < ActionController::TestCase
end
end
+ def render_simon_says
+ render :simon => "foo"
+ end
+
private
def default_render
if @alternate_default_render
@@ -240,4 +249,9 @@ class RenderOtherTest < ActionController::TestCase
xhr :get, :render_alternate_default
assert_equal %(Element.replace("foo", "partial html");), @response.body
end
+
+ def test_using_custom_render_option
+ get :render_simon_says
+ assert_equal "Simon says: foo", @response.body
+ end
end
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index b32325fa20..54f2739d38 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -39,35 +39,35 @@ class TestController < ActionController::Base
render :action => 'hello_world'
end
end
-
+
def conditional_hello_with_public_header
if stale?(:last_modified => Time.now.utc.beginning_of_day, :etag => [:foo, 123], :public => true)
render :action => 'hello_world'
end
end
-
+
def conditional_hello_with_public_header_and_expires_at
expires_in 1.minute
if stale?(:last_modified => Time.now.utc.beginning_of_day, :etag => [:foo, 123], :public => true)
render :action => 'hello_world'
end
end
-
+
def conditional_hello_with_expires_in
- expires_in 1.minute
+ expires_in 60.1.seconds
render :action => 'hello_world'
end
-
+
def conditional_hello_with_expires_in_with_public
expires_in 1.minute, :public => true
render :action => 'hello_world'
end
-
+
def conditional_hello_with_expires_in_with_public_with_more_keys
expires_in 1.minute, :public => true, 'max-stale' => 5.hours
render :action => 'hello_world'
end
-
+
def conditional_hello_with_expires_in_with_public_with_more_keys_old_syntax
expires_in 1.minute, :public => true, :private => nil, 'max-stale' => 5.hours
render :action => 'hello_world'
@@ -272,7 +272,7 @@ class TestController < ActionController::Base
def builder_layout_test
render :action => "hello", :layout => "layouts/builder"
end
-
+
# :move: test this in ActionView
def builder_partial_test
render :action => "hello_world_container"
@@ -1093,8 +1093,8 @@ class RenderTest < ActionController::TestCase
def test_head_with_location_object
with_routing do |set|
set.draw do |map|
- map.resources :customers
- map.connect ':controller/:action/:id'
+ resources :customers
+ match ':controller/:action'
end
get :head_with_location_object
@@ -1125,7 +1125,7 @@ class RenderTest < ActionController::TestCase
assert !@response.headers.include?('Content-Length')
assert_response :no_content
- ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE.each do |status, code|
+ Rack::Utils::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
@@ -1133,7 +1133,7 @@ class RenderTest < ActionController::TestCase
end
def test_head_with_integer_status
- ActionDispatch::StatusCodes::STATUS_CODES.each do |code, message|
+ Rack::Utils::HTTP_STATUS_CODES.each do |code, message|
get :head_with_integer_status, :status => code.to_s
assert_equal message, @response.message
end
@@ -1306,22 +1306,22 @@ class ExpiresInRenderTest < ActionController::TestCase
def setup
@request.host = "www.nextangle.com"
end
-
+
def test_expires_in_header
get :conditional_hello_with_expires_in
assert_equal "max-age=60, private", @response.headers["Cache-Control"]
end
-
+
def test_expires_in_header_with_public
get :conditional_hello_with_expires_in_with_public
assert_equal "max-age=60, public", @response.headers["Cache-Control"]
end
-
+
def test_expires_in_header_with_additional_headers
get :conditional_hello_with_expires_in_with_public_with_more_keys
assert_equal "max-age=60, public, max-stale=18000", @response.headers["Cache-Control"]
end
-
+
def test_expires_in_old_syntax
get :conditional_hello_with_expires_in_with_public_with_more_keys_old_syntax
assert_equal "max-age=60, public, max-stale=18000", @response.headers["Cache-Control"]
@@ -1425,12 +1425,12 @@ class EtagRenderTest < ActionController::TestCase
get :conditional_hello_with_bangs
assert_response :not_modified
end
-
+
def test_etag_with_public_true_should_set_header
get :conditional_hello_with_public_header
assert_equal "public", @response.headers['Cache-Control']
end
-
+
def test_etag_with_public_true_should_set_header_and_retain_other_headers
get :conditional_hello_with_public_header_and_expires_at
assert_equal "max-age=60, public", @response.headers['Cache-Control']
diff --git a/actionpack/test/controller/render_xml_test.rb b/actionpack/test/controller/render_xml_test.rb
index 68a52c3e8c..b5b0d0b9d5 100644
--- a/actionpack/test/controller/render_xml_test.rb
+++ b/actionpack/test/controller/render_xml_test.rb
@@ -61,8 +61,8 @@ class RenderXmlTest < ActionController::TestCase
def test_rendering_with_object_location_should_set_header_with_url_for
with_routing do |set|
set.draw do |map|
- map.resources :customers
- map.connect ':controller/:action/:id'
+ resources :customers
+ match ':controller/:action'
end
get :render_with_object_location
diff --git a/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb
index 04e9acf855..1a03396ae9 100644
--- a/actionpack/test/controller/resources_test.rb
+++ b/actionpack/test/controller/resources_test.rb
@@ -403,7 +403,7 @@ class ResourcesTest < ActionController::TestCase
with_restful_routing :messages do
assert_restful_routes_for :messages do |options|
assert_recognizes(options.merge(:action => "new"), :path => "/messages/new", :method => :get)
- assert_raise(ActionController::MethodNotAllowed) do
+ assert_raise(ActionController::RoutingError) do
ActionController::Routing::Routes.recognize_path("/messages/new", :method => :post)
end
end
@@ -689,11 +689,11 @@ class ResourcesTest < ActionController::TestCase
options = { :controller => controller_name.to_s }
collection_path = "/#{controller_name}"
- assert_raise(ActionController::MethodNotAllowed) do
+ assert_raise(ActionController::RoutingError) do
assert_recognizes(options.merge(:action => 'update'), :path => collection_path, :method => :put)
end
- assert_raise(ActionController::MethodNotAllowed) do
+ assert_raise(ActionController::RoutingError) do
assert_recognizes(options.merge(:action => 'destroy'), :path => collection_path, :method => :delete)
end
end
@@ -1378,7 +1378,7 @@ class ResourcesTest < ActionController::TestCase
end
def assert_not_recognizes(expected_options, path)
- assert_raise ActionController::RoutingError, ActionController::MethodNotAllowed, Assertion do
+ assert_raise ActionController::RoutingError, Assertion do
assert_recognizes(expected_options, path)
end
end
diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb
index 4eaf309c41..c15eaade58 100644
--- a/actionpack/test/controller/routing_test.rb
+++ b/actionpack/test/controller/routing_test.rb
@@ -51,30 +51,6 @@ class UriReservedCharactersRoutingTest < Test::Unit::TestCase
end
end
-class RoutingTest < Test::Unit::TestCase
- def test_normalize_unix_paths
- load_paths = %w(. config/../app/controllers config/../app//helpers script/../config/../vendor/rails/actionpack/lib vendor/rails/railties/builtin/rails_info app/models lib script/../config/../foo/bar/../../app/models .foo/../.bar foo.bar/../config)
- paths = ActionController::Routing.normalize_paths(load_paths)
- assert_equal %w(vendor/rails/railties/builtin/rails_info vendor/rails/actionpack/lib app/controllers app/helpers app/models config .bar lib .), paths
- end
-
- def test_normalize_windows_paths
- load_paths = %w(. config\\..\\app\\controllers config\\..\\app\\\\helpers script\\..\\config\\..\\vendor\\rails\\actionpack\\lib vendor\\rails\\railties\\builtin\\rails_info app\\models lib script\\..\\config\\..\\foo\\bar\\..\\..\\app\\models .foo\\..\\.bar foo.bar\\..\\config)
- paths = ActionController::Routing.normalize_paths(load_paths)
- assert_equal %w(vendor\\rails\\railties\\builtin\\rails_info vendor\\rails\\actionpack\\lib app\\controllers app\\helpers app\\models config .bar lib .), paths
- end
-
- def test_routing_helper_module
- assert_kind_of Module, ActionController::Routing::Helpers
-
- h = ActionController::Routing::Helpers
- c = Class.new
- assert ! c.ancestors.include?(h)
- ActionController::Routing::Routes.install_helpers c
- assert c.ancestors.include?(h)
- end
-end
-
class MockController
attr_accessor :routes
@@ -578,10 +554,6 @@ class LegacyRouteSetTests < Test::Unit::TestCase
end
def setup_request_method_routes_for(method)
- @request = ActionController::TestRequest.new
- @request.env["REQUEST_METHOD"] = method
- @request.request_uri = "/match"
-
rs.draw do |r|
r.connect '/match', :controller => 'books', :action => 'get', :conditions => { :method => :get }
r.connect '/match', :controller => 'books', :action => 'post', :conditions => { :method => :post }
@@ -593,8 +565,8 @@ class LegacyRouteSetTests < Test::Unit::TestCase
%w(GET POST PUT DELETE).each do |request_method|
define_method("test_request_method_recognized_with_#{request_method}") do
setup_request_method_routes_for(request_method)
- assert_nothing_raised { rs.recognize(@request) }
- assert_equal request_method.downcase, @request.path_parameters[:action]
+ params = rs.recognize_path("/match", :method => request_method)
+ assert_equal request_method.downcase, params[:action]
end
end
@@ -604,18 +576,11 @@ class LegacyRouteSetTests < Test::Unit::TestCase
r.connect '/match', :controller => 'books', :action => 'not_get_or_post'
end
- @request = ActionController::TestRequest.new
- @request.env["REQUEST_METHOD"] = 'POST'
- @request.request_uri = "/match"
- assert_nothing_raised { rs.recognize(@request) }
- assert_equal 'get_or_post', @request.path_parameters[:action]
+ params = rs.recognize_path("/match", :method => :post)
+ assert_equal 'get_or_post', params[:action]
- # have to recreate or else the RouteSet uses a cached version:
- @request = ActionController::TestRequest.new
- @request.env["REQUEST_METHOD"] = 'PUT'
- @request.request_uri = "/match"
- assert_nothing_raised { rs.recognize(@request) }
- assert_equal 'not_get_or_post', @request.path_parameters[:action]
+ params = rs.recognize_path("/match", :method => :put)
+ assert_equal 'not_get_or_post', params[:action]
end
def test_subpath_recognized
@@ -769,9 +734,7 @@ class RouteSetTest < ActiveSupport::TestCase
set.draw do |map|
map.connect '/users/index', :controller => :users, :action => :index
end
- @request = ActionController::TestRequest.new
- @request.request_uri = '/users/index'
- assert_nothing_raised { set.recognize(@request) }
+ params = set.recognize_path('/users/index', :method => :get)
assert_equal 1, set.routes.size
end
@@ -1004,55 +967,34 @@ class RouteSetTest < ActiveSupport::TestCase
end
end
- request.request_uri = "/people"
- request.env["REQUEST_METHOD"] = "GET"
- assert_nothing_raised { set.recognize(request) }
- assert_equal("index", request.path_parameters[:action])
- request.recycle!
+ params = set.recognize_path("/people", :method => :get)
+ assert_equal("index", params[:action])
- request.env["REQUEST_METHOD"] = "POST"
- assert_nothing_raised { set.recognize(request) }
- assert_equal("create", request.path_parameters[:action])
- request.recycle!
+ params = set.recognize_path("/people", :method => :post)
+ assert_equal("create", params[:action])
- request.env["REQUEST_METHOD"] = "PUT"
- assert_nothing_raised { set.recognize(request) }
- assert_equal("update", request.path_parameters[:action])
- request.recycle!
+ params = set.recognize_path("/people", :method => :put)
+ assert_equal("update", params[:action])
- assert_raise(ActionController::UnknownHttpMethod) {
- request.env["REQUEST_METHOD"] = "BACON"
- set.recognize(request)
+ assert_raise(ActionController::RoutingError) {
+ set.recognize_path("/people", :method => :bacon)
}
- request.recycle!
- request.request_uri = "/people/5"
- request.env["REQUEST_METHOD"] = "GET"
- assert_nothing_raised { set.recognize(request) }
- assert_equal("show", request.path_parameters[:action])
- assert_equal("5", request.path_parameters[:id])
- request.recycle!
+ params = set.recognize_path("/people/5", :method => :get)
+ assert_equal("show", params[:action])
+ assert_equal("5", params[:id])
- request.env["REQUEST_METHOD"] = "PUT"
- assert_nothing_raised { set.recognize(request) }
- assert_equal("update", request.path_parameters[:action])
- assert_equal("5", request.path_parameters[:id])
- request.recycle!
+ params = set.recognize_path("/people/5", :method => :put)
+ assert_equal("update", params[:action])
+ assert_equal("5", params[:id])
- request.env["REQUEST_METHOD"] = "DELETE"
- assert_nothing_raised { set.recognize(request) }
- assert_equal("destroy", request.path_parameters[:action])
- assert_equal("5", request.path_parameters[:id])
- request.recycle!
+ params = set.recognize_path("/people/5", :method => :delete)
+ assert_equal("destroy", params[:action])
+ assert_equal("5", params[:id])
- begin
- request.env["REQUEST_METHOD"] = "POST"
- set.recognize(request)
- flunk 'Should have raised MethodNotAllowed'
- rescue ActionController::MethodNotAllowed => e
- assert_equal [:get, :put, :delete], e.allowed_methods
- end
- request.recycle!
+ assert_raise(ActionController::RoutingError) {
+ set.recognize_path("/people/5", :method => :post)
+ }
end
def test_recognize_with_alias_in_conditions
@@ -1062,17 +1004,13 @@ class RouteSetTest < ActiveSupport::TestCase
map.root :people
end
- request.path = "/people"
- request.env["REQUEST_METHOD"] = "GET"
- assert_nothing_raised { set.recognize(request) }
- assert_equal("people", request.path_parameters[:controller])
- assert_equal("index", request.path_parameters[:action])
+ params = set.recognize_path("/people", :method => :get)
+ assert_equal("people", params[:controller])
+ assert_equal("index", params[:action])
- request.path = "/"
- request.env["REQUEST_METHOD"] = "GET"
- assert_nothing_raised { set.recognize(request) }
- assert_equal("people", request.path_parameters[:controller])
- assert_equal("index", request.path_parameters[:action])
+ params = set.recognize_path("/", :method => :get)
+ assert_equal("people", params[:controller])
+ assert_equal("index", params[:action])
end
def test_typo_recognition
@@ -1082,14 +1020,12 @@ class RouteSetTest < ActiveSupport::TestCase
:year => /\d{4}/, :day => /\d{1,2}/, :month => /\d{1,2}/
end
- request.path = "/articles/2005/11/05/a-very-interesting-article"
- request.env["REQUEST_METHOD"] = "GET"
- assert_nothing_raised { set.recognize(request) }
- assert_equal("permalink", request.path_parameters[:action])
- assert_equal("2005", request.path_parameters[:year])
- assert_equal("11", request.path_parameters[:month])
- assert_equal("05", request.path_parameters[:day])
- assert_equal("a-very-interesting-article", request.path_parameters[:title])
+ params = set.recognize_path("/articles/2005/11/05/a-very-interesting-article", :method => :get)
+ assert_equal("permalink", params[:action])
+ assert_equal("2005", params[:year])
+ assert_equal("11", params[:month])
+ assert_equal("05", params[:day])
+ assert_equal("a-very-interesting-article", params[:title])
end
def test_routing_traversal_does_not_load_extra_classes
@@ -1098,9 +1034,7 @@ class RouteSetTest < ActiveSupport::TestCase
map.connect '/profile', :controller => 'profile'
end
- request.path = '/profile'
-
- set.recognize(request) rescue nil
+ params = set.recognize_path("/profile") rescue nil
assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"
end
@@ -1114,24 +1048,17 @@ class RouteSetTest < ActiveSupport::TestCase
end
end
- request.request_uri = "/people/5"
- request.env["REQUEST_METHOD"] = "GET"
- assert_nothing_raised { set.recognize(request) }
- assert_equal("show", request.path_parameters[:action])
- assert_equal("5", request.path_parameters[:id])
- request.recycle!
+ params = set.recognize_path("/people/5", :method => :get)
+ assert_equal("show", params[:action])
+ assert_equal("5", params[:id])
- request.env["REQUEST_METHOD"] = "PUT"
- assert_nothing_raised { set.recognize(request) }
- assert_equal("update", request.path_parameters[:action])
- request.recycle!
+ params = set.recognize_path("/people/5", :method => :put)
+ assert_equal("update", params[:action])
- request.request_uri = "/people/5.png"
- request.env["REQUEST_METHOD"] = "GET"
- assert_nothing_raised { set.recognize(request) }
- assert_equal("show", request.path_parameters[:action])
- assert_equal("5", request.path_parameters[:id])
- assert_equal("png", request.path_parameters[:_format])
+ params = set.recognize_path("/people/5.png", :method => :get)
+ assert_equal("show", params[:action])
+ assert_equal("5", params[:id])
+ assert_equal("png", params[:_format])
end
def test_generate_with_default_action
@@ -1147,11 +1074,9 @@ class RouteSetTest < ActiveSupport::TestCase
def test_root_map
set.draw { |map| map.root :controller => "people" }
- request.path = ""
- request.env["REQUEST_METHOD"] = "GET"
- assert_nothing_raised { set.recognize(request) }
- assert_equal("people", request.path_parameters[:controller])
- assert_equal("index", request.path_parameters[:action])
+ params = set.recognize_path("", :method => :get)
+ assert_equal("people", params[:controller])
+ assert_equal("index", params[:action])
end
def test_namespace
@@ -1163,11 +1088,9 @@ class RouteSetTest < ActiveSupport::TestCase
end
- request.path = "/api/inventory"
- request.env["REQUEST_METHOD"] = "GET"
- assert_nothing_raised { set.recognize(request) }
- assert_equal("api/products", request.path_parameters[:controller])
- assert_equal("inventory", request.path_parameters[:action])
+ params = set.recognize_path("/api/inventory", :method => :get)
+ assert_equal("api/products", params[:controller])
+ assert_equal("inventory", params[:action])
end
def test_namespaced_root_map
@@ -1179,11 +1102,9 @@ class RouteSetTest < ActiveSupport::TestCase
end
- request.path = "/api"
- request.env["REQUEST_METHOD"] = "GET"
- assert_nothing_raised { set.recognize(request) }
- assert_equal("api/products", request.path_parameters[:controller])
- assert_equal("index", request.path_parameters[:action])
+ params = set.recognize_path("/api", :method => :get)
+ assert_equal("api/products", params[:controller])
+ assert_equal("index", params[:action])
end
def test_namespace_with_path_prefix
@@ -1193,11 +1114,9 @@ class RouteSetTest < ActiveSupport::TestCase
end
end
- request.path = "/prefix/inventory"
- request.env["REQUEST_METHOD"] = "GET"
- assert_nothing_raised { set.recognize(request) }
- assert_equal("api/products", request.path_parameters[:controller])
- assert_equal("inventory", request.path_parameters[:action])
+ params = set.recognize_path("/prefix/inventory", :method => :get)
+ assert_equal("api/products", params[:controller])
+ assert_equal("inventory", params[:action])
end
def test_namespace_with_blank_path_prefix
@@ -1207,11 +1126,9 @@ class RouteSetTest < ActiveSupport::TestCase
end
end
- request.path = "/inventory"
- request.env["REQUEST_METHOD"] = "GET"
- assert_nothing_raised { set.recognize(request) }
- assert_equal("api/products", request.path_parameters[:controller])
- assert_equal("inventory", request.path_parameters[:action])
+ params = set.recognize_path("/inventory", :method => :get)
+ assert_equal("api/products", params[:controller])
+ assert_equal("inventory", params[:action])
end
def test_generate_changes_controller_module
@@ -1340,11 +1257,9 @@ class RouteSetTest < ActiveSupport::TestCase
end
end
- request.path = "/projects/1/milestones"
- request.env["REQUEST_METHOD"] = "GET"
- assert_nothing_raised { set.recognize(request) }
- assert_equal("milestones", request.path_parameters[:controller])
- assert_equal("index", request.path_parameters[:action])
+ params = set.recognize_path("/projects/1/milestones", :method => :get)
+ assert_equal("milestones", params[:controller])
+ assert_equal("index", params[:action])
end
def test_setting_root_in_namespace_using_symbol
@@ -1461,15 +1376,13 @@ class RouteSetTest < ActiveSupport::TestCase
)/x}
end
- pending do
- url = set.generate({:controller => 'pages', :action => 'show', :name => 'david'})
- assert_equal "/page/david", url
- assert_raise ActionController::RoutingError do
- url = set.generate({:controller => 'pages', :action => 'show', :name => 'davidjamis'})
- end
- assert_raise ActionController::RoutingError do
- url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
- end
+ url = set.generate({:controller => 'pages', :action => 'show', :name => 'david'})
+ assert_equal "/page/david", url
+ assert_raise ActionController::RoutingError do
+ url = set.generate({:controller => 'pages', :action => 'show', :name => 'davidjamis'})
+ end
+ assert_raise ActionController::RoutingError do
+ url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
end
end
@@ -1485,10 +1398,8 @@ class RouteSetTest < ActiveSupport::TestCase
)/xi}
end
- pending do
- url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
- assert_equal "/page/JAMIS", url
- end
+ url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
+ assert_equal "/page/JAMIS", url
end
def test_route_requirement_recognize_with_xi_modifiers
@@ -1645,7 +1556,7 @@ class RouteSetTest < ActiveSupport::TestCase
end
def test_expand_array_build_query_string
- assert_uri_equal '/foo?x%5B%5D=1&x%5B%5D=2', default_route_set.generate({:controller => 'foo', :x => [1, 2]})
+ assert_uri_equal '/foo?x[]=1&x[]=2', default_route_set.generate({:controller => 'foo', :x => [1, 2]})
end
def test_escape_spaces_build_query_string_selected_keys
@@ -1663,9 +1574,7 @@ class RouteSetTest < ActiveSupport::TestCase
map.connect ':controller/:action/:id'
end
- pending do
- assert_equal '/ibocorp', set.generate({:controller => 'ibocorp', :page => 1})
- end
+ assert_equal '/ibocorp', set.generate({:controller => 'ibocorp', :page => 1})
end
def test_generate_with_optional_params_recalls_last_request
@@ -1698,9 +1607,7 @@ class RouteSetTest < ActiveSupport::TestCase
assert_equal("/blog/2006/07/25", set.generate({:day => 25}, last_request))
assert_equal("/blog/2005", set.generate({:year => 2005}, last_request))
assert_equal("/blog/show/123", set.generate({:action => "show" , :id => 123}, last_request))
- pending do
- assert_equal("/blog/2006/07/28", set.generate({:year => 2006}, last_request))
- end
+ assert_equal("/blog/2006", set.generate({:year => 2006}, last_request))
assert_equal("/blog/2006", set.generate({:year => 2006, :month => nil}, last_request))
end
@@ -1716,85 +1623,6 @@ class RouteSetTest < ActiveSupport::TestCase
end
end
-class RouteLoadingTest < Test::Unit::TestCase
- def setup
- routes.instance_variable_set '@routes_last_modified', nil
- Object.remove_const(:RAILS_ROOT) if defined?(::RAILS_ROOT)
- Object.const_set :RAILS_ROOT, '.'
- routes.add_configuration_file(File.join(RAILS_ROOT, 'config', 'routes.rb'))
-
- @stat = stub_everything
- end
-
- def teardown
- ActionController::Routing::Routes.configuration_files.clear
- Object.send :remove_const, :RAILS_ROOT
- end
-
- def test_load
- File.expects(:stat).returns(@stat)
- routes.expects(:load).with(regexp_matches(/routes\.rb$/))
-
- routes.reload
- end
-
- def test_no_reload_when_not_modified
- @stat.expects(:mtime).times(2).returns(1)
- File.expects(:stat).times(2).returns(@stat)
- routes.expects(:load).with(regexp_matches(/routes\.rb$/)).at_most_once
-
- 2.times { routes.reload }
- end
-
- def test_reload_when_modified
- @stat.expects(:mtime).at_least(2).returns(1, 2)
- File.expects(:stat).at_least(2).returns(@stat)
- routes.expects(:load).with(regexp_matches(/routes\.rb$/)).times(2)
-
- 2.times { routes.reload }
- end
-
- def test_bang_forces_reload
- @stat.expects(:mtime).at_least(2).returns(1)
- File.expects(:stat).at_least(2).returns(@stat)
- routes.expects(:load).with(regexp_matches(/routes\.rb$/)).times(2)
-
- 2.times { routes.reload! }
- end
-
- def test_adding_inflections_forces_reload
- ActiveSupport::Inflector::Inflections.instance.expects(:uncountable).with('equipment')
- routes.expects(:reload!)
-
- ActiveSupport::Inflector.inflections { |inflect| inflect.uncountable('equipment') }
- end
-
- def test_load_with_configuration
- routes.configuration_files.clear
- routes.add_configuration_file("foobarbaz")
- File.expects(:stat).returns(@stat)
- routes.expects(:load).with("foobarbaz")
-
- routes.reload
- end
-
- def test_load_multiple_configurations
- routes.add_configuration_file("engines.rb")
-
- File.expects(:stat).at_least_once.returns(@stat)
-
- routes.expects(:load).with('./config/routes.rb')
- routes.expects(:load).with('engines.rb')
-
- routes.reload
- end
-
- private
- def routes
- ActionController::Routing::Routes
- end
-end
-
class RackMountIntegrationTests < ActiveSupport::TestCase
Model = Struct.new(:to_param)
@@ -1884,11 +1712,9 @@ class RackMountIntegrationTests < ActiveSupport::TestCase
assert_equal({:controller => 'posts', :action => 'show_date', :year => '2009'}, @routes.recognize_path('/blog/2009', :method => :get))
assert_equal({:controller => 'posts', :action => 'show_date', :year => '2009', :month => '01'}, @routes.recognize_path('/blog/2009/01', :method => :get))
assert_equal({:controller => 'posts', :action => 'show_date', :year => '2009', :month => '01', :day => '01'}, @routes.recognize_path('/blog/2009/01/01', :method => :get))
- assert_raise(ActionController::ActionControllerError) { @routes.recognize_path('/blog/123456789', :method => :get) }
assert_equal({:controller => 'archive', :action => 'index', :year => '2010'}, @routes.recognize_path('/archive/2010'))
assert_equal({:controller => 'archive', :action => 'index'}, @routes.recognize_path('/archive'))
- assert_raise(ActionController::ActionControllerError) { @routes.recognize_path('/archive/january') }
assert_equal({:controller => 'people', :action => 'index'}, @routes.recognize_path('/people', :method => :get))
assert_equal({:controller => 'people', :action => 'index', :format => 'xml'}, @routes.recognize_path('/people.xml', :method => :get))
@@ -2047,9 +1873,9 @@ class RackMountIntegrationTests < ActiveSupport::TestCase
assert_equal '/posts', @routes.generate({:controller => 'posts'}, {:controller => 'posts', :action => 'index'})
assert_equal '/posts/create', @routes.generate({:action => 'create'}, {:controller => 'posts'})
assert_equal '/posts?foo=bar', @routes.generate(:controller => 'posts', :foo => 'bar')
- assert_equal '/posts?foo%5B%5D=bar&foo%5B%5D=baz', @routes.generate(:controller => 'posts', :foo => ['bar', 'baz'])
+ assert_equal '/posts?foo[]=bar&foo[]=baz', @routes.generate(:controller => 'posts', :foo => ['bar', 'baz'])
assert_equal '/posts?page=2', @routes.generate(:controller => 'posts', :page => 2)
- assert_equal '/posts?q%5Bfoo%5D%5Ba%5D=b', @routes.generate(:controller => 'posts', :q => { :foo => { :a => 'b'}})
+ assert_equal '/posts?q[foo][a]=b', @routes.generate(:controller => 'posts', :q => { :foo => { :a => 'b'}})
assert_equal '/', @routes.generate(:controller => 'news', :action => 'index')
assert_equal '/', @routes.generate(:controller => 'news', :action => 'index', :format => nil)
diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb
index 375878b755..0f074b32e6 100644
--- a/actionpack/test/controller/test_test.rb
+++ b/actionpack/test/controller/test_test.rb
@@ -456,8 +456,8 @@ XML
def test_array_path_parameter_handled_properly
with_routing do |set|
set.draw do |map|
- map.connect 'file/*path', :controller => 'test_test/test', :action => 'test_params'
- map.connect ':controller/:action/:id'
+ match 'file/*path', :to => 'test_test/test#test_params'
+ match ':controller/:action'
end
get :test_params, :path => ['hello', 'world']
@@ -563,7 +563,7 @@ XML
expected = File.read(path)
expected.force_encoding(Encoding::BINARY) if expected.respond_to?(:force_encoding)
- file = ActionController::TestUploadedFile.new(path, content_type)
+ file = Rack::Test::UploadedFile.new(path, content_type)
assert_equal filename, file.original_filename
assert_equal content_type, file.content_type
assert_equal file.path, file.local_path
@@ -580,10 +580,10 @@ XML
path = "#{FILES_DIR}/#{filename}"
content_type = 'image/png'
- binary_uploaded_file = ActionController::TestUploadedFile.new(path, content_type, :binary)
+ binary_uploaded_file = Rack::Test::UploadedFile.new(path, content_type, :binary)
assert_equal File.open(path, READ_BINARY).read, binary_uploaded_file.read
- plain_uploaded_file = ActionController::TestUploadedFile.new(path, content_type)
+ plain_uploaded_file = Rack::Test::UploadedFile.new(path, content_type)
assert_equal File.open(path, READ_PLAIN).read, plain_uploaded_file.read
end
@@ -605,7 +605,7 @@ XML
end
def test_test_uploaded_file_exception_when_file_doesnt_exist
- assert_raise(RuntimeError) { ActionController::TestUploadedFile.new('non_existent_file') }
+ assert_raise(RuntimeError) { Rack::Test::UploadedFile.new('non_existent_file') }
end
def test_redirect_url_only_cares_about_location_header
@@ -628,17 +628,6 @@ XML
assert_nothing_raised(NoMethodError) { @response.binary_content }
end
end
-
- protected
- def with_foo_routing
- with_routing do |set|
- set.draw do |map|
- map.generate_url 'foo', :controller => 'test'
- map.connect ':controller/:action/:id'
- end
- yield set
- end
- end
end
class InferringClassNameTest < ActionController::TestCase
@@ -673,7 +662,7 @@ class NamedRoutesControllerTest < ActionController::TestCase
def test_should_be_able_to_use_named_routes_before_a_request_is_done
with_routing do |set|
- set.draw { |map| map.resources :contents }
+ set.draw { |map| resources :contents }
assert_equal 'http://test.host/contents/new', new_content_url
assert_equal 'http://test.host/contents/1', content_url(:id => 1)
end
diff --git a/actionpack/test/controller/url_rewriter_test.rb b/actionpack/test/controller/url_rewriter_test.rb
index 3b14cbb2d8..428f40b9f8 100644
--- a/actionpack/test/controller/url_rewriter_test.rb
+++ b/actionpack/test/controller/url_rewriter_test.rb
@@ -247,7 +247,7 @@ class UrlWriterTests < ActionController::TestCase
with_routing do |set|
set.draw do |map|
- map.home '/home/sweet/home/:user', :controller => 'home', :action => 'index'
+ match '/home/sweet/home/:user', :to => 'home#index', :as => :home
end
kls = Class.new { include ActionController::UrlWriter }
@@ -264,7 +264,7 @@ class UrlWriterTests < ActionController::TestCase
with_routing do |set|
set.draw do |map|
match 'home/sweet/home/:user', :to => 'home#index', :as => :home
- map.connect ':controller/:action/:id'
+ match ':controller/:action/:id'
end
# We need to create a new class in order to install the new named route.
@@ -331,8 +331,8 @@ class UrlWriterTests < ActionController::TestCase
def test_named_routes_with_nil_keys
with_routing do |set|
set.draw do |map|
- map.main '', :controller => 'posts', :format => nil
- map.resources :posts
+ match 'posts.:format', :to => 'posts#index', :as => :posts
+ match '/', :to => 'posts#index', :as => :main
end
# We need to create a new class in order to install the new named route.
@@ -350,7 +350,7 @@ class UrlWriterTests < ActionController::TestCase
def test_formatted_url_methods_are_deprecated
with_routing do |set|
set.draw do |map|
- map.resources :posts
+ resources :posts
end
# We need to create a new class in order to install the new named route.
kls = Class.new { include ActionController::UrlWriter }
diff --git a/actionpack/test/controller/webservice_test.rb b/actionpack/test/controller/webservice_test.rb
index 0514c098bf..5882a8cfa3 100644
--- a/actionpack/test/controller/webservice_test.rb
+++ b/actionpack/test/controller/webservice_test.rb
@@ -255,9 +255,7 @@ class WebServiceTest < ActionController::IntegrationTest
def with_test_route_set
with_routing do |set|
set.draw do |map|
- map.with_options :controller => "web_service_test/test" do |c|
- c.connect "/", :action => "assign_parameters"
- end
+ match '/', :to => 'web_service_test/test#assign_parameters'
end
yield
end
diff --git a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb
index 301080842e..40c5ac2d09 100644
--- a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb
@@ -151,7 +151,7 @@ class MultipartParamsParsingTest < ActionController::IntegrationTest
def with_test_routing
with_routing do |set|
set.draw do |map|
- map.connect ':action', :controller => "multipart_params_parsing_test/test"
+ match ':action', :to => 'multipart_params_parsing_test/test'
end
yield
end
diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb
index 256ed06a45..02f63f7006 100644
--- a/actionpack/test/dispatch/response_test.rb
+++ b/actionpack/test/dispatch/response_test.rb
@@ -7,7 +7,6 @@ class ResponseTest < ActiveSupport::TestCase
test "simple output" do
@response.body = "Hello, World!"
- @response.prepare!
status, headers, body = @response.to_a
assert_equal 200, status
@@ -25,7 +24,6 @@ class ResponseTest < ActiveSupport::TestCase
test "utf8 output" do
@response.body = [1090, 1077, 1089, 1090].pack("U*")
- @response.prepare!
status, headers, body = @response.to_a
assert_equal 200, status
@@ -41,7 +39,6 @@ class ResponseTest < ActiveSupport::TestCase
@response.body = Proc.new do |response, output|
5.times { |n| output.write(n) }
end
- @response.prepare!
status, headers, body = @response.to_a
assert_equal 200, status
@@ -59,14 +56,12 @@ class ResponseTest < ActiveSupport::TestCase
test "content type" do
[204, 304].each do |c|
@response.status = c.to_s
- @response.prepare!
status, headers, body = @response.to_a
assert !headers.has_key?("Content-Type"), "#{c} should not have Content-Type header"
end
[200, 302, 404, 500].each do |c|
@response.status = c.to_s
- @response.prepare!
status, headers, body = @response.to_a
assert headers.has_key?("Content-Type"), "#{c} did not have Content-Type header"
end
@@ -74,7 +69,6 @@ class ResponseTest < ActiveSupport::TestCase
test "does not include Status header" do
@response.status = "200 OK"
- @response.prepare!
status, headers, body = @response.to_a
assert !headers.has_key?('Status')
end
@@ -114,15 +108,126 @@ class ResponseTest < ActiveSupport::TestCase
test "cookies" do
@response.set_cookie("user_name", :value => "david", :path => "/")
- @response.prepare!
status, headers, body = @response.to_a
assert_equal "user_name=david; path=/", headers["Set-Cookie"]
assert_equal({"user_name" => "david"}, @response.cookies)
@response.set_cookie("login", :value => "foo&bar", :path => "/", :expires => Time.utc(2005, 10, 10,5))
- @response.prepare!
status, headers, body = @response.to_a
assert_equal "user_name=david; path=/\nlogin=foo%26bar; path=/; expires=Mon, 10-Oct-2005 05:00:00 GMT", headers["Set-Cookie"]
assert_equal({"login" => "foo&bar", "user_name" => "david"}, @response.cookies)
end
+
+ test "read cache control" do
+ resp = ActionDispatch::Response.new.tap { |resp|
+ resp.cache_control[:public] = true
+ resp.etag = '123'
+ resp.body = 'Hello'
+ }
+ resp.to_a
+
+ assert_equal('"202cb962ac59075b964b07152d234b70"', resp.etag)
+ assert_equal({:public => true}, resp.cache_control)
+
+ assert_equal('public', resp.headers['Cache-Control'])
+ assert_equal('"202cb962ac59075b964b07152d234b70"', resp.headers['ETag'])
+ end
+
+ test "read charset and content type" do
+ resp = ActionDispatch::Response.new.tap { |resp|
+ resp.charset = 'utf-16'
+ resp.content_type = Mime::XML
+ resp.body = 'Hello'
+ }
+ resp.to_a
+
+ assert_equal('utf-16', resp.charset)
+ assert_equal(Mime::XML, resp.content_type)
+
+ assert_equal('application/xml; charset=utf-16', resp.headers['Content-Type'])
+ end
+end
+
+class ResponseIntegrationTest < ActionDispatch::IntegrationTest
+ def app
+ @app
+ end
+
+ test "response cache control from railsish app" do
+ @app = lambda { |env|
+ ActionDispatch::Response.new.tap { |resp|
+ resp.cache_control[:public] = true
+ resp.etag = '123'
+ resp.body = 'Hello'
+ }.to_a
+ }
+
+ get '/'
+ assert_response :success
+
+ assert_equal('public', @response.headers['Cache-Control'])
+ assert_equal('"202cb962ac59075b964b07152d234b70"', @response.headers['ETag'])
+
+ pending do
+ assert_equal('"202cb962ac59075b964b07152d234b70"', @response.etag)
+ assert_equal({:public => true}, @response.cache_control)
+ end
+ end
+
+ test "response cache control from rackish app" do
+ @app = lambda { |env|
+ [200,
+ {'ETag' => '"202cb962ac59075b964b07152d234b70"',
+ 'Cache-Control' => 'public'}, ['Hello']]
+ }
+
+ get '/'
+ assert_response :success
+
+ assert_equal('public', @response.headers['Cache-Control'])
+ assert_equal('"202cb962ac59075b964b07152d234b70"', @response.headers['ETag'])
+
+ pending do
+ assert_equal('"202cb962ac59075b964b07152d234b70"', @response.etag)
+ assert_equal({:public => true}, @response.cache_control)
+ end
+ end
+
+ test "response charset and content type from railsish app" do
+ @app = lambda { |env|
+ ActionDispatch::Response.new.tap { |resp|
+ resp.charset = 'utf-16'
+ resp.content_type = Mime::XML
+ resp.body = 'Hello'
+ }.to_a
+ }
+
+ get '/'
+ assert_response :success
+
+ pending do
+ assert_equal('utf-16', @response.charset)
+ assert_equal(Mime::XML, @response.content_type)
+ end
+
+ assert_equal('application/xml; charset=utf-16', @response.headers['Content-Type'])
+ end
+
+ test "response charset and content type from rackish app" do
+ @app = lambda { |env|
+ [200,
+ {'Content-Type' => 'application/xml; charset=utf-16'},
+ ['Hello']]
+ }
+
+ get '/'
+ assert_response :success
+
+ pending do
+ assert_equal('utf-16', @response.charset)
+ assert_equal(Mime::XML, @response.content_type)
+ end
+
+ assert_equal('application/xml; charset=utf-16', @response.headers['Content-Type'])
+ end
end
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index 496445fc34..360ffe977b 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -14,7 +14,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
stub_controllers do |routes|
Routes = routes
- Routes.draw do |map|
+ Routes.draw do
controller :sessions do
get 'login', :to => :new, :as => :login
post 'login', :to => :create
@@ -22,8 +22,12 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
delete 'logout', :to => :destroy, :as => :logout
end
+ match 'account/logout' => redirect("/logout"), :as => :logout_redirect
match 'account/login', :to => redirect("/login")
+ match 'account/modulo/:name', :to => redirect("/%{name}s")
+ match 'account/proc/:name', :to => redirect {|params| "/#{params[:name].pluralize}" }
+
match 'openid/login', :via => [:get, :post], :to => "openid#login"
controller(:global) do
@@ -34,11 +38,11 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
constraints(:ip => /192\.168\.1\.\d\d\d/) do
- get 'admin', :to => "queenbee#index"
+ get 'admin' => "queenbee#index"
end
constraints ::TestRoutingMapper::IpRestrictor do
- get 'admin/accounts', :to => "queenbee#accounts"
+ get 'admin/accounts' => "queenbee#accounts"
end
resources :projects, :controller => :project do
@@ -58,8 +62,10 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
resources :people do
- namespace ":access_token" do
- resource :avatar
+ nested do
+ namespace ":access_token" do
+ resource :avatar
+ end
end
member do
@@ -80,7 +86,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
- match 'sprockets.js', :to => ::TestRoutingMapper::SprocketsApp
+ match 'sprockets.js' => ::TestRoutingMapper::SprocketsApp
match 'people/:id/update', :to => 'people#update', :as => :update_person
match '/projects/:project_id/people/:id/update', :to => 'people#update', :as => :update_project_person
@@ -93,9 +99,9 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
controller :articles do
- scope 'articles' do
- scope ':title', :title => /[a-z]+/, :as => :with_title do
- match ':id', :to => :with_id
+ scope '/articles', :name_prefix => 'article' do
+ scope :path => '/:title', :title => /[a-z]+/, :as => :with_title do
+ match '/:id', :to => :with_id
end
end
end
@@ -103,6 +109,10 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
scope ':access_token', :constraints => { :access_token => /\w{5,5}/ } do
resources :rooms
end
+
+ match '/info' => 'projects#info', :as => 'info'
+
+ root :to => 'projects#index'
end
end
@@ -143,6 +153,34 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
+ def test_logout_redirect_without_to
+ with_test_routes do
+ assert_equal '/account/logout', logout_redirect_path
+ get '/account/logout'
+ assert_equal 301, @response.status
+ assert_equal 'http://www.example.com/logout', @response.headers['Location']
+ assert_equal 'Moved Permanently', @response.body
+ end
+ end
+
+ def test_redirect_modulo
+ with_test_routes do
+ get '/account/modulo/name'
+ assert_equal 301, @response.status
+ assert_equal 'http://www.example.com/names', @response.headers['Location']
+ assert_equal 'Moved Permanently', @response.body
+ end
+ end
+
+ def test_redirect_proc
+ with_test_routes do
+ get '/account/proc/person'
+ assert_equal 301, @response.status
+ assert_equal 'http://www.example.com/people', @response.headers['Location']
+ assert_equal 'Moved Permanently', @response.body
+ end
+ end
+
def test_openid
with_test_routes do
get '/openid/login'
@@ -194,14 +232,26 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal 'projects#index', @response.body
assert_equal '/projects', projects_path
+ get '/projects.xml'
+ assert_equal 'projects#index', @response.body
+ assert_equal '/projects.xml', projects_path(:format => 'xml')
+
get '/projects/new'
assert_equal 'projects#new', @response.body
assert_equal '/projects/new', new_project_path
+ get '/projects/new.xml'
+ assert_equal 'projects#new', @response.body
+ assert_equal '/projects/new.xml', new_project_path(:format => 'xml')
+
get '/projects/1'
assert_equal 'projects#show', @response.body
assert_equal '/projects/1', project_path(:id => '1')
+ get '/projects/1.xml'
+ assert_equal 'projects#show', @response.body
+ assert_equal '/projects/1.xml', project_path(:id => '1', :format => 'xml')
+
get '/projects/1/edit'
assert_equal 'projects#edit', @response.body
assert_equal '/projects/1/edit', edit_project_path(:id => '1')
@@ -214,9 +264,23 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal 'involvements#index', @response.body
assert_equal '/projects/1/involvements', project_involvements_path(:project_id => '1')
+ get '/projects/1/involvements/new'
+ assert_equal 'involvements#new', @response.body
+ assert_equal '/projects/1/involvements/new', new_project_involvement_path(:project_id => '1')
+
get '/projects/1/involvements/1'
assert_equal 'involvements#show', @response.body
assert_equal '/projects/1/involvements/1', project_involvement_path(:project_id => '1', :id => '1')
+
+ put '/projects/1/involvements/1'
+ assert_equal 'involvements#update', @response.body
+
+ delete '/projects/1/involvements/1'
+ assert_equal 'involvements#destroy', @response.body
+
+ get '/projects/1/involvements/1/edit'
+ assert_equal 'involvements#edit', @response.body
+ assert_equal '/projects/1/involvements/1/edit', edit_project_involvement_path(:project_id => '1', :id => '1')
end
end
@@ -236,10 +300,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
put '/projects/1/participants/update_all'
assert_equal 'participants#update_all', @response.body
-
- pending do
- assert_equal '/projects/1/participants/update_all', update_all_project_participants_path(:project_id => '1')
- end
+ assert_equal '/projects/1/participants/update_all', update_all_project_participants_path(:project_id => '1')
end
end
@@ -251,15 +312,11 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get '/projects/1/companies/1/people'
assert_equal 'people#index', @response.body
- pending do
- assert_equal '/projects/1/companies/1/people', project_company_people_path(:project_id => '1', :company_id => '1')
- end
+ assert_equal '/projects/1/companies/1/people', project_company_people_path(:project_id => '1', :company_id => '1')
get '/projects/1/companies/1/avatar'
assert_equal 'avatars#show', @response.body
- pending do
- assert_equal '/projects/1/companies/1/avatar', project_company_avatar_path(:project_id => '1', :company_id => '1')
- end
+ assert_equal '/projects/1/companies/1/avatar', project_company_avatar_path(:project_id => '1', :company_id => '1')
end
end
@@ -271,9 +328,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
post '/projects/1/images/1/revise'
assert_equal 'images#revise', @response.body
- pending do
- assert_equal '/projects/1/images/1/revise', revise_project_image_path(:project_id => '1', :id => '1')
- end
+ assert_equal '/projects/1/images/1/revise', revise_project_image_path(:project_id => '1', :id => '1')
end
end
@@ -289,27 +344,19 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get '/projects/1/people/1/7a2dec8/avatar'
assert_equal 'avatars#show', @response.body
- pending do
- assert_equal '/projects/1/people/1/7a2dec8/avatar', project_person_avatar_path(:project_id => '1', :person_id => '1', :access_token => '7a2dec8')
- end
+ assert_equal '/projects/1/people/1/7a2dec8/avatar', project_person_avatar_path(:project_id => '1', :person_id => '1', :access_token => '7a2dec8')
put '/projects/1/people/1/accessible_projects'
assert_equal 'people#accessible_projects', @response.body
- pending do
- assert_equal '/projects/1/people/1/accessible_projects', accessible_projects_project_person_path(:project_id => '1', :id => '1')
- end
+ assert_equal '/projects/1/people/1/accessible_projects', accessible_projects_project_person_path(:project_id => '1', :id => '1')
post '/projects/1/people/1/resend'
assert_equal 'people#resend', @response.body
- pending do
- assert_equal '/projects/1/people/1/resend', resend_project_person_path(:project_id => '1', :id => '1')
- end
+ assert_equal '/projects/1/people/1/resend', resend_project_person_path(:project_id => '1', :id => '1')
post '/projects/1/people/1/generate_new_password'
assert_equal 'people#generate_new_password', @response.body
- pending do
- assert_equal '/projects/1/people/1/generate_new_password', generate_new_password_project_person_path(:project_id => '1', :id => '1')
- end
+ assert_equal '/projects/1/people/1/generate_new_password', generate_new_password_project_person_path(:project_id => '1', :id => '1')
end
end
@@ -321,39 +368,27 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get '/projects/1/posts/archive'
assert_equal 'posts#archive', @response.body
- pending do
- assert_equal '/projects/1/posts/archive', archive_project_posts_path(:project_id => '1')
- end
+ assert_equal '/projects/1/posts/archive', archive_project_posts_path(:project_id => '1')
get '/projects/1/posts/toggle_view'
assert_equal 'posts#toggle_view', @response.body
- pending do
- assert_equal '/projects/1/posts/toggle_view', toggle_view_project_posts_path(:project_id => '1')
- end
+ assert_equal '/projects/1/posts/toggle_view', toggle_view_project_posts_path(:project_id => '1')
post '/projects/1/posts/1/preview'
assert_equal 'posts#preview', @response.body
- pending do
- assert_equal '/projects/1/posts/1/preview', preview_project_post_path(:project_id => '1', :id => '1')
- end
+ assert_equal '/projects/1/posts/1/preview', preview_project_post_path(:project_id => '1', :id => '1')
get '/projects/1/posts/1/subscription'
assert_equal 'subscriptions#show', @response.body
- pending do
- assert_equal '/projects/1/posts/1/subscription', project_post_subscription_path(:project_id => '1', :post_id => '1')
- end
+ assert_equal '/projects/1/posts/1/subscription', project_post_subscription_path(:project_id => '1', :post_id => '1')
get '/projects/1/posts/1/comments'
assert_equal 'comments#index', @response.body
- pending do
- assert_equal '/projects/1/posts/1/comments', project_post_comments_path(:project_id => '1', :post_id => '1')
- end
+ assert_equal '/projects/1/posts/1/comments', project_post_comments_path(:project_id => '1', :post_id => '1')
post '/projects/1/posts/1/comments/preview'
assert_equal 'comments#preview', @response.body
- pending do
- assert_equal '/projects/1/posts/1/comments/preview', preview_project_post_comments_path(:project_id => '1', :post_id => '1')
- end
+ assert_equal '/projects/1/posts/1/comments/preview', preview_project_post_comments_path(:project_id => '1', :post_id => '1')
end
end
@@ -411,7 +446,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_raise(ActionController::RoutingError) { get '/articles/123/1' }
- assert_equal '/articles/rails/1', with_title_path(:title => 'rails', :id => 1)
+ assert_equal '/articles/rails/1', article_with_title_path(:title => 'rails', :id => 1)
end
end
@@ -428,6 +463,30 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
+ def test_root
+ with_test_routes do
+ assert_equal '/', root_path
+ get '/'
+ assert_equal 'projects#index', @response.body
+ end
+ end
+
+ def test_index
+ with_test_routes do
+ assert_equal '/info', info_path
+ get '/info'
+ assert_equal 'projects#info', @response.body
+ end
+ end
+
+ def test_index
+ with_test_routes do
+ assert_equal '/info', info_path
+ get '/info'
+ assert_equal 'projects#info', @response.body
+ end
+ end
+
private
def with_test_routes
real_routes, temp_routes = ActionController::Routing::Routes, Routes
diff --git a/actionpack/test/dispatch/test_request_test.rb b/actionpack/test/dispatch/test_request_test.rb
index 5da02b2ea6..e42ade73d1 100644
--- a/actionpack/test/dispatch/test_request_test.rb
+++ b/actionpack/test/dispatch/test_request_test.rb
@@ -18,7 +18,7 @@ class TestRequestTest < ActiveSupport::TestCase
assert_equal "0.0.0.0", env.delete("REMOTE_ADDR")
assert_equal "Rails Testing", env.delete("HTTP_USER_AGENT")
- assert_equal [1, 0], env.delete("rack.version")
+ assert_equal [1, 1], env.delete("rack.version")
assert_equal "", env.delete("rack.input").string
assert_kind_of StringIO, env.delete("rack.errors")
assert_equal true, env.delete("rack.multithread")
diff --git a/actionpack/test/lib/controller/fake_controllers.rb b/actionpack/test/lib/controller/fake_controllers.rb
index 250327e6dc..09692f77b5 100644
--- a/actionpack/test/lib/controller/fake_controllers.rb
+++ b/actionpack/test/lib/controller/fake_controllers.rb
@@ -1,37 +1,48 @@
class << Object; alias_method :const_available?, :const_defined?; end
class ContentController < ActionController::Base; end
-class NotAController; end
module Admin
class << self; alias_method :const_available?, :const_defined?; end
+ class AccountsController < ActionController::Base; end
class NewsFeedController < ActionController::Base; end
class PostsController < ActionController::Base; end
class StuffController < ActionController::Base; end
class UserController < ActionController::Base; end
+ class UsersController < ActionController::Base; end
end
module Api
+ class UsersController < ActionController::Base; end
class ProductsController < ActionController::Base; end
end
# TODO: Reduce the number of test controllers we use
+class AccountController < ActionController::Base; end
class AddressesController < ActionController::Base; end
+class ArchiveController < ActionController::Base; end
class ArticlesController < ActionController::Base; end
class BarController < ActionController::Base; end
+class BlogController < ActionController::Base; end
class BooksController < ActionController::Base; end
class BraveController < ActionController::Base; end
+class CarsController < ActionController::Base; end
+class CcController < ActionController::Base; end
class CController < ActionController::Base; end
class ElsewhereController < ActionController::Base; end
class FooController < ActionController::Base; end
+class GeocodeController < ActionController::Base; end
class HiController < ActionController::Base; end
class ImageController < ActionController::Base; end
+class NewsController < ActionController::Base; end
class NotesController < ActionController::Base; end
class PeopleController < ActionController::Base; end
class PostsController < ActionController::Base; end
class SessionsController < ActionController::Base; end
class StuffController < ActionController::Base; end
class SubpathBooksController < ActionController::Base; end
+class SymbolsController < ActionController::Base; end
+class UserController < ActionController::Base; end
class WeblogController < ActionController::Base; end
# For speed test
diff --git a/actionpack/test/template/ajax_test.rb b/actionpack/test/template/ajax_test.rb
index 670ba92697..aeb7c09b09 100644
--- a/actionpack/test/template/ajax_test.rb
+++ b/actionpack/test/template/ajax_test.rb
@@ -6,7 +6,7 @@ class AjaxTestCase < ActiveSupport::TestCase
def assert_html(html, matches)
matches.each do |match|
- assert_match Regexp.new(Regexp.escape(match)), html
+ assert_match(Regexp.new(Regexp.escape(match)), html)
end
end
@@ -52,18 +52,18 @@ class LinkToRemoteTest < AjaxTestCase
test "with a hash for :update" do
link = link(:update => {:success => "#posts", :failure => "#error"})
- assert_match /data-update-success="#posts"/, link
- assert_match /data-update-failure="#error"/, link
+ assert_match(/data-update-success="#posts"/, link)
+ assert_match(/data-update-failure="#error"/, link)
end
test "with positional parameters" do
link = link(:position => :top, :update => "#posts")
- assert_match /data\-update\-position="top"/, link
+ assert_match(/data\-update\-position="top"/, link)
end
test "with an optional method" do
link = link(:method => "delete")
- assert_match /data-method="delete"/, link
+ assert_match(/data-method="delete"/, link)
end
class LegacyLinkToRemoteTest < AjaxTestCase
@@ -99,7 +99,7 @@ class ButtonToRemoteTest < AjaxTestCase
button = button({:url => {:action => "whatnot"}}, {:class => "fine"})
[/input/, /class="fine"/, /type="button"/, /value="Remote outpost"/,
/data-url="\/whatnot"/].each do |match|
- assert_match match, button
+ assert_match(match, button)
end
end
end
diff --git a/actionpack/test/template/atom_feed_helper_test.rb b/actionpack/test/template/atom_feed_helper_test.rb
index 6a5fb0acff..347cb98303 100644
--- a/actionpack/test/template/atom_feed_helper_test.rb
+++ b/actionpack/test/template/atom_feed_helper_test.rb
@@ -187,10 +187,9 @@ class ScrollsController < ActionController::Base
end
protected
-
- def rescue_action(e)
- raise(e)
- end
+ def rescue_action(e)
+ raise(e)
+ end
end
class AtomFeedTest < ActionController::TestCase
@@ -311,11 +310,12 @@ class AtomFeedTest < ActionController::TestCase
assert_select "summary div p", :text => "after 2"
end
end
-private
+
+ private
def with_restful_routing(resources)
with_routing do |set|
set.draw do |map|
- map.resources(resources)
+ resources(resources)
end
yield
end
diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb
index 35c51ca7ea..fdf3db1cdb 100644
--- a/actionpack/test/template/render_test.rb
+++ b/actionpack/test/template/render_test.rb
@@ -106,8 +106,8 @@ module RenderTestCases
def test_render_partial_with_errors
@view.render(:partial => "test/raise")
- flunk "Render did not raise TemplateError"
- rescue ActionView::TemplateError => e
+ flunk "Render did not raise Template::Error"
+ rescue ActionView::Template::Error => e
assert_match "undefined local variable or method `doesnt_exist'", e.message
assert_equal "", e.sub_template_message
assert_equal "1", e.line_number
@@ -116,8 +116,8 @@ module RenderTestCases
def test_render_sub_template_with_errors
@view.render(:file => "test/sub_template_raise")
- flunk "Render did not raise TemplateError"
- rescue ActionView::TemplateError => e
+ flunk "Render did not raise Template::Error"
+ rescue ActionView::Template::Error => e
assert_match "undefined local variable or method `doesnt_exist'", e.message
assert_equal "Trace of template inclusion: #{File.expand_path("#{FIXTURE_LOAD_PATH}/test/sub_template_raise.html.erb")}", e.sub_template_message
assert_equal "1", e.line_number
diff --git a/actionpack/test/template/test_case_test.rb b/actionpack/test/template/test_case_test.rb
index 05a409d05a..9a448ce328 100644
--- a/actionpack/test/template/test_case_test.rb
+++ b/actionpack/test/template/test_case_test.rb
@@ -114,7 +114,7 @@ module ActionView
test "is able to use named routes" do
with_routing do |set|
- set.draw { |map| map.resources :contents }
+ set.draw { |map| resources :contents }
assert_equal 'http://test.host/contents/new', new_content_url
assert_equal 'http://test.host/contents/1', content_url(:id => 1)
end
@@ -122,7 +122,7 @@ module ActionView
test "named routes can be used from helper included in view" do
with_routing do |set|
- set.draw { |map| map.resources :contents }
+ set.draw { |map| resources :contents }
_helpers.module_eval do
def render_from_helper
new_content_url
diff --git a/actionpack/test/template/translation_helper_test.rb b/actionpack/test/template/translation_helper_test.rb
index a20f3c394c..d67d2c7911 100644
--- a/actionpack/test/template/translation_helper_test.rb
+++ b/actionpack/test/template/translation_helper_test.rb
@@ -9,7 +9,7 @@ class TranslationHelperTest < Test::Unit::TestCase
end
def test_delegates_to_i18n_setting_the_raise_option
- I18n.expects(:translate).with(:foo, :locale => 'en', :raise => true)
+ I18n.expects(:translate).with(:foo, :locale => 'en', :raise => true).returns("")
translate :foo, :locale => 'en'
end
@@ -26,7 +26,7 @@ class TranslationHelperTest < Test::Unit::TestCase
def test_scoping_by_partial
expects(:template).returns(stub(:path_without_format_and_extension => "people/index"))
- I18n.expects(:translate).with("people.index.foo", :locale => 'en', :raise => true)
+ I18n.expects(:translate).with("people.index.foo", :locale => 'en', :raise => true).returns("")
translate ".foo", :locale => 'en'
end
end
diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb
index bf0b4ad3a7..d4b58efe1e 100644
--- a/actionpack/test/template/url_helper_test.rb
+++ b/actionpack/test/template/url_helper_test.rb
@@ -391,54 +391,47 @@ class UrlHelperTest < ActionView::TestCase
end
end
-class UrlHelperController < ActionController::Base
- def self.controller_path; 'url_helper_with_controller' end
+class UrlHelperControllerTest < ActionController::TestCase
+ class UrlHelperController < ActionController::Base
+ def show_url_for
+ render :inline => "<%= url_for :controller => 'url_helper_controller_test/url_helper', :action => 'show_url_for' %>"
+ end
- def show_url_for
- render :inline => "<%= url_for :controller => 'url_helper_with_controller', :action => 'show_url_for' %>"
- end
+ def show_named_route
+ render :inline => "<%= show_named_route_#{params[:kind]} %>"
+ end
- def show_named_route
- render :inline => "<%= show_named_route_#{params[:kind]} %>"
- end
+ def nil_url_for
+ render :inline => '<%= url_for(nil) %>'
+ end
- def nil_url_for
- render :inline => '<%= url_for(nil) %>'
+ def rescue_action(e) raise e end
end
- def rescue_action(e) raise e end
-end
-
-class UrlHelperWithControllerTest < ActionController::TestCase
- def setup
- super
- @request = ActionController::TestRequest.new
- @response = ActionController::TestResponse.new
- @controller = UrlHelperController.new
- end
+ tests UrlHelperController
def test_url_for_shows_only_path
get :show_url_for
- assert_equal '/url_helper_with_controller/show_url_for', @response.body
+ assert_equal '/url_helper_controller_test/url_helper/show_url_for', @response.body
end
def test_named_route_url_shows_host_and_path
with_url_helper_routing do
get :show_named_route, :kind => 'url'
- assert_equal 'http://test.host/url_helper_with_controller/show_named_route', @response.body
+ assert_equal 'http://test.host/url_helper_controller_test/url_helper/show_named_route', @response.body
end
end
def test_named_route_path_shows_only_path
with_url_helper_routing do
get :show_named_route, :kind => 'path'
- assert_equal '/url_helper_with_controller/show_named_route', @response.body
+ assert_equal '/url_helper_controller_test/url_helper/show_named_route', @response.body
end
end
def test_url_for_nil_returns_current_path
get :nil_url_for
- assert_equal '/url_helper/nil_url_for', @response.body
+ assert_equal '/url_helper_controller_test/url_helper/nil_url_for', @response.body
end
def test_named_route_should_show_host_and_path_using_controller_default_url_options
@@ -450,7 +443,7 @@ class UrlHelperWithControllerTest < ActionController::TestCase
with_url_helper_routing do
get :show_named_route, :kind => 'url'
- assert_equal 'http://testtwo.host/url_helper_with_controller/show_named_route', @response.body
+ assert_equal 'http://testtwo.host/url_helper_controller_test/url_helper/show_named_route', @response.body
end
end
@@ -458,7 +451,7 @@ class UrlHelperWithControllerTest < ActionController::TestCase
def with_url_helper_routing
with_routing do |set|
set.draw do |map|
- map.show_named_route 'url_helper_with_controller/show_named_route', :controller => 'url_helper', :action => 'show_named_route'
+ match 'url_helper_controller_test/url_helper/show_named_route', :to => 'url_helper_controller_test/url_helper#show_named_route', :as => :show_named_route
end
yield
end
@@ -512,7 +505,7 @@ class LinkToUnlessCurrentWithControllerTest < ActionController::TestCase
def with_restful_routing
with_routing do |set|
set.draw do |map|
- map.resources :tasks
+ resources :tasks
end
yield
end
@@ -632,8 +625,8 @@ class PolymorphicControllerTest < ActionController::TestCase
def with_restful_routing
with_routing do |set|
set.draw do |map|
- map.resources :workshops do |w|
- w.resources :sessions
+ resources :workshops do
+ resources :sessions
end
end
yield
diff --git a/activemodel/Rakefile b/activemodel/Rakefile
index 1f4a8466c9..f098ce0671 100755
--- a/activemodel/Rakefile
+++ b/activemodel/Rakefile
@@ -15,7 +15,6 @@ task :default => :test
Rake::TestTask.new do |t|
t.libs << "#{dir}/test"
t.test_files = Dir.glob("#{dir}/test/cases/**/*_test.rb").sort
- t.verbose = true
t.warning = true
end
diff --git a/activemodel/lib/active_model.rb b/activemodel/lib/active_model.rb
index 505e16c195..e0de27b96d 100644
--- a/activemodel/lib/active_model.rb
+++ b/activemodel/lib/active_model.rb
@@ -21,33 +21,37 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
-activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
-$:.unshift(activesupport_path) if File.directory?(activesupport_path)
+activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
+$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
require 'active_support'
+
module ActiveModel
- autoload :AttributeMethods, 'active_model/attribute_methods'
- autoload :Conversion, 'active_model/conversion'
- autoload :DeprecatedErrorMethods, 'active_model/deprecated_error_methods'
- autoload :Dirty, 'active_model/dirty'
- autoload :Errors, 'active_model/errors'
- autoload :Lint, 'active_model/lint'
- autoload :Name, 'active_model/naming'
- autoload :Naming, 'active_model/naming'
- autoload :Observer, 'active_model/observing'
- autoload :Observing, 'active_model/observing'
- autoload :Serialization, 'active_model/serialization'
- autoload :StateMachine, 'active_model/state_machine'
- autoload :TestCase, 'active_model/test_case'
- autoload :Translation, 'active_model/translation'
- autoload :Validations, 'active_model/validations'
- autoload :ValidationsRepairHelper, 'active_model/validations_repair_helper'
- autoload :Validator, 'active_model/validator'
- autoload :VERSION, 'active_model/version'
+ extend ActiveSupport::Autoload
+
+ autoload :AttributeMethods
+ autoload :Conversion
+ autoload :DeprecatedErrorMethods
+ autoload :Dirty
+ autoload :Errors
+ autoload :Lint
+ autoload :Name, 'active_model/naming'
+ autoload :Naming
+ autoload :Observer, 'active_model/observing'
+ autoload :Observing
+ autoload :Serialization
+ autoload :StateMachine
+ autoload :Translation
+ autoload :Validations
+ autoload :ValidationsRepairHelper
+ autoload :Validator
+ autoload :VERSION
module Serializers
- autoload :JSON, 'active_model/serializers/json'
- autoload :Xml, 'active_model/serializers/xml'
+ extend ActiveSupport::Autoload
+
+ autoload :JSON
+ autoload :Xml
end
end
diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb
index 977a101277..8f855958c6 100644
--- a/activemodel/lib/active_model/attribute_methods.rb
+++ b/activemodel/lib/active_model/attribute_methods.rb
@@ -235,6 +235,10 @@ module ActiveModel
# It's also possible to instantiate related objects, so a Client class belonging to the clients
# table with a +master_id+ foreign key can instantiate master through Client#master.
def method_missing(method_id, *args, &block)
+ if method_id == :to_ary || method_id == :to_str
+ raise NoMethodError, "undefined method `#{method_id}' for #{inspect}:#{self.class}"
+ end
+
method_name = method_id.to_s
if match = match_attribute_method?(method_name)
guard_private_attribute_method!(method_name, args)
diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb
index 064ec98f3a..a0d64507f9 100644
--- a/activemodel/lib/active_model/validations.rb
+++ b/activemodel/lib/active_model/validations.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/array/extract_options'
require 'active_support/core_ext/hash/keys'
+require 'active_model/errors'
module ActiveModel
module Validations
diff --git a/activemodel/test/cases/helper.rb b/activemodel/test/cases/helper.rb
index c1a3f6a4a7..30193956ea 100644
--- a/activemodel/test/cases/helper.rb
+++ b/activemodel/test/cases/helper.rb
@@ -1,15 +1,14 @@
-root = File.expand_path('../../../..', __FILE__)
begin
- require "#{root}/vendor/gems/environment"
+ require File.expand_path('../../../../vendor/gems/environment', __FILE__)
rescue LoadError
- $:.unshift("#{root}/activesupport/lib")
end
-lib = File.expand_path("#{File.dirname(__FILE__)}/../../lib")
+lib = File.expand_path('../../../lib', __FILE__)
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
require 'config'
require 'active_model'
+require 'active_model/test_case'
# Show backtraces for deprecated behavior for quicker cleanup.
ActiveSupport::Deprecation.debug = true
diff --git a/activemodel/test/cases/tests_database.rb b/activemodel/test/cases/tests_database.rb
index 8dd00ea147..79668dd941 100644
--- a/activemodel/test/cases/tests_database.rb
+++ b/activemodel/test/cases/tests_database.rb
@@ -2,6 +2,7 @@ require 'logger'
$:.unshift(File.dirname(__FILE__) + '/../../../activerecord/lib')
require 'active_record'
+require 'active_record/test_case'
require 'active_record/fixtures'
module ActiveModel
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index d8bfb1916d..a2c5528860 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,5 +1,65 @@
*Edge*
+* Add find(ids) to relations. [Pratik Naik]
+
+ old_users = User.order("age DESC")
+ old_users.find(1)
+ old_users.find(1, 2, 3)
+
+* Add new finder methods to association collection. [Pratik Naik]
+
+ class User < ActiveRecord::Base
+ has_many :items
+ end
+
+ user = User.first
+ user.items.where(:items => {:colour => 'red'})
+ user.items.select('items.id')
+
+* Add relation.reload to force reloading the records. [Pratik Naik]
+
+ topics = Topic.scoped
+ topics.to_a # force load
+ topics.first # returns a cached record
+ topics.reload
+ topics.first # Fetches a new record from the database
+
+* Rename Model.conditions and relation.conditions to .where. [Pratik Naik]
+
+ Before :
+ User.conditions(:name => 'lifo')
+ User.select('id').conditions(["age > ?", 21])
+
+ Now :
+ User.where(:name => 'lifo')
+ User.select('id').where(["age > ?", 21])
+
+* Add Model.select/group/order/limit/joins/conditions/preload/eager_load class methods returning a lazy relation. [Pratik Naik]
+
+ Examples :
+
+ posts = Post.select('id).order('name') # Returns a lazy relation
+ posts.each {|p| puts p.id } # Fires "select id from posts order by name"
+
+* Model.scoped now returns a relation if invoked without any arguments. [Pratik Naik]
+
+ Example :
+
+ posts = Post.scoped
+ posts.size # Fires "select count(*) from posts" and returns the count
+ posts.each {|p| puts p.name } # Fires "select * from posts" and loads post objects
+
+* Association inverses for belongs_to, has_one, and has_many. Optimization to reduce database queries. #3533 [Murray Steele]
+
+ # post.comments sets each comment's post without needing to :include
+ class Post < ActiveRecord::Base
+ has_many :comments, :inverse_of => :post
+ end
+
+* MySQL: add_ and change_column support positioning. #3286 [Ben Marini]
+
+* Reset your Active Record counter caches with the reset_counter_cache class method. #1211 [Mike Breen, Gabe da Silveira]
+
* Remove support for SQLite 2. Please upgrade to SQLite 3+ or install the plugin from git://github.com/rails/sqlite2_adapter.git [Pratik Naik]
* PostgreSQL: XML datatype support. #1874 [Leonardo Borges]
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb
index 8195e78826..196b87c0ac 100644
--- a/activerecord/lib/active_record.rb
+++ b/activerecord/lib/active_record.rb
@@ -21,89 +21,108 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
-activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
-$:.unshift(activesupport_path) if File.directory?(activesupport_path)
-activemodel_path = "#{File.dirname(__FILE__)}/../../activemodel/lib"
-$:.unshift(activemodel_path) if File.directory?(activemodel_path)
+activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
+$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
+
+activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__)
+$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path)
require 'active_support'
require 'active_model'
require 'arel'
module ActiveRecord
- # TODO: Review explicit loads to see if they will automatically be handled by the initializer.
- def self.load_all!
- [Base, DynamicFinderMatch, ConnectionAdapters::AbstractAdapter]
- end
+ extend ActiveSupport::Autoload
+
+ eager_autoload do
+ autoload :VERSION
- autoload :VERSION, 'active_record/version'
-
- autoload :ActiveRecordError, 'active_record/base'
- autoload :ConnectionNotEstablished, 'active_record/base'
-
- autoload :Aggregations, 'active_record/aggregations'
- autoload :AssociationPreload, 'active_record/association_preload'
- autoload :Associations, 'active_record/associations'
- autoload :AttributeMethods, 'active_record/attribute_methods'
- autoload :Attributes, 'active_record/attributes'
- autoload :AutosaveAssociation, 'active_record/autosave_association'
- autoload :Relation, 'active_record/relation'
- autoload :Base, 'active_record/base'
- autoload :Batches, 'active_record/batches'
- autoload :Calculations, 'active_record/calculations'
- autoload :Callbacks, 'active_record/callbacks'
- autoload :DynamicFinderMatch, 'active_record/dynamic_finder_match'
- autoload :DynamicScopeMatch, 'active_record/dynamic_scope_match'
- autoload :Migration, 'active_record/migration'
- autoload :Migrator, 'active_record/migration'
- autoload :NamedScope, 'active_record/named_scope'
- autoload :NestedAttributes, 'active_record/nested_attributes'
- autoload :Observer, 'active_record/observer'
- autoload :QueryCache, 'active_record/query_cache'
- autoload :Reflection, 'active_record/reflection'
- autoload :Schema, 'active_record/schema'
- autoload :SchemaDumper, 'active_record/schema_dumper'
- autoload :Serialization, 'active_record/serialization'
- autoload :SessionStore, 'active_record/session_store'
- autoload :StateMachine, 'active_record/state_machine'
- autoload :TestCase, 'active_record/test_case'
- autoload :Timestamp, 'active_record/timestamp'
- autoload :Transactions, 'active_record/transactions'
- autoload :Types, 'active_record/types'
- autoload :Validations, 'active_record/validations'
+ autoload :ActiveRecordError, 'active_record/base'
+ autoload :ConnectionNotEstablished, 'active_record/base'
+
+ autoload :Aggregations
+ autoload :AssociationPreload
+ autoload :Associations
+ autoload :AttributeMethods
+ autoload :Attributes
+ autoload :AutosaveAssociation
+ autoload :Relation
+ autoload :Base
+ autoload :Batches
+ autoload :Calculations
+ autoload :Callbacks
+ autoload :DynamicFinderMatch
+ autoload :DynamicScopeMatch
+ autoload :Migration
+ autoload :Migrator, 'active_record/migration'
+ autoload :NamedScope
+ autoload :NestedAttributes
+ autoload :Observer
+ autoload :QueryCache
+ autoload :Reflection
+ autoload :Schema
+ autoload :SchemaDumper
+ autoload :Serialization
+ autoload :SessionStore
+ autoload :StateMachine
+ autoload :Timestamp
+ autoload :Transactions
+ autoload :Types
+ autoload :Validations
+ end
module AttributeMethods
- autoload :BeforeTypeCast, 'active_record/attribute_methods/before_type_cast'
- autoload :Dirty, 'active_record/attribute_methods/dirty'
- autoload :PrimaryKey, 'active_record/attribute_methods/primary_key'
- autoload :Query, 'active_record/attribute_methods/query'
- autoload :Read, 'active_record/attribute_methods/read'
- autoload :TimeZoneConversion, 'active_record/attribute_methods/time_zone_conversion'
- autoload :Write, 'active_record/attribute_methods/write'
+ extend ActiveSupport::Autoload
+
+ eager_autoload do
+ autoload :BeforeTypeCast
+ autoload :Dirty
+ autoload :PrimaryKey
+ autoload :Query
+ autoload :Read
+ autoload :TimeZoneConversion
+ autoload :Write
+ end
end
module Attributes
- autoload :Aliasing, 'active_record/attributes/aliasing'
- autoload :Store, 'active_record/attributes/store'
- autoload :Typecasting, 'active_record/attributes/typecasting'
+ extend ActiveSupport::Autoload
+
+ eager_autoload do
+ autoload :Aliasing
+ autoload :Store
+ autoload :Typecasting
+ end
end
module Type
- autoload :Number, 'active_record/types/number'
- autoload :Object, 'active_record/types/object'
- autoload :Serialize, 'active_record/types/serialize'
- autoload :TimeWithZone, 'active_record/types/time_with_zone'
- autoload :Unknown, 'active_record/types/unknown'
+ extend ActiveSupport::Autoload
+
+ eager_autoload do
+ autoload :Number, 'active_record/types/number'
+ autoload :Object, 'active_record/types/object'
+ autoload :Serialize, 'active_record/types/serialize'
+ autoload :TimeWithZone, 'active_record/types/time_with_zone'
+ autoload :Unknown, 'active_record/types/unknown'
+ end
end
module Locking
- autoload :Optimistic, 'active_record/locking/optimistic'
- autoload :Pessimistic, 'active_record/locking/pessimistic'
+ extend ActiveSupport::Autoload
+
+ eager_autoload do
+ autoload :Optimistic
+ autoload :Pessimistic
+ end
end
module ConnectionAdapters
- autoload :AbstractAdapter, 'active_record/connection_adapters/abstract_adapter'
+ extend ActiveSupport::Autoload
+
+ eager_autoload do
+ autoload :AbstractAdapter
+ end
end
end
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 0fcd288fc5..2735bc5141 100755
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1325,7 +1325,7 @@ module ActiveRecord
if association.nil? || force_reload
association = association_proxy_class.new(self, reflection)
- retval = association.reload
+ retval = force_reload ? reflection.klass.uncached { association.reload } : association.reload
if retval.nil? and association_proxy_class == BelongsToAssociation
association_instance_set(reflection.name, nil)
return nil
@@ -1370,7 +1370,7 @@ module ActiveRecord
association_instance_set(reflection.name, association)
end
- association.reload if force_reload
+ reflection.klass.uncached { association.reload } if force_reload
association
end
@@ -1382,9 +1382,9 @@ module ActiveRecord
if reflection.through_reflection && reflection.source_reflection.belongs_to?
through = reflection.through_reflection
primary_key = reflection.source_reflection.primary_key_name
- send(through.name).all(:select => "DISTINCT #{through.quoted_table_name}.#{primary_key}").map!(&:"#{primary_key}")
+ send(through.name).select("DISTINCT #{through.quoted_table_name}.#{primary_key}").map!(&:"#{primary_key}")
else
- send(reflection.name).all(:select => "#{reflection.quoted_table_name}.#{reflection.klass.primary_key}").map!(&:id)
+ send(reflection.name).select("#{reflection.quoted_table_name}.#{reflection.klass.primary_key}").map!(&:id)
end
end
end
@@ -1717,9 +1717,9 @@ module ActiveRecord
select(column_aliases(join_dependency)).
group(construct_group(options[:group], options[:having], scope)).
order(construct_order(options[:order], scope)).
- conditions(construct_conditions(options[:conditions], scope))
+ where(construct_conditions(options[:conditions], scope))
- relation = relation.conditions(construct_arel_limited_ids_condition(options, join_dependency)) if !using_limitable_reflections?(join_dependency.reflections) && ((scope && scope[:limit]) || options[:limit])
+ relation = relation.where(construct_arel_limited_ids_condition(options, join_dependency)) if !using_limitable_reflections?(join_dependency.reflections) && ((scope && scope[:limit]) || options[:limit])
relation = relation.limit(construct_limit(options[:limit], scope)) if using_limitable_reflections?(join_dependency.reflections)
relation
@@ -1757,7 +1757,7 @@ module ActiveRecord
end
relation = relation.joins(construct_join(options[:joins], scope)).
- conditions(construct_conditions(options[:conditions], scope)).
+ where(construct_conditions(options[:conditions], scope)).
group(construct_group(options[:group], options[:having], scope)).
order(construct_order(options[:order], scope)).
limit(construct_limit(options[:limit], scope)).
diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb
index 25e329c0c1..b85d76e8d3 100644
--- a/activerecord/lib/active_record/associations/association_collection.rb
+++ b/activerecord/lib/active_record/associations/association_collection.rb
@@ -20,7 +20,22 @@ module ActiveRecord
super
construct_sql
end
-
+
+ delegate :group, :order, :limit, :joins, :where, :preload, :eager_load, :to => :scoped
+
+ def select(select = nil, &block)
+ if block_given?
+ load_target
+ @target.select(&block)
+ else
+ scoped.select(select)
+ end
+ end
+
+ def scoped
+ with_scope(construct_scope) { @reflection.klass.scoped }
+ end
+
def find(*args)
options = args.extract_options!
@@ -383,7 +398,7 @@ module ActiveRecord
loaded if target
target
end
-
+
def method_missing(method, *args)
if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method))
if block_given?
diff --git a/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb b/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb
index b01faa5212..9569b0c6f9 100644
--- a/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb
+++ b/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb
@@ -71,7 +71,7 @@ module ActiveRecord
records.each { |record| @owner.connection.delete(interpolate_sql(sql, record)) }
else
relation = arel_table(@reflection.options[:join_table])
- relation.conditions(relation[@reflection.primary_key_name].eq(@owner.id).
+ relation.where(relation[@reflection.primary_key_name].eq(@owner.id).
and(Arel::Predicates::In.new(relation[@reflection.association_foreign_key], records.map(&:id)))
).delete
end
diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb
index cd31b0e211..be74ddfcf0 100644
--- a/activerecord/lib/active_record/associations/has_many_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_association.rb
@@ -70,7 +70,7 @@ module ActiveRecord
@reflection.klass.delete(records.map { |record| record.id })
else
relation = arel_table(@reflection.table_name)
- relation.conditions(relation[@reflection.primary_key_name].eq(@owner.id).
+ relation.where(relation[@reflection.primary_key_name].eq(@owner.id).
and(Arel::Predicates::In.new(relation[@reflection.klass.primary_key], records.map(&:id)))
).update(relation[@reflection.primary_key_name] => nil)
diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb
index 8f37fcd515..c0d8904bc8 100644
--- a/activerecord/lib/active_record/autosave_association.rb
+++ b/activerecord/lib/active_record/autosave_association.rb
@@ -221,9 +221,9 @@ module ActiveRecord
if new_record
association
elsif association.loaded?
- autosave ? association : association.select { |record| record.new_record? }
+ autosave ? association : association.find_all { |record| record.new_record? }
else
- autosave ? association.target : association.target.select { |record| record.new_record? }
+ autosave ? association.target : association.target.find_all { |record| record.new_record? }
end
end
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 056f29f029..2008dea5e9 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -13,6 +13,7 @@ require 'active_support/core_ext/hash/indifferent_access'
require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/string/behavior'
require 'active_support/core_ext/object/metaclass'
+require 'active_support/core_ext/module/delegation'
module ActiveRecord #:nodoc:
# Generic Active Record exception class.
@@ -650,6 +651,8 @@ module ActiveRecord #:nodoc:
end
end
+ delegate :select, :group, :order, :limit, :joins, :where, :preload, :eager_load, :to => :scoped
+
# A convenience wrapper for <tt>find(:first, *args)</tt>. You can pass in all the
# same arguments to this method as you can to <tt>find(:first)</tt>.
def first(*args)
@@ -668,20 +671,10 @@ module ActiveRecord #:nodoc:
options = args.extract_options!
if options.empty? && !scoped?(:find)
- relation = arel_table
+ arel_table.to_a
else
- relation = construct_finder_arel(options)
- include_associations = merge_includes(scope(:find, :include), options[:include])
-
- if include_associations.any?
- if references_eager_loaded_tables?(options)
- relation.eager_load(include_associations)
- else
- relation.preload(include_associations)
- end
- end
+ construct_finder_arel_with_includes(options).to_a
end
- relation
end
# Executes a custom SQL query against your database and returns all the results. The results will
@@ -882,7 +875,7 @@ module ActiveRecord #:nodoc:
relation = arel_table
if conditions = construct_conditions(conditions, scope)
- relation = relation.conditions(Arel::SqlLiteral.new(conditions))
+ relation = relation.where(Arel::SqlLiteral.new(conditions))
end
relation = if options.has_key?(:limit) || (scope && scope[:limit])
@@ -945,7 +938,7 @@ module ActiveRecord #:nodoc:
# associations or call your <tt>before_*</tt> or +after_destroy+ callbacks, use the +destroy_all+ method instead.
def delete_all(conditions = nil)
if conditions
- arel_table.conditions(Arel::SqlLiteral.new(construct_conditions(conditions, scope(:find)))).delete
+ arel_table.where(Arel::SqlLiteral.new(construct_conditions(conditions, scope(:find)))).delete
else
arel_table.delete
end
@@ -967,6 +960,29 @@ module ActiveRecord #:nodoc:
connection.select_value(sql, "#{name} Count").to_i
end
+ # Resets one or more counter caches to their correct value using an SQL
+ # count query. This is useful when adding new counter caches, or if the
+ # counter has been corrupted or modified directly by SQL.
+ #
+ # ==== Parameters
+ #
+ # * +id+ - The id of the object you wish to reset a counter on.
+ # * +counters+ - One or more counter names to reset
+ #
+ # ==== Examples
+ #
+ # # For Post with id #1 records reset the comments_count
+ # Post.reset_counters(1, :comments)
+ def reset_counters(id, *counters)
+ object = find(id)
+ counters.each do |association|
+ child_class = reflect_on_association(association).klass
+ counter_name = child_class.reflect_on_association(self.name.downcase.to_sym).counter_cache_column
+
+ connection.update("UPDATE #{quoted_table_name} SET #{connection.quote_column_name(counter_name)} = #{object.send(association).count} WHERE #{connection.quote_column_name(primary_key)} = #{quote_value(object.id)}", "#{name} UPDATE")
+ end
+ end
+
# A generic "counter updater" implementation, intended primarily to be
# used by increment_counter and decrement_counter, but which may also
# be useful on its own. It simply does a direct SQL update for the record
@@ -1491,13 +1507,8 @@ module ActiveRecord #:nodoc:
"(#{segments.join(') AND (')})" unless segments.empty?
end
-
def arel_table(table = nil)
- table = table_name if table.blank?
- if @arel_table.nil? || @arel_table.name != table
- @arel_table = Relation.new(self, Arel::Table.new(table))
- end
- @arel_table
+ Relation.new(self, Arel::Table.new(table || table_name))
end
private
@@ -1666,9 +1677,11 @@ module ActiveRecord #:nodoc:
def construct_finder_arel(options = {}, scope = scope(:find))
# TODO add lock to Arel
+ validate_find_options(options)
+
relation = arel_table(options[:from]).
joins(construct_join(options[:joins], scope)).
- conditions(construct_conditions(options[:conditions], scope)).
+ where(construct_conditions(options[:conditions], scope)).
select(options[:select] || (scope && scope[:select]) || default_select(options[:joins] || (scope && scope[:joins]))).
group(construct_group(options[:group], options[:having], scope)).
order(construct_order(options[:order], scope)).
@@ -1680,6 +1693,21 @@ module ActiveRecord #:nodoc:
relation
end
+ def construct_finder_arel_with_includes(options = {})
+ relation = construct_finder_arel(options)
+ include_associations = merge_includes(scope(:find, :include), options[:include])
+
+ if include_associations.any?
+ if references_eager_loaded_tables?(options)
+ relation = relation.eager_load(include_associations)
+ else
+ relation = relation.preload(include_associations)
+ end
+ end
+
+ relation
+ end
+
def construct_finder_sql(options, scope = scope(:find))
construct_finder_arel(options, scope).to_sql
end
@@ -1814,9 +1842,8 @@ module ActiveRecord #:nodoc:
end
# Enables dynamic finders like <tt>find_by_user_name(user_name)</tt> and <tt>find_by_user_name_and_password(user_name, password)</tt>
- # that are turned into <tt>find(:first, :conditions => ["user_name = ?", user_name])</tt> and
- # <tt>find(:first, :conditions => ["user_name = ? AND password = ?", user_name, password])</tt> respectively. Also works for
- # <tt>find(:all)</tt> by using <tt>find_all_by_amount(50)</tt> that is turned into <tt>find(:all, :conditions => ["amount = ?", 50])</tt>.
+ # that are turned into <tt>where(:user_name => user_name).first</tt> and <tt>where(:user_name => user_name, :password => :password).first</tt>
+ # respectively. Also works for <tt>all</tt> by using <tt>find_all_by_amount(50)</tt> that is turned into <tt>where(:amount => 50).all</tt>.
#
# It's even possible to use all the additional parameters to +find+. For example, the full interface for +find_all_by_amount+
# is actually <tt>find_all_by_amount(amount, options)</tt>.
@@ -1832,103 +1859,11 @@ module ActiveRecord #:nodoc:
attribute_names = match.attribute_names
super unless all_attributes_exists?(attribute_names)
if match.finder?
- finder = match.finder
- bang = match.bang?
- # def self.find_by_login_and_activated(*args)
- # options = args.extract_options!
- # attributes = construct_attributes_from_arguments(
- # [:login,:activated],
- # args
- # )
- # finder_options = { :conditions => attributes }
- # validate_find_options(options)
- # set_readonly_option!(options)
- #
- # if options[:conditions]
- # with_scope(:find => finder_options) do
- # find(:first, options)
- # end
- # else
- # find(:first, options.merge(finder_options))
- # end
- # end
- self.class_eval %{
- def self.#{method_id}(*args)
- options = args.extract_options!
- attributes = construct_attributes_from_arguments(
- [:#{attribute_names.join(',:')}],
- args
- )
- finder_options = { :conditions => attributes }
- validate_find_options(options)
- set_readonly_option!(options)
-
- #{'result = ' if bang}if options[:conditions]
- with_scope(:find => finder_options) do
- find(:#{finder}, options)
- end
- else
- find(:#{finder}, options.merge(finder_options))
- end
- #{'result || raise(RecordNotFound, "Couldn\'t find #{name} with #{attributes.to_a.collect { |pair| pair.join(\' = \') }.join(\', \')}")' if bang}
- end
- }, __FILE__, __LINE__
- send(method_id, *arguments)
+ options = arguments.extract_options!
+ relation = options.any? ? construct_finder_arel_with_includes(options) : scoped
+ relation.send :find_by_attributes, match, attribute_names, *arguments
elsif match.instantiator?
- instantiator = match.instantiator
- # def self.find_or_create_by_user_id(*args)
- # guard_protected_attributes = false
- #
- # if args[0].is_a?(Hash)
- # guard_protected_attributes = true
- # attributes = args[0].with_indifferent_access
- # find_attributes = attributes.slice(*[:user_id])
- # else
- # find_attributes = attributes = construct_attributes_from_arguments([:user_id], args)
- # end
- #
- # options = { :conditions => find_attributes }
- # set_readonly_option!(options)
- #
- # record = find(:first, options)
- #
- # if record.nil?
- # record = self.new { |r| r.send(:attributes=, attributes, guard_protected_attributes) }
- # yield(record) if block_given?
- # record.save
- # record
- # else
- # record
- # end
- # end
- self.class_eval %{
- def self.#{method_id}(*args)
- guard_protected_attributes = false
-
- if args[0].is_a?(Hash)
- guard_protected_attributes = true
- attributes = args[0].with_indifferent_access
- find_attributes = attributes.slice(*[:#{attribute_names.join(',:')}])
- else
- find_attributes = attributes = construct_attributes_from_arguments([:#{attribute_names.join(',:')}], args)
- end
-
- options = { :conditions => find_attributes }
- set_readonly_option!(options)
-
- record = find(:first, options)
-
- if record.nil?
- record = self.new { |r| r.send(:attributes=, attributes, guard_protected_attributes) }
- #{'yield(record) if block_given?'}
- #{'record.save' if instantiator == :create}
- record
- else
- record
- end
- end
- }, __FILE__, __LINE__
- send(method_id, *arguments, &block)
+ scoped.send :find_or_instantiator_by_attributes, match, attribute_names, *arguments, &block
end
elsif match = DynamicScopeMatch.match(method_id)
attribute_names = match.attribute_names
@@ -2543,7 +2478,7 @@ module ActiveRecord #:nodoc:
# be made (since they can't be persisted).
def destroy
unless new_record?
- self.class.arel_table.conditions(self.class.arel_table[self.class.primary_key].eq(id)).delete
+ self.class.arel_table.where(self.class.arel_table[self.class.primary_key].eq(id)).delete
end
@destroyed = true
@@ -2830,7 +2765,7 @@ module ActiveRecord #:nodoc:
def update(attribute_names = @attributes.keys)
attributes_with_values = arel_attributes_values(false, false, attribute_names)
return 0 if attributes_with_values.empty?
- self.class.arel_table.conditions(self.class.arel_table[self.class.primary_key].eq(id)).update(attributes_with_values)
+ self.class.arel_table.where(self.class.arel_table[self.class.primary_key].eq(id)).update(attributes_with_values)
end
# Creates a record with values matching those of the instance attributes
diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb
index 40242333e5..fcba23dc0d 100644
--- a/activerecord/lib/active_record/calculations.rb
+++ b/activerecord/lib/active_record/calculations.rb
@@ -148,7 +148,7 @@ module ActiveRecord
else
relation = arel_table(options[:from]).
joins(construct_join(options[:joins], scope)).
- conditions(construct_conditions(options[:conditions], scope)).
+ where(construct_conditions(options[:conditions], scope)).
order(options[:order]).
limit(options[:limit]).
offset(options[:offset])
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index ad36ff22e3..fa28bc64df 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -470,6 +470,13 @@ module ActiveRecord
execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
end
+ def add_column(table_name, column_name, type, options = {})
+ add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
+ add_column_options!(add_column_sql, options)
+ add_column_position!(add_column_sql, options)
+ execute(add_column_sql)
+ end
+
def change_column_default(table_name, column_name, default) #:nodoc:
column = column_for(table_name, column_name)
change_column table_name, column_name, column.sql_type, :default => default
@@ -498,6 +505,7 @@ module ActiveRecord
change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
add_column_options!(change_column_sql, options)
+ add_column_position!(change_column_sql, options)
execute(change_column_sql)
end
@@ -529,6 +537,13 @@ module ActiveRecord
end
end
+ def add_column_position!(sql, options)
+ if options[:first]
+ sql << " FIRST"
+ elsif options[:after]
+ sql << " AFTER #{quote_column_name(options[:after])}"
+ end
+ end
# SHOW VARIABLES LIKE 'name'
def show_variable(name)
diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb
index bbe2d1f205..a6336e762a 100644
--- a/activerecord/lib/active_record/named_scope.rb
+++ b/activerecord/lib/active_record/named_scope.rb
@@ -6,18 +6,34 @@ module ActiveRecord
module NamedScope
extend ActiveSupport::Concern
- # All subclasses of ActiveRecord::Base have one named scope:
- # * <tt>scoped</tt> - which allows for the creation of anonymous \scopes, on the fly: <tt>Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions)</tt>
- #
- # These anonymous \scopes tend to be useful when procedurally generating complex queries, where passing
- # intermediate values (scopes) around as first-class objects is convenient.
- #
- # You can define a scope that applies to all finders using ActiveRecord::Base.default_scope.
- included do
- named_scope :scoped, lambda { |scope| scope }
- end
-
module ClassMethods
+ # Returns a relation if invoked without any arguments.
+ #
+ # posts = Post.scoped
+ # posts.size # Fires "select count(*) from posts" and returns the count
+ # posts.each {|p| puts p.name } # Fires "select * from posts" and loads post objects
+ #
+ # Returns an anonymous named scope if any options are supplied.
+ #
+ # shirts = Shirt.scoped(:conditions => {:color => 'red'})
+ # shirts = shirts.scoped(:include => :washing_instructions)
+ #
+ # Anonymous \scopes tend to be useful when procedurally generating complex queries, where passing
+ # intermediate values (scopes) around as first-class objects is convenient.
+ #
+ # You can define a scope that applies to all finders using ActiveRecord::Base.default_scope.
+ def scoped(options = {}, &block)
+ if options.present?
+ Scope.new(self, options, &block)
+ else
+ unless scoped?(:find)
+ finder_needs_type_condition? ? arel_table.where(type_condition) : arel_table
+ else
+ construct_finder_arel_with_includes
+ end
+ end
+ end
+
def scopes
read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})
end
diff --git a/activerecord/lib/active_record/notifications.rb b/activerecord/lib/active_record/notifications.rb
deleted file mode 100644
index 562a5b91f4..0000000000
--- a/activerecord/lib/active_record/notifications.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-require 'active_support/notifications'
-
-ActiveSupport::Notifications.subscribe("sql") do |name, before, after, result, instrumenter_id, payload|
- ActiveRecord::Base.connection.log_info(payload[:sql], name, after - before)
-end
diff --git a/activerecord/lib/active_record/rails.rb b/activerecord/lib/active_record/rails.rb
new file mode 100644
index 0000000000..ddbc555113
--- /dev/null
+++ b/activerecord/lib/active_record/rails.rb
@@ -0,0 +1,59 @@
+# For now, action_controller must always be present with
+# rails, so let's make sure that it gets required before
+# here. This is needed for correctly setting up the middleware.
+# In the future, this might become an optional require.
+require "action_controller/rails"
+
+module ActiveRecord
+ class Plugin < Rails::Plugin
+ plugin_name :active_record
+
+ initializer "active_record.set_configs" do |app|
+ app.config.active_record.each do |k,v|
+ ActiveRecord::Base.send "#{k}=", v
+ end
+ end
+
+ # This sets the database configuration from Configuration#database_configuration
+ # and then establishes the connection.
+ initializer "active_record.initialize_database" do |app|
+ ActiveRecord::Base.configurations = app.config.database_configuration
+ ActiveRecord::Base.establish_connection
+ end
+
+ initializer "active_record.initialize_timezone" do
+ ActiveRecord::Base.time_zone_aware_attributes = true
+ ActiveRecord::Base.default_timezone = :utc
+ end
+
+ # Setup database middleware after initializers have run
+ initializer "active_record.initialize_database_middleware" do |app|
+ middleware = app.config.middleware
+ if middleware.include?(ActiveRecord::SessionStore)
+ middleware.insert_before ActiveRecord::SessionStore, ActiveRecord::ConnectionAdapters::ConnectionManagement
+ middleware.insert_before ActiveRecord::SessionStore, ActiveRecord::QueryCache
+ else
+ middleware.use ActiveRecord::ConnectionAdapters::ConnectionManagement
+ middleware.use ActiveRecord::QueryCache
+ end
+ end
+
+ initializer "active_record.load_observers" do
+ ActiveRecord::Base.instantiate_observers
+ end
+
+ # TODO: ActiveRecord::Base.logger should delegate to its own config.logger
+ initializer "active_record.logger" do
+ ActiveRecord::Base.logger ||= Rails.logger
+ end
+
+ initializer "active_record.notifications" do
+ require 'active_support/notifications'
+
+ ActiveSupport::Notifications.subscribe("sql") do |name, before, after, result, instrumenter_id, payload|
+ ActiveRecord::Base.connection.log_info(payload[:sql], name, after - before)
+ end
+ end
+
+ end
+end \ No newline at end of file
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 5f0eec754f..c927270eee 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -4,37 +4,94 @@ module ActiveRecord
delegate :length, :collect, :find, :map, :each, :to => :to_a
attr_reader :relation, :klass
- def initialize(klass, relation)
+ def initialize(klass, relation, readonly = false, preload = [], eager_load = [])
@klass, @relation = klass, relation
- @readonly = false
- @associations_to_preload = []
- @eager_load_associations = []
+ @readonly = readonly
+ @associations_to_preload = preload
+ @eager_load_associations = eager_load
+ @loaded = false
end
- def preload(association)
- @associations_to_preload += association
- self
+ def preload(*associations)
+ create_new_relation(@relation, @readonly, @associations_to_preload + Array.wrap(associations))
end
- def eager_load(association)
- @eager_load_associations += association
- self
+ def eager_load(*associations)
+ create_new_relation(@relation, @readonly, @associations_to_preload, @eager_load_associations + Array.wrap(associations))
end
def readonly
- @readonly = true
- self
+ create_new_relation(@relation, true)
+ end
+
+ def select(selects)
+ create_new_relation(@relation.project(selects))
+ end
+
+ def group(groups)
+ create_new_relation(@relation.group(groups))
+ end
+
+ def order(orders)
+ create_new_relation(@relation.order(orders))
+ end
+
+ def limit(limits)
+ create_new_relation(@relation.take(limits))
+ end
+
+ def offset(offsets)
+ create_new_relation(@relation.skip(offsets))
+ end
+
+ def on(join)
+ create_new_relation(@relation.on(join))
+ end
+
+ def joins(join, join_type = nil)
+ return self if join.blank?
+
+ join_relation = case join
+ when String
+ @relation.join(join)
+ when Hash, Array, Symbol
+ if @klass.send(:array_of_strings?, join)
+ @relation.join(join.join(' '))
+ else
+ @relation.join(@klass.send(:build_association_joins, join))
+ end
+ else
+ @relation.join(join, join_type)
+ end
+
+ create_new_relation(join_relation)
+ end
+
+ def where(*args)
+ if [String, Hash, Array].include?(args.first.class)
+ conditions = @klass.send(:merge_conditions, args.size > 1 ? Array.wrap(args) : args.first)
+ else
+ conditions = args.first
+ end
+
+ create_new_relation(@relation.where(conditions))
+ end
+
+ def respond_to?(method)
+ @relation.respond_to?(method) || Array.method_defined?(method) || super
end
def to_a
- records = if @eager_load_associations.any?
+ return @records if loaded?
+
+ @records = if @eager_load_associations.any?
catch :invalid_query do
return @klass.send(:find_with_associations, {
:select => @relation.send(:select_clauses).join(', '),
:joins => @relation.joins(relation),
:group => @relation.send(:group_clauses).join(', '),
:order => @relation.send(:order_clauses).join(', '),
- :conditions => @relation.send(:where_clauses).join("\n\tAND "),
+ :conditions => where_clause,
:limit => @relation.taken,
:offset => @relation.skipped
},
@@ -45,83 +102,151 @@ module ActiveRecord
@klass.find_by_sql(@relation.to_sql)
end
- @klass.send(:preload_associations, records, @associations_to_preload) unless @associations_to_preload.empty?
- records.each { |record| record.readonly! } if @readonly
+ @associations_to_preload.each {|associations| @klass.send(:preload_associations, @records, associations) }
+ @records.each { |record| record.readonly! } if @readonly
- records
+ @loaded = true
+ @records
end
- def first
- @relation = @relation.take(1)
- to_a.first
- end
+ alias all to_a
- def select(selects)
- selects.blank? ? self : Relation.new(@klass, @relation.project(selects))
- end
+ def find(*ids, &block)
+ return to_a.find(&block) if block_given?
- def group(groups)
- groups.blank? ? self : Relation.new(@klass, @relation.group(groups))
+ expects_array = ids.first.kind_of?(Array)
+ return ids.first if expects_array && ids.first.empty?
+
+ ids = ids.flatten.compact.uniq
+
+ case ids.size
+ when 0
+ raise RecordNotFound, "Couldn't find #{@klass.name} without an ID"
+ when 1
+ result = find_one(ids.first)
+ expects_array ? [ result ] : result
+ else
+ find_some(ids)
+ end
end
- def order(orders)
- orders.blank? ? self : Relation.new(@klass, @relation.order(orders))
+ def first
+ if loaded?
+ @records.first
+ else
+ @first ||= limit(1).to_a[0]
+ end
end
- def limit(limits)
- limits.blank? ? self : Relation.new(@klass, @relation.take(limits))
+ def loaded?
+ @loaded
end
- def offset(offsets)
- offsets.blank? ? self : Relation.new(@klass, @relation.skip(offsets))
+ def reload
+ @loaded = false
+ @records = @first = nil
+ self
end
- def on(join)
- join.blank? ? self : Relation.new(@klass, @relation.on(join))
+ protected
+
+ def method_missing(method, *args, &block)
+ if @relation.respond_to?(method)
+ @relation.send(method, *args, &block)
+ elsif Array.method_defined?(method)
+ to_a.send(method, *args, &block)
+ elsif match = DynamicFinderMatch.match(method)
+ attributes = match.attribute_names
+ super unless @klass.send(:all_attributes_exists?, attributes)
+
+ if match.finder?
+ find_by_attributes(match, attributes, *args)
+ elsif match.instantiator?
+ find_or_instantiator_by_attributes(match, attributes, *args, &block)
+ end
+ else
+ super
+ end
end
- def joins(join, join_type = nil)
- if join.blank?
- self
+ def find_by_attributes(match, attributes, *args)
+ conditions = attributes.inject({}) {|h, a| h[a] = args[attributes.index(a)]; h}
+ result = where(conditions).send(match.finder)
+
+ if match.bang? && result.blank?
+ raise RecordNotFound, "Couldn't find #{@klass.name} with #{conditions.to_a.collect {|p| p.join(' = ')}.join(', ')}"
else
- join = case join
- when String
- @relation.join(join)
- when Hash, Array, Symbol
- if @klass.send(:array_of_strings?, join)
- @relation.join(join.join(' '))
- else
- @relation.join(@klass.send(:build_association_joins, join))
- end
- else
- @relation.join(join, join_type)
- end
- Relation.new(@klass, join)
+ result
end
end
- def conditions(conditions)
- if conditions.blank?
- self
+ def find_or_instantiator_by_attributes(match, attributes, *args)
+ guard_protected_attributes = false
+
+ if args[0].is_a?(Hash)
+ guard_protected_attributes = true
+ attributes_for_create = args[0].with_indifferent_access
+ conditions = attributes_for_create.slice(*attributes).symbolize_keys
else
- conditions = @klass.send(:merge_conditions, conditions) if [String, Hash, Array].include?(conditions.class)
- Relation.new(@klass, @relation.where(conditions))
+ attributes_for_create = conditions = attributes.inject({}) {|h, a| h[a] = args[attributes.index(a)]; h}
end
+
+ record = where(conditions).first
+
+ unless record
+ record = @klass.new { |r| r.send(:attributes=, attributes_for_create, guard_protected_attributes) }
+ yield(record) if block_given?
+ record.save if match.instantiator == :create
+ end
+
+ record
end
- def respond_to?(method)
- @relation.respond_to?(method) || Array.method_defined?(method) || super
+ def find_one(id)
+ record = where(@klass.primary_key => id).first
+
+ unless record
+ conditions = where_clause(', ')
+ conditions = " [WHERE #{conditions}]" if conditions.present?
+ raise RecordNotFound, "Couldn't find #{@klass.name} with ID=#{id}#{conditions}"
+ end
+
+ record
end
- private
- def method_missing(method, *args, &block)
- if @relation.respond_to?(method)
- @relation.send(method, *args, &block)
- elsif Array.method_defined?(method)
- to_a.send(method, *args, &block)
+ def find_some(ids)
+ result = where(@klass.primary_key => ids).all
+
+ expected_size =
+ if @relation.taken && ids.size > @relation.taken
+ @relation.taken
else
- super
+ ids.size
end
+
+ # 11 ids with limit 3, offset 9 should give 2 results.
+ if @relation.skipped && (ids.size - @relation.skipped < expected_size)
+ expected_size = ids.size - @relation.skipped
+ end
+
+ if result.size == expected_size
+ result
+ else
+ conditions = where_clause(', ')
+ conditions = " [WHERE #{conditions}]" if conditions.present?
+
+ error = "Couldn't find all #{@klass.name.pluralize} with IDs "
+ error << "(#{ids.join(", ")})#{conditions} (found #{result.size} results, but was looking for #{expected_size})"
+ raise RecordNotFound, error
end
+ end
+
+ def create_new_relation(relation, readonly = @readonly, preload = @associations_to_preload, eager_load = @eager_load_associations)
+ Relation.new(@klass, relation, readonly, preload, eager_load)
+ end
+
+ def where_clause(join_string = "\n\tAND ")
+ @relation.send(:where_clauses).join(join_string)
+ end
end
end
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index 86d14c9c81..ce7eedbb54 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -1179,4 +1179,3 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal firm.name, client.firm_name
end
end
-
diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb
index fe68d03de2..608d5a3608 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -140,23 +140,23 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
def test_replace_order_is_preserved
posts(:welcome).people.clear
posts(:welcome).people = [people(:david), people(:michael)]
- assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.all(:order => 'id').map(&:person_id)
+ assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.order('id').map(&:person_id)
# Test the inverse order in case the first success was a coincidence
posts(:welcome).people.clear
posts(:welcome).people = [people(:michael), people(:david)]
- assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.all(:order => 'id').map(&:person_id)
+ assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.order('id').map(&:person_id)
end
def test_replace_by_id_order_is_preserved
posts(:welcome).people.clear
posts(:welcome).person_ids = [people(:david).id, people(:michael).id]
- assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.all(:order => 'id').map(&:person_id)
+ assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.order('id').map(&:person_id)
# Test the inverse order in case the first success was a coincidence
posts(:welcome).people.clear
posts(:welcome).person_ids = [people(:michael).id, people(:david).id]
- assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.all(:order => 'id').map(&:person_id)
+ assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.order('id').map(&:person_id)
end
def test_associate_with_create
diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb
index e429c1d157..9bc34bd750 100644
--- a/activerecord/test/cases/associations_test.rb
+++ b/activerecord/test/cases/associations_test.rb
@@ -64,6 +64,16 @@ class AssociationsTest < ActiveRecord::TestCase
assert !firm.clients(true).empty?, "New firm should have reloaded client objects"
assert_equal 1, firm.clients(true).size, "New firm should have reloaded clients count"
end
+
+ def test_force_reload_is_uncached
+ firm = Firm.create!("name" => "A New Firm, Inc")
+ client = Client.create!("name" => "TheClient.com", :firm => firm)
+ ActiveRecord::Base.cache do
+ firm.clients.each {}
+ assert_queries(0) { assert_not_nil firm.clients.each {} }
+ assert_queries(1) { assert_not_nil firm.clients(true).each {} }
+ end
+ end
end
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 5c2911eca1..b51c9f0cb3 100755
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -680,6 +680,16 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal -2, Topic.find(2).replies_count
end
+ def test_reset_counters
+ assert_equal 1, Topic.find(1).replies_count
+
+ Topic.increment_counter("replies_count", 1)
+ assert_equal 2, Topic.find(1).replies_count
+
+ Topic.reset_counters(1, :replies)
+ assert_equal 1, Topic.find(1).replies_count
+ end
+
def test_update_counter
category = categories(:general)
assert_nil category.categorizations_count
@@ -1892,8 +1902,14 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal Developer.find(:first, :order => 'id desc'), Developer.last
end
+ def test_all
+ developers = Developer.all
+ assert_kind_of Array, developers
+ assert_equal Developer.find(:all), developers
+ end
+
def test_all_with_conditions
- assert_equal Developer.find(:all, :order => 'id desc'), Developer.all.order('id desc').to_a
+ assert_equal Developer.find(:all, :order => 'id desc'), Developer.order('id desc').all
end
def test_find_ordered_last
diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb
index 5009a90846..e417d8a803 100644
--- a/activerecord/test/cases/batches_test.rb
+++ b/activerecord/test/cases/batches_test.rb
@@ -5,7 +5,7 @@ class EachTest < ActiveRecord::TestCase
fixtures :posts
def setup
- @posts = Post.all(:order => "id asc")
+ @posts = Post.order("id asc")
@total = Post.count
end
diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb
index f456d273fe..4961d12a44 100644
--- a/activerecord/test/cases/dirty_test.rb
+++ b/activerecord/test/cases/dirty_test.rb
@@ -301,7 +301,7 @@ class DirtyTest < ActiveRecord::TestCase
def test_save_should_not_save_serialized_attribute_with_partial_updates_if_not_present
with_partial_updates(Topic) do
Topic.create!(:author_name => 'Bill', :content => {:a => "a"})
- topic = Topic.first(:select => 'id, author_name')
+ topic = Topic.select('id, author_name').first
topic.update_attribute :author_name, 'John'
topic = Topic.first
assert_not_nil topic.content
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 3de07797d4..c531a2dec1 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -233,11 +233,11 @@ class FinderTest < ActiveRecord::TestCase
end
def test_first
- assert_equal topics(:second).title, Topic.first(:conditions => "title = 'The Second Topic of the day'").title
+ assert_equal topics(:second).title, Topic.where("title = 'The Second Topic of the day'").first.title
end
def test_first_failing
- assert_nil Topic.first(:conditions => "title = 'The Second Topic of the day!'")
+ assert_nil Topic.where("title = 'The Second Topic of the day!'").first
end
def test_unexisting_record_exception_handling
@@ -291,7 +291,7 @@ class FinderTest < ActiveRecord::TestCase
end
def test_find_with_hash_conditions_on_joined_table
- firms = Firm.all :joins => :account, :conditions => {:accounts => { :credit_limit => 50 }}
+ firms = Firm.joins(:account).where(:accounts => { :credit_limit => 50 })
assert_equal 1, firms.size
assert_equal companies(:first_firm), firms.first
end
@@ -571,21 +571,6 @@ class FinderTest < ActiveRecord::TestCase
assert_equal(2, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 1]))
end
- def test_dynamic_finders_should_go_through_the_find_class_method
- Topic.expects(:find).with(:first, :conditions => { :title => 'The First Topic!' })
- Topic.find_by_title("The First Topic!")
-
- Topic.expects(:find).with(:last, :conditions => { :title => 'The Last Topic!' })
- Topic.find_last_by_title("The Last Topic!")
-
- Topic.expects(:find).with(:all, :conditions => { :title => 'A Topic.' })
- Topic.find_all_by_title("A Topic.")
-
- Topic.expects(:find).with(:first, :conditions => { :title => 'Does not exist yet for sure!' }).times(2)
- Topic.find_or_initialize_by_title('Does not exist yet for sure!')
- Topic.find_or_create_by_title('Does not exist yet for sure!')
- end
-
def test_find_by_one_attribute
assert_equal topics(:first), Topic.find_by_title("The First Topic")
assert_nil Topic.find_by_title("The First Topic!")
@@ -596,21 +581,6 @@ class FinderTest < ActiveRecord::TestCase
assert_raise(ActiveRecord::RecordNotFound) { Topic.find_by_title!("The First Topic!") }
end
- def test_find_by_one_attribute_caches_dynamic_finder
- # ensure this test can run independently of order
- class << Topic; self; end.send(:remove_method, :find_by_title) if Topic.public_methods.any? { |m| m.to_s == 'find_by_title' }
- assert !Topic.public_methods.any? { |m| m.to_s == 'find_by_title' }
- t = Topic.find_by_title("The First Topic")
- assert Topic.public_methods.any? { |m| m.to_s == 'find_by_title' }
- end
-
- def test_dynamic_finder_returns_same_results_after_caching
- # ensure this test can run independently of order
- class << Topic; self; end.send(:remove_method, :find_by_title) if Topic.public_method_defined?(:find_by_title)
- t = Topic.find_by_title("The First Topic")
- assert_equal t, Topic.find_by_title("The First Topic") # find_by_title has been cached
- end
-
def test_find_by_one_attribute_with_order_option
assert_equal accounts(:signals37), Account.find_by_credit_limit(50, :order => 'id')
assert_equal accounts(:rails_core_account), Account.find_by_credit_limit(50, :order => 'id DESC')
@@ -654,14 +624,6 @@ class FinderTest < ActiveRecord::TestCase
assert_equal customers(:david), found_customer
end
- def test_dynamic_finder_on_one_attribute_with_conditions_caches_method
- # ensure this test can run independently of order
- class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.public_methods.any? { |m| m.to_s == 'find_by_credit_limit' }
- assert !Account.public_methods.any? { |m| m.to_s == 'find_by_credit_limit' }
- a = Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6])
- assert Account.public_methods.any? { |m| m.to_s == 'find_by_credit_limit' }
- end
-
def test_dynamic_finder_on_one_attribute_with_conditions_returns_same_results_after_caching
# ensure this test can run independently of order
class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.public_methods.any? { |m| m.to_s == 'find_by_credit_limit' }
@@ -694,14 +656,6 @@ class FinderTest < ActiveRecord::TestCase
assert_nil Topic.find_last_by_title("A title with no matches")
end
- def test_find_last_by_one_attribute_caches_dynamic_finder
- # ensure this test can run independently of order
- class << Topic; self; end.send(:remove_method, :find_last_by_title) if Topic.public_methods.any? { |m| m.to_s == 'find_last_by_title' }
- assert !Topic.public_methods.any? { |m| m.to_s == 'find_last_by_title' }
- t = Topic.find_last_by_title(Topic.last.title)
- assert Topic.public_methods.any? { |m| m.to_s == 'find_last_by_title' }
- end
-
def test_find_last_by_invalid_method_syntax
assert_raise(NoMethodError) { Topic.fail_to_find_last_by_title("The First Topic") }
assert_raise(NoMethodError) { Topic.find_last_by_title?("The First Topic") }
@@ -926,13 +880,6 @@ class FinderTest < ActiveRecord::TestCase
assert !c.new_record?
end
- def test_dynamic_find_or_initialize_from_one_attribute_caches_method
- class << Company; self; end.send(:remove_method, :find_or_initialize_by_name) if Company.public_methods.any? { |m| m.to_s == 'find_or_initialize_by_name' }
- assert !Company.public_methods.any? { |m| m.to_s == 'find_or_initialize_by_name' }
- sig38 = Company.find_or_initialize_by_name("38signals")
- assert Company.public_methods.any? { |m| m.to_s == 'find_or_initialize_by_name' }
- end
-
def test_find_or_initialize_from_two_attributes
another = Topic.find_or_initialize_by_title_and_author_name("Another topic","John")
assert_equal "Another topic", another.title
diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb
index 25613da912..307320b964 100644
--- a/activerecord/test/cases/helper.rb
+++ b/activerecord/test/cases/helper.rb
@@ -1,11 +1,9 @@
-root = File.expand_path('../../../..', __FILE__)
begin
- require "#{root}/vendor/gems/environment"
+ require File.expand_path('../../../../vendor/gems/environment', __FILE__)
rescue LoadError
- $:.unshift("#{root}/activesupport/lib")
end
-lib = File.expand_path("#{File.dirname(__FILE__)}/../../lib")
+lib = File.expand_path('../../../lib', __FILE__)
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
require 'config'
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index 6d3f938799..0ef34e440a 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -527,6 +527,53 @@ if ActiveRecord::Base.connection.supports_migrations?
assert !Person.column_methods_hash.include?(:last_name)
end
+ if current_adapter?(:MysqlAdapter)
+ def testing_table_for_positioning
+ Person.connection.create_table :testings, :id => false do |t|
+ t.column :first, :integer
+ t.column :second, :integer
+ t.column :third, :integer
+ end
+
+ yield Person.connection
+ ensure
+ Person.connection.drop_table :testings rescue nil
+ end
+ protected :testing_table_for_positioning
+
+ def test_column_positioning
+ testing_table_for_positioning do |conn|
+ assert_equal %w(first second third), conn.columns(:testings).map {|c| c.name }
+ end
+ end
+
+ def test_add_column_with_positioning
+ testing_table_for_positioning do |conn|
+ conn.add_column :testings, :new_col, :integer
+ assert_equal %w(first second third new_col), conn.columns(:testings).map {|c| c.name }
+ end
+ testing_table_for_positioning do |conn|
+ conn.add_column :testings, :new_col, :integer, :first => true
+ assert_equal %w(new_col first second third), conn.columns(:testings).map {|c| c.name }
+ end
+ testing_table_for_positioning do |conn|
+ conn.add_column :testings, :new_col, :integer, :after => :first
+ assert_equal %w(first new_col second third), conn.columns(:testings).map {|c| c.name }
+ end
+ end
+
+ def test_change_column_with_positioning
+ testing_table_for_positioning do |conn|
+ conn.change_column :testings, :second, :integer, :first => true
+ assert_equal %w(second first third), conn.columns(:testings).map {|c| c.name }
+ end
+ testing_table_for_positioning do |conn|
+ conn.change_column :testings, :second, :integer, :after => :third
+ assert_equal %w(first third second), conn.columns(:testings).map {|c| c.name }
+ end
+ end
+ end
+
def test_add_rename
Person.delete_all
diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb
index 13427daf53..5d9232bc52 100644
--- a/activerecord/test/cases/named_scope_test.rb
+++ b/activerecord/test/cases/named_scope_test.rb
@@ -345,8 +345,8 @@ class NamedScopeTest < ActiveRecord::TestCase
def test_chaining_should_use_latest_conditions_when_searching
# Normal hash conditions
- assert_equal Topic.all(:conditions => {:approved => true}).to_a, Topic.rejected.approved.all.to_a
- assert_equal Topic.all(:conditions => {:approved => false}).to_a, Topic.approved.rejected.all.to_a
+ assert_equal Topic.where(:approved => true).to_a, Topic.rejected.approved.all.to_a
+ assert_equal Topic.where(:approved => false).to_a, Topic.approved.rejected.all.to_a
# Nested hash conditions with same keys
assert_equal [posts(:sti_comments)], Post.with_special_comments.with_very_special_comments.all.to_a
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index 1a2c8030fb..9c5a38a399 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -1,4 +1,6 @@
require "cases/helper"
+require 'models/tag'
+require 'models/tagging'
require 'models/post'
require 'models/topic'
require 'models/comment'
@@ -10,50 +12,112 @@ require 'models/developer'
require 'models/company'
class RelationTest < ActiveRecord::TestCase
- fixtures :authors, :topics, :entrants, :developers, :companies, :developers_projects, :accounts, :categories, :categorizations, :posts, :comments
+ fixtures :authors, :topics, :entrants, :developers, :companies, :developers_projects, :accounts, :categories, :categorizations, :posts, :comments,
+ :taggings
+
+ def test_scoped
+ topics = Topic.scoped
+ assert_kind_of ActiveRecord::Relation, topics
+ assert_equal 4, topics.size
+ end
+
+ def test_scoped_all
+ topics = Topic.scoped.all
+ assert_kind_of Array, topics
+ assert_no_queries { assert_equal 4, topics.size }
+ end
+
+ def test_loaded_all
+ topics = Topic.scoped
+
+ assert_queries(1) do
+ 2.times { assert_equal 4, topics.all.size }
+ end
+
+ assert topics.loaded?
+ end
+
+ def test_scoped_first
+ topics = Topic.scoped
+
+ assert_queries(1) do
+ 2.times { assert_equal "The First Topic", topics.first.title }
+ end
+
+ assert ! topics.loaded?
+ end
+
+ def test_loaded_first
+ topics = Topic.scoped
+
+ assert_queries(1) do
+ topics.all # force load
+ 2.times { assert_equal "The First Topic", topics.first.title }
+ end
+
+ assert topics.loaded?
+ end
+
+ def test_reload
+ topics = Topic.scoped
+
+ assert_queries(1) do
+ 2.times { topics.to_a }
+ end
+
+ assert topics.loaded?
+
+ topics.reload
+ assert ! topics.loaded?
+
+ assert_queries(1) { topics.to_a }
+ end
def test_finding_with_conditions
- assert_equal Author.find(:all, :conditions => "name = 'David'"), Author.all.conditions("name = 'David'").to_a
+ assert_equal ["David"], Author.where(:name => 'David').map(&:name)
+ assert_equal ['Mary'], Author.where(["name = ?", 'Mary']).map(&:name)
+ assert_equal ['Mary'], Author.where("name = ?", 'Mary').map(&:name)
end
def test_finding_with_order
- topics = Topic.all.order('id')
+ topics = Topic.order('id')
assert_equal 4, topics.size
assert_equal topics(:first).title, topics.first.title
end
def test_finding_with_order_and_take
- entrants = Entrant.all.order("id ASC").limit(2).to_a
+ entrants = Entrant.order("id ASC").limit(2).to_a
- assert_equal(2, entrants.size)
- assert_equal(entrants(:first).name, entrants.first.name)
+ assert_equal 2, entrants.size
+ assert_equal entrants(:first).name, entrants.first.name
end
def test_finding_with_order_limit_and_offset
- entrants = Entrant.all.order("id ASC").limit(2).offset(1)
+ entrants = Entrant.order("id ASC").limit(2).offset(1)
- assert_equal(2, entrants.size)
- assert_equal(entrants(:second).name, entrants.first.name)
+ assert_equal 2, entrants.size
+ assert_equal entrants(:second).name, entrants.first.name
- entrants = Entrant.all.order("id ASC").limit(2).offset(2)
- assert_equal(1, entrants.size)
- assert_equal(entrants(:third).name, entrants.first.name)
+ entrants = Entrant.order("id ASC").limit(2).offset(2)
+ assert_equal 1, entrants.size
+ assert_equal entrants(:third).name, entrants.first.name
end
def test_finding_with_group
- developers = Developer.all.group("salary").select("salary").to_a
+ developers = Developer.group("salary").select("salary").to_a
assert_equal 4, developers.size
assert_equal 4, developers.map(&:salary).uniq.size
end
def test_finding_with_hash_conditions_on_joined_table
- firms = DependentFirm.all.joins(:account).conditions({:name => 'RailsCore', :accounts => { :credit_limit => 55..60 }}).to_a
+ firms = DependentFirm.joins(:account).where({:name => 'RailsCore', :accounts => { :credit_limit => 55..60 }}).to_a
assert_equal 1, firms.size
assert_equal companies(:rails_core), firms.first
end
def test_find_all_with_join
- developers_on_project_one = Developer.all.joins('LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id').conditions('project_id=1').to_a
+ developers_on_project_one = Developer.joins('LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id').
+ where('project_id=1').to_a
assert_equal 3, developers_on_project_one.length
developer_names = developers_on_project_one.map { |d| d.name }
@@ -62,11 +126,11 @@ class RelationTest < ActiveRecord::TestCase
end
def test_find_on_hash_conditions
- assert_equal Topic.find(:all, :conditions => {:approved => false}), Topic.all.conditions({ :approved => false }).to_a
+ assert_equal Topic.find(:all, :conditions => {:approved => false}), Topic.where({ :approved => false }).to_a
end
def test_joins_with_string_array
- person_with_reader_and_post = Post.all.joins([
+ person_with_reader_and_post = Post.joins([
"INNER JOIN categorizations ON categorizations.post_id = posts.id",
"INNER JOIN categories ON categories.id = categorizations.category_id AND categories.type = 'SpecialCategory'"
]
@@ -74,8 +138,8 @@ class RelationTest < ActiveRecord::TestCase
assert_equal 1, person_with_reader_and_post.size
end
- def test_relation_responds_to_delegated_methods
- relation = Topic.all
+ def test_scoped_responds_to_delegated_methods
+ relation = Topic.scoped
["map", "uniq", "sort", "insert", "delete", "update"].each do |method|
assert relation.respond_to?(method), "Topic.all should respond to #{method.inspect}"
@@ -83,13 +147,14 @@ class RelationTest < ActiveRecord::TestCase
end
def test_find_with_readonly_option
- Developer.all.each { |d| assert !d.readonly? }
- Developer.all.readonly.each { |d| assert d.readonly? }
- Developer.all(:readonly => true).each { |d| assert d.readonly? }
+ Developer.scoped.each { |d| assert !d.readonly? }
+ Developer.scoped.readonly.each { |d| assert d.readonly? }
end
def test_eager_association_loading_of_stis_with_multiple_references
- authors = Author.all(:include => { :posts => { :special_comments => { :post => [ :special_comments, :very_special_comment ] } } }, :order => 'comments.body, very_special_comments_posts.body', :conditions => 'posts.id = 4').to_a
+ authors = Author.eager_load(:posts => { :special_comments => { :post => [ :special_comments, :very_special_comment ] } }).
+ order('comments.body, very_special_comments_posts.body').where('posts.id = 4').to_a
+
assert_equal [authors(:david)], authors
assert_no_queries do
authors.first.posts.first.special_comments.first.post.special_comments
@@ -99,52 +164,138 @@ class RelationTest < ActiveRecord::TestCase
def test_find_with_included_associations
assert_queries(2) do
- posts = Post.find(:all, :include => :comments)
- posts.first.comments.first
+ posts = Post.preload(:comments)
+ assert posts.first.comments.first
end
+
assert_queries(2) do
- posts = Post.all(:include => :comments).to_a
- posts.first.comments.first
+ posts = Post.preload(:comments).to_a
+ assert posts.first.comments.first
end
+
assert_queries(2) do
- posts = Post.find(:all, :include => :author)
- posts.first.author
+ posts = Post.preload(:author)
+ assert posts.first.author
end
+
assert_queries(2) do
- posts = Post.all(:include => :author).to_a
- posts.first.author
+ posts = Post.preload(:author).to_a
+ assert posts.first.author
+ end
+
+ assert_queries(3) do
+ posts = Post.preload(:author, :comments).to_a
+ assert posts.first.author
+ assert posts.first.comments.first
end
end
- def test_default_scope_with_conditions_string
- assert_equal Developer.find_all_by_name('David').map(&:id).sort, DeveloperCalledDavid.all.to_a.map(&:id).sort
+ def test_default_scope_with_conditions_string
+ assert_equal Developer.find_all_by_name('David').map(&:id).sort, DeveloperCalledDavid.scoped.map(&:id).sort
assert_equal nil, DeveloperCalledDavid.create!.name
end
def test_default_scope_with_conditions_hash
- assert_equal Developer.find_all_by_name('Jamis').map(&:id).sort, DeveloperCalledJamis.all.map(&:id).sort
+ assert_equal Developer.find_all_by_name('Jamis').map(&:id).sort, DeveloperCalledJamis.scoped.map(&:id).sort
assert_equal 'Jamis', DeveloperCalledJamis.create!.name
end
- def test_loading_with_one_association
- posts = Post.all(:include => :comments)
+ def test_default_scoping_finder_methods
+ developers = DeveloperCalledDavid.order('id').map(&:id).sort
+ assert_equal Developer.find_all_by_name('David').map(&:id).sort, developers
+ end
+
+ def test_loading_with_one_association
+ posts = Post.preload(:comments)
post = posts.find { |p| p.id == 1 }
assert_equal 2, post.comments.size
assert post.comments.include?(comments(:greetings))
- post = Post.find(:first, :include => :comments, :conditions => "posts.title = 'Welcome to the weblog'")
+ post = Post.where("posts.title = 'Welcome to the weblog'").preload(:comments).first
assert_equal 2, post.comments.size
assert post.comments.include?(comments(:greetings))
- posts = Post.all(:include => :last_comment)
+ posts = Post.preload(:last_comment)
post = posts.find { |p| p.id == 1 }
assert_equal Post.find(1).last_comment, post.last_comment
end
def test_loading_with_one_association_with_non_preload
- posts = Post.all(:include => :last_comment, :order => 'comments.id DESC')
+ posts = Post.eager_load(:last_comment).order('comments.id DESC')
post = posts.find { |p| p.id == 1 }
assert_equal Post.find(1).last_comment, post.last_comment
end
-end
+ def test_dynamic_find_by_attributes
+ david = authors(:david)
+ author = Author.preload(:taggings).find_by_id(david.id)
+ expected_taggings = taggings(:welcome_general, :thinking_general)
+
+ assert_no_queries do
+ assert_equal expected_taggings, author.taggings.uniq.sort_by { |t| t.id }
+ end
+
+ authors = Author.scoped
+ assert_equal david, authors.find_by_id_and_name(david.id, david.name)
+ assert_equal david, authors.find_by_id_and_name!(david.id, david.name)
+ end
+
+ def test_dynamic_find_by_attributes_bang
+ author = Author.scoped.find_by_id!(authors(:david).id)
+ assert_equal "David", author.name
+
+ assert_raises(ActiveRecord::RecordNotFound) { Author.scoped.find_by_id_and_name!('invalid', 'wt') }
+ end
+
+ def test_dynamic_find_all_by_attributes
+ authors = Author.scoped
+
+ davids = authors.find_all_by_name('David')
+ assert_kind_of Array, davids
+ assert_equal [authors(:david)], davids
+ end
+
+ def test_dynamic_find_or_initialize_by_attributes
+ authors = Author.scoped
+
+ lifo = authors.find_or_initialize_by_name('Lifo')
+ assert_equal "Lifo", lifo.name
+ assert lifo.new_record?
+
+ assert_equal authors(:david), authors.find_or_initialize_by_name(:name => 'David')
+ end
+
+ def test_dynamic_find_or_create_by_attributes
+ authors = Author.scoped
+
+ lifo = authors.find_or_create_by_name('Lifo')
+ assert_equal "Lifo", lifo.name
+ assert ! lifo.new_record?
+
+ assert_equal authors(:david), authors.find_or_create_by_name(:name => 'David')
+ end
+
+ def test_find_id
+ authors = Author.scoped
+
+ david = authors.find(authors(:david).id)
+ assert_equal 'David', david.name
+
+ assert_raises(ActiveRecord::RecordNotFound) { authors.where(:name => 'lifo').find('invalid') }
+ end
+
+ def test_find_ids
+ authors = Author.order('id ASC')
+
+ results = authors.find(authors(:david).id, authors(:mary).id)
+ assert_kind_of Array, results
+ assert_equal 2, results.size
+ assert_equal 'David', results[0].name
+ assert_equal 'Mary', results[1].name
+ assert_equal results, authors.find([authors(:david).id, authors(:mary).id])
+
+ assert_raises(ActiveRecord::RecordNotFound) { authors.where(:name => 'lifo').find(authors(:david).id, 'invalid') }
+ assert_raises(ActiveRecord::RecordNotFound) { authors.find(['invalid', 'oops']) }
+ end
+
+end
diff --git a/activerecord/test/cases/yaml_serialization_test.rb b/activerecord/test/cases/yaml_serialization_test.rb
new file mode 100644
index 0000000000..f221def6b6
--- /dev/null
+++ b/activerecord/test/cases/yaml_serialization_test.rb
@@ -0,0 +1,11 @@
+require "cases/helper"
+require 'models/topic'
+
+class YamlSerializationTest < ActiveRecord::TestCase
+ def test_to_yaml_with_time_with_zone_should_not_raise_exception
+ Time.zone = ActiveSupport::TimeZone["Pacific Time (US & Canada)"]
+ ActiveRecord::Base.time_zone_aware_attributes = true
+ topic = Topic.new(:written_on => DateTime.now)
+ assert_nothing_raised { topic.to_yaml }
+ end
+end
diff --git a/activeresource/Rakefile b/activeresource/Rakefile
index 6566e84d4c..9fa1f86914 100644
--- a/activeresource/Rakefile
+++ b/activeresource/Rakefile
@@ -27,11 +27,8 @@ task :default => [ :test ]
# Run the unit tests
Rake::TestTask.new { |t|
- activesupport_path = "#{File.dirname(__FILE__)}/../activesupport/lib"
- t.libs << activesupport_path if File.directory?(activesupport_path)
t.libs << "test"
t.pattern = 'test/**/*_test.rb'
- t.verbose = true
t.warning = true
}
diff --git a/activeresource/lib/active_resource.rb b/activeresource/lib/active_resource.rb
index fd4c199b48..3e4a1dd4a1 100644
--- a/activeresource/lib/active_resource.rb
+++ b/activeresource/lib/active_resource.rb
@@ -21,20 +21,24 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
-activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
-$:.unshift(activesupport_path) if File.directory?(activesupport_path)
-require 'active_support'
+activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
+$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
+
+activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__)
+$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path)
-activemodel_path = "#{File.dirname(__FILE__)}/../../activemodel/lib"
-$:.unshift(activemodel_path) if File.directory?(activemodel_path)
+require 'active_support'
require 'active_model'
module ActiveResource
- autoload :Base, 'active_resource/base'
- autoload :Connection, 'active_resource/connection'
- autoload :CustomMethods, 'active_resource/custom_methods'
- autoload :Formats, 'active_resource/formats'
- autoload :Observing, 'active_resource/observing'
- autoload :Validations, 'active_resource/validations'
- autoload :HttpMock, 'active_resource/http_mock'
+ extend ActiveSupport::Autoload
+
+ autoload :Base
+ autoload :Connection
+ autoload :CustomMethods
+ autoload :Formats
+ autoload :HttpMock
+ autoload :Observing
+ autoload :Schema
+ autoload :Validations
end
diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb
index 18105e8887..a6243e7011 100644
--- a/activeresource/lib/active_resource/base.rb
+++ b/activeresource/lib/active_resource/base.rb
@@ -13,6 +13,9 @@ require 'set'
require 'uri'
require 'active_resource/exceptions'
+require 'active_resource/connection'
+require 'active_resource/formats'
+require 'active_resource/schema'
module ActiveResource
# ActiveResource::Base is the main class for mapping RESTful resources as models in a Rails application.
@@ -241,6 +244,124 @@ module ActiveResource
cattr_accessor :logger
class << self
+ # Creates a schema for this resource - setting the attributes that are
+ # known prior to fetching an instance from the remote system.
+ #
+ # The schema helps define the set of <tt>known_attributes</tt> of the
+ # current resource.
+ #
+ # There is no need to specify a schema for your Active Resource. If
+ # you do not, the <tt>known_attributes</tt> will be guessed from the
+ # instance attributes returned when an instance is fetched from the
+ # remote system.
+ #
+ # example:
+ # class Person < ActiveResource::Base
+ # schema do
+ # # define each attribute separately
+ # attribute 'name', :string
+ #
+ # # or use the convenience methods and pass >=1 attribute names
+ # string 'eye_colour', 'hair_colour'
+ # integer 'age'
+ # float 'height', 'weight'
+ #
+ # # unsupported types should be left as strings
+ # # overload the accessor methods if you need to convert them
+ # attribute 'created_at', 'string'
+ # end
+ # end
+ #
+ # p = Person.new
+ # p.respond_to? :name # => true
+ # p.respond_to? :age # => true
+ # p.name # => nil
+ # p.age # => nil
+ #
+ # j = Person.find_by_name('John') # <person><name>John</name><age>34</age><num_children>3</num_children></person>
+ # j.respond_to? :name # => true
+ # j.respond_to? :age # => true
+ # j.name # => 'John'
+ # j.age # => '34' # note this is a string!
+ # j.num_children # => '3' # note this is a string!
+ #
+ # p.num_children # => NoMethodError
+ #
+ # Attribute-types must be one of:
+ # string, integer, float
+ #
+ # Note: at present the attribute-type doesn't do anything, but stay
+ # tuned...
+ # Shortly it will also *cast* the value of the returned attribute.
+ # ie:
+ # j.age # => 34 # cast to an integer
+ # j.weight # => '65' # still a string!
+ #
+ def schema(&block)
+ if block_given?
+ schema_definition = Schema.new
+ schema_definition.instance_eval(&block)
+
+ # skip out if we didn't define anything
+ return unless schema_definition.attrs.present?
+
+ @schema ||= {}.with_indifferent_access
+ @known_attributes ||= []
+
+ schema_definition.attrs.each do |k,v|
+ @schema[k] = v
+ @known_attributes << k
+ end
+
+ schema
+ else
+ @schema ||= nil
+ end
+ end
+
+ # Alternative, direct way to specify a <tt>schema</tt> for this
+ # Resource. <tt>schema</tt> is more flexible, but this is quick
+ # for a very simple schema.
+ #
+ # Pass the schema as a hash with the keys being the attribute-names
+ # and the value being one of the accepted attribute types (as defined
+ # in <tt>schema</tt>)
+ #
+ # example:
+ #
+ # class Person < ActiveResource::Base
+ # schema = {'name' => :string, 'age' => :integer }
+ # end
+ #
+ # The keys/values can be strings or symbols. They will be converted to
+ # strings.
+ #
+ def schema=(the_schema)
+ unless the_schema.present?
+ # purposefully nulling out the schema
+ @schema = nil
+ @known_attributes = []
+ return
+ end
+
+ raise ArgumentError, "Expected a hash" unless the_schema.kind_of? Hash
+
+ schema do
+ the_schema.each {|k,v| attribute(k,v) }
+ end
+ end
+
+ # Returns the list of known attributes for this resource, gathered
+ # from the provided <tt>schema</tt>
+ # Attributes that are known will cause your resource to return 'true'
+ # when <tt>respond_to?</tt> is called on them. A known attribute will
+ # return nil if not set (rather than <t>MethodNotFound</tt>); thus
+ # known attributes can be used with <tt>validates_presence_of</tt>
+ # without a getter-method.
+ def known_attributes
+ @known_attributes ||= []
+ end
+
# Gets the URI of the REST resources to map for this class. The site variable is required for
# Active Resource's mapping to work.
def site
@@ -776,6 +897,21 @@ module ActiveResource
attr_accessor :attributes #:nodoc:
attr_accessor :prefix_options #:nodoc:
+ # If no schema has been defined for the class (see
+ # <tt>ActiveResource::schema=</tt>), the default automatic schema is
+ # generated from the current instance's attributes
+ def schema
+ self.class.schema || self.attributes
+ end
+
+ # This is a list of known attributes for this resource. Either
+ # gathered fromthe provided <tt>schema</tt>, or from the attributes
+ # set on this instance after it has been fetched from the remote system.
+ def known_attributes
+ self.class.known_attributes + self.attributes.keys.map(&:to_s)
+ end
+
+
# Constructor method for \new resources; the optional +attributes+ parameter takes a \hash
# of attributes for the \new resource.
#
@@ -1157,7 +1293,7 @@ module ActiveResource
method_name = method.to_s
if attributes.nil?
super
- elsif attributes.has_key?(method_name)
+ elsif known_attributes.include?(method_name)
true
elsif method_name =~ /(?:=|\?)$/ && attributes.include?($`)
true
@@ -1262,7 +1398,10 @@ module ActiveResource
attributes[$`]
end
else
- attributes.include?(method_name) ? attributes[method_name] : super
+ return attributes[method_name] if attributes.include?(method_name)
+ # not set right now but we know about it
+ return nil if known_attributes.include?(method_name)
+ super
end
end
end
diff --git a/activeresource/lib/active_resource/schema.rb b/activeresource/lib/active_resource/schema.rb
new file mode 100644
index 0000000000..8368b652c2
--- /dev/null
+++ b/activeresource/lib/active_resource/schema.rb
@@ -0,0 +1,55 @@
+require 'active_resource/exceptions'
+
+module ActiveResource # :nodoc:
+ class Schema # :nodoc:
+ # attributes can be known to be one of these types. They are easy to
+ # cast to/from.
+ KNOWN_ATTRIBUTE_TYPES = %w( string integer float )
+
+ # An array of attribute definitions, representing the attributes that
+ # have been defined.
+ attr_accessor :attrs
+
+ # The internals of an Active Resource Schema are very simple -
+ # unlike an Active Record TableDefinition (on which it is based).
+ # It provides a set of convenience methods for people to define their
+ # schema using the syntax:
+ # schema do
+ # string :foo
+ # integer :bar
+ # end
+ #
+ # The schema stores the name and type of each attribute. That is then
+ # read out by the schema method to populate the actual
+ # Resource's schema
+ def initialize
+ @attrs = {}
+ end
+
+ def attribute(name, type, options = {})
+ raise ArgumentError, "Unknown Attribute type: #{type.inspect} for key: #{name.inspect}" unless type.nil? || Schema::KNOWN_ATTRIBUTE_TYPES.include?(type.to_s)
+
+ the_type = type.to_s
+ # TODO: add defaults
+ #the_attr = [type.to_s]
+ #the_attr << options[:default] if options.has_key? :default
+ @attrs[name.to_s] = the_type
+ self
+ end
+
+ # The following are the attribute types supported by Active Resource
+ # migrations.
+ # TODO: We should eventually support all of these:
+ # %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |attr_type|
+ KNOWN_ATTRIBUTE_TYPES.each do |attr_type|
+ class_eval <<-EOV
+ def #{attr_type.to_s}(*args)
+ options = args.extract_options!
+ attr_names = args
+
+ attr_names.each { |name| attribute(name, '#{attr_type}', options) }
+ end
+ EOV
+ end
+ end
+end
diff --git a/activeresource/test/abstract_unit.rb b/activeresource/test/abstract_unit.rb
index 10849be20c..5fa6d3023b 100644
--- a/activeresource/test/abstract_unit.rb
+++ b/activeresource/test/abstract_unit.rb
@@ -1,18 +1,17 @@
-root = File.expand_path('../../..', __FILE__)
begin
- require "#{root}/vendor/gems/environment"
+ require File.expand_path('../../../vendor/gems/environment', __FILE__)
rescue LoadError
- $:.unshift("#{root}/activesupport/lib")
end
-lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
+lib = File.expand_path('../../lib', __FILE__)
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
require 'rubygems'
require 'test/unit'
+require 'active_resource'
require 'active_support'
require 'active_support/test_case'
-require 'active_resource'
+require 'active_model/test_case'
$:.unshift "#{File.dirname(__FILE__)}/../test"
require 'setter_trap'
diff --git a/activeresource/test/cases/base/schema_test.rb b/activeresource/test/cases/base/schema_test.rb
new file mode 100644
index 0000000000..d9dc679941
--- /dev/null
+++ b/activeresource/test/cases/base/schema_test.rb
@@ -0,0 +1,420 @@
+require 'abstract_unit'
+require 'active_support/core_ext/hash/conversions'
+require "fixtures/person"
+require "fixtures/street_address"
+
+########################################################################
+# Testing the schema of your Active Resource models
+########################################################################
+class SchemaTest < ActiveModel::TestCase
+ def setup
+ @matz = { :id => 1, :name => 'Matz' }.to_xml(:root => 'person')
+ @david = { :id => 2, :name => 'David' }.to_xml(:root => 'person')
+ @greg = { :id => 3, :name => 'Greg' }.to_xml(:root => 'person')
+ @addy = { :id => 1, :street => '12345 Street', :country => 'Australia' }.to_xml(:root => 'address')
+ @default_request_headers = { 'Content-Type' => 'application/xml' }
+ @rick = { :name => "Rick", :age => 25 }.to_xml(:root => "person")
+ @people = [{ :id => 1, :name => 'Matz' }, { :id => 2, :name => 'David' }].to_xml(:root => 'people')
+ @people_david = [{ :id => 2, :name => 'David' }].to_xml(:root => 'people')
+ @addresses = [{ :id => 1, :street => '12345 Street', :country => 'Australia' }].to_xml(:root => 'addresses')
+
+ ActiveResource::HttpMock.respond_to do |mock|
+ mock.get "/people/1.xml", {}, @matz
+ mock.get "/people/2.xml", {}, @david
+ mock.get "/people/Greg.xml", {}, @greg
+ mock.get "/people/4.xml", {'key' => 'value'}, nil, 404
+ mock.get "/people/5.xml", {}, @rick
+ mock.put "/people/1.xml", {}, nil, 204
+ mock.delete "/people/1.xml", {}, nil, 200
+ mock.delete "/people/2.xml", {}, nil, 400
+ mock.get "/people/99.xml", {}, nil, 404
+ mock.post "/people.xml", {}, @rick, 201, 'Location' => '/people/5.xml'
+ mock.get "/people.xml", {}, @people
+ mock.get "/people/1/addresses.xml", {}, @addresses
+ mock.get "/people/1/addresses/1.xml", {}, @addy
+ mock.get "/people/1/addresses/2.xml", {}, nil, 404
+ mock.get "/people/2/addresses/1.xml", {}, nil, 404
+ mock.get "/people/Greg/addresses/1.xml", {}, @addy
+ mock.put "/people/1/addresses/1.xml", {}, nil, 204
+ mock.delete "/people/1/addresses/1.xml", {}, nil, 200
+ mock.post "/people/1/addresses.xml", {}, nil, 201, 'Location' => '/people/1/addresses/5'
+ mock.get "/people//addresses.xml", {}, nil, 404
+ mock.get "/people//addresses/1.xml", {}, nil, 404
+ mock.put "/people//addressaddresseses/1.xml", {}, nil, 404
+ mock.delete "/people//addresses/1.xml", {}, nil, 404
+ mock.post "/people//addresses.xml", {}, nil, 404
+ mock.head "/people/1.xml", {}, nil, 200
+ mock.head "/people/Greg.xml", {}, nil, 200
+ mock.head "/people/99.xml", {}, nil, 404
+ mock.head "/people/1/addresses/1.xml", {}, nil, 200
+ mock.head "/people/1/addresses/2.xml", {}, nil, 404
+ mock.head "/people/2/addresses/1.xml", {}, nil, 404
+ mock.head "/people/Greg/addresses/1.xml", {}, nil, 200
+ end
+
+ Person.user = nil
+ Person.password = nil
+ end
+ def teardown
+ Person.schema = nil # hack to stop test bleedthrough...
+ end
+
+
+ #####################################################
+ # Passing in a schema directly and returning it
+ ####
+
+ test "schema on a new model should be empty" do
+ assert Person.schema.blank?, "should have a blank class schema"
+ assert Person.new.schema.blank?, "should have a blank instance schema"
+ end
+
+ test "schema should only accept a hash" do
+ ["blahblah", ['one','two'], [:age, :name], Person.new].each do |bad_schema|
+ assert_raises(ArgumentError,"should only accept a hash (or nil), but accepted: #{bad_schema.inspect}") do
+ Person.schema = bad_schema
+ end
+ end
+ end
+
+ test "schema should accept a simple hash" do
+ new_schema = {'age' => 'integer', 'name' => 'string'}
+
+ assert_nothing_raised { Person.schema = new_schema }
+ assert_equal new_schema, Person.schema
+ end
+
+ test "schema should accept a hash with simple values" do
+ new_schema = {'age' => 'integer', 'name' => 'string', 'height' => 'float', 'mydatetime' => 'string'}
+
+ assert_nothing_raised { Person.schema = new_schema }
+ assert_equal new_schema, Person.schema
+ end
+
+ test "schema should accept all known attribute types as values" do
+ # I'd prefer to use here...
+ ActiveResource::Schema::KNOWN_ATTRIBUTE_TYPES.each do |the_type|
+ assert_nothing_raised("should have accepted #{the_type.inspect}"){ Person.schema = {'my_key' => the_type }}
+ end
+ end
+
+ test "schema should not accept unknown values" do
+ bad_values = [ :oogle, :blob, 'thing']
+
+ bad_values.each do |bad_value|
+ assert_raises(ArgumentError,"should only accept a known attribute type, but accepted: #{bad_value.inspect}") do
+ Person.schema = {'key' => bad_value}
+ end
+ end
+ end
+
+ test "schema should accept nil and remove the schema" do
+ new_schema = {'age' => 'integer', 'name' => 'string'}
+ assert_nothing_raised { Person.schema = new_schema }
+ assert_equal new_schema, Person.schema # sanity check
+
+
+ assert_nothing_raised { Person.schema = nil }
+ assert_nil Person.schema, "should have nulled out the schema, but still had: #{Person.schema.inspect}"
+ end
+
+
+ test "schema should be with indifferent access" do
+ new_schema = {:age => :integer, 'name' => 'string'}
+ new_schema_syms = new_schema.keys
+
+ assert_nothing_raised { Person.schema = new_schema }
+ new_schema_syms.each do |col|
+ assert Person.new.respond_to?(col.to_s), "should respond to the schema's string key, but failed on: #{col.to_s}"
+ assert Person.new.respond_to?(col.to_sym), "should respond to the schema's symbol key, but failed on: #{col.to_sym}"
+ end
+ end
+
+
+ test "schema on a fetched resource should return all the attributes of that model instance" do
+ p = Person.find(1)
+ s = p.schema
+
+ assert s.present?, "should have found a non-empty schema!"
+
+ p.attributes.each do |the_attr, val|
+ assert s.has_key?(the_attr), "should have found attr: #{the_attr} in schema, but only had: #{s.inspect}"
+ end
+ end
+
+ test "with two instances, default schema should match the attributes of the individual instances - even if they differ" do
+ matz = Person.find(1)
+ rick = Person.find(5)
+
+ m_attrs = matz.attributes.keys.sort
+ r_attrs = rick.attributes.keys.sort
+
+ assert_not_equal m_attrs, r_attrs, "should have different attributes on each model"
+
+ assert_not_equal matz.schema, rick.schema, "should have had different schemas too"
+ end
+
+ test "defining a schema should return it when asked" do
+ assert Person.schema.blank?, "should have a blank class schema"
+ new_schema = {'name' => 'string', 'age' => 'integer', 'height' => 'float', 'weight' => 'float'}
+ assert_nothing_raised {
+ Person.schema = new_schema
+ assert_equal new_schema, Person.schema, "should have saved the schema on the class"
+ assert_equal new_schema, Person.new.schema, "should have mde the schema available to every instance"
+ }
+ end
+
+ test "defining a schema, then fetching a model should still match the defined schema" do
+ # sanity checks
+ assert Person.schema.blank?, "should have a blank class schema"
+ new_schema = {'name' => 'string', 'age' => 'integer', 'height' => 'float', 'weight' => 'float'}
+
+ matz = Person.find(1)
+ assert !matz.schema.blank?, "should have some sort of schema on an instance variable"
+ assert_not_equal new_schema, matz.schema, "should not have the class-level schema until it's been added to the class!"
+
+ assert_nothing_raised {
+ Person.schema = new_schema
+ assert_equal new_schema, matz.schema, "class-level schema should override instance-level schema"
+ }
+ end
+
+
+ #####################################################
+ # Using the schema syntax
+ ####
+
+ test "should be able to use schema" do
+ assert Person.respond_to?(:schema), "should at least respond to the schema method"
+
+ assert_nothing_raised("Should allow the schema to take a block") do
+ Person.schema { }
+ end
+ end
+
+ test "schema definition should store and return attribute set" do
+ assert_nothing_raised do
+ s = nil
+ Person.schema do
+ s = self
+ attribute :foo, :string
+ end
+ assert s.respond_to?(:attrs), "should return attributes in theory"
+ assert_equal({'foo' => 'string' }, s.attrs, "should return attributes in practice")
+ end
+ end
+
+ test "should be able to add attributes through schema" do
+ assert_nothing_raised do
+ s = nil
+ Person.schema do
+ s = self
+ attribute('foo', 'string')
+ end
+ assert s.attrs.has_key?('foo'), "should have saved the attribute name"
+ assert_equal 'string', s.attrs['foo'], "should have saved the attribute type"
+ end
+ end
+
+ test "should convert symbol attributes to strings" do
+ assert_nothing_raised do
+ s = nil
+ Person.schema do
+ attribute(:foo, :integer)
+ s = self
+ end
+
+ assert s.attrs.has_key?('foo'), "should have saved the attribute name as a string"
+ assert_equal 'integer', s.attrs['foo'], "should have saved the attribute type as a string"
+ end
+ end
+
+ test "should be able to add all known attribute types" do
+ assert_nothing_raised do
+ ActiveResource::Schema::KNOWN_ATTRIBUTE_TYPES.each do |the_type|
+ s = nil
+ Person.schema do
+ s = self
+ attribute('foo', the_type)
+ end
+ assert s.attrs.has_key?('foo'), "should have saved the attribute name"
+ assert_equal the_type.to_s, s.attrs['foo'], "should have saved the attribute type of: #{the_type}"
+ end
+ end
+ end
+
+ test "attributes should not accept unknown values" do
+ bad_values = [ :oogle, :blob, 'thing']
+
+ bad_values.each do |bad_value|
+ s = nil
+ assert_raises(ArgumentError,"should only accept a known attribute type, but accepted: #{bad_value.inspect}") do
+ Person.schema do
+ s = self
+ attribute 'key', bad_value
+ end
+ end
+ assert !self.respond_to?(bad_value), "should only respond to a known attribute type, but accepted: #{bad_value.inspect}"
+ assert_raises(NoMethodError,"should only have methods for known attribute types, but accepted: #{bad_value.inspect}") do
+ Person.schema do
+ send bad_value, 'key'
+ end
+ end
+ end
+ end
+
+
+ test "should accept attribute types as the type's name as the method" do
+ ActiveResource::Schema::KNOWN_ATTRIBUTE_TYPES.each do |the_type|
+ s = nil
+ Person.schema do
+ s = self
+ send(the_type,'foo')
+ end
+ assert s.attrs.has_key?('foo'), "should now have saved the attribute name"
+ assert_equal the_type.to_s, s.attrs['foo'], "should have saved the attribute type of: #{the_type}"
+ end
+ end
+
+ test "should accept multiple attribute names for an attribute method" do
+ names = ['foo','bar','baz']
+ s = nil
+ Person.schema do
+ s = self
+ string(*names)
+ end
+ names.each do |the_name|
+ assert s.attrs.has_key?(the_name), "should now have saved the attribute name: #{the_name}"
+ assert_equal 'string', s.attrs[the_name], "should have saved the attribute as a string"
+ end
+ end
+
+ #####################################################
+ # What a schema does for us
+ ####
+
+ # respond_to?
+
+ test "should respond positively to attributes that are only in the schema" do
+ new_attr_name = :my_new_schema_attribute
+ new_attr_name_two = :another_new_schema_attribute
+ assert Person.schema.blank?, "sanity check - should have a blank class schema"
+
+ assert !Person.new.respond_do?(new_attr_name), "sanity check - should not respond to the brand-new attribute yet"
+ assert !Person.new.respond_do?(new_attr_name_two), "sanity check - should not respond to the brand-new attribute yet"
+
+ assert_nothing_raised do
+ Person.schema = {new_attr_name.to_s => 'string'}
+ Person.schema { string new_attr_name_two }
+ end
+
+ assert Person.new.respond_to?(new_attr_name), "should respond to the attribute in a passed-in schema, but failed on: #{new_attr_name}"
+ assert Person.new.respond_to?(new_attr_name_two), "should respond to the attribute from the schema, but failed on: #{new_attr_name_two}"
+ end
+
+ test "should not care about ordering of schema definitions" do
+ new_attr_name = :my_new_schema_attribute
+ new_attr_name_two = :another_new_schema_attribute
+
+ assert Person.schema.blank?, "sanity check - should have a blank class schema"
+
+ assert !Person.new.respond_do?(new_attr_name), "sanity check - should not respond to the brand-new attribute yet"
+ assert !Person.new.respond_do?(new_attr_name_two), "sanity check - should not respond to the brand-new attribute yet"
+
+ assert_nothing_raised do
+ Person.schema { string new_attr_name_two }
+ Person.schema = {new_attr_name.to_s => 'string'}
+ end
+
+ assert Person.new.respond_to?(new_attr_name), "should respond to the attribute in a passed-in schema, but failed on: #{new_attr_name}"
+ assert Person.new.respond_to?(new_attr_name_two), "should respond to the attribute from the schema, but failed on: #{new_attr_name_two}"
+ end
+
+ # method_missing effects
+
+ test "should not give method_missing for attribute only in schema" do
+ new_attr_name = :another_new_schema_attribute
+ new_attr_name_two = :another_new_schema_attribute
+
+ assert Person.schema.blank?, "sanity check - should have a blank class schema"
+
+ assert_raises(NoMethodError, "should not have found the attribute: #{new_attr_name} as a method") do
+ Person.new.send(new_attr_name)
+ end
+ assert_raises(NoMethodError, "should not have found the attribute: #{new_attr_name_two} as a method") do
+ Person.new.send(new_attr_name_two)
+ end
+
+ Person.schema = {new_attr_name.to_s => :float}
+ Person.schema { string new_attr_name_two }
+
+ assert_nothing_raised do
+ Person.new.send(new_attr_name)
+ Person.new.send(new_attr_name_two)
+ end
+ end
+
+
+ ########
+ # Known attributes
+ #
+ # Attributes can be known to be attributes even if they aren't actually
+ # 'set' on a particular instance.
+ # This will only differ from 'attributes' if a schema has been set.
+
+ test "new model should have no known attributes" do
+ assert Person.known_attributes.blank?, "should have no known attributes"
+ assert Person.new.known_attributes.blank?, "should have no known attributes on a new instance"
+ end
+
+ test "setting schema should set known attributes on class and instance" do
+ new_schema = {'age' => 'integer', 'name' => 'string'}
+
+ assert_nothing_raised { Person.schema = new_schema }
+
+ assert_equal new_schema.keys, Person.known_attributes
+ assert_equal new_schema.keys, Person.new.known_attributes
+ end
+
+ test "known attributes on a fetched resource should return all the attributes of the instance" do
+ p = Person.find(1)
+ attrs = p.known_attributes
+
+ assert attrs.present?, "should have found some attributes!"
+
+ p.attributes.each do |the_attr, val|
+ assert attrs.include?(the_attr), "should have found attr: #{the_attr} in known attributes, but only had: #{attrs.inspect}"
+ end
+ end
+
+ test "with two instances, known attributes should match the attributes of the individual instances - even if they differ" do
+ matz = Person.find(1)
+ rick = Person.find(5)
+
+ m_attrs = matz.attributes.keys.sort
+ r_attrs = rick.attributes.keys.sort
+
+ assert_not_equal m_attrs, r_attrs, "should have different attributes on each model"
+
+ assert_not_equal matz.known_attributes, rick.known_attributes, "should have had different known attributes too"
+ end
+
+ test "setting schema then fetching should add schema attributes to the intance attributes" do
+ # an attribute in common with fetched instance and one that isn't
+ new_schema = {'name' => 'string', 'my_strange_attribute' => 'string'}
+
+ assert_nothing_raised { Person.schema = new_schema }
+
+ matz = Person.find(1)
+ known_attrs = matz.known_attributes
+
+ matz.attributes.keys.each do |the_attr|
+ assert known_attrs.include?(the_attr), "should have found instance attr: #{the_attr} in known attributes, but only had: #{known_attrs.inspect}"
+ end
+ new_schema.keys.each do |the_attr|
+ assert known_attrs.include?(the_attr), "should have found schema attr: #{the_attr} in known attributes, but only had: #{known_attrs.inspect}"
+ end
+ end
+
+
+end
diff --git a/activeresource/test/cases/base_test.rb b/activeresource/test/cases/base_test.rb
index 1d3f7891ec..91349b810a 100644
--- a/activeresource/test/cases/base_test.rb
+++ b/activeresource/test/cases/base_test.rb
@@ -543,9 +543,9 @@ class BaseTest < Test::Unit::TestCase
assert Person.collection_path(:gender => 'male', :student => true).include?('gender=male')
assert Person.collection_path(:gender => 'male', :student => true).include?('student=true')
- assert_equal '/people.xml?name%5B%5D=bob&name%5B%5D=your+uncle%2Bme&name%5B%5D=&name%5B%5D=false', Person.collection_path(:name => ['bob', 'your uncle+me', nil, false])
+ assert_equal '/people.xml?name[]=bob&name[]=your+uncle%2Bme&name[]=&name[]=false', Person.collection_path(:name => ['bob', 'your uncle+me', nil, false])
- assert_equal '/people.xml?struct%5Ba%5D%5B%5D=2&struct%5Ba%5D%5B%5D=1&struct%5Bb%5D=fred', Person.collection_path(:struct => {:a => [2,1], 'b' => 'fred'})
+ assert_equal '/people.xml?struct[a][]=2&struct[a][]=1&struct[b]=fred', Person.collection_path(:struct => {:a => [2,1], 'b' => 'fred'})
end
def test_custom_element_path
@@ -581,7 +581,7 @@ class BaseTest < Test::Unit::TestCase
assert_equal '/people/1/addresses/1.xml?type=work', StreetAddress.element_path(1, :person_id => 1, :type => 'work')
assert_equal '/people/1/addresses/1.xml?type=work', StreetAddress.element_path(1, 'person_id' => 1, :type => 'work')
assert_equal '/people/1/addresses/1.xml?type=work', StreetAddress.element_path(1, :type => 'work', :person_id => 1)
- assert_equal '/people/1/addresses/1.xml?type%5B%5D=work&type%5B%5D=play+time', StreetAddress.element_path(1, :person_id => 1, :type => ['work', 'play time'])
+ assert_equal '/people/1/addresses/1.xml?type[]=work&type[]=play+time', StreetAddress.element_path(1, :person_id => 1, :type => ['work', 'play time'])
end
def test_custom_element_path_with_prefix_and_parameters
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index 4edeadf10c..cc4a2ff90e 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -1,5 +1,7 @@
*Edge*
+* Add Enumerable#exclude? to bring parity to Enumerable#include? and avoid if !x.include?/else calls [DHH]
+
* Update Edinburgh TimeZone to use "Europe/London" instead of "Europe/Dublin" #3310 [Phil Ross]
* Update bundled TZInfo to v0.3.15 [Geoff Buesing]
diff --git a/activesupport/Rakefile b/activesupport/Rakefile
index 2ada91830f..08af1d6fca 100644
--- a/activesupport/Rakefile
+++ b/activesupport/Rakefile
@@ -18,7 +18,6 @@ task :default => :test
Rake::TestTask.new do |t|
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
- t.verbose = true
t.warning = true
end
diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb
index 0478ae4ebc..f2baa5a56a 100644
--- a/activesupport/lib/active_support.rb
+++ b/activesupport/lib/active_support.rb
@@ -34,7 +34,41 @@ module ActiveSupport
end
end
-require 'active_support/autoload'
+require "active_support/dependencies/autoload"
+
+module ActiveSupport
+ extend ActiveSupport::Autoload
+
+ # TODO: Narrow this list down
+ eager_autoload do
+ autoload :BacktraceCleaner
+ autoload :Base64
+ autoload :BasicObject
+ autoload :Benchmarkable
+ autoload :BufferedLogger
+ autoload :Cache
+ autoload :Callbacks
+ autoload :Concern
+ autoload :Configurable
+ autoload :DeprecatedCallbacks
+ autoload :Deprecation
+ autoload :Gzip
+ autoload :Inflector
+ autoload :Memoizable
+ autoload :MessageEncryptor
+ autoload :MessageVerifier
+ autoload :Multibyte
+ autoload :OptionMerger
+ autoload :OrderedHash
+ autoload :OrderedOptions
+ autoload :Notifications
+ autoload :Rescuable
+ autoload :SecureRandom
+ autoload :StringInquirer
+ autoload :XmlMini
+ end
+end
+
require 'active_support/vendor'
require 'i18n'
diff --git a/activesupport/lib/active_support/autoload.rb b/activesupport/lib/active_support/autoload.rb
deleted file mode 100644
index 63f7338a68..0000000000
--- a/activesupport/lib/active_support/autoload.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-module ActiveSupport
- autoload :BacktraceCleaner, 'active_support/backtrace_cleaner'
- autoload :Base64, 'active_support/base64'
- autoload :BasicObject, 'active_support/basic_object'
- autoload :Benchmarkable, 'active_support/benchmarkable'
- autoload :BufferedLogger, 'active_support/buffered_logger'
- autoload :Cache, 'active_support/cache'
- autoload :Callbacks, 'active_support/callbacks'
- autoload :Concern, 'active_support/concern'
- autoload :Configurable, 'active_support/configurable'
- autoload :DependencyModule, 'active_support/dependency_module'
- autoload :DeprecatedCallbacks, 'active_support/deprecated_callbacks'
- autoload :Deprecation, 'active_support/deprecation'
- autoload :Gzip, 'active_support/gzip'
- autoload :Inflector, 'active_support/inflector'
- autoload :Memoizable, 'active_support/memoizable'
- autoload :MessageEncryptor, 'active_support/message_encryptor'
- autoload :MessageVerifier, 'active_support/message_verifier'
- autoload :Multibyte, 'active_support/multibyte'
- autoload :OptionMerger, 'active_support/option_merger'
- autoload :OrderedHash, 'active_support/ordered_hash'
- autoload :OrderedOptions, 'active_support/ordered_options'
- autoload :Notifications, 'active_support/notifications'
- autoload :Rescuable, 'active_support/rescuable'
- autoload :SecureRandom, 'active_support/secure_random'
- autoload :StringInquirer, 'active_support/string_inquirer'
- autoload :XmlMini, 'active_support/xml_mini'
-end
diff --git a/activesupport/lib/active_support/core_ext/class/removal.rb b/activesupport/lib/active_support/core_ext/class/removal.rb
index 2dea3c24d5..652be4ed78 100644
--- a/activesupport/lib/active_support/core_ext/class/removal.rb
+++ b/activesupport/lib/active_support/core_ext/class/removal.rb
@@ -2,7 +2,11 @@ require 'active_support/core_ext/object/extending'
require 'active_support/core_ext/module/introspection'
class Class #:nodoc:
-
+
+ def reachable?
+ eval("defined?(::#{self}) && ::#{self}.equal?(self)")
+ end
+
# Unassociates the class with its subclasses and removes the subclasses
# themselves.
#
diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb
index 3dd61334d0..2b76b93153 100644
--- a/activesupport/lib/active_support/core_ext/date/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date/calculations.rb
@@ -1,3 +1,4 @@
+require 'date'
require 'active_support/duration'
require 'active_support/core_ext/time/zones'
diff --git a/activesupport/lib/active_support/core_ext/date/conversions.rb b/activesupport/lib/active_support/core_ext/date/conversions.rb
index f6c870035b..90ab1eb281 100644
--- a/activesupport/lib/active_support/core_ext/date/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/date/conversions.rb
@@ -1,3 +1,4 @@
+require 'date'
require 'active_support/inflector'
class Date
diff --git a/activesupport/lib/active_support/core_ext/date_time/conversions.rb b/activesupport/lib/active_support/core_ext/date_time/conversions.rb
index 5f01bc4fd6..47a31839a6 100644
--- a/activesupport/lib/active_support/core_ext/date_time/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/conversions.rb
@@ -78,7 +78,18 @@ class DateTime
# Converts self to a floating-point number of seconds since the Unix epoch
def to_f
- days_since_unix_epoch = self - ::DateTime.civil(1970)
- (days_since_unix_epoch * 86_400).to_f
+ seconds_since_unix_epoch.to_f
+ end
+
+ # Converts self to an integer number of seconds since the Unix epoch
+ def to_i
+ seconds_since_unix_epoch.to_i
+ end
+
+ private
+
+ def seconds_since_unix_epoch
+ seconds_per_day = 86_400
+ (self - ::DateTime.civil(1970)) * seconds_per_day
end
end
diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb
index b11c916f61..d0821a7c68 100644
--- a/activesupport/lib/active_support/core_ext/enumerable.rb
+++ b/activesupport/lib/active_support/core_ext/enumerable.rb
@@ -101,6 +101,11 @@ module Enumerable
size = block_given? ? select(&block).size : self.size
size > 1
end
+
+ # The negative of the Enumerable#include?. Returns true if the collection does not include the object.
+ def exclude?(object)
+ !include?(object)
+ end
end
class Range #:nodoc:
diff --git a/activesupport/lib/active_support/core_ext/logger.rb b/activesupport/lib/active_support/core_ext/logger.rb
index e4df8fe338..22749229a3 100644
--- a/activesupport/lib/active_support/core_ext/logger.rb
+++ b/activesupport/lib/active_support/core_ext/logger.rb
@@ -137,10 +137,10 @@ class Logger
attr_writer :formatter
public :formatter=
- alias old_format_datetime format_datetime if method_defined?(:format_datetime)
+ alias old_format_datetime format_datetime
def format_datetime(datetime) datetime end
- alias old_msg2str msg2str if method_defined?(:msg2str)
+ alias old_msg2str msg2str
def msg2str(msg) msg end
end
end
diff --git a/activesupport/lib/active_support/core_ext/object/extending.rb b/activesupport/lib/active_support/core_ext/object/extending.rb
index 0cc74c8298..de8121f274 100644
--- a/activesupport/lib/active_support/core_ext/object/extending.rb
+++ b/activesupport/lib/active_support/core_ext/object/extending.rb
@@ -1,46 +1,53 @@
-class Object
- def remove_subclasses_of(*superclasses) #:nodoc:
- Class.remove_class(*subclasses_of(*superclasses))
- end
-
- begin
- ObjectSpace.each_object(Class.new) {}
-
- # Exclude this class unless it's a subclass of our supers and is defined.
- # We check defined? in case we find a removed class that has yet to be
- # garbage collected. This also fails for anonymous classes -- please
- # submit a patch if you have a workaround.
- def subclasses_of(*superclasses) #:nodoc:
+class Class
+ # Rubinius
+ if defined?(Class.__subclasses__)
+ def descendents
subclasses = []
-
- superclasses.each do |sup|
- ObjectSpace.each_object(class << sup; self; end) do |k|
- if k != sup && (k.name.blank? || eval("defined?(::#{k}) && ::#{k}.object_id == k.object_id"))
- subclasses << k
- end
- end
- end
-
+ __subclasses__.each {|k| subclasses << k; subclasses.concat k.descendents }
subclasses
end
- rescue RuntimeError
- # JRuby and any implementations which cannot handle the objectspace traversal
- # above fall back to this implementation
- def subclasses_of(*superclasses) #:nodoc:
- subclasses = []
+ else
+ # MRI
+ begin
+ ObjectSpace.each_object(Class.new) {}
- superclasses.each do |sup|
+ def descendents
+ subclasses = []
+ ObjectSpace.each_object(class << self; self; end) do |k|
+ subclasses << k unless k == self
+ end
+ subclasses
+ end
+ # JRuby
+ rescue StandardError
+ def descendents
+ subclasses = []
ObjectSpace.each_object(Class) do |k|
- if superclasses.any? { |superclass| k < superclass } &&
- (k.name.blank? || eval("defined?(::#{k}) && ::#{k}.object_id == k.object_id"))
- subclasses << k
- end
+ subclasses << k if k < self
end
subclasses.uniq!
+ subclasses
end
- subclasses
end
end
+end
+
+class Object
+ def remove_subclasses_of(*superclasses) #:nodoc:
+ Class.remove_class(*subclasses_of(*superclasses))
+ end
+
+ # Exclude this class unless it's a subclass of our supers and is defined.
+ # We check defined? in case we find a removed class that has yet to be
+ # garbage collected. This also fails for anonymous classes -- please
+ # submit a patch if you have a workaround.
+ def subclasses_of(*superclasses) #:nodoc:
+ subclasses = []
+ superclasses.each do |klass|
+ subclasses.concat klass.descendents.select {|k| k.name.blank? || k.reachable?}
+ end
+ subclasses
+ end
def extended_by #:nodoc:
ancestors = class << self; ancestors end
diff --git a/activesupport/lib/active_support/core_ext/object/to_param.rb b/activesupport/lib/active_support/core_ext/object/to_param.rb
index a5e2260791..7ca763cbad 100644
--- a/activesupport/lib/active_support/core_ext/object/to_param.rb
+++ b/activesupport/lib/active_support/core_ext/object/to_param.rb
@@ -38,7 +38,7 @@ class Hash
# ==== Examples
# { :name => 'David', :nationality => 'Danish' }.to_query # => "name=David&nationality=Danish"
#
- # { :name => 'David', :nationality => 'Danish' }.to_query('user') # => "user%5Bname%5D=David&user%5Bnationality%5D=Danish"
+ # { :name => 'David', :nationality => 'Danish' }.to_query('user') # => "user[name]=David&user[nationality]=Danish"
def to_param(namespace = nil)
collect do |key, value|
value.to_query(namespace ? "#{namespace}[#{key}]" : key)
diff --git a/activesupport/lib/active_support/core_ext/object/to_query.rb b/activesupport/lib/active_support/core_ext/object/to_query.rb
index 3f1540f685..c9981895b4 100644
--- a/activesupport/lib/active_support/core_ext/object/to_query.rb
+++ b/activesupport/lib/active_support/core_ext/object/to_query.rb
@@ -7,7 +7,7 @@ class Object
# Note: This method is defined as a default implementation for all Objects for Hash#to_query to work.
def to_query(key)
require 'cgi' unless defined?(CGI) && defined?(CGI::escape)
- "#{CGI.escape(key.to_s)}=#{CGI.escape(to_param.to_s)}"
+ "#{CGI.escape(key.to_s).gsub(/%(5B|5D)/n) { [$1].pack('H*') }}=#{CGI.escape(to_param.to_s)}"
end
end
@@ -15,7 +15,7 @@ class Array
# Converts an array into a string suitable for use as a URL query string,
# using the given +key+ as the param name.
#
- # ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"
+ # ['Rails', 'coding'].to_query('hobbies') # => "hobbies[]=Rails&hobbies[]=coding"
def to_query(key)
prefix = "#{key}[]"
collect { |value| value.to_query(prefix) }.join '&'
diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb
index 2cca4763f4..3e6ab0ebd2 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -1,43 +1,29 @@
class String
- def html_safe?
- defined?(@_rails_html_safe) && @_rails_html_safe
- end
+ attr_accessor :_rails_html_safe
+ alias html_safe? _rails_html_safe
def html_safe!
@_rails_html_safe = true
self
end
-
+
def html_safe
dup.html_safe!
end
-
+
alias original_plus +
def +(other)
result = original_plus(other)
- if html_safe? && also_html_safe?(other)
- result.html_safe!
- else
- result
- end
+ result._rails_html_safe = html_safe? && other.html_safe?
+ result
end
-
+
alias original_concat <<
+ alias safe_concat <<
def <<(other)
+ @_rails_html_safe = false unless other.html_safe?
result = original_concat(other)
- unless html_safe? && also_html_safe?(other)
- @_rails_html_safe = false
- end
- result
end
-
- def concat(other)
- self << other
- end
-
- private
- def also_html_safe?(other)
- other.respond_to?(:html_safe?) && other.html_safe?
- end
-
+
+ alias concat <<
end \ No newline at end of file
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index 4f4492f0fd..703b89ffd0 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -1,4 +1,5 @@
require 'active_support/duration'
+require 'active_support/core_ext/date/acts_like'
require 'active_support/core_ext/date/calculations'
class Time
diff --git a/activesupport/lib/active_support/dependencies/autoload.rb b/activesupport/lib/active_support/dependencies/autoload.rb
new file mode 100644
index 0000000000..44edb89ad5
--- /dev/null
+++ b/activesupport/lib/active_support/dependencies/autoload.rb
@@ -0,0 +1,49 @@
+require "active_support/inflector/methods"
+
+module ActiveSupport
+ module Autoload
+ @@autoloads = {}
+ @@under_path = nil
+ @@at_path = nil
+ @@eager_autoload = false
+
+ def autoload(const_name, path = @@at_path)
+ full = [self.name, @@under_path, const_name.to_s, path].compact.join("::")
+ location = path || Inflector.underscore(full)
+
+ if @@eager_autoload
+ @@autoloads[const_name] = location
+ end
+ super const_name, location
+ end
+
+ def autoload_under(path)
+ @@under_path, old_path = path, @@under_path
+ yield
+ ensure
+ @@under_path = old_path
+ end
+
+ def autoload_at(path)
+ @@at_path, old_path = path, @@at_path
+ yield
+ ensure
+ @@at_path = old_path
+ end
+
+ def eager_autoload
+ old_eager, @@eager_autoload = @@eager_autoload, true
+ yield
+ ensure
+ @@eager_autoload = old_eager
+ end
+
+ def self.eager_autoload!
+ @@autoloads.values.each { |file| require file }
+ end
+
+ def autoloads
+ @@autoloads
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb
index 3c15056c41..c8415d5449 100644
--- a/activesupport/lib/active_support/json/encoding.rb
+++ b/activesupport/lib/active_support/json/encoding.rb
@@ -65,6 +65,15 @@ module ActiveSupport
ESCAPED_CHARS = {
+ "\x00" => '\u0000', "\x01" => '\u0001', "\x02" => '\u0002',
+ "\x03" => '\u0003', "\x04" => '\u0004', "\x05" => '\u0005',
+ "\x06" => '\u0006', "\x07" => '\u0007', "\x0B" => '\u000B',
+ "\x0E" => '\u000E', "\x0F" => '\u000F', "\x10" => '\u0010',
+ "\x11" => '\u0011', "\x12" => '\u0012', "\x13" => '\u0013',
+ "\x14" => '\u0014', "\x15" => '\u0015', "\x16" => '\u0016',
+ "\x17" => '\u0017', "\x18" => '\u0018', "\x19" => '\u0019',
+ "\x1A" => '\u001A', "\x1B" => '\u001B', "\x1C" => '\u001C',
+ "\x1D" => '\u001D', "\x1E" => '\u001E', "\x1F" => '\u001F',
"\010" => '\b',
"\f" => '\f',
"\n" => '\n',
@@ -86,9 +95,9 @@ module ActiveSupport
def escape_html_entities_in_json=(value)
self.escape_regex = \
if @escape_html_entities_in_json = value
- /[\010\f\n\r\t"\\><&]/
+ /[\x00-\x1F"\\><&]/
else
- /[\010\f\n\r\t"\\]/
+ /[\x00-\x1F"\\]/
end
end
diff --git a/activesupport/lib/active_support/notifications.rb b/activesupport/lib/active_support/notifications.rb
index e2540cd598..d9bfcbfcab 100644
--- a/activesupport/lib/active_support/notifications.rb
+++ b/activesupport/lib/active_support/notifications.rb
@@ -1,7 +1,4 @@
-require 'thread'
require 'active_support/core_ext/module/delegation'
-require 'active_support/core_ext/module/attribute_accessors'
-require 'active_support/secure_random'
module ActiveSupport
# Notifications provides an instrumentation API for Ruby. To instrument an
@@ -41,173 +38,42 @@ module ActiveSupport
# to subscribers in a thread. You can use any queue implementation you want.
#
module Notifications
- mattr_accessor :queue, :listener
+ autoload :Instrumenter, 'active_support/notifications/instrumenter'
+ autoload :Event, 'active_support/notifications/instrumenter'
+ autoload :Fanout, 'active_support/notifications/fanout'
class << self
- delegate :instrument, :transaction_id, :transaction, :to => :instrumenter
+ attr_writer :notifier
+ delegate :publish, :subscribe, :instrument, :to => :notifier
- def instrumenter
- Thread.current[:notifications_instrumeter] ||= Instrumenter.new(publisher)
- end
-
- def publisher
- @publisher ||= Publisher.new(queue)
- end
-
- def subscriber
- @subscriber ||= Subscriber.new(queue)
- end
-
- def subscribe(pattern=nil, options={}, &block)
- with = options[:with] || listener
- subscriber.bind(with, pattern).subscribe(&block)
+ def notifier
+ @notifier ||= Notifier.new
end
end
- class Instrumenter
- def initialize(publisher)
- @publisher = publisher
- @id = random_id
- end
-
- def transaction
- @id, old_id = random_id, @id
- yield
- ensure
- @id = old_id
- end
-
- def transaction_id
- @id
- end
-
- def instrument(name, payload={})
- time = Time.now
- result = yield if block_given?
- ensure
- @publisher.publish(name, time, Time.now, result, @id, payload)
- end
-
- private
- def random_id
- SecureRandom.hex(10)
- end
- end
-
- class Publisher
- def initialize(queue)
+ class Notifier
+ def initialize(queue = Fanout.new)
@queue = queue
end
def publish(*args)
@queue.publish(*args)
end
- end
-
- class Subscriber
- def initialize(queue)
- @queue = queue
- end
-
- def bind(listener, pattern)
- @listener = listener
- @pattern = pattern
- self
- end
- def subscribe
- @queue.subscribe(@listener, @pattern) do |*args|
- yield(*args)
- end
+ def subscribe(pattern = nil, &block)
+ @queue.bind(pattern).subscribe(&block)
end
- end
-
- class Event
- attr_reader :name, :time, :end, :transaction_id, :result, :payload
- def initialize(name, start, ending, result, transaction_id, payload)
- @name = name
- @payload = payload.dup
- @time = start
- @transaction_id = transaction_id
- @end = ending
- @result = result
+ def wait
+ @queue.wait
end
- def duration
- @duration ||= 1000.0 * (@end - @time)
- end
+ delegate :instrument, :to => :current_instrumenter
- def parent_of?(event)
- start = (self.time - event.time) * 1000
- start <= 0 && (start + duration >= event.duration)
- end
- end
-
- class AsyncListener
- def initialize(pattern, &block)
- @pattern = pattern
- @subscriber = block
- @queue = Queue.new
- Thread.new { consume }
- end
-
- def publish(name, *args)
- if !@pattern || @pattern === name.to_s
- @queue << args.unshift(name)
- end
- end
-
- def consume
- while args = @queue.shift
- @subscriber.call(*args)
- end
- end
-
- def drained?
- @queue.size.zero?
- end
- end
-
- class SyncListener
- def initialize(pattern, &block)
- @pattern = pattern
- @subscriber = block
- end
-
- def publish(name, *args)
- if !@pattern || @pattern === name.to_s
- @subscriber.call(*args.unshift(name))
+ private
+ def current_instrumenter
+ Thread.current[:"instrumentation_#{object_id}"] ||= Notifications::Instrumenter.new(self)
end
- end
-
- def drained?
- true
- end
- end
-
- # This is a default queue implementation that ships with Notifications. It
- # consumes events in a thread and publish them to all registered subscribers.
- #
- class LittleFanout
- def initialize
- @listeners = []
- end
-
- def publish(*args)
- @listeners.each { |l| l.publish(*args) }
- end
-
- def subscribe(listener, pattern=nil, &block)
- @listeners << listener.new(pattern, &block)
- end
-
- def drained?
- @listeners.all? &:drained?
- end
end
end
-
- Notifications.queue = Notifications::LittleFanout.new
- Notifications.listener = Notifications::AsyncListener
end
diff --git a/activesupport/lib/active_support/notifications/fanout.rb b/activesupport/lib/active_support/notifications/fanout.rb
new file mode 100644
index 0000000000..bb07e4765c
--- /dev/null
+++ b/activesupport/lib/active_support/notifications/fanout.rb
@@ -0,0 +1,101 @@
+require 'thread'
+
+module ActiveSupport
+ module Notifications
+ # This is a default queue implementation that ships with Notifications. It
+ # consumes events in a thread and publish them to all registered subscribers.
+ #
+ class Fanout
+ def initialize(sync = false)
+ @subscriber_klass = sync ? Subscriber : AsyncSubscriber
+ @subscribers = []
+ end
+
+ def bind(pattern)
+ Binding.new(self, pattern)
+ end
+
+ def subscribe(pattern = nil, &block)
+ @subscribers << @subscriber_klass.new(pattern, &block)
+ end
+
+ def publish(*args)
+ @subscribers.each { |s| s.publish(*args) }
+ end
+
+ def wait
+ sleep(0.05) until @subscribers.all?(&:drained?)
+ end
+
+ # Used for internal implementation only.
+ class Binding #:nodoc:
+ def initialize(queue, pattern)
+ @queue = queue
+ @pattern =
+ case pattern
+ when Regexp, NilClass
+ pattern
+ else
+ /^#{Regexp.escape(pattern.to_s)}/
+ end
+ end
+
+ def subscribe(&block)
+ @queue.subscribe(@pattern, &block)
+ end
+ end
+
+ class Subscriber #:nodoc:
+ def initialize(pattern, &block)
+ @pattern = pattern
+ @block = block
+ end
+
+ def publish(*args)
+ push(*args) if matches?(args.first)
+ end
+
+ def drained?
+ true
+ end
+
+ private
+ def matches?(name)
+ !@pattern || @pattern =~ name.to_s
+ end
+
+ def push(*args)
+ @block.call(*args)
+ end
+ end
+
+ # Used for internal implementation only.
+ class AsyncSubscriber < Subscriber #:nodoc:
+ def initialize(pattern, &block)
+ super
+ @events = Queue.new
+ start_consumer
+ end
+
+ def drained?
+ @events.empty?
+ end
+
+ private
+ def start_consumer
+ Thread.new { consume }
+ end
+
+ def consume
+ while args = @events.shift
+ @block.call(*args)
+ end
+ end
+
+ def push(*args)
+ @events << args
+ end
+ end
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/notifications/instrumenter.rb b/activesupport/lib/active_support/notifications/instrumenter.rb
new file mode 100644
index 0000000000..fb95422af2
--- /dev/null
+++ b/activesupport/lib/active_support/notifications/instrumenter.rb
@@ -0,0 +1,47 @@
+require 'active_support/secure_random'
+require 'active_support/core_ext/module/delegation'
+
+module ActiveSupport
+ module Notifications
+ class Instrumenter
+ def initialize(notifier)
+ @id = unique_id
+ @notifier = notifier
+ end
+
+ def instrument(name, payload={})
+ time = Time.now
+ result = yield if block_given?
+ ensure
+ @notifier.publish(name, time, Time.now, result, @id, payload)
+ end
+
+ private
+ def unique_id
+ SecureRandom.hex(10)
+ end
+ end
+
+ class Event
+ attr_reader :name, :time, :end, :transaction_id, :result, :payload
+
+ def initialize(name, start, ending, result, transaction_id, payload)
+ @name = name
+ @payload = payload.dup
+ @time = start
+ @transaction_id = transaction_id
+ @end = ending
+ @result = result
+ end
+
+ def duration
+ @duration ||= 1000.0 * (@end - @time)
+ end
+
+ def parent_of?(event)
+ start = (self.time - event.time) * 1000
+ start <= 0 && (start + duration >= event.duration)
+ end
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/ruby/shim.rb b/activesupport/lib/active_support/ruby/shim.rb
index f811239077..1e49ccdade 100644
--- a/activesupport/lib/active_support/ruby/shim.rb
+++ b/activesupport/lib/active_support/ruby/shim.rb
@@ -14,5 +14,6 @@ require 'active_support/core_ext/date_time/conversions'
require 'active_support/core_ext/enumerable'
require 'active_support/core_ext/process/daemon'
require 'active_support/core_ext/string/conversions'
+require 'active_support/core_ext/string/interpolation'
require 'active_support/core_ext/rexml'
require 'active_support/core_ext/time/conversions'
diff --git a/activesupport/lib/active_support/testing/isolation.rb b/activesupport/lib/active_support/testing/isolation.rb
index c75b59c284..81f7e3c9df 100644
--- a/activesupport/lib/active_support/testing/isolation.rb
+++ b/activesupport/lib/active_support/testing/isolation.rb
@@ -1,10 +1,25 @@
module ActiveSupport
module Testing
+ class RemoteError < StandardError
+
+ attr_reader :message, :backtrace
+
+ def initialize(exception)
+ @message = "caught #{exception.class.name}: #{exception.message}"
+ @backtrace = exception.backtrace
+ end
+ end
+
class ProxyTestResult
def initialize
@calls = []
end
+ def add_error(e)
+ e = Test::Unit::Error.new(e.test_name, RemoteError.new(e.exception))
+ @calls << [:add_error, e]
+ end
+
def __replay__(result)
@calls.each do |name, args|
result.send(name, *args)
diff --git a/activesupport/lib/active_support/testing/performance.rb b/activesupport/lib/active_support/testing/performance.rb
index ab34f975f6..66e32fa5d7 100644
--- a/activesupport/lib/active_support/testing/performance.rb
+++ b/activesupport/lib/active_support/testing/performance.rb
@@ -1,450 +1,454 @@
-require 'ruby-prof'
-
-require 'fileutils'
-require 'rails/version'
-
-module ActiveSupport
- module Testing
- module Performance
- DEFAULTS =
- if benchmark = ARGV.include?('--benchmark') # HAX for rake test
- { :benchmark => true,
- :runs => 4,
- :metrics => [:wall_time, :memory, :objects, :gc_runs, :gc_time],
- :output => 'tmp/performance' }
- else
- { :benchmark => false,
- :runs => 1,
- :min_percent => 0.01,
- :metrics => [:process_time, :memory, :objects],
- :formats => [:flat, :graph_html, :call_tree],
- :output => 'tmp/performance' }
- end.freeze
-
- def self.included(base)
- base.superclass_delegating_accessor :profile_options
- base.profile_options = DEFAULTS
- end
+begin
+ require 'ruby-prof'
+
+ require 'fileutils'
+ require 'rails/version'
+ require 'active_support/core_ext/class/delegating_attributes'
+
+ module ActiveSupport
+ module Testing
+ module Performance
+ DEFAULTS =
+ if benchmark = ARGV.include?('--benchmark') # HAX for rake test
+ { :benchmark => true,
+ :runs => 4,
+ :metrics => [:wall_time, :memory, :objects, :gc_runs, :gc_time],
+ :output => 'tmp/performance' }
+ else
+ { :benchmark => false,
+ :runs => 1,
+ :min_percent => 0.01,
+ :metrics => [:process_time, :memory, :objects],
+ :formats => [:flat, :graph_html, :call_tree],
+ :output => 'tmp/performance' }
+ end.freeze
+
+ def self.included(base)
+ base.superclass_delegating_accessor :profile_options
+ base.profile_options = DEFAULTS
+ end
- def full_test_name
- "#{self.class.name}##{method_name}"
- end
+ def full_test_name
+ "#{self.class.name}##{method_name}"
+ end
- def run(result)
- return if method_name =~ /^default_test$/
+ def run(result)
+ return if method_name =~ /^default_test$/
- yield(self.class::STARTED, name)
- @_result = result
+ yield(self.class::STARTED, name)
+ @_result = result
- run_warmup
- if profile_options && metrics = profile_options[:metrics]
- metrics.each do |metric_name|
- if klass = Metrics[metric_name.to_sym]
- run_profile(klass.new)
- result.add_run
+ run_warmup
+ if profile_options && metrics = profile_options[:metrics]
+ metrics.each do |metric_name|
+ if klass = Metrics[metric_name.to_sym]
+ run_profile(klass.new)
+ result.add_run
+ end
end
end
- end
- yield(self.class::FINISHED, name)
- end
+ yield(self.class::FINISHED, name)
+ end
- def run_test(metric, mode)
- run_callbacks :setup
- setup
- metric.send(mode) { __send__ @method_name }
- rescue ::Test::Unit::AssertionFailedError => e
- add_failure(e.message, e.backtrace)
- rescue StandardError, ScriptError
- add_error($!)
- ensure
- begin
- teardown
- run_callbacks :teardown, :enumerator => :reverse_each
+ def run_test(metric, mode)
+ run_callbacks :setup
+ setup
+ metric.send(mode) { __send__ @method_name }
rescue ::Test::Unit::AssertionFailedError => e
add_failure(e.message, e.backtrace)
rescue StandardError, ScriptError
add_error($!)
+ ensure
+ begin
+ teardown
+ run_callbacks :teardown, :enumerator => :reverse_each
+ rescue ::Test::Unit::AssertionFailedError => e
+ add_failure(e.message, e.backtrace)
+ rescue StandardError, ScriptError
+ add_error($!)
+ end
end
- end
- protected
- def run_warmup
- GC.start
+ protected
+ def run_warmup
+ GC.start
- time = Metrics::Time.new
- run_test(time, :benchmark)
- puts "%s (%s warmup)" % [full_test_name, time.format(time.total)]
+ time = Metrics::Time.new
+ run_test(time, :benchmark)
+ puts "%s (%s warmup)" % [full_test_name, time.format(time.total)]
- GC.start
- end
-
- def run_profile(metric)
- klass = profile_options[:benchmark] ? Benchmarker : Profiler
- performer = klass.new(self, metric)
+ GC.start
+ end
- performer.run
- puts performer.report
- performer.record
- end
+ def run_profile(metric)
+ klass = profile_options[:benchmark] ? Benchmarker : Profiler
+ performer = klass.new(self, metric)
- class Performer
- delegate :run_test, :profile_options, :full_test_name, :to => :@harness
+ performer.run
+ puts performer.report
+ performer.record
+ end
- def initialize(harness, metric)
- @harness, @metric = harness, metric
- end
+ class Performer
+ delegate :run_test, :profile_options, :full_test_name, :to => :@harness
- def report
- rate = @total / profile_options[:runs]
- '%20s: %s' % [@metric.name, @metric.format(rate)]
- end
+ def initialize(harness, metric)
+ @harness, @metric = harness, metric
+ end
- protected
- def output_filename
- "#{profile_options[:output]}/#{full_test_name}_#{@metric.name}"
+ def report
+ rate = @total / profile_options[:runs]
+ '%20s: %s' % [@metric.name, @metric.format(rate)]
end
- end
- class Benchmarker < Performer
- def run
- profile_options[:runs].to_i.times { run_test(@metric, :benchmark) }
- @total = @metric.total
+ protected
+ def output_filename
+ "#{profile_options[:output]}/#{full_test_name}_#{@metric.name}"
+ end
end
- def record
- avg = @metric.total / profile_options[:runs].to_i
- now = Time.now.utc.xmlschema
- with_output_file do |file|
- file.puts "#{avg},#{now},#{environment}"
+ class Benchmarker < Performer
+ def run
+ profile_options[:runs].to_i.times { run_test(@metric, :benchmark) }
+ @total = @metric.total
end
- end
- def environment
- unless defined? @env
- app = "#{$1}.#{$2}" if File.directory?('.git') && `git branch -v` =~ /^\* (\S+)\s+(\S+)/
-
- rails = Rails::VERSION::STRING
- if File.directory?('vendor/rails/.git')
- Dir.chdir('vendor/rails') do
- rails += ".#{$1}.#{$2}" if `git branch -v` =~ /^\* (\S+)\s+(\S+)/
- end
+ def record
+ avg = @metric.total / profile_options[:runs].to_i
+ now = Time.now.utc.xmlschema
+ with_output_file do |file|
+ file.puts "#{avg},#{now},#{environment}"
end
-
- ruby = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
- ruby += "-#{RUBY_VERSION}.#{RUBY_PATCHLEVEL}"
-
- @env = [app, rails, ruby, RUBY_PLATFORM] * ','
end
- @env
- end
+ def environment
+ unless defined? @env
+ app = "#{$1}.#{$2}" if File.directory?('.git') && `git branch -v` =~ /^\* (\S+)\s+(\S+)/
- protected
- HEADER = 'measurement,created_at,app,rails,ruby,platform'
+ rails = Rails::VERSION::STRING
+ if File.directory?('vendor/rails/.git')
+ Dir.chdir('vendor/rails') do
+ rails += ".#{$1}.#{$2}" if `git branch -v` =~ /^\* (\S+)\s+(\S+)/
+ end
+ end
- def with_output_file
- fname = output_filename
+ ruby = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
+ ruby += "-#{RUBY_VERSION}.#{RUBY_PATCHLEVEL}"
- if new = !File.exist?(fname)
- FileUtils.mkdir_p(File.dirname(fname))
+ @env = [app, rails, ruby, RUBY_PLATFORM] * ','
end
- File.open(fname, 'ab') do |file|
- file.puts(HEADER) if new
- yield file
- end
+ @env
end
- def output_filename
- "#{super}.csv"
- end
- end
+ protected
+ HEADER = 'measurement,created_at,app,rails,ruby,platform'
- class Profiler < Performer
- def initialize(*args)
- super
- @supported = @metric.measure_mode rescue false
- end
+ def with_output_file
+ fname = output_filename
+
+ if new = !File.exist?(fname)
+ FileUtils.mkdir_p(File.dirname(fname))
+ end
- def run
- return unless @supported
+ File.open(fname, 'ab') do |file|
+ file.puts(HEADER) if new
+ yield file
+ end
+ end
- RubyProf.measure_mode = @metric.measure_mode
- RubyProf.start
- RubyProf.pause
- profile_options[:runs].to_i.times { run_test(@metric, :profile) }
- @data = RubyProf.stop
- @total = @data.threads.values.sum(0) { |method_infos| method_infos.sort.last.total_time }
+ def output_filename
+ "#{super}.csv"
+ end
end
- def report
- if @supported
+ class Profiler < Performer
+ def initialize(*args)
super
- else
- '%20s: unsupported' % @metric.name
+ @supported = @metric.measure_mode rescue false
end
- end
- def record
- return unless @supported
+ def run
+ return unless @supported
- klasses = profile_options[:formats].map { |f| RubyProf.const_get("#{f.to_s.camelize}Printer") }.compact
+ RubyProf.measure_mode = @metric.measure_mode
+ RubyProf.start
+ RubyProf.pause
+ profile_options[:runs].to_i.times { run_test(@metric, :profile) }
+ @data = RubyProf.stop
+ @total = @data.threads.values.sum(0) { |method_infos| method_infos.sort.last.total_time }
+ end
- klasses.each do |klass|
- fname = output_filename(klass)
- FileUtils.mkdir_p(File.dirname(fname))
- File.open(fname, 'wb') do |file|
- klass.new(@data).print(file, profile_options.slice(:min_percent))
+ def report
+ if @supported
+ super
+ else
+ '%20s: unsupported' % @metric.name
end
end
- end
- protected
- def output_filename(printer_class)
- suffix =
- case printer_class.name.demodulize
- when 'FlatPrinter'; 'flat.txt'
- when 'GraphPrinter'; 'graph.txt'
- when 'GraphHtmlPrinter'; 'graph.html'
- when 'CallTreePrinter'; 'tree.txt'
- else printer_class.name.sub(/Printer$/, '').underscore
- end
+ def record
+ return unless @supported
+
+ klasses = profile_options[:formats].map { |f| RubyProf.const_get("#{f.to_s.camelize}Printer") }.compact
- "#{super()}_#{suffix}"
+ klasses.each do |klass|
+ fname = output_filename(klass)
+ FileUtils.mkdir_p(File.dirname(fname))
+ File.open(fname, 'wb') do |file|
+ klass.new(@data).print(file, profile_options.slice(:min_percent))
+ end
+ end
end
- end
- module Metrics
- def self.[](name)
- const_get(name.to_s.camelize)
- rescue NameError
- nil
+ protected
+ def output_filename(printer_class)
+ suffix =
+ case printer_class.name.demodulize
+ when 'FlatPrinter'; 'flat.txt'
+ when 'GraphPrinter'; 'graph.txt'
+ when 'GraphHtmlPrinter'; 'graph.html'
+ when 'CallTreePrinter'; 'tree.txt'
+ else printer_class.name.sub(/Printer$/, '').underscore
+ end
+
+ "#{super()}_#{suffix}"
+ end
end
- class Base
- attr_reader :total
-
- def initialize
- @total = 0
+ module Metrics
+ def self.[](name)
+ const_get(name.to_s.camelize)
+ rescue NameError
+ nil
end
- def name
- @name ||= self.class.name.demodulize.underscore
- end
+ class Base
+ attr_reader :total
- def measure_mode
- self.class::Mode
- end
+ def initialize
+ @total = 0
+ end
- def measure
- 0
- end
+ def name
+ @name ||= self.class.name.demodulize.underscore
+ end
- def benchmark
- with_gc_stats do
- before = measure
- yield
- @total += (measure - before)
+ def measure_mode
+ self.class::Mode
end
- end
- def profile
- RubyProf.resume
- yield
- ensure
- RubyProf.pause
- end
+ def measure
+ 0
+ end
- protected
- if GC.respond_to?(:enable_stats)
- def with_gc_stats
- GC.enable_stats
- yield
- ensure
- GC.disable_stats
- end
- elsif defined?(GC::Profiler)
- def with_gc_stats
- GC.start
- GC.disable
- GC::Profiler.enable
- yield
- ensure
- GC::Profiler.disable
- GC.enable
- end
- else
- def with_gc_stats
+ def benchmark
+ with_gc_stats do
+ before = measure
yield
+ @total += (measure - before)
end
end
- end
- class Time < Base
- def measure
- ::Time.now.to_f
- end
-
- def format(measurement)
- if measurement < 2
- '%d ms' % (measurement * 1000)
- else
- '%.2f sec' % measurement
+ def profile
+ RubyProf.resume
+ yield
+ ensure
+ RubyProf.pause
end
- end
- end
-
- class ProcessTime < Time
- Mode = RubyProf::PROCESS_TIME
-
- def measure
- RubyProf.measure_process_time
- end
- end
-
- class WallTime < Time
- Mode = RubyProf::WALL_TIME
- def measure
- RubyProf.measure_wall_time
+ protected
+ if GC.respond_to?(:enable_stats)
+ def with_gc_stats
+ GC.enable_stats
+ yield
+ ensure
+ GC.disable_stats
+ end
+ elsif defined?(GC::Profiler)
+ def with_gc_stats
+ GC.start
+ GC.disable
+ GC::Profiler.enable
+ yield
+ ensure
+ GC::Profiler.disable
+ GC.enable
+ end
+ else
+ def with_gc_stats
+ yield
+ end
+ end
end
- end
- class CpuTime < Time
- Mode = RubyProf::CPU_TIME if RubyProf.const_defined?(:CPU_TIME)
-
- def initialize(*args)
- # FIXME: yeah my CPU is 2.33 GHz
- RubyProf.cpu_frequency = 2.33e9
- super
- end
+ class Time < Base
+ def measure
+ ::Time.now.to_f
+ end
- def measure
- RubyProf.measure_cpu_time
+ def format(measurement)
+ if measurement < 2
+ '%d ms' % (measurement * 1000)
+ else
+ '%.2f sec' % measurement
+ end
+ end
end
- end
- class Memory < Base
- Mode = RubyProf::MEMORY if RubyProf.const_defined?(:MEMORY)
+ class ProcessTime < Time
+ Mode = RubyProf::PROCESS_TIME
- # ruby-prof wrapper
- if RubyProf.respond_to?(:measure_memory)
def measure
- RubyProf.measure_memory / 1024.0
+ RubyProf.measure_process_time
end
+ end
- # Ruby 1.8 + railsbench patch
- elsif GC.respond_to?(:allocated_size)
- def measure
- GC.allocated_size / 1024.0
- end
+ class WallTime < Time
+ Mode = RubyProf::WALL_TIME
- # Ruby 1.8 + lloyd patch
- elsif GC.respond_to?(:heap_info)
def measure
- GC.heap_info['heap_current_memory'] / 1024.0
+ RubyProf.measure_wall_time
end
+ end
- # Ruby 1.9 with total_malloc_allocated_size patch
- elsif GC.respond_to?(:malloc_total_allocated_size)
- def measure
- GC.total_malloc_allocated_size / 1024.0
- end
+ class CpuTime < Time
+ Mode = RubyProf::CPU_TIME if RubyProf.const_defined?(:CPU_TIME)
- # Ruby 1.9 unpatched
- elsif GC.respond_to?(:malloc_allocated_size)
- def measure
- GC.malloc_allocated_size / 1024.0
+ def initialize(*args)
+ # FIXME: yeah my CPU is 2.33 GHz
+ RubyProf.cpu_frequency = 2.33e9
+ super
end
- # Ruby 1.9 + GC profiler patch
- elsif defined?(GC::Profiler)
def measure
- GC.enable
- GC.start
- kb = GC::Profiler.data.last[:HEAP_USE_SIZE] / 1024.0
- GC.disable
- kb
+ RubyProf.measure_cpu_time
end
end
- def format(measurement)
- '%.2f KB' % measurement
- end
- end
+ class Memory < Base
+ Mode = RubyProf::MEMORY if RubyProf.const_defined?(:MEMORY)
- class Objects < Base
- Mode = RubyProf::ALLOCATIONS if RubyProf.const_defined?(:ALLOCATIONS)
+ # ruby-prof wrapper
+ if RubyProf.respond_to?(:measure_memory)
+ def measure
+ RubyProf.measure_memory / 1024.0
+ end
- if RubyProf.respond_to?(:measure_allocations)
- def measure
- RubyProf.measure_allocations
- end
+ # Ruby 1.8 + railsbench patch
+ elsif GC.respond_to?(:allocated_size)
+ def measure
+ GC.allocated_size / 1024.0
+ end
- # Ruby 1.8 + railsbench patch
- elsif ObjectSpace.respond_to?(:allocated_objects)
- def measure
- ObjectSpace.allocated_objects
+ # Ruby 1.8 + lloyd patch
+ elsif GC.respond_to?(:heap_info)
+ def measure
+ GC.heap_info['heap_current_memory'] / 1024.0
+ end
+
+ # Ruby 1.9 with total_malloc_allocated_size patch
+ elsif GC.respond_to?(:malloc_total_allocated_size)
+ def measure
+ GC.total_malloc_allocated_size / 1024.0
+ end
+
+ # Ruby 1.9 unpatched
+ elsif GC.respond_to?(:malloc_allocated_size)
+ def measure
+ GC.malloc_allocated_size / 1024.0
+ end
+
+ # Ruby 1.9 + GC profiler patch
+ elsif defined?(GC::Profiler)
+ def measure
+ GC.enable
+ GC.start
+ kb = GC::Profiler.data.last[:HEAP_USE_SIZE] / 1024.0
+ GC.disable
+ kb
+ end
end
- # Ruby 1.9 + GC profiler patch
- elsif defined?(GC::Profiler)
- def measure
- GC.enable
- GC.start
- last = GC::Profiler.data.last
- count = last[:HEAP_LIVE_OBJECTS] + last[:HEAP_FREE_OBJECTS]
- GC.disable
- count
+ def format(measurement)
+ '%.2f KB' % measurement
end
end
- def format(measurement)
- measurement.to_i.to_s
- end
- end
+ class Objects < Base
+ Mode = RubyProf::ALLOCATIONS if RubyProf.const_defined?(:ALLOCATIONS)
- class GcRuns < Base
- Mode = RubyProf::GC_RUNS if RubyProf.const_defined?(:GC_RUNS)
+ if RubyProf.respond_to?(:measure_allocations)
+ def measure
+ RubyProf.measure_allocations
+ end
- if RubyProf.respond_to?(:measure_gc_runs)
- def measure
- RubyProf.measure_gc_runs
- end
- elsif GC.respond_to?(:collections)
- def measure
- GC.collections
- end
- elsif GC.respond_to?(:heap_info)
- def measure
- GC.heap_info['num_gc_passes']
+ # Ruby 1.8 + railsbench patch
+ elsif ObjectSpace.respond_to?(:allocated_objects)
+ def measure
+ ObjectSpace.allocated_objects
+ end
+
+ # Ruby 1.9 + GC profiler patch
+ elsif defined?(GC::Profiler)
+ def measure
+ GC.enable
+ GC.start
+ last = GC::Profiler.data.last
+ count = last[:HEAP_LIVE_OBJECTS] + last[:HEAP_FREE_OBJECTS]
+ GC.disable
+ count
+ end
end
- end
- def format(measurement)
- measurement.to_i.to_s
+ def format(measurement)
+ measurement.to_i.to_s
+ end
end
- end
- class GcTime < Base
- Mode = RubyProf::GC_TIME if RubyProf.const_defined?(:GC_TIME)
+ class GcRuns < Base
+ Mode = RubyProf::GC_RUNS if RubyProf.const_defined?(:GC_RUNS)
- if RubyProf.respond_to?(:measure_gc_time)
- def measure
- RubyProf.measure_gc_time
+ if RubyProf.respond_to?(:measure_gc_runs)
+ def measure
+ RubyProf.measure_gc_runs
+ end
+ elsif GC.respond_to?(:collections)
+ def measure
+ GC.collections
+ end
+ elsif GC.respond_to?(:heap_info)
+ def measure
+ GC.heap_info['num_gc_passes']
+ end
end
- elsif GC.respond_to?(:time)
- def measure
- GC.time
+
+ def format(measurement)
+ measurement.to_i.to_s
end
end
- def format(measurement)
- '%d ms' % (measurement / 1000)
+ class GcTime < Base
+ Mode = RubyProf::GC_TIME if RubyProf.const_defined?(:GC_TIME)
+
+ if RubyProf.respond_to?(:measure_gc_time)
+ def measure
+ RubyProf.measure_gc_time
+ end
+ elsif GC.respond_to?(:time)
+ def measure
+ GC.time
+ end
+ end
+
+ def format(measurement)
+ '%d ms' % (measurement / 1000)
+ end
end
end
end
end
end
-end
+rescue LoadError
+end \ No newline at end of file
diff --git a/activesupport/lib/active_support/vendor.rb b/activesupport/lib/active_support/vendor.rb
index eb5080888c..1e46491d83 100644
--- a/activesupport/lib/active_support/vendor.rb
+++ b/activesupport/lib/active_support/vendor.rb
@@ -4,7 +4,7 @@ def ActiveSupport.requirable?(file)
$LOAD_PATH.any? { |p| Dir.glob("#{p}/#{file}.*").any? }
end
-[%w(builder 2.1.2), %w(i18n 0.1.3), %w(memcache-client 1.7.5), %w(tzinfo 0.3.15)].each do |lib, version|
+[%w(builder 2.1.2), %w(memcache-client 1.7.5), %w(tzinfo 0.3.15)].each do |lib, version|
# If the lib is not already requirable
unless ActiveSupport.requirable? lib
# Try to activate a gem ~> satisfying the requested version first.
diff --git a/activesupport/lib/active_support/vendor/i18n-0.1.3/MIT-LICENSE b/activesupport/lib/active_support/vendor/i18n-0.1.3/MIT-LICENSE
deleted file mode 100755
index ed8e9ee66d..0000000000
--- a/activesupport/lib/active_support/vendor/i18n-0.1.3/MIT-LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-Copyright (c) 2008 The Ruby I18n team
-
-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. \ No newline at end of file
diff --git a/activesupport/lib/active_support/vendor/i18n-0.1.3/README.textile b/activesupport/lib/active_support/vendor/i18n-0.1.3/README.textile
deleted file mode 100644
index a07fc8426d..0000000000
--- a/activesupport/lib/active_support/vendor/i18n-0.1.3/README.textile
+++ /dev/null
@@ -1,20 +0,0 @@
-h1. Ruby I18n gem
-
-I18n and localization solution for Ruby.
-
-For information please refer to http://rails-i18n.org
-
-h2. Authors
-
-* "Matt Aimonetti":http://railsontherun.com
-* "Sven Fuchs":http://www.artweb-design.de
-* "Joshua Harvey":http://www.workingwithrails.com/person/759-joshua-harvey
-* "Saimon Moore":http://saimonmoore.net
-* "Stephan Soller":http://www.arkanis-development.de
-
-h2. License
-
-MIT License. See the included MIT-LICENCE file.
-
-
-
diff --git a/activesupport/lib/active_support/vendor/i18n-0.1.3/Rakefile b/activesupport/lib/active_support/vendor/i18n-0.1.3/Rakefile
deleted file mode 100644
index 2164e13e69..0000000000
--- a/activesupport/lib/active_support/vendor/i18n-0.1.3/Rakefile
+++ /dev/null
@@ -1,5 +0,0 @@
-task :default => [:test]
-
-task :test do
- ruby "test/all.rb"
-end
diff --git a/activesupport/lib/active_support/vendor/i18n-0.1.3/i18n.gemspec b/activesupport/lib/active_support/vendor/i18n-0.1.3/i18n.gemspec
deleted file mode 100644
index f102689a6f..0000000000
--- a/activesupport/lib/active_support/vendor/i18n-0.1.3/i18n.gemspec
+++ /dev/null
@@ -1,27 +0,0 @@
-Gem::Specification.new do |s|
- s.name = "i18n"
- s.version = "0.1.3"
- s.date = "2009-01-09"
- s.summary = "Internationalization support for Ruby"
- s.email = "rails-i18n@googlegroups.com"
- s.homepage = "http://rails-i18n.org"
- s.description = "Add Internationalization support to your Ruby application."
- s.has_rdoc = false
- s.authors = ['Sven Fuchs', 'Joshua Harvey', 'Matt Aimonetti', 'Stephan Soller', 'Saimon Moore']
- s.files = [
- 'i18n.gemspec',
- 'lib/i18n/backend/simple.rb',
- 'lib/i18n/exceptions.rb',
- 'lib/i18n.rb',
- 'MIT-LICENSE',
- 'README.textile'
- ]
- s.test_files = [
- 'test/all.rb',
- 'test/i18n_exceptions_test.rb',
- 'test/i18n_test.rb',
- 'test/locale/en.rb',
- 'test/locale/en.yml',
- 'test/simple_backend_test.rb'
- ]
-end
diff --git a/activesupport/lib/active_support/vendor/i18n-0.1.3/lib/i18n.rb b/activesupport/lib/active_support/vendor/i18n-0.1.3/lib/i18n.rb
deleted file mode 100755
index 1b49debc05..0000000000
--- a/activesupport/lib/active_support/vendor/i18n-0.1.3/lib/i18n.rb
+++ /dev/null
@@ -1,204 +0,0 @@
-#--
-# Authors:: Matt Aimonetti (http://railsontherun.com/),
-# Sven Fuchs (http://www.artweb-design.de),
-# Joshua Harvey (http://www.workingwithrails.com/person/759-joshua-harvey),
-# Saimon Moore (http://saimonmoore.net),
-# Stephan Soller (http://www.arkanis-development.de/)
-# Copyright:: Copyright (c) 2008 The Ruby i18n Team
-# License:: MIT
-#++
-
-module I18n
- autoload :ArgumentError, 'i18n/exceptions'
- module Backend
- autoload :Simple, 'i18n/backend/simple'
- end
-
- @@backend = nil
- @@load_path = nil
- @@default_locale = :'en'
- @@exception_handler = :default_exception_handler
-
- class << self
- # Returns the current backend. Defaults to +Backend::Simple+.
- def backend
- @@backend ||= Backend::Simple.new
- end
-
- # Sets the current backend. Used to set a custom backend.
- def backend=(backend)
- @@backend = backend
- end
-
- # Returns the current default locale. Defaults to :'en'
- def default_locale
- @@default_locale
- end
-
- # Sets the current default locale. Used to set a custom default locale.
- def default_locale=(locale)
- @@default_locale = locale
- end
-
- # Returns the current locale. Defaults to I18n.default_locale.
- def locale
- Thread.current[:locale] ||= default_locale
- end
-
- # Sets the current locale pseudo-globally, i.e. in the Thread.current hash.
- def locale=(locale)
- Thread.current[:locale] = locale
- end
-
- # Returns an array of locales for which translations are available
- def available_locales
- backend.available_locales
- end
-
- # Sets the exception handler.
- def exception_handler=(exception_handler)
- @@exception_handler = exception_handler
- end
-
- # Allow clients to register paths providing translation data sources. The
- # backend defines acceptable sources.
- #
- # E.g. the provided SimpleBackend accepts a list of paths to translation
- # files which are either named *.rb and contain plain Ruby Hashes or are
- # named *.yml and contain YAML data. So for the SimpleBackend clients may
- # register translation files like this:
- # I18n.load_path << 'path/to/locale/en.yml'
- def load_path
- @@load_path ||= []
- end
-
- # Sets the load path instance. Custom implementations are expected to
- # behave like a Ruby Array.
- def load_path=(load_path)
- @@load_path = load_path
- end
-
- # Tells the backend to reload translations. Used in situations like the
- # Rails development environment. Backends can implement whatever strategy
- # is useful.
- def reload!
- backend.reload!
- end
-
- # Translates, pluralizes and interpolates a given key using a given locale,
- # scope, and default, as well as interpolation values.
- #
- # *LOOKUP*
- #
- # Translation data is organized as a nested hash using the upper-level keys
- # as namespaces. <em>E.g.</em>, ActionView ships with the translation:
- # <tt>:date => {:formats => {:short => "%b %d"}}</tt>.
- #
- # Translations can be looked up at any level of this hash using the key argument
- # and the scope option. <em>E.g.</em>, in this example <tt>I18n.t :date</tt>
- # returns the whole translations hash <tt>{:formats => {:short => "%b %d"}}</tt>.
- #
- # Key can be either a single key or a dot-separated key (both Strings and Symbols
- # work). <em>E.g.</em>, the short format can be looked up using both:
- # I18n.t 'date.formats.short'
- # I18n.t :'date.formats.short'
- #
- # Scope can be either a single key, a dot-separated key or an array of keys
- # or dot-separated keys. Keys and scopes can be combined freely. So these
- # examples will all look up the same short date format:
- # I18n.t 'date.formats.short'
- # I18n.t 'formats.short', :scope => 'date'
- # I18n.t 'short', :scope => 'date.formats'
- # I18n.t 'short', :scope => %w(date formats)
- #
- # *INTERPOLATION*
- #
- # Translations can contain interpolation variables which will be replaced by
- # values passed to #translate as part of the options hash, with the keys matching
- # the interpolation variable names.
- #
- # <em>E.g.</em>, with a translation <tt>:foo => "foo {{bar}}"</tt> the option
- # value for the key +bar+ will be interpolated into the translation:
- # I18n.t :foo, :bar => 'baz' # => 'foo baz'
- #
- # *PLURALIZATION*
- #
- # Translation data can contain pluralized translations. Pluralized translations
- # are arrays of singluar/plural versions of translations like <tt>['Foo', 'Foos']</tt>.
- #
- # Note that <tt>I18n::Backend::Simple</tt> only supports an algorithm for English
- # pluralization rules. Other algorithms can be supported by custom backends.
- #
- # This returns the singular version of a pluralized translation:
- # I18n.t :foo, :count => 1 # => 'Foo'
- #
- # These both return the plural version of a pluralized translation:
- # I18n.t :foo, :count => 0 # => 'Foos'
- # I18n.t :foo, :count => 2 # => 'Foos'
- #
- # The <tt>:count</tt> option can be used both for pluralization and interpolation.
- # <em>E.g.</em>, with the translation
- # <tt>:foo => ['{{count}} foo', '{{count}} foos']</tt>, count will
- # be interpolated to the pluralized translation:
- # I18n.t :foo, :count => 1 # => '1 foo'
- #
- # *DEFAULTS*
- #
- # This returns the translation for <tt>:foo</tt> or <tt>default</tt> if no translation was found:
- # I18n.t :foo, :default => 'default'
- #
- # This returns the translation for <tt>:foo</tt> or the translation for <tt>:bar</tt> if no
- # translation for <tt>:foo</tt> was found:
- # I18n.t :foo, :default => :bar
- #
- # Returns the translation for <tt>:foo</tt> or the translation for <tt>:bar</tt>
- # or <tt>default</tt> if no translations for <tt>:foo</tt> and <tt>:bar</tt> were found.
- # I18n.t :foo, :default => [:bar, 'default']
- #
- # <b>BULK LOOKUP</b>
- #
- # This returns an array with the translations for <tt>:foo</tt> and <tt>:bar</tt>.
- # I18n.t [:foo, :bar]
- #
- # Can be used with dot-separated nested keys:
- # I18n.t [:'baz.foo', :'baz.bar']
- #
- # Which is the same as using a scope option:
- # I18n.t [:foo, :bar], :scope => :baz
- def translate(key, options = {})
- locale = options.delete(:locale) || I18n.locale
- backend.translate(locale, key, options)
- rescue I18n::ArgumentError => e
- raise e if options[:raise]
- send(@@exception_handler, e, locale, key, options)
- end
- alias :t :translate
-
- # Localizes certain objects, such as dates and numbers to local formatting.
- def localize(object, options = {})
- locale = options[:locale] || I18n.locale
- format = options[:format] || :default
- backend.localize(locale, object, format)
- end
- alias :l :localize
-
- protected
- # Handles exceptions raised in the backend. All exceptions except for
- # MissingTranslationData exceptions are re-raised. When a MissingTranslationData
- # was caught and the option :raise is not set the handler returns an error
- # message string containing the key/scope.
- def default_exception_handler(exception, locale, key, options)
- return exception.message if MissingTranslationData === exception
- raise exception
- end
-
- # Merges the given locale, key and scope into a single array of keys.
- # Splits keys that contain dots into multiple keys. Makes sure all
- # keys are Symbols.
- def normalize_translation_keys(locale, key, scope)
- keys = [locale] + Array(scope) + [key]
- keys = keys.map { |k| k.to_s.split(/\./) }
- keys.flatten.map { |k| k.to_sym }
- end
- end
-end
diff --git a/activesupport/lib/active_support/vendor/i18n-0.1.3/lib/i18n/backend/simple.rb b/activesupport/lib/active_support/vendor/i18n-0.1.3/lib/i18n/backend/simple.rb
deleted file mode 100644
index c32cc76f34..0000000000
--- a/activesupport/lib/active_support/vendor/i18n-0.1.3/lib/i18n/backend/simple.rb
+++ /dev/null
@@ -1,215 +0,0 @@
-require 'i18n/exceptions'
-
-module I18n
- module Backend
- class Simple
- INTERPOLATION_RESERVED_KEYS = %w(scope default)
- MATCH = /(\\\\)?\{\{([^\}]+)\}\}/
-
- # Accepts a list of paths to translation files. Loads translations from
- # plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml
- # for details.
- def load_translations(*filenames)
- filenames.each { |filename| load_file(filename) }
- end
-
- # Stores translations for the given locale in memory.
- # This uses a deep merge for the translations hash, so existing
- # translations will be overwritten by new ones only at the deepest
- # level of the hash.
- def store_translations(locale, data)
- merge_translations(locale, data)
- end
-
- def translate(locale, key, options = {})
- raise InvalidLocale.new(locale) if locale.nil?
- return key.map { |k| translate(locale, k, options) } if key.is_a? Array
-
- reserved = :scope, :default
- count, scope, default = options.values_at(:count, *reserved)
- options.delete(:default)
- values = options.reject { |name, value| reserved.include?(name) }
-
- entry = lookup(locale, key, scope)
- if entry.nil?
- entry = default(locale, default, options)
- if entry.nil?
- raise(I18n::MissingTranslationData.new(locale, key, options))
- end
- end
- entry = pluralize(locale, entry, count)
- entry = interpolate(locale, entry, values)
- entry
- end
-
- # Acts the same as +strftime+, but returns a localized version of the
- # formatted date string. Takes a key from the date/time formats
- # translations as a format argument (<em>e.g.</em>, <tt>:short</tt> in <tt>:'date.formats'</tt>).
- def localize(locale, object, format = :default)
- raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime)
-
- type = object.respond_to?(:sec) ? 'time' : 'date'
- # TODO only translate these if format is a String?
- formats = translate(locale, :"#{type}.formats")
- format = formats[format.to_sym] if formats && formats[format.to_sym]
- # TODO raise exception unless format found?
- format = format.to_s.dup
-
- # TODO only translate these if the format string is actually present
- # TODO check which format strings are present, then bulk translate then, then replace them
- format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday])
- format.gsub!(/%A/, translate(locale, :"date.day_names")[object.wday])
- format.gsub!(/%b/, translate(locale, :"date.abbr_month_names")[object.mon])
- format.gsub!(/%B/, translate(locale, :"date.month_names")[object.mon])
- format.gsub!(/%p/, translate(locale, :"time.#{object.hour < 12 ? :am : :pm}")) if object.respond_to? :hour
- object.strftime(format)
- end
-
- def initialized?
- @initialized ||= false
- end
-
- # Returns an array of locales for which translations are available
- def available_locales
- init_translations unless initialized?
- translations.keys
- end
-
- def reload!
- @initialized = false
- @translations = nil
- end
-
- protected
- def init_translations
- load_translations(*I18n.load_path.flatten)
- @initialized = true
- end
-
- def translations
- @translations ||= {}
- end
-
- # Looks up a translation from the translations hash. Returns nil if
- # eiher key is nil, or locale, scope or key do not exist as a key in the
- # nested translations hash. Splits keys or scopes containing dots
- # into multiple keys, i.e. <tt>currency.format</tt> is regarded the same as
- # <tt>%w(currency format)</tt>.
- def lookup(locale, key, scope = [])
- return unless key
- init_translations unless initialized?
- keys = I18n.send(:normalize_translation_keys, locale, key, scope)
- keys.inject(translations) do |result, k|
- if (x = result[k.to_sym]).nil?
- return nil
- else
- x
- end
- end
- end
-
- # Evaluates a default translation.
- # If the given default is a String it is used literally. If it is a Symbol
- # it will be translated with the given options. If it is an Array the first
- # translation yielded will be returned.
- #
- # <em>I.e.</em>, <tt>default(locale, [:foo, 'default'])</tt> will return +default+ if
- # <tt>translate(locale, :foo)</tt> does not yield a result.
- def default(locale, default, options = {})
- case default
- when String then default
- when Symbol then translate locale, default, options
- when Array then default.each do |obj|
- result = default(locale, obj, options.dup) and return result
- end and nil
- end
- rescue MissingTranslationData
- nil
- end
-
- # Picks a translation from an array according to English pluralization
- # rules. It will pick the first translation if count is not equal to 1
- # and the second translation if it is equal to 1. Other backends can
- # implement more flexible or complex pluralization rules.
- def pluralize(locale, entry, count)
- return entry unless entry.is_a?(Hash) and count
- # raise InvalidPluralizationData.new(entry, count) unless entry.is_a?(Hash)
- key = :zero if count == 0 && entry.has_key?(:zero)
- key ||= count == 1 ? :one : :other
- raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key)
- entry[key]
- end
-
- # Interpolates values into a given string.
- #
- # interpolate "file {{file}} opened by \\{{user}}", :file => 'test.txt', :user => 'Mr. X'
- # # => "file test.txt opened by {{user}}"
- #
- # Note that you have to double escape the <tt>\\</tt> when you want to escape
- # the <tt>{{...}}</tt> key in a string (once for the string and once for the
- # interpolation).
- def interpolate(locale, string, values = {})
- return string unless string.is_a?(String)
-
- string.gsub(MATCH) do
- escaped, pattern, key = $1, $2, $2.to_sym
-
- if escaped
- pattern
- elsif INTERPOLATION_RESERVED_KEYS.include?(pattern)
- raise ReservedInterpolationKey.new(pattern, string)
- elsif !values.include?(key)
- raise MissingInterpolationArgument.new(pattern, string)
- else
- values[key].to_s
- end
- end
- end
-
- # Loads a single translations file by delegating to #load_rb or
- # #load_yml depending on the file extension and directly merges the
- # data to the existing translations. Raises I18n::UnknownFileType
- # for all other file extensions.
- def load_file(filename)
- type = File.extname(filename).tr('.', '').downcase
- raise UnknownFileType.new(type, filename) unless respond_to?(:"load_#{type}")
- data = send :"load_#{type}", filename # TODO raise a meaningful exception if this does not yield a Hash
- data.each { |locale, d| merge_translations(locale, d) }
- end
-
- # Loads a plain Ruby translations file. eval'ing the file must yield
- # a Hash containing translation data with locales as toplevel keys.
- def load_rb(filename)
- eval(IO.read(filename), binding, filename)
- end
-
- # Loads a YAML translations file. The data must have locales as
- # toplevel keys.
- def load_yml(filename)
- require 'yaml' unless defined? :YAML
- YAML::load(IO.read(filename))
- end
-
- # Deep merges the given translations hash with the existing translations
- # for the given locale
- def merge_translations(locale, data)
- locale = locale.to_sym
- translations[locale] ||= {}
- data = deep_symbolize_keys(data)
-
- # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809
- merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
- translations[locale].merge!(data, &merger)
- end
-
- # Return a new hash with all keys and nested keys converted to symbols.
- def deep_symbolize_keys(hash)
- hash.inject({}) { |result, (key, value)|
- value = deep_symbolize_keys(value) if value.is_a? Hash
- result[(key.to_sym rescue key) || key] = value
- result
- }
- end
- end
- end
-end
diff --git a/activesupport/lib/active_support/vendor/i18n-0.1.3/lib/i18n/exceptions.rb b/activesupport/lib/active_support/vendor/i18n-0.1.3/lib/i18n/exceptions.rb
deleted file mode 100644
index 6897055d6d..0000000000
--- a/activesupport/lib/active_support/vendor/i18n-0.1.3/lib/i18n/exceptions.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-module I18n
- class ArgumentError < ::ArgumentError; end
-
- class InvalidLocale < ArgumentError
- attr_reader :locale
- def initialize(locale)
- @locale = locale
- super "#{locale.inspect} is not a valid locale"
- end
- end
-
- class MissingTranslationData < ArgumentError
- attr_reader :locale, :key, :options
- def initialize(locale, key, options)
- @key, @locale, @options = key, locale, options
- keys = I18n.send(:normalize_translation_keys, locale, key, options[:scope])
- keys << 'no key' if keys.size < 2
- super "translation missing: #{keys.join(', ')}"
- end
- end
-
- class InvalidPluralizationData < ArgumentError
- attr_reader :entry, :count
- def initialize(entry, count)
- @entry, @count = entry, count
- super "translation data #{entry.inspect} can not be used with :count => #{count}"
- end
- end
-
- class MissingInterpolationArgument < ArgumentError
- attr_reader :key, :string
- def initialize(key, string)
- @key, @string = key, string
- super "interpolation argument #{key} missing in #{string.inspect}"
- end
- end
-
- class ReservedInterpolationKey < ArgumentError
- attr_reader :key, :string
- def initialize(key, string)
- @key, @string = key, string
- super "reserved key #{key.inspect} used in #{string.inspect}"
- end
- end
-
- class UnknownFileType < ArgumentError
- attr_reader :type, :filename
- def initialize(type, filename)
- @type, @filename = type, filename
- super "can not load translations from #{filename}, the file type #{type} is not known"
- end
- end
-end
diff --git a/activesupport/lib/active_support/vendor/i18n-0.1.3/test/all.rb b/activesupport/lib/active_support/vendor/i18n-0.1.3/test/all.rb
deleted file mode 100644
index 353712da49..0000000000
--- a/activesupport/lib/active_support/vendor/i18n-0.1.3/test/all.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-dir = File.dirname(__FILE__)
-require dir + '/i18n_test.rb'
-require dir + '/simple_backend_test.rb'
-require dir + '/i18n_exceptions_test.rb'
-# *require* dir + '/custom_backend_test.rb' \ No newline at end of file
diff --git a/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_exceptions_test.rb b/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_exceptions_test.rb
deleted file mode 100644
index 4e78e71b34..0000000000
--- a/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_exceptions_test.rb
+++ /dev/null
@@ -1,99 +0,0 @@
-$:.unshift "lib"
-
-require 'rubygems'
-require 'test/unit'
-require 'i18n'
-require 'active_support'
-
-class I18nExceptionsTest < Test::Unit::TestCase
- def test_invalid_locale_stores_locale
- force_invalid_locale
- rescue I18n::ArgumentError => e
- assert_nil e.locale
- end
-
- def test_invalid_locale_message
- force_invalid_locale
- rescue I18n::ArgumentError => e
- assert_equal 'nil is not a valid locale', e.message
- end
-
- def test_missing_translation_data_stores_locale_key_and_options
- force_missing_translation_data
- rescue I18n::ArgumentError => e
- options = {:scope => :bar}
- assert_equal 'de', e.locale
- assert_equal :foo, e.key
- assert_equal options, e.options
- end
-
- def test_missing_translation_data_message
- force_missing_translation_data
- rescue I18n::ArgumentError => e
- assert_equal 'translation missing: de, bar, foo', e.message
- end
-
- def test_invalid_pluralization_data_stores_entry_and_count
- force_invalid_pluralization_data
- rescue I18n::ArgumentError => e
- assert_equal [:bar], e.entry
- assert_equal 1, e.count
- end
-
- def test_invalid_pluralization_data_message
- force_invalid_pluralization_data
- rescue I18n::ArgumentError => e
- assert_equal 'translation data [:bar] can not be used with :count => 1', e.message
- end
-
- def test_missing_interpolation_argument_stores_key_and_string
- force_missing_interpolation_argument
- rescue I18n::ArgumentError => e
- assert_equal 'bar', e.key
- assert_equal "{{bar}}", e.string
- end
-
- def test_missing_interpolation_argument_message
- force_missing_interpolation_argument
- rescue I18n::ArgumentError => e
- assert_equal 'interpolation argument bar missing in "{{bar}}"', e.message
- end
-
- def test_reserved_interpolation_key_stores_key_and_string
- force_reserved_interpolation_key
- rescue I18n::ArgumentError => e
- assert_equal 'scope', e.key
- assert_equal "{{scope}}", e.string
- end
-
- def test_reserved_interpolation_key_message
- force_reserved_interpolation_key
- rescue I18n::ArgumentError => e
- assert_equal 'reserved key "scope" used in "{{scope}}"', e.message
- end
-
- private
- def force_invalid_locale
- I18n.backend.translate nil, :foo
- end
-
- def force_missing_translation_data
- I18n.backend.store_translations 'de', :bar => nil
- I18n.backend.translate 'de', :foo, :scope => :bar
- end
-
- def force_invalid_pluralization_data
- I18n.backend.store_translations 'de', :foo => [:bar]
- I18n.backend.translate 'de', :foo, :count => 1
- end
-
- def force_missing_interpolation_argument
- I18n.backend.store_translations 'de', :foo => "{{bar}}"
- I18n.backend.translate 'de', :foo, :baz => 'baz'
- end
-
- def force_reserved_interpolation_key
- I18n.backend.store_translations 'de', :foo => "{{scope}}"
- I18n.backend.translate 'de', :foo, :baz => 'baz'
- end
-end \ No newline at end of file
diff --git a/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_test.rb b/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_test.rb
deleted file mode 100644
index 2835ec4eab..0000000000
--- a/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_test.rb
+++ /dev/null
@@ -1,124 +0,0 @@
-$:.unshift "lib"
-
-require 'rubygems'
-require 'test/unit'
-require 'i18n'
-require 'active_support'
-
-class I18nTest < Test::Unit::TestCase
- def setup
- I18n.backend.store_translations :'en', {
- :currency => {
- :format => {
- :separator => '.',
- :delimiter => ',',
- }
- }
- }
- end
-
- def test_uses_simple_backend_set_by_default
- assert I18n.backend.is_a?(I18n::Backend::Simple)
- end
-
- def test_can_set_backend
- assert_nothing_raised{ I18n.backend = self }
- assert_equal self, I18n.backend
- I18n.backend = I18n::Backend::Simple.new
- end
-
- def test_uses_en_us_as_default_locale_by_default
- assert_equal 'en', I18n.default_locale
- end
-
- def test_can_set_default_locale
- assert_nothing_raised{ I18n.default_locale = 'de' }
- assert_equal 'de', I18n.default_locale
- I18n.default_locale = 'en'
- end
-
- def test_uses_default_locale_as_locale_by_default
- assert_equal I18n.default_locale, I18n.locale
- end
-
- def test_can_set_locale_to_thread_current
- assert_nothing_raised{ I18n.locale = 'de' }
- assert_equal 'de', I18n.locale
- assert_equal 'de', Thread.current[:locale]
- I18n.locale = 'en'
- end
-
- def test_can_set_exception_handler
- assert_nothing_raised{ I18n.exception_handler = :custom_exception_handler }
- I18n.exception_handler = :default_exception_handler # revert it
- end
-
- def test_uses_custom_exception_handler
- I18n.exception_handler = :custom_exception_handler
- I18n.expects(:custom_exception_handler)
- I18n.translate :bogus
- I18n.exception_handler = :default_exception_handler # revert it
- end
-
- def test_delegates_translate_to_backend
- I18n.backend.expects(:translate).with 'de', :foo, {}
- I18n.translate :foo, :locale => 'de'
- end
-
- def test_delegates_localize_to_backend
- I18n.backend.expects(:localize).with 'de', :whatever, :default
- I18n.localize :whatever, :locale => 'de'
- end
-
- def test_translate_given_no_locale_uses_i18n_locale
- I18n.backend.expects(:translate).with 'en', :foo, {}
- I18n.translate :foo
- end
-
- def test_translate_on_nested_symbol_keys_works
- assert_equal ".", I18n.t(:'currency.format.separator')
- end
-
- def test_translate_with_nested_string_keys_works
- assert_equal ".", I18n.t('currency.format.separator')
- end
-
- def test_translate_with_array_as_scope_works
- assert_equal ".", I18n.t(:separator, :scope => ['currency.format'])
- end
-
- def test_translate_with_array_containing_dot_separated_strings_as_scope_works
- assert_equal ".", I18n.t(:separator, :scope => ['currency.format'])
- end
-
- def test_translate_with_key_array_and_dot_separated_scope_works
- assert_equal [".", ","], I18n.t(%w(separator delimiter), :scope => 'currency.format')
- end
-
- def test_translate_with_dot_separated_key_array_and_scope_works
- assert_equal [".", ","], I18n.t(%w(format.separator format.delimiter), :scope => 'currency')
- end
-
- def test_translate_with_options_using_scope_works
- I18n.backend.expects(:translate).with('de', :precision, :scope => :"currency.format")
- I18n.with_options :locale => 'de', :scope => :'currency.format' do |locale|
- locale.t :precision
- end
- end
-
- # def test_translate_given_no_args_raises_missing_translation_data
- # assert_equal "translation missing: en, no key", I18n.t
- # end
-
- def test_translate_given_a_bogus_key_raises_missing_translation_data
- assert_equal "translation missing: en, bogus", I18n.t(:bogus)
- end
-
- def test_localize_nil_raises_argument_error
- assert_raise(I18n::ArgumentError) { I18n.l nil }
- end
-
- def test_localize_object_raises_argument_error
- assert_raise(I18n::ArgumentError) { I18n.l Object.new }
- end
-end
diff --git a/activesupport/lib/active_support/vendor/i18n-0.1.3/test/locale/en.rb b/activesupport/lib/active_support/vendor/i18n-0.1.3/test/locale/en.rb
deleted file mode 100644
index 6044ce10d9..0000000000
--- a/activesupport/lib/active_support/vendor/i18n-0.1.3/test/locale/en.rb
+++ /dev/null
@@ -1 +0,0 @@
-{:'en-Ruby' => {:foo => {:bar => "baz"}}} \ No newline at end of file
diff --git a/activesupport/lib/active_support/vendor/i18n-0.1.3/test/locale/en.yml b/activesupport/lib/active_support/vendor/i18n-0.1.3/test/locale/en.yml
deleted file mode 100644
index 0b298c9c0e..0000000000
--- a/activesupport/lib/active_support/vendor/i18n-0.1.3/test/locale/en.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-en-Yaml:
- foo:
- bar: baz \ No newline at end of file
diff --git a/activesupport/lib/active_support/vendor/i18n-0.1.3/test/simple_backend_test.rb b/activesupport/lib/active_support/vendor/i18n-0.1.3/test/simple_backend_test.rb
deleted file mode 100644
index a1696c77f6..0000000000
--- a/activesupport/lib/active_support/vendor/i18n-0.1.3/test/simple_backend_test.rb
+++ /dev/null
@@ -1,567 +0,0 @@
-# encoding: utf-8
-$:.unshift "lib"
-
-require 'rubygems'
-require 'test/unit'
-require 'i18n'
-require 'time'
-require 'yaml'
-
-module I18nSimpleBackendTestSetup
- def setup_backend
- # backend_reset_translations!
- @backend = I18n::Backend::Simple.new
- @backend.store_translations 'en', :foo => {:bar => 'bar', :baz => 'baz'}
- @locale_dir = File.dirname(__FILE__) + '/locale'
- end
- alias :setup :setup_backend
-
- # def backend_reset_translations!
- # I18n::Backend::Simple::ClassMethods.send :class_variable_set, :@@translations, {}
- # end
-
- def backend_get_translations
- # I18n::Backend::Simple::ClassMethods.send :class_variable_get, :@@translations
- @backend.instance_variable_get :@translations
- end
-
- def add_datetime_translations
- @backend.store_translations :'de', {
- :date => {
- :formats => {
- :default => "%d.%m.%Y",
- :short => "%d. %b",
- :long => "%d. %B %Y",
- },
- :day_names => %w(Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag),
- :abbr_day_names => %w(So Mo Di Mi Do Fr Sa),
- :month_names => %w(Januar Februar März April Mai Juni Juli August September Oktober November Dezember).unshift(nil),
- :abbr_month_names => %w(Jan Feb Mar Apr Mai Jun Jul Aug Sep Okt Nov Dez).unshift(nil),
- :order => [:day, :month, :year]
- },
- :time => {
- :formats => {
- :default => "%a, %d. %b %Y %H:%M:%S %z",
- :short => "%d. %b %H:%M",
- :long => "%d. %B %Y %H:%M",
- },
- :am => 'am',
- :pm => 'pm'
- },
- :datetime => {
- :distance_in_words => {
- :half_a_minute => 'half a minute',
- :less_than_x_seconds => {
- :one => 'less than 1 second',
- :other => 'less than {{count}} seconds'
- },
- :x_seconds => {
- :one => '1 second',
- :other => '{{count}} seconds'
- },
- :less_than_x_minutes => {
- :one => 'less than a minute',
- :other => 'less than {{count}} minutes'
- },
- :x_minutes => {
- :one => '1 minute',
- :other => '{{count}} minutes'
- },
- :about_x_hours => {
- :one => 'about 1 hour',
- :other => 'about {{count}} hours'
- },
- :x_days => {
- :one => '1 day',
- :other => '{{count}} days'
- },
- :about_x_months => {
- :one => 'about 1 month',
- :other => 'about {{count}} months'
- },
- :x_months => {
- :one => '1 month',
- :other => '{{count}} months'
- },
- :about_x_years => {
- :one => 'about 1 year',
- :other => 'about {{count}} year'
- },
- :over_x_years => {
- :one => 'over 1 year',
- :other => 'over {{count}} years'
- }
- }
- }
- }
- end
-end
-
-class I18nSimpleBackendTranslationsTest < Test::Unit::TestCase
- include I18nSimpleBackendTestSetup
-
- def test_store_translations_adds_translations # no, really :-)
- @backend.store_translations :'en', :foo => 'bar'
- assert_equal Hash[:'en', {:foo => 'bar'}], backend_get_translations
- end
-
- def test_store_translations_deep_merges_translations
- @backend.store_translations :'en', :foo => {:bar => 'bar'}
- @backend.store_translations :'en', :foo => {:baz => 'baz'}
- assert_equal Hash[:'en', {:foo => {:bar => 'bar', :baz => 'baz'}}], backend_get_translations
- end
-
- def test_store_translations_forces_locale_to_sym
- @backend.store_translations 'en', :foo => 'bar'
- assert_equal Hash[:'en', {:foo => 'bar'}], backend_get_translations
- end
-
- def test_store_translations_converts_keys_to_symbols
- # backend_reset_translations!
- @backend.store_translations 'en', 'foo' => {'bar' => 'bar', 'baz' => 'baz'}
- assert_equal Hash[:'en', {:foo => {:bar => 'bar', :baz => 'baz'}}], backend_get_translations
- end
-end
-
-class I18nSimpleBackendAvailableLocalesTest < Test::Unit::TestCase
- def test_available_locales
- @backend = I18n::Backend::Simple.new
- @backend.store_translations 'de', :foo => 'bar'
- @backend.store_translations 'en', :foo => 'foo'
-
- assert_equal ['de', 'en'], @backend.available_locales.map{|locale| locale.to_s }.sort
- end
-end
-
-class I18nSimpleBackendTranslateTest < Test::Unit::TestCase
- include I18nSimpleBackendTestSetup
-
- def test_translate_calls_lookup_with_locale_given
- @backend.expects(:lookup).with('de', :bar, [:foo]).returns 'bar'
- @backend.translate 'de', :bar, :scope => [:foo]
- end
-
- def test_given_no_keys_it_returns_the_default
- assert_equal 'default', @backend.translate('en', nil, :default => 'default')
- end
-
- def test_translate_given_a_symbol_as_a_default_translates_the_symbol
- assert_equal 'bar', @backend.translate('en', nil, :scope => [:foo], :default => :bar)
- end
-
- def test_translate_given_an_array_as_default_uses_the_first_match
- assert_equal 'bar', @backend.translate('en', :does_not_exist, :scope => [:foo], :default => [:does_not_exist_2, :bar])
- end
-
- def test_translate_given_an_array_of_inexistent_keys_it_raises_missing_translation_data
- assert_raise I18n::MissingTranslationData do
- @backend.translate('en', :does_not_exist, :scope => [:foo], :default => [:does_not_exist_2, :does_not_exist_3])
- end
- end
-
- def test_translate_an_array_of_keys_translates_all_of_them
- assert_equal %w(bar baz), @backend.translate('en', [:bar, :baz], :scope => [:foo])
- end
-
- def test_translate_calls_pluralize
- @backend.expects(:pluralize).with 'en', 'bar', 1
- @backend.translate 'en', :bar, :scope => [:foo], :count => 1
- end
-
- def test_translate_calls_interpolate
- @backend.expects(:interpolate).with 'en', 'bar', {}
- @backend.translate 'en', :bar, :scope => [:foo]
- end
-
- def test_translate_calls_interpolate_including_count_as_a_value
- @backend.expects(:interpolate).with 'en', 'bar', {:count => 1}
- @backend.translate 'en', :bar, :scope => [:foo], :count => 1
- end
-
- def test_translate_given_nil_as_a_locale_raises_an_argument_error
- assert_raise(I18n::InvalidLocale){ @backend.translate nil, :bar }
- end
-
- def test_translate_with_a_bogus_key_and_no_default_raises_missing_translation_data
- assert_raise(I18n::MissingTranslationData){ @backend.translate 'de', :bogus }
- end
-end
-
-class I18nSimpleBackendLookupTest < Test::Unit::TestCase
- include I18nSimpleBackendTestSetup
-
- # useful because this way we can use the backend with no key for interpolation/pluralization
- def test_lookup_given_nil_as_a_key_returns_nil
- assert_nil @backend.send(:lookup, 'en', nil)
- end
-
- def test_lookup_given_nested_keys_looks_up_a_nested_hash_value
- assert_equal 'bar', @backend.send(:lookup, 'en', :bar, [:foo])
- end
-end
-
-class I18nSimpleBackendPluralizeTest < Test::Unit::TestCase
- include I18nSimpleBackendTestSetup
-
- def test_pluralize_given_nil_returns_the_given_entry
- entry = {:one => 'bar', :other => 'bars'}
- assert_equal entry, @backend.send(:pluralize, nil, entry, nil)
- end
-
- def test_pluralize_given_0_returns_zero_string_if_zero_key_given
- assert_equal 'zero', @backend.send(:pluralize, nil, {:zero => 'zero', :one => 'bar', :other => 'bars'}, 0)
- end
-
- def test_pluralize_given_0_returns_plural_string_if_no_zero_key_given
- assert_equal 'bars', @backend.send(:pluralize, nil, {:one => 'bar', :other => 'bars'}, 0)
- end
-
- def test_pluralize_given_1_returns_singular_string
- assert_equal 'bar', @backend.send(:pluralize, nil, {:one => 'bar', :other => 'bars'}, 1)
- end
-
- def test_pluralize_given_2_returns_plural_string
- assert_equal 'bars', @backend.send(:pluralize, nil, {:one => 'bar', :other => 'bars'}, 2)
- end
-
- def test_pluralize_given_3_returns_plural_string
- assert_equal 'bars', @backend.send(:pluralize, nil, {:one => 'bar', :other => 'bars'}, 3)
- end
-
- def test_interpolate_given_incomplete_pluralization_data_raises_invalid_pluralization_data
- assert_raise(I18n::InvalidPluralizationData){ @backend.send(:pluralize, nil, {:one => 'bar'}, 2) }
- end
-
- # def test_interpolate_given_a_string_raises_invalid_pluralization_data
- # assert_raise(I18n::InvalidPluralizationData){ @backend.send(:pluralize, nil, 'bar', 2) }
- # end
- #
- # def test_interpolate_given_an_array_raises_invalid_pluralization_data
- # assert_raise(I18n::InvalidPluralizationData){ @backend.send(:pluralize, nil, ['bar'], 2) }
- # end
-end
-
-class I18nSimpleBackendInterpolateTest < Test::Unit::TestCase
- include I18nSimpleBackendTestSetup
-
- def test_interpolate_given_a_value_hash_interpolates_the_values_to_the_string
- assert_equal 'Hi David!', @backend.send(:interpolate, nil, 'Hi {{name}}!', :name => 'David')
- end
-
- def test_interpolate_given_a_value_hash_interpolates_into_unicode_string
- assert_equal 'Häi David!', @backend.send(:interpolate, nil, 'Häi {{name}}!', :name => 'David')
- end
-
- def test_interpolate_given_an_unicode_value_hash_interpolates_to_the_string
- assert_equal 'Hi ゆきひろ!', @backend.send(:interpolate, nil, 'Hi {{name}}!', :name => 'ゆきひろ')
- end
-
- def test_interpolate_given_an_unicode_value_hash_interpolates_into_unicode_string
- assert_equal 'こんにちは、ゆきひろさん!', @backend.send(:interpolate, nil, 'こんにちは、{{name}}さん!', :name => 'ゆきひろ')
- end
-
- if Kernel.const_defined?(:Encoding)
- def test_interpolate_given_a_non_unicode_multibyte_value_hash_interpolates_into_a_string_with_the_same_encoding
- assert_equal euc_jp('Hi ゆきひろ!'), @backend.send(:interpolate, nil, 'Hi {{name}}!', :name => euc_jp('ゆきひろ'))
- end
-
- def test_interpolate_given_an_unicode_value_hash_into_a_non_unicode_multibyte_string_raises_encoding_compatibility_error
- assert_raise(Encoding::CompatibilityError) do
- @backend.send(:interpolate, nil, euc_jp('こんにちは、{{name}}さん!'), :name => 'ゆきひろ')
- end
- end
-
- def test_interpolate_given_a_non_unicode_multibyte_value_hash_into_an_unicode_string_raises_encoding_compatibility_error
- assert_raise(Encoding::CompatibilityError) do
- @backend.send(:interpolate, nil, 'こんにちは、{{name}}さん!', :name => euc_jp('ゆきひろ'))
- end
- end
- end
-
- def test_interpolate_given_nil_as_a_string_returns_nil
- assert_nil @backend.send(:interpolate, nil, nil, :name => 'David')
- end
-
- def test_interpolate_given_an_non_string_as_a_string_returns_nil
- assert_equal [], @backend.send(:interpolate, nil, [], :name => 'David')
- end
-
- def test_interpolate_given_a_values_hash_with_nil_values_interpolates_the_string
- assert_equal 'Hi !', @backend.send(:interpolate, nil, 'Hi {{name}}!', {:name => nil})
- end
-
- def test_interpolate_given_an_empty_values_hash_raises_missing_interpolation_argument
- assert_raise(I18n::MissingInterpolationArgument) { @backend.send(:interpolate, nil, 'Hi {{name}}!', {}) }
- end
-
- def test_interpolate_given_a_string_containing_a_reserved_key_raises_reserved_interpolation_key
- assert_raise(I18n::ReservedInterpolationKey) { @backend.send(:interpolate, nil, '{{default}}', {:default => nil}) }
- end
-
- private
-
- def euc_jp(string)
- string.encode!(Encoding::EUC_JP)
- end
-end
-
-class I18nSimpleBackendLocalizeDateTest < Test::Unit::TestCase
- include I18nSimpleBackendTestSetup
-
- def setup
- @backend = I18n::Backend::Simple.new
- add_datetime_translations
- @date = Date.new 2008, 1, 1
- end
-
- def test_translate_given_the_short_format_it_uses_it
- assert_equal '01. Jan', @backend.localize('de', @date, :short)
- end
-
- def test_translate_given_the_long_format_it_uses_it
- assert_equal '01. Januar 2008', @backend.localize('de', @date, :long)
- end
-
- def test_translate_given_the_default_format_it_uses_it
- assert_equal '01.01.2008', @backend.localize('de', @date, :default)
- end
-
- def test_translate_given_a_day_name_format_it_returns_a_day_name
- assert_equal 'Dienstag', @backend.localize('de', @date, '%A')
- end
-
- def test_translate_given_an_abbr_day_name_format_it_returns_an_abbrevated_day_name
- assert_equal 'Di', @backend.localize('de', @date, '%a')
- end
-
- def test_translate_given_a_month_name_format_it_returns_a_month_name
- assert_equal 'Januar', @backend.localize('de', @date, '%B')
- end
-
- def test_translate_given_an_abbr_month_name_format_it_returns_an_abbrevated_month_name
- assert_equal 'Jan', @backend.localize('de', @date, '%b')
- end
-
- def test_translate_given_no_format_it_does_not_fail
- assert_nothing_raised{ @backend.localize 'de', @date }
- end
-
- def test_translate_given_an_unknown_format_it_does_not_fail
- assert_nothing_raised{ @backend.localize 'de', @date, '%x' }
- end
-
- def test_localize_nil_raises_argument_error
- assert_raise(I18n::ArgumentError) { @backend.localize 'de', nil }
- end
-
- def test_localize_object_raises_argument_error
- assert_raise(I18n::ArgumentError) { @backend.localize 'de', Object.new }
- end
-end
-
-class I18nSimpleBackendLocalizeDateTimeTest < Test::Unit::TestCase
- include I18nSimpleBackendTestSetup
-
- def setup
- @backend = I18n::Backend::Simple.new
- add_datetime_translations
- @morning = DateTime.new 2008, 1, 1, 6
- @evening = DateTime.new 2008, 1, 1, 18
- end
-
- def test_translate_given_the_short_format_it_uses_it
- assert_equal '01. Jan 06:00', @backend.localize('de', @morning, :short)
- end
-
- def test_translate_given_the_long_format_it_uses_it
- assert_equal '01. Januar 2008 06:00', @backend.localize('de', @morning, :long)
- end
-
- def test_translate_given_the_default_format_it_uses_it
- assert_equal 'Di, 01. Jan 2008 06:00:00 +0000', @backend.localize('de', @morning, :default)
- end
-
- def test_translate_given_a_day_name_format_it_returns_the_correct_day_name
- assert_equal 'Dienstag', @backend.localize('de', @morning, '%A')
- end
-
- def test_translate_given_an_abbr_day_name_format_it_returns_the_correct_abbrevated_day_name
- assert_equal 'Di', @backend.localize('de', @morning, '%a')
- end
-
- def test_translate_given_a_month_name_format_it_returns_the_correct_month_name
- assert_equal 'Januar', @backend.localize('de', @morning, '%B')
- end
-
- def test_translate_given_an_abbr_month_name_format_it_returns_the_correct_abbrevated_month_name
- assert_equal 'Jan', @backend.localize('de', @morning, '%b')
- end
-
- def test_translate_given_a_meridian_indicator_format_it_returns_the_correct_meridian_indicator
- assert_equal 'am', @backend.localize('de', @morning, '%p')
- assert_equal 'pm', @backend.localize('de', @evening, '%p')
- end
-
- def test_translate_given_no_format_it_does_not_fail
- assert_nothing_raised{ @backend.localize 'de', @morning }
- end
-
- def test_translate_given_an_unknown_format_it_does_not_fail
- assert_nothing_raised{ @backend.localize 'de', @morning, '%x' }
- end
-end
-
-class I18nSimpleBackendLocalizeTimeTest < Test::Unit::TestCase
- include I18nSimpleBackendTestSetup
-
- def setup
- @old_timezone, ENV['TZ'] = ENV['TZ'], 'UTC'
- @backend = I18n::Backend::Simple.new
- add_datetime_translations
- @morning = Time.parse '2008-01-01 6:00 UTC'
- @evening = Time.parse '2008-01-01 18:00 UTC'
- end
-
- def teardown
- @old_timezone ? ENV['TZ'] = @old_timezone : ENV.delete('TZ')
- end
-
- def test_translate_given_the_short_format_it_uses_it
- assert_equal '01. Jan 06:00', @backend.localize('de', @morning, :short)
- end
-
- def test_translate_given_the_long_format_it_uses_it
- assert_equal '01. Januar 2008 06:00', @backend.localize('de', @morning, :long)
- end
-
- # TODO Seems to break on Windows because ENV['TZ'] is ignored. What's a better way to do this?
- # def test_translate_given_the_default_format_it_uses_it
- # assert_equal 'Di, 01. Jan 2008 06:00:00 +0000', @backend.localize('de', @morning, :default)
- # end
-
- def test_translate_given_a_day_name_format_it_returns_the_correct_day_name
- assert_equal 'Dienstag', @backend.localize('de', @morning, '%A')
- end
-
- def test_translate_given_an_abbr_day_name_format_it_returns_the_correct_abbrevated_day_name
- assert_equal 'Di', @backend.localize('de', @morning, '%a')
- end
-
- def test_translate_given_a_month_name_format_it_returns_the_correct_month_name
- assert_equal 'Januar', @backend.localize('de', @morning, '%B')
- end
-
- def test_translate_given_an_abbr_month_name_format_it_returns_the_correct_abbrevated_month_name
- assert_equal 'Jan', @backend.localize('de', @morning, '%b')
- end
-
- def test_translate_given_a_meridian_indicator_format_it_returns_the_correct_meridian_indicator
- assert_equal 'am', @backend.localize('de', @morning, '%p')
- assert_equal 'pm', @backend.localize('de', @evening, '%p')
- end
-
- def test_translate_given_no_format_it_does_not_fail
- assert_nothing_raised{ @backend.localize 'de', @morning }
- end
-
- def test_translate_given_an_unknown_format_it_does_not_fail
- assert_nothing_raised{ @backend.localize 'de', @morning, '%x' }
- end
-end
-
-class I18nSimpleBackendHelperMethodsTest < Test::Unit::TestCase
- def setup
- @backend = I18n::Backend::Simple.new
- end
-
- def test_deep_symbolize_keys_works
- result = @backend.send :deep_symbolize_keys, 'foo' => {'bar' => {'baz' => 'bar'}}
- expected = {:foo => {:bar => {:baz => 'bar'}}}
- assert_equal expected, result
- end
-end
-
-class I18nSimpleBackendLoadTranslationsTest < Test::Unit::TestCase
- include I18nSimpleBackendTestSetup
-
- def test_load_translations_with_unknown_file_type_raises_exception
- assert_raise(I18n::UnknownFileType) { @backend.load_translations "#{@locale_dir}/en.xml" }
- end
-
- def test_load_translations_with_ruby_file_type_does_not_raise_exception
- assert_nothing_raised { @backend.load_translations "#{@locale_dir}/en.rb" }
- end
-
- def test_load_rb_loads_data_from_ruby_file
- data = @backend.send :load_rb, "#{@locale_dir}/en.rb"
- assert_equal({:'en-Ruby' => {:foo => {:bar => "baz"}}}, data)
- end
-
- def test_load_rb_loads_data_from_yaml_file
- data = @backend.send :load_yml, "#{@locale_dir}/en.yml"
- assert_equal({'en-Yaml' => {'foo' => {'bar' => 'baz'}}}, data)
- end
-
- def test_load_translations_loads_from_different_file_formats
- @backend = I18n::Backend::Simple.new
- @backend.load_translations "#{@locale_dir}/en.rb", "#{@locale_dir}/en.yml"
- expected = {
- :'en-Ruby' => {:foo => {:bar => "baz"}},
- :'en-Yaml' => {:foo => {:bar => "baz"}}
- }
- assert_equal expected, backend_get_translations
- end
-end
-
-class I18nSimpleBackendLoadPathTest < Test::Unit::TestCase
- include I18nSimpleBackendTestSetup
-
- def teardown
- I18n.load_path = []
- end
-
- def test_nested_load_paths_do_not_break_locale_loading
- @backend = I18n::Backend::Simple.new
- I18n.load_path = [[File.dirname(__FILE__) + '/locale/en.yml']]
- assert_nil backend_get_translations
- assert_nothing_raised { @backend.send :init_translations }
- assert_not_nil backend_get_translations
- end
-
- def test_adding_arrays_of_filenames_to_load_path_do_not_break_locale_loading
- @backend = I18n::Backend::Simple.new
- I18n.load_path << Dir[File.dirname(__FILE__) + '/locale/*.{rb,yml}']
- assert_nil backend_get_translations
- assert_nothing_raised { @backend.send :init_translations }
- assert_not_nil backend_get_translations
- end
-end
-
-class I18nSimpleBackendReloadTranslationsTest < Test::Unit::TestCase
- include I18nSimpleBackendTestSetup
-
- def setup
- @backend = I18n::Backend::Simple.new
- I18n.load_path = [File.dirname(__FILE__) + '/locale/en.yml']
- assert_nil backend_get_translations
- @backend.send :init_translations
- end
-
- def teardown
- I18n.load_path = []
- end
-
- def test_setup
- assert_not_nil backend_get_translations
- end
-
- def test_reload_translations_unloads_translations
- @backend.reload!
- assert_nil backend_get_translations
- end
-
- def test_reload_translations_uninitializes_translations
- @backend.reload!
- assert_equal @backend.initialized?, false
- end
-end
diff --git a/activesupport/lib/active_support/whiny_nil.rb b/activesupport/lib/active_support/whiny_nil.rb
index c4aaba7ab3..4f6ff7d3b5 100644
--- a/activesupport/lib/active_support/whiny_nil.rb
+++ b/activesupport/lib/active_support/whiny_nil.rb
@@ -43,10 +43,7 @@ class NilClass
private
def method_missing(method, *args, &block)
- # Ruby 1.9.2: disallow explicit coercion via method_missing.
- if method == :to_ary || method == :to_str
- super
- elsif klass = METHOD_CLASS_MAP[method]
+ if klass = METHOD_CLASS_MAP[method]
raise_nil_warning_for klass, method, caller
else
super
diff --git a/activesupport/test/autoload.rb b/activesupport/test/autoload.rb
new file mode 100644
index 0000000000..5d8026a9ca
--- /dev/null
+++ b/activesupport/test/autoload.rb
@@ -0,0 +1,80 @@
+require 'abstract_unit'
+
+class TestAutoloadModule < ActiveSupport::TestCase
+ include ActiveSupport::Testing::Isolation
+
+ module ::Fixtures
+ extend ActiveSupport::Autoload
+
+ module Autoload
+ extend ActiveSupport::Autoload
+ end
+ end
+
+ test "the autoload module works like normal autoload" do
+ module ::Fixtures::Autoload
+ autoload :SomeClass, "fixtures/autoload/some_class"
+ end
+
+ assert_nothing_raised { ::Fixtures::Autoload::SomeClass }
+ end
+
+ test "when specifying an :eager constant it still works like normal autoload by default" do
+ module ::Fixtures::Autoload
+ autoload :SomeClass, "fixtures/autoload/some_class"
+ end
+
+ assert !$LOADED_FEATURES.include?("fixtures/autoload/some_class.rb")
+ assert_nothing_raised { ::Fixtures::Autoload::SomeClass }
+ end
+
+ test ":eager constants can be triggered via ActiveSupport::Autoload.eager_autoload!" do
+ module ::Fixtures::Autoload
+ autoload :SomeClass, "fixtures/autoload/some_class"
+ end
+ ActiveSupport::Autoload.eager_autoload!
+ assert $LOADED_FEATURES.include?("fixtures/autoload/some_class.rb")
+ assert_nothing_raised { ::Fixtures::Autoload::SomeClass }
+ end
+
+ test "the location of autoloaded constants defaults to :name.underscore" do
+ module ::Fixtures::Autoload
+ autoload :SomeClass
+ end
+
+ assert !$LOADED_FEATURES.include?("fixtures/autoload/some_class.rb")
+ assert_nothing_raised { ::Fixtures::Autoload::SomeClass }
+ end
+
+ test "the location of :eager autoloaded constants defaults to :name.underscore" do
+ module ::Fixtures::Autoload
+ autoload :SomeClass
+ end
+
+ ActiveSupport::Autoload.eager_autoload!
+ assert $LOADED_FEATURES.include?("fixtures/autoload/some_class.rb")
+ assert_nothing_raised { ::Fixtures::Autoload::SomeClass }
+ end
+
+ test "a directory for a block of autoloads can be specified" do
+ module ::Fixtures
+ autoload_under "autoload" do
+ autoload :AnotherClass
+ end
+ end
+
+ assert !$LOADED_FEATURES.include?("fixtures/autoload/another_class.rb")
+ assert_nothing_raised { ::Fixtures::AnotherClass }
+ end
+
+ test "a path for a block of autoloads can be specified" do
+ module ::Fixtures
+ autoload_at "fixtures/autoload/another_class" do
+ autoload :AnotherClass
+ end
+ end
+
+ assert !$LOADED_FEATURES.include?("fixtures/autoload/another_class.rb")
+ assert_nothing_raised { ::Fixtures::AnotherClass }
+ end
+end \ No newline at end of file
diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb
index 4341ead488..278c05797b 100644
--- a/activesupport/test/core_ext/date_time_ext_test.rb
+++ b/activesupport/test/core_ext/date_time_ext_test.rb
@@ -350,6 +350,10 @@ class DateTimeExtCalculationsTest < Test::Unit::TestCase
assert_equal 946684800.0, DateTime.civil(1999,12,31,19,0,0,Rational(-5,24)).to_f
end
+ def test_to_i
+ assert_equal 946684800, DateTime.civil(2000).to_i
+ end
+
protected
def with_env_tz(new_tz = 'US/Eastern')
old_tz, ENV['TZ'] = ENV['TZ'], new_tz
diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb
index 66f5f9fbde..4650b796b6 100644
--- a/activesupport/test/core_ext/enumerable_test.rb
+++ b/activesupport/test/core_ext/enumerable_test.rb
@@ -89,4 +89,9 @@ class EnumerableTests < Test::Unit::TestCase
assert ![ 1, 2 ].many? {|x| x > 1 }
assert [ 1, 2, 2 ].many? {|x| x > 1 }
end
+
+ def test_exclude?
+ assert [ 1 ].exclude?(2)
+ assert ![ 1 ].exclude?(1)
+ end
end
diff --git a/activesupport/test/core_ext/object/to_query_test.rb b/activesupport/test/core_ext/object/to_query_test.rb
index 0fb15be654..4d655913cc 100644
--- a/activesupport/test/core_ext/object/to_query_test.rb
+++ b/activesupport/test/core_ext/object/to_query_test.rb
@@ -17,22 +17,22 @@ class ToQueryTest < Test::Unit::TestCase
end
def test_nested_conversion
- assert_query_equal 'person%5Blogin%5D=seckar&person%5Bname%5D=Nicholas',
+ assert_query_equal 'person[login]=seckar&person[name]=Nicholas',
:person => {:name => 'Nicholas', :login => 'seckar'}
end
def test_multiple_nested
- assert_query_equal 'account%5Bperson%5D%5Bid%5D=20&person%5Bid%5D=10',
+ assert_query_equal 'account[person][id]=20&person[id]=10',
:person => {:id => 10}, :account => {:person => {:id => 20}}
end
def test_array_values
- assert_query_equal 'person%5Bid%5D%5B%5D=10&person%5Bid%5D%5B%5D=20',
+ assert_query_equal 'person[id][]=10&person[id][]=20',
:person => {:id => [10, 20]}
end
def test_array_values_are_not_sorted
- assert_query_equal 'person%5Bid%5D%5B%5D=20&person%5Bid%5D%5B%5D=10',
+ assert_query_equal 'person[id][]=20&person[id][]=10',
:person => {:id => [20, 10]}
end
diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb
index bb60968a4f..3a12100e86 100644
--- a/activesupport/test/core_ext/time_with_zone_test.rb
+++ b/activesupport/test/core_ext/time_with_zone_test.rb
@@ -284,6 +284,12 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal 946684800, result
assert result.is_a?(Integer)
end
+
+ def test_to_i_with_wrapped_datetime
+ datetime = DateTime.civil(2000, 1, 1, 0)
+ twz = ActiveSupport::TimeWithZone.new(datetime, @time_zone)
+ assert_equal 946684800, twz.to_i
+ end
def test_to_time
assert_equal @twz, @twz.to_time
diff --git a/activesupport/test/deprecation_test.rb b/activesupport/test/deprecation_test.rb
index a3ae39d071..cf27357b32 100644
--- a/activesupport/test/deprecation_test.rb
+++ b/activesupport/test/deprecation_test.rb
@@ -62,7 +62,7 @@ class DeprecationTest < ActiveSupport::TestCase
end
def test_deprecate_class_method
- assert_deprecated(/none is deprecated.*test_deprecate_class_method at/) do
+ assert_deprecated(/none is deprecated.*test_deprecate_class_method/) do
assert_equal 1, @dtc.none
end
diff --git a/activesupport/test/fixtures/autoload/another_class.rb b/activesupport/test/fixtures/autoload/another_class.rb
new file mode 100644
index 0000000000..a240b3de41
--- /dev/null
+++ b/activesupport/test/fixtures/autoload/another_class.rb
@@ -0,0 +1,2 @@
+class Fixtures::AnotherClass
+end \ No newline at end of file
diff --git a/activesupport/test/fixtures/autoload/some_class.rb b/activesupport/test/fixtures/autoload/some_class.rb
new file mode 100644
index 0000000000..13b3c73ef5
--- /dev/null
+++ b/activesupport/test/fixtures/autoload/some_class.rb
@@ -0,0 +1,2 @@
+class Fixtures::Autoload::SomeClass
+end \ No newline at end of file
diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb
index 5d81d09f03..cf9a635b5f 100644
--- a/activesupport/test/json/encoding_test.rb
+++ b/activesupport/test/json/encoding_test.rb
@@ -23,7 +23,9 @@ class TestJSONEncoding < Test::Unit::TestCase
StringTests = [[ 'this is the <string>', %("this is the \\u003Cstring\\u003E")],
[ 'a "string" with quotes & an ampersand', %("a \\"string\\" with quotes \\u0026 an ampersand") ],
- [ 'http://test.host/posts/1', %("http://test.host/posts/1")]]
+ [ 'http://test.host/posts/1', %("http://test.host/posts/1")],
+ [ "Control characters: \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ %("Control characters: \\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000B\\f\\r\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F") ]]
ArrayTests = [[ ['a', 'b', 'c'], %([\"a\",\"b\",\"c\"]) ],
[ [1, 'a', :b, nil, false], %([1,\"a\",\"b\",null,false]) ]]
diff --git a/activesupport/test/notifications_test.rb b/activesupport/test/notifications_test.rb
index 35d44367cf..4f880d0db7 100644
--- a/activesupport/test/notifications_test.rb
+++ b/activesupport/test/notifications_test.rb
@@ -1,221 +1,170 @@
require 'abstract_unit'
-# Allow LittleFanout to be cleaned.
-class ActiveSupport::Notifications::LittleFanout
- def clear
- @listeners.clear
- end
-end
-
-class NotificationsEventTest < Test::Unit::TestCase
- def test_events_are_initialized_with_details
- event = event(:foo, Time.now, Time.now + 1, 1, random_id, :payload => :bar)
- assert_equal :foo, event.name
- assert_equal Hash[:payload => :bar], event.payload
- end
-
- def test_events_consumes_information_given_as_payload
- time = Time.now
- event = event(:foo, time, time + 0.01, 1, random_id, {})
-
- assert_equal Hash.new, event.payload
- assert_equal time, event.time
- assert_equal 1, event.result
- assert_equal 10.0, event.duration
- end
-
- def test_event_is_parent_based_on_time_frame
- time = Time.utc(2009, 01, 01, 0, 0, 1)
-
- parent = event(:foo, Time.utc(2009), Time.utc(2009) + 100, nil, random_id, {})
- child = event(:foo, time, time + 10, nil, random_id, {})
- not_child = event(:foo, time, time + 100, nil, random_id, {})
-
- assert parent.parent_of?(child)
- assert !child.parent_of?(parent)
- assert !parent.parent_of?(not_child)
- assert !not_child.parent_of?(parent)
- end
+module Notifications
+ class TestCase < ActiveSupport::TestCase
+ def setup
+ Thread.abort_on_exception = true
+
+ @notifier = ActiveSupport::Notifications::Notifier.new
+ @events = []
+ @notifier.subscribe { |*args| @events << event(*args) }
+ end
-protected
+ def teardown
+ Thread.abort_on_exception = false
+ end
- def random_id
- @random_id ||= ActiveSupport::SecureRandom.hex(10)
- end
+ private
+ def event(*args)
+ ActiveSupport::Notifications::Event.new(*args)
+ end
- def event(*args)
- ActiveSupport::Notifications::Event.new(*args)
+ def drain
+ @notifier.wait
+ end
end
-end
-class NotificationsMainTest < Test::Unit::TestCase
- def setup
- @events = []
- Thread.abort_on_exception = true
- ActiveSupport::Notifications.subscribe do |*args|
- @events << ActiveSupport::Notifications::Event.new(*args)
+ class PubSubTest < TestCase
+ def test_events_are_published_to_a_listener
+ @notifier.publish :foo
+ @notifier.wait
+ assert_equal [[:foo]], @events
end
- end
- def teardown
- Thread.abort_on_exception = false
- ActiveSupport::Notifications.queue.clear
- end
-
- def test_notifications_returns_action_result
- result = ActiveSupport::Notifications.instrument(:awesome, :payload => "notifications") do
- 1 + 1
- end
+ def test_subscriber_with_pattern
+ events = []
+ @notifier.subscribe('1') { |*args| events << args }
- assert_equal 2, result
- end
+ @notifier.publish '1'
+ @notifier.publish '1.a'
+ @notifier.publish 'a.1'
+ @notifier.wait
- def test_events_are_published_to_a_listener
- ActiveSupport::Notifications.instrument(:awesome, :payload => "notifications") do
- 1 + 1
+ assert_equal [['1'], ['1.a']], events
end
- drain
-
- assert_equal 1, @events.size
- assert_equal :awesome, @events.last.name
- assert_equal Hash[:payload => "notifications"], @events.last.payload
- end
+ def test_subscriber_with_pattern_as_regexp
+ events = []
+ @notifier.subscribe(/\d/) { |*args| events << args }
- def test_nested_events_can_be_instrumented
- ActiveSupport::Notifications.instrument(:awesome, :payload => "notifications") do
- ActiveSupport::Notifications.instrument(:wot, :payload => "child") do
- 1 + 1
- end
+ @notifier.publish '1'
+ @notifier.publish 'a.1'
+ @notifier.publish '1.a'
+ @notifier.wait
- drain
-
- assert_equal 1, @events.size
- assert_equal :wot, @events.first.name
- assert_equal Hash[:payload => "child"], @events.first.payload
+ assert_equal [['1'], ['a.1'], ['1.a']], events
end
- drain
+ def test_multiple_subscribers
+ @another = []
+ @notifier.subscribe { |*args| @another << args }
+ @notifier.publish :foo
+ @notifier.wait
- assert_equal 2, @events.size
- assert_equal :awesome, @events.last.name
- assert_equal Hash[:payload => "notifications"], @events.last.payload
- end
-
- def test_event_is_pushed_even_if_block_fails
- ActiveSupport::Notifications.instrument(:awesome, :payload => "notifications") do
- raise "OMG"
- end rescue RuntimeError
-
- drain
+ assert_equal [[:foo]], @events
+ assert_equal [[:foo]], @another
+ end
- assert_equal 1, @events.size
- assert_equal :awesome, @events.last.name
- assert_equal Hash[:payload => "notifications"], @events.last.payload
+ private
+ def event(*args)
+ args
+ end
end
- def test_event_is_pushed_even_without_block
- ActiveSupport::Notifications.instrument(:awesome, :payload => "notifications")
- drain
+ class SyncPubSubTest < PubSubTest
+ def setup
+ Thread.abort_on_exception = true
- assert_equal 1, @events.size
- assert_equal :awesome, @events.last.name
- assert_equal Hash[:payload => "notifications"], @events.last.payload
+ @notifier = ActiveSupport::Notifications::Notifier.new(ActiveSupport::Notifications::Fanout.new(true))
+ @events = []
+ @notifier.subscribe { |*args| @events << event(*args) }
+ end
end
- def test_subscribed_in_a_transaction
- @another = []
-
- ActiveSupport::Notifications.subscribe("cache") do |*args|
- @another << ActiveSupport::Notifications::Event.new(*args)
+ class InstrumentationTest < TestCase
+ def test_instrument_returns_block_result
+ assert_equal 2, @notifier.instrument(:awesome) { 1 + 1 }
end
- ActiveSupport::Notifications.instrument(:cache){ 1 }
- ActiveSupport::Notifications.transaction do
- ActiveSupport::Notifications.instrument(:cache){ 1 }
- end
- ActiveSupport::Notifications.instrument(:cache){ 1 }
+ def test_nested_events_can_be_instrumented
+ @notifier.instrument(:awesome, :payload => "notifications") do
+ @notifier.instrument(:wot, :payload => "child") do
+ 1 + 1
+ end
- drain
+ drain
- assert_equal 3, @another.size
- before, during, after = @another.map {|e| e.transaction_id }
- assert_equal before, after
- assert_not_equal before, during
- end
+ assert_equal 1, @events.size
+ assert_equal :wot, @events.first.name
+ assert_equal Hash[:payload => "child"], @events.first.payload
+ end
- def test_subscriber_with_pattern
- @another = []
+ drain
- ActiveSupport::Notifications.subscribe("cache") do |*args|
- @another << ActiveSupport::Notifications::Event.new(*args)
+ assert_equal 2, @events.size
+ assert_equal :awesome, @events.last.name
+ assert_equal Hash[:payload => "notifications"], @events.last.payload
end
- ActiveSupport::Notifications.instrument(:cache){ 1 }
-
- drain
+ def test_instrument_publishes_when_exception_is_raised
+ begin
+ @notifier.instrument(:awesome, :payload => "notifications") do
+ raise "OMG"
+ end
+ flunk
+ rescue
+ end
- assert_equal 1, @another.size
- assert_equal :cache, @another.first.name
- assert_equal 1, @another.first.result
- end
+ drain
- def test_subscriber_with_pattern_as_regexp
- @another = []
- ActiveSupport::Notifications.subscribe(/cache/) do |*args|
- @another << ActiveSupport::Notifications::Event.new(*args)
+ assert_equal 1, @events.size
+ assert_equal :awesome, @events.last.name
+ assert_equal Hash[:payload => "notifications"], @events.last.payload
end
- ActiveSupport::Notifications.instrument(:something){ 0 }
- ActiveSupport::Notifications.instrument(:cache){ 1 }
-
- drain
+ def test_event_is_pushed_even_without_block
+ @notifier.instrument(:awesome, :payload => "notifications")
+ drain
- assert_equal 1, @another.size
- assert_equal :cache, @another.first.name
- assert_equal 1, @another.first.result
+ assert_equal 1, @events.size
+ assert_equal :awesome, @events.last.name
+ assert_equal Hash[:payload => "notifications"], @events.last.payload
+ end
end
- def test_subscriber_allows_sync_listeners
- @another = []
- ActiveSupport::Notifications.subscribe(/cache/, :with => ActiveSupport::Notifications::SyncListener) do |*args|
- @another << ActiveSupport::Notifications::Event.new(*args)
+ class EventTest < TestCase
+ def test_events_are_initialized_with_details
+ event = event(:foo, Time.now, Time.now + 1, 1, random_id, :payload => :bar)
+ assert_equal :foo, event.name
+ assert_equal Hash[:payload => :bar], event.payload
end
- Thread.expects(:new).never
- ActiveSupport::Notifications.instrument(:something){ 0 }
- ActiveSupport::Notifications.instrument(:cache){ 1 }
+ def test_events_consumes_information_given_as_payload
+ time = Time.now
+ event = event(:foo, time, time + 0.01, 1, random_id, {})
- assert_equal 1, @another.size
- assert_equal :cache, @another.first.name
- assert_equal 1, @another.first.result
- end
-
- def test_with_several_consumers_and_several_events
- @another = []
- ActiveSupport::Notifications.subscribe do |*args|
- @another << ActiveSupport::Notifications::Event.new(*args)
+ assert_equal Hash.new, event.payload
+ assert_equal time, event.time
+ assert_equal 1, event.result
+ assert_equal 10.0, event.duration
end
- 1.upto(100) do |i|
- ActiveSupport::Notifications.instrument(:value){ i }
- end
+ def test_event_is_parent_based_on_time_frame
+ time = Time.utc(2009, 01, 01, 0, 0, 1)
- drain
+ parent = event(:foo, Time.utc(2009), Time.utc(2009) + 100, nil, random_id, {})
+ child = event(:foo, time, time + 10, nil, random_id, {})
+ not_child = event(:foo, time, time + 100, nil, random_id, {})
- assert_equal 100, @events.size
- assert_equal :value, @events.first.name
- assert_equal 1, @events.first.result
- assert_equal 100, @events.last.result
+ assert parent.parent_of?(child)
+ assert !child.parent_of?(parent)
+ assert !parent.parent_of?(not_child)
+ assert !not_child.parent_of?(parent)
+ end
- assert_equal 100, @another.size
- assert_equal :value, @another.first.name
- assert_equal 1, @another.first.result
- assert_equal 100, @another.last.result
+ protected
+ def random_id
+ @random_id ||= ActiveSupport::SecureRandom.hex(10)
+ end
end
-
- private
- def drain
- sleep(0.05) until ActiveSupport::Notifications.queue.drained?
- end
end
diff --git a/activesupport/test/whiny_nil_test.rb b/activesupport/test/whiny_nil_test.rb
index 009d97940f..1e4f8d854a 100644
--- a/activesupport/test/whiny_nil_test.rb
+++ b/activesupport/test/whiny_nil_test.rb
@@ -13,38 +13,39 @@ class WhinyNilTest < Test::Unit::TestCase
def test_unchanged
nil.method_thats_not_in_whiners
rescue NoMethodError => nme
- assert(nme.message =~ /nil:NilClass/)
+ assert_match(/nil:NilClass/, nme.message)
end
def test_active_record
nil.save!
rescue NoMethodError => nme
- assert(!(nme.message =~ /nil:NilClass/))
+ assert_no_match(/nil:NilClass/, nme.message)
assert_match(/nil\.save!/, nme.message)
end
def test_array
nil.each
rescue NoMethodError => nme
- assert(!(nme.message =~ /nil:NilClass/))
+ assert_no_match(/nil:NilClass/, nme.message)
assert_match(/nil\.each/, nme.message)
end
def test_id
nil.id
rescue RuntimeError => nme
- assert(!(nme.message =~ /nil:NilClass/))
+ assert_no_match(/nil:NilClass/, nme.message)
end
def test_no_to_ary_coercion
nil.to_ary
rescue NoMethodError => nme
- assert(nme.message =~ /nil:NilClass/)
+ assert_no_match(/nil:NilClass/, nme.message)
+ assert_match(/nil\.to_ary/, nme.message)
end
def test_no_to_str_coercion
nil.to_str
rescue NoMethodError => nme
- assert(nme.message =~ /nil:NilClass/)
+ assert_match(/nil:NilClass/, nme.message)
end
end
diff --git a/ci/geminstaller.yml b/ci/geminstaller.yml
index 776ae8d98d..3dc2000bf9 100644
--- a/ci/geminstaller.yml
+++ b/ci/geminstaller.yml
@@ -5,4 +5,4 @@ gems:
- name: rubygems-update
version: >= 1.3.5
- name: bundler
- version: >= 0.6.0
+ version: >= 0.7.1
diff --git a/rack b/rack
new file mode 160000
+Subproject adf996587aecdd604eff441b8b69e4c47a8c261
diff --git a/rack-mount b/rack-mount
deleted file mode 160000
-Subproject 3784e633b42f43a4131e02519be60080d179da2
diff --git a/railties/rails.gemspec b/rails.gemspec
index dc66e1efea..878a342903 100644
--- a/railties/rails.gemspec
+++ b/rails.gemspec
@@ -8,22 +8,16 @@ Gem::Specification.new do |s|
on top of either MySQL, PostgreSQL, SQLite, DB2, SQL Server, or Oracle with eRuby- or Builder-based templates.
EOF
- s.add_dependency('rake', '>= 0.8.3')
s.add_dependency('activesupport', '= 3.0.pre')
- s.add_dependency('activerecord', '= 3.0.pre')
s.add_dependency('actionpack', '= 3.0.pre')
- s.add_dependency('actionmailer', '= 3.0.pre')
+ s.add_dependency('activerecord', '= 3.0.pre')
s.add_dependency('activeresource', '= 3.0.pre')
+ s.add_dependency('actionmailer', '= 3.0.pre')
+ s.add_dependency('railties', '= 3.0.pre')
s.rdoc_options << '--exclude' << '.'
s.has_rdoc = false
- s.files = Dir['CHANGELOG', 'README', 'bin/**/*', 'builtin/**/*', 'guides/**/*', 'lib/**/{*,.[a-z]*}']
- s.require_path = 'lib'
- s.bindir = "bin"
- s.executables = ["rails"]
- s.default_executable = "rails"
-
s.author = "David Heinemeier Hansson"
s.email = "david@loudthinking.com"
s.homepage = "http://www.rubyonrails.org"
diff --git a/railties/CHANGELOG b/railties/CHANGELOG
index 66e0d5e9c5..9ef2922133 100644
--- a/railties/CHANGELOG
+++ b/railties/CHANGELOG
@@ -1,5 +1,23 @@
*Edge*
+* Added cookies.permanent, cookies.signed, and cookies.permanent.signed accessor for common cookie actions [DHH]. Examples:
+
+ cookies.permanent[:prefers_open_id] = true
+ # => Set-Cookie: prefers_open_id=true; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
+
+ cookies.signed[:discount] = 45
+ # => Set-Cookie: discount=BAhpMg==--2c1c6906c90a3bc4fd54a51ffb41dffa4bf6b5f7; path=/
+
+ cookies.signed[:discount]
+ # => 45 (if the cookie was changed, you'll get a InvalidSignature exception)
+
+ cookies.permanent.signed[:remember_me] = current_user.id
+ # => Set-Cookie: discount=BAhU--848956038e692d7046deab32b7131856ab20e14e; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
+
+ ...to use the signed cookies, you need to set a secret to ActionController::Base.cookie_verifier_secret (automatically done in config/initializers/cookie_verification_secret.rb for new Rails applications).
+
+* Added config/initializers/cookie_verification_secret.rb with an auto-generated secret for using ActionController::Base#cookies.signed [DHH]
+
* Fixed that the debugger wouldn't go into IRB mode because of left-over ARGVs [DHH]
* I18n support for plugins. #2325 [Antonio Tapiador, Sven Fuchs]
diff --git a/railties/Rakefile b/railties/Rakefile
index e6f698fc74..07c2ff84a0 100644
--- a/railties/Rakefile
+++ b/railties/Rakefile
@@ -1,3 +1,8 @@
+begin
+ require File.expand_path('../../vendor/gems/environment', __FILE__)
+rescue LoadError
+end
+
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
@@ -10,7 +15,7 @@ $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/lib"
require 'rails/version'
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
-PKG_NAME = ENV['PKG_NAME'] || 'rails'
+PKG_NAME = ENV['PKG_NAME'] || 'railties'
PKG_VERSION = Rails::VERSION::STRING + PKG_BUILD
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
PKG_DESTINATION = ENV["RAILS_PKG_DESTINATION"] || "../#{PKG_NAME}"
@@ -141,7 +146,7 @@ Rake::RDocTask.new { |rdoc|
# Generate GEM ----------------------------------------------------------------------------
-spec = eval(File.read('rails.gemspec'))
+spec = eval(File.read('railties.gemspec'))
Rake::GemPackageTask.new(spec) do |pkg|
pkg.gem_spec = spec
diff --git a/railties/bin/rails b/railties/bin/rails
index 808df97429..0f51d5739f 100755
--- a/railties/bin/rails
+++ b/railties/bin/rails
@@ -4,9 +4,10 @@ rescue LoadError
# If people are not using gems, the load path must still
# be correct.
# TODO: Remove the begin / rescue block somehow
- $:.unshift File.dirname(__FILE__) + '/../lib'
- $:.unshift File.dirname(__FILE__) + '/../../activesupport/lib'
- retry
+ $:.unshift File.expand_path('../../lib', __FILE__)
+ $:.unshift File.expand_path('../../../activesupport/lib', __FILE__)
+ $:.unshift File.expand_path('../../../actionpack/lib', __FILE__)
+ require 'rails/ruby_version_check'
end
Signal.trap("INT") { puts; exit }
diff --git a/railties/builtin/routes.rb b/railties/builtin/routes.rb
new file mode 100644
index 0000000000..ef9d9e756d
--- /dev/null
+++ b/railties/builtin/routes.rb
@@ -0,0 +1,3 @@
+ActionController::Routing::Routes.draw do |map|
+ match '/rails/info/properties' => "rails/info#properties"
+end \ No newline at end of file
diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb
index c23b67e321..9fb3cd9f94 100644
--- a/railties/lib/rails.rb
+++ b/railties/lib/rails.rb
@@ -1,13 +1,9 @@
-require "pathname"
+require "rails/core"
-require 'rails/initializable'
-require 'rails/application'
-require 'rails/railties_path'
-require 'rails/version'
-require 'rails/rack'
-require 'rails/paths'
-require 'rails/core'
-require 'rails/configuration'
-require 'rails/deprecation'
-require 'rails/initializer'
-require 'rails/plugin' \ No newline at end of file
+%w(active_model active_record action_controller action_view action_mailer active_resource).each do |framework|
+ begin
+ require framework
+ require "#{framework}/rails"
+ rescue LoadError
+ end
+end \ No newline at end of file
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 7c2d8eab67..cd579a1c0d 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -1,58 +1,83 @@
+require "fileutils"
+require 'active_support/core_ext/module/delegation'
+
module Rails
class Application
include Initializable
class << self
- def inherited(klass)
- Rails.application ||= klass unless klass.name =~ /Rails/
- super
- end
+ attr_writer :config
+ alias configure class_eval
+ delegate :initialize!, :load_tasks, :to => :instance
- # Stub out App initialize
- def initialize!
- new
- end
-
- def new
- @instance ||= super
+ private :new
+ def instance
+ @instance ||= new
end
def config
- @config ||= Configuration.new
+ @config ||= Configuration.new(Plugin::Configuration.default)
end
- # TODO: change the plugin loader to use config
- alias configuration config
-
- def config=(config)
- @config = config
+ def routes
+ ActionController::Routing::Routes
end
+ end
- def root
- config.root
- end
+ delegate :config, :routes, :to => :'self.class'
+ delegate :root, :middleware, :to => :config
+ attr_reader :route_configuration_files
- def call(env)
- new.call(env)
- end
+ def initialize
+ require_environment
+ Rails.application ||= self
+ @route_configuration_files = []
end
- def initialize
+ def initialize!
run_initializers(self)
+ self
end
- def config
- self.class.config
+ def require_environment
+ require config.environment_path
+ rescue LoadError
end
- alias configuration config
+ def routes_changed_at
+ routes_changed_at = nil
- def middleware
- config.middleware
+ route_configuration_files.each do |config|
+ config_changed_at = File.stat(config).mtime
+
+ if routes_changed_at.nil? || config_changed_at > routes_changed_at
+ routes_changed_at = config_changed_at
+ end
+ end
+
+ routes_changed_at
end
- def routes
- ActionController::Routing::Routes
+ def reload_routes!
+ routes.disable_clear_and_finalize = true
+
+ routes.clear!
+ route_configuration_files.each { |config| load(config) }
+ routes.finalize!
+
+ nil
+ ensure
+ routes.disable_clear_and_finalize = false
+ end
+
+ def load_tasks
+ require "rails/tasks"
+ Dir["#{root}/vendor/plugins/*/**/tasks/**/*.rake"].sort.each { |ext| load ext }
+ Dir["#{root}/lib/tasks/**/*.rake"].sort.each { |ext| load ext }
+ task :environment do
+ $rails_rake_task = true
+ initialize!
+ end
end
def initializers
@@ -61,8 +86,11 @@ module Rails
initializers
end
+ # TODO: Fix this method
def plugins
@plugins ||= begin
+ plugin_names = config.plugins || [:all]
+ Plugin.plugins.select { |p| plugin_names.include?(:all) || plugin_names.include?(p.plugin_name) } +
Plugin::Vendored.all(config.plugins || [:all], config.paths.vendor.plugins)
end
end
@@ -72,8 +100,8 @@ module Rails
@app.call(env)
end
- initializer :initialize_rails do
- Rails.run_initializers
+ initializer :load_all_active_support do
+ require "active_support/all" unless config.active_support.bare
end
# Set the <tt>$LOAD_PATH</tt> based on the value of
@@ -83,24 +111,6 @@ module Rails
$LOAD_PATH.uniq!
end
- # Requires all frameworks specified by the Configuration#frameworks
- # list. By default, all frameworks (Active Record, Active Support,
- # Action Pack, Action Mailer, and Active Resource) are loaded.
- initializer :require_frameworks do
- begin
- require 'active_support'
- require 'active_support/core_ext/kernel/reporting'
- require 'active_support/core_ext/logger'
-
- # TODO: This is here to make Sam Ruby's tests pass. Needs discussion.
- require 'active_support/core_ext/numeric/bytes'
- config.frameworks.each { |framework| require(framework.to_s) }
- rescue LoadError => e
- # Re-raise as RuntimeError because Mongrel would swallow LoadError.
- raise e.to_s
- end
- end
-
# Set the paths from which Rails will automatically load source files, and
# the load_once paths.
initializer :set_autoload_paths do
@@ -123,25 +133,7 @@ module Rails
# Create tmp directories
initializer :ensure_tmp_directories_exist do
%w(cache pids sessions sockets).each do |dir_to_make|
- FileUtils.mkdir_p(File.join(config.root, 'tmp', dir_to_make))
- end
- end
-
- # Loads the environment specified by Configuration#environment_path, which
- # is typically one of development, test, or production.
- initializer :load_environment do
- silence_warnings do
- next if @environment_loaded
- next unless File.file?(config.environment_path)
-
- @environment_loaded = true
- constants = self.class.constants
-
- eval(IO.read(config.environment_path), binding, config.environment_path)
-
- (self.class.constants - constants).each do |const|
- Object.const_set(const, self.class.const_get(const))
- end
+ FileUtils.mkdir_p(File.join(root, 'tmp', dir_to_make))
end
end
@@ -149,44 +141,7 @@ module Rails
# Used by Passenger to ensure everything's loaded before forking and
# to avoid autoload race conditions in JRuby.
initializer :preload_frameworks do
- if config.preload_frameworks
- config.frameworks.each do |framework|
- # String#classify and #constantize aren't available yet.
- toplevel = Object.const_get(framework.to_s.gsub(/(?:^|_)(.)/) { $1.upcase })
- toplevel.load_all! if toplevel.respond_to?(:load_all!)
- end
- end
- end
-
- # This initialization routine does nothing unless <tt>:active_record</tt>
- # is one of the frameworks to load (Configuration#frameworks). If it is,
- # this sets the database configuration from Configuration#database_configuration
- # and then establishes the connection.
- initializer :initialize_database do
- if config.frameworks.include?(:active_record)
- ActiveRecord::Base.configurations = config.database_configuration
- ActiveRecord::Base.establish_connection
- end
- end
-
- # Include middleware to serve up static assets
- initializer :initialize_static_server do
- if config.frameworks.include?(:action_controller) && config.serve_static_assets
- config.middleware.use(ActionDispatch::Static, Rails.public_path)
- end
- end
-
- initializer :initialize_middleware_stack do
- if config.frameworks.include?(:action_controller)
- config.middleware.use(::Rack::Lock) unless ActionController::Base.allow_concurrency
- config.middleware.use(ActionDispatch::ShowExceptions, ActionController::Base.consider_all_requests_local)
- config.middleware.use(ActionDispatch::Callbacks, ActionController::Dispatcher.prepare_each_request)
- config.middleware.use(lambda { ActionController::Base.session_store }, lambda { ActionController::Base.session_options })
- config.middleware.use(ActionDispatch::ParamsParser)
- config.middleware.use(::Rack::MethodOverride)
- config.middleware.use(::Rack::Head)
- config.middleware.use(ActionDispatch::StringCoercion)
- end
+ ActiveSupport::Autoload.eager_load! if config.preload_frameworks
end
initializer :initialize_cache do
@@ -200,12 +155,6 @@ module Rails
end
end
- initializer :initialize_framework_caches do
- if config.frameworks.include?(:action_controller)
- ActionController::Base.cache_store ||= RAILS_CACHE
- end
- end
-
initializer :initialize_logger do
# if the environment has explicitly defined a logger, use it
next if Rails.logger
@@ -236,10 +185,6 @@ module Rails
# logger is already set, it is not changed, otherwise it is set to use
# RAILS_DEFAULT_LOGGER.
initializer :initialize_framework_logging do
- for framework in ([ :active_record, :action_controller, :action_mailer ] & config.frameworks)
- framework.to_s.camelize.constantize.const_get("Base").logger ||= Rails.logger
- end
-
ActiveSupport::Dependencies.logger ||= Rails.logger
Rails.cache.logger ||= Rails.logger
end
@@ -257,7 +202,7 @@ module Rails
require('active_support/whiny_nil') if config.whiny_nils
end
- # Sets the default value for Time.zone, and turns on ActiveRecord::Base#time_zone_aware_attributes.
+ # Sets the default value for Time.zone
# If assigned value cannot be matched to a TimeZone, an exception will be raised.
initializer :initialize_time_zone do
if config.time_zone
@@ -271,11 +216,6 @@ module Rails
end
Time.zone_default = zone_default
-
- if config.frameworks.include?(:active_record)
- ActiveRecord::Base.time_zone_aware_attributes = true
- ActiveRecord::Base.default_timezone = :utc
- end
end
end
@@ -291,110 +231,28 @@ module Rails
end
end
- # Initializes framework-specific settings for each of the loaded frameworks
- # (Configuration#frameworks). The available settings map to the accessors
- # on each of the corresponding Base classes.
- initializer :initialize_framework_settings do
- config.frameworks.each do |framework|
- base_class = framework.to_s.camelize.constantize.const_get("Base")
-
- config.send(framework).each do |setting, value|
- base_class.send("#{setting}=", value)
- end
- end
- config.active_support.each do |setting, value|
- ActiveSupport.send("#{setting}=", value)
- end
- end
-
- # Sets +ActionController::Base#view_paths+ and +ActionMailer::Base#template_root+
- # (but only for those frameworks that are to be loaded). If the framework's
- # paths have already been set, it is not changed, otherwise it is
- # set to use Configuration#view_path.
- initializer :initialize_framework_views do
- if config.frameworks.include?(:action_view)
- view_path = ActionView::PathSet.type_cast(config.view_path, config.cache_classes)
- ActionMailer::Base.template_root = view_path if config.frameworks.include?(:action_mailer) && ActionMailer::Base.view_paths.blank?
- ActionController::Base.view_paths = view_path if config.frameworks.include?(:action_controller) && ActionController::Base.view_paths.blank?
- end
- end
-
- initializer :initialize_metal do
- # TODO: Make Rails and metal work without ActionController
- if config.frameworks.include?(:action_controller)
- Rails::Rack::Metal.requested_metals = config.metals
-
- config.middleware.insert_before(
- :"ActionDispatch::ParamsParser",
- Rails::Rack::Metal, :if => Rails::Rack::Metal.metals.any?)
- end
- end
-
# # bail out if gems are missing - note that check_gem_dependencies will have
# # already called abort() unless $gems_rake_task is set
# return unless gems_dependencies_loaded
initializer :load_application_initializers do
- Dir["#{configuration.root}/config/initializers/**/*.rb"].sort.each do |initializer|
+ Dir["#{root}/config/initializers/**/*.rb"].sort.each do |initializer|
load(initializer)
end
end
# Fires the user-supplied after_initialize block (Configuration#after_initialize)
initializer :after_initialize do
- configuration.after_initialize_blocks.each do |block|
+ config.after_initialize_blocks.each do |block|
block.call
end
end
- # # Setup database middleware after initializers have run
- initializer :initialize_database_middleware do
- if configuration.frameworks.include?(:active_record)
- if configuration.frameworks.include?(:action_controller) && ActionController::Base.session_store &&
- ActionController::Base.session_store.name == 'ActiveRecord::SessionStore'
- configuration.middleware.insert_before :"ActiveRecord::SessionStore", ActiveRecord::ConnectionAdapters::ConnectionManagement
- configuration.middleware.insert_before :"ActiveRecord::SessionStore", ActiveRecord::QueryCache
- else
- configuration.middleware.use ActiveRecord::ConnectionAdapters::ConnectionManagement
- configuration.middleware.use ActiveRecord::QueryCache
- end
- end
- end
-
- # TODO: Make a DSL way to limit an initializer to a particular framework
-
- # # Prepare dispatcher callbacks and run 'prepare' callbacks
- initializer :prepare_dispatcher do
- next unless configuration.frameworks.include?(:action_controller)
- require 'rails/dispatcher' unless defined?(::Dispatcher)
- Dispatcher.define_dispatcher_callbacks(configuration.cache_classes)
- end
-
- # Routing must be initialized after plugins to allow the former to extend the routes
- # ---
- # If Action Controller is not one of the loaded frameworks (Configuration#frameworks)
- # this does nothing. Otherwise, it loads the routing definitions and sets up
- # loading module used to lazily load controllers (Configuration#controller_paths).
- initializer :initialize_routing do
- next unless configuration.frameworks.include?(:action_controller)
-
- ActionController::Routing.controller_paths += configuration.controller_paths
- ActionController::Routing::Routes.add_configuration_file(configuration.routes_configuration_file)
- ActionController::Routing::Routes.reload!
- end
- #
- # # Observers are loaded after plugins in case Observers or observed models are modified by plugins.
- initializer :load_observers do
- if configuration.frameworks.include?(:active_record)
- ActiveRecord::Base.instantiate_observers
- end
- end
-
# Eager load application classes
initializer :load_application_classes do
next if $rails_rake_task
- if configuration.cache_classes
- configuration.eager_load_paths.each do |load_path|
+ if config.cache_classes
+ config.eager_load_paths.each do |load_path|
matcher = /\A#{Regexp.escape(load_path)}(.*)\.rb\Z/
Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
require_dependency file.sub(matcher, '\1')
@@ -405,7 +263,7 @@ module Rails
# Disable dependency loading during request cycle
initializer :disable_dependency_loading do
- if configuration.cache_classes && !configuration.dependency_loading
+ if config.cache_classes && !config.dependency_loading
ActiveSupport::Dependencies.unhook!
end
end
diff --git a/railties/lib/rails/commands/console.rb b/railties/lib/rails/commands/console.rb
index b977b7162f..37eb6d40ea 100644
--- a/railties/lib/rails/commands/console.rb
+++ b/railties/lib/rails/commands/console.rb
@@ -1,45 +1,56 @@
-irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
-
require 'optparse'
+require 'irb'
+require "irb/completion"
-options = { :sandbox => false, :irb => irb }
-OptionParser.new do |opt|
- opt.banner = "Usage: console [environment] [options]"
- opt.on('-s', '--sandbox', 'Rollback database modifications on exit.') { |v| options[:sandbox] = v }
- opt.on("--irb=[#{irb}]", 'Invoke a different irb.') { |v| options[:irb] = v }
- opt.on("--debugger", 'Enable ruby-debugging for the console.') { |v| options[:debugger] = v }
- opt.parse!(ARGV)
-end
+module Rails
+ class Console
+ ENVIRONMENTS = %w(production development test)
-libs = " -r irb/completion"
-libs << %( -r "#{Rails.root}/config/environment")
-libs << " -r rails/console_app"
-libs << " -r rails/console_sandbox" if options[:sandbox]
-libs << " -r rails/console_with_helpers"
-
-if options[:debugger]
- begin
- require 'ruby-debug'
- libs << " -r ruby-debug"
- puts "=> Debugger enabled"
- rescue Exception
- puts "You need to install ruby-debug to run the console in debugging mode. With gems, use 'gem install ruby-debug'"
- exit
- end
-end
+ def self.start(app)
+ new(app).start
+ end
-ENV['RAILS_ENV'] = case ARGV.first
- when "p"; "production"
- when "d"; "development"
- when "t"; "test"
- else
- ARGV.first || ENV['RAILS_ENV'] || 'development'
-end
+ def initialize(app)
+ @app = app
+ end
+
+ def start
+ options = {}
-if options[:sandbox]
- puts "Loading #{ENV['RAILS_ENV']} environment in sandbox (Rails #{Rails.version})"
- puts "Any modifications you make will be rolled back on exit"
-else
- puts "Loading #{ENV['RAILS_ENV']} environment (Rails #{Rails.version})"
+ OptionParser.new do |opt|
+ opt.banner = "Usage: console [environment] [options]"
+ opt.on('-s', '--sandbox', 'Rollback database modifications on exit.') { |v| options[:sandbox] = v }
+ opt.on("--debugger", 'Enable ruby-debugging for the console.') { |v| options[:debugger] = v }
+ opt.on('--irb') { |v| abort '--irb option is no longer supported. Invoke `/your/choice/of/ruby script/console` instead' }
+ opt.parse!(ARGV)
+ end
+
+ if env = ARGV.first
+ ENV['RAILS_ENV'] = ENVIRONMENTS.find { |e| e.index(env) } || env
+ end
+
+ @app.initialize!
+ require "rails/console_app"
+ require "rails/console_sandbox" if options[:sandbox]
+ require "rails/console_with_helpers"
+
+ if options[:debugger]
+ begin
+ require 'ruby-debug'
+ puts "=> Debugger enabled"
+ rescue Exception
+ puts "You need to install ruby-debug to run the console in debugging mode. With gems, use 'gem install ruby-debug'"
+ exit
+ end
+ end
+
+ if options[:sandbox]
+ puts "Loading #{Rails.env} environment in sandbox (Rails #{Rails.version})"
+ puts "Any modifications you make will be rolled back on exit"
+ else
+ puts "Loading #{Rails.env} environment (Rails #{Rails.version})"
+ end
+ IRB.start
+ end
+ end
end
-exec "#{options[:irb]} #{libs} --simple-prompt"
diff --git a/railties/lib/rails/commands/dbconsole.rb b/railties/lib/rails/commands/dbconsole.rb
index 4e699acf6b..77c3404343 100644
--- a/railties/lib/rails/commands/dbconsole.rb
+++ b/railties/lib/rails/commands/dbconsole.rb
@@ -2,86 +2,99 @@ require 'erb'
require 'yaml'
require 'optparse'
-include_password = false
-options = {}
-
-OptionParser.new do |opt|
- opt.banner = "Usage: dbconsole [options] [environment]"
- opt.on("-p", "--include-password", "Automatically provide the password from database.yml") do |v|
- include_password = true
- end
-
- opt.on("--mode [MODE]", ['html', 'list', 'line', 'column'],
- "Automatically put the sqlite3 database in the specified mode (html, list, line, column).") do |mode|
- options['mode'] = mode
- end
-
- opt.on("-h", "--header") do |h|
- options['header'] = h
- end
-
- opt.parse!(ARGV)
- abort opt.to_s unless (0..1).include?(ARGV.size)
-end
-
-env = ARGV.first || ENV['RAILS_ENV'] || 'development'
-unless config = YAML::load(ERB.new(IO.read(Rails.root + "/config/database.yml")).result)[env]
- abort "No database is configured for the environment '#{env}'"
-end
-
+module Rails
+ class DBConsole
+ def self.start(app)
+ new(app).start
+ end
-def find_cmd(*commands)
- dirs_on_path = ENV['PATH'].to_s.split(File::PATH_SEPARATOR)
- commands += commands.map{|cmd| "#{cmd}.exe"} if RUBY_PLATFORM =~ /win32/
+ def initialize(app)
+ @app = app
+ end
- full_path_command = nil
- found = commands.detect do |cmd|
- dir = dirs_on_path.detect do |path|
- full_path_command = File.join(path, cmd)
- File.executable? full_path_command
+ def start
+ include_password = false
+ options = {}
+ OptionParser.new do |opt|
+ opt.banner = "Usage: dbconsole [options] [environment]"
+ opt.on("-p", "--include-password", "Automatically provide the password from database.yml") do |v|
+ include_password = true
+ end
+
+ opt.on("--mode [MODE]", ['html', 'list', 'line', 'column'],
+ "Automatically put the sqlite3 database in the specified mode (html, list, line, column).") do |mode|
+ options['mode'] = mode
+ end
+
+ opt.on("-h", "--header") do |h|
+ options['header'] = h
+ end
+
+ opt.parse!(ARGV)
+ abort opt.to_s unless (0..1).include?(ARGV.size)
+ end
+
+ env = ARGV.first || ENV['RAILS_ENV'] || 'development'
+ unless config = YAML::load(ERB.new(IO.read("#{@app.root}/config/database.yml")).result)[env]
+ abort "No database is configured for the environment '#{env}'"
+ end
+
+
+ def find_cmd(*commands)
+ dirs_on_path = ENV['PATH'].to_s.split(File::PATH_SEPARATOR)
+ commands += commands.map{|cmd| "#{cmd}.exe"} if RUBY_PLATFORM =~ /win32/
+
+ full_path_command = nil
+ found = commands.detect do |cmd|
+ dir = dirs_on_path.detect do |path|
+ full_path_command = File.join(path, cmd)
+ File.executable? full_path_command
+ end
+ end
+ found ? full_path_command : abort("Couldn't find database client: #{commands.join(', ')}. Check your $PATH and try again.")
+ end
+
+ case config["adapter"]
+ when "mysql"
+ args = {
+ 'host' => '--host',
+ 'port' => '--port',
+ 'socket' => '--socket',
+ 'username' => '--user',
+ 'encoding' => '--default-character-set'
+ }.map { |opt, arg| "#{arg}=#{config[opt]}" if config[opt] }.compact
+
+ if config['password'] && include_password
+ args << "--password=#{config['password']}"
+ elsif config['password'] && !config['password'].to_s.empty?
+ args << "-p"
+ end
+
+ args << config['database']
+
+ exec(find_cmd('mysql', 'mysql5'), *args)
+
+ when "postgresql"
+ ENV['PGUSER'] = config["username"] if config["username"]
+ ENV['PGHOST'] = config["host"] if config["host"]
+ ENV['PGPORT'] = config["port"].to_s if config["port"]
+ ENV['PGPASSWORD'] = config["password"].to_s if config["password"] && include_password
+ exec(find_cmd('psql'), config["database"])
+
+ when "sqlite"
+ exec(find_cmd('sqlite'), config["database"])
+
+ when "sqlite3"
+ args = []
+
+ args << "-#{options['mode']}" if options['mode']
+ args << "-header" if options['header']
+ args << config['database']
+
+ exec(find_cmd('sqlite3'), *args)
+ else
+ abort "Unknown command-line client for #{config['database']}. Submit a Rails patch to add support!"
+ end
end
end
- found ? full_path_command : abort("Couldn't find database client: #{commands.join(', ')}. Check your $PATH and try again.")
-end
-
-case config["adapter"]
-when "mysql"
- args = {
- 'host' => '--host',
- 'port' => '--port',
- 'socket' => '--socket',
- 'username' => '--user',
- 'encoding' => '--default-character-set'
- }.map { |opt, arg| "#{arg}=#{config[opt]}" if config[opt] }.compact
-
- if config['password'] && include_password
- args << "--password=#{config['password']}"
- elsif config['password'] && !config['password'].to_s.empty?
- args << "-p"
- end
-
- args << config['database']
-
- exec(find_cmd('mysql', 'mysql5'), *args)
-
-when "postgresql"
- ENV['PGUSER'] = config["username"] if config["username"]
- ENV['PGHOST'] = config["host"] if config["host"]
- ENV['PGPORT'] = config["port"].to_s if config["port"]
- ENV['PGPASSWORD'] = config["password"].to_s if config["password"] && include_password
- exec(find_cmd('psql'), config["database"])
-
-when "sqlite"
- exec(find_cmd('sqlite'), config["database"])
-
-when "sqlite3"
- args = []
-
- args << "-#{options['mode']}" if options['mode']
- args << "-header" if options['header']
- args << config['database']
-
- exec(find_cmd('sqlite3'), *args)
-else
- abort "Unknown command-line client for #{config['database']}. Submit a Rails patch to add support!"
-end
+end \ No newline at end of file
diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb
index 2c90851fb2..09d7207d51 100644
--- a/railties/lib/rails/commands/server.rb
+++ b/railties/lib/rails/commands/server.rb
@@ -1,73 +1,76 @@
-require 'action_dispatch'
-
require 'fileutils'
require 'optparse'
+require 'action_dispatch'
-options = {
- :Port => 3000,
- :Host => "0.0.0.0",
- :environment => (ENV['RAILS_ENV'] || "development").dup,
- :config => "#{Rails.root}/config.ru",
- :detach => false,
- :debugger => false
-}
-
-ARGV.clone.options do |opts|
- opts.on("-p", "--port=port", Integer,
- "Runs Rails on the specified port.", "Default: #{options[:Port]}") { |v| options[:Port] = v }
- opts.on("-b", "--binding=ip", String,
- "Binds Rails to the specified ip.", "Default: #{options[:Host]}") { |v| options[:Host] = v }
- opts.on("-c", "--config=file", String,
- "Use custom rackup configuration file") { |v| options[:config] = v }
- opts.on("-d", "--daemon", "Make server run as a Daemon.") { options[:detach] = true }
- opts.on("-u", "--debugger", "Enable ruby-debugging for the server.") { options[:debugger] = true }
- opts.on("-e", "--environment=name", String,
- "Specifies the environment to run this server under (test/development/production).",
- "Default: #{options[:environment]}") { |v| options[:environment] = v }
-
- opts.separator ""
+module Rails
+ class Server < ::Rack::Server
+ class Options
+ def parse!(args)
+ options = {}
+ args = args.dup
+ opt_parser = OptionParser.new do |opts|
+ opts.on("-p", "--port=port", Integer,
+ "Runs Rails on the specified port.", "Default: #{options[:Port]}") { |v| options[:Port] = v }
+ opts.on("-b", "--binding=ip", String,
+ "Binds Rails to the specified ip.", "Default: #{options[:Host]}") { |v| options[:Host] = v }
+ opts.on("-c", "--config=file", String,
+ "Use custom rackup configuration file") { |v| options[:config] = v }
+ opts.on("-d", "--daemon", "Make server run as a Daemon.") { options[:daemonize] = true }
+ opts.on("-u", "--debugger", "Enable ruby-debugging for the server.") { options[:debugger] = true }
+ opts.on("-e", "--environment=name", String,
+ "Specifies the environment to run this server under (test/development/production).",
+ "Default: #{options[:environment]}") { |v| options[:environment] = v }
- opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
+ opts.separator ""
- opts.parse!
-end
+ opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
+ end
-server = Rack::Handler.get(ARGV.first) rescue nil
-unless server
- begin
- server = Rack::Handler::Mongrel
- rescue LoadError => e
- server = Rack::Handler::WEBrick
- end
-end
+ opt_parser.parse! args
-puts "=> Booting #{ActiveSupport::Inflector.demodulize(server)}"
-puts "=> Rails #{Rails.version} application starting on http://#{options[:Host]}:#{options[:Port]}"
+ options[:server] = args.shift
+ options
+ end
+ end
-if options[:detach]
- Process.daemon
- pid = "#{Rails.root}/tmp/pids/server.pid"
- File.open(pid, 'w'){ |f| f.write(Process.pid) }
- at_exit { File.delete(pid) if File.exist?(pid) }
-end
+ def opt_parser
+ Options.new
+ end
-ENV["RAILS_ENV"] = options[:environment]
-RAILS_ENV.replace(options[:environment]) if defined?(RAILS_ENV)
+ def start
+ puts "=> Booting #{ActiveSupport::Inflector.demodulize(server)}"
+ puts "=> Rails #{Rails.version} application starting on http://#{options[:Host]}:#{options[:Port]}"
+ puts "=> Call with -d to detach" unless options[:daemonize]
+ trap(:INT) { exit }
+ puts "=> Ctrl-C to shutdown server" unless options[:daemonize]
-app = Rack::Builder.new {
- use Rails::Rack::LogTailer unless options[:detach]
- use Rails::Rack::Debugger if options[:debugger]
- run ActionDispatch::Utils.parse_config(options[:config])
-}.to_app
+ ENV["RAILS_ENV"] = options[:environment]
+ RAILS_ENV.replace(options[:environment]) if defined?(RAILS_ENV)
-puts "=> Call with -d to detach"
+ super
+ ensure
+ puts 'Exiting' unless options[:daemonize]
+ end
-trap(:INT) { exit }
+ def middleware
+ middlewares = []
+ middlewares << [Rails::Rack::LogTailer, log_path] unless options[:daemonize]
+ middlewares << [Rails::Rack::Debugger] if options[:debugger]
+ Hash.new(middlewares)
+ end
-puts "=> Ctrl-C to shutdown server"
+ def log_path
+ "log/#{options[:environment]}.log"
+ end
-begin
- server.run(app, options.merge(:AccessLog => []))
-ensure
- puts 'Exiting'
+ def default_options
+ super.merge({
+ :Port => 3000,
+ :environment => (ENV['RAILS_ENV'] || "development").dup,
+ :daemonize => false,
+ :debugger => false,
+ :pid => "tmp/pids/server.pid"
+ })
+ end
+ end
end
diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb
index 102a0836dc..086f67a419 100644
--- a/railties/lib/rails/configuration.rb
+++ b/railties/lib/rails/configuration.rb
@@ -1,27 +1,74 @@
require 'active_support/ordered_options'
module Rails
- class Configuration
- attr_accessor :cache_classes, :load_paths, :load_once_paths, :after_initialize_blocks,
- :frameworks, :framework_root_path, :root, :gems, :plugins,
- :i18n, :gems, :whiny_nils, :consider_all_requests_local,
- :action_controller, :active_record, :action_view, :active_support,
- :action_mailer, :active_resource,
- :reload_plugins, :log_path, :log_level, :logger, :preload_frameworks,
- :database_configuration_file, :cache_store, :time_zone,
- :view_path, :metals, :controller_paths, :routes_configuration_file,
- :eager_load_paths, :dependency_loading, :paths, :serve_static_assets
-
- def initialize
+ # Temporarily separate the plugin configuration class from the main
+ # configuration class while this bit is being cleaned up.
+ class Plugin::Configuration
+
+ def self.default
+ @default ||= new
+ end
+
+ attr_reader :middleware
+
+ def initialize(base = nil)
+ if base
+ @options = base.options.dup
+ @middleware = base.middleware.dup
+ else
+ @options = Hash.new { |h,k| h[k] = ActiveSupport::OrderedOptions.new }
+ @middleware = ActionDispatch::MiddlewareStack.new
+ end
+ end
+
+ def respond_to?(name)
+ super || name.to_s =~ config_key_regexp
+ end
+
+ protected
+
+ attr_reader :options
+
+ private
+
+ def method_missing(name, *args, &blk)
+ if name.to_s =~ config_key_regexp
+ return $2 == '=' ? @options[$1] = args.first : @options[$1]
+ end
+
+ super
+ end
+
+ def config_key_regexp
+ bits = config_keys.map { |n| Regexp.escape(n.to_s) }.join('|')
+ /^(#{bits})(?:=)?$/
+ end
+
+ def config_keys
+ ([ :active_support, :action_view, :action_mailer, :active_resource ] +
+ Plugin.plugin_names).map { |n| n.to_s }.uniq
+ end
+ end
+
+ class Configuration < Plugin::Configuration
+ attr_accessor :after_initialize_blocks, :cache_classes,
+ :consider_all_requests_local, :dependency_loading, :gems,
+ :load_once_paths, :logger, :metals, :plugins,
+ :preload_frameworks, :reload_plugins, :serve_static_assets,
+ :time_zone, :whiny_nils
+
+ attr_writer :cache_store, :controller_paths,
+ :database_configuration_file, :eager_load_paths,
+ :frameworks, :framework_root_path, :i18n, :load_paths,
+ :log_level, :log_path, :paths, :routes_configuration_file,
+ :view_path
+
+ def initialize(base = nil)
+ super
@load_once_paths = []
@after_initialize_blocks = []
@dependency_loading = true
@serve_static_assets = true
-
- for framework in frameworks
- self.send("#{framework}=", ActiveSupport::OrderedOptions.new)
- end
- self.active_support = ActiveSupport::OrderedOptions.new
end
def after_initialize(&blk)
@@ -31,7 +78,7 @@ module Rails
def root
@root ||= begin
call_stack = caller.map { |p| p.split(':').first }
- root_path = call_stack.detect { |p| p !~ %r[railties/lib/rails] }
+ root_path = call_stack.detect { |p| p !~ %r[railties/lib/rails|rack/lib/rack] }
root_path = File.dirname(root_path)
while root_path && File.directory?(root_path) && !File.exist?("#{root_path}/config.ru")
@@ -80,7 +127,10 @@ module Rails
self.preload_frameworks = true
self.cache_classes = true
self.dependency_loading = false
- self.action_controller.allow_concurrency = true
+
+ if respond_to?(:action_controller)
+ action_controller.allow_concurrency = true
+ end
self
end
@@ -99,11 +149,6 @@ module Rails
defined?(::RAILS_FRAMEWORK_ROOT) ? ::RAILS_FRAMEWORK_ROOT : "#{root}/vendor/rails"
end
- def middleware
- require 'action_dispatch'
- @middleware ||= ActionDispatch::MiddlewareStack.new
- end
-
# Loads and returns the contents of the #database_configuration_file. The
# contents of the file are processed via ERB before being sent through
# YAML::load.
@@ -116,6 +161,10 @@ module Rails
@routes_configuration_file ||= File.join(root, 'config', 'routes.rb')
end
+ def builtin_routes_configuration_file
+ @builtin_routes_configuration_file ||= File.join(RAILTIES_PATH, 'builtin', 'routes.rb')
+ end
+
def controller_paths
@controller_paths ||= begin
paths = [File.join(root, 'app', 'controllers')]
diff --git a/railties/lib/rails/console_app.rb b/railties/lib/rails/console_app.rb
index 1ad62e5058..2c4a7a51e8 100644
--- a/railties/lib/rails/console_app.rb
+++ b/railties/lib/rails/console_app.rb
@@ -27,6 +27,6 @@ end
def reload!
puts "Reloading..."
ActionDispatch::Callbacks.new(lambda {}, true)
- ActionController::Routing::Routes.reload
+ Rails.application.reload_routes!
true
end
diff --git a/railties/lib/rails/core.rb b/railties/lib/rails/core.rb
index a5e51ad04a..da16c5816c 100644
--- a/railties/lib/rails/core.rb
+++ b/railties/lib/rails/core.rb
@@ -1,3 +1,37 @@
+require "pathname"
+
+require 'active_support'
+require 'active_support/core_ext/kernel/reporting'
+require 'active_support/core_ext/logger'
+require 'action_dispatch'
+
+require 'rails/initializable'
+require 'rails/application'
+require 'rails/plugin'
+require 'rails/railties_path'
+require 'rails/version'
+require 'rails/rack'
+require 'rails/paths'
+require 'rails/core'
+require 'rails/configuration'
+require 'rails/deprecation'
+require 'rails/initializer'
+require 'rails/ruby_version_check'
+
+# For Ruby 1.8, this initialization sets $KCODE to 'u' to enable the
+# multibyte safe operations. Plugin authors supporting other encodings
+# should override this behaviour and set the relevant +default_charset+
+# on ActionController::Base.
+#
+# For Ruby 1.9, UTF-8 is the default internal and external encoding.
+if RUBY_VERSION < '1.9'
+ $KCODE='u'
+else
+ Encoding.default_external = Encoding::UTF_8
+end
+
+RAILS_ENV = (ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development").dup unless defined?(RAILS_ENV)
+
module Rails
# Needs to be duplicated from Active Support since its needed before Active
# Support is available. Here both Options and Hash are namespaced to prevent
diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb
index 85c2fd52a4..0e66c9f58f 100644
--- a/railties/lib/rails/generators.rb
+++ b/railties/lib/rails/generators.rb
@@ -1,5 +1,6 @@
-activesupport_path = "#{File.dirname(__FILE__)}/../../../activesupport/lib"
-$LOAD_PATH.unshift(activesupport_path) if File.directory?(activesupport_path)
+activesupport_path = File.expand_path('../../../../activesupport/lib', __FILE__)
+$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
+
require 'active_support'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/object/metaclass'
@@ -9,7 +10,7 @@ require 'active_support/core_ext/module/attribute_accessors'
require 'active_support/core_ext/string/inflections'
# TODO: Do not always push on vendored thor
-$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/vendor/thor-0.12.0/lib")
+$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/vendor/thor-0.12.1/lib")
require 'rails/generators/base'
require 'rails/generators/named_base'
diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb
index 8677bf283b..f95b15acce 100644
--- a/railties/lib/rails/generators/actions.rb
+++ b/railties/lib/rails/generators/actions.rb
@@ -104,7 +104,7 @@ module Rails
# file in config/environments.
#
def environment(data=nil, options={}, &block)
- sentinel = "Rails::Initializer.run do |config|"
+ sentinel = /class [a-z_:]+ < Rails::Application/i
data = block.call if !data && block_given?
in_root do
@@ -269,11 +269,11 @@ module Rails
#
# === Example
#
- # route "map.root :controller => :welcome"
+ # route "root :to => 'welcome'"
#
def route(routing_code)
log :route, routing_code
- sentinel = "ActionController::Routing::Routes.draw do |map|"
+ sentinel = "routes.draw do |map|"
in_root do
inject_into_file 'config/routes.rb', "\n #{routing_code}\n", { :after => sentinel, :verbose => false }
diff --git a/railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb
index 6460e5b599..51c4ad0e2e 100644
--- a/railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb
+++ b/railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb
@@ -7,7 +7,7 @@
</head>
<body>
-<p class="notice"><%%= flash[:notice] %></p>
+<p class="notice"><%%= notice %></p>
<%%= yield %>
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index 2bcea4bc8f..30272ed9b2 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -48,9 +48,9 @@ module Rails::Generators
end
def create_root_files
- copy_file "Rakefile"
copy_file "README"
- copy_file "config.ru"
+ template "Rakefile"
+ template "config.ru"
template "Gemfile"
end
@@ -62,9 +62,9 @@ module Rails::Generators
empty_directory "config"
inside "config" do
- copy_file "routes.rb"
- template "application.rb"
- template "environment.rb"
+ template "routes.rb"
+ template "application.rb"
+ template "environment.rb"
directory "environments"
directory "initializers"
@@ -123,10 +123,10 @@ module Rails::Generators
end
def create_script_files
- directory "script" do |file|
- prepend_file file, "#{shebang}\n", :verbose => false
- chmod file, 0755, :verbose => false
+ directory "script" do |content|
+ "#{shebang}\n" + content
end
+ chmod "script", 0755, :verbose => false
end
def create_test_files
@@ -181,6 +181,10 @@ module Rails::Generators
@app_name ||= File.basename(destination_root)
end
+ def app_const
+ @app_const ||= "#{app_name.classify}::Application"
+ end
+
def app_secret
ActiveSupport::SecureRandom.hex(64)
end
diff --git a/railties/lib/rails/generators/rails/app/templates/Rakefile b/railties/lib/rails/generators/rails/app/templates/Rakefile
index 6b6d07e8cc..c19ad0e945 100755
--- a/railties/lib/rails/generators/rails/app/templates/Rakefile
+++ b/railties/lib/rails/generators/rails/app/templates/Rakefile
@@ -7,4 +7,4 @@ require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
-require 'rails/tasks'
+<%= app_const %>.load_tasks
diff --git a/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb
index 6635a3f487..9889b52893 100644
--- a/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb
+++ b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb
@@ -2,9 +2,7 @@
# Likewise, all the methods added will be available for all controllers.
class ApplicationController < ActionController::Base
- helper :all # include all helpers, all the time
- protect_from_forgery # See ActionController::RequestForgeryProtection for details
-
- # Scrub sensitive parameters from your log
- # filter_parameter_logging :password
+ helper :all
+ protect_from_forgery
+ filter_parameter_logging :password
end
diff --git a/railties/lib/rails/generators/rails/app/templates/config.ru b/railties/lib/rails/generators/rails/app/templates/config.ru
index 509a0da5b7..acb8435446 100644
--- a/railties/lib/rails/generators/rails/app/templates/config.ru
+++ b/railties/lib/rails/generators/rails/app/templates/config.ru
@@ -2,4 +2,4 @@
require ::File.expand_path('../config/environment', __FILE__)
# Dispatch the request
-run Rails.application
+run <%= app_const %>.instance
diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb
index 8008c6ba07..15dc553e53 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/application.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb
@@ -1,41 +1,43 @@
require File.expand_path('../boot', __FILE__)
-Rails::Initializer.run do |config|
- # Settings in config/environments/* take precedence over those specified here.
- # Application configuration should go into files in config/initializers
- # -- all .rb files in that directory are automatically loaded.
+module <%= app_name.classify %>
+ class Application < Rails::Application
+ # Settings in config/environments/* take precedence over those specified here.
+ # Application configuration should go into files in config/initializers
+ # -- all .rb files in that directory are automatically loaded.
- # Add additional load paths for your own custom dirs
- # config.load_paths += %W( #{root}/extras )
+ # Add additional load paths for your own custom dirs
+ # config.load_paths += %W( #{root}/extras )
- # Only load the plugins named here, in the order given (default is alphabetical).
- # :all can be used as a placeholder for all plugins not explicitly named
- # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
+ # Only load the plugins named here, in the order given (default is alphabetical).
+ # :all can be used as a placeholder for all plugins not explicitly named
+ # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
- # Skip frameworks you're not going to use. To use Rails without a database,
- # you must remove the Active Record framework.
+ # Skip frameworks you're not going to use. To use Rails without a database,
+ # you must remove the Active Record framework.
<% if options[:skip_activerecord] -%>
- config.frameworks -= [ :active_record ]
+ config.frameworks -= [ :active_record ]
<% else -%>
- # config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
+ # config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
- # Activate observers that should always be running
- # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
+ # Activate observers that should always be running
+ # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
<% end -%>
- # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
- # Run "rake -D time" for a list of tasks for finding time zone names.
- config.time_zone = 'UTC'
-
- # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
- # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')]
- # config.i18n.default_locale = :de
-
- # Configure generators values. Many other options are available, be sure to
- # check the documentation.
- # config.generators do |g|
- # g.orm :active_record
- # g.template_engine :erb
- # g.test_framework :test_unit, :fixture => true
- # end
+ # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
+ # Run "rake -D time" for a list of tasks for finding time zone names.
+ config.time_zone = 'UTC'
+
+ # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
+ # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')]
+ # config.i18n.default_locale = :de
+
+ # Configure generators values. Many other options are available, be sure to
+ # check the documentation.
+ # config.generators do |g|
+ # g.orm :active_record
+ # g.template_engine :erb
+ # g.test_framework :test_unit, :fixture => true
+ # end
+ end
end
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environment.rb b/railties/lib/rails/generators/rails/app/templates/config/environment.rb
index 0bb191f205..1684986a59 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environment.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/environment.rb
@@ -2,4 +2,4 @@
require File.expand_path('../application', __FILE__)
# Initialize the rails application
-Rails.initialize!
+<%= app_const %>.initialize!
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb
deleted file mode 100644
index 85c9a6080e..0000000000
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# Settings specified here will take precedence over those in config/environment.rb
-
-# In the development environment your application's code is reloaded on
-# every request. This slows down response time but is perfect for development
-# since you don't have to restart the webserver when you make code changes.
-config.cache_classes = false
-
-# Log error messages when you accidentally call methods on nil.
-config.whiny_nils = true
-
-# Show full error reports and disable caching
-config.action_controller.consider_all_requests_local = true
-config.action_view.debug_rjs = true
-config.action_controller.perform_caching = false
-
-# Don't care if the mailer can't send
-config.action_mailer.raise_delivery_errors = false \ No newline at end of file
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
new file mode 100644
index 0000000000..b10103b436
--- /dev/null
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
@@ -0,0 +1,19 @@
+<%= app_const %>.configure do
+ # Settings specified here will take precedence over those in config/environment.rb
+
+ # In the development environment your application's code is reloaded on
+ # every request. This slows down response time but is perfect for development
+ # since you don't have to restart the webserver when you make code changes.
+ config.cache_classes = false
+
+ # Log error messages when you accidentally call methods on nil.
+ config.whiny_nils = true
+
+ # Show full error reports and disable caching
+ config.action_controller.consider_all_requests_local = true
+ config.action_view.debug_rjs = true
+ config.action_controller.perform_caching = false
+
+ # Don't care if the mailer can't send
+ config.action_mailer.raise_delivery_errors = false
+end \ No newline at end of file
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb
deleted file mode 100644
index 377b9207c7..0000000000
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# Settings specified here will take precedence over those in config/environment.rb
-
-# The production environment is meant for finished, "live" apps.
-# Code is not reloaded between requests
-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
-
-# See everything in the log (default is :info)
-# config.log_level = :debug
-
-# Use a different logger for distributed setups
-# config.logger = SyslogLogger.new
-
-# Use a different cache store in production
-# config.cache_store = :mem_cache_store
-
-# Disable Rails's static asset server
-# In production, Apache or nginx will already do this
-config.serve_static_assets = false
-
-# Enable serving of images, stylesheets, and javascripts from an asset server
-# config.action_controller.asset_host = "http://assets.example.com"
-
-# Disable delivery errors, bad email addresses will be ignored
-# config.action_mailer.raise_delivery_errors = false
-
-# Enable threaded mode
-# config.threadsafe!
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
new file mode 100644
index 0000000000..543a40108c
--- /dev/null
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
@@ -0,0 +1,33 @@
+<%= app_const %>.configure do
+ # Settings specified here will take precedence over those in config/environment.rb
+
+ # The production environment is meant for finished, "live" apps.
+ # Code is not reloaded between requests
+ 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
+
+ # See everything in the log (default is :info)
+ # config.log_level = :debug
+
+ # Use a different logger for distributed setups
+ # config.logger = SyslogLogger.new
+
+ # Use a different cache store in production
+ # config.cache_store = :mem_cache_store
+
+ # Disable Rails's static asset server
+ # In production, Apache or nginx will already do this
+ config.serve_static_assets = false
+
+ # Enable serving of images, stylesheets, and javascripts from an asset server
+ # config.action_controller.asset_host = "http://assets.example.com"
+
+ # Disable delivery errors, bad email addresses will be ignored
+ # config.action_mailer.raise_delivery_errors = false
+
+ # Enable threaded mode
+ # config.threadsafe!
+end \ No newline at end of file
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb
deleted file mode 100644
index 496eb9572b..0000000000
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-# Settings specified here will take precedence over those in config/environment.rb
-
-# The test environment is used exclusively to run your application's
-# test suite. You never need to work with it otherwise. Remember that
-# your test database is "scratch space" for the test suite and is wiped
-# and recreated between test runs. Don't rely on the data there!
-config.cache_classes = true
-
-# Log error messages when you accidentally call methods on nil.
-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
-
-# Disable request forgery protection in test environment
-config.action_controller.allow_forgery_protection = false
-
-# Tell Action Mailer not to deliver emails to the real world.
-# The :test delivery method accumulates sent emails in the
-# ActionMailer::Base.deliveries array.
-config.action_mailer.delivery_method = :test
-
-# Use SQL instead of Active Record's schema dumper when creating the test database.
-# This is necessary if your schema can't be completely dumped by the schema dumper,
-# like if you have constraints or database-specific column types
-# config.active_record.schema_format = :sql \ No newline at end of file
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
new file mode 100644
index 0000000000..428fa35633
--- /dev/null
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
@@ -0,0 +1,29 @@
+<%= app_const %>.configure do
+ # Settings specified here will take precedence over those in config/environment.rb
+
+ # The test environment is used exclusively to run your application's
+ # test suite. You never need to work with it otherwise. Remember that
+ # your test database is "scratch space" for the test suite and is wiped
+ # and recreated between test runs. Don't rely on the data there!
+ config.cache_classes = true
+
+ # Log error messages when you accidentally call methods on nil.
+ 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
+
+ # Disable request forgery protection in test environment
+ config.action_controller.allow_forgery_protection = false
+
+ # Tell Action Mailer not to deliver emails to the real world.
+ # The :test delivery method accumulates sent emails in the
+ # ActionMailer::Base.deliveries array.
+ config.action_mailer.delivery_method = :test
+
+ # Use SQL instead of Active Record's schema dumper when creating the test database.
+ # This is necessary if your schema can't be completely dumped by the schema dumper,
+ # like if you have constraints or database-specific column types
+ # config.active_record.schema_format = :sql
+end \ No newline at end of file
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/cookie_verification_secret.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/cookie_verification_secret.rb.tt
new file mode 100644
index 0000000000..9f05cd5a31
--- /dev/null
+++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/cookie_verification_secret.rb.tt
@@ -0,0 +1,7 @@
+# Be sure to restart your server when you modify this file.
+
+# Your secret key for verifying the integrity of signed cookies.
+# If you change this key, all old signed cookies will become invalid!
+# Make sure the secret is at least 30 characters and all random,
+# no regular words or you'll be exposed to dictionary attacks.
+ActionController::Base.cookie_verifier_secret = '<%= app_secret %>';
diff --git a/railties/lib/rails/generators/rails/app/templates/config/routes.rb b/railties/lib/rails/generators/rails/app/templates/config/routes.rb
index ea14ce1bfc..d6c0365c04 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/routes.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/routes.rb
@@ -1,43 +1,58 @@
-ActionController::Routing::Routes.draw do |map|
- # The priority is based upon order of creation: first created -> highest priority.
+<%= app_const %>.routes.draw do |map|
+ # The priority is based upon order of creation:
+ # first created -> highest priority.
# Sample of regular route:
- # map.connect 'products/:id', :controller => 'catalog', :action => 'view'
+ # match 'products/:id' => 'catalog#view'
# Keep in mind you can assign values other than :controller and :action
# Sample of named route:
- # map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase'
+ # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
# This route can be invoked with purchase_url(:id => product.id)
# Sample resource route (maps HTTP verbs to controller actions automatically):
- # map.resources :products
+ # resources :products
# Sample resource route with options:
- # map.resources :products, :member => { :short => :get, :toggle => :post }, :collection => { :sold => :get }
+ # resources :products do
+ # member do
+ # get :short
+ # post :toggle
+ # end
+ #
+ # collection do
+ # get :sold
+ # end
+ # end
# Sample resource route with sub-resources:
- # map.resources :products, :has_many => [ :comments, :sales ], :has_one => :seller
-
+ # resources :products do
+ # resources :comments, :sales
+ # resource :seller
+ # end
+
# Sample resource route with more complex sub-resources
- # map.resources :products do |products|
- # products.resources :comments
- # products.resources :sales, :collection => { :recent => :get }
+ # resources :products do
+ # resources :comments
+ # resources :sales do
+ # get :recent, :on => :collection
+ # end
# end
# Sample resource route within a namespace:
- # map.namespace :admin do |admin|
- # # Directs /admin/products/* to Admin::ProductsController (app/controllers/admin/products_controller.rb)
- # admin.resources :products
+ # namespace :admin do
+ # # Directs /admin/products/* to Admin::ProductsController
+ # # (app/controllers/admin/products_controller.rb)
+ # resources :products
# end
- # You can have the root of your site routed with map.root -- just remember to delete public/index.html.
- # map.root :controller => "welcome"
+ # You can have the root of your site routed with "root"
+ # just remember to delete public/index.html.
+ # root :to => "welcome#index"
# See how all your routes lay out with "rake routes"
- # Install the default routes as the lowest priority.
- # Note: These default routes make all actions in every controller accessible via GET requests. You should
- # consider removing or commenting them out if you're using named routes and resources.
- map.connect ':controller/:action/:id'
- map.connect ':controller/:action/:id.:format'
+ # This is a legacy wild controller route that's not recommended for RESTful applications.
+ # Note: This route will make all actions in every controller accessible via GET requests.
+ # match ':controller(/:action(/:id(.:format)))'
end
diff --git a/railties/lib/rails/generators/rails/app/templates/script/console b/railties/lib/rails/generators/rails/app/templates/script/console.tt
index 20aa799d2f..9ddd4cfe62 100755
--- a/railties/lib/rails/generators/rails/app/templates/script/console
+++ b/railties/lib/rails/generators/rails/app/templates/script/console.tt
@@ -1,2 +1,3 @@
require File.expand_path('../../config/application', __FILE__)
require 'rails/commands/console'
+Rails::Console.start(<%= app_const %>.instance)
diff --git a/railties/lib/rails/generators/rails/app/templates/script/dbconsole b/railties/lib/rails/generators/rails/app/templates/script/dbconsole.tt
index e6a1c59394..96e0bc191b 100755
--- a/railties/lib/rails/generators/rails/app/templates/script/dbconsole
+++ b/railties/lib/rails/generators/rails/app/templates/script/dbconsole.tt
@@ -1,2 +1,3 @@
require File.expand_path('../../config/application', __FILE__)
require 'rails/commands/dbconsole'
+Rails::DBConsole.start(<%= app_const %>.instance)
diff --git a/railties/lib/rails/generators/rails/app/templates/script/server b/railties/lib/rails/generators/rails/app/templates/script/server
deleted file mode 100755
index a7aaee2953..0000000000
--- a/railties/lib/rails/generators/rails/app/templates/script/server
+++ /dev/null
@@ -1,2 +0,0 @@
-require File.expand_path('../../config/application', __FILE__)
-require 'rails/commands/server'
diff --git a/railties/lib/rails/generators/rails/app/templates/script/server.tt b/railties/lib/rails/generators/rails/app/templates/script/server.tt
new file mode 100755
index 0000000000..4fd0cc7832
--- /dev/null
+++ b/railties/lib/rails/generators/rails/app/templates/script/server.tt
@@ -0,0 +1,5 @@
+require File.expand_path('../../config/boot', __FILE__)
+require 'rails/commands/server'
+
+Dir.chdir(File.expand_path('../..', __FILE__))
+Rails::Server.start
diff --git a/railties/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt b/railties/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt
index 675f00043f..d8757460e4 100644
--- a/railties/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt
+++ b/railties/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt
@@ -1,5 +1,5 @@
class <%= class_name %>Generator < Rails::Generators::NamedBase
def self.source_root
- @source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
+ @source_root ||= File.expand_path('../templates', __FILE__)
end
end
diff --git a/railties/lib/rails/generators/rails/plugin/templates/Rakefile b/railties/lib/rails/generators/rails/plugin/templates/Rakefile
index 85e8ff1834..23c2245a41 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/Rakefile
+++ b/railties/lib/rails/generators/rails/plugin/templates/Rakefile
@@ -10,7 +10,6 @@ Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
- t.verbose = true
end
desc 'Generate documentation for the <%= file_name %> plugin.'
diff --git a/railties/lib/rails/generators/rails/resource/resource_generator.rb b/railties/lib/rails/generators/rails/resource/resource_generator.rb
index e49f9aea1b..a89ce7faed 100644
--- a/railties/lib/rails/generators/rails/resource/resource_generator.rb
+++ b/railties/lib/rails/generators/rails/resource/resource_generator.rb
@@ -16,7 +16,7 @@ module Rails
class_option :singleton, :type => :boolean, :desc => "Supply to create a singleton controller"
def add_resource_route
- route "map.resource#{:s unless options[:singleton]} :#{pluralize?(file_name)}"
+ route "resource#{:s unless options[:singleton]} :#{pluralize?(file_name)}"
end
protected
diff --git a/railties/lib/rails/generators/rails/scaffold/USAGE b/railties/lib/rails/generators/rails/scaffold/USAGE
index 71edd2f469..530ccdaf0a 100644
--- a/railties/lib/rails/generators/rails/scaffold/USAGE
+++ b/railties/lib/rails/generators/rails/scaffold/USAGE
@@ -17,7 +17,7 @@ Description:
For example, 'scaffold post title:string body:text published:boolean'
gives you a model with those three attributes, a controller that handles
the create/show/update/destroy, forms to create and edit your posts, and
- an index that lists them all, as well as a map.resources :posts
+ an index that lists them all, as well as a resources :posts
declaration in config/routes.rb.
If you want to remove all the generated files, run
diff --git a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb
index 3cc8bbf8e7..874e96a2b4 100644
--- a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb
+++ b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb
@@ -46,8 +46,7 @@ class <%= controller_class_name %>Controller < ApplicationController
respond_to do |format|
if @<%= orm_instance.save %>
- flash[:notice] = '<%= class_name %> was successfully created.'
- format.html { redirect_to(@<%= file_name %>) }
+ format.html { redirect_to(@<%= file_name %>, :notice => '<%= class_name %> was successfully created.') }
format.xml { render :xml => @<%= file_name %>, :status => :created, :location => @<%= file_name %> }
else
format.html { render :action => "new" }
@@ -63,8 +62,7 @@ class <%= controller_class_name %>Controller < ApplicationController
respond_to do |format|
if @<%= orm_instance.update_attributes("params[:#{file_name}]") %>
- flash[:notice] = '<%= class_name %> was successfully updated.'
- format.html { redirect_to(@<%= file_name %>) }
+ format.html { redirect_to(@<%= file_name %>, :notice => '<%= class_name %> was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
diff --git a/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml
index c21035113e..a30132bc99 100644
--- a/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml
+++ b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml
@@ -11,9 +11,13 @@ two:
<%= attribute.name %>: <%= attribute.default %>
<% end -%>
<% else -%>
-# one:
-# column: value
+# This model initially had no columns defined. If you add columns to the
+# model remove the '{}' from the fixture names and add the columns immediately
+# below each fixture, per the syntax in the comments below
#
-# two:
-# column: value
-<% end -%>
+one: {}
+# column: value
+#
+two: {}
+# column: value
+<% end -%> \ No newline at end of file
diff --git a/railties/lib/rails/initializable.rb b/railties/lib/rails/initializable.rb
index 3866b856b2..8fcb254590 100644
--- a/railties/lib/rails/initializable.rb
+++ b/railties/lib/rails/initializable.rb
@@ -5,7 +5,7 @@ module Rails
end
class Initializer
- attr_reader :name, :before, :after, :global, :block
+ attr_reader :name, :block
def initialize(name, context, options, &block)
@name, @context, @options, @block = name, context, options, block
@@ -62,7 +62,7 @@ module Rails
end
def run_initializers(*args)
- return if @ran
+ return if instance_variable_defined?(:@ran)
initializers.each do |initializer|
initializer.run(*args)
end
@@ -93,6 +93,7 @@ module Rails
end
def initializer(name, opts = {}, &blk)
+ raise ArgumentError, "A block must be passed when defining an initializer" unless blk
@initializers ||= []
@initializers << Initializer.new(name, nil, opts, &blk)
end
@@ -106,26 +107,4 @@ module Rails
end
end
end
-
- include Initializable
-
- # Check for valid Ruby version (1.8.2 or 1.8.4 or higher). This is done in an
- # external file, so we can use it from the `rails` program as well without duplication.
- initializer :check_ruby_version, :global => true do
- require 'rails/ruby_version_check'
- end
-
- # For Ruby 1.8, this initialization sets $KCODE to 'u' to enable the
- # multibyte safe operations. Plugin authors supporting other encodings
- # should override this behaviour and set the relevant +default_charset+
- # on ActionController::Base.
- #
- # For Ruby 1.9, UTF-8 is the default internal and external encoding.
- initializer :initialize_encoding, :global => true do
- if RUBY_VERSION < '1.9'
- $KCODE='u'
- else
- Encoding.default_external = Encoding::UTF_8
- end
- end
end \ No newline at end of file
diff --git a/railties/lib/rails/initializer.rb b/railties/lib/rails/initializer.rb
index 44d04688c8..95478428ec 100644
--- a/railties/lib/rails/initializer.rb
+++ b/railties/lib/rails/initializer.rb
@@ -1,7 +1,5 @@
require "rails" # In case people require this file directly
-RAILS_ENV = (ENV['RAILS_ENV'] || 'development').dup unless defined?(RAILS_ENV)
-
module Rails
class Initializer
class Error < StandardError ; end
@@ -14,4 +12,4 @@ module Rails
end
end
end
-end \ No newline at end of file
+end
diff --git a/railties/lib/rails/plugin.rb b/railties/lib/rails/plugin.rb
index 86bf032641..0699affea7 100644
--- a/railties/lib/rails/plugin.rb
+++ b/railties/lib/rails/plugin.rb
@@ -2,6 +2,29 @@ module Rails
class Plugin
include Initializable
+ def self.plugin_name(plugin_name = nil)
+ @plugin_name ||= name.demodulize.underscore
+ @plugin_name = plugin_name if plugin_name
+ @plugin_name
+ end
+
+ def self.inherited(klass)
+ @plugins ||= []
+ @plugins << klass unless klass == Vendored
+ end
+
+ def self.plugins
+ @plugins
+ end
+
+ def self.plugin_names
+ plugins.map { |p| p.plugin_name }
+ end
+
+ def self.config
+ Configuration.default
+ end
+
class Vendored < Plugin
def self.all(list, paths)
plugins = []
@@ -55,8 +78,8 @@ module Rails
initializer :add_routing_file, :after => :initialize_routing do |app|
routing_file = "#{path}/config/routes.rb"
if File.exist?(routing_file)
- app.routes.add_configuration_file(routing_file)
- app.routes.reload!
+ app.route_configuration_files << routing_file
+ app.reload_routes!
end
end
end
diff --git a/railties/lib/rails/rack/log_tailer.rb b/railties/lib/rails/rack/log_tailer.rb
index a237cee6bc..077311be3c 100644
--- a/railties/lib/rails/rack/log_tailer.rb
+++ b/railties/lib/rails/rack/log_tailer.rb
@@ -1,12 +1,10 @@
module Rails
module Rack
class LogTailer
- EnvironmentLog = "#{File.expand_path(Rails.root)}/log/#{Rails.env}.log"
-
def initialize(app, log = nil)
@app = app
- path = Pathname.new(log || EnvironmentLog).cleanpath
+ path = Pathname.new(log || "#{File.expand_path(Rails.root)}/log/#{Rails.env}.log").cleanpath
@cursor = ::File.size(path)
@last_checked = Time.now.to_f
diff --git a/railties/lib/rails/tasks.rb b/railties/lib/rails/tasks.rb
index 82113a297c..dc886f4a4d 100644
--- a/railties/lib/rails/tasks.rb
+++ b/railties/lib/rails/tasks.rb
@@ -16,8 +16,3 @@ $VERBOSE = nil
).each do |task|
load "rails/tasks/#{task}.rake"
end
-
-# Load any custom rakefile extensions
-# TODO: Don't hardcode these paths.
-Dir["#{Rails.root}/vendor/plugins/*/**/tasks/**/*.rake"].sort.each { |ext| load ext }
-Dir["#{Rails.root}/lib/tasks/**/*.rake"].sort.each { |ext| load ext }
diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake
index 1611d1d94d..f7b53885c8 100644
--- a/railties/lib/rails/tasks/framework.rake
+++ b/railties/lib/rails/tasks/framework.rake
@@ -92,7 +92,7 @@ namespace :rails do
namespace :update do
def invoke_from_app_generator(method)
- require 'generators'
+ require 'rails/generators'
require 'rails/generators/rails/app/app_generator'
generator = Rails::Generators::AppGenerator.new ["rails"], { :with_dispatchers => true },
@@ -100,6 +100,12 @@ namespace :rails do
generator.invoke(method)
end
+ desc "Update config/boot.rb from your current rails install"
+ task :configs do
+ invoke_from_app_generator :create_boot_file
+ invoke_from_app_generator :create_config_files
+ end
+
desc "Update Prototype javascripts from your current rails install"
task :javascripts do
invoke_from_app_generator :create_prototype_files
diff --git a/railties/lib/rails/tasks/misc.rake b/railties/lib/rails/tasks/misc.rake
index 7f244ebaed..9433b3556a 100644
--- a/railties/lib/rails/tasks/misc.rake
+++ b/railties/lib/rails/tasks/misc.rake
@@ -1,8 +1,4 @@
task :default => :test
-task :environment do
- $rails_rake_task = true
- require(File.join(Rails.root, 'config', 'environment'))
-end
task :rails_env do
unless defined? RAILS_ENV
diff --git a/railties/lib/rails/tasks/testing.rake b/railties/lib/rails/tasks/testing.rake
index fd5e52a05b..57857fb911 100644
--- a/railties/lib/rails/tasks/testing.rake
+++ b/railties/lib/rails/tasks/testing.rake
@@ -48,7 +48,7 @@ task :test do
task
end
end.compact
- abort "Errors running #{errors.to_sentence(:locale => :en)}!" if errors.any?
+ abort "Errors running #{errors * ', '}!" if errors.any?
end
namespace :test do
@@ -59,7 +59,6 @@ namespace :test do
recent_tests('app/controllers/**/*.rb', 'test/functional', since)
t.libs << 'test'
- t.verbose = true
t.test_files = touched.uniq
end
Rake::Task['test:recent'].comment = "Test recent changes"
@@ -84,35 +83,30 @@ namespace :test do
end
t.libs << 'test'
- t.verbose = true
end
Rake::Task['test:uncommitted'].comment = "Test changes since last checkin (only Subversion and Git)"
Rake::TestTask.new(:units => "db:test:prepare") do |t|
t.libs << "test"
t.pattern = 'test/unit/**/*_test.rb'
- t.verbose = true
end
Rake::Task['test:units'].comment = "Run the unit tests in test/unit"
Rake::TestTask.new(:functionals => "db:test:prepare") do |t|
t.libs << "test"
t.pattern = 'test/functional/**/*_test.rb'
- t.verbose = true
end
Rake::Task['test:functionals'].comment = "Run the functional tests in test/functional"
Rake::TestTask.new(:integration => "db:test:prepare") do |t|
t.libs << "test"
t.pattern = 'test/integration/**/*_test.rb'
- t.verbose = true
end
Rake::Task['test:integration'].comment = "Run the integration tests in test/integration"
Rake::TestTask.new(:benchmark => 'db:test:prepare') do |t|
t.libs << 'test'
t.pattern = 'test/performance/**/*_test.rb'
- t.verbose = true
t.options = '-- --benchmark'
end
Rake::Task['test:benchmark'].comment = 'Benchmark the performance tests'
@@ -120,7 +114,6 @@ namespace :test do
Rake::TestTask.new(:profile => 'db:test:prepare') do |t|
t.libs << 'test'
t.pattern = 'test/performance/**/*_test.rb'
- t.verbose = true
end
Rake::Task['test:profile'].comment = 'Profile the performance tests'
@@ -132,8 +125,6 @@ namespace :test do
else
t.pattern = 'vendor/plugins/*/**/test/**/*_test.rb'
end
-
- t.verbose = true
end
Rake::Task['test:plugins'].comment = "Run the plugin tests in vendor/plugins/*/**/test (or specify with PLUGIN=name)"
end
diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb
index 9f6c42945f..2601765065 100644
--- a/railties/lib/rails/test_help.rb
+++ b/railties/lib/rails/test_help.rb
@@ -2,14 +2,18 @@
# so fixtures are loaded to the right database
silence_warnings { RAILS_ENV = "test" }
-require 'rubygems'
-gem "rack", "~> 1.0.0"
-gem "rack-test", "~> 0.5.0"
+require 'rack'
+require 'rack/test'
require 'test/unit'
require 'active_support/core_ext/kernel/requires'
+
+# AP is always present
+require 'action_controller/test_case'
require 'action_view/test_case'
+
require 'action_mailer/test_case' if defined?(ActionMailer)
+require 'active_model/test_case' if defined?(ActiveModel)
if defined?(ActiveRecord)
require 'active_record/test_case'
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/version.rb b/railties/lib/rails/vendor/thor-0.12.0/lib/thor/version.rb
deleted file mode 100644
index 885230fac4..0000000000
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/version.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-class Thor
- VERSION = "0.11.8".freeze
-end
diff --git a/railties/lib/rails/vendor/thor-0.12.0/CHANGELOG.rdoc b/railties/lib/rails/vendor/thor-0.12.1/CHANGELOG.rdoc
index adedfeca9d..606a0cdb52 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/CHANGELOG.rdoc
+++ b/railties/lib/rails/vendor/thor-0.12.1/CHANGELOG.rdoc
@@ -17,7 +17,7 @@
* thor help now show information about any class/task. All those calls are
possible:
-
+
thor help describe
thor help describe:amazing
@@ -47,7 +47,7 @@
are in the 'standard' group. Running 'thor -T' will only show the standard
tasks - adding --all will show all tasks. You can also filter on a specific
group using the --group option: thor -T --group advanced
-
+
== 0.9.6, released 2008-09-13
* Generic improvements
diff --git a/railties/lib/rails/vendor/thor-0.12.0/LICENSE b/railties/lib/rails/vendor/thor-0.12.1/LICENSE
index 98722da459..98722da459 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/LICENSE
+++ b/railties/lib/rails/vendor/thor-0.12.1/LICENSE
diff --git a/railties/lib/rails/vendor/thor-0.12.0/README.rdoc b/railties/lib/rails/vendor/thor-0.12.1/README.rdoc
index f1106f02b6..ee545f3d97 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/README.rdoc
+++ b/railties/lib/rails/vendor/thor-0.12.1/README.rdoc
@@ -7,7 +7,7 @@ Example:
class App < Thor # [1]
map "-L" => :list # [2]
-
+
desc "install APP_NAME", "install one of the available apps" # [3]
method_options :force => :boolean, :alias => :string # [4]
def install(name)
@@ -17,7 +17,7 @@ Example:
end
# other code
end
-
+
desc "list [SEARCH]", "list all of the available apps, limited by SEARCH"
def list(search="")
# list everything
@@ -126,13 +126,13 @@ invoked only once. For example:
invoke :two
invoke :three
end
-
+
desc "two", "Prints 2, 3"
def two
puts 2
invoke :three
end
-
+
desc "three", "Prints 3"
def three
puts 3
@@ -155,15 +155,15 @@ Thor::Group as this:
class Counter < Thor::Group
desc "Prints 1, 2, 3"
-
+
def one
puts 1
end
-
+
def two
puts 2
end
-
+
def three
puts 3
end
@@ -184,15 +184,15 @@ Besides, Thor::Group can parse arguments and options as Thor tasks:
# number will be available as attr_accessor
argument :number, :type => :numeric, :desc => "The number to start counting"
desc "Prints the 'number' given upto 'number+2'"
-
+
def one
puts number + 0
end
-
+
def two
puts number + 1
end
-
+
def three
puts number + 2
end
diff --git a/railties/lib/rails/vendor/thor-0.12.0/Thorfile b/railties/lib/rails/vendor/thor-0.12.1/Thorfile
index f71a1e57e2..ff1cb4498a 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/Thorfile
+++ b/railties/lib/rails/vendor/thor-0.12.1/Thorfile
@@ -56,7 +56,7 @@ class Default < Thor
s.test_files.exclude 'spec/sandbox/**/*'
end
- Jeweler::RubyforgeTasks.new
+ Jeweler::GemcutterTasks.new
rescue LoadError
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
end
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor.rb
index 68944f140d..68944f140d 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor.rb
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/actions.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/actions.rb
index d561ccb2aa..4bfb7c2870 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/actions.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/actions.rb
@@ -114,7 +114,7 @@ class Thor
@source_paths ||= self.class.source_paths_for_search
end
- # Receives a file or directory and search for it in the source paths.
+ # Receives a file or directory and search for it in the source paths.
#
def find_in_source_paths(file)
relative_root = relative_to_original_destination_root(destination_root, false)
@@ -222,7 +222,7 @@ class Thor
run "#{command}", config.merge(:with => Thor::Util.ruby_command)
end
- # Run a thor command. A hash of options can be given and it's converted to
+ # Run a thor command. A hash of options can be given and it's converted to
# switches.
#
# ==== Parameters
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/actions/create_file.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/actions/create_file.rb
index a3d9296823..a3d9296823 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/actions/create_file.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/actions/create_file.rb
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/actions/directory.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/actions/directory.rb
index 467e63732a..2e0b459fa3 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/actions/directory.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/actions/directory.rb
@@ -79,11 +79,9 @@ class Thor
next if dirname == given_destination
base.empty_directory(dirname, config)
when /\.tt$/
- destination = base.template(file_source, file_destination[0..-4], config)
- @block.call(destination) if @block
+ destination = base.template(file_source, file_destination[0..-4], config, &@block)
else
- destination = base.copy_file(file_source, file_destination, config)
- @block.call(destination) if @block
+ destination = base.copy_file(file_source, file_destination, config, &@block)
end
end
end
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/actions/empty_directory.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/actions/empty_directory.rb
index 484cb820f8..484cb820f8 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/actions/empty_directory.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/actions/empty_directory.rb
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/actions/file_manipulation.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/actions/file_manipulation.rb
index d77d90d448..8a45c83f25 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/actions/file_manipulation.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/actions/file_manipulation.rb
@@ -18,12 +18,14 @@ class Thor
#
# copy_file "doc/README"
#
- def copy_file(source, destination=nil, config={})
+ def copy_file(source, destination=nil, config={}, &block)
destination ||= source
source = File.expand_path(find_in_source_paths(source.to_s))
create_file destination, nil, config do
- File.read(source)
+ content = File.read(source)
+ content = block.call(content) if block
+ content
end
end
@@ -72,13 +74,15 @@ class Thor
#
# template "doc/README"
#
- def template(source, destination=nil, config={})
+ def template(source, destination=nil, config={}, &block)
destination ||= source
source = File.expand_path(find_in_source_paths(source.to_s))
context = instance_eval('binding')
create_file destination, nil, config do
- ERB.new(::File.read(source), nil, '-').result(context)
+ content = ERB.new(::File.read(source), nil, '-').result(context)
+ content = block.call(content) if block
+ content
end
end
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/actions/inject_into_file.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/actions/inject_into_file.rb
index 0636ec6591..6b0b42ea02 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/actions/inject_into_file.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/actions/inject_into_file.rb
@@ -11,7 +11,7 @@ class Thor
# data<String>:: Data to add to the file. Can be given as a block.
# config<Hash>:: give :verbose => false to not log the status and the flag
# for injection (:after or :before).
- #
+ #
# ==== Examples
#
# inject_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n"
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/base.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/base.rb
index 700d794123..700d794123 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/base.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/base.rb
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/core_ext/hash_with_indifferent_access.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/core_ext/hash_with_indifferent_access.rb
index 78bc5cf4bf..40d201d9e4 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/core_ext/hash_with_indifferent_access.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/core_ext/hash_with_indifferent_access.rb
@@ -65,7 +65,7 @@ class Thor
else
self[$1] == args.first
end
- else
+ else
self[method]
end
end
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/core_ext/ordered_hash.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/core_ext/ordered_hash.rb
index 27fea5bb35..27fea5bb35 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/core_ext/ordered_hash.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/core_ext/ordered_hash.rb
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/error.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/error.rb
index f9b31a35d1..f9b31a35d1 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/error.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/error.rb
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/group.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/group.rb
index 0964a9667a..021a067a3e 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/group.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/group.rb
@@ -132,7 +132,7 @@ class Thor::Group
names.each do |name|
unless class_options.key?(name)
- raise ArgumentError, "You have to define the option #{name.inspect} " <<
+ raise ArgumentError, "You have to define the option #{name.inspect} " <<
"before setting invoke_from_option."
end
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/invocation.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/invocation.rb
index 32e6a72454..32e6a72454 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/invocation.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/invocation.rb
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/parser.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/parser.rb
index 57a3f6e1a5..57a3f6e1a5 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/parser.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/parser.rb
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/parser/argument.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/parser/argument.rb
index aa8ace4719..aa8ace4719 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/parser/argument.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/parser/argument.rb
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/parser/arguments.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/parser/arguments.rb
index fb5d965e06..fb5d965e06 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/parser/arguments.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/parser/arguments.rb
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/parser/option.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/parser/option.rb
index 9e40ec73fa..e09b4901e2 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/parser/option.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/parser/option.rb
@@ -36,7 +36,7 @@ class Thor
# string (--foo=value) or booleans (just --foo).
#
# By default all options are optional, unless :required is given.
- #
+ #
def self.parse(key, value)
if key.is_a?(Array)
name, *aliases = key
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/parser/options.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/parser/options.rb
index 75092308b5..75092308b5 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/parser/options.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/parser/options.rb
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/rake_compat.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/rake_compat.rb
index 0d0757fdda..0d0757fdda 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/rake_compat.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/rake_compat.rb
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/runner.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/runner.rb
index 9dc70ea069..079f9e0c65 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/runner.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/runner.rb
@@ -36,7 +36,7 @@ class Thor::Runner < Thor #:nodoc:
def install(name)
initialize_thorfiles
- # If a directory name is provided as the argument, look for a 'main.thor'
+ # If a directory name is provided as the argument, look for a 'main.thor'
# task in said directory.
begin
if File.directory?(File.expand_path(name))
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/shell.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/shell.rb
index 1dc8f0e5b4..1dc8f0e5b4 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/shell.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/shell.rb
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/shell/basic.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/shell/basic.rb
index ea9665380b..f6be3575ca 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/shell/basic.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/shell/basic.rb
@@ -143,7 +143,7 @@ class Thor
answer = ask %[Overwrite #{destination}? (enter "h" for help) #{options}]
case answer
- when is?(:yes), is?(:force)
+ when is?(:yes), is?(:force), ""
return true
when is?(:no), is?(:skip)
return false
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/shell/color.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/shell/color.rb
index 24704f7885..24704f7885 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/shell/color.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/shell/color.rb
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/task.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/task.rb
index 91c7564d3f..91c7564d3f 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/task.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/task.rb
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/util.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/util.rb
index ebae0a3193..ebae0a3193 100644
--- a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/util.rb
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/util.rb
diff --git a/railties/lib/rails/vendor/thor-0.12.1/lib/thor/version.rb b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/version.rb
new file mode 100644
index 0000000000..650253d648
--- /dev/null
+++ b/railties/lib/rails/vendor/thor-0.12.1/lib/thor/version.rb
@@ -0,0 +1,3 @@
+class Thor
+ VERSION = "0.12.1".freeze
+end
diff --git a/railties/railties.gemspec b/railties/railties.gemspec
new file mode 100644
index 0000000000..a060c3c301
--- /dev/null
+++ b/railties/railties.gemspec
@@ -0,0 +1,28 @@
+Gem::Specification.new do |s|
+ s.platform = Gem::Platform::RUBY
+ s.name = 'railties'
+ s.version = '3.0.pre'
+ s.summary = "Controls boot-up, rake tasks and generators for the Rails framework."
+ s.description = <<-EOF
+ Rails is a framework for building web-application using CGI, FCGI, mod_ruby, or WEBrick
+ on top of either MySQL, PostgreSQL, SQLite, DB2, SQL Server, or Oracle with eRuby- or Builder-based templates.
+ EOF
+
+ s.add_dependency('rake', '>= 0.8.3')
+ s.add_dependency('activesupport', '= 3.0.pre')
+ s.add_dependency('actionpack', '= 3.0.pre')
+
+ s.rdoc_options << '--exclude' << '.'
+ s.has_rdoc = false
+
+ s.files = Dir['CHANGELOG', 'README', 'bin/**/*', 'builtin/**/*', 'guides/**/*', 'lib/**/{*,.[a-z]*}']
+ s.require_path = 'lib'
+ s.bindir = "bin"
+ s.executables = ["rails"]
+ s.default_executable = "rails"
+
+ s.author = "David Heinemeier Hansson"
+ s.email = "david@loudthinking.com"
+ s.homepage = "http://www.rubyonrails.org"
+ s.rubyforge_project = "rails"
+end
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index a3e1916494..4d9da525d7 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -4,7 +4,16 @@ module ApplicationTests
class InitializerTest < Test::Unit::TestCase
include ActiveSupport::Testing::Isolation
+ def new_app
+ File.expand_path("#{app_path}/../new_app")
+ end
+
+ def copy_app
+ FileUtils.cp_r(app_path, new_app)
+ end
+
def setup
+ FileUtils.rm_rf(new_app) if File.directory?(new_app)
build_app
boot_rails
end
@@ -15,34 +24,64 @@ module ApplicationTests
end
test "the application root can be set" do
- FileUtils.mkdir_p("#{app_path}/hello")
+ copy_app
add_to_config <<-RUBY
- config.frameworks = []
- config.root = '#{app_path}/hello'
+ config.root = '#{new_app}'
RUBY
+
+ use_frameworks []
+
+ require "#{app_path}/config/environment"
+ assert_equal Pathname.new(new_app), Rails.application.root
+ end
+
+ test "the application root is Dir.pwd if there is no config.ru" do
+ File.delete("#{app_path}/config.ru")
+
+ use_frameworks []
+
+ Dir.chdir("#{app_path}") do
+ require "#{app_path}/config/environment"
+ assert_equal Pathname.new("#{app_path}"), Rails.application.root
+ end
+ end
+
+ test "if there's no config.active_support.bare, all of ActiveSupport is required" do
+ use_frameworks []
require "#{app_path}/config/environment"
- assert_equal Pathname.new("#{app_path}/hello"), Rails.application.root
+ assert_nothing_raised { [1,2,3].rand }
+ end
+
+ test "config.active_support.bare does not require all of ActiveSupport" do
+ add_to_config "config.active_support.bare = true"
+
+ use_frameworks []
+
+ Dir.chdir("#{app_path}/app") do
+ require "#{app_path}/config/environment"
+ assert_raises(NoMethodError) { [1,2,3].rand }
+ end
end
- test "the application root is detected as where config.ru is located" do
+ test "marking the application as threadsafe sets the correct config variables" do
add_to_config <<-RUBY
- config.frameworks = []
+ config.threadsafe!
RUBY
- FileUtils.mv "#{app_path}/config.ru", "#{app_path}/config/config.ru"
- require "#{app_path}/config/environment"
- assert_equal Pathname.new("#{app_path}/config"), Rails.application.root
+
+ require "#{app_path}/config/application"
+ assert AppTemplate::Application.config.action_controller.allow_concurrency
end
- test "the application root is Dir.pwd if there is no config.ru" do
- File.delete("#{app_path}/config.ru")
+ test "the application can be marked as threadsafe when there are no frameworks" do
+ FileUtils.rm_rf("#{app_path}/config/environments")
add_to_config <<-RUBY
config.frameworks = []
+ config.threadsafe!
RUBY
- Dir.chdir("#{app_path}/app") do
- require "#{app_path}/config/environment"
- assert_equal Pathname.new("#{app_path}/app"), Rails.application.root
+ assert_nothing_raised do
+ require "#{app_path}/config/application"
end
end
end
-end \ No newline at end of file
+end
diff --git a/railties/test/application/generators_test.rb b/railties/test/application/generators_test.rb
index ccbcd84176..7b27c780aa 100644
--- a/railties/test/application/generators_test.rb
+++ b/railties/test/application/generators_test.rb
@@ -7,12 +7,20 @@ module ApplicationTests
def setup
build_app
boot_rails
+ end
+
+ def app_const
+ @app_const ||= Class.new(Rails::Application)
+ end
+
+ def with_config
require "rails"
require "rails/generators"
+ yield app_const.config
end
test "generators default values" do
- Rails::Initializer.run do |c|
+ with_config do |c|
assert_equal(true, c.generators.colorize_logging)
assert_equal({}, c.generators.aliases)
assert_equal({}, c.generators.options)
@@ -20,7 +28,7 @@ module ApplicationTests
end
test "generators set rails options" do
- Rails::Initializer.run do |c|
+ with_config do |c|
c.generators.orm = :datamapper
c.generators.test_framework = :rspec
c.generators.helper = false
@@ -30,7 +38,7 @@ module ApplicationTests
end
test "generators set rails aliases" do
- Rails::Initializer.run do |c|
+ with_config do |c|
c.generators.aliases = { :rails => { :test_framework => "-w" } }
expected = { :rails => { :test_framework => "-w" } }
assert_equal expected, c.generators.aliases
@@ -38,14 +46,15 @@ module ApplicationTests
end
test "generators aliases and options on initialization" do
- Rails::Initializer.run do |c|
- c.frameworks = []
- c.generators.rails :aliases => { :test_framework => "-w" }
- c.generators.orm :datamapper
- c.generators.test_framework :rspec
- end
+ add_to_config <<-RUBY
+ config.generators.rails :aliases => { :test_framework => "-w" }
+ config.generators.orm :datamapper
+ config.generators.test_framework :rspec
+ RUBY
+
+ require "#{app_path}/config/environment"
# Initialize the application
- Rails.initialize!
+ require "rails/generators"
Rails::Generators.configure!
assert_equal :rspec, Rails::Generators.options[:rails][:test_framework]
@@ -53,19 +62,20 @@ module ApplicationTests
end
test "generators no color on initialization" do
- Rails::Initializer.run do |c|
- c.frameworks = []
- c.generators.colorize_logging = false
- end
+ add_to_config <<-RUBY
+ config.generators.colorize_logging = false
+ RUBY
+
# Initialize the application
- Rails.initialize!
+ require "#{app_path}/config/environment"
+ require "rails/generators"
Rails::Generators.configure!
assert_equal Thor::Base.shell, Thor::Shell::Basic
end
test "generators with hashes for options and aliases" do
- Rails::Initializer.run do |c|
+ with_config do |c|
c.generators do |g|
g.orm :datamapper, :migration => false
g.plugin :aliases => { :generator => "-g" },
@@ -84,7 +94,7 @@ module ApplicationTests
end
test "generators with hashes are deep merged" do
- Rails::Initializer.run do |c|
+ with_config do |c|
c.generators do |g|
g.orm :datamapper, :migration => false
g.plugin :aliases => { :generator => "-g" },
diff --git a/railties/test/application/initializer_test.rb b/railties/test/application/initializer_test.rb
index 719520bf68..2ecc3e9e2d 100644
--- a/railties/test/application/initializer_test.rb
+++ b/railties/test/application/initializer_test.rb
@@ -10,42 +10,15 @@ module ApplicationTests
require "rails"
end
- test "initializing an application initializes rails" do
- Rails::Initializer.run do |config|
- config.root = app_path
- end
-
- if RUBY_VERSION < '1.9'
- $KCODE = ''
- Rails.initialize!
- assert_equal 'UTF8', $KCODE
- else
- Encoding.default_external = Encoding::US_ASCII
- Rails.initialize!
- assert_equal Encoding::UTF_8, Encoding.default_external
- end
- end
-
test "initializing an application adds the application paths to the load path" do
- Rails::Initializer.run do |config|
- config.root = app_path
- end
+ add_to_config <<-RUBY
+ config.root = "#{app_path}"
+ RUBY
- Rails.initialize!
+ require "#{app_path}/config/environment"
assert $:.include?("#{app_path}/app/models")
end
- test "adding an unknown framework raises an error" do
- Rails::Initializer.run do |config|
- config.root = app_path
- config.frameworks << :action_foo
- end
-
- assert_raises RuntimeError do
- Rails.initialize!
- end
- end
-
test "eager loading loads parent classes before children" do
app_file "lib/zoo.rb", <<-ZOO
class Zoo ; include ReptileHouse ; end
@@ -54,12 +27,12 @@ module ApplicationTests
module Zoo::ReptileHouse ; end
ZOO
- Rails::Initializer.run do |config|
- config.root = app_path
+ add_to_config <<-RUBY
+ config.root = "#{app_path}"
config.eager_load_paths = "#{app_path}/lib"
- end
+ RUBY
- Rails.initialize!
+ require "#{app_path}/config/environment"
assert Zoo
end
@@ -67,41 +40,43 @@ module ApplicationTests
test "load environment with global" do
app_file "config/environments/development.rb", "$initialize_test_set_from_env = 'success'"
assert_nil $initialize_test_set_from_env
- Rails::Initializer.run { |config| config.root = app_path }
- Rails.initialize!
+ add_to_config <<-RUBY
+ config.root = "#{app_path}"
+ RUBY
+ require "#{app_path}/config/environment"
assert_equal "success", $initialize_test_set_from_env
end
test "action_controller load paths set only if action controller in use" do
assert_nothing_raised NameError do
- Rails::Initializer.run do |config|
- config.root = app_path
+ add_to_config <<-RUBY
+ config.root = "#{app_path}"
config.frameworks = []
- end
- Rails.initialize!
+ RUBY
+ require "#{app_path}/config/environment"
end
end
test "after_initialize block works correctly" do
- Rails::Initializer.run do |config|
- config.root = app_path
+ add_to_config <<-RUBY
+ config.root = "#{app_path}"
config.after_initialize { $test_after_initialize_block1 = "success" }
config.after_initialize { $test_after_initialize_block2 = "congratulations" }
- end
- Rails.initialize!
+ RUBY
+ require "#{app_path}/config/environment"
assert_equal "success", $test_after_initialize_block1
assert_equal "congratulations", $test_after_initialize_block2
end
test "after_initialize block works correctly when no block is passed" do
- Rails::Initializer.run do |config|
- config.root = app_path
+ add_to_config <<-RUBY
+ config.root = "#{app_path}"
config.after_initialize { $test_after_initialize_block1 = "success" }
config.after_initialize # don't pass a block, this is what we're testing!
config.after_initialize { $test_after_initialize_block2 = "congratulations" }
- end
- Rails.initialize!
+ RUBY
+ require "#{app_path}/config/environment"
assert_equal "success", $test_after_initialize_block1
assert_equal "congratulations", $test_after_initialize_block2
@@ -109,35 +84,40 @@ module ApplicationTests
# i18n
test "setting another default locale" do
- Rails::Initializer.run do |config|
- config.root = app_path
+ add_to_config <<-RUBY
+ config.root = "#{app_path}"
config.i18n.default_locale = :de
- end
- Rails.initialize!
+ RUBY
+ require "#{app_path}/config/environment"
assert_equal :de, I18n.default_locale
end
test "no config locales dir present should return empty load path" do
FileUtils.rm_rf "#{app_path}/config/locales"
- Rails::Initializer.run do |c|
- c.root = app_path
- assert_equal [], c.i18n.load_path
- end
+ add_to_config <<-RUBY
+ config.root = "#{app_path}"
+ RUBY
+ require "#{app_path}/config/environment"
+
+ assert_equal [], Rails.application.config.i18n.load_path
end
test "config locales dir present should be added to load path" do
- Rails::Initializer.run do |c|
- c.root = app_path
- assert_equal ["#{app_path}/config/locales/en.yml"], c.i18n.load_path
- end
+ add_to_config <<-RUBY
+ config.root = "#{app_path}"
+ RUBY
+
+ require "#{app_path}/config/environment"
+ assert_equal ["#{app_path}/config/locales/en.yml"], Rails.application.config.i18n.load_path
end
test "config defaults should be added with config settings" do
- Rails::Initializer.run do |c|
- c.root = app_path
- c.i18n.load_path << "my/other/locale.yml"
- end
+ add_to_config <<-RUBY
+ config.root = "#{app_path}"
+ config.i18n.load_path << "my/other/locale.yml"
+ RUBY
+ require "#{app_path}/config/environment"
assert_equal [
"#{app_path}/config/locales/en.yml", "my/other/locale.yml"
@@ -146,64 +126,47 @@ module ApplicationTests
# DB middleware
test "database middleware doesn't initialize when session store is not active_record" do
- Rails::Initializer.run do |config|
- config.root = app_path
+ add_to_config <<-RUBY
+ config.root = "#{app_path}"
config.action_controller.session_store = :cookie_store
- end
- Rails.initialize!
+ RUBY
+ require "#{app_path}/config/environment"
assert !Rails.application.config.middleware.include?(ActiveRecord::SessionStore)
end
- test "database middleware doesn't initialize when activerecord is not in frameworks" do
- Rails::Initializer.run do |c|
- c.root = app_path
- c.frameworks = []
- end
- assert_equal [], Rails.application.config.middleware
- end
-
test "database middleware initializes when session store is active record" do
- Rails::Initializer.run do |c|
- c.root = app_path
- c.action_controller.session_store = :active_record_store
- end
- Rails.initialize!
+ add_to_config "config.action_controller.session_store = :active_record_store"
+
+ require "#{app_path}/config/environment"
expects = [ActiveRecord::ConnectionAdapters::ConnectionManagement, ActiveRecord::QueryCache, ActiveRecord::SessionStore]
middleware = Rails.application.config.middleware.map { |m| m.klass }
assert_equal expects, middleware & expects
end
- test "ensure database middleware doesn't use action_controller on initializing" do
- Rails::Initializer.run do |c|
- c.root = app_path
- c.frameworks -= [:action_controller]
- c.action_controller.session_store = :active_record_store
- end
- Rails.initialize!
-
- assert !Rails.application.config.middleware.include?(ActiveRecord::SessionStore)
+ test "Rails.root should be a Pathname" do
+ add_to_config <<-RUBY
+ config.root = "#{app_path}"
+ RUBY
+ require "#{app_path}/config/environment"
+ assert_instance_of Pathname, Rails.root
end
+ end
- # Pathview test
- test "load view paths doesn't perform anything when action_view not in frameworks" do
- Rails::Initializer.run do |c|
- c.root = app_path
- c.frameworks -= [:action_view]
- end
- Rails.initialize!
+ class InitializerCustomFrameworkExtensionsTest < Test::Unit::TestCase
+ include ActiveSupport::Testing::Isolation
- assert_equal nil, ActionMailer::Base.template_root
- assert_equal [], ActionController::Base.view_paths
+ def setup
+ build_app
+ boot_rails
end
- test "Rails.root should be a Pathname" do
- Rails::Initializer.run do |c|
- c.root = app_path
- end
- Rails.initialize!
- assert_instance_of Pathname, Rails.root
+ test "database middleware doesn't initialize when activerecord is not in frameworks" do
+ use_frameworks []
+ require "#{app_path}/config/environment"
+
+ assert !defined?(ActiveRecord)
end
end
end \ No newline at end of file
diff --git a/railties/test/application/load_test.rb b/railties/test/application/load_test.rb
index 3da51c4355..1c5811b07a 100644
--- a/railties/test/application/load_test.rb
+++ b/railties/test/application/load_test.rb
@@ -1,27 +1,13 @@
require "isolation/abstract_unit"
-# require "rails"
-# require 'action_dispatch'
module ApplicationTests
class LoadTest < Test::Unit::TestCase
include ActiveSupport::Testing::Isolation
def rackup
- config = "#{app_path}/config.ru"
- # Copied from ActionDispatch::Utils.parse_config
- # ActionDispatch is not necessarily available at this point.
- require 'rack'
- if config =~ /\.ru$/
- cfgfile = ::File.read(config)
- if cfgfile[/^#\\(.*)/]
- opts.parse! $1.split(/\s+/)
- end
- inner_app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app",
- nil, config
- else
- require config
- inner_app = Object.const_get(::File.basename(config, '.rb').capitalize)
- end
+ require "rack"
+ app, options = Rack::Builder.parse_file("#{app_path}/config.ru")
+ app
end
def setup
@@ -34,20 +20,22 @@ module ApplicationTests
end
test "config.ru can be racked up" do
- @app = rackup
- assert_welcome get("/")
+ Dir.chdir app_path do
+ @app = rackup
+ assert_welcome get("/")
+ end
end
test "Rails.application is available after config.ru has been racked up" do
rackup
- assert Rails.application < Rails::Application
+ assert Rails.application.is_a?(Rails::Application)
end
# Passenger still uses AC::Dispatcher, so we need to
# keep it working for now
test "deprecated ActionController::Dispatcher still works" do
rackup
- assert ActionController::Dispatcher.new < Rails::Application
+ assert ActionController::Dispatcher.new.is_a?(Rails::Application)
end
test "the config object is available on the application object" do
diff --git a/railties/test/application/notifications_test.rb b/railties/test/application/notifications_test.rb
index 62ed4f4ad4..71e406f2c1 100644
--- a/railties/test/application/notifications_test.rb
+++ b/railties/test/application/notifications_test.rb
@@ -5,19 +5,8 @@ module ApplicationTests
include ActiveSupport::Testing::Isolation
class MyQueue
- attr_reader :events, :subscribers
-
- def initialize
- @events = []
- @subscribers = []
- end
-
def publish(name, *args)
- @events << name
- end
-
- def subscribe(pattern=nil, &block)
- @subscribers << pattern
+ raise name
end
end
@@ -26,21 +15,16 @@ module ApplicationTests
boot_rails
require "rails"
require "active_support/notifications"
+ @events = []
Rails::Initializer.run do |c|
- c.notifications.queue = MyQueue.new
- c.notifications.subscribe(/listening/) do
- puts "Cool"
- end
+ c.notifications.notifier = ActiveSupport::Notifications::Notifier.new(MyQueue.new)
end
end
test "new queue is set" do
- ActiveSupport::Notifications.instrument(:foo)
- assert_equal :foo, ActiveSupport::Notifications.queue.events.first
- end
-
- test "configuration subscribers are loaded" do
- assert_equal 1, ActiveSupport::Notifications.queue.subscribers.count { |s| s == /listening/ }
+ assert_raise RuntimeError do
+ ActiveSupport::Notifications.publish('foo')
+ end
end
end
end
diff --git a/railties/test/application/routing_test.rb b/railties/test/application/routing_test.rb
new file mode 100644
index 0000000000..725dd06929
--- /dev/null
+++ b/railties/test/application/routing_test.rb
@@ -0,0 +1,180 @@
+require 'isolation/abstract_unit'
+
+module ApplicationTests
+ class RoutingTest < Test::Unit::TestCase
+ include ActiveSupport::Testing::Isolation
+
+ def setup
+ build_app
+ boot_rails
+ require 'rack/test'
+ extend Rack::Test::Methods
+ end
+
+ def app
+ @app ||= begin
+ require "#{app_path}/config/environment"
+
+ Rails.application
+ end
+ end
+
+ test "rails/info/properties" do
+ get "/rails/info/properties"
+ assert_equal 200, last_response.status
+ end
+
+ test "simple controller" do
+ controller :foo, <<-RUBY
+ class FooController < ActionController::Base
+ def index
+ render :text => "foo"
+ end
+ end
+ RUBY
+
+ app_file 'config/routes.rb', <<-RUBY
+ AppTemplate::Application.routes.draw do |map|
+ match ':controller(/:action)'
+ end
+ RUBY
+
+ get '/foo'
+ assert_equal 'foo', last_response.body
+ end
+
+ test "multiple controllers" do
+ controller :foo, <<-RUBY
+ class FooController < ActionController::Base
+ def index
+ render :text => "foo"
+ end
+ end
+ RUBY
+
+ controller :bar, <<-RUBY
+ class BarController < ActionController::Base
+ def index
+ render :text => "bar"
+ end
+ end
+ RUBY
+
+ app_file 'config/routes.rb', <<-RUBY
+ AppTemplate::Application.routes.draw do |map|
+ match ':controller(/:action)'
+ end
+ RUBY
+
+ get '/foo'
+ assert_equal 'foo', last_response.body
+
+ get '/bar'
+ assert_equal 'bar', last_response.body
+ end
+
+ test "nested controller" do
+ controller 'foo', <<-RUBY
+ class FooController < ActionController::Base
+ def index
+ render :text => "foo"
+ end
+ end
+ RUBY
+
+ controller 'admin/foo', <<-RUBY
+ module Admin
+ class FooController < ActionController::Base
+ def index
+ render :text => "admin::foo"
+ end
+ end
+ end
+ RUBY
+
+ app_file 'config/routes.rb', <<-RUBY
+ AppTemplate::Application.routes.draw do |map|
+ match ':controller(/:action)'
+ end
+ RUBY
+
+ get '/foo'
+ assert_equal 'foo', last_response.body
+
+ get '/admin/foo'
+ assert_equal 'admin::foo', last_response.body
+ end
+
+ test "merges with plugin routes" do
+ controller 'foo', <<-RUBY
+ class FooController < ActionController::Base
+ def index
+ render :text => "foo"
+ end
+ end
+ RUBY
+
+ app_file 'config/routes.rb', <<-RUBY
+ AppTemplate::Application.routes.draw do |map|
+ match 'foo', :to => 'foo#index'
+ end
+ RUBY
+
+ plugin 'bar', 'require File.dirname(__FILE__) + "/app/controllers/bar"' do |plugin|
+ plugin.write 'app/controllers/bar.rb', <<-RUBY
+ class BarController < ActionController::Base
+ def index
+ render :text => "bar"
+ end
+ end
+ RUBY
+
+ plugin.write 'config/routes.rb', <<-RUBY
+ AppTemplate::Application.routes.draw do |map|
+ match 'bar', :to => 'bar#index'
+ end
+ RUBY
+ end
+
+ get '/foo'
+ assert_equal 'foo', last_response.body
+
+ get '/bar'
+ assert_equal 'bar', last_response.body
+ end
+
+ test "reloads routes when configuration is changed" do
+ controller :foo, <<-RUBY
+ class FooController < ActionController::Base
+ def bar
+ render :text => "bar"
+ end
+
+ def baz
+ render :text => "baz"
+ end
+ end
+ RUBY
+
+ app_file 'config/routes.rb', <<-RUBY
+ AppTemplate::Application.routes.draw do |map|
+ match 'foo', :to => 'foo#bar'
+ end
+ RUBY
+
+ get '/foo'
+ assert_equal 'bar', last_response.body
+
+ app_file 'config/routes.rb', <<-RUBY
+ AppTemplate::Application.routes.draw do |map|
+ match 'foo', :to => 'foo#baz'
+ end
+ RUBY
+
+ sleep 0.1
+
+ get '/foo'
+ assert_equal 'baz', last_response.body
+ end
+ end
+end
diff --git a/railties/test/fixtures/plugins/engines/engine/config/routes.rb b/railties/test/fixtures/plugins/engines/engine/config/routes.rb
index cca8d1b146..da44595693 100644
--- a/railties/test/fixtures/plugins/engines/engine/config/routes.rb
+++ b/railties/test/fixtures/plugins/engines/engine/config/routes.rb
@@ -1,3 +1,3 @@
ActionController::Routing::Routes.draw do |map|
- map.connect '/engine', :controller => "engine"
+ match '/engine', :to => "engine"
end
diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb
index 7d03a37f2a..b69f23c965 100644
--- a/railties/test/generators/actions_test.rb
+++ b/railties/test/generators/actions_test.rb
@@ -171,7 +171,7 @@ class ActionsTest < GeneratorsTestCase
def test_route_should_add_data_to_the_routes_block_in_config_routes
run_generator
- route_command = "map.route '/login', :controller => 'sessions', :action => 'new'"
+ route_command = "route '/login', :controller => 'sessions', :action => 'new'"
action :route, route_command
assert_file 'config/routes.rb', /#{Regexp.escape(route_command)}/
end
diff --git a/railties/test/generators/resource_generator_test.rb b/railties/test/generators/resource_generator_test.rb
index 886af01b22..dff3908ea1 100644
--- a/railties/test/generators/resource_generator_test.rb
+++ b/railties/test/generators/resource_generator_test.rb
@@ -62,7 +62,7 @@ class ResourceGeneratorTest < GeneratorsTestCase
run_generator
assert_file "config/routes.rb" do |route|
- assert_match /map\.resources :accounts$/, route
+ assert_match /resources :accounts$/, route
end
end
@@ -70,7 +70,7 @@ class ResourceGeneratorTest < GeneratorsTestCase
run_generator ["account", "--singleton"]
assert_file "config/routes.rb" do |route|
- assert_match /map\.resource :account$/, route
+ assert_match /resource :account$/, route
end
end
@@ -93,7 +93,7 @@ class ResourceGeneratorTest < GeneratorsTestCase
run_generator ["account"], :behavior => :revoke
assert_file "config/routes.rb" do |route|
- assert_no_match /map\.resources :accounts$/, route
+ assert_no_match /resources :accounts$/, route
end
end
diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb
index c0652c034f..0b961cee19 100644
--- a/railties/test/generators/scaffold_generator_test.rb
+++ b/railties/test/generators/scaffold_generator_test.rb
@@ -25,7 +25,7 @@ class ScaffoldGeneratorTest < GeneratorsTestCase
# Route
assert_file "config/routes.rb" do |route|
- assert_match /map\.resources :product_lines$/, route
+ assert_match /resources :product_lines$/, route
end
# Controller
@@ -99,7 +99,7 @@ class ScaffoldGeneratorTest < GeneratorsTestCase
# Route
assert_file "config/routes.rb" do |route|
- assert_no_match /map\.resources :product_lines$/, route
+ assert_no_match /resources :product_lines$/, route
end
# Controller
diff --git a/railties/test/initializable_test.rb b/railties/test/initializable_test.rb
index a9e60680ac..e308cbcb0e 100644
--- a/railties/test/initializable_test.rb
+++ b/railties/test/initializable_test.rb
@@ -150,6 +150,16 @@ module InitializableTests
Word.run_initializers
assert_equal "bird", $word
end
+
+ test "creating initializer without a block raises an error" do
+ assert_raise(ArgumentError) do
+ Class.new do
+ include Rails::Initializable
+
+ initializer :foo
+ end
+ end
+ end
end
class BeforeAfter < ActiveSupport::TestCase
diff --git a/railties/test/initializer/check_ruby_version_test.rb b/railties/test/initializer/check_ruby_version_test.rb
index 97d884e1be..0691caad9d 100644
--- a/railties/test/initializer/check_ruby_version_test.rb
+++ b/railties/test/initializer/check_ruby_version_test.rb
@@ -7,7 +7,6 @@ module InitializerTests
def setup
build_app
boot_rails
- require "rails"
end
test "rails does not initialize with ruby version 1.8.1" do
@@ -50,8 +49,7 @@ module InitializerTests
def assert_rails_boots(version = nil)
set_ruby_version(version) if version
assert_nothing_raised "It appears that rails does not boot" do
- Rails::Initializer.run { |c| c.frameworks = [] }
- Rails.initialize!
+ require "rails"
end
end
@@ -59,8 +57,7 @@ module InitializerTests
set_ruby_version(version)
$stderr = File.open("/dev/null", "w")
assert_raises(SystemExit) do
- Rails::Initializer.run { |c| c.frameworks = [] }
- Rails.initialize!
+ require "rails"
end
end
end
diff --git a/railties/test/initializer/initialize_i18n_test.rb b/railties/test/initializer/initialize_i18n_test.rb
index 076816d73b..472566378d 100644
--- a/railties/test/initializer/initialize_i18n_test.rb
+++ b/railties/test/initializer/initialize_i18n_test.rb
@@ -7,16 +7,15 @@ module InitializerTests
def setup
build_app
boot_rails
- require "rails"
end
# test_config_defaults_and_settings_should_be_added_to_i18n_defaults
test "i18n config defaults and settings should be added to i18n defaults" do
- Rails::Initializer.run do |c|
- c.root = app_path
- c.i18n.load_path << "my/other/locale.yml"
- end
- Rails.initialize!
+ add_to_config <<-RUBY
+ config.root = "#{app_path}"
+ config.i18n.load_path << "my/other/locale.yml"
+ RUBY
+ require "#{app_path}/config/environment"
#{RAILS_FRAMEWORK_ROOT}/railties/test/fixtures/plugins/engines/engine/config/locales/en.yml
assert_equal %W(
diff --git a/railties/test/initializer/path_test.rb b/railties/test/initializer/path_test.rb
index 1b58a58555..fa66ebcd83 100644
--- a/railties/test/initializer/path_test.rb
+++ b/railties/test/initializer/path_test.rb
@@ -7,14 +7,14 @@ class PathsTest < Test::Unit::TestCase
build_app
boot_rails
require "rails"
- Rails::Initializer.run do |config|
- config.root = app_path
+ add_to_config <<-RUBY
+ config.root = "#{app_path}"
config.frameworks = [:action_controller, :action_view, :action_mailer, :active_record]
config.after_initialize do
ActionController::Base.session_store = nil
end
- end
- Rails.initialize!
+ RUBY
+ require "#{app_path}/config/environment"
@paths = Rails.application.config.paths
end
diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb
index ba8b35d5cc..ee0a812b47 100644
--- a/railties/test/isolation/abstract_unit.rb
+++ b/railties/test/isolation/abstract_unit.rb
@@ -89,6 +89,13 @@ module TestHelpers
end
end
+ routes = File.read("#{app_path}/config/routes.rb")
+ if routes =~ /(\n\s*end\s*)\Z/
+ File.open("#{app_path}/config/routes.rb", 'w') do |f|
+ f.puts $` + "\nmatch ':controller(/:action(/:id))(.:format)'\n" + $1
+ end
+ end
+
add_to_config 'config.action_controller.session = { :key => "_myapp_session", :secret => "bac838a849c1d5c4de2e6a50af826079" }'
end
@@ -128,7 +135,7 @@ module TestHelpers
def add_to_config(str)
environment = File.read("#{app_path}/config/application.rb")
- if environment =~ /(\n\s*end\s*)\Z/
+ if environment =~ /(\n\s*end\s*end\s*)\Z/
File.open("#{app_path}/config/application.rb", 'w') do |f|
f.puts $` + "\n#{str}\n" + $1
end
@@ -146,6 +153,14 @@ module TestHelpers
app_file("app/controllers/#{name}_controller.rb", contents)
end
+ def use_frameworks(arr)
+ to_remove = [:actionmailer,
+ :activemodel,
+ :activerecord,
+ :activeresource] - arr
+ $:.reject! {|path| path =~ %r'/(#{to_remove.join('|')})/' }
+ end
+
def boot_rails
root = File.expand_path('../../../..', __FILE__)
begin
diff --git a/railties/test/paths_test.rb b/railties/test/paths_test.rb
index c724799d64..d60d6177f6 100644
--- a/railties/test/paths_test.rb
+++ b/railties/test/paths_test.rb
@@ -2,7 +2,6 @@ require 'abstract_unit'
require 'rails/paths'
class PathsTest < ActiveSupport::TestCase
-
def setup
@root = Rails::Application::Root.new("/foo/bar")
end
@@ -228,4 +227,4 @@ class PathsTest < ActiveSupport::TestCase
@root.app.eager_load!
assert_equal ["/foo/bar/app"], @root.load_paths
end
-end \ No newline at end of file
+end
diff --git a/railties/test/plugins/configuration_test.rb b/railties/test/plugins/configuration_test.rb
new file mode 100644
index 0000000000..5786316d1d
--- /dev/null
+++ b/railties/test/plugins/configuration_test.rb
@@ -0,0 +1,36 @@
+require "isolation/abstract_unit"
+
+module PluginsTest
+ class ConfigurationTest < Test::Unit::TestCase
+ def setup
+ build_app
+ boot_rails
+ require "rails"
+ end
+
+ test "config is available to plugins" do
+ class Foo < Rails::Plugin ; end
+ assert_nil Foo.config.action_controller.foo
+ end
+
+ test "a config name is available for the plugin" do
+ class Foo < Rails::Plugin ; config.foo.greetings = "hello" ; end
+ assert_equal "hello", Foo.config.foo.greetings
+ end
+
+ test "plugin configurations are available in the application" do
+ class Foo < Rails::Plugin ; config.foo.greetings = "hello" ; end
+ require "#{app_path}/config/application"
+ assert_equal "hello", AppTemplate::Application.config.foo.greetings
+ end
+
+ test "plugin config merges are deep" do
+ class Foo < Rails::Plugin ; config.foo.greetings = 'hello' ; end
+ class MyApp < Rails::Application
+ config.foo.bar = "bar"
+ end
+ assert_equal "hello", MyApp.config.foo.greetings
+ assert_equal "bar", MyApp.config.foo.bar
+ end
+ end
+end
diff --git a/railties/test/plugins/framework_extension_test.rb b/railties/test/plugins/framework_extension_test.rb
new file mode 100644
index 0000000000..87e19cadce
--- /dev/null
+++ b/railties/test/plugins/framework_extension_test.rb
@@ -0,0 +1,18 @@
+require "isolation/abstract_unit"
+
+module PluginsTest
+ class FrameworkExtensionTest < Test::Unit::TestCase
+ def setup
+ build_app
+ boot_rails
+ end
+
+ test "active_record extensions are applied to ActiveRecord" do
+ add_to_config "config.active_record.table_name_prefix = 'tbl_'"
+
+ require "#{app_path}/config/environment"
+
+ assert_equal 'tbl_', ActiveRecord::Base.table_name_prefix
+ end
+ end
+end \ No newline at end of file
diff --git a/railties/test/rails_info_controller_test.rb b/railties/test/rails_info_controller_test.rb
index a0484c0868..435bd34925 100644
--- a/railties/test/rails_info_controller_test.rb
+++ b/railties/test/rails_info_controller_test.rb
@@ -1,5 +1,6 @@
require 'abstract_unit'
require 'action_controller'
+require 'action_controller/test_case'
require 'rails/info'
require 'rails/info_controller'
@@ -14,17 +15,12 @@ class InfoControllerTest < ActionController::TestCase
tests Rails::InfoController
def setup
- ActionController::Routing.use_controllers!(['rails/info'])
ActionController::Routing::Routes.draw do |map|
- map.connect ':controller/:action/:id'
+ match ':controller/:action'
end
@controller.stubs(:consider_all_requests_local => false, :local_request? => true)
end
- def teardown
- ActionController::Routing.use_controllers! nil
- end
-
test "info controller does not allow remote requests" do
@controller.stubs(:consider_all_requests_local => false, :local_request? => false)
get :properties