aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Rakefile62
-rwxr-xr-xactionmailer/Rakefile7
-rw-r--r--actionmailer/lib/action_mailer/base.rb8
-rwxr-xr-xactionmailer/test/mail_service_test.rb6
-rw-r--r--actionpack/CHANGELOG26
-rw-r--r--actionpack/Rakefile12
-rw-r--r--actionpack/lib/action_controller/assertions/response_assertions.rb2
-rwxr-xr-xactionpack/lib/action_controller/base.rb35
-rw-r--r--actionpack/lib/action_controller/caching/actions.rb61
-rw-r--r--actionpack/lib/action_controller/caching/fragments.rb18
-rw-r--r--actionpack/lib/action_controller/dispatcher.rb6
-rw-r--r--actionpack/lib/action_controller/integration.rb9
-rw-r--r--actionpack/lib/action_controller/layout.rb2
-rw-r--r--actionpack/lib/action_controller/performance_test.rb16
-rw-r--r--actionpack/lib/action_controller/polymorphic_routes.rb37
-rw-r--r--actionpack/lib/action_controller/rack_process.rb54
-rw-r--r--actionpack/lib/action_controller/record_identifier.rb33
-rwxr-xr-xactionpack/lib/action_controller/request.rb9
-rw-r--r--actionpack/lib/action_controller/resources.rb6
-rw-r--r--actionpack/lib/action_controller/routing.rb2
-rw-r--r--actionpack/lib/action_controller/routing/segments.rb2
-rw-r--r--actionpack/lib/action_controller/templates/rescues/layout.erb2
-rw-r--r--actionpack/lib/action_controller/vendor/html-scanner/html/document.rb2
-rw-r--r--actionpack/lib/action_controller/verification.rb2
-rw-r--r--actionpack/lib/action_view.rb10
-rw-r--r--actionpack/lib/action_view/base.rb135
-rw-r--r--actionpack/lib/action_view/helpers/capture_helper.rb59
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb58
-rw-r--r--actionpack/lib/action_view/helpers/javascript_helper.rb141
-rw-r--r--actionpack/lib/action_view/helpers/prototype_helper.rb14
-rw-r--r--actionpack/lib/action_view/helpers/record_tag_helper.rb5
-rw-r--r--actionpack/lib/action_view/helpers/tag_helper.rb48
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb14
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb62
-rw-r--r--actionpack/lib/action_view/inline_template.rb9
-rw-r--r--actionpack/lib/action_view/partial_template.rb78
-rw-r--r--actionpack/lib/action_view/template.rb109
-rw-r--r--actionpack/lib/action_view/template_file.rb88
-rw-r--r--actionpack/lib/action_view/template_finder.rb177
-rw-r--r--actionpack/lib/action_view/template_handler.rb1
-rw-r--r--actionpack/lib/action_view/template_handlers.rb46
-rw-r--r--actionpack/lib/action_view/template_handlers/builder.rb7
-rw-r--r--actionpack/lib/action_view/template_handlers/compilable.rb10
-rw-r--r--actionpack/lib/action_view/template_handlers/erb.rb10
-rw-r--r--actionpack/lib/action_view/test_case.rb5
-rw-r--r--actionpack/lib/action_view/view_load_paths.rb103
-rw-r--r--actionpack/test/controller/action_pack_assertions_test.rb23
-rw-r--r--actionpack/test/controller/base_test.rb18
-rw-r--r--actionpack/test/controller/caching_test.rb72
-rw-r--r--actionpack/test/controller/capture_test.rb20
-rwxr-xr-xactionpack/test/controller/cgi_test.rb50
-rw-r--r--actionpack/test/controller/dispatcher_test.rb4
-rw-r--r--actionpack/test/controller/html-scanner/document_test.rb25
-rw-r--r--actionpack/test/controller/integration_test.rb93
-rw-r--r--actionpack/test/controller/integration_upload_test.rb2
-rw-r--r--actionpack/test/controller/new_render_test.rb29
-rw-r--r--actionpack/test/controller/polymorphic_routes_test.rb33
-rw-r--r--actionpack/test/controller/rack_test.rb64
-rw-r--r--actionpack/test/controller/request_test.rb3
-rw-r--r--actionpack/test/controller/routing_test.rb3235
-rw-r--r--actionpack/test/controller/verification_test.rb51
-rw-r--r--actionpack/test/controller/view_paths_test.rb111
-rw-r--r--actionpack/test/fixtures/test/block_content_for.erb2
-rw-r--r--actionpack/test/fixtures/test/erb_content_for.erb2
-rw-r--r--actionpack/test/fixtures/test/non_erb_block_content_for.builder2
-rw-r--r--actionpack/test/fixtures/test/render_file_from_template.html.erb1
-rwxr-xr-xactionpack/test/template/date_helper_test.rb12
-rw-r--r--actionpack/test/template/form_helper_test.rb251
-rw-r--r--actionpack/test/template/form_options_helper_test.rb36
-rw-r--r--actionpack/test/template/form_tag_helper_test.rb62
-rw-r--r--actionpack/test/template/javascript_helper_test.rb22
-rw-r--r--actionpack/test/template/prototype_helper_test.rb162
-rw-r--r--actionpack/test/template/record_tag_helper_test.rb36
-rw-r--r--actionpack/test/template/tag_helper_test.rb44
-rw-r--r--actionpack/test/template/template_file_test.rb95
-rw-r--r--actionpack/test/template/template_finder_test.rb73
-rw-r--r--actionpack/test/template/template_object_test.rb37
-rw-r--r--actionpack/test/template/text_helper_test.rb6
-rw-r--r--actionpack/test/template/url_helper_test.rb20
-rw-r--r--activemodel/Rakefile4
-rw-r--r--activerecord/CHANGELOG18
-rwxr-xr-xactiverecord/Rakefile8
-rw-r--r--activerecord/lib/active_record/association_preload.rb4
-rwxr-xr-xactiverecord/lib/active_record/associations.rb30
-rw-r--r--activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb1
-rw-r--r--activerecord/lib/active_record/associations/has_many_association.rb2
-rwxr-xr-xactiverecord/lib/active_record/base.rb76
-rw-r--r--activerecord/lib/active_record/calculations.rb15
-rwxr-xr-xactiverecord/lib/active_record/callbacks.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb21
-rwxr-xr-xactiverecord/lib/active_record/connection_adapters/mysql_adapter.rb110
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb96
-rwxr-xr-xactiverecord/lib/active_record/fixtures.rb2
-rw-r--r--activerecord/lib/active_record/locking/optimistic.rb1
-rw-r--r--activerecord/lib/active_record/migration.rb5
-rw-r--r--activerecord/lib/active_record/named_scope.rb1
-rw-r--r--activerecord/lib/active_record/observer.rb2
-rwxr-xr-xactiverecord/lib/active_record/validations.rb9
-rw-r--r--activerecord/lib/active_record/vendor/db2.rb362
-rw-r--r--activerecord/lib/active_record/vendor/mysql.rb1214
-rw-r--r--activerecord/test/cases/active_schema_test_postgresql.rb4
-rwxr-xr-xactiverecord/test/cases/associations/belongs_to_associations_test.rb19
-rw-r--r--activerecord/test/cases/associations/eager_test.rb13
-rw-r--r--activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb6
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb17
-rw-r--r--activerecord/test/cases/associations/has_many_through_associations_test.rb6
-rwxr-xr-xactiverecord/test/cases/associations/has_one_associations_test.rb12
-rwxr-xr-xactiverecord/test/cases/attribute_methods_test.rb20
-rwxr-xr-xactiverecord/test/cases/base_test.rb28
-rw-r--r--activerecord/test/cases/calculations_test.rb54
-rw-r--r--activerecord/test/cases/callbacks_observers_test.rb38
-rw-r--r--activerecord/test/cases/database_statements_test.rb12
-rw-r--r--activerecord/test/cases/dirty_test.rb19
-rw-r--r--activerecord/test/cases/finder_test.rb7
-rwxr-xr-xactiverecord/test/cases/inheritance_test.rb4
-rwxr-xr-xactiverecord/test/cases/lifecycle_test.rb17
-rw-r--r--activerecord/test/cases/locking_test.rb20
-rw-r--r--activerecord/test/cases/method_scoping_test.rb10
-rw-r--r--activerecord/test/cases/migration_test.rb56
-rw-r--r--activerecord/test/cases/multiple_db_test.rb2
-rw-r--r--activerecord/test/cases/named_scope_test.rb27
-rw-r--r--activerecord/test/cases/reflection_test.rb6
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb46
-rw-r--r--activerecord/test/models/author.rb1
-rw-r--r--activerecord/test/models/category.rb1
-rwxr-xr-xactiverecord/test/models/company.rb4
-rw-r--r--activerecord/test/models/developer.rb3
-rw-r--r--activerecord/test/models/person.rb2
-rw-r--r--activerecord/test/models/post.rb7
-rwxr-xr-xactiverecord/test/models/topic.rb1
-rw-r--r--activerecord/test/schema/schema.rb7
-rw-r--r--activeresource/CHANGELOG5
-rw-r--r--activeresource/Rakefile9
-rw-r--r--activeresource/lib/active_resource/base.rb8
-rw-r--r--activeresource/test/base_test.rb48
-rw-r--r--activeresource/test/fixtures/customer.rb3
-rw-r--r--activesupport/CHANGELOG20
-rw-r--r--activesupport/Rakefile14
-rw-r--r--activesupport/lib/active_support.rb6
-rw-r--r--activesupport/lib/active_support/cache.rb16
-rw-r--r--activesupport/lib/active_support/core_ext/array/access.rb45
-rw-r--r--activesupport/lib/active_support/core_ext/array/conversions.rb5
-rw-r--r--activesupport/lib/active_support/core_ext/blank.rb5
-rw-r--r--activesupport/lib/active_support/core_ext/date/calculations.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/enumerable.rb24
-rw-r--r--activesupport/lib/active_support/core_ext/hash/except.rb7
-rw-r--r--activesupport/lib/active_support/core_ext/hash/slice.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/module.rb5
-rw-r--r--activesupport/lib/active_support/core_ext/module/model_naming.rb23
-rw-r--r--activesupport/lib/active_support/core_ext/object/extending.rb17
-rw-r--r--activesupport/lib/active_support/core_ext/string/unicode.rb24
-rw-r--r--activesupport/lib/active_support/dependencies.rb785
-rw-r--r--activesupport/lib/active_support/deprecation.rb32
-rw-r--r--activesupport/lib/active_support/inflections.rb100
-rw-r--r--activesupport/lib/active_support/inflector.rb528
-rw-r--r--activesupport/lib/active_support/ordered_hash.rb15
-rw-r--r--activesupport/lib/active_support/ordered_options.rb26
-rw-r--r--activesupport/lib/active_support/string_inquirer.rb11
-rw-r--r--activesupport/lib/active_support/test_case.rb9
-rw-r--r--activesupport/lib/active_support/testing/performance.rb397
-rw-r--r--activesupport/lib/active_support/testing/setup_and_teardown.rb38
-rw-r--r--activesupport/lib/active_support/values/time_zone.rb694
-rw-r--r--activesupport/lib/active_support/vendor.rb4
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/offset_rationals.rb95
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone_info.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone_info.rb)2
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Algiers.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Algiers.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Cairo.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Cairo.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Casablanca.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Casablanca.rb)2
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Harare.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Harare.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Johannesburg.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Johannesburg.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Monrovia.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Monrovia.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Nairobi.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Nairobi.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Argentina/Buenos_Aires.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Argentina/Buenos_Aires.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Argentina/San_Juan.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Argentina/San_Juan.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Bogota.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Bogota.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Caracas.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Caracas.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Chicago.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Chicago.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Chihuahua.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Chihuahua.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Denver.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Denver.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Godthab.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Godthab.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Guatemala.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Guatemala.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Halifax.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Halifax.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Indiana/Indianapolis.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Indiana/Indianapolis.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Juneau.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Juneau.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/La_Paz.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/La_Paz.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Lima.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Lima.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Los_Angeles.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Los_Angeles.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Mazatlan.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Mazatlan.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Mexico_City.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Mexico_City.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Monterrey.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Monterrey.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/New_York.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/New_York.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Phoenix.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Phoenix.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Regina.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Regina.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Santiago.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Santiago.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/St_Johns.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/St_Johns.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Tijuana.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Tijuana.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Almaty.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Almaty.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Baghdad.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Baghdad.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Baku.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Baku.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Bangkok.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Bangkok.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Chongqing.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Chongqing.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Dhaka.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Dhaka.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Hong_Kong.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Hong_Kong.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Irkutsk.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Irkutsk.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Jakarta.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Jakarta.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Jerusalem.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Jerusalem.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kabul.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kabul.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kamchatka.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kamchatka.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Karachi.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Karachi.rb)2
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Katmandu.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Katmandu.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kolkata.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kolkata.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Krasnoyarsk.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Krasnoyarsk.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kuala_Lumpur.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kuala_Lumpur.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kuwait.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kuwait.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Magadan.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Magadan.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Muscat.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Muscat.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Novosibirsk.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Novosibirsk.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Rangoon.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Rangoon.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Riyadh.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Riyadh.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Seoul.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Seoul.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Shanghai.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Shanghai.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Singapore.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Singapore.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Taipei.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Taipei.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tashkent.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tashkent.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tbilisi.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tbilisi.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tehran.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tehran.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tokyo.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tokyo.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Ulaanbaatar.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Ulaanbaatar.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Urumqi.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Urumqi.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Vladivostok.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Vladivostok.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Yakutsk.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Yakutsk.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Yekaterinburg.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Yekaterinburg.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Yerevan.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Yerevan.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Atlantic/Azores.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Atlantic/Azores.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Atlantic/Cape_Verde.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Atlantic/Cape_Verde.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Atlantic/South_Georgia.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Atlantic/South_Georgia.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Adelaide.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Adelaide.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Brisbane.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Brisbane.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Darwin.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Darwin.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Hobart.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Hobart.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Melbourne.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Melbourne.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Perth.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Perth.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Sydney.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Sydney.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Etc/UTC.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Etc/UTC.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Amsterdam.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Amsterdam.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Athens.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Athens.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Belgrade.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Belgrade.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Berlin.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Berlin.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Bratislava.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Bratislava.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Brussels.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Brussels.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Bucharest.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Bucharest.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Budapest.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Budapest.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Copenhagen.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Copenhagen.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Dublin.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Dublin.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Helsinki.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Helsinki.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Istanbul.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Istanbul.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Kiev.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Kiev.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Lisbon.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Lisbon.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Ljubljana.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Ljubljana.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/London.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/London.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Madrid.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Madrid.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Minsk.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Minsk.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Moscow.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Moscow.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Paris.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Paris.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Prague.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Prague.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Riga.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Riga.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Rome.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Rome.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Sarajevo.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Sarajevo.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Skopje.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Skopje.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Sofia.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Sofia.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Stockholm.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Stockholm.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Tallinn.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Tallinn.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Vienna.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Vienna.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Vilnius.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Vilnius.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Warsaw.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Warsaw.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Zagreb.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Zagreb.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Auckland.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Auckland.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Fiji.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Fiji.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Guam.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Guam.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Honolulu.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Honolulu.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Majuro.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Majuro.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Midway.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Midway.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Noumea.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Noumea.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Pago_Pago.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Pago_Pago.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Port_Moresby.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Port_Moresby.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Tongatapu.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Tongatapu.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/info_timezone.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/info_timezone.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/linked_timezone.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/linked_timezone.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/linked_timezone_info.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/linked_timezone_info.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/offset_rationals.rb95
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/time_or_datetime.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/time_or_datetime.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone.rb)12
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_definition.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_definition.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_info.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_info.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_offset_info.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_offset_info.rb)8
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_period.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_period.rb)0
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_transition_info.rb (renamed from activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_transition_info.rb)4
-rw-r--r--activesupport/test/caching_test.rb6
-rw-r--r--activesupport/test/core_ext/array_ext_test.rb41
-rw-r--r--activesupport/test/core_ext/bigdecimal.rb1
-rw-r--r--activesupport/test/core_ext/blank_test.rb5
-rw-r--r--activesupport/test/core_ext/class_test.rb2
-rw-r--r--activesupport/test/core_ext/date_ext_test.rb17
-rw-r--r--activesupport/test/core_ext/date_time_ext_test.rb24
-rw-r--r--activesupport/test/core_ext/duration_test.rb8
-rw-r--r--activesupport/test/core_ext/enumerable_test.rb11
-rw-r--r--activesupport/test/core_ext/module/model_naming_test.rb19
-rw-r--r--activesupport/test/core_ext/time_ext_test.rb28
-rw-r--r--activesupport/test/core_ext/time_with_zone_test.rb274
-rw-r--r--activesupport/test/dependencies_test.rb240
-rw-r--r--activesupport/test/deprecation_test.rb10
-rw-r--r--activesupport/test/gzip_test.rb7
-rw-r--r--activesupport/test/inflector_test.rb126
-rw-r--r--activesupport/test/ordered_hash_test.rb19
-rw-r--r--activesupport/test/ordered_options_test.rb6
-rw-r--r--activesupport/test/string_inquirer_test.rb15
-rw-r--r--activesupport/test/test_test.rb6
-rw-r--r--activesupport/test/time_zone_test.rb135
-rw-r--r--doc/template/horo.rb613
-rw-r--r--railties/CHANGELOG17
-rw-r--r--railties/Rakefile14
-rw-r--r--railties/bin/about3
-rw-r--r--railties/builtin/rails_info/rails/info_controller.rb2
-rw-r--r--railties/configs/initializers/inflections.rb2
-rw-r--r--railties/configs/initializers/new_rails_defaults.rb10
-rw-r--r--railties/helpers/performance_test.rb8
-rw-r--r--railties/helpers/performance_test_helper.rb6
-rw-r--r--railties/lib/commands/about.rb1
-rw-r--r--railties/lib/initializer.rb35
-rw-r--r--railties/lib/rails/gem_dependency.rb51
-rw-r--r--railties/lib/rails/plugin.rb31
-rw-r--r--railties/lib/rails/plugin/loader.rb4
-rw-r--r--railties/lib/rails/plugin/locator.rb7
-rw-r--r--railties/lib/rails_generator/generators/applications/app/app_generator.rb3
-rw-r--r--railties/lib/rails_generator/generators/components/controller/templates/functional_test.rb2
-rw-r--r--railties/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb4
-rw-r--r--railties/lib/rails_generator/generators/components/mailer/templates/unit_test.rb4
-rw-r--r--railties/lib/rails_generator/generators/components/model/templates/unit_test.rb2
-rw-r--r--railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb2
-rw-r--r--railties/lib/rails_generator/generators/components/performance_test/USAGE8
-rw-r--r--railties/lib/rails_generator/generators/components/performance_test/performance_test_generator.rb16
-rw-r--r--railties/lib/rails_generator/generators/components/performance_test/templates/performance_test.rb8
-rw-r--r--railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb4
-rw-r--r--railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb2
-rw-r--r--railties/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb14
-rw-r--r--railties/lib/tasks/databases.rake12
-rw-r--r--railties/lib/tasks/rails.rb2
-rw-r--r--railties/lib/tasks/testing.rake15
-rw-r--r--railties/lib/test_help.rb3
-rw-r--r--railties/lib/webrick_server.rb13
-rw-r--r--railties/test/fixtures/plugins/default/gemlike/init.rb1
-rw-r--r--railties/test/fixtures/plugins/default/gemlike/lib/gemlike.rb2
-rw-r--r--railties/test/fixtures/plugins/default/gemlike/rails/init.rb7
-rw-r--r--railties/test/gem_dependency_test.rb16
-rw-r--r--railties/test/initializer_test.rb122
-rw-r--r--railties/test/plugin_loader_test.rb22
-rw-r--r--railties/test/plugin_locator_test.rb4
-rw-r--r--railties/test/plugin_test.rb16
-rw-r--r--railties/test/rails_info_controller_test.rb4
364 files changed, 7483 insertions, 6549 deletions
diff --git a/.gitignore b/.gitignore
index 8c5dfb64e1..bba7d5dce8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
debug.log
+doc/rdoc
activeresource/doc
activerecord/doc
actionpack/doc
diff --git a/Rakefile b/Rakefile
index 11d205a725..352fd632d9 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,4 +1,6 @@
require 'rake'
+require 'rake/rdoctask'
+require 'rake/contrib/sshpublisher'
env = %(PKG_BUILD="#{ENV['PKG_BUILD']}") if ENV['PKG_BUILD']
@@ -11,7 +13,7 @@ end
desc 'Run all tests by default'
task :default => :test
-%w(test rdoc package pgem release).each do |task_name|
+%w(test rdoc pgem package release).each do |task_name|
desc "Run #{task_name} task for all projects"
task task_name do
PROJECTS.each do |project|
@@ -19,3 +21,61 @@ task :default => :test
end
end
end
+
+
+desc "Generate documentation for the Rails framework"
+Rake::RDocTask.new do |rdoc|
+ rdoc.rdoc_dir = 'doc/rdoc'
+ rdoc.title = "Ruby on Rails Documentation"
+
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.options << '-A cattr_accessor=object'
+ rdoc.options << '--charset' << 'utf-8'
+
+ rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : './doc/template/horo'
+
+ rdoc.rdoc_files.include('railties/CHANGELOG')
+ rdoc.rdoc_files.include('railties/MIT-LICENSE')
+ rdoc.rdoc_files.include('railties/README')
+ rdoc.rdoc_files.include('railties/lib/{*.rb,commands/*.rb,rails/*.rb,rails_generator/*.rb}')
+
+ rdoc.rdoc_files.include('activerecord/README')
+ rdoc.rdoc_files.include('activerecord/CHANGELOG')
+ rdoc.rdoc_files.include('activerecord/lib/active_record/**/*.rb')
+ rdoc.rdoc_files.exclude('activerecord/lib/active_record/vendor/*')
+
+ rdoc.rdoc_files.include('activeresource/README')
+ rdoc.rdoc_files.include('activeresource/CHANGELOG')
+ rdoc.rdoc_files.include('activeresource/lib/active_resource.rb')
+ rdoc.rdoc_files.include('activeresource/lib/active_resource/*')
+
+ rdoc.rdoc_files.include('actionpack/README')
+ rdoc.rdoc_files.include('actionpack/CHANGELOG')
+ rdoc.rdoc_files.include('actionpack/lib/action_controller/**/*.rb')
+ rdoc.rdoc_files.include('actionpack/lib/action_view/**/*.rb')
+ rdoc.rdoc_files.exclude('actionpack/lib/action_controller/vendor/*')
+
+ rdoc.rdoc_files.include('actionmailer/README')
+ rdoc.rdoc_files.include('actionmailer/CHANGELOG')
+ rdoc.rdoc_files.include('actionmailer/lib/action_mailer/base.rb')
+ rdoc.rdoc_files.exclude('actionmailer/lib/action_mailer/vendor/*')
+
+ rdoc.rdoc_files.include('activesupport/README')
+ rdoc.rdoc_files.include('activesupport/CHANGELOG')
+ rdoc.rdoc_files.include('activesupport/lib/active_support/**/*.rb')
+ rdoc.rdoc_files.exclude('activesupport/lib/active_support/vendor/*')
+end
+
+# Enhance rdoc task to copy referenced images also
+task :rdoc do
+ FileUtils.mkdir_p "doc/rdoc/files/examples/"
+ FileUtils.copy "activerecord/examples/associations.png", "doc/rdoc/files/examples/associations.png"
+end
+
+desc "Publish API docs for Rails as a whole and for each component"
+task :pdoc => :rdoc do
+ Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/api", "doc/rdoc").upload
+ PROJECTS.each do |project|
+ system %(cd #{project} && #{env} #{$0} pdoc)
+ end
+end
diff --git a/actionmailer/Rakefile b/actionmailer/Rakefile
index c09526cbef..612bd27774 100755
--- a/actionmailer/Rakefile
+++ b/actionmailer/Rakefile
@@ -35,7 +35,7 @@ Rake::RDocTask.new { |rdoc|
rdoc.title = "Action Mailer -- Easy email delivery and testing"
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
rdoc.options << '--charset' << 'utf-8'
- rdoc.template = "#{ENV['template']}.rb" if ENV['template']
+ rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
rdoc.rdoc_files.include('README', 'CHANGELOG')
rdoc.rdoc_files.include('lib/action_mailer.rb')
rdoc.rdoc_files.include('lib/action_mailer/*.rb')
@@ -76,12 +76,13 @@ end
desc "Publish the API documentation"
task :pgem => [:package] do
- Rake::SshFilePublisher.new("davidhh@wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
+ Rake::SshFilePublisher.new("wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
+ `ssh wrath.rubyonrails.org './gemupdate.sh'`
end
desc "Publish the API documentation"
task :pdoc => [:rdoc] do
- Rake::SshDirPublisher.new("davidhh@wrath.rubyonrails.org", "public_html/am", "doc").upload
+ Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/am", "doc").upload
end
desc "Publish the release files to RubyForge."
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index e065132107..1518e23dfe 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -426,8 +426,7 @@ module ActionMailer #:nodoc:
end
def template_root=(root)
- write_inheritable_attribute(:template_root, root)
- ActionView::TemplateFinder.process_view_paths(root)
+ write_inheritable_attribute(:template_root, ActionView::ViewLoadPaths.new(Array(root)))
end
end
@@ -530,7 +529,7 @@ module ActionMailer #:nodoc:
end
def render_message(method_name, body)
- render :file => method_name, :body => body
+ render :file => method_name, :body => body, :use_full_path => true
end
def render(opts)
@@ -538,6 +537,7 @@ module ActionMailer #:nodoc:
if opts[:file] && opts[:file] !~ /\//
opts[:file] = "#{mailer_name}/#{opts[:file]}"
end
+ opts[:use_full_path] = true
initialize_template_class(body).render(opts)
end
@@ -546,7 +546,7 @@ module ActionMailer #:nodoc:
end
def initialize_template_class(assigns)
- ActionView::Base.new([template_root], assigns, self)
+ ActionView::Base.new(template_root, assigns, self)
end
def sort_parts(parts, order = [])
diff --git a/actionmailer/test/mail_service_test.rb b/actionmailer/test/mail_service_test.rb
index e5ecb0e254..7f4a8817ca 100755
--- a/actionmailer/test/mail_service_test.rb
+++ b/actionmailer/test/mail_service_test.rb
@@ -942,13 +942,13 @@ end # uses_mocha
class InheritableTemplateRootTest < Test::Unit::TestCase
def test_attr
expected = "#{File.dirname(__FILE__)}/fixtures/path.with.dots"
- assert_equal expected, FunkyPathMailer.template_root
+ assert_equal [expected], FunkyPathMailer.template_root.map(&:to_s)
sub = Class.new(FunkyPathMailer)
sub.template_root = 'test/path'
- assert_equal 'test/path', sub.template_root
- assert_equal expected, FunkyPathMailer.template_root
+ assert_equal ['test/path'], sub.template_root.map(&:to_s)
+ assert_equal [expected], FunkyPathMailer.template_root.map(&:to_s)
end
end
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 9622029362..a28bf66b88 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,3 +1,29 @@
+*Edge*
+
+* Fix polymorphic_url with singleton resources. #461 [Tammer Saleh]
+
+* Replaced TemplateFinder abstraction with ViewLoadPaths [Josh Peek]
+
+* Added block-call style to link_to [Sam Stephenson/DHH]. Example:
+
+ <% link_to(@profile) do %>
+ <strong><%= @profile.name %></strong> -- <span>Check it out!!</span>
+ <% end %>
+
+* Performance: integration test benchmarking and profiling. [Jeremy Kemper]
+
+* Make caching more aware of mime types. Ensure request format is not considered while expiring cache. [Jonathan del Strother]
+
+* Drop ActionController::Base.allow_concurrency flag [Josh Peek]
+
+* More efficient concat and capture helpers. Remove ActionView::Base.erb_variable. [Jeremy Kemper]
+
+* Added page.reload functionality. Resolves #277. [Sean Huber]
+
+* Fixed Request#remote_ip to only raise hell if the HTTP_CLIENT_IP and HTTP_X_FORWARDED_FOR doesn't match (not just if they're both present) [Mark Imbriaco, Bradford Folkens]
+
+* Allow caches_action to accept a layout option [José Valim]
+
* Added Rack processor [Ezra Zygmuntowicz, Josh Peek]
diff --git a/actionpack/Rakefile b/actionpack/Rakefile
index b37f756c1e..1880f21f67 100644
--- a/actionpack/Rakefile
+++ b/actionpack/Rakefile
@@ -49,12 +49,14 @@ Rake::RDocTask.new { |rdoc|
rdoc.title = "Action Pack -- On rails from request to response"
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.options << '--charset' << 'utf-8'
- rdoc.template = "#{ENV['template']}.rb" if ENV['template']
+ rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
if ENV['DOC_FILES']
rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/))
else
rdoc.rdoc_files.include('README', 'RUNNING_UNIT_TESTS', 'CHANGELOG')
- rdoc.rdoc_files.include('lib/**/*.rb')
+ rdoc.rdoc_files.include(Dir['lib/**/*.rb'] -
+ Dir['lib/*/vendor/**/*.rb'])
+ rdoc.rdoc_files.exclude('lib/actionpack.rb')
end
}
@@ -132,13 +134,13 @@ task :update_js => [ :update_scriptaculous ]
desc "Publish the API documentation"
task :pgem => [:package] do
- Rake::SshFilePublisher.new("davidhh@wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
- `ssh davidhh@wrath.rubyonrails.org './gemupdate.sh'`
+ Rake::SshFilePublisher.new("wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
+ `ssh wrath.rubyonrails.org './gemupdate.sh'`
end
desc "Publish the API documentation"
task :pdoc => [:rdoc] do
- Rake::SshDirPublisher.new("davidhh@wrath.rubyonrails.org", "public_html/ap", "doc").upload
+ Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/ap", "doc").upload
end
desc "Publish the release files to RubyForge."
diff --git a/actionpack/lib/action_controller/assertions/response_assertions.rb b/actionpack/lib/action_controller/assertions/response_assertions.rb
index c5fc6c7966..3deda0b45a 100644
--- a/actionpack/lib/action_controller/assertions/response_assertions.rb
+++ b/actionpack/lib/action_controller/assertions/response_assertions.rb
@@ -97,7 +97,7 @@ module ActionController
value['controller'] = value['controller'].to_s
if key == :actual && value['controller'].first != '/' && !value['controller'].include?('/')
new_controller_path = ActionController::Routing.controller_relative_to(value['controller'], @controller.class.controller_path)
- value['controller'] = new_controller_path if value['controller'] != new_controller_path && ActionController::Routing.possible_controllers.include?(new_controller_path)
+ value['controller'] = new_controller_path if value['controller'] != new_controller_path && ActionController::Routing.possible_controllers.include?(new_controller_path) && @response.redirected_to.is_a?(Hash)
end
value['controller'] = value['controller'][1..-1] if value['controller'].first == '/' # strip leading hash
end
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 6222c3205d..817b270feb 100755
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -283,13 +283,6 @@ module ActionController #:nodoc:
@@debug_routes = true
cattr_accessor :debug_routes
- # Indicates to Mongrel or Webrick whether to allow concurrent action
- # processing. Your controller actions and any other code they call must
- # also behave well when called from concurrent threads. Turned off by
- # default.
- @@allow_concurrency = false
- cattr_accessor :allow_concurrency
-
# Modern REST web services often need to submit complex data to the web application.
# The <tt>@@param_parsers</tt> hash lets you register handlers which will process the HTTP body and add parameters to the
# <tt>params</tt> hash. These handlers are invoked for POST and PUT requests.
@@ -428,8 +421,7 @@ module ActionController #:nodoc:
end
def view_paths=(value)
- @view_paths = value
- ActionView::TemplateFinder.process_view_paths(value)
+ @view_paths = ActionView::ViewLoadPaths.new(Array(value)) if value
end
# Adds a view_path to the front of the view_paths array.
@@ -441,8 +433,7 @@ module ActionController #:nodoc:
#
def prepend_view_path(path)
@view_paths = superclass.view_paths.dup if @view_paths.nil?
- view_paths.unshift(*path)
- ActionView::TemplateFinder.process_view_paths(path)
+ @view_paths.unshift(*path)
end
# Adds a view_path to the end of the view_paths array.
@@ -454,8 +445,7 @@ module ActionController #:nodoc:
#
def append_view_path(path)
@view_paths = superclass.view_paths.dup if @view_paths.nil?
- view_paths.push(*path)
- ActionView::TemplateFinder.process_view_paths(path)
+ @view_paths.push(*path)
end
# Replace sensitive parameter data from the request log.
@@ -613,8 +603,8 @@ module ActionController #:nodoc:
#
# This takes the current URL as is and only exchanges the action. In contrast, <tt>url_for :action => 'print'</tt>
# would have slashed-off the path components after the changed action.
- def url_for(options = nil) #:doc:
- case options || {}
+ def url_for(options = {}) #:doc:
+ case options
when String
options
when Hash
@@ -647,11 +637,11 @@ module ActionController #:nodoc:
# View load paths for controller.
def view_paths
- @template.finder.view_paths
+ @template.view_paths
end
def view_paths=(value)
- @template.finder.view_paths = value # Mutex needed
+ @template.view_paths = ViewLoadPaths.new(value)
end
# Adds a view_path to the front of the view_paths array.
@@ -661,7 +651,7 @@ module ActionController #:nodoc:
# self.prepend_view_path(["views/default", "views/custom"])
#
def prepend_view_path(path)
- @template.finder.prepend_view_path(path) # Mutex needed
+ @template.view_paths.unshift(*path)
end
# Adds a view_path to the end of the view_paths array.
@@ -671,7 +661,7 @@ module ActionController #:nodoc:
# self.append_view_path(["views/default", "views/custom"])
#
def append_view_path(path)
- @template.finder.append_view_path(path) # Mutex needed
+ @template.view_paths.push(*path)
end
protected
@@ -1232,7 +1222,7 @@ module ActionController #:nodoc:
end
def template_exists?(template_name = default_template_name)
- @template.finder.file_exists?(template_name)
+ @template.file_exists?(template_name)
end
def template_public?(template_name = default_template_name)
@@ -1240,9 +1230,8 @@ module ActionController #:nodoc:
end
def template_exempt_from_layout?(template_name = default_template_name)
- extension = @template && @template.finder.pick_template_extension(template_name)
- name_with_extension = !template_name.include?('.') && extension ? "#{template_name}.#{extension}" : template_name
- @@exempt_from_layout.any? { |ext| name_with_extension =~ ext }
+ template_name = @template.send(:template_file_from_name, template_name) if @template
+ @@exempt_from_layout.any? { |ext| template_name.to_s =~ ext }
end
def default_template_name(action_name = self.action_name)
diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb
index 1ef9e60a21..65a36f7f98 100644
--- a/actionpack/lib/action_controller/caching/actions.rb
+++ b/actionpack/lib/action_controller/caching/actions.rb
@@ -40,6 +40,8 @@ module ActionController #:nodoc:
# controller.send(:list_url, c.params[:id]) }
# end
#
+ # If you pass :layout => false, it will only cache your action content. It is useful when your layout has dynamic information.
+ #
module Actions
def self.included(base) #:nodoc:
base.extend(ClassMethods)
@@ -54,7 +56,8 @@ module ActionController #:nodoc:
def caches_action(*actions)
return unless cache_configured?
options = actions.extract_options!
- around_filter(ActionCacheFilter.new(:cache_path => options.delete(:cache_path)), {:only => actions}.merge(options))
+ cache_filter = ActionCacheFilter.new(:layout => options.delete(:layout), :cache_path => options.delete(:cache_path))
+ around_filter(cache_filter, {:only => actions}.merge(options))
end
end
@@ -64,10 +67,10 @@ module ActionController #:nodoc:
if options[:action].is_a?(Array)
options[:action].dup.each do |action|
- expire_fragment(ActionCachePath.path_for(self, options.merge({ :action => action })))
+ expire_fragment(ActionCachePath.path_for(self, options.merge({ :action => action }), false))
end
else
- expire_fragment(ActionCachePath.path_for(self, options))
+ expire_fragment(ActionCachePath.path_for(self, options, false))
end
end
@@ -81,7 +84,9 @@ module ActionController #:nodoc:
if cache = controller.read_fragment(cache_path.path)
controller.rendered_action_cache = true
set_content_type!(controller, cache_path.extension)
- controller.send!(:render_for_text, cache)
+ options = { :text => cache }
+ options.merge!(:layout => true) if cache_layout?
+ controller.send!(:render, options)
false
else
controller.action_cache_path = cache_path
@@ -90,7 +95,8 @@ module ActionController #:nodoc:
def after(controller)
return if controller.rendered_action_cache || !caching_allowed(controller)
- controller.write_fragment(controller.action_cache_path.path, controller.response.body)
+ action_content = cache_layout? ? content_for_layout(controller) : controller.response.body
+ controller.write_fragment(controller.action_cache_path.path, action_content)
end
private
@@ -105,22 +111,38 @@ module ActionController #:nodoc:
def caching_allowed(controller)
controller.request.get? && controller.response.headers['Status'].to_i == 200
end
+
+ def cache_layout?
+ @options[:layout] == false
+ end
+
+ def content_for_layout(controller)
+ controller.response.layout && controller.response.template.instance_variable_get('@content_for_layout')
+ end
end
class ActionCachePath
attr_reader :path, :extension
class << self
- def path_for(controller, options)
- new(controller, options).path
+ def path_for(controller, options, infer_extension=true)
+ new(controller, options, infer_extension).path
end
end
-
- def initialize(controller, options = {})
- @extension = extract_extension(controller.request.path)
+
+ # When true, infer_extension will look up the cache path extension from the request's path & format.
+ # This is desirable when reading and writing the cache, but not when expiring the cache - expire_action should expire the same files regardless of the request format.
+ def initialize(controller, options = {}, infer_extension=true)
+ if infer_extension and options.is_a? Hash
+ request_extension = extract_extension(controller.request)
+ options = options.reverse_merge(:format => request_extension)
+ end
path = controller.url_for(options).split('://').last
normalize!(path)
- add_extension!(path, @extension)
+ if infer_extension
+ @extension = request_extension
+ add_extension!(path, @extension)
+ end
@path = URI.unescape(path)
end
@@ -130,13 +152,22 @@ module ActionController #:nodoc:
end
def add_extension!(path, extension)
- path << ".#{extension}" if extension
+ path << ".#{extension}" if extension and !path.ends_with?(extension)
end
-
- def extract_extension(file_path)
+
+ def extract_extension(request)
# Don't want just what comes after the last '.' to accommodate multi part extensions
# such as tar.gz.
- file_path[/^[^.]+\.(.+)$/, 1]
+ extension = request.path[/^[^.]+\.(.+)$/, 1]
+
+ # If there's no extension in the path, check request.format
+ if extension.nil?
+ extension = request.format.to_sym.to_s
+ if extension=='all'
+ extension = nil
+ end
+ end
+ extension
end
end
end
diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/action_controller/caching/fragments.rb
index 578e031a17..45946421fc 100644
--- a/actionpack/lib/action_controller/caching/fragments.rb
+++ b/actionpack/lib/action_controller/caching/fragments.rb
@@ -61,16 +61,18 @@ module ActionController #:nodoc:
end
def fragment_for(block, name = {}, options = nil) #:nodoc:
- unless perform_caching then block.call; return end
-
- buffer = yield
-
- if cache = read_fragment(name, options)
- buffer.concat(cache)
+ if perform_caching
+ buffer = yield
+
+ if cache = read_fragment(name, options)
+ buffer.concat(cache)
+ else
+ pos = buffer.length
+ block.call
+ write_fragment(name, buffer[pos..-1], options)
+ end
else
- pos = buffer.length
block.call
- write_fragment(name, buffer[pos..-1], options)
end
end
diff --git a/actionpack/lib/action_controller/dispatcher.rb b/actionpack/lib/action_controller/dispatcher.rb
index b40f1ba9be..7df987d525 100644
--- a/actionpack/lib/action_controller/dispatcher.rb
+++ b/actionpack/lib/action_controller/dispatcher.rb
@@ -125,7 +125,7 @@ module ActionController
def call(env)
@request = RackRequest.new(env)
- @response = RackResponse.new
+ @response = RackResponse.new(@request)
dispatch
end
@@ -134,14 +134,14 @@ module ActionController
run_callbacks :prepare_dispatch
Routing::Routes.reload
- ActionView::TemplateFinder.reload! unless ActionView::Base.cache_template_loading
+ ActionController::Base.view_paths.reload!
end
# Cleanup the application by clearing out loaded classes so they can
# be reloaded on the next request without restarting the server.
def cleanup_application
ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
- Dependencies.clear
+ ActiveSupport::Dependencies.clear
ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
end
diff --git a/actionpack/lib/action_controller/integration.rb b/actionpack/lib/action_controller/integration.rb
index 12e1b4d493..2a732448f2 100644
--- a/actionpack/lib/action_controller/integration.rb
+++ b/actionpack/lib/action_controller/integration.rb
@@ -1,9 +1,10 @@
-require 'stringio'
-require 'uri'
-
+require 'active_support/test_case'
require 'action_controller/dispatcher'
require 'action_controller/test_process'
+require 'stringio'
+require 'uri'
+
module ActionController
module Integration #:nodoc:
# An integration Session instance represents a set of requests and responses
@@ -580,7 +581,7 @@ EOF
# end
# end
# end
- class IntegrationTest < Test::Unit::TestCase
+ class IntegrationTest < ActiveSupport::TestCase
include Integration::Runner
# Work around a bug in test/unit caused by the default test being named
diff --git a/actionpack/lib/action_controller/layout.rb b/actionpack/lib/action_controller/layout.rb
index b5b59f2d7c..0721f71498 100644
--- a/actionpack/lib/action_controller/layout.rb
+++ b/actionpack/lib/action_controller/layout.rb
@@ -304,7 +304,7 @@ module ActionController #:nodoc:
end
def layout_directory?(layout_name)
- @template.finder.find_template_extension_from_handler(File.join('layouts', layout_name))
+ @template.view_paths.find_template_file_for_path("#{File.join('layouts', layout_name)}.#{@template.template_format}.erb") ? true : false
end
end
end
diff --git a/actionpack/lib/action_controller/performance_test.rb b/actionpack/lib/action_controller/performance_test.rb
new file mode 100644
index 0000000000..85543fffae
--- /dev/null
+++ b/actionpack/lib/action_controller/performance_test.rb
@@ -0,0 +1,16 @@
+require 'action_controller/integration'
+require 'active_support/testing/performance'
+require 'active_support/testing/default'
+
+module ActionController
+ # An integration test that runs a code profiler on your test methods.
+ # Profiling output for combinations of each test method, measurement, and
+ # output format are written to your tmp/performance directory.
+ #
+ # By default, process_time is measured and both flat and graph_html output
+ # formats are written, so you'll have two output files per test method.
+ class PerformanceTest < ActionController::IntegrationTest
+ include ActiveSupport::Testing::Performance
+ include ActiveSupport::Testing::Default
+ end
+end
diff --git a/actionpack/lib/action_controller/polymorphic_routes.rb b/actionpack/lib/action_controller/polymorphic_routes.rb
index 509fa6a08e..7c30bf0778 100644
--- a/actionpack/lib/action_controller/polymorphic_routes.rb
+++ b/actionpack/lib/action_controller/polymorphic_routes.rb
@@ -48,6 +48,9 @@ module ActionController
#
# # calls post_url(post)
# polymorphic_url(post) # => "http://example.com/posts/1"
+ # polymorphic_url([blog, post]) # => "http://example.com/blogs/1/posts/1"
+ # polymorphic_url([:admin, blog, post]) # => "http://example.com/admin/blogs/1/posts/1"
+ # polymorphic_url([user, :blog, post]) # => "http://example.com/users/1/blog/posts/1"
#
# ==== Options
#
@@ -83,8 +86,6 @@ module ActionController
else [ record_or_hash_or_array ]
end
- args << format if format
-
inflection =
case
when options[:action].to_s == "new"
@@ -96,6 +97,9 @@ module ActionController
else
:singular
end
+
+ args.delete_if {|arg| arg.is_a?(Symbol) || arg.is_a?(String)}
+ args << format if format
named_route = build_named_route_call(record_or_hash_or_array, namespace, inflection, options)
send!(named_route, *args)
@@ -136,11 +140,19 @@ module ActionController
else
record = records.pop
route = records.inject("") do |string, parent|
- string << "#{RecordIdentifier.send!("singular_class_name", parent)}_"
+ if parent.is_a?(Symbol) || parent.is_a?(String)
+ string << "#{parent}_"
+ else
+ string << "#{RecordIdentifier.send!("singular_class_name", parent)}_"
+ end
end
end
- route << "#{RecordIdentifier.send!("#{inflection}_class_name", record)}_"
+ if record.is_a?(Symbol) || record.is_a?(String)
+ route << "#{record}_"
+ else
+ route << "#{RecordIdentifier.send!("#{inflection}_class_name", record)}_"
+ end
action_prefix(options) + namespace + route + routing_type(options).to_s
end
@@ -163,16 +175,17 @@ module ActionController
end
end
+ # Remove the first symbols from the array and return the url prefix
+ # implied by those symbols.
def extract_namespace(record_or_hash_or_array)
- returning "" do |namespace|
- if record_or_hash_or_array.is_a?(Array)
- record_or_hash_or_array.delete_if do |record_or_namespace|
- if record_or_namespace.is_a?(String) || record_or_namespace.is_a?(Symbol)
- namespace << "#{record_or_namespace}_"
- end
- end
- end
+ return "" unless record_or_hash_or_array.is_a?(Array)
+
+ namespace_keys = []
+ while (key = record_or_hash_or_array.first) && key.is_a?(String) || key.is_a?(Symbol)
+ namespace_keys << record_or_hash_or_array.shift
end
+
+ namespace_keys.map {|k| "#{k}_"}.join
end
end
end
diff --git a/actionpack/lib/action_controller/rack_process.rb b/actionpack/lib/action_controller/rack_process.rb
index f42212e740..58a0a9280d 100644
--- a/actionpack/lib/action_controller/rack_process.rb
+++ b/actionpack/lib/action_controller/rack_process.rb
@@ -4,6 +4,7 @@ require 'action_controller/session/cookie_store'
module ActionController #:nodoc:
class RackRequest < AbstractRequest #:nodoc:
attr_accessor :env, :session_options
+ attr_reader :cgi
class SessionFixationAttempt < StandardError #:nodoc:
end
@@ -48,21 +49,12 @@ module ActionController #:nodoc:
def cookies
return {} unless @env["HTTP_COOKIE"]
- if @env["rack.request.cookie_string"] == @env["HTTP_COOKIE"]
- @env["rack.request.cookie_hash"]
- else
+ unless @env["rack.request.cookie_string"] == @env["HTTP_COOKIE"]
@env["rack.request.cookie_string"] = @env["HTTP_COOKIE"]
- # According to RFC 2109:
- # If multiple cookies satisfy the criteria above, they are ordered in
- # the Cookie header such that those with more specific Path attributes
- # precede those with less specific. Ordering with respect to other
- # attributes (e.g., Domain) is unspecified.
- @env["rack.request.cookie_hash"] =
- parse_query(@env["rack.request.cookie_string"], ';,').inject({}) { |h, (k,v)|
- h[k] = Array === v ? v.first : v
- h
- }
+ @env["rack.request.cookie_hash"] = CGI::Cookie::parse(@env["rack.request.cookie_string"])
end
+
+ @env["rack.request.cookie_hash"]
end
def host_with_port_without_standard_port_handling
@@ -169,37 +161,13 @@ end_msg
def session_options_with_string_keys
@session_options_with_string_keys ||= DEFAULT_SESSION_OPTIONS.merge(@session_options).stringify_keys
end
-
- # From Rack::Utils
- def parse_query(qs, d = '&;')
- params = {}
- (qs || '').split(/[#{d}] */n).inject(params) { |h,p|
- k, v = unescape(p).split('=',2)
- if cur = params[k]
- if cur.class == Array
- params[k] << v
- else
- params[k] = [cur, v]
- end
- else
- params[k] = v
- end
- }
-
- return params
- end
-
- def unescape(s)
- s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){
- [$1.delete('%')].pack('H*')
- }
- end
end
class RackResponse < AbstractResponse #:nodoc:
attr_accessor :status
- def initialize
+ def initialize(request)
+ @request = request
@writer = lambda { |x| @body << x }
@block = nil
super()
@@ -221,6 +189,8 @@ end_msg
if @body.respond_to?(:call)
@writer = lambda { |x| callback.call(x) }
@body.call(self, self)
+ elsif @body.is_a?(String)
+ @body.each_line(&callback)
else
@body.each(&callback)
end
@@ -270,9 +240,9 @@ end_msg
else cookies << cookie.to_s
end
- @output_cookies.each { |c| cookies << c.to_s } if @output_cookies
+ @request.cgi.output_cookies.each { |c| cookies << c.to_s } if @request.cgi.output_cookies
- headers['Set-Cookie'] = [headers['Set-Cookie'], cookies].compact.join("\n")
+ headers['Set-Cookie'] = [headers['Set-Cookie'], cookies].flatten.compact
end
options.each { |k,v| headers[k] = v }
@@ -283,6 +253,8 @@ end_msg
end
class CGIWrapper < ::CGI
+ attr_reader :output_cookies
+
def initialize(request, *args)
@request = request
@args = *args
diff --git a/actionpack/lib/action_controller/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb
index 643ff7e5f4..742d290ad6 100644
--- a/actionpack/lib/action_controller/record_identifier.rb
+++ b/actionpack/lib/action_controller/record_identifier.rb
@@ -31,18 +31,21 @@ module ActionController
module RecordIdentifier
extend self
+ JOIN = '_'.freeze
+ NEW = 'new'.freeze
+
# Returns plural/singular for a record or class. Example:
#
# partial_path(post) # => "posts/post"
# partial_path(Person) # => "people/person"
# partial_path(Person, "admin/games") # => "admin/people/person"
def partial_path(record_or_class, controller_path = nil)
- klass = class_from_record_or_class(record_or_class)
+ name = model_name_from_record_or_class(record_or_class)
if controller_path && controller_path.include?("/")
- "#{File.dirname(controller_path)}/#{klass.name.tableize}/#{klass.name.demodulize.underscore}"
+ "#{File.dirname(controller_path)}/#{name.partial_path}"
else
- "#{klass.name.tableize}/#{klass.name.demodulize.underscore}"
+ name.partial_path
end
end
@@ -56,21 +59,25 @@ module ActionController
# dom_class(post, :edit) # => "edit_post"
# dom_class(Person, :edit) # => "edit_person"
def dom_class(record_or_class, prefix = nil)
- [ prefix, singular_class_name(record_or_class) ].compact * '_'
+ singular = singular_class_name(record_or_class)
+ prefix ? "#{prefix}#{JOIN}#{singular}" : singular
end
# The DOM id convention is to use the singular form of an object or class with the id following an underscore.
# If no id is found, prefix with "new_" instead. Examples:
#
- # dom_id(Post.new(:id => 45)) # => "post_45"
+ # dom_id(Post.find(45)) # => "post_45"
# dom_id(Post.new) # => "new_post"
#
# If you need to address multiple instances of the same class in the same view, you can prefix the dom_id:
#
- # dom_id(Post.new(:id => 45), :edit) # => "edit_post_45"
+ # dom_id(Post.find(45), :edit) # => "edit_post_45"
def dom_id(record, prefix = nil)
- prefix ||= 'new' unless record.id
- [ prefix, singular_class_name(record), record.id ].compact * '_'
+ if record_id = record.id
+ "#{dom_class(record, prefix)}#{JOIN}#{record_id}"
+ else
+ dom_class(record, prefix || NEW)
+ end
end
# Returns the plural class name of a record or class. Examples:
@@ -78,7 +85,7 @@ module ActionController
# plural_class_name(post) # => "posts"
# plural_class_name(Highrise::Person) # => "highrise_people"
def plural_class_name(record_or_class)
- singular_class_name(record_or_class).pluralize
+ model_name_from_record_or_class(record_or_class).plural
end
# Returns the singular class name of a record or class. Examples:
@@ -86,12 +93,12 @@ module ActionController
# singular_class_name(post) # => "post"
# singular_class_name(Highrise::Person) # => "highrise_person"
def singular_class_name(record_or_class)
- class_from_record_or_class(record_or_class).name.underscore.tr('/', '_')
+ model_name_from_record_or_class(record_or_class).singular
end
private
- def class_from_record_or_class(record_or_class)
- record_or_class.is_a?(Class) ? record_or_class : record_or_class.class
+ def model_name_from_record_or_class(record_or_class)
+ (record_or_class.is_a?(Class) ? record_or_class : record_or_class.class).model_name
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_controller/request.rb b/actionpack/lib/action_controller/request.rb
index 914163a709..38f8e10fe7 100755
--- a/actionpack/lib/action_controller/request.rb
+++ b/actionpack/lib/action_controller/request.rb
@@ -134,14 +134,15 @@ module ActionController
# REMOTE_ADDR is a proxy. HTTP_X_FORWARDED_FOR may be a comma-
# delimited list in the case of multiple chained proxies; the last
# address which is not trusted is the originating IP.
-
def remote_ip
if TRUSTED_PROXIES !~ @env['REMOTE_ADDR']
return @env['REMOTE_ADDR']
end
+ remote_ips = @env['HTTP_X_FORWARDED_FOR'] && @env['HTTP_X_FORWARDED_FOR'].split(',')
+
if @env.include? 'HTTP_CLIENT_IP'
- if @env.include? 'HTTP_X_FORWARDED_FOR'
+ if remote_ips && !remote_ips.include?(@env['HTTP_CLIENT_IP'])
# We don't know which came from the proxy, and which from the user
raise ActionControllerError.new(<<EOM)
IP spoofing attack?!
@@ -149,11 +150,11 @@ HTTP_CLIENT_IP=#{@env['HTTP_CLIENT_IP'].inspect}
HTTP_X_FORWARDED_FOR=#{@env['HTTP_X_FORWARDED_FOR'].inspect}
EOM
end
+
return @env['HTTP_CLIENT_IP']
end
- if @env.include? 'HTTP_X_FORWARDED_FOR' then
- remote_ips = @env['HTTP_X_FORWARDED_FOR'].split(',')
+ if remote_ips
while remote_ips.size > 1 && TRUSTED_PROXIES =~ remote_ips.last.strip
remote_ips.pop
end
diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb
index 79ec2b13b7..b11aa5625b 100644
--- a/actionpack/lib/action_controller/resources.rb
+++ b/actionpack/lib/action_controller/resources.rb
@@ -72,7 +72,7 @@ module ActionController
end
def conditions
- @conditions = @options[:conditions] || {}
+ @conditions ||= @options[:conditions] || {}
end
def path
@@ -80,9 +80,9 @@ module ActionController
end
def new_path
- new_action = self.options[:path_names][:new] if self.options[:path_names]
+ new_action = self.options[:path_names][:new] if self.options[:path_names]
new_action ||= Base.resources_path_names[:new]
- @new_path ||= "#{path}/#{new_action}"
+ @new_path ||= "#{path}/#{new_action}"
end
def member_path
diff --git a/actionpack/lib/action_controller/routing.rb b/actionpack/lib/action_controller/routing.rb
index 6aa266513d..8846dcc504 100644
--- a/actionpack/lib/action_controller/routing.rb
+++ b/actionpack/lib/action_controller/routing.rb
@@ -369,7 +369,7 @@ module ActionController
Routes = RouteSet.new
- ::Inflector.module_eval do
+ 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)) {
diff --git a/actionpack/lib/action_controller/routing/segments.rb b/actionpack/lib/action_controller/routing/segments.rb
index 864e068004..f0ad066bad 100644
--- a/actionpack/lib/action_controller/routing/segments.rb
+++ b/actionpack/lib/action_controller/routing/segments.rb
@@ -249,7 +249,7 @@ module ActionController
end
def extract_value
- "#{local_name} = hash[:#{key}] && hash[:#{key}].collect { |path_component| URI.escape(path_component.to_param, ActionController::Routing::Segment::UNSAFE_PCHAR) }.to_param #{"|| #{default.inspect}" if default}"
+ "#{local_name} = hash[:#{key}] && Array(hash[:#{key}]).collect { |path_component| URI.escape(path_component.to_param, ActionController::Routing::Segment::UNSAFE_PCHAR) }.to_param #{"|| #{default.inspect}" if default}"
end
def default
diff --git a/actionpack/lib/action_controller/templates/rescues/layout.erb b/actionpack/lib/action_controller/templates/rescues/layout.erb
index d38f3e67f9..4a04742e40 100644
--- a/actionpack/lib/action_controller/templates/rescues/layout.erb
+++ b/actionpack/lib/action_controller/templates/rescues/layout.erb
@@ -1,4 +1,4 @@
-<html>
+<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Action Controller: Exception caught</title>
<style>
diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/document.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/document.rb
index 607fd186b9..b8d73c350d 100644
--- a/actionpack/lib/action_controller/vendor/html-scanner/html/document.rb
+++ b/actionpack/lib/action_controller/vendor/html-scanner/html/document.rb
@@ -17,7 +17,7 @@ module HTML #:nodoc:
@root = Node.new(nil)
node_stack = [ @root ]
while token = tokenizer.next
- node = Node.parse(node_stack.last, tokenizer.line, tokenizer.position, token)
+ node = Node.parse(node_stack.last, tokenizer.line, tokenizer.position, token, strict)
node_stack.last.children << node unless node.tag? && node.closing == :close
if node.tag?
diff --git a/actionpack/lib/action_controller/verification.rb b/actionpack/lib/action_controller/verification.rb
index 9f606e7b7c..35b12a7f13 100644
--- a/actionpack/lib/action_controller/verification.rb
+++ b/actionpack/lib/action_controller/verification.rb
@@ -116,7 +116,7 @@ module ActionController #:nodoc:
end
def apply_redirect_to(redirect_to_option) # :nodoc:
- redirect_to_option.is_a?(Symbol) ? self.send!(redirect_to_option) : redirect_to_option
+ (redirect_to_option.is_a?(Symbol) && redirect_to_option != :back) ? self.send!(redirect_to_option) : redirect_to_option
end
def apply_remaining_actions(options) # :nodoc:
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb
index 5f4126e4e9..973020a768 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -21,13 +21,9 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
-require 'action_view/template_handler'
-require 'action_view/template_handlers/compilable'
-require 'action_view/template_handlers/builder'
-require 'action_view/template_handlers/erb'
-require 'action_view/template_handlers/rjs'
-
-require 'action_view/template_finder'
+require 'action_view/template_handlers'
+require 'action_view/template_file'
+require 'action_view/view_load_paths'
require 'action_view/template'
require 'action_view/partial_template'
require 'action_view/inline_template'
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index c236666dcd..91a86470d3 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -1,17 +1,17 @@
module ActionView #:nodoc:
class ActionViewError < StandardError #:nodoc:
end
-
+
class MissingTemplate < ActionViewError #:nodoc:
end
- # Action View templates can be written in three ways. If the template file has a <tt>.erb</tt> (or <tt>.rhtml</tt>) extension then it uses a mixture of ERb
- # (included in Ruby) and HTML. If the template file has a <tt>.builder</tt> (or <tt>.rxml</tt>) extension then Jim Weirich's Builder::XmlMarkup library is used.
+ # Action View templates can be written in three ways. If the template file has a <tt>.erb</tt> (or <tt>.rhtml</tt>) extension then it uses a mixture of ERb
+ # (included in Ruby) and HTML. If the template file has a <tt>.builder</tt> (or <tt>.rxml</tt>) extension then Jim Weirich's Builder::XmlMarkup library is used.
# If the template file has a <tt>.rjs</tt> extension then it will use ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.
- #
+ #
# = ERb
- #
- # You trigger ERb by using embeddings such as <% %>, <% -%>, and <%= %>. The <%= %> tag set is used when you want output. Consider the
+ #
+ # You trigger ERb by using embeddings such as <% %>, <% -%>, and <%= %>. The <%= %> tag set is used when you want output. Consider the
# following loop for names:
#
# <b>Names of all the people</b>
@@ -51,7 +51,7 @@ module ActionView #:nodoc:
# <title><%= @page_title %></title>
#
# == Passing local variables to sub templates
- #
+ #
# You can pass local variables to sub templates by using a hash with the variable names as keys and the objects as values:
#
# <%= render "shared/header", { :headline => "Welcome", :person => person } %>
@@ -77,8 +77,8 @@ module ActionView #:nodoc:
#
# == Builder
#
- # Builder templates are a more programmatic alternative to ERb. They are especially useful for generating XML content. An XmlMarkup object
- # named +xml+ is automatically made available to templates with a <tt>.builder</tt> extension.
+ # Builder templates are a more programmatic alternative to ERb. They are especially useful for generating XML content. An XmlMarkup object
+ # named +xml+ is automatically made available to templates with a <tt>.builder</tt> extension.
#
# Here are some basic examples:
#
@@ -87,7 +87,7 @@ module ActionView #:nodoc:
# xml.a("A Link", "href"=>"http://onestepback.org") # => <a href="http://onestepback.org">A Link</a>
# xml.target("name"=>"compile", "option"=>"fast") # => <target option="fast" name="compile"\>
# # NOTE: order of attributes is not specified.
- #
+ #
# Any method with a block will be treated as an XML markup tag with nested markup in the block. For example, the following:
#
# xml.div {
@@ -111,7 +111,7 @@ module ActionView #:nodoc:
# xml.description "Basecamp: Recent items"
# xml.language "en-us"
# xml.ttl "40"
- #
+ #
# for item in @recent_items
# xml.item do
# xml.title(item_title(item))
@@ -119,7 +119,7 @@ module ActionView #:nodoc:
# xml.pubDate(item_pubDate(item))
# xml.guid(@person.firm.account.url + @recent_items.url(item))
# xml.link(@person.firm.account.url + @recent_items.url(item))
- #
+ #
# xml.tag!("dc:creator", item.author_name) if item_has_creator?(item)
# end
# end
@@ -130,12 +130,12 @@ module ActionView #:nodoc:
#
# == JavaScriptGenerator
#
- # JavaScriptGenerator templates end in <tt>.rjs</tt>. Unlike conventional templates which are used to
- # render the results of an action, these templates generate instructions on how to modify an already rendered page. This makes it easy to
- # modify multiple elements on your page in one declarative Ajax response. Actions with these templates are called in the background with Ajax
+ # JavaScriptGenerator templates end in <tt>.rjs</tt>. Unlike conventional templates which are used to
+ # render the results of an action, these templates generate instructions on how to modify an already rendered page. This makes it easy to
+ # modify multiple elements on your page in one declarative Ajax response. Actions with these templates are called in the background with Ajax
# and make updates to the page where the request originated from.
- #
- # An instance of the JavaScriptGenerator object named +page+ is automatically made available to your template, which is implicitly wrapped in an ActionView::Helpers::PrototypeHelper#update_page block.
+ #
+ # An instance of the JavaScriptGenerator object named +page+ is automatically made available to your template, which is implicitly wrapped in an ActionView::Helpers::PrototypeHelper#update_page block.
#
# When an <tt>.rjs</tt> action is called with +link_to_remote+, the generated JavaScript is automatically evaluated. Example:
#
@@ -145,48 +145,45 @@ module ActionView #:nodoc:
#
# page.replace_html 'sidebar', :partial => 'sidebar'
# page.remove "person-#{@person.id}"
- # page.visual_effect :highlight, 'user-list'
+ # page.visual_effect :highlight, 'user-list'
#
# This refreshes the sidebar, removes a person element and highlights the user list.
- #
+ #
# See the ActionView::Helpers::PrototypeHelper::GeneratorMethods documentation for more details.
class Base
include ERB::Util
- attr_reader :finder
attr_accessor :base_path, :assigns, :template_extension, :first_render
attr_accessor :controller
-
+
attr_writer :template_format
attr_accessor :current_render_extension
- # Specify trim mode for the ERB compiler. Defaults to '-'.
- # See ERb documentation for suitable values.
- @@erb_trim_mode = '-'
- cattr_accessor :erb_trim_mode
+ attr_accessor :output_buffer
+
+ class << self
+ delegate :erb_trim_mode=, :to => 'ActionView::TemplateHandlers::ERB'
+ end
# Specify whether file modification times should be checked to see if a template needs recompilation
@@cache_template_loading = false
cattr_accessor :cache_template_loading
-
+
def self.cache_template_extensions=(*args)
ActiveSupport::Deprecation.warn("config.action_view.cache_template_extensions option has been deprecated and has no effect. " <<
"Please remove it from your config files.", caller)
end
# Specify whether RJS responses should be wrapped in a try/catch block
- # that alert()s the caught exception (and then re-raises it).
+ # that alert()s the caught exception (and then re-raises it).
@@debug_rjs = false
cattr_accessor :debug_rjs
-
- @@erb_variable = '_erbout'
- cattr_accessor :erb_variable
-
+
attr_internal :request
delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers,
- :flash, :logger, :action_name, :to => :controller
-
+ :flash, :logger, :action_name, :controller_name, :to => :controller
+
module CompiledTemplates #:nodoc:
# holds compiled template code
end
@@ -222,11 +219,17 @@ module ActionView #:nodoc:
@assigns = assigns_for_first_render
@assigns_added = nil
@controller = controller
- @finder = TemplateFinder.new(self, view_paths)
+ self.view_paths = view_paths
+ end
+
+ attr_reader :view_paths
+
+ def view_paths=(paths)
+ @view_paths = ViewLoadPaths.new(Array(paths))
end
- # Renders the template present at <tt>template_path</tt>. If <tt>use_full_path</tt> is set to true,
- # it's relative to the view_paths array, otherwise it's absolute. The hash in <tt>local_assigns</tt>
+ # Renders the template present at <tt>template_path</tt>. If <tt>use_full_path</tt> is set to true,
+ # it's relative to the view_paths array, otherwise it's absolute. The hash in <tt>local_assigns</tt>
# is made available as local variables.
def render_file(template_path, use_full_path = true, local_assigns = {}) #:nodoc:
if defined?(ActionMailer) && defined?(ActionMailer::Base) && controller.is_a?(ActionMailer::Base) && !template_path.include?("/")
@@ -241,11 +244,11 @@ If you are rendering a subtemplate, you must now use controller-like partial syn
render :partial => 'signup' # no mailer_name necessary
END_ERROR
end
-
+
Template.new(self, template_path, use_full_path, local_assigns).render_template
end
-
- # Renders the template present at <tt>template_path</tt> (relative to the view_paths array).
+
+ # Renders the template present at <tt>template_path</tt> (relative to the view_paths array).
# The hash in <tt>local_assigns</tt> is made available as local variables.
def render(options = {}, local_assigns = {}, &block) #:nodoc:
if options.is_a?(String)
@@ -253,12 +256,13 @@ If you are rendering a subtemplate, you must now use controller-like partial syn
elsif options == :update
update_page(&block)
elsif options.is_a?(Hash)
+ use_full_path = options[:use_full_path]
options = options.reverse_merge(:locals => {}, :use_full_path => true)
if partial_layout = options.delete(:layout)
if block_given?
- wrap_content_for_layout capture(&block) do
- concat(render(options.merge(:partial => partial_layout)), block.binding)
+ wrap_content_for_layout capture(&block) do
+ concat(render(options.merge(:partial => partial_layout)))
end
else
wrap_content_for_layout render(options) do
@@ -266,7 +270,7 @@ If you are rendering a subtemplate, you must now use controller-like partial syn
end
end
elsif options[:file]
- render_file(options[:file], options[:use_full_path], options[:locals])
+ render_file(options[:file], use_full_path || false, options[:locals])
elsif options[:partial] && options[:collection]
render_partial_collection(options[:partial], options[:collection], options[:spacer_template], options[:locals])
elsif options[:partial]
@@ -314,11 +318,16 @@ If you are rendering a subtemplate, you must now use controller-like partial syn
end
end
+ def file_exists?(template_path)
+ view_paths.template_exists?(template_file_from_name(template_path))
+ end
+
private
def wrap_content_for_layout(content)
- original_content_for_layout = @content_for_layout
- @content_for_layout = content
- returning(yield) { @content_for_layout = original_content_for_layout }
+ original_content_for_layout, @content_for_layout = @content_for_layout, content
+ yield
+ ensure
+ @content_for_layout = original_content_for_layout
end
# Evaluate the local assigns and pushes them to the view.
@@ -333,11 +342,43 @@ If you are rendering a subtemplate, you must now use controller-like partial syn
def assign_variables_from_controller
@assigns.each { |key, value| instance_variable_set("@#{key}", value) }
end
-
+
def execute(template)
send(template.method, template.locals) do |*names|
instance_variable_get "@content_for_#{names.first || 'layout'}"
- end
+ end
+ end
+
+ def template_file_from_name(template_name)
+ template_name = TemplateFile.from_path(template_name)
+ pick_template_extension(template_name) unless template_name.extension
+ end
+
+ # Gets the extension for an existing template with the given template_path.
+ # Returns the format with the extension if that template exists.
+ #
+ # pick_template_extension('users/show')
+ # # => 'html.erb'
+ #
+ # pick_template_extension('users/legacy')
+ # # => "rhtml"
+ #
+ def pick_template_extension(file)
+ if f = self.view_paths.find_template_file_for_path(file.dup_with_extension(template_format)) || file_from_first_render(file)
+ f
+ elsif template_format == :js && f = self.view_paths.find_template_file_for_path(file.dup_with_extension(:html))
+ @template_format = :html
+ f
+ else
+ nil
+ end
+ end
+
+ # Determine the template extension from the <tt>@first_render</tt> filename
+ def file_from_first_render(file)
+ if extension = File.basename(@first_render.to_s)[/^[^.]+\.(.+)$/, 1]
+ file.dup_with_extension(extension)
+ end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb
index 9ea06568cf..990c30b90d 100644
--- a/actionpack/lib/action_view/helpers/capture_helper.rb
+++ b/actionpack/lib/action_view/helpers/capture_helper.rb
@@ -31,20 +31,16 @@ module ActionView
# </body></html>
#
def capture(*args, &block)
- # execute the block
- begin
- buffer = eval(ActionView::Base.erb_variable, block.binding)
- rescue
- buffer = nil
- end
-
- if buffer.nil?
- capture_block(*args, &block).to_s
+ # Return captured buffer in erb.
+ if block_called_from_erb?(block)
+ with_output_buffer { block.call(*args) }
+
+ # Return block result otherwise, but protect buffer also.
else
- capture_erb_with_buffer(buffer, *args, &block).to_s
+ with_output_buffer { return block.call(*args) }
end
end
-
+
# Calling content_for stores a block of markup in an identifier for later use.
# You can make subsequent calls to the stored content in other templates or the layout
# by passing the identifier as an argument to <tt>yield</tt>.
@@ -121,40 +117,19 @@ module ActionView
# named <tt>@content_for_#{name_of_the_content_block}</tt>. The preferred usage is now
# <tt><%= yield :footer %></tt>.
def content_for(name, content = nil, &block)
- existing_content_for = instance_variable_get("@content_for_#{name}").to_s
- new_content_for = existing_content_for + (block_given? ? capture(&block) : content)
- instance_variable_set("@content_for_#{name}", new_content_for)
+ ivar = "@content_for_#{name}"
+ content = capture(&block) if block_given?
+ instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{content}")
+ nil
end
private
- def capture_block(*args, &block)
- block.call(*args)
- end
-
- def capture_erb(*args, &block)
- buffer = eval(ActionView::Base.erb_variable, block.binding)
- capture_erb_with_buffer(buffer, *args, &block)
- end
-
- def capture_erb_with_buffer(buffer, *args, &block)
- pos = buffer.length
- block.call(*args)
-
- # extract the block
- data = buffer[pos..-1]
-
- # replace it in the original with empty string
- buffer[pos..-1] = ''
-
- data
- end
-
- def erb_content_for(name, &block)
- eval "@content_for_#{name} = (@content_for_#{name} || '') + capture_erb(&block)"
- end
-
- def block_content_for(name, &block)
- eval "@content_for_#{name} = (@content_for_#{name} || '') + capture_block(&block)"
+ def with_output_buffer(buf = '')
+ self.output_buffer, old_buffer = buf, output_buffer
+ yield
+ output_buffer
+ ensure
+ self.output_buffer = old_buffer
end
end
end
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index af43397cb7..f952ada691 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -249,9 +249,9 @@ module ActionView
args.unshift object
end
- concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {}), proc.binding)
+ concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {}))
fields_for(object_name, *(args << options), &proc)
- concat('</form>', proc.binding)
+ concat('</form>')
end
def apply_form_for_options!(object_or_array, options) #:nodoc:
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index c0cba24be4..f22c12c9ad 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -306,7 +306,7 @@ module ActionView
#
# NOTE: Only the option tags are returned, you have to wrap this call in
# a regular HTML select tag.
- def time_zone_options_for_select(selected = nil, priority_zones = nil, model = TimeZone)
+ def time_zone_options_for_select(selected = nil, priority_zones = nil, model = ::ActiveSupport::TimeZone)
zone_options = ""
zones = model.all
@@ -419,7 +419,7 @@ module ActionView
value = value(object)
content_tag("select",
add_options(
- time_zone_options_for_select(value || options[:default], priority_zones, options[:model] || TimeZone),
+ time_zone_options_for_select(value || options[:default], priority_zones, options[:model] || ActiveSupport::TimeZone),
options, value
), html_options
)
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index ca58f4ba26..ccebec3692 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -6,7 +6,7 @@ module ActionView
# Provides a number of methods for creating form tags that doesn't rely on an Active Record object assigned to the template like
# FormHelper does. Instead, you provide the names and values manually.
#
- # NOTE: The HTML options <tt>disabled</tt>, <tt>readonly</tt>, and <tt>multiple</tt> can all be treated as booleans. So specifying
+ # NOTE: The HTML options <tt>disabled</tt>, <tt>readonly</tt>, and <tt>multiple</tt> can all be treated as booleans. So specifying
# <tt>:disabled => true</tt> will give <tt>disabled="disabled"</tt>.
module FormTagHelper
# Starts a form tag that points the action to an url configured with <tt>url_for_options</tt> just like
@@ -20,15 +20,15 @@ module ActionView
# * A list of parameters to feed to the URL the form will be posted to.
#
# ==== Examples
- # form_tag('/posts')
+ # form_tag('/posts')
# # => <form action="/posts" method="post">
#
- # form_tag('/posts/1', :method => :put)
+ # form_tag('/posts/1', :method => :put)
# # => <form action="/posts/1" method="put">
#
- # form_tag('/upload', :multipart => true)
+ # form_tag('/upload', :multipart => true)
# # => <form action="/upload" method="post" enctype="multipart/form-data">
- #
+ #
# <% form_tag '/posts' do -%>
# <div><%= submit_tag 'Save' %></div>
# <% end -%>
@@ -88,7 +88,7 @@ module ActionView
# * <tt>:size</tt> - The number of visible characters that will fit in the input.
# * <tt>:maxlength</tt> - The maximum number of characters that the browser will allow the user to enter.
# * Any other key creates standard HTML attributes for the tag.
- #
+ #
# ==== Examples
# text_field_tag 'name'
# # => <input id="name" name="name" type="text" />
@@ -146,13 +146,13 @@ module ActionView
# # => <input id="token" name="token" type="hidden" value="VUBJKB23UIVI1UU1VOBVI@" />
#
# hidden_field_tag 'collected_input', '', :onchange => "alert('Input collected!')"
- # # => <input id="collected_input" name="collected_input" onchange="alert('Input collected!')"
+ # # => <input id="collected_input" name="collected_input" onchange="alert('Input collected!')"
# # type="hidden" value="" />
def hidden_field_tag(name, value = nil, options = {})
text_field_tag(name, value, options.stringify_keys.update("type" => "hidden"))
end
- # Creates a file upload field. If you are using file uploads then you will also need
+ # Creates a file upload field. If you are using file uploads then you will also need
# to set the multipart option for the form tag:
#
# <%= form_tag { :action => "post" }, { :multipart => true } %>
@@ -160,7 +160,7 @@ module ActionView
# <%= submit_tag %>
# <%= end_form_tag %>
#
- # The specified URL will then be passed a File object containing the selected file, or if the field
+ # The specified URL will then be passed a File object containing the selected file, or if the field
# was left blank, a StringIO object.
#
# ==== Options
@@ -181,7 +181,7 @@ module ActionView
# # => <input id="resume" name="resume" type="file" value="~/resume.doc" />
#
# file_field_tag 'user_pic', :accept => 'image/png,image/gif,image/jpeg'
- # # => <input accept="image/png,image/gif,image/jpeg" id="user_pic" name="user_pic" type="file" />
+ # # => <input accept="image/png,image/gif,image/jpeg" id="user_pic" name="user_pic" type="file" />
#
# file_field_tag 'file', :accept => 'text/html', :class => 'upload', :value => 'index.html'
# # => <input accept="text/html" class="upload" id="file" name="file" type="file" value="index.html" />
@@ -286,7 +286,7 @@ module ActionView
tag :input, html_options
end
- # Creates a radio button; use groups of radio buttons named the same to allow users to
+ # Creates a radio button; use groups of radio buttons named the same to allow users to
# select from a group of options.
#
# ==== Options
@@ -313,14 +313,14 @@ module ActionView
tag :input, html_options
end
- # Creates a submit button with the text <tt>value</tt> as the caption.
+ # Creates a submit button with the text <tt>value</tt> as the caption.
#
# ==== Options
# * <tt>:confirm => 'question?'</tt> - This will add a JavaScript confirm
# prompt with the question specified. If the user accepts, the form is
# processed normally, otherwise no action is taken.
# * <tt>:disabled</tt> - If true, the user will not be able to use this input.
- # * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a disabled version
+ # * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a disabled version
# of the submit button when the form is submitted.
# * Any other key creates standard HTML options for the tag.
#
@@ -335,7 +335,7 @@ module ActionView
# # => <input disabled="disabled" name="commit" type="submit" value="Save edits" />
#
# submit_tag "Complete sale", :disable_with => "Please wait..."
- # # => <input name="commit" onclick="this.disabled=true;this.value='Please wait...';this.form.submit();"
+ # # => <input name="commit" onclick="this.disabled=true;this.value='Please wait...';this.form.submit();"
# # type="submit" value="Complete sale" />
#
# submit_tag nil, :class => "form_submit"
@@ -346,7 +346,7 @@ module ActionView
# # name="commit" type="submit" value="Edit" />
def submit_tag(value = "Save changes", options = {})
options.stringify_keys!
-
+
if disable_with = options.delete("disable_with")
options["onclick"] = [
"this.setAttribute('originalValue', this.value)",
@@ -358,15 +358,15 @@ module ActionView
"return result;",
].join(";")
end
-
+
if confirm = options.delete("confirm")
options["onclick"] ||= ''
options["onclick"] += "return #{confirm_javascript_function(confirm)};"
end
-
+
tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options.stringify_keys)
end
-
+
# Displays an image which when clicked will submit the form.
#
# <tt>source</tt> is passed to AssetTagHelper#image_path
@@ -407,12 +407,12 @@ module ActionView
# # => <fieldset><legend>Your details</legend><p><input id="name" name="name" type="text" /></p></fieldset>
def field_set_tag(legend = nil, &block)
content = capture(&block)
- concat(tag(:fieldset, {}, true), block.binding)
- concat(content_tag(:legend, legend), block.binding) unless legend.blank?
- concat(content, block.binding)
- concat("</fieldset>", block.binding)
+ concat(tag(:fieldset, {}, true))
+ concat(content_tag(:legend, legend)) unless legend.blank?
+ concat(content)
+ concat("</fieldset>")
end
-
+
private
def html_options_for_form(url_for_options, options, *parameters_for_url)
returning options.stringify_keys do |html_options|
@@ -420,7 +420,7 @@ module ActionView
html_options["action"] = url_for(url_for_options, *parameters_for_url)
end
end
-
+
def extra_tags_for_form(html_options)
case method = html_options.delete("method").to_s
when /^get$/i # must be case-insentive, but can't use downcase as might be nil
@@ -434,17 +434,17 @@ module ActionView
content_tag(:div, tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag, :style => 'margin:0;padding:0')
end
end
-
+
def form_tag_html(html_options)
extra_tags = extra_tags_for_form(html_options)
tag(:form, html_options, true) + extra_tags
end
-
+
def form_tag_in_block(html_options, &block)
content = capture(&block)
- concat(form_tag_html(html_options), block.binding)
- concat(content, block.binding)
- concat("</form>", block.binding)
+ concat(form_tag_html(html_options))
+ concat(content)
+ concat("</form>")
end
def token_tag
diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb
index ed931e064f..00092adc87 100644
--- a/actionpack/lib/action_view/helpers/javascript_helper.rb
+++ b/actionpack/lib/action_view/helpers/javascript_helper.rb
@@ -4,10 +4,10 @@ require 'action_view/helpers/prototype_helper'
module ActionView
module Helpers
# Provides functionality for working with JavaScript in your views.
- #
+ #
# == Ajax, controls and visual effects
- #
- # * For information on using Ajax, see
+ #
+ # * For information on using Ajax, see
# ActionView::Helpers::PrototypeHelper.
# * For information on using controls and visual effects, see
# ActionView::Helpers::ScriptaculousHelper.
@@ -20,22 +20,22 @@ module ActionView
# and ActionView::Helpers::ScriptaculousHelper), you must do one of the
# following:
#
- # * Use <tt><%= javascript_include_tag :defaults %></tt> in the HEAD
- # section of your page (recommended): This function will return
+ # * Use <tt><%= javascript_include_tag :defaults %></tt> in the HEAD
+ # section of your page (recommended): This function will return
# references to the JavaScript files created by the +rails+ command in
# your <tt>public/javascripts</tt> directory. Using it is recommended as
- # the browser can then cache the libraries instead of fetching all the
+ # the browser can then cache the libraries instead of fetching all the
# functions anew on every request.
- # * Use <tt><%= javascript_include_tag 'prototype' %></tt>: As above, but
+ # * Use <tt><%= javascript_include_tag 'prototype' %></tt>: As above, but
# will only include the Prototype core library, which means you are able
- # to use all basic AJAX functionality. For the Scriptaculous-based
- # JavaScript helpers, like visual effects, autocompletion, drag and drop
+ # to use all basic AJAX functionality. For the Scriptaculous-based
+ # JavaScript helpers, like visual effects, autocompletion, drag and drop
# and so on, you should use the method described above.
# * Use <tt><%= define_javascript_functions %></tt>: this will copy all the
# JavaScript support functions within a single script block. Not
# recommended.
#
- # For documentation on +javascript_include_tag+ see
+ # For documentation on +javascript_include_tag+ see
# ActionView::Helpers::AssetTagHelper.
module JavaScriptHelper
unless const_defined? :JAVASCRIPT_PATH
@@ -53,7 +53,7 @@ module ActionView
#
# The +function+ argument can be omitted in favor of an +update_page+
# block, which evaluates to a string when the template is rendered
- # (instead of making an Ajax request first).
+ # (instead of making an Ajax request first).
#
# The +html_options+ will accept a hash of html attributes for the link tag. Some examples are :class => "nav_button", :id => "articles_nav_button"
#
@@ -79,28 +79,23 @@ module ActionView
# <a href="#" id="more_link" onclick="try {
# $(&quot;details&quot;).visualEffect(&quot;toggle_blind&quot;);
# $(&quot;more_link&quot;).update(&quot;Show me less&quot;);
- # }
- # catch (e) {
- # alert('RJS error:\n\n' + e.toString());
+ # }
+ # catch (e) {
+ # alert('RJS error:\n\n' + e.toString());
# alert('$(\&quot;details\&quot;).visualEffect(\&quot;toggle_blind\&quot;);
# \n$(\&quot;more_link\&quot;).update(\&quot;Show me less\&quot;);');
- # throw e
+ # throw e
# };
# return false;">Show me more</a>
#
def link_to_function(name, *args, &block)
- html_options = args.extract_options!
- function = args[0] || ''
-
- html_options.symbolize_keys!
- function = update_page(&block) if block_given?
- content_tag(
- "a", name,
- html_options.merge({
- :href => html_options[:href] || "#",
- :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function}; return false;"
- })
- )
+ html_options = args.extract_options!.symbolize_keys
+
+ function = block_given? ? update_page(&block) : args[0] || ''
+ onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function}; return false;"
+ href = html_options[:href] || '#'
+
+ content_tag(:a, name, html_options.merge(:href => href, :onclick => onclick))
end
# Returns a button with the given +name+ text that'll trigger a JavaScript +function+ using the
@@ -112,7 +107,7 @@ module ActionView
#
# The +function+ argument can be omitted in favor of an +update_page+
# block, which evaluates to a string when the template is rendered
- # (instead of making an Ajax request first).
+ # (instead of making an Ajax request first).
#
# The +html_options+ will accept a hash of html attributes for the link tag. Some examples are :class => "nav_button", :id => "articles_nav_button"
#
@@ -128,45 +123,56 @@ module ActionView
# page[:details].visual_effect :toggle_slide
# end
def button_to_function(name, *args, &block)
- html_options = args.extract_options!
- function = args[0] || ''
-
- html_options.symbolize_keys!
- function = update_page(&block) if block_given?
- tag(:input, html_options.merge({
- :type => "button", :value => name,
- :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
- }))
+ html_options = args.extract_options!.symbolize_keys
+
+ function = block_given? ? update_page(&block) : args[0] || ''
+ onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function};"
+
+ tag(:input, html_options.merge(:type => 'button', :value => name, :onclick => onclick))
end
- # Includes the Action Pack JavaScript libraries inside a single <script>
+ # Includes the Action Pack JavaScript libraries inside a single <script>
# tag. The function first includes prototype.js and then its core extensions,
# (determined by filenames starting with "prototype").
# Afterwards, any additional scripts will be included in undefined order.
#
# Note: The recommended approach is to copy the contents of
# lib/action_view/helpers/javascripts/ into your application's
- # public/javascripts/ directory, and use +javascript_include_tag+ to
+ # public/javascripts/ directory, and use +javascript_include_tag+ to
# create remote <script> links.
def define_javascript_functions
javascript = "<script type=\"#{Mime::JS}\">"
-
- # load prototype.js and its extensions first
+
+ # load prototype.js and its extensions first
prototype_libs = Dir.glob(File.join(JAVASCRIPT_PATH, 'prototype*')).sort.reverse
- prototype_libs.each do |filename|
+ prototype_libs.each do |filename|
javascript << "\n" << IO.read(filename)
end
-
+
# load other libraries
- (Dir.glob(File.join(JAVASCRIPT_PATH, '*')) - prototype_libs).each do |filename|
+ (Dir.glob(File.join(JAVASCRIPT_PATH, '*')) - prototype_libs).each do |filename|
javascript << "\n" << IO.read(filename)
end
javascript << '</script>'
end
+
+ JS_ESCAPE_MAP = {
+ '\\' => '\\\\',
+ '</' => '<\/',
+ "\r\n" => '\n',
+ "\n" => '\n',
+ "\r" => '\n',
+ '"' => '\\"',
+ "'" => "\\'" }
+
# Escape carrier returns and single and double quotes for JavaScript segments.
def escape_javascript(javascript)
- (javascript || '').gsub('\\','\0\0').gsub('</','<\/').gsub(/\r\n|\n|\r/, "\\n").gsub(/["']/) { |m| "\\#{m}" }
+ if javascript
+ javascript.gsub(/(\\|<\/|\r\n|[\n\r"'])/) { JS_ESCAPE_MAP[$1] }
+ else
+ ''
+ end
end
# Returns a JavaScript tag with the +content+ inside. Example:
@@ -180,7 +186,7 @@ module ActionView
# </script>
#
# +html_options+ may be a hash of attributes for the <script> tag. Example:
- # javascript_tag "alert('All is good')", :defer => 'defer'
+ # javascript_tag "alert('All is good')", :defer => 'defer'
# # => <script defer="defer" type="text/javascript">alert('All is good')</script>
#
# Instead of passing the content as an argument, you can also use a block
@@ -189,46 +195,45 @@ module ActionView
# alert('All is good')
# <% end -%>
def javascript_tag(content_or_options_with_block = nil, html_options = {}, &block)
- if block_given?
- html_options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash)
- content = capture(&block)
- else
- content = content_or_options_with_block
- end
+ content =
+ if block_given?
+ html_options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash)
+ capture(&block)
+ else
+ content_or_options_with_block
+ end
+
+ tag = content_tag(:script, javascript_cdata_section(content), html_options.merge(:type => Mime::JS))
- javascript_tag = content_tag("script", javascript_cdata_section(content), html_options.merge(:type => Mime::JS))
-
- if block_given? && block_is_within_action_view?(block)
- concat(javascript_tag, block.binding)
+ if block_called_from_erb?(block)
+ concat(tag)
else
- javascript_tag
+ tag
end
end
def javascript_cdata_section(content) #:nodoc:
"\n//#{cdata_section("\n#{content}\n//")}\n"
end
-
+
protected
def options_for_javascript(options)
- '{' + options.map {|k, v| "#{k}:#{v}"}.sort.join(', ') + '}'
+ if options.empty?
+ '{}'
+ else
+ "{#{options.keys.map { |k| "#{k}:#{options[k]}" }.sort.join(', ')}}"
+ end
end
-
+
def array_or_string_for_javascript(option)
- js_option = if option.kind_of?(Array)
+ if option.kind_of?(Array)
"['#{option.join('\',\'')}']"
elsif !option.nil?
"'#{option}'"
end
- js_option
- end
-
- private
- def block_is_within_action_view?(block)
- eval("defined? _erbout", block.binding)
end
end
-
+
JavascriptHelper = JavaScriptHelper unless const_defined? :JavascriptHelper
end
end
diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb
index c731824f18..9f6e550c09 100644
--- a/actionpack/lib/action_view/helpers/prototype_helper.rb
+++ b/actionpack/lib/action_view/helpers/prototype_helper.rb
@@ -382,9 +382,9 @@ module ActionView
args.unshift object
end
- concat(form_remote_tag(options), proc.binding)
+ concat(form_remote_tag(options))
fields_for(object_name, *(args << options), &proc)
- concat('</form>', proc.binding)
+ concat('</form>')
end
alias_method :form_remote_for, :remote_form_for
@@ -868,6 +868,16 @@ module ActionView
record "window.location.href = #{url.inspect}"
end
+ # Reloads the browser's current +location+ using JavaScript
+ #
+ # Examples:
+ #
+ # # Generates: window.location.reload();
+ # page.reload
+ def reload
+ record 'window.location.reload()'
+ end
+
# Calls the JavaScript +function+, optionally with the given +arguments+.
#
# If a block is given, the block will be passed to a new JavaScriptGenerator;
diff --git a/actionpack/lib/action_view/helpers/record_tag_helper.rb b/actionpack/lib/action_view/helpers/record_tag_helper.rb
index 66c596f3a9..9bb235175e 100644
--- a/actionpack/lib/action_view/helpers/record_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/record_tag_helper.rb
@@ -51,9 +51,8 @@ module ActionView
prefix = args.first.is_a?(Hash) ? nil : args.shift
options = args.first.is_a?(Hash) ? args.shift : {}
concat content_tag(tag_name, capture(&block),
- options.merge({ :class => "#{dom_class(record)} #{options[:class]}".strip, :id => dom_id(record, prefix) })),
- block.binding
+ options.merge({ :class => "#{dom_class(record)} #{options[:class]}".strip, :id => dom_id(record, prefix) }))
end
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb
index 999cbfb52a..aeafd3906d 100644
--- a/actionpack/lib/action_view/helpers/tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/tag_helper.rb
@@ -1,5 +1,6 @@
require 'cgi'
require 'erb'
+require 'set'
module ActionView
module Helpers #:nodoc:
@@ -8,16 +9,17 @@ module ActionView
module TagHelper
include ERB::Util
- BOOLEAN_ATTRIBUTES = Set.new(%w(disabled readonly multiple))
+ BOOLEAN_ATTRIBUTES = %w(disabled readonly multiple).to_set
+ BOOLEAN_ATTRIBUTES.merge(BOOLEAN_ATTRIBUTES.map(&:to_sym))
- # Returns an empty HTML tag of type +name+ which by default is XHTML
- # compliant. Set +open+ to true to create an open tag compatible
- # with HTML 4.0 and below. Add HTML attributes by passing an attributes
+ # Returns an empty HTML tag of type +name+ which by default is XHTML
+ # compliant. Set +open+ to true to create an open tag compatible
+ # with HTML 4.0 and below. Add HTML attributes by passing an attributes
# hash to +options+. Set +escape+ to false to disable attribute value
# escaping.
#
# ==== Options
- # The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and
+ # The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and
# <tt>readonly</tt>), which you can give a value of true in the +options+ hash. You can use
# symbols or strings for the attribute names.
#
@@ -28,7 +30,7 @@ module ActionView
# tag("br", nil, true)
# # => <br>
#
- # tag("input", { :type => 'text', :disabled => true })
+ # tag("input", { :type => 'text', :disabled => true })
# # => <input type="text" disabled="disabled" />
#
# tag("img", { :src => "open & shut.png" })
@@ -37,17 +39,17 @@ module ActionView
# tag("img", { :src => "open &amp; shut.png" }, false, false)
# # => <img src="open &amp; shut.png" />
def tag(name, options = nil, open = false, escape = true)
- "<#{name}#{tag_options(options, escape) if options}" + (open ? ">" : " />")
+ "<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}"
end
# Returns an HTML block tag of type +name+ surrounding the +content+. Add
- # HTML attributes by passing an attributes hash to +options+.
+ # HTML attributes by passing an attributes hash to +options+.
# Instead of passing the content as an argument, you can also use a block
# in which case, you pass your +options+ as the second parameter.
# Set escape to false to disable attribute value escaping.
#
# ==== Options
- # The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and
+ # The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and
# <tt>readonly</tt>), which you can give a value of true in the +options+ hash. You can use
# symbols or strings for the attribute names.
#
@@ -66,12 +68,15 @@ module ActionView
def content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block)
if block_given?
options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash)
- content = capture(&block)
- content_tag = content_tag_string(name, content, options, escape)
- block_is_within_action_view?(block) ? concat(content_tag, block.binding) : content_tag
+ content_tag = content_tag_string(name, capture(&block), options, escape)
+
+ if block_called_from_erb?(block)
+ concat(content_tag)
+ else
+ content_tag
+ end
else
- content = content_or_options_with_block
- content_tag_string(name, content, options, escape)
+ content_tag_string(name, content_or_options_with_block, options, escape)
end
end
@@ -103,6 +108,16 @@ module ActionView
end
private
+ BLOCK_CALLED_FROM_ERB = 'defined? __in_erb_template'
+
+ # Check whether we're called from an erb template.
+ # We'd return a string in any other case, but erb <%= ... %>
+ # can't take an <% end %> later on, so we have to use <% ... %>
+ # and implicitly concat.
+ def block_called_from_erb?(block)
+ block && eval(BLOCK_CALLED_FROM_ERB, block)
+ end
+
def content_tag_string(name, content, options, escape = true)
tag_options = tag_options(options, escape) if options
"<#{name}#{tag_options}>#{content}</#{name}>"
@@ -114,7 +129,6 @@ module ActionView
if escape
options.each do |key, value|
next unless value
- key = key.to_s
value = BOOLEAN_ATTRIBUTES.include?(key) ? key : escape_once(value)
attrs << %(#{key}="#{value}")
end
@@ -124,10 +138,6 @@ module ActionView
" #{attrs.sort * ' '}" unless attrs.empty?
end
end
-
- def block_is_within_action_view?(block)
- eval("defined? _erbout", block.binding)
- end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index 669a285424..d98c5bd0d5 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -15,18 +15,22 @@ module ActionView
#
# ==== Examples
# <%
- # concat "hello", binding
+ # concat "hello"
# # is the equivalent of <%= "hello" %>
#
# if (logged_in == true):
- # concat "Logged in!", binding
+ # concat "Logged in!"
# else
- # concat link_to('login', :action => login), binding
+ # concat link_to('login', :action => login)
# end
# # will either display "Logged in!" or a login link
# %>
- def concat(string, binding)
- eval(ActionView::Base.erb_variable, binding) << string
+ def concat(string, unused_binding = nil)
+ if unused_binding
+ ActiveSupport::Deprecation.warn("The binding argument of #concat is no longer needed. Please remove it from your views and helpers.")
+ end
+
+ output_buffer << string
end
if RUBY_VERSION < '1.9'
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index 7bb189420b..89166fe19a 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -90,6 +90,13 @@ module ActionView
# link will be used in place of a referrer if none exists. If nil is passed as
# a name, the link itself will become the name.
#
+ # ==== Signatures
+ #
+ # link_to(name, options = {}, html_options = nil)
+ # link_to(options = {}, html_options = nil) do
+ # # name
+ # end
+ #
# ==== Options
# * <tt>:confirm => 'question?'</tt> - This will add a JavaScript confirm
# prompt with the question specified. If the user accepts, the link is
@@ -147,6 +154,13 @@ module ActionView
# link_to "Profiles", :controller => "profiles"
# # => <a href="/profiles">Profiles</a>
#
+ # You can use a block as well if your link target is hard to fit into the name parameter. ERb example:
+ #
+ # <% link_to(@profile) do %>
+ # <strong><%= @profile.name %></strong> -- <span>Check it out!!</span>
+ # <% end %>
+ # # => <a href="/profiles/1"><strong>David</strong> -- <span>Check it out!!</span></a>
+ #
# Classes and ids for CSS are easy to produce:
#
# link_to "Articles", articles_path, :id => "news", :class => "article"
@@ -189,27 +203,37 @@ module ActionView
# f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;
# var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method');
# m.setAttribute('value', 'delete'); f.appendChild(m);f.submit(); };return false;">Delete Image</a>
- def link_to(name, options = {}, html_options = nil)
- url = case options
- when String
- options
- when :back
- @controller.request.env["HTTP_REFERER"] || 'javascript:history.back()'
+ def link_to(*args, &block)
+ if block_given?
+ options = args.first || {}
+ html_options = args.second
+ concat(link_to(capture(&block), options, html_options))
+ else
+ name = args.first
+ options = args.second || {}
+ html_options = args.third
+
+ url = case options
+ when String
+ options
+ when :back
+ @controller.request.env["HTTP_REFERER"] || 'javascript:history.back()'
+ else
+ self.url_for(options)
+ end
+
+ if html_options
+ html_options = html_options.stringify_keys
+ href = html_options['href']
+ convert_options_to_javascript!(html_options, url)
+ tag_options = tag_options(html_options)
else
- self.url_for(options)
+ tag_options = nil
end
-
- if html_options
- html_options = html_options.stringify_keys
- href = html_options['href']
- convert_options_to_javascript!(html_options, url)
- tag_options = tag_options(html_options)
- else
- tag_options = nil
+
+ href_attr = "href=\"#{url}\"" unless href
+ "<a #{href_attr}#{tag_options}>#{name || url}</a>"
end
-
- href_attr = "href=\"#{url}\"" unless href
- "<a #{href_attr}#{tag_options}>#{name || url}</a>"
end
# Generates a form containing a single button that submits to the URL created
@@ -511,7 +535,7 @@ module ActionView
when method
"#{method_javascript_function(method, url, href)}return false;"
when popup
- popup_javascript_function(popup) + 'return false;'
+ "#{popup_javascript_function(popup)}return false;"
else
html_options["onclick"]
end
diff --git a/actionpack/lib/action_view/inline_template.rb b/actionpack/lib/action_view/inline_template.rb
index 87c012d181..fd0ad48302 100644
--- a/actionpack/lib/action_view/inline_template.rb
+++ b/actionpack/lib/action_view/inline_template.rb
@@ -1,20 +1,17 @@
module ActionView #:nodoc:
class InlineTemplate < Template #:nodoc:
-
def initialize(view, source, locals = {}, type = nil)
@view = view
- @finder = @view.finder
-
+
@source = source
@extension = type
@locals = locals || {}
-
+
@handler = self.class.handler_class_for_extension(@extension).new(@view)
end
-
+
def method_key
@source
end
-
end
end
diff --git a/actionpack/lib/action_view/partial_template.rb b/actionpack/lib/action_view/partial_template.rb
index 1fb3aaee02..0cf996ca04 100644
--- a/actionpack/lib/action_view/partial_template.rb
+++ b/actionpack/lib/action_view/partial_template.rb
@@ -1,70 +1,70 @@
module ActionView #:nodoc:
class PartialTemplate < Template #:nodoc:
-
attr_reader :variable_name, :object
-
+
def initialize(view, partial_path, object = nil, locals = {})
- @path, @variable_name = extract_partial_name_and_path(view, partial_path)
+ @view_controller = view.controller if view.respond_to?(:controller)
+ set_path_and_variable_name!(partial_path)
super(view, @path, true, locals)
add_object_to_local_assigns!(object)
# This is needed here in order to compile template with knowledge of 'counter'
- initialize_counter
-
+ initialize_counter!
+
# Prepare early. This is a performance optimization for partial collections
prepare!
end
-
+
def render
- ActionController::Base.benchmark("Rendered #{@path}", Logger::DEBUG, false) do
+ ActionController::Base.benchmark("Rendered #{@path.path_without_format_and_extension}", Logger::DEBUG, false) do
@handler.render(self)
end
end
-
+
def render_member(object)
- @locals[@counter_name] += 1
@locals[:object] = @locals[@variable_name] = object
-
+
template = render_template
+ @locals[@counter_name] += 1
@locals.delete(@variable_name)
@locals.delete(:object)
-
+
template
end
-
+
def counter=(num)
@locals[@counter_name] = num
end
private
+ def add_object_to_local_assigns!(object)
+ @locals[:object] ||=
+ @locals[@variable_name] ||=
+ if object.is_a?(ActionView::Base::ObjectWrapper)
+ object.value
+ else
+ object
+ end || @view_controller.instance_variable_get("@#{variable_name}")
+ end
- def add_object_to_local_assigns!(object)
- @locals[:object] ||=
- @locals[@variable_name] ||=
- if object.is_a?(ActionView::Base::ObjectWrapper)
- object.value
- else
- object
- end || @view.controller.instance_variable_get("@#{variable_name}")
- end
-
- def extract_partial_name_and_path(view, partial_path)
- path, partial_name = partial_pieces(view, partial_path)
- [File.join(path, "_#{partial_name}"), partial_name.split('/').last.split('.').first.to_sym]
- end
-
- def partial_pieces(view, partial_path)
- if partial_path.include?('/')
- return File.dirname(partial_path), File.basename(partial_path)
- else
- return view.controller.class.controller_path, partial_path
+ def set_path_and_variable_name!(partial_path)
+ if partial_path.include?('/')
+ @variable_name = File.basename(partial_path)
+ @path = "#{File.dirname(partial_path)}/_#{@variable_name}"
+ elsif @view_controller
+ @variable_name = partial_path
+ @path = "#{@view_controller.class.controller_path}/_#{@variable_name}"
+ else
+ @variable_name = partial_path
+ @path = "_#{@variable_name}"
+ end
+
+ @variable_name = @variable_name.sub(/\..*$/, '').to_sym
+ end
+
+ def initialize_counter!
+ @counter_name ||= "#{@variable_name}_counter".to_sym
+ @locals[@counter_name] = 0
end
- end
-
- def initialize_counter
- @counter_name ||= "#{@variable_name}_counter".to_sym
- @locals[@counter_name] = 0
- end
-
end
end
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb
index 369526188f..4c3f252c10 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template.rb
@@ -1,19 +1,20 @@
module ActionView #:nodoc:
class Template #:nodoc:
+ extend TemplateHandlers
attr_accessor :locals
- attr_reader :handler, :path, :extension, :filename, :path_without_extension, :method
+ attr_reader :handler, :path, :extension, :filename, :method
def initialize(view, path, use_full_path, locals = {})
@view = view
- @finder = @view.finder
+ @paths = view.view_paths
- # Clear the forward slash at the beginning if exists
- @path = use_full_path ? path.sub(/^\//, '') : path
- @view.first_render ||= @path
+ @original_path = path
+ @path = TemplateFile.from_path(path, !use_full_path)
+ @view.first_render ||= @path.to_s
@source = nil # Don't read the source until we know that it is required
set_extension_and_file_name(use_full_path)
-
+
@locals = locals || {}
@handler = self.class.handler_class_for_extension(@extension).new(@view)
end
@@ -29,12 +30,16 @@ module ActionView #:nodoc:
raise TemplateError.new(self, @view.assigns, e)
end
end
-
+
def render
prepare!
@handler.render(self)
end
+ def path_without_extension
+ @path.path_without_extension
+ end
+
def source
@source ||= File.read(self.filename)
end
@@ -44,13 +49,13 @@ module ActionView #:nodoc:
end
def base_path_for_exception
- @finder.find_base_path_for("#{@path_without_extension}.#{@extension}") || @finder.view_paths.first
+ (@paths.find_load_path_for_path(@path) || @paths.first).to_s
end
-
+
def prepare!
@view.send :evaluate_assigns
@view.current_render_extension = @extension
-
+
if @handler.compilable?
@handler.compile_template(self) # compile the given template, if necessary
@method = @view.method_names[method_key] # Set the method name for this template and run it
@@ -58,70 +63,32 @@ module ActionView #:nodoc:
end
private
-
- def set_extension_and_file_name(use_full_path)
- @path_without_extension, @extension = @finder.path_and_extension(@path)
- if use_full_path
- if @extension
- @filename = @finder.pick_template(@path_without_extension, @extension)
+ def set_extension_and_file_name(use_full_path)
+ @extension = @path.extension
+
+ if use_full_path
+ unless @extension
+ @path = @view.send(:template_file_from_name, @path)
+ raise_missing_template_exception unless @path
+ @extension = @path.extension
+ end
+
+ if @path = @paths.find_template_file_for_path(path)
+ @filename = @path.full_path
+ @extension = @path.extension
+ end
else
- @extension = @finder.pick_template_extension(@path).to_s
- raise_missing_template_exception unless @extension
-
- @filename = @finder.pick_template(@path, @extension)
- @extension = @extension.gsub(/^.+\./, '') # strip off any formats
+ @filename = @path.full_path
end
- else
- @filename = @path
- end
-
- raise_missing_template_exception if @filename.blank?
- end
-
- def raise_missing_template_exception
- full_template_path = @path.include?('.') ? @path : "#{@path}.#{@view.template_format}.erb"
- display_paths = @finder.view_paths.join(':')
- template_type = (@path =~ /layouts/i) ? 'layout' : 'template'
- raise(MissingTemplate, "Missing #{template_type} #{full_template_path} in view path #{display_paths}")
- end
-
- # Template Handlers
-
- @@template_handlers = HashWithIndifferentAccess.new
- @@default_template_handlers = nil
-
- # Register a class that knows how to handle template files with the given
- # extension. This can be used to implement new template types.
- # The constructor for the class must take the ActiveView::Base instance
- # as a parameter, and the class must implement a +render+ method that
- # takes the contents of the template to render as well as the Hash of
- # local assigns available to the template. The +render+ method ought to
- # return the rendered template as a string.
- def self.register_template_handler(extension, klass)
- @@template_handlers[extension.to_sym] = klass
- TemplateFinder.update_extension_cache_for(extension.to_s)
- end
- def self.template_handler_extensions
- @@template_handlers.keys.map(&:to_s).sort
- end
-
- def self.register_default_template_handler(extension, klass)
- register_template_handler(extension, klass)
- @@default_template_handlers = klass
- end
-
- def self.handler_class_for_extension(extension)
- (extension && @@template_handlers[extension.to_sym]) || @@default_template_handlers
- end
-
- register_default_template_handler :erb, TemplateHandlers::ERB
- register_template_handler :rjs, TemplateHandlers::RJS
- register_template_handler :builder, TemplateHandlers::Builder
+ raise_missing_template_exception if @filename.blank?
+ end
- # TODO: Depreciate old template extensions
- register_template_handler :rhtml, TemplateHandlers::ERB
- register_template_handler :rxml, TemplateHandlers::Builder
-
+ def raise_missing_template_exception
+ full_template_path = @original_path.include?('.') ? @original_path : "#{@original_path}.#{@view.template_format}.erb"
+ display_paths = @paths.join(':')
+ template_type = (@original_path =~ /layouts/i) ? 'layout' : 'template'
+ raise(MissingTemplate, "Missing #{template_type} #{full_template_path} in view path #{display_paths}")
+ end
end
end
diff --git a/actionpack/lib/action_view/template_file.rb b/actionpack/lib/action_view/template_file.rb
new file mode 100644
index 0000000000..dd66482b3c
--- /dev/null
+++ b/actionpack/lib/action_view/template_file.rb
@@ -0,0 +1,88 @@
+module ActionView #:nodoc:
+ # TemplateFile abstracts the pattern of querying a file path for its
+ # path with or without its extension. The path is only the partial path
+ # from the load path root e.g. "hello/index.html.erb" not
+ # "app/views/hello/index.html.erb"
+ class TemplateFile
+ def self.from_path(path, use_full_path = false)
+ path.is_a?(self) ? path : new(path, use_full_path)
+ end
+
+ def self.from_full_path(load_path, full_path)
+ file = new(full_path.split(load_path).last)
+ file.load_path = load_path
+ file.freeze
+ end
+
+ attr_accessor :load_path, :base_path, :name, :format, :extension
+ delegate :to_s, :inspect, :to => :path
+
+ def initialize(path, use_full_path = false)
+ path = path.dup
+
+ # Clear the forward slash in the beginning unless using full path
+ trim_forward_slash!(path) unless use_full_path
+
+ @base_path, @name, @format, @extension = split(path)
+ end
+
+ def freeze
+ @load_path.freeze
+ @base_path.freeze
+ @name.freeze
+ @format.freeze
+ @extension.freeze
+ super
+ end
+
+ def format_and_extension
+ extensions = [format, extension].compact.join(".")
+ extensions.blank? ? nil : extensions
+ end
+
+ def full_path
+ if load_path
+ "#{load_path}/#{path}"
+ else
+ path
+ end
+ end
+
+ def path
+ base_path.to_s + [name, format, extension].compact.join(".")
+ end
+
+ def path_without_extension
+ base_path.to_s + [name, format].compact.join(".")
+ end
+
+ def path_without_format_and_extension
+ "#{base_path}#{name}"
+ end
+
+ def dup_with_extension(extension)
+ file = dup
+ file.extension = extension ? extension.to_s : nil
+ file
+ end
+
+ private
+ def trim_forward_slash!(path)
+ path.sub!(/^\//, '')
+ end
+
+ # Returns file split into an array
+ # [base_path, name, format, extension]
+ def split(file)
+ if m = file.match(/^(.*\/)?(\w+)\.?(\w+)?\.?(\w+)?\.?(\w+)?$/)
+ if m[5] # Mulipart formats
+ [m[1], m[2], "#{m[3]}.#{m[4]}", m[5]]
+ elsif m[4] # Single format
+ [m[1], m[2], m[3], m[4]]
+ else # No format
+ [m[1], m[2], nil, m[3]]
+ end
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_view/template_finder.rb b/actionpack/lib/action_view/template_finder.rb
deleted file mode 100644
index 83b7e27c09..0000000000
--- a/actionpack/lib/action_view/template_finder.rb
+++ /dev/null
@@ -1,177 +0,0 @@
-module ActionView #:nodoc:
- class TemplateFinder #:nodoc:
-
- class InvalidViewPath < StandardError #:nodoc:
- attr_reader :unprocessed_path
- def initialize(path)
- @unprocessed_path = path
- super("Unprocessed view path found: #{@unprocessed_path.inspect}. Set your view paths with #append_view_path, #prepend_view_path, or #view_paths=.")
- end
- end
-
- cattr_reader :processed_view_paths
- @@processed_view_paths = Hash.new {|hash, key| hash[key] = []}
-
- cattr_reader :file_extension_cache
- @@file_extension_cache = Hash.new {|hash, key|
- hash[key] = Hash.new {|hash, key| hash[key] = []}
- }
-
- class << self #:nodoc:
-
- # This method is not thread safe. Mutex should be used whenever this is accessed from an instance method
- def process_view_paths(*view_paths)
- view_paths.flatten.compact.each do |dir|
- next if @@processed_view_paths.has_key?(dir)
- @@processed_view_paths[dir] = []
-
- #
- # Dir.glob("#{dir}/**/*/**") reads all the directories in view path and templates inside those directories
- # Dir.glob("#{dir}/**") reads templates residing at top level of view path
- #
- (Dir.glob("#{dir}/**/*/**") | Dir.glob("#{dir}/**")).each do |file|
- unless File.directory?(file)
- @@processed_view_paths[dir] << file.split(dir).last.sub(/^\//, '')
-
- # Build extension cache
- extension = file.split(".").last
- if template_handler_extensions.include?(extension)
- key = file.split(dir).last.sub(/^\//, '').sub(/\.(\w+)$/, '')
- @@file_extension_cache[dir][key] << extension
- end
- end
- end
- end
- end
-
- def update_extension_cache_for(extension)
- @@processed_view_paths.keys.each do |dir|
- Dir.glob("#{dir}/**/*.#{extension}").each do |file|
- key = file.split(dir).last.sub(/^\//, '').sub(/\.(\w+)$/, '')
- @@file_extension_cache[dir][key] << extension
- end
- end
- end
-
- def template_handler_extensions
- ActionView::Template.template_handler_extensions
- end
-
- def reload!
- view_paths = @@processed_view_paths.keys
-
- @@processed_view_paths = Hash.new {|hash, key| hash[key] = []}
- @@file_extension_cache = Hash.new {|hash, key|
- hash[key] = Hash.new {|hash, key| hash[key] = []}
- }
-
- process_view_paths(view_paths)
- end
- end
-
- attr_accessor :view_paths
-
- def initialize(*args)
- @template = args.shift
-
- @view_paths = args.flatten
- @view_paths = @view_paths.respond_to?(:find) ? @view_paths.dup : [*@view_paths].compact
- check_view_paths(@view_paths)
- end
-
- def prepend_view_path(path)
- @view_paths.unshift(*path)
-
- self.class.process_view_paths(path)
- end
-
- def append_view_path(path)
- @view_paths.push(*path)
-
- self.class.process_view_paths(path)
- end
-
- def view_paths=(path)
- @view_paths = path
- self.class.process_view_paths(path)
- end
-
- def pick_template(template_path, extension)
- file_name = "#{template_path}.#{extension}"
- base_path = find_base_path_for(file_name)
- base_path.blank? ? false : "#{base_path}/#{file_name}"
- end
- alias_method :template_exists?, :pick_template
-
- def file_exists?(template_path)
- # Clear the forward slash in the beginning if exists
- template_path = template_path.sub(/^\//, '')
-
- template_file_name, template_file_extension = path_and_extension(template_path)
-
- if template_file_extension
- template_exists?(template_file_name, template_file_extension)
- else
- template_exists?(template_file_name, pick_template_extension(template_path))
- end
- end
-
- def find_base_path_for(template_file_name)
- @view_paths.find { |path| @@processed_view_paths[path].include?(template_file_name) }
- end
-
- # Returns the view path that the full path resides in.
- def extract_base_path_from(full_path)
- @view_paths.find { |p| full_path[0..p.size - 1] == p }
- end
-
- # Gets the extension for an existing template with the given template_path.
- # Returns the format with the extension if that template exists.
- #
- # pick_template_extension('users/show')
- # # => 'html.erb'
- #
- # pick_template_extension('users/legacy')
- # # => "rhtml"
- #
- def pick_template_extension(template_path)
- if extension = find_template_extension_from_handler(template_path, @template.template_format) || find_template_extension_from_first_render
- extension
- elsif @template.template_format == :js && extension = find_template_extension_from_handler(template_path, :html)
- @template.template_format = :html
- extension
- end
- end
-
- def find_template_extension_from_handler(template_path, template_format = @template.template_format)
- formatted_template_path = "#{template_path}.#{template_format}"
-
- view_paths.each do |path|
- if (extensions = @@file_extension_cache[path][formatted_template_path]).any?
- return "#{template_format}.#{extensions.first}"
- elsif (extensions = @@file_extension_cache[path][template_path]).any?
- return extensions.first.to_s
- end
- end
- nil
- end
-
- # Splits the path and extension from the given template_path and returns as an array.
- def path_and_extension(template_path)
- template_path_without_extension = template_path.sub(/\.(\w+)$/, '')
- [ template_path_without_extension, $1 ]
- end
-
- # Determine the template extension from the <tt>@first_render</tt> filename
- def find_template_extension_from_first_render
- File.basename(@template.first_render.to_s)[/^[^.]+\.(.+)$/, 1]
- end
-
- private
- def check_view_paths(view_paths)
- view_paths.each do |path|
- raise InvalidViewPath.new(path) unless @@processed_view_paths.has_key?(path)
- end
- end
- end
-end
diff --git a/actionpack/lib/action_view/template_handler.rb b/actionpack/lib/action_view/template_handler.rb
index ec407e3fb3..39e578e586 100644
--- a/actionpack/lib/action_view/template_handler.rb
+++ b/actionpack/lib/action_view/template_handler.rb
@@ -1,6 +1,5 @@
module ActionView
class TemplateHandler
-
def self.line_offset
0
end
diff --git a/actionpack/lib/action_view/template_handlers.rb b/actionpack/lib/action_view/template_handlers.rb
new file mode 100644
index 0000000000..1471e99e01
--- /dev/null
+++ b/actionpack/lib/action_view/template_handlers.rb
@@ -0,0 +1,46 @@
+require 'action_view/template_handler'
+require 'action_view/template_handlers/compilable'
+require 'action_view/template_handlers/builder'
+require 'action_view/template_handlers/erb'
+require 'action_view/template_handlers/rjs'
+
+module ActionView #:nodoc:
+ module TemplateHandlers #:nodoc:
+ def self.extended(base)
+ base.register_default_template_handler :erb, TemplateHandlers::ERB
+ base.register_template_handler :rjs, TemplateHandlers::RJS
+ base.register_template_handler :builder, TemplateHandlers::Builder
+
+ # TODO: Depreciate old template extensions
+ base.register_template_handler :rhtml, TemplateHandlers::ERB
+ base.register_template_handler :rxml, TemplateHandlers::Builder
+ end
+
+ @@template_handlers = {}
+ @@default_template_handlers = nil
+
+ # Register a class that knows how to handle template files with the given
+ # extension. This can be used to implement new template types.
+ # The constructor for the class must take the ActiveView::Base instance
+ # as a parameter, and the class must implement a +render+ method that
+ # takes the contents of the template to render as well as the Hash of
+ # local assigns available to the template. The +render+ method ought to
+ # return the rendered template as a string.
+ def register_template_handler(extension, klass)
+ @@template_handlers[extension.to_sym] = klass
+ end
+
+ def template_handler_extensions
+ @@template_handlers.keys.map(&:to_s).sort
+ end
+
+ def register_default_template_handler(extension, klass)
+ register_template_handler(extension, klass)
+ @@default_template_handlers = klass
+ end
+
+ def handler_class_for_extension(extension)
+ (extension && @@template_handlers[extension.to_sym]) || @@default_template_handlers
+ end
+ end
+end
diff --git a/actionpack/lib/action_view/template_handlers/builder.rb b/actionpack/lib/action_view/template_handlers/builder.rb
index f76d89777a..ee02ce1a6f 100644
--- a/actionpack/lib/action_view/template_handlers/builder.rb
+++ b/actionpack/lib/action_view/template_handlers/builder.rb
@@ -11,10 +11,11 @@ module ActionView
def compile(template)
content_type_handler = (@view.send!(:controller).respond_to?(:response) ? "controller.response" : "controller")
+
"#{content_type_handler}.content_type ||= Mime::XML\n" +
- "xml = ::Builder::XmlMarkup.new(:indent => 2)\n" +
- template.source +
- "\nxml.target!\n"
+ "xml = ::Builder::XmlMarkup.new(:indent => 2)\n" +
+ template.source +
+ "\nxml.target!\n"
end
def cache_fragment(block, name = {}, options = nil)
diff --git a/actionpack/lib/action_view/template_handlers/compilable.rb b/actionpack/lib/action_view/template_handlers/compilable.rb
index 25bd0fea7f..783456ab53 100644
--- a/actionpack/lib/action_view/template_handlers/compilable.rb
+++ b/actionpack/lib/action_view/template_handlers/compilable.rb
@@ -106,7 +106,13 @@ module ActionView
locals_code << "#{key} = local_assigns[:#{key}]\n"
end
- "def #{render_symbol}(local_assigns)\n#{locals_code}#{body}\nend"
+ <<-end_src
+ def #{render_symbol}(local_assigns)
+ old_output_buffer = output_buffer;#{locals_code}#{body}
+ ensure
+ self.output_buffer = old_output_buffer
+ end
+ end_src
end
# Return true if the given template was compiled for a superset of the keys in local_assigns
@@ -125,4 +131,4 @@ module ActionView
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_view/template_handlers/erb.rb b/actionpack/lib/action_view/template_handlers/erb.rb
index 15a9064461..ac715e30c2 100644
--- a/actionpack/lib/action_view/template_handlers/erb.rb
+++ b/actionpack/lib/action_view/template_handlers/erb.rb
@@ -42,13 +42,19 @@ module ActionView
class ERB < TemplateHandler
include Compilable
+ # Specify trim mode for the ERB compiler. Defaults to '-'.
+ # See ERb documentation for suitable values.
+ cattr_accessor :erb_trim_mode
+ self.erb_trim_mode = '-'
+
def compile(template)
- ::ERB.new(template.source, nil, @view.erb_trim_mode).src
+ src = ::ERB.new(template.source, nil, erb_trim_mode, '@output_buffer').src
+ "__in_erb_template=true;#{src}"
end
def cache_fragment(block, name = {}, options = nil) #:nodoc:
@view.fragment_for(block, name, options) do
- eval(ActionView::Base.erb_variable, block.binding)
+ @view.response.template.output_buffer
end
end
end
diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb
index 16fedd9732..1a3c93c283 100644
--- a/actionpack/lib/action_view/test_case.rb
+++ b/actionpack/lib/action_view/test_case.rb
@@ -37,6 +37,8 @@ module ActionView
if helper_class && !self.class.ancestors.include?(helper_class)
self.class.send(:include, helper_class)
end
+
+ self.output_buffer = ''
end
class TestController < ActionController::Base
@@ -48,6 +50,9 @@ module ActionView
end
end
+ protected
+ attr_accessor :output_buffer
+
private
def method_missing(selector, *args)
controller = TestController.new
diff --git a/actionpack/lib/action_view/view_load_paths.rb b/actionpack/lib/action_view/view_load_paths.rb
new file mode 100644
index 0000000000..e873d96aa0
--- /dev/null
+++ b/actionpack/lib/action_view/view_load_paths.rb
@@ -0,0 +1,103 @@
+module ActionView #:nodoc:
+ class ViewLoadPaths < Array #:nodoc:
+ def self.type_cast(obj)
+ obj.is_a?(String) ? LoadPath.new(obj) : obj
+ end
+
+ class LoadPath #:nodoc:
+ attr_reader :path, :paths
+ delegate :to_s, :inspect, :to => :path
+
+ def initialize(path)
+ @path = path.freeze
+ reload!
+ end
+
+ def eql?(view_path)
+ view_path.is_a?(ViewPath) && @path == view_path.path
+ end
+
+ def hash
+ @path.hash
+ end
+
+ # Rebuild load path directory cache
+ def reload!
+ @paths = {}
+
+ files.each do |file|
+ @paths[file.path] = file
+ @paths[file.path_without_extension] ||= file
+ end
+
+ @paths.freeze
+ end
+
+ # Tries to find the extension for the template name.
+ # If it does not it exist, tries again without the format extension
+ # find_template_file_for_partial_path('users/show') => 'html.erb'
+ # find_template_file_for_partial_path('users/legacy') => 'rhtml'
+ def find_template_file_for_partial_path(file)
+ @paths[file.path] || @paths[file.path_without_extension] || @paths[file.path_without_format_and_extension]
+ end
+
+ private
+ # Get all the files and directories in the path
+ def files_in_path
+ Dir.glob("#{@path}/**/*/**") | Dir.glob("#{@path}/**")
+ end
+
+ # Create an array of all the files within the path
+ def files
+ files_in_path.map do |file|
+ TemplateFile.from_full_path(@path, file) unless File.directory?(file)
+ end.compact
+ end
+ end
+
+ def initialize(*args)
+ super(*args).map! { |obj| self.class.type_cast(obj) }
+ end
+
+ def reload!
+ each { |path| path.reload! }
+ end
+
+ def <<(obj)
+ super(self.class.type_cast(obj))
+ end
+
+ def push(*objs)
+ delete_paths!(objs)
+ super(*objs.map { |obj| self.class.type_cast(obj) })
+ end
+
+ def unshift(*objs)
+ delete_paths!(objs)
+ super(*objs.map { |obj| self.class.type_cast(obj) })
+ end
+
+ def template_exists?(file)
+ find_load_path_for_path(file) ? true : false
+ end
+
+ def find_load_path_for_path(file)
+ find { |path| path.paths[file.to_s] }
+ end
+
+ def find_template_file_for_path(file)
+ file = TemplateFile.from_path(file)
+ each do |path|
+ if f = path.find_template_file_for_partial_path(file)
+ return f
+ end
+ end
+ nil
+ end
+
+ private
+ def delete_paths!(paths)
+ paths.each { |p1| delete_if { |p2| p1.to_s == p2.to_s } }
+ end
+ end
+end
diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb
index f152b1d19c..c25e9e1df6 100644
--- a/actionpack/test/controller/action_pack_assertions_test.rb
+++ b/actionpack/test/controller/action_pack_assertions_test.rb
@@ -137,6 +137,9 @@ class AssertResponseWithUnexpectedErrorController < ActionController::Base
end
end
+class UserController < ActionController::Base
+end
+
module Admin
class InnerModuleController < ActionController::Base
def index
@@ -174,7 +177,7 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase
# let's get this party started
def setup
ActionController::Routing::Routes.reload
- ActionController::Routing.use_controllers!(%w(action_pack_assertions admin/inner_module content admin/user))
+ ActionController::Routing.use_controllers!(%w(action_pack_assertions admin/inner_module user content admin/user))
@controller = ActionPackAssertionsController.new
@request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new
end
@@ -268,7 +271,7 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase
assert_redirected_to admin_inner_module_path
end
end
-
+
def test_assert_redirected_to_top_level_named_route_from_nested_controller
with_routing do |set|
set.draw do |map|
@@ -277,11 +280,25 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase
end
@controller = Admin::InnerModuleController.new
process :redirect_to_top_level_named_route
- # passes -> assert_redirected_to "http://test.host/action_pack_assertions/foo"
+ # assert_redirected_to "http://test.host/action_pack_assertions/foo" would pass because of exact match early return
assert_redirected_to "/action_pack_assertions/foo"
end
end
+ def test_assert_redirected_to_top_level_named_route_with_same_controller_name_in_both_namespaces
+ 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'
+ end
+ @controller = Admin::InnerModuleController.new
+ process :redirect_to_top_level_named_route
+ # assert_redirected_to top_level_url('foo') would pass because of exact match early return
+ assert_redirected_to top_level_path('foo')
+ end
+ end
+
# -- standard request/response object testing --------------------------------
# make sure that the template objects exist
diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb
index b28717597e..34c0200fe8 100644
--- a/actionpack/test/controller/base_test.rb
+++ b/actionpack/test/controller/base_test.rb
@@ -169,6 +169,22 @@ class DefaultUrlOptionsTest < Test::Unit::TestCase
end
end
+class EmptyUrlOptionsTest < Test::Unit::TestCase
+ def setup
+ @controller = NonEmptyController.new
+
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+
+ @request.host = 'www.example.com'
+ end
+
+ def test_ensure_url_for_works_as_expected_when_called_with_no_options_if_default_url_options_is_not_set
+ get :public_action
+ assert_equal "http://www.example.com/non_empty/public_action", @controller.url_for
+ end
+end
+
class EnsureNamedRoutesWorksTicket22BugTest < Test::Unit::TestCase
def test_named_routes_still_work
ActionController::Routing::Routes.draw do |map|
@@ -180,4 +196,4 @@ class EnsureNamedRoutesWorksTicket22BugTest < Test::Unit::TestCase
ensure
ActionController::Routing::Routes.load!
end
-end \ No newline at end of file
+end
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index f9b6b87bc6..14cf0a86a1 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -156,6 +156,7 @@ class ActionCachingTestController < ActionController::Base
caches_action :show, :cache_path => 'http://test.host/custom/show'
caches_action :edit, :cache_path => Proc.new { |c| c.params[:id] ? "http://test.host/#{c.params[:id]};edit" : "http://test.host/edit" }
caches_action :with_layout
+ caches_action :layout_false, :layout => false
layout 'talk_from_action.erb'
@@ -181,11 +182,16 @@ class ActionCachingTestController < ActionController::Base
alias_method :show, :index
alias_method :edit, :index
alias_method :destroy, :index
+ alias_method :layout_false, :with_layout
def expire
expire_action :controller => 'action_caching_test', :action => 'index'
render :nothing => true
end
+ def expire_xml
+ expire_action :controller => 'action_caching_test', :action => 'index', :format => 'xml'
+ render :nothing => true
+ end
end
class MockTime < Time
@@ -211,6 +217,7 @@ class ActionCachingMockController
mocked_path = @mock_path
Object.new.instance_eval(<<-EVAL)
def path; '#{@mock_path}' end
+ def format; 'all' end
self
EVAL
end
@@ -263,6 +270,19 @@ class ActionCacheTest < Test::Unit::TestCase
assert_equal @response.body, read_fragment('hostname.com/action_caching_test/with_layout')
end
+ def test_action_cache_with_layout_and_layout_cache_false
+ get :layout_false
+ cached_time = content_to_cache
+ assert_not_equal cached_time, @response.body
+ assert fragment_exist?('hostname.com/action_caching_test/layout_false')
+ reset!
+
+ get :layout_false
+ assert_not_equal cached_time, @response.body
+
+ assert_equal cached_time, read_fragment('hostname.com/action_caching_test/layout_false')
+ end
+
def test_action_cache_conditional_options
@request.env['HTTP_ACCEPT'] = 'application/json'
get :index
@@ -311,6 +331,20 @@ class ActionCacheTest < Test::Unit::TestCase
assert_equal new_cached_time, @response.body
end
+ def test_cache_expiration_isnt_affected_by_request_format
+ get :index
+ cached_time = content_to_cache
+ reset!
+
+ @request.set_REQUEST_URI "/action_caching_test/expire.xml"
+ get :expire, :format => :xml
+ reset!
+
+ get :index
+ new_cached_time = content_to_cache
+ assert_not_equal cached_time, @response.body
+ end
+
def test_cache_is_scoped_by_subdomain
@request.host = 'jamis.hostname.com'
get :index
@@ -355,11 +389,35 @@ class ActionCacheTest < Test::Unit::TestCase
end
def test_xml_version_of_resource_is_treated_as_different_cache
- @mock_controller.mock_url_for = 'http://example.org/posts/'
- @mock_controller.mock_path = '/posts/index.xml'
- path_object = @path_class.new(@mock_controller, {})
- assert_equal 'xml', path_object.extension
- assert_equal 'example.org/posts/index.xml', path_object.path
+ with_routing do |set|
+ ActionController::Routing::Routes.draw do |map|
+ map.connect ':controller/:action.:format'
+ map.connect ':controller/:action'
+ end
+
+ get :index, :format => 'xml'
+ cached_time = content_to_cache
+ assert_equal cached_time, @response.body
+ assert fragment_exist?('hostname.com/action_caching_test/index.xml')
+ reset!
+
+ get :index, :format => 'xml'
+ assert_equal cached_time, @response.body
+ assert_equal 'application/xml', @response.content_type
+ reset!
+
+ @request.env['HTTP_ACCEPT'] = "application/xml"
+ get :index
+ assert_equal cached_time, @response.body
+ assert_equal 'application/xml', @response.content_type
+ reset!
+
+ get :expire_xml
+ reset!
+
+ get :index, :format => 'xml'
+ assert_not_equal cached_time, @response.body
+ end
end
def test_correct_content_type_is_returned_for_cache_hit
@@ -421,6 +479,8 @@ class FragmentCachingTest < Test::Unit::TestCase
@controller.request = @request
@controller.response = @response
@controller.send(:initialize_current_url)
+ @controller.send(:initialize_template_class, @response)
+ @controller.send(:assign_shortcuts, @request, @response)
end
def test_fragment_cache_key
@@ -510,7 +570,7 @@ class FragmentCachingTest < Test::Unit::TestCase
def test_cache_erb_fragment
@store.write('views/expensive', 'fragment content')
- _erbout = 'generated till now -> '
+ @controller.response.template.output_buffer = 'generated till now -> '
assert_equal( 'generated till now -> fragment content',
ActionView::TemplateHandlers::ERB.new(@controller).cache_fragment(Proc.new{ }, 'expensive'))
diff --git a/actionpack/test/controller/capture_test.rb b/actionpack/test/controller/capture_test.rb
index aaafea3920..2604844b84 100644
--- a/actionpack/test/controller/capture_test.rb
+++ b/actionpack/test/controller/capture_test.rb
@@ -11,16 +11,8 @@ class CaptureController < ActionController::Base
def content_for_with_parameter
render :layout => "talk_from_action"
end
-
- def content_for_concatenated
- render :layout => "talk_from_action"
- end
- def erb_content_for
- render :layout => "talk_from_action"
- end
-
- def block_content_for
+ def content_for_concatenated
render :layout => "talk_from_action"
end
@@ -62,21 +54,11 @@ class CaptureTest < Test::Unit::TestCase
assert_equal expected_content_for_output, @response.body
end
- def test_erb_content_for
- get :erb_content_for
- assert_equal expected_content_for_output, @response.body
- end
-
def test_should_set_content_for_with_parameter
get :content_for_with_parameter
assert_equal expected_content_for_output, @response.body
end
- def test_block_content_for
- get :block_content_for
- assert_equal expected_content_for_output, @response.body
- end
-
def test_non_erb_block_content_for
get :non_erb_block_content_for
assert_equal expected_content_for_output, @response.body
diff --git a/actionpack/test/controller/cgi_test.rb b/actionpack/test/controller/cgi_test.rb
index f0f3a4b826..1b1ded4615 100755
--- a/actionpack/test/controller/cgi_test.rb
+++ b/actionpack/test/controller/cgi_test.rb
@@ -115,35 +115,37 @@ class CgiRequestNeedsRewoundTest < BaseCgiTest
end
end
-class CgiResponseTest < BaseCgiTest
- def setup
- super
- @fake_cgi.expects(:header).returns("HTTP/1.0 200 OK\nContent-Type: text/html\n")
- @response = ActionController::CgiResponse.new(@fake_cgi)
- @output = StringIO.new('')
- end
-
- def test_simple_output
- @response.body = "Hello, World!"
+uses_mocha 'CGI Response' do
+ class CgiResponseTest < BaseCgiTest
+ def setup
+ super
+ @fake_cgi.expects(:header).returns("HTTP/1.0 200 OK\nContent-Type: text/html\n")
+ @response = ActionController::CgiResponse.new(@fake_cgi)
+ @output = StringIO.new('')
+ end
- @response.out(@output)
- assert_equal "HTTP/1.0 200 OK\nContent-Type: text/html\nHello, World!", @output.string
- end
+ def test_simple_output
+ @response.body = "Hello, World!"
- def test_head_request
- @fake_cgi.env_table['REQUEST_METHOD'] = 'HEAD'
- @response.body = "Hello, World!"
+ @response.out(@output)
+ assert_equal "HTTP/1.0 200 OK\nContent-Type: text/html\nHello, World!", @output.string
+ end
- @response.out(@output)
- assert_equal "HTTP/1.0 200 OK\nContent-Type: text/html\n", @output.string
- end
+ def test_head_request
+ @fake_cgi.env_table['REQUEST_METHOD'] = 'HEAD'
+ @response.body = "Hello, World!"
- def test_streaming_block
- @response.body = Proc.new do |response, output|
- 5.times { |n| output.write(n) }
+ @response.out(@output)
+ assert_equal "HTTP/1.0 200 OK\nContent-Type: text/html\n", @output.string
end
- @response.out(@output)
- assert_equal "HTTP/1.0 200 OK\nContent-Type: text/html\n01234", @output.string
+ def test_streaming_block
+ @response.body = Proc.new do |response, output|
+ 5.times { |n| output.write(n) }
+ end
+
+ @response.out(@output)
+ assert_equal "HTTP/1.0 200 OK\nContent-Type: text/html\n01234", @output.string
+ end
end
end
diff --git a/actionpack/test/controller/dispatcher_test.rb b/actionpack/test/controller/dispatcher_test.rb
index eea0813ed5..911fcab67b 100644
--- a/actionpack/test/controller/dispatcher_test.rb
+++ b/actionpack/test/controller/dispatcher_test.rb
@@ -27,14 +27,14 @@ class DispatcherTest < Test::Unit::TestCase
def test_clears_dependencies_after_dispatch_if_in_loading_mode
ActionController::Routing::Routes.expects(:reload).once
- Dependencies.expects(:clear).once
+ ActiveSupport::Dependencies.expects(:clear).once
dispatch(@output, false)
end
def test_leaves_dependencies_after_dispatch_if_not_in_loading_mode
ActionController::Routing::Routes.expects(:reload).never
- Dependencies.expects(:clear).never
+ ActiveSupport::Dependencies.expects(:clear).never
dispatch
end
diff --git a/actionpack/test/controller/html-scanner/document_test.rb b/actionpack/test/controller/html-scanner/document_test.rb
index 0519533dbd..1c3facb9e3 100644
--- a/actionpack/test/controller/html-scanner/document_test.rb
+++ b/actionpack/test/controller/html-scanner/document_test.rb
@@ -120,4 +120,29 @@ HTML
assert doc.find(:tag => "div", :attributes => { :id => "map" }, :content => "")
assert doc.find(:tag => "div", :attributes => { :id => "map" }, :content => nil)
end
+
+ def test_parse_invalid_document
+ assert_nothing_raised do
+ doc = HTML::Document.new("<html>
+ <table>
+ <tr>
+ <td style=\"color: #FFFFFF; height: 17px; onclick=\"window.location.href='http://www.rmeinc.com/about_rme.aspx'\" style=\"cursor:pointer; height: 17px;\"; nowrap onclick=\"window.location.href='http://www.rmeinc.com/about_rme.aspx'\" onmouseout=\"this.bgColor='#0066cc'; this.style.color='#FFFFFF'\" onmouseover=\"this.bgColor='#ffffff'; this.style.color='#0033cc'\">About Us</td>
+ </tr>
+ </table>
+ </html>")
+ end
+ end
+
+ def test_invalid_document_raises_exception_when_strict
+ assert_raises RuntimeError do
+ doc = HTML::Document.new("<html>
+ <table>
+ <tr>
+ <td style=\"color: #FFFFFF; height: 17px; onclick=\"window.location.href='http://www.rmeinc.com/about_rme.aspx'\" style=\"cursor:pointer; height: 17px;\"; nowrap onclick=\"window.location.href='http://www.rmeinc.com/about_rme.aspx'\" onmouseout=\"this.bgColor='#0066cc'; this.style.color='#FFFFFF'\" onmouseover=\"this.bgColor='#ffffff'; this.style.color='#0033cc'\">About Us</td>
+ </tr>
+ </table>
+ </html>", true)
+ end
+ end
+
end
diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb
index 62c00c5b9a..475e13897b 100644
--- a/actionpack/test/controller/integration_test.rb
+++ b/actionpack/test/controller/integration_test.rb
@@ -1,5 +1,6 @@
require 'abstract_unit'
require 'action_controller/integration'
+require 'action_controller/routing'
uses_mocha 'integration' do
@@ -12,12 +13,12 @@ end
class SessionTest < Test::Unit::TestCase
include IntegrationSessionStubbing
-
+
def setup
@session = ActionController::Integration::Session.new
stub_integration_session(@session)
end
-
+
def test_https_bang_works_and_sets_truth_by_default
assert !@session.https?
@session.https!
@@ -196,7 +197,7 @@ class SessionTest < Test::Unit::TestCase
@session.expects(:process).with(:head,path,params,headers_after_xhr)
@session.xml_http_request(:head,path,params,headers)
end
-
+
def test_xml_http_request_override_accept
path = "/index"; params = "blah"; headers = {:location => 'blah', "Accept" => "application/xml"}
headers_after_xhr = headers.merge(
@@ -227,7 +228,6 @@ class IntegrationTestTest < Test::Unit::TestCase
assert_equal ::ActionController::Integration::Session, session2.class
assert_not_equal session1, session2
end
-
end
# Tests that integration tests don't call Controller test methods for processing.
@@ -246,7 +246,90 @@ class IntegrationTestUsesCorrectClass < ActionController::IntegrationTest
assert_nothing_raised("'#{verb}' should use integration test methods") { send!(verb, '/') }
end
end
+end
+
+class IntegrationProcessTest < ActionController::IntegrationTest
+ class IntegrationController < ActionController::Base
+ session :off
+
+ def get
+ render :text => "OK", :status => 200
+ end
+
+ def post
+ render :text => "Created", :status => 201
+ end
+
+ def cookie_monster
+ cookies["cookie_1"] = nil
+ cookies["cookie_3"] = "chocolate"
+ render :text => "Gone", :status => 410
+ end
+ end
+ def test_get
+ with_test_route_set do
+ get '/get'
+ assert_equal 200, status
+ assert_equal "OK", status_message
+ assert_equal "200 OK", response.headers["Status"]
+ assert_equal ["200 OK"], headers["status"]
+ assert_equal [], response.headers["cookie"]
+ assert_equal [], headers["cookie"]
+ assert_equal({}, cookies)
+ assert_equal "OK", response.body
+ assert_kind_of HTML::Document, html_document
+ assert_equal 1, request_count
+ end
+ end
+
+ def test_post
+ with_test_route_set do
+ post '/post'
+ assert_equal 201, status
+ assert_equal "Created", status_message
+ assert_equal "201 Created", response.headers["Status"]
+ assert_equal ["201 Created"], headers["status"]
+ assert_equal [], response.headers["cookie"]
+ assert_equal [], headers["cookie"]
+ assert_equal({}, cookies)
+ assert_equal "Created", response.body
+ assert_kind_of HTML::Document, html_document
+ assert_equal 1, request_count
+ end
+ end
+
+ def test_cookie_monster
+ with_test_route_set do
+ self.cookies['cookie_1'] = "sugar"
+ self.cookies['cookie_2'] = "oatmeal"
+ get '/cookie_monster'
+ assert_equal 410, status
+ assert_equal "Gone", status_message
+ assert_equal "410 Gone", response.headers["Status"]
+ assert_equal ["410 Gone"], headers["status"]
+ assert_equal nil, response.headers["Set-Cookie"]
+ assert_equal ["cookie_1=; path=/", "cookie_3=chocolate; path=/"], headers['set-cookie']
+ assert_equal [[], ["chocolate"]], response.headers["cookie"]
+ assert_equal [], headers["cookie"]
+ assert_equal({"cookie_1"=>"", "cookie_2"=>"oatmeal", "cookie_3"=>"chocolate"}, cookies)
+ assert_equal "Gone", response.body
+ end
+ end
+
+ private
+ def with_test_route_set
+ with_routing do |set|
+ set.draw do |map|
+ map.with_options :controller => "IntegrationProcessTest::Integration" do |c|
+ c.connect '/get', :action => "get"
+ c.connect '/post', :action => "post"
+ c.connect '/cookie_monster', :action => "cookie_monster"
+ end
+ end
+ yield
+ end
+ end
end
-end # uses_mocha
+end
diff --git a/actionpack/test/controller/integration_upload_test.rb b/actionpack/test/controller/integration_upload_test.rb
index 33df1131cb..4af9b7e697 100644
--- a/actionpack/test/controller/integration_upload_test.rb
+++ b/actionpack/test/controller/integration_upload_test.rb
@@ -28,7 +28,7 @@ class SessionUploadTest < ActionController::IntegrationTest
# end
def test_post_with_upload
uses_mocha "test_post_with_upload" do
- Dependencies.stubs(:load?).returns(false)
+ ActiveSupport::Dependencies.stubs(:load?).returns(false)
with_routing do |set|
set.draw do |map|
map.update 'update', :controller => "upload_test", :action => "update", :method => :post
diff --git a/actionpack/test/controller/new_render_test.rb b/actionpack/test/controller/new_render_test.rb
index 6e2c6d90c6..b77b3ceffa 100644
--- a/actionpack/test/controller/new_render_test.rb
+++ b/actionpack/test/controller/new_render_test.rb
@@ -68,6 +68,11 @@ class NewRenderTestController < ActionController::Base
path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb')
render :file => path
end
+
+ def render_file_from_template
+ @secret = 'in the sauce'
+ @path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb'))
+ end
def render_file_with_locals
path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_locals.erb')
@@ -215,7 +220,7 @@ class NewRenderTestController < ActionController::Base
render :action => "test/hello_world"
end
- def render_to_string_with_partial
+ def render_to_string_with_partial
@partial_only = render_to_string :partial => "partial_only"
@partial_with_locals = render_to_string :partial => "customer", :locals => { :customer => Customer.new("david") }
render :action => "test/hello_world"
@@ -246,11 +251,15 @@ class NewRenderTestController < ActionController::Base
def accessing_logger_in_template
render :inline => "<%= logger.class %>"
end
-
+
def accessing_action_name_in_template
render :inline => "<%= action_name %>"
end
+ def accessing_controller_name_in_template
+ render :inline => "<%= controller_name %>"
+ end
+
def accessing_params_in_template_with_layout
render :layout => nil, :inline => "Hello: <%= params[:name] %>"
end
@@ -531,6 +540,11 @@ class NewRenderTest < Test::Unit::TestCase
get :render_file_with_locals
assert_equal "The secret is in the sauce\n", @response.body
end
+
+ def test_render_file_from_template
+ get :render_file_from_template
+ assert_equal "The secret is in the sauce\n", @response.body
+ end
def test_attempt_to_access_object_method
assert_raises(ActionController::UnknownAction, "No action responded to [clone]") { get :clone }
@@ -549,12 +563,17 @@ class NewRenderTest < Test::Unit::TestCase
get :accessing_logger_in_template
assert_equal "Logger", @response.body
end
-
+
def test_access_to_action_name_in_view
get :accessing_action_name_in_template
assert_equal "accessing_action_name_in_template", @response.body
end
+ def test_access_to_controller_name_in_view
+ get :accessing_controller_name_in_template
+ assert_equal "test", @response.body # name is explicitly set to 'test' inside the controller.
+ end
+
def test_render_xml
get :render_xml_hello
assert_equal "<html>\n <p>Hello David</p>\n<p>This is grand!</p>\n</html>\n", @response.body
@@ -742,7 +761,7 @@ EOS
def test_partial_collection_with_counter
get :partial_collection_with_counter
- assert_equal "david1mary2", @response.body
+ assert_equal "david0mary1", @response.body
end
def test_partial_collection_with_locals
@@ -762,7 +781,7 @@ EOS
def test_partial_collection_shorthand_with_different_types_of_records
get :partial_collection_shorthand_with_different_types_of_records
- assert_equal "Bonjour bad customer: mark1Bonjour good customer: craig2Bonjour bad customer: john3Bonjour good customer: zach4Bonjour good customer: brandon5Bonjour bad customer: dan6", @response.body
+ assert_equal "Bonjour bad customer: mark0Bonjour good customer: craig1Bonjour bad customer: john2Bonjour good customer: zach3Bonjour good customer: brandon4Bonjour bad customer: dan5", @response.body
end
def test_empty_partial_collection
diff --git a/actionpack/test/controller/polymorphic_routes_test.rb b/actionpack/test/controller/polymorphic_routes_test.rb
index 4ec0d3cd4e..3f52526f08 100644
--- a/actionpack/test/controller/polymorphic_routes_test.rb
+++ b/actionpack/test/controller/polymorphic_routes_test.rb
@@ -118,6 +118,39 @@ uses_mocha 'polymorphic URL helpers' do
polymorphic_url([:site, :admin, @article, @response, @tag])
end
+ def test_nesting_with_array_ending_in_singleton_resource
+ expects(:article_response_url).with(@article)
+ polymorphic_url([@article, :response])
+ end
+
+ def test_nesting_with_array_containing_singleton_resource
+ @tag = Tag.new
+ @tag.save
+ expects(:article_response_tag_url).with(@article, @tag)
+ polymorphic_url([@article, :response, @tag])
+ end
+
+ def test_nesting_with_array_containing_namespace_and_singleton_resource
+ @tag = Tag.new
+ @tag.save
+ expects(:admin_article_response_tag_url).with(@article, @tag)
+ polymorphic_url([:admin, @article, :response, @tag])
+ end
+
+ def test_nesting_with_array_containing_singleton_resource_and_format
+ @tag = Tag.new
+ @tag.save
+ expects(:formatted_article_response_tag_url).with(@article, @tag, :pdf)
+ formatted_polymorphic_url([@article, :response, @tag, :pdf])
+ end
+
+ def test_nesting_with_array_containing_singleton_resource_and_format_option
+ @tag = Tag.new
+ @tag.save
+ expects(:article_response_tag_url).with(@article, @tag, :pdf)
+ polymorphic_url([@article, :response, @tag], :format => :pdf)
+ end
+
# TODO: Needs to be updated to correctly know about whether the object is in a hash or not
def xtest_with_hash
expects(:article_url).with(@article)
diff --git a/actionpack/test/controller/rack_test.rb b/actionpack/test/controller/rack_test.rb
index cd4151783e..856f24bbdb 100644
--- a/actionpack/test/controller/rack_test.rb
+++ b/actionpack/test/controller/rack_test.rb
@@ -3,11 +3,40 @@ require 'action_controller/rack_process'
class BaseRackTest < Test::Unit::TestCase
def setup
- @env = {"HTTP_MAX_FORWARDS"=>"10", "SERVER_NAME"=>"glu.ttono.us:8007", "FCGI_ROLE"=>"RESPONDER", "HTTP_X_FORWARDED_HOST"=>"glu.ttono.us", "HTTP_ACCEPT_ENCODING"=>"gzip, deflate", "HTTP_USER_AGENT"=>"Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/312.5.1 (KHTML, like Gecko) Safari/312.3.1", "PATH_INFO"=>"", "HTTP_ACCEPT_LANGUAGE"=>"en", "HTTP_HOST"=>"glu.ttono.us:8007", "SERVER_PROTOCOL"=>"HTTP/1.1", "REDIRECT_URI"=>"/dispatch.fcgi", "SCRIPT_NAME"=>"/dispatch.fcgi", "SERVER_ADDR"=>"207.7.108.53", "REMOTE_ADDR"=>"207.7.108.53", "SERVER_SOFTWARE"=>"lighttpd/1.4.5", "HTTP_COOKIE"=>"_session_id=c84ace84796670c052c6ceb2451fb0f2; is_admin=yes", "HTTP_X_FORWARDED_SERVER"=>"glu.ttono.us", "REQUEST_URI"=>"/admin", "DOCUMENT_ROOT"=>"/home/kevinc/sites/typo/public", "SERVER_PORT"=>"8007", "QUERY_STRING"=>"", "REMOTE_PORT"=>"63137", "GATEWAY_INTERFACE"=>"CGI/1.1", "HTTP_X_FORWARDED_FOR"=>"65.88.180.234", "HTTP_ACCEPT"=>"*/*", "SCRIPT_FILENAME"=>"/home/kevinc/sites/typo/public/dispatch.fcgi", "REDIRECT_STATUS"=>"200", "REQUEST_METHOD"=>"GET"}
+ @env = {
+ "HTTP_MAX_FORWARDS" => "10",
+ "SERVER_NAME" => "glu.ttono.us:8007",
+ "FCGI_ROLE" => "RESPONDER",
+ "HTTP_X_FORWARDED_HOST" => "glu.ttono.us",
+ "HTTP_ACCEPT_ENCODING" => "gzip, deflate",
+ "HTTP_USER_AGENT" => "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)",
+ "PATH_INFO" => "",
+ "HTTP_ACCEPT_LANGUAGE" => "en",
+ "HTTP_HOST" => "glu.ttono.us:8007",
+ "SERVER_PROTOCOL" => "HTTP/1.1",
+ "REDIRECT_URI" => "/dispatch.fcgi",
+ "SCRIPT_NAME" => "/dispatch.fcgi",
+ "SERVER_ADDR" => "207.7.108.53",
+ "REMOTE_ADDR" => "207.7.108.53",
+ "SERVER_SOFTWARE" => "lighttpd/1.4.5",
+ "HTTP_COOKIE" => "_session_id=c84ace84796670c052c6ceb2451fb0f2; is_admin=yes",
+ "HTTP_X_FORWARDED_SERVER" => "glu.ttono.us",
+ "REQUEST_URI" => "/admin",
+ "DOCUMENT_ROOT" => "/home/kevinc/sites/typo/public",
+ "SERVER_PORT" => "8007",
+ "QUERY_STRING" => "",
+ "REMOTE_PORT" => "63137",
+ "GATEWAY_INTERFACE" => "CGI/1.1",
+ "HTTP_X_FORWARDED_FOR" => "65.88.180.234",
+ "HTTP_ACCEPT" => "*/*",
+ "SCRIPT_FILENAME" => "/home/kevinc/sites/typo/public/dispatch.fcgi",
+ "REDIRECT_STATUS" => "200",
+ "REQUEST_METHOD" => "GET"
+ }
+ @request = ActionController::RackRequest.new(@env)
# some Nokia phone browsers omit the space after the semicolon separator.
# some developers have grown accustomed to using comma in cookie values.
- @alt_cookie_fmt_request_hash = {"HTTP_COOKIE"=>"_session_id=c84ace847,96670c052c6ceb2451fb0f2;is_admin=yes"}
- @request = ActionController::RackRequest.new(@env)
+ @alt_cookie_fmt_request = ActionController::RackRequest.new(@env.merge({"HTTP_COOKIE"=>"_session_id=c84ace847,96670c052c6ceb2451fb0f2;is_admin=yes"}))
end
def default_test; end
@@ -71,11 +100,11 @@ class RackRequestTest < BaseRackTest
end
def test_cookie_syntax_resilience
- cookies = CGI::Cookie::parse(@env["HTTP_COOKIE"]);
+ cookies = @request.cookies
assert_equal ["c84ace84796670c052c6ceb2451fb0f2"], cookies["_session_id"], cookies.inspect
assert_equal ["yes"], cookies["is_admin"], cookies.inspect
- alt_cookies = CGI::Cookie::parse(@alt_cookie_fmt_request_hash["HTTP_COOKIE"]);
+ alt_cookies = @alt_cookie_fmt_request.cookies
assert_equal ["c84ace847,96670c052c6ceb2451fb0f2"], alt_cookies["_session_id"], alt_cookies.inspect
assert_equal ["yes"], alt_cookies["is_admin"], alt_cookies.inspect
end
@@ -118,7 +147,7 @@ end
class RackResponseTest < BaseRackTest
def setup
super
- @response = ActionController::RackResponse.new
+ @response = ActionController::RackResponse.new(@request)
@output = StringIO.new('')
end
@@ -127,7 +156,7 @@ class RackResponseTest < BaseRackTest
status, headers, body = @response.out(@output)
assert_equal 200, status
- assert_equal({"Content-Type" => "text/html", "Cache-Control" => "no-cache", "Set-Cookie" => ""}, headers)
+ assert_equal({"Content-Type" => "text/html", "Cache-Control" => "no-cache", "Set-Cookie" => []}, headers)
parts = []
body.each { |part| parts << part }
@@ -141,10 +170,29 @@ class RackResponseTest < BaseRackTest
status, headers, body = @response.out(@output)
assert_equal 200, status
- assert_equal({"Content-Type" => "text/html", "Cache-Control" => "no-cache", "Set-Cookie" => ""}, headers)
+ assert_equal({"Content-Type" => "text/html", "Cache-Control" => "no-cache", "Set-Cookie" => []}, headers)
parts = []
body.each { |part| parts << part }
assert_equal ["0", "1", "2", "3", "4"], parts
end
+
+ def test_set_session_cookie
+ cookie = CGI::Cookie.new({"name" => "name", "value" => "Josh"})
+ @request.cgi.send :instance_variable_set, '@output_cookies', [cookie]
+
+ @response.body = "Hello, World!"
+
+ status, headers, body = @response.out(@output)
+ assert_equal 200, status
+ assert_equal({
+ "Content-Type" => "text/html",
+ "Cache-Control" => "no-cache",
+ "Set-Cookie" => ["name=Josh; path="]
+ }, headers)
+
+ parts = []
+ body.each { |part| parts << part }
+ assert_equal ["Hello, World!"], parts
+ end
end
diff --git a/actionpack/test/controller/request_test.rb b/actionpack/test/controller/request_test.rb
index 82ddfec8e8..2bd489b2c7 100644
--- a/actionpack/test/controller/request_test.rb
+++ b/actionpack/test/controller/request_test.rb
@@ -59,6 +59,9 @@ class RequestTest < Test::Unit::TestCase
assert_match /HTTP_X_FORWARDED_FOR="9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4"/, e.message
assert_match /HTTP_CLIENT_IP="8.8.8.8"/, e.message
+ @request.env['HTTP_X_FORWARDED_FOR'] = '8.8.8.8, 9.9.9.9'
+ assert_equal '8.8.8.8', @request.remote_ip
+
@request.env.delete 'HTTP_CLIENT_IP'
@request.env.delete 'HTTP_X_FORWARDED_FOR'
end
diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb
index 5e5503fd52..07c13ebbf7 100644
--- a/actionpack/test/controller/routing_test.rb
+++ b/actionpack/test/controller/routing_test.rb
@@ -59,647 +59,30 @@ class UriReservedCharactersRoutingTest < Test::Unit::TestCase
end
end
-class LegacyRouteSetTests < Test::Unit::TestCase
- attr_reader :rs
- def setup
- # These tests assume optimisation is on, so re-enable it.
- ActionController::Base.optimise_named_routes = true
-
- @rs = ::ActionController::Routing::RouteSet.new
- @rs.draw {|m| m.connect ':controller/:action/:id' }
-
- ActionController::Routing.use_controllers! %w(content admin/user admin/news_feed)
- end
-
- def test_default_setup
- assert_equal({:controller => "content", :action => 'index'}, rs.recognize_path("/content"))
- assert_equal({:controller => "content", :action => 'list'}, rs.recognize_path("/content/list"))
- assert_equal({:controller => "content", :action => 'show', :id => '10'}, rs.recognize_path("/content/show/10"))
-
- assert_equal({:controller => "admin/user", :action => 'show', :id => '10'}, rs.recognize_path("/admin/user/show/10"))
-
- assert_equal '/admin/user/show/10', rs.generate(:controller => 'admin/user', :action => 'show', :id => 10)
-
- assert_equal '/admin/user/show', rs.generate({:action => 'show'}, {:controller => 'admin/user', :action => 'list', :id => '10'})
- assert_equal '/admin/user/list/10', rs.generate({}, {:controller => 'admin/user', :action => 'list', :id => '10'})
-
- assert_equal '/admin/stuff', rs.generate({:controller => 'stuff'}, {:controller => 'admin/user', :action => 'list', :id => '10'})
- assert_equal '/stuff', rs.generate({:controller => '/stuff'}, {:controller => 'admin/user', :action => 'list', :id => '10'})
- end
-
- def test_ignores_leading_slash
- @rs.draw {|m| m.connect '/:controller/:action/:id'}
- test_default_setup
- end
-
- def test_time_recognition
- # We create many routes to make situation more realistic
- @rs = ::ActionController::Routing::RouteSet.new
- @rs.draw { |map|
- map.frontpage '', :controller => 'search', :action => 'new'
- map.resources :videos do |video|
- video.resources :comments
- video.resource :file, :controller => 'video_file'
- video.resource :share, :controller => 'video_shares'
- video.resource :abuse, :controller => 'video_abuses'
- end
- map.resources :abuses, :controller => 'video_abuses'
- map.resources :video_uploads
- map.resources :video_visits
-
- map.resources :users do |user|
- user.resource :settings
- user.resources :videos
- end
- map.resources :channels do |channel|
- channel.resources :videos, :controller => 'channel_videos'
- end
- map.resource :session
- map.resource :lost_password
- map.search 'search', :controller => 'search'
- map.resources :pages
- map.connect ':controller/:action/:id'
- }
- n = 1000
- if RunTimeTests
- GC.start
- rectime = Benchmark.realtime do
- n.times do
- rs.recognize_path("/videos/1234567", {:method => :get})
- rs.recognize_path("/videos/1234567/abuse", {:method => :get})
- rs.recognize_path("/users/1234567/settings", {:method => :get})
- rs.recognize_path("/channels/1234567", {:method => :get})
- rs.recognize_path("/session/new", {:method => :get})
- rs.recognize_path("/admin/user/show/10", {:method => :get})
- end
- end
- puts "\n\nRecognition (#{rs.routes.size} routes):"
- per_url = rectime / (n * 6)
- puts "#{per_url * 1000} ms/url"
- puts "#{1 / per_url} url/s\n\n"
- end
- end
- def test_time_generation
- n = 5000
- if RunTimeTests
- GC.start
- pairs = [
- [{:controller => 'content', :action => 'index'}, {:controller => 'content', :action => 'show'}],
- [{:controller => 'content'}, {:controller => 'content', :action => 'index'}],
- [{:controller => 'content', :action => 'list'}, {:controller => 'content', :action => 'index'}],
- [{:controller => 'content', :action => 'show', :id => '10'}, {:controller => 'content', :action => 'list'}],
- [{:controller => 'admin/user', :action => 'index'}, {:controller => 'admin/user', :action => 'show'}],
- [{:controller => 'admin/user'}, {:controller => 'admin/user', :action => 'index'}],
- [{:controller => 'admin/user', :action => 'list'}, {:controller => 'admin/user', :action => 'index'}],
- [{:controller => 'admin/user', :action => 'show', :id => '10'}, {:controller => 'admin/user', :action => 'list'}],
- ]
- p = nil
- gentime = Benchmark.realtime do
- n.times do
- pairs.each {|(a, b)| rs.generate(a, b)}
- end
- end
-
- puts "\n\nGeneration (RouteSet): (#{(n * 8)} urls)"
- per_url = gentime / (n * 8)
- puts "#{per_url * 1000} ms/url"
- puts "#{1 / per_url} url/s\n\n"
- end
- end
-
- def test_route_with_colon_first
- rs.draw do |map|
- map.connect '/:controller/:action/:id', :action => 'index', :id => nil
- map.connect ':url', :controller => 'tiny_url', :action => 'translate'
- end
- end
-
- def test_route_with_regexp_for_controller
- rs.draw do |map|
- map.connect ':controller/:admintoken/:action/:id', :controller => /admin\/.+/
- map.connect ':controller/:action/:id'
- end
- assert_equal({:controller => "admin/user", :admintoken => "foo", :action => "index"},
- rs.recognize_path("/admin/user/foo"))
- assert_equal({:controller => "content", :action => "foo"}, rs.recognize_path("/content/foo"))
- assert_equal '/admin/user/foo', rs.generate(:controller => "admin/user", :admintoken => "foo", :action => "index")
- assert_equal '/content/foo', rs.generate(:controller => "content", :action => "foo")
- end
-
- def test_route_with_regexp_and_dot
- rs.draw do |map|
- map.connect ':controller/:action/:file',
- :controller => /admin|user/,
- :action => /upload|download/,
- :defaults => {:file => nil},
- :requirements => {:file => %r{[^/]+(\.[^/]+)?}}
- end
- # Without a file extension
- assert_equal '/user/download/file',
- rs.generate(:controller => "user", :action => "download", :file => "file")
- assert_equal(
- {:controller => "user", :action => "download", :file => "file"},
- rs.recognize_path("/user/download/file"))
-
- # Now, let's try a file with an extension, really a dot (.)
- assert_equal '/user/download/file.jpg',
- rs.generate(
- :controller => "user", :action => "download", :file => "file.jpg")
- assert_equal(
- {:controller => "user", :action => "download", :file => "file.jpg"},
- rs.recognize_path("/user/download/file.jpg"))
- end
-
- def test_basic_named_route
- rs.add_named_route :home, '', :controller => 'content', :action => 'list'
- x = setup_for_named_route
- assert_equal("http://named.route.test/",
- x.send(:home_url))
- end
-
- def test_basic_named_route_with_relative_url_root
- rs.add_named_route :home, '', :controller => 'content', :action => 'list'
- x = setup_for_named_route
- x.relative_url_root="/foo"
- assert_equal("http://named.route.test/foo/",
- x.send(:home_url))
- assert_equal "/foo/", x.send(:home_path)
- end
-
- def test_named_route_with_option
- rs.add_named_route :page, 'page/:title', :controller => 'content', :action => 'show_page'
- x = setup_for_named_route
- assert_equal("http://named.route.test/page/new%20stuff",
- x.send(:page_url, :title => 'new stuff'))
- end
-
- def test_named_route_with_default
- rs.add_named_route :page, 'page/:title', :controller => 'content', :action => 'show_page', :title => 'AboutPage'
- x = setup_for_named_route
- assert_equal("http://named.route.test/page/AboutRails",
- x.send(:page_url, :title => "AboutRails"))
-
- end
-
- def test_named_route_with_nested_controller
- rs.add_named_route :users, 'admin/user', :controller => 'admin/user', :action => 'index'
- x = setup_for_named_route
- assert_equal("http://named.route.test/admin/user",
- x.send(:users_url))
- end
-
- uses_mocha "named route optimisation" do
- def test_optimised_named_route_call_never_uses_url_for
- rs.add_named_route :users, 'admin/user', :controller => '/admin/user', :action => 'index'
- rs.add_named_route :user, 'admin/user/:id', :controller=>'/admin/user', :action=>'show'
- x = setup_for_named_route
- x.expects(:url_for).never
- x.send(:users_url)
- x.send(:users_path)
- x.send(:user_url, 2, :foo=>"bar")
- x.send(:user_path, 3, :bar=>"foo")
- end
-
- def test_optimised_named_route_with_host
- rs.add_named_route :pages, 'pages', :controller => 'content', :action => 'show_page', :host => 'foo.com'
- x = setup_for_named_route
- x.expects(:url_for).with(:host => 'foo.com', :only_path => false, :controller => 'content', :action => 'show_page', :use_route => :pages).once
- x.send(:pages_url)
- end
- end
-
- def setup_for_named_route
- klass = Class.new(MockController)
- rs.install_helpers(klass)
- klass.new(rs)
- end
-
- def test_named_route_without_hash
- rs.draw do |map|
- map.normal ':controller/:action/:id'
- end
- end
-
- def test_named_route_root
- rs.draw do |map|
- map.root :controller => "hello"
- end
- x = setup_for_named_route
- assert_equal("http://named.route.test/", x.send(:root_url))
- assert_equal("/", x.send(:root_path))
- end
-
- def test_named_route_with_regexps
- rs.draw do |map|
- map.article 'page/:year/:month/:day/:title', :controller => 'page', :action => 'show',
- :year => /\d+/, :month => /\d+/, :day => /\d+/
- map.connect ':controller/:action/:id'
- end
- x = setup_for_named_route
- # assert_equal(
- # {:controller => 'page', :action => 'show', :title => 'hi', :use_route => :article, :only_path => false},
- # x.send(:article_url, :title => 'hi')
- # )
- assert_equal(
- "http://named.route.test/page/2005/6/10/hi",
- x.send(:article_url, :title => 'hi', :day => 10, :year => 2005, :month => 6)
- )
- end
-
- def test_changing_controller
- assert_equal '/admin/stuff/show/10', rs.generate(
- {:controller => 'stuff', :action => 'show', :id => 10},
- {:controller => 'admin/user', :action => 'index'}
- )
- end
-
- def test_paths_escaped
- rs.draw do |map|
- map.path 'file/*path', :controller => 'content', :action => 'show_file'
- map.connect ':controller/:action/:id'
- end
-
- # No + to space in URI escaping, only for query params.
- results = rs.recognize_path "/file/hello+world/how+are+you%3F"
- assert results, "Recognition should have succeeded"
- assert_equal ['hello+world', 'how+are+you?'], results[:path]
-
- # Use %20 for space instead.
- results = rs.recognize_path "/file/hello%20world/how%20are%20you%3F"
- assert results, "Recognition should have succeeded"
- assert_equal ['hello world', 'how are you?'], results[:path]
-
- results = rs.recognize_path "/file"
- assert results, "Recognition should have succeeded"
- assert_equal [], results[:path]
- end
-
- def test_paths_slashes_unescaped_with_ordered_parameters
- rs.add_named_route :path, '/file/*path', :controller => 'content'
-
- # No / to %2F in URI, only for query params.
- x = setup_for_named_route
- assert_equal("/file/hello/world", x.send(:path_path, 'hello/world'))
- end
-
- def test_non_controllers_cannot_be_matched
- rs.draw do |map|
- map.connect ':controller/:action/:id'
- end
- assert_raises(ActionController::RoutingError) { rs.recognize_path("/not_a/show/10") }
- end
-
- def test_paths_do_not_accept_defaults
- assert_raises(ActionController::RoutingError) do
- rs.draw do |map|
- map.path 'file/*path', :controller => 'content', :action => 'show_file', :path => %w(fake default)
- map.connect ':controller/:action/:id'
- end
- end
-
- rs.draw do |map|
- map.path 'file/*path', :controller => 'content', :action => 'show_file', :path => []
- map.connect ':controller/:action/:id'
- end
- end
-
- def test_should_list_options_diff_when_routing_requirements_dont_match
- rs.draw do |map|
- map.post 'post/:id', :controller=> 'post', :action=> 'show', :requirements => {:id => /\d+/}
- end
- exception = assert_raise(ActionController::RoutingError) { rs.generate(:controller => 'post', :action => 'show', :bad_param => "foo", :use_route => "post") }
- assert_match /^post_url failed to generate/, exception.message
- from_match = exception.message.match(/from \{[^\}]+\}/).to_s
- assert_match /:bad_param=>"foo"/, from_match
- assert_match /:action=>"show"/, from_match
- assert_match /:controller=>"post"/, from_match
-
- expected_match = exception.message.match(/expected: \{[^\}]+\}/).to_s
- assert_no_match /:bad_param=>"foo"/, expected_match
- assert_match /:action=>"show"/, expected_match
- assert_match /:controller=>"post"/, expected_match
-
- diff_match = exception.message.match(/diff: \{[^\}]+\}/).to_s
- assert_match /:bad_param=>"foo"/, diff_match
- assert_no_match /:action=>"show"/, diff_match
- assert_no_match /:controller=>"post"/, diff_match
- end
-
- # this specifies the case where your formerly would get a very confusing error message with an empty diff
- def test_should_have_better_error_message_when_options_diff_is_empty
- rs.draw do |map|
- map.content '/content/:query', :controller => 'content', :action => 'show'
- end
-
- exception = assert_raise(ActionController::RoutingError) { rs.generate(:controller => 'content', :action => 'show', :use_route => "content") }
- assert_match %r[:action=>"show"], exception.message
- assert_match %r[:controller=>"content"], exception.message
- assert_match %r[you may have ambiguous routes, or you may need to supply additional parameters for this route], exception.message
- assert_match %r[content_url has the following required parameters: \["content", :query\] - are they all satisfied?], exception.message
- end
-
- def test_dynamic_path_allowed
- rs.draw do |map|
- map.connect '*path', :controller => 'content', :action => 'show_file'
- end
-
- assert_equal '/pages/boo', rs.generate(:controller => 'content', :action => 'show_file', :path => %w(pages boo))
- end
-
- def test_dynamic_recall_paths_allowed
- rs.draw do |map|
- map.connect '*path', :controller => 'content', :action => 'show_file'
- end
-
- recall_path = ActionController::Routing::PathSegment::Result.new(%w(pages boo))
- assert_equal '/pages/boo', rs.generate({}, :controller => 'content', :action => 'show_file', :path => recall_path)
- end
-
- def test_backwards
- rs.draw do |map|
- map.connect 'page/:id/:action', :controller => 'pages', :action => 'show'
- map.connect ':controller/:action/:id'
- end
-
- assert_equal '/page/20', rs.generate({:id => 20}, {:controller => 'pages', :action => 'show'})
- assert_equal '/page/20', rs.generate(:controller => 'pages', :id => 20, :action => 'show')
- assert_equal '/pages/boo', rs.generate(:controller => 'pages', :action => 'boo')
- end
-
- def test_route_with_fixnum_default
- rs.draw do |map|
- map.connect 'page/:id', :controller => 'content', :action => 'show_page', :id => 1
- map.connect ':controller/:action/:id'
- end
-
- assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page')
- assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page', :id => 1)
- assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page', :id => '1')
- assert_equal '/page/10', rs.generate(:controller => 'content', :action => 'show_page', :id => 10)
-
- assert_equal({:controller => "content", :action => 'show_page', :id => '1'}, rs.recognize_path("/page"))
- assert_equal({:controller => "content", :action => 'show_page', :id => '1'}, rs.recognize_path("/page/1"))
- assert_equal({:controller => "content", :action => 'show_page', :id => '10'}, rs.recognize_path("/page/10"))
- end
-
- # For newer revision
- def test_route_with_text_default
- rs.draw do |map|
- map.connect 'page/:id', :controller => 'content', :action => 'show_page', :id => 1
- map.connect ':controller/:action/:id'
- end
-
- assert_equal '/page/foo', rs.generate(:controller => 'content', :action => 'show_page', :id => 'foo')
- assert_equal({:controller => "content", :action => 'show_page', :id => 'foo'}, rs.recognize_path("/page/foo"))
-
- token = "\321\202\320\265\320\272\321\201\321\202" # 'text' in russian
- escaped_token = CGI::escape(token)
-
- assert_equal '/page/' + escaped_token, rs.generate(:controller => 'content', :action => 'show_page', :id => token)
- assert_equal({:controller => "content", :action => 'show_page', :id => token}, rs.recognize_path("/page/#{escaped_token}"))
- end
-
- def test_action_expiry
- assert_equal '/content', rs.generate({:controller => 'content'}, {:controller => 'content', :action => 'show'})
- end
-
- def test_recognition_with_uppercase_controller_name
- assert_equal({:controller => "content", :action => 'index'}, rs.recognize_path("/Content"))
- assert_equal({:controller => "content", :action => 'list'}, rs.recognize_path("/ConTent/list"))
- assert_equal({:controller => "content", :action => 'show', :id => '10'}, rs.recognize_path("/CONTENT/show/10"))
-
- # these used to work, before the routes rewrite, but support for this was pulled in the new version...
- #assert_equal({'controller' => "admin/news_feed", 'action' => 'index'}, rs.recognize_path("Admin/NewsFeed"))
- #assert_equal({'controller' => "admin/news_feed", 'action' => 'index'}, rs.recognize_path("Admin/News_Feed"))
- end
-
- def test_requirement_should_prevent_optional_id
- rs.draw do |map|
- map.post 'post/:id', :controller=> 'post', :action=> 'show', :requirements => {:id => /\d+/}
- end
-
- assert_equal '/post/10', rs.generate(:controller => 'post', :action => 'show', :id => 10)
-
- assert_raises ActionController::RoutingError do
- rs.generate(:controller => 'post', :action => 'show')
- end
- end
-
- def test_both_requirement_and_optional
- rs.draw do |map|
- map.blog('test/:year', :controller => 'post', :action => 'show',
- :defaults => { :year => nil },
- :requirements => { :year => /\d{4}/ }
- )
- map.connect ':controller/:action/:id'
- end
-
- assert_equal '/test', rs.generate(:controller => 'post', :action => 'show')
- assert_equal '/test', rs.generate(:controller => 'post', :action => 'show', :year => nil)
-
- x = setup_for_named_route
- assert_equal("http://named.route.test/test",
- x.send(:blog_url))
- end
-
- def test_set_to_nil_forgets
- rs.draw do |map|
- map.connect 'pages/:year/:month/:day', :controller => 'content', :action => 'list_pages', :month => nil, :day => nil
- map.connect ':controller/:action/:id'
- end
-
- assert_equal '/pages/2005',
- rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005)
- assert_equal '/pages/2005/6',
- rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005, :month => 6)
- assert_equal '/pages/2005/6/12',
- rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005, :month => 6, :day => 12)
-
- assert_equal '/pages/2005/6/4',
- rs.generate({:day => 4}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'})
-
- assert_equal '/pages/2005/6',
- rs.generate({:day => nil}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'})
-
- assert_equal '/pages/2005',
- rs.generate({:day => nil, :month => nil}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'})
- end
-
- def test_url_with_no_action_specified
- rs.draw do |map|
- map.connect '', :controller => 'content'
- map.connect ':controller/:action/:id'
- end
-
- assert_equal '/', rs.generate(:controller => 'content', :action => 'index')
- assert_equal '/', rs.generate(:controller => 'content')
- end
-
- def test_named_url_with_no_action_specified
- rs.draw do |map|
- map.home '', :controller => 'content'
- map.connect ':controller/:action/:id'
- end
-
- assert_equal '/', rs.generate(:controller => 'content', :action => 'index')
- assert_equal '/', rs.generate(:controller => 'content')
-
- x = setup_for_named_route
- assert_equal("http://named.route.test/",
- x.send(:home_url))
- end
-
- def test_url_generated_when_forgetting_action
- [{:controller => 'content', :action => 'index'}, {:controller => 'content'}].each do |hash|
- rs.draw do |map|
- map.home '', hash
- map.connect ':controller/:action/:id'
- end
- assert_equal '/', rs.generate({:action => nil}, {:controller => 'content', :action => 'hello'})
- assert_equal '/', rs.generate({:controller => 'content'})
- assert_equal '/content/hi', rs.generate({:controller => 'content', :action => 'hi'})
- end
- end
-
- def test_named_route_method
- rs.draw do |map|
- map.categories 'categories', :controller => 'content', :action => 'categories'
- map.connect ':controller/:action/:id'
- end
-
- assert_equal '/categories', rs.generate(:controller => 'content', :action => 'categories')
- assert_equal '/content/hi', rs.generate({:controller => 'content', :action => 'hi'})
- end
-
- def test_named_routes_array
- test_named_route_method
- assert_equal [:categories], rs.named_routes.names
- end
-
- def test_nil_defaults
- rs.draw do |map|
- map.connect 'journal',
- :controller => 'content',
- :action => 'list_journal',
- :date => nil, :user_id => nil
- map.connect ':controller/:action/:id'
- end
-
- assert_equal '/journal', rs.generate(:controller => 'content', :action => 'list_journal', :date => nil, :user_id => nil)
- 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 }
- r.connect '/match', :controller => 'books', :action => 'put', :conditions => { :method => :put }
- r.connect '/match', :controller => 'books', :action => 'delete', :conditions => { :method => :delete }
- end
- end
-
- %w(GET POST PUT DELETE).each do |request_method|
- define_method("test_request_method_recognized_with_#{request_method}") do
- begin
- Object.const_set(:BooksController, Class.new(ActionController::Base))
-
- setup_request_method_routes_for(request_method)
-
- assert_nothing_raised { rs.recognize(@request) }
- assert_equal request_method.downcase, @request.path_parameters[:action]
- ensure
- Object.send(:remove_const, :BooksController) rescue nil
- end
- end
- end
-
- def test_subpath_recognized
- Object.const_set(:SubpathBooksController, Class.new(ActionController::Base))
-
- rs.draw do |r|
- r.connect '/books/:id/edit', :controller => 'subpath_books', :action => 'edit'
- r.connect '/items/:id/:action', :controller => 'subpath_books'
- r.connect '/posts/new/:action', :controller => 'subpath_books'
- r.connect '/posts/:id', :controller => 'subpath_books', :action => "show"
- end
-
- hash = rs.recognize_path "/books/17/edit"
- assert_not_nil hash
- assert_equal %w(subpath_books 17 edit), [hash[:controller], hash[:id], hash[:action]]
-
- hash = rs.recognize_path "/items/3/complete"
- assert_not_nil hash
- assert_equal %w(subpath_books 3 complete), [hash[:controller], hash[:id], hash[:action]]
-
- hash = rs.recognize_path "/posts/new/preview"
- assert_not_nil hash
- assert_equal %w(subpath_books preview), [hash[:controller], hash[:action]]
-
- hash = rs.recognize_path "/posts/7"
- assert_not_nil hash
- assert_equal %w(subpath_books show 7), [hash[:controller], hash[:action], hash[:id]]
- ensure
- Object.send(:remove_const, :SubpathBooksController) rescue nil
- end
-
- def test_subpath_generated
- Object.const_set(:SubpathBooksController, Class.new(ActionController::Base))
-
- rs.draw do |r|
- r.connect '/books/:id/edit', :controller => 'subpath_books', :action => 'edit'
- r.connect '/items/:id/:action', :controller => 'subpath_books'
- r.connect '/posts/new/:action', :controller => 'subpath_books'
- end
-
- assert_equal "/books/7/edit", rs.generate(:controller => "subpath_books", :id => 7, :action => "edit")
- assert_equal "/items/15/complete", rs.generate(:controller => "subpath_books", :id => 15, :action => "complete")
- assert_equal "/posts/new/preview", rs.generate(:controller => "subpath_books", :action => "preview")
- ensure
- Object.send(:remove_const, :SubpathBooksController) rescue nil
- end
-
- def test_failed_requirements_raises_exception_with_violated_requirements
- rs.draw do |r|
- r.foo_with_requirement 'foos/:id', :controller=>'foos', :requirements=>{:id=>/\d+/}
- end
-
- x = setup_for_named_route
- assert_raises(ActionController::RoutingError) do
- x.send(:foo_with_requirement_url, "I am Against the requirements")
- end
- end
-end
-
class SegmentTest < Test::Unit::TestCase
-
def test_first_segment_should_interpolate_for_structure
s = ROUTING::Segment.new
def s.interpolation_statement(array) 'hello' end
assert_equal 'hello', s.continue_string_structure([])
end
-
+
def test_interpolation_statement
s = ROUTING::StaticSegment.new
s.value = "Hello"
assert_equal "Hello", eval(s.interpolation_statement([]))
assert_equal "HelloHello", eval(s.interpolation_statement([s]))
-
+
s2 = ROUTING::StaticSegment.new
s2.value = "-"
assert_equal "Hello-Hello", eval(s.interpolation_statement([s, s2]))
-
+
s3 = ROUTING::StaticSegment.new
s3.value = "World"
assert_equal "Hello-World", eval(s3.interpolation_statement([s, s2]))
end
-
end
class StaticSegmentTest < Test::Unit::TestCase
-
def test_interpolation_chunk_should_respect_raw
s = ROUTING::StaticSegment.new
s.value = 'Hello World'
@@ -713,28 +96,26 @@ class StaticSegmentTest < Test::Unit::TestCase
def test_regexp_chunk_should_escape_specials
s = ROUTING::StaticSegment.new
-
+
s.value = 'Hello*World'
assert_equal 'Hello\*World', s.regexp_chunk
-
+
s.value = 'HelloWorld'
assert_equal 'HelloWorld', s.regexp_chunk
end
-
+
def test_regexp_chunk_should_add_question_mark_for_optionals
s = ROUTING::StaticSegment.new
s.value = "/"
s.is_optional = true
assert_equal "/?", s.regexp_chunk
-
+
s.value = "hello"
assert_equal "(?:hello)?", s.regexp_chunk
end
-
end
class DynamicSegmentTest < Test::Unit::TestCase
-
def segment
unless @segment
@segment = ROUTING::DynamicSegment.new
@@ -742,126 +123,126 @@ class DynamicSegmentTest < Test::Unit::TestCase
end
@segment
end
-
+
def test_extract_value
s = ROUTING::DynamicSegment.new
s.key = :a
-
+
hash = {:a => '10', :b => '20'}
assert_equal '10', eval(s.extract_value)
-
+
hash = {:b => '20'}
assert_equal nil, eval(s.extract_value)
-
+
s.default = '20'
assert_equal '20', eval(s.extract_value)
end
-
+
def test_default_local_name
assert_equal 'a_value', segment.local_name,
"Unexpected name -- all value_check tests will fail!"
end
-
+
def test_presence_value_check
a_value = 10
assert eval(segment.value_check)
end
-
+
def test_regexp_value_check_rejects_nil
segment.regexp = /\d+/
a_value = nil
assert ! eval(segment.value_check)
end
-
+
def test_optional_regexp_value_check_should_accept_nil
segment.regexp = /\d+/
segment.is_optional = true
a_value = nil
assert eval(segment.value_check)
end
-
+
def test_regexp_value_check_rejects_no_match
segment.regexp = /\d+/
-
+
a_value = "Hello20World"
assert ! eval(segment.value_check)
-
+
a_value = "20Hi"
assert ! eval(segment.value_check)
end
-
+
def test_regexp_value_check_accepts_match
segment.regexp = /\d+/
-
+
a_value = "30"
assert eval(segment.value_check)
end
-
+
def test_value_check_fails_on_nil
a_value = nil
assert ! eval(segment.value_check)
end
-
+
def test_optional_value_needs_no_check
segment.is_optional = true
a_value = nil
assert_equal nil, segment.value_check
end
-
+
def test_regexp_value_check_should_accept_match_with_default
segment.regexp = /\d+/
segment.default = '200'
-
+
a_value = '100'
assert eval(segment.value_check)
end
-
+
def test_expiry_should_not_trigger_once_expired
expired = true
hash = merged = {:a => 2, :b => 3}
options = {:b => 3}
expire_on = Hash.new { raise 'No!!!' }
-
+
eval(segment.expiry_statement)
rescue RuntimeError
flunk "Expiry check should not have occurred!"
end
-
+
def test_expiry_should_occur_according_to_expire_on
expired = false
hash = merged = {:a => 2, :b => 3}
options = {:b => 3}
-
+
expire_on = {:b => true, :a => false}
eval(segment.expiry_statement)
assert !expired
assert_equal({:a => 2, :b => 3}, hash)
-
+
expire_on = {:b => true, :a => true}
eval(segment.expiry_statement)
assert expired
assert_equal({:b => 3}, hash)
end
-
+
def test_extraction_code_should_return_on_nil
hash = merged = {:b => 3}
options = {:b => 3}
a_value = nil
-
+
# Local jump because of return inside eval.
assert_raises(LocalJumpError) { eval(segment.extraction_code) }
end
-
+
def test_extraction_code_should_return_on_mismatch
segment.regexp = /\d+/
hash = merged = {:a => 'Hi', :b => '3'}
options = {:b => '3'}
a_value = nil
-
+
# Local jump because of return inside eval.
assert_raises(LocalJumpError) { eval(segment.extraction_code) }
end
-
+
def test_extraction_code_should_accept_value_and_set_local
hash = merged = {:a => 'Hi', :b => '3'}
options = {:b => '3'}
@@ -871,45 +252,45 @@ class DynamicSegmentTest < Test::Unit::TestCase
eval(segment.extraction_code)
assert_equal 'Hi', a_value
end
-
+
def test_extraction_should_work_without_value_check
segment.default = 'hi'
hash = merged = {:b => '3'}
options = {:b => '3'}
a_value = nil
expired = true
-
+
eval(segment.extraction_code)
assert_equal 'hi', a_value
end
-
+
def test_extraction_code_should_perform_expiry
expired = false
hash = merged = {:a => 'Hi', :b => '3'}
options = {:b => '3'}
expire_on = {:a => true}
a_value = nil
-
+
eval(segment.extraction_code)
assert_equal 'Hi', a_value
assert expired
assert_equal options, hash
end
-
+
def test_interpolation_chunk_should_replace_value
a_value = 'Hi'
assert_equal a_value, eval(%("#{segment.interpolation_chunk}"))
end
-
+
def test_interpolation_chunk_should_accept_nil
a_value = nil
assert_equal '', eval(%("#{segment.interpolation_chunk('a_value')}"))
end
-
+
def test_value_regexp_should_be_nil_without_regexp
assert_equal nil, segment.value_regexp
end
-
+
def test_value_regexp_should_match_exacly
segment.regexp = /\d+/
assert_no_match segment.value_regexp, "Hello 10 World"
@@ -917,12 +298,12 @@ class DynamicSegmentTest < Test::Unit::TestCase
assert_no_match segment.value_regexp, "10 World"
assert_match segment.value_regexp, "10"
end
-
+
def test_regexp_chunk_should_return_string
segment.regexp = /\d+/
assert_kind_of String, segment.regexp_chunk
end
-
+
def test_build_pattern_non_optional_with_no_captures
# Non optional
a_segment = ROUTING::DynamicSegment.new
@@ -958,264 +339,23 @@ class DynamicSegmentTest < Test::Unit::TestCase
end
class ControllerSegmentTest < Test::Unit::TestCase
-
def test_regexp_should_only_match_possible_controllers
ActionController::Routing.with_controllers %w(admin/accounts admin/users account pages) do
cs = ROUTING::ControllerSegment.new :controller
regexp = %r{\A#{cs.regexp_chunk}\Z}
-
+
ActionController::Routing.possible_controllers.each do |name|
assert_match regexp, name
assert_no_match regexp, "#{name}_fake"
-
+
match = regexp.match name
assert_equal name, match[1]
end
end
end
-
-end
-
-uses_mocha 'RouteTest' do
-
- class MockController
- attr_accessor :routes
-
- def initialize(routes)
- self.routes = routes
- end
-
- def url_for(options)
- only_path = options.delete(:only_path)
-
- port = options.delete(:port) || 80
- port_string = port == 80 ? '' : ":#{port}"
-
- host = options.delete(:host) || "named.route.test"
- anchor = "##{options.delete(:anchor)}" if options.key?(:anchor)
-
- path = routes.generate(options)
-
- only_path ? "#{path}#{anchor}" : "http://#{host}#{port_string}#{path}#{anchor}"
- end
-
- def request
- @request ||= MockRequest.new(:host => "named.route.test", :method => :get)
- end
-
- def relative_url_root=(value)
- request.relative_url_root=value
- end
- end
-
- class MockRequest
- attr_accessor :path, :path_parameters, :host, :subdomains, :domain,
- :method, :relative_url_root
-
- def initialize(values={})
- values.each { |key, value| send("#{key}=", value) }
- if values[:host]
- subdomain, self.domain = values[:host].split(/\./, 2)
- self.subdomains = [subdomain]
- end
- end
-
- def protocol
- "http://"
- end
-
- def host_with_port
- (subdomains * '.') + '.' + domain
- end
- end
-
-class RouteTest < Test::Unit::TestCase
-
- def setup
- @route = ROUTING::Route.new
- end
-
- def slash_segment(is_optional = false)
- returning ROUTING::DividerSegment.new('/') do |s|
- s.is_optional = is_optional
- end
- end
-
- def default_route
- unless defined?(@default_route)
- @default_route = ROUTING::Route.new
-
- @default_route.segments << (s = ROUTING::StaticSegment.new)
- s.value = '/'
- s.raw = true
-
- @default_route.segments << (s = ROUTING::DynamicSegment.new)
- s.key = :controller
-
- @default_route.segments << slash_segment(:optional)
- @default_route.segments << (s = ROUTING::DynamicSegment.new)
- s.key = :action
- s.default = 'index'
- s.is_optional = true
-
- @default_route.segments << slash_segment(:optional)
- @default_route.segments << (s = ROUTING::DynamicSegment.new)
- s.key = :id
- s.is_optional = true
-
- @default_route.segments << slash_segment(:optional)
- end
- @default_route
- end
-
- def test_default_route_recognition
- expected = {:controller => 'accounts', :action => 'show', :id => '10'}
- assert_equal expected, default_route.recognize('/accounts/show/10')
- assert_equal expected, default_route.recognize('/accounts/show/10/')
-
- expected[:id] = 'jamis'
- assert_equal expected, default_route.recognize('/accounts/show/jamis/')
-
- expected.delete :id
- assert_equal expected, default_route.recognize('/accounts/show')
- assert_equal expected, default_route.recognize('/accounts/show/')
-
- expected[:action] = 'index'
- assert_equal expected, default_route.recognize('/accounts/')
- assert_equal expected, default_route.recognize('/accounts')
-
- assert_equal nil, default_route.recognize('/')
- assert_equal nil, default_route.recognize('/accounts/how/goood/it/is/to/be/free')
- end
-
- def test_default_route_should_omit_default_action
- o = {:controller => 'accounts', :action => 'index'}
- assert_equal '/accounts', default_route.generate(o, o, {})
- end
-
- def test_default_route_should_include_default_action_when_id_present
- o = {:controller => 'accounts', :action => 'index', :id => '20'}
- assert_equal '/accounts/index/20', default_route.generate(o, o, {})
- end
-
- def test_default_route_should_work_with_action_but_no_id
- o = {:controller => 'accounts', :action => 'list_all'}
- assert_equal '/accounts/list_all', default_route.generate(o, o, {})
- end
-
- def test_default_route_should_uri_escape_pluses
- expected = { :controller => 'accounts', :action => 'show', :id => 'hello world' }
- assert_equal expected, default_route.recognize('/accounts/show/hello world')
- assert_equal expected, default_route.recognize('/accounts/show/hello%20world')
- assert_equal '/accounts/show/hello%20world', default_route.generate(expected, expected, {})
-
- expected[:id] = 'hello+world'
- assert_equal expected, default_route.recognize('/accounts/show/hello+world')
- assert_equal expected, default_route.recognize('/accounts/show/hello%2Bworld')
- assert_equal '/accounts/show/hello+world', default_route.generate(expected, expected, {})
- end
-
- def test_matches_controller_and_action
- # requirement_for should only be called for the action and controller _once_
- @route.expects(:requirement_for).with(:controller).times(1).returns('pages')
- @route.expects(:requirement_for).with(:action).times(1).returns('show')
-
- @route.requirements = {:controller => 'pages', :action => 'show'}
- assert @route.matches_controller_and_action?('pages', 'show')
- assert !@route.matches_controller_and_action?('not_pages', 'show')
- assert !@route.matches_controller_and_action?('pages', 'not_show')
- end
-
- def test_parameter_shell
- page_url = ROUTING::Route.new
- page_url.requirements = {:controller => 'pages', :action => 'show', :id => /\d+/}
- assert_equal({:controller => 'pages', :action => 'show'}, page_url.parameter_shell)
- end
-
- def test_defaults
- route = ROUTING::RouteBuilder.new.build '/users/:id.:format', :controller => "users", :action => "show", :format => "html"
- assert_equal(
- { :controller => "users", :action => "show", :format => "html" },
- route.defaults)
- end
-
- def test_builder_complains_without_controller
- assert_raises(ArgumentError) do
- ROUTING::RouteBuilder.new.build '/contact', :contoller => "contact", :action => "index"
- end
- end
-
- def test_significant_keys_for_default_route
- keys = default_route.significant_keys.sort_by {|k| k.to_s }
- assert_equal [:action, :controller, :id], keys
- end
-
- def test_significant_keys
- user_url = ROUTING::Route.new
- user_url.segments << (s = ROUTING::StaticSegment.new)
- s.value = '/'
- s.raw = true
-
- user_url.segments << (s = ROUTING::StaticSegment.new)
- s.value = 'user'
-
- user_url.segments << (s = ROUTING::StaticSegment.new)
- s.value = '/'
- s.raw = true
- s.is_optional = true
-
- user_url.segments << (s = ROUTING::DynamicSegment.new)
- s.key = :user
-
- user_url.segments << (s = ROUTING::StaticSegment.new)
- s.value = '/'
- s.raw = true
- s.is_optional = true
-
- user_url.requirements = {:controller => 'users', :action => 'show'}
-
- keys = user_url.significant_keys.sort_by { |k| k.to_s }
- assert_equal [:action, :controller, :user], keys
- end
-
- def test_build_empty_query_string
- assert_equal '', @route.build_query_string({})
- end
-
- def test_build_query_string_with_nil_value
- assert_equal '', @route.build_query_string({:x => nil})
- end
-
- def test_simple_build_query_string
- assert_equal '?x=1&y=2', order_query_string(@route.build_query_string(:x => '1', :y => '2'))
- end
-
- def test_convert_ints_build_query_string
- assert_equal '?x=1&y=2', order_query_string(@route.build_query_string(:x => 1, :y => 2))
- end
-
- def test_escape_spaces_build_query_string
- assert_equal '?x=hello+world&y=goodbye+world', order_query_string(@route.build_query_string(:x => 'hello world', :y => 'goodbye world'))
- end
-
- def test_expand_array_build_query_string
- assert_equal '?x%5B%5D=1&x%5B%5D=2', order_query_string(@route.build_query_string(:x => [1, 2]))
- end
-
- def test_escape_spaces_build_query_string_selected_keys
- assert_equal '?x=hello+world', order_query_string(@route.build_query_string({:x => 'hello world', :y => 'goodbye world'}, [:x]))
- end
-
- private
- def order_query_string(qs)
- '?' + qs[1..-1].split('&').sort.join('&')
- end
end
-end # uses_mocha
-
class RouteBuilderTest < Test::Unit::TestCase
-
def builder
@builder ||= ROUTING::RouteBuilder.new
end
@@ -1244,7 +384,7 @@ class RouteBuilderTest < Test::Unit::TestCase
assert_kind_of ROUTING::StaticSegment, segment
assert_equal 'ulysses', segment.value
end
-
+
def test_segment_for_action
segment, rest = builder.segment_for ':action'
assert_equal '', rest
@@ -1252,7 +392,7 @@ class RouteBuilderTest < Test::Unit::TestCase
assert_equal :action, segment.key
assert_equal 'index', segment.default
end
-
+
def test_segment_for_dynamic
segment, rest = builder.segment_for ':login'
assert_equal '', rest
@@ -1261,7 +401,7 @@ class RouteBuilderTest < Test::Unit::TestCase
assert_equal nil, segment.default
assert ! segment.optional?
end
-
+
def test_segment_for_with_rest
segment, rest = builder.segment_for ':login/:action'
assert_equal :login, segment.key
@@ -1273,105 +413,104 @@ class RouteBuilderTest < Test::Unit::TestCase
assert_equal :action, segment.key
assert_equal '', rest
end
-
+
def test_segments_for
segments = builder.segments_for_route_path '/:controller/:action/:id'
-
+
assert_kind_of ROUTING::DividerSegment, segments[0]
assert_equal '/', segments[2].value
-
+
assert_kind_of ROUTING::DynamicSegment, segments[1]
assert_equal :controller, segments[1].key
-
+
assert_kind_of ROUTING::DividerSegment, segments[2]
assert_equal '/', segments[2].value
-
+
assert_kind_of ROUTING::DynamicSegment, segments[3]
assert_equal :action, segments[3].key
-
+
assert_kind_of ROUTING::DividerSegment, segments[4]
assert_equal '/', segments[4].value
-
+
assert_kind_of ROUTING::DynamicSegment, segments[5]
assert_equal :id, segments[5].key
end
-
+
def test_segment_for_action
s, r = builder.segment_for(':action/something/else')
assert_equal '/something/else', r
assert_equal :action, s.key
end
-
+
def test_action_default_should_not_trigger_on_prefix
s, r = builder.segment_for ':action_name/something/else'
assert_equal '/something/else', r
assert_equal :action_name, s.key
assert_equal nil, s.default
end
-
+
def test_divide_route_options
segments = builder.segments_for_route_path '/cars/:action/:person/:car/'
defaults, requirements = builder.divide_route_options(segments,
:action => 'buy', :person => /\w+/, :car => /\w+/,
:defaults => {:person => nil, :car => nil}
)
-
+
assert_equal({:action => 'buy', :person => nil, :car => nil}, defaults)
assert_equal({:person => /\w+/, :car => /\w+/}, requirements)
end
-
+
def test_assign_route_options
segments = builder.segments_for_route_path '/cars/:action/:person/:car/'
defaults = {:action => 'buy', :person => nil, :car => nil}
requirements = {:person => /\w+/, :car => /\w+/}
-
+
route_requirements = builder.assign_route_options(segments, defaults, requirements)
assert_equal({}, route_requirements)
-
+
assert_equal :action, segments[3].key
assert_equal 'buy', segments[3].default
-
+
assert_equal :person, segments[5].key
assert_equal %r/\w+/, segments[5].regexp
assert segments[5].optional?
-
+
assert_equal :car, segments[7].key
assert_equal %r/\w+/, segments[7].regexp
assert segments[7].optional?
end
-
+
def test_assign_route_options_with_anchor_chars
segments = builder.segments_for_route_path '/cars/:action/:person/:car/'
defaults = {:action => 'buy', :person => nil, :car => nil}
requirements = {:person => /\w+/, :car => /^\w+$/}
-
+
assert_raises ArgumentError do
route_requirements = builder.assign_route_options(segments, defaults, requirements)
end
-
+
requirements[:car] = /[^\/]+/
route_requirements = builder.assign_route_options(segments, defaults, requirements)
end
-
def test_optional_segments_preceding_required_segments
segments = builder.segments_for_route_path '/cars/:action/:person/:car/'
defaults = {:action => 'buy', :person => nil, :car => "model-t"}
assert builder.assign_route_options(segments, defaults, {}).empty?
-
+
0.upto(1) { |i| assert !segments[i].optional?, "segment #{i} is optional and it shouldn't be" }
assert segments[2].optional?
-
+
assert_equal nil, builder.warn_output # should only warn on the :person segment
end
-
+
def test_segmentation_of_dot_path
segments = builder.segments_for_route_path '/books/:action.rss'
assert builder.assign_route_options(segments, {}, {}).empty?
assert_equal 6, segments.length # "/", "books", "/", ":action", ".", "rss"
assert !segments.any? { |seg| seg.optional? }
end
-
+
def test_segmentation_of_dynamic_dot_path
segments = builder.segments_for_route_path '/books/:action.:format'
assert builder.assign_route_options(segments, {}, {}).empty?
@@ -1379,56 +518,56 @@ class RouteBuilderTest < Test::Unit::TestCase
assert !segments.any? { |seg| seg.optional? }
assert_kind_of ROUTING::DynamicSegment, segments.last
end
-
+
def test_assignment_of_default_options
segments = builder.segments_for_route_path '/:controller/:action/:id/'
action, id = segments[-4], segments[-2]
-
+
assert_equal :action, action.key
assert_equal :id, id.key
assert ! action.optional?
assert ! id.optional?
-
+
builder.assign_default_route_options(segments)
-
+
assert_equal 'index', action.default
assert action.optional?
assert id.optional?
end
-
+
def test_assignment_of_default_options_respects_existing_defaults
segments = builder.segments_for_route_path '/:controller/:action/:id/'
action, id = segments[-4], segments[-2]
-
+
assert_equal :action, action.key
assert_equal :id, id.key
action.default = 'show'
action.is_optional = true
-
+
id.default = 'Welcome'
id.is_optional = true
-
+
builder.assign_default_route_options(segments)
-
+
assert_equal 'show', action.default
assert action.optional?
assert_equal 'Welcome', id.default
assert id.optional?
end
-
+
def test_assignment_of_default_options_respects_regexps
segments = builder.segments_for_route_path '/:controller/:action/:id/'
action = segments[-4]
-
+
assert_equal :action, action.key
action.regexp = /show|in/ # Use 'in' to check partial matches
-
+
builder.assign_default_route_options(segments)
-
+
assert_equal nil, action.default
assert ! action.optional?
end
-
+
def test_assignment_of_is_optional_when_default
segments = builder.segments_for_route_path '/books/:action.rss'
assert_equal segments[3].key, :action
@@ -1436,44 +575,44 @@ class RouteBuilderTest < Test::Unit::TestCase
builder.ensure_required_segments(segments)
assert ! segments[3].optional?
end
-
+
def test_is_optional_is_assigned_to_default_segments
segments = builder.segments_for_route_path '/books/:action'
builder.assign_route_options(segments, {:action => 'index'}, {})
-
+
assert_equal segments[3].key, :action
assert segments[3].optional?
assert_kind_of ROUTING::DividerSegment, segments[2]
assert segments[2].optional?
end
-
+
# XXX is optional not being set right?
# /blah/:defaulted_segment <-- is the second slash optional? it should be.
-
+
def test_route_build
ActionController::Routing.with_controllers %w(users pages) do
r = builder.build '/:controller/:action/:id/', :action => nil
-
+
[0, 2, 4].each do |i|
assert_kind_of ROUTING::DividerSegment, r.segments[i]
assert_equal '/', r.segments[i].value
assert r.segments[i].optional? if i > 1
end
-
+
assert_kind_of ROUTING::DynamicSegment, r.segments[1]
assert_equal :controller, r.segments[1].key
assert_equal nil, r.segments[1].default
-
+
assert_kind_of ROUTING::DynamicSegment, r.segments[3]
assert_equal :action, r.segments[3].key
assert_equal 'index', r.segments[3].default
-
+
assert_kind_of ROUTING::DynamicSegment, r.segments[5]
assert_equal :id, r.segments[5].key
assert r.segments[5].optional?
end
end
-
+
def test_slashes_are_implied
routes = [
builder.build('/:controller/:action/:id/', :action => nil),
@@ -1487,866 +626,1699 @@ class RouteBuilderTest < Test::Unit::TestCase
assert_equal expected, found, "Route #{i + 1} has #{found} segments, expected #{expected}"
end
end
-
end
+class RoutingTest < Test::Unit::TestCase
+ def test_possible_controllers
+ true_controller_paths = ActionController::Routing.controller_paths
+ ActionController::Routing.use_controllers! nil
+ silence_warnings do
+ Object.send(:const_set, :RAILS_ROOT, File.dirname(__FILE__) + '/controller_fixtures')
+ end
-class RouteSetTest < Test::Unit::TestCase
+ ActionController::Routing.controller_paths = [
+ RAILS_ROOT, RAILS_ROOT + '/app/controllers', RAILS_ROOT + '/vendor/plugins/bad_plugin/lib'
+ ]
- def set
- @set ||= ROUTING::RouteSet.new
+ assert_equal ["admin/user", "plugin", "user"], ActionController::Routing.possible_controllers.sort
+ ensure
+ if true_controller_paths
+ ActionController::Routing.controller_paths = true_controller_paths
+ end
+ ActionController::Routing.use_controllers! nil
+ Object.send(:remove_const, :RAILS_ROOT) rescue nil
end
- def request
- @request ||= MockRequest.new(:host => "named.routes.test", :method => :get)
+ def test_possible_controllers_are_reset_on_each_load
+ true_possible_controllers = ActionController::Routing.possible_controllers
+ true_controller_paths = ActionController::Routing.controller_paths
+
+ ActionController::Routing.use_controllers! nil
+ root = File.dirname(__FILE__) + '/controller_fixtures'
+
+ ActionController::Routing.controller_paths = []
+ assert_equal [], ActionController::Routing.possible_controllers
+
+ ActionController::Routing::Routes.load!
+ ActionController::Routing.controller_paths = [
+ root, root + '/app/controllers', root + '/vendor/plugins/bad_plugin/lib'
+ ]
+
+ assert_equal ["admin/user", "plugin", "user"], ActionController::Routing.possible_controllers.sort
+ ensure
+ ActionController::Routing.controller_paths = true_controller_paths
+ ActionController::Routing.use_controllers! true_possible_controllers
+ Object.send(:remove_const, :RAILS_ROOT) rescue nil
+
+ ActionController::Routing::Routes.clear!
+ ActionController::Routing::Routes.load_routes!
end
- def test_generate_extras
- set.draw { |m| m.connect ':controller/:action/:id' }
- path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
- assert_equal "/foo/bar/15", path
- assert_equal %w(that this), extras.map(&:to_s).sort
+ def test_with_controllers
+ c = %w(admin/accounts admin/users account pages)
+ ActionController::Routing.with_controllers c do
+ assert_equal c, ActionController::Routing.possible_controllers
+ end
end
- def test_extra_keys
- set.draw { |m| m.connect ':controller/:action/:id' }
- extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
- assert_equal %w(that this), extras.map(&:to_s).sort
+ 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_generate_extras_not_first
- set.draw do |map|
- map.connect ':controller/:action/:id.:format'
- map.connect ':controller/:action/:id'
- end
- path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
- assert_equal "/foo/bar/15", path
- assert_equal %w(that this), extras.map(&:to_s).sort
+
+ 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_generate_not_first
- set.draw do |map|
- map.connect ':controller/:action/:id.:format'
- map.connect ':controller/:action/:id'
- end
- assert_equal "/foo/bar/15?this=hello", set.generate(:controller => "foo", :action => "bar", :id => 15, :this => "hello")
+
+ 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
-
- def test_extra_keys_not_first
- set.draw do |map|
- map.connect ':controller/:action/:id.:format'
- map.connect ':controller/:action/:id'
+end
+
+uses_mocha 'LegacyRouteSet, Route, RouteSet and RouteLoading' do
+ class MockController
+ attr_accessor :routes
+
+ def initialize(routes)
+ self.routes = routes
end
- extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
- assert_equal %w(that this), extras.map(&:to_s).sort
- end
- def test_draw
- assert_equal 0, set.routes.size
- set.draw do |map|
- map.connect '/hello/world', :controller => 'a', :action => 'b'
+ def url_for(options)
+ only_path = options.delete(:only_path)
+
+ port = options.delete(:port) || 80
+ port_string = port == 80 ? '' : ":#{port}"
+
+ host = options.delete(:host) || "named.route.test"
+ anchor = "##{options.delete(:anchor)}" if options.key?(:anchor)
+
+ path = routes.generate(options)
+
+ only_path ? "#{path}#{anchor}" : "http://#{host}#{port_string}#{path}#{anchor}"
end
- assert_equal 1, set.routes.size
- end
-
- def test_named_draw
- assert_equal 0, set.routes.size
- set.draw do |map|
- map.hello '/hello/world', :controller => 'a', :action => 'b'
+
+ def request
+ @request ||= MockRequest.new(:host => "named.route.test", :method => :get)
end
- assert_equal 1, set.routes.size
- assert_equal set.routes.first, set.named_routes[:hello]
- end
-
- def test_later_named_routes_take_precedence
- set.draw do |map|
- map.hello '/hello/world', :controller => 'a', :action => 'b'
- map.hello '/hello', :controller => 'a', :action => 'b'
+
+ def relative_url_root=(value)
+ request.relative_url_root=value
end
- assert_equal set.routes.last, set.named_routes[:hello]
end
- def setup_named_route_test
- set.draw do |map|
- map.show '/people/:id', :controller => 'people', :action => 'show'
- map.index '/people', :controller => 'people', :action => 'index'
- map.multi '/people/go/:foo/:bar/joe/:id', :controller => 'people', :action => 'multi'
- map.users '/admin/users', :controller => 'admin/users', :action => 'index'
+ class MockRequest
+ attr_accessor :path, :path_parameters, :host, :subdomains, :domain,
+ :method, :relative_url_root
+
+ def initialize(values={})
+ values.each { |key, value| send("#{key}=", value) }
+ if values[:host]
+ subdomain, self.domain = values[:host].split(/\./, 2)
+ self.subdomains = [subdomain]
+ end
+ end
+
+ def protocol
+ "http://"
end
- klass = Class.new(MockController)
- set.install_helpers(klass)
- klass.new(set)
+ def host_with_port
+ (subdomains * '.') + '.' + domain
+ end
end
- def test_named_route_hash_access_method
- controller = setup_named_route_test
+ class LegacyRouteSetTests < Test::Unit::TestCase
+ attr_reader :rs
- assert_equal(
- { :controller => 'people', :action => 'show', :id => 5, :use_route => :show, :only_path => false },
- controller.send(:hash_for_show_url, :id => 5))
+ def setup
+ # These tests assume optimisation is on, so re-enable it.
+ ActionController::Base.optimise_named_routes = true
- assert_equal(
- { :controller => 'people', :action => 'index', :use_route => :index, :only_path => false },
- controller.send(:hash_for_index_url))
-
- assert_equal(
- { :controller => 'people', :action => 'show', :id => 5, :use_route => :show, :only_path => true },
- controller.send(:hash_for_show_path, :id => 5)
- )
- end
+ @rs = ::ActionController::Routing::RouteSet.new
+ @rs.draw {|m| m.connect ':controller/:action/:id' }
- def test_named_route_url_method
- controller = setup_named_route_test
-
- assert_equal "http://named.route.test/people/5", controller.send(:show_url, :id => 5)
- assert_equal "/people/5", controller.send(:show_path, :id => 5)
-
- assert_equal "http://named.route.test/people", controller.send(:index_url)
- assert_equal "/people", controller.send(:index_path)
+ ActionController::Routing.use_controllers! %w(content admin/user admin/news_feed)
+ end
- assert_equal "http://named.route.test/admin/users", controller.send(:users_url)
- assert_equal '/admin/users', controller.send(:users_path)
- assert_equal '/admin/users', set.generate(controller.send(:hash_for_users_url), {:controller => 'users', :action => 'index'})
- end
+ def test_default_setup
+ assert_equal({:controller => "content", :action => 'index'}, rs.recognize_path("/content"))
+ assert_equal({:controller => "content", :action => 'list'}, rs.recognize_path("/content/list"))
+ assert_equal({:controller => "content", :action => 'show', :id => '10'}, rs.recognize_path("/content/show/10"))
- def test_named_route_url_method_with_anchor
- controller = setup_named_route_test
+ assert_equal({:controller => "admin/user", :action => 'show', :id => '10'}, rs.recognize_path("/admin/user/show/10"))
- assert_equal "http://named.route.test/people/5#location", controller.send(:show_url, :id => 5, :anchor => 'location')
- assert_equal "/people/5#location", controller.send(:show_path, :id => 5, :anchor => 'location')
+ assert_equal '/admin/user/show/10', rs.generate(:controller => 'admin/user', :action => 'show', :id => 10)
- assert_equal "http://named.route.test/people#location", controller.send(:index_url, :anchor => 'location')
- assert_equal "/people#location", controller.send(:index_path, :anchor => 'location')
+ assert_equal '/admin/user/show', rs.generate({:action => 'show'}, {:controller => 'admin/user', :action => 'list', :id => '10'})
+ assert_equal '/admin/user/list/10', rs.generate({}, {:controller => 'admin/user', :action => 'list', :id => '10'})
- assert_equal "http://named.route.test/admin/users#location", controller.send(:users_url, :anchor => 'location')
- assert_equal '/admin/users#location', controller.send(:users_path, :anchor => 'location')
+ assert_equal '/admin/stuff', rs.generate({:controller => 'stuff'}, {:controller => 'admin/user', :action => 'list', :id => '10'})
+ assert_equal '/stuff', rs.generate({:controller => '/stuff'}, {:controller => 'admin/user', :action => 'list', :id => '10'})
+ end
- assert_equal "http://named.route.test/people/go/7/hello/joe/5#location",
- controller.send(:multi_url, 7, "hello", 5, :anchor => 'location')
+ def test_ignores_leading_slash
+ @rs.draw {|m| m.connect '/:controller/:action/:id'}
+ test_default_setup
+ end
- assert_equal "http://named.route.test/people/go/7/hello/joe/5?baz=bar#location",
- controller.send(:multi_url, 7, "hello", 5, :baz => "bar", :anchor => 'location')
+ def test_time_recognition
+ # We create many routes to make situation more realistic
+ @rs = ::ActionController::Routing::RouteSet.new
+ @rs.draw { |map|
+ map.frontpage '', :controller => 'search', :action => 'new'
+ map.resources :videos do |video|
+ video.resources :comments
+ video.resource :file, :controller => 'video_file'
+ video.resource :share, :controller => 'video_shares'
+ video.resource :abuse, :controller => 'video_abuses'
+ end
+ map.resources :abuses, :controller => 'video_abuses'
+ map.resources :video_uploads
+ map.resources :video_visits
- assert_equal "http://named.route.test/people?baz=bar#location",
- controller.send(:index_url, :baz => "bar", :anchor => 'location')
- end
-
- def test_named_route_url_method_with_port
- controller = setup_named_route_test
- assert_equal "http://named.route.test:8080/people/5", controller.send(:show_url, 5, :port=>8080)
- end
-
- def test_named_route_url_method_with_host
- controller = setup_named_route_test
- assert_equal "http://some.example.com/people/5", controller.send(:show_url, 5, :host=>"some.example.com")
- end
-
+ map.resources :users do |user|
+ user.resource :settings
+ user.resources :videos
+ end
+ map.resources :channels do |channel|
+ channel.resources :videos, :controller => 'channel_videos'
+ end
+ map.resource :session
+ map.resource :lost_password
+ map.search 'search', :controller => 'search'
+ map.resources :pages
+ map.connect ':controller/:action/:id'
+ }
+ n = 1000
+ if RunTimeTests
+ GC.start
+ rectime = Benchmark.realtime do
+ n.times do
+ rs.recognize_path("/videos/1234567", {:method => :get})
+ rs.recognize_path("/videos/1234567/abuse", {:method => :get})
+ rs.recognize_path("/users/1234567/settings", {:method => :get})
+ rs.recognize_path("/channels/1234567", {:method => :get})
+ rs.recognize_path("/session/new", {:method => :get})
+ rs.recognize_path("/admin/user/show/10", {:method => :get})
+ end
+ end
+ puts "\n\nRecognition (#{rs.routes.size} routes):"
+ per_url = rectime / (n * 6)
+ puts "#{per_url * 1000} ms/url"
+ puts "#{1 / per_url} url/s\n\n"
+ end
+ end
+ def test_time_generation
+ n = 5000
+ if RunTimeTests
+ GC.start
+ pairs = [
+ [{:controller => 'content', :action => 'index'}, {:controller => 'content', :action => 'show'}],
+ [{:controller => 'content'}, {:controller => 'content', :action => 'index'}],
+ [{:controller => 'content', :action => 'list'}, {:controller => 'content', :action => 'index'}],
+ [{:controller => 'content', :action => 'show', :id => '10'}, {:controller => 'content', :action => 'list'}],
+ [{:controller => 'admin/user', :action => 'index'}, {:controller => 'admin/user', :action => 'show'}],
+ [{:controller => 'admin/user'}, {:controller => 'admin/user', :action => 'index'}],
+ [{:controller => 'admin/user', :action => 'list'}, {:controller => 'admin/user', :action => 'index'}],
+ [{:controller => 'admin/user', :action => 'show', :id => '10'}, {:controller => 'admin/user', :action => 'list'}],
+ ]
+ p = nil
+ gentime = Benchmark.realtime do
+ n.times do
+ pairs.each {|(a, b)| rs.generate(a, b)}
+ end
+ end
- def test_named_route_url_method_with_ordered_parameters
- controller = setup_named_route_test
- assert_equal "http://named.route.test/people/go/7/hello/joe/5",
- controller.send(:multi_url, 7, "hello", 5)
- end
+ puts "\n\nGeneration (RouteSet): (#{(n * 8)} urls)"
+ per_url = gentime / (n * 8)
+ puts "#{per_url * 1000} ms/url"
+ puts "#{1 / per_url} url/s\n\n"
+ end
+ end
- def test_named_route_url_method_with_ordered_parameters_and_hash
- controller = setup_named_route_test
- assert_equal "http://named.route.test/people/go/7/hello/joe/5?baz=bar",
- controller.send(:multi_url, 7, "hello", 5, :baz => "bar")
- end
-
- def test_named_route_url_method_with_no_positional_arguments
- controller = setup_named_route_test
- assert_equal "http://named.route.test/people?baz=bar",
- controller.send(:index_url, :baz => "bar")
- end
-
- def test_draw_default_route
- ActionController::Routing.with_controllers(['users']) do
- set.draw do |map|
- map.connect '/:controller/:action/:id'
+ def test_route_with_colon_first
+ rs.draw do |map|
+ map.connect '/:controller/:action/:id', :action => 'index', :id => nil
+ map.connect ':url', :controller => 'tiny_url', :action => 'translate'
end
+ end
- assert_equal 1, set.routes.size
- route = set.routes.first
+ def test_route_with_regexp_for_controller
+ rs.draw do |map|
+ map.connect ':controller/:admintoken/:action/:id', :controller => /admin\/.+/
+ map.connect ':controller/:action/:id'
+ end
+ assert_equal({:controller => "admin/user", :admintoken => "foo", :action => "index"},
+ rs.recognize_path("/admin/user/foo"))
+ assert_equal({:controller => "content", :action => "foo"}, rs.recognize_path("/content/foo"))
+ assert_equal '/admin/user/foo', rs.generate(:controller => "admin/user", :admintoken => "foo", :action => "index")
+ assert_equal '/content/foo', rs.generate(:controller => "content", :action => "foo")
+ end
- assert route.segments.last.optional?
+ def test_route_with_regexp_and_dot
+ rs.draw do |map|
+ map.connect ':controller/:action/:file',
+ :controller => /admin|user/,
+ :action => /upload|download/,
+ :defaults => {:file => nil},
+ :requirements => {:file => %r{[^/]+(\.[^/]+)?}}
+ end
+ # Without a file extension
+ assert_equal '/user/download/file',
+ rs.generate(:controller => "user", :action => "download", :file => "file")
+ assert_equal(
+ {:controller => "user", :action => "download", :file => "file"},
+ rs.recognize_path("/user/download/file"))
+
+ # Now, let's try a file with an extension, really a dot (.)
+ assert_equal '/user/download/file.jpg',
+ rs.generate(
+ :controller => "user", :action => "download", :file => "file.jpg")
+ assert_equal(
+ {:controller => "user", :action => "download", :file => "file.jpg"},
+ rs.recognize_path("/user/download/file.jpg"))
+ end
+
+ def test_basic_named_route
+ rs.add_named_route :home, '', :controller => 'content', :action => 'list'
+ x = setup_for_named_route
+ assert_equal("http://named.route.test/",
+ x.send(:home_url))
+ end
- assert_equal '/users/show/10', set.generate(:controller => 'users', :action => 'show', :id => 10)
- assert_equal '/users/index/10', set.generate(:controller => 'users', :id => 10)
+ def test_basic_named_route_with_relative_url_root
+ rs.add_named_route :home, '', :controller => 'content', :action => 'list'
+ x = setup_for_named_route
+ x.relative_url_root="/foo"
+ assert_equal("http://named.route.test/foo/",
+ x.send(:home_url))
+ assert_equal "/foo/", x.send(:home_path)
+ end
- assert_equal({:controller => 'users', :action => 'index', :id => '10'}, set.recognize_path('/users/index/10'))
- assert_equal({:controller => 'users', :action => 'index', :id => '10'}, set.recognize_path('/users/index/10/'))
+ def test_named_route_with_option
+ rs.add_named_route :page, 'page/:title', :controller => 'content', :action => 'show_page'
+ x = setup_for_named_route
+ assert_equal("http://named.route.test/page/new%20stuff",
+ x.send(:page_url, :title => 'new stuff'))
end
- end
- def test_draw_default_route_with_default_controller
- ActionController::Routing.with_controllers(['users']) do
- set.draw do |map|
- map.connect '/:controller/:action/:id', :controller => 'users'
- end
- assert_equal({:controller => 'users', :action => 'index'}, set.recognize_path('/'))
+ def test_named_route_with_default
+ rs.add_named_route :page, 'page/:title', :controller => 'content', :action => 'show_page', :title => 'AboutPage'
+ x = setup_for_named_route
+ assert_equal("http://named.route.test/page/AboutRails",
+ x.send(:page_url, :title => "AboutRails"))
+
end
- end
- def test_route_with_parameter_shell
- ActionController::Routing.with_controllers(['users', 'pages']) do
- set.draw do |map|
- map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+/
- map.connect '/:controller/:action/:id'
+ def test_named_route_with_nested_controller
+ rs.add_named_route :users, 'admin/user', :controller => 'admin/user', :action => 'index'
+ x = setup_for_named_route
+ assert_equal("http://named.route.test/admin/user",
+ x.send(:users_url))
+ end
+
+ def test_optimised_named_route_call_never_uses_url_for
+ rs.add_named_route :users, 'admin/user', :controller => '/admin/user', :action => 'index'
+ rs.add_named_route :user, 'admin/user/:id', :controller=>'/admin/user', :action=>'show'
+ x = setup_for_named_route
+ x.expects(:url_for).never
+ x.send(:users_url)
+ x.send(:users_path)
+ x.send(:user_url, 2, :foo=>"bar")
+ x.send(:user_path, 3, :bar=>"foo")
+ end
+
+ def test_optimised_named_route_with_host
+ rs.add_named_route :pages, 'pages', :controller => 'content', :action => 'show_page', :host => 'foo.com'
+ x = setup_for_named_route
+ x.expects(:url_for).with(:host => 'foo.com', :only_path => false, :controller => 'content', :action => 'show_page', :use_route => :pages).once
+ x.send(:pages_url)
+ end
+
+ def setup_for_named_route
+ klass = Class.new(MockController)
+ rs.install_helpers(klass)
+ klass.new(rs)
+ end
+
+ def test_named_route_without_hash
+ rs.draw do |map|
+ map.normal ':controller/:action/:id'
+ end
+ end
+
+ def test_named_route_root
+ rs.draw do |map|
+ map.root :controller => "hello"
end
+ x = setup_for_named_route
+ assert_equal("http://named.route.test/", x.send(:root_url))
+ assert_equal("/", x.send(:root_path))
+ end
- assert_equal({:controller => 'pages', :action => 'index'}, set.recognize_path('/pages'))
- assert_equal({:controller => 'pages', :action => 'index'}, set.recognize_path('/pages/index'))
- assert_equal({:controller => 'pages', :action => 'list'}, set.recognize_path('/pages/list'))
+ def test_named_route_with_regexps
+ rs.draw do |map|
+ map.article 'page/:year/:month/:day/:title', :controller => 'page', :action => 'show',
+ :year => /\d+/, :month => /\d+/, :day => /\d+/
+ map.connect ':controller/:action/:id'
+ end
+ x = setup_for_named_route
+ # assert_equal(
+ # {:controller => 'page', :action => 'show', :title => 'hi', :use_route => :article, :only_path => false},
+ # x.send(:article_url, :title => 'hi')
+ # )
+ assert_equal(
+ "http://named.route.test/page/2005/6/10/hi",
+ x.send(:article_url, :title => 'hi', :day => 10, :year => 2005, :month => 6)
+ )
+ end
- assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, set.recognize_path('/pages/show/10'))
- assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, set.recognize_path('/page/10'))
+ def test_changing_controller
+ assert_equal '/admin/stuff/show/10', rs.generate(
+ {:controller => 'stuff', :action => 'show', :id => 10},
+ {:controller => 'admin/user', :action => 'index'}
+ )
end
- end
- def test_route_requirements_with_anchor_chars_are_invalid
- assert_raises ArgumentError do
- set.draw do |map|
- map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /^\d+/
+ def test_paths_escaped
+ rs.draw do |map|
+ map.path 'file/*path', :controller => 'content', :action => 'show_file'
+ map.connect ':controller/:action/:id'
end
+
+ # No + to space in URI escaping, only for query params.
+ results = rs.recognize_path "/file/hello+world/how+are+you%3F"
+ assert results, "Recognition should have succeeded"
+ assert_equal ['hello+world', 'how+are+you?'], results[:path]
+
+ # Use %20 for space instead.
+ results = rs.recognize_path "/file/hello%20world/how%20are%20you%3F"
+ assert results, "Recognition should have succeeded"
+ assert_equal ['hello world', 'how are you?'], results[:path]
+
+ results = rs.recognize_path "/file"
+ assert results, "Recognition should have succeeded"
+ assert_equal [], results[:path]
end
- assert_raises ArgumentError do
- set.draw do |map|
- map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\A\d+/
+
+ def test_paths_slashes_unescaped_with_ordered_parameters
+ rs.add_named_route :path, '/file/*path', :controller => 'content'
+
+ # No / to %2F in URI, only for query params.
+ x = setup_for_named_route
+ assert_equal("/file/hello/world", x.send(:path_path, 'hello/world'))
+ end
+
+ def test_non_controllers_cannot_be_matched
+ rs.draw do |map|
+ map.connect ':controller/:action/:id'
end
+ assert_raises(ActionController::RoutingError) { rs.recognize_path("/not_a/show/10") }
end
- assert_raises ArgumentError do
- set.draw do |map|
- map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+$/
+
+ def test_paths_do_not_accept_defaults
+ assert_raises(ActionController::RoutingError) do
+ rs.draw do |map|
+ map.path 'file/*path', :controller => 'content', :action => 'show_file', :path => %w(fake default)
+ map.connect ':controller/:action/:id'
+ end
+ end
+
+ rs.draw do |map|
+ map.path 'file/*path', :controller => 'content', :action => 'show_file', :path => []
+ map.connect ':controller/:action/:id'
end
end
- assert_raises ArgumentError do
- set.draw do |map|
- map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+\Z/
+
+ def test_should_list_options_diff_when_routing_requirements_dont_match
+ rs.draw do |map|
+ map.post 'post/:id', :controller=> 'post', :action=> 'show', :requirements => {:id => /\d+/}
end
+ exception = assert_raise(ActionController::RoutingError) { rs.generate(:controller => 'post', :action => 'show', :bad_param => "foo", :use_route => "post") }
+ assert_match /^post_url failed to generate/, exception.message
+ from_match = exception.message.match(/from \{[^\}]+\}/).to_s
+ assert_match /:bad_param=>"foo"/, from_match
+ assert_match /:action=>"show"/, from_match
+ assert_match /:controller=>"post"/, from_match
+
+ expected_match = exception.message.match(/expected: \{[^\}]+\}/).to_s
+ assert_no_match /:bad_param=>"foo"/, expected_match
+ assert_match /:action=>"show"/, expected_match
+ assert_match /:controller=>"post"/, expected_match
+
+ diff_match = exception.message.match(/diff: \{[^\}]+\}/).to_s
+ assert_match /:bad_param=>"foo"/, diff_match
+ assert_no_match /:action=>"show"/, diff_match
+ assert_no_match /:controller=>"post"/, diff_match
+ end
+
+ # this specifies the case where your formerly would get a very confusing error message with an empty diff
+ def test_should_have_better_error_message_when_options_diff_is_empty
+ rs.draw do |map|
+ map.content '/content/:query', :controller => 'content', :action => 'show'
+ end
+
+ exception = assert_raise(ActionController::RoutingError) { rs.generate(:controller => 'content', :action => 'show', :use_route => "content") }
+ assert_match %r[:action=>"show"], exception.message
+ assert_match %r[:controller=>"content"], exception.message
+ assert_match %r[you may have ambiguous routes, or you may need to supply additional parameters for this route], exception.message
+ assert_match %r[content_url has the following required parameters: \["content", :query\] - are they all satisfied?], exception.message
end
- assert_raises ArgumentError do
- set.draw do |map|
- map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+\z/
+
+ def test_dynamic_path_allowed
+ rs.draw do |map|
+ map.connect '*path', :controller => 'content', :action => 'show_file'
+ end
+
+ assert_equal '/pages/boo', rs.generate(:controller => 'content', :action => 'show_file', :path => %w(pages boo))
+ end
+
+ def test_dynamic_recall_paths_allowed
+ rs.draw do |map|
+ map.connect '*path', :controller => 'content', :action => 'show_file'
end
+
+ recall_path = ActionController::Routing::PathSegment::Result.new(%w(pages boo))
+ assert_equal '/pages/boo', rs.generate({}, :controller => 'content', :action => 'show_file', :path => recall_path)
end
- assert_nothing_raised do
- set.draw do |map|
- map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+/, :name => /^(david|jamis)/
+
+ def test_backwards
+ rs.draw do |map|
+ map.connect 'page/:id/:action', :controller => 'pages', :action => 'show'
+ map.connect ':controller/:action/:id'
+ end
+
+ assert_equal '/page/20', rs.generate({:id => 20}, {:controller => 'pages', :action => 'show'})
+ assert_equal '/page/20', rs.generate(:controller => 'pages', :id => 20, :action => 'show')
+ assert_equal '/pages/boo', rs.generate(:controller => 'pages', :action => 'boo')
+ end
+
+ def test_route_with_fixnum_default
+ rs.draw do |map|
+ map.connect 'page/:id', :controller => 'content', :action => 'show_page', :id => 1
+ map.connect ':controller/:action/:id'
+ end
+
+ assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page')
+ assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page', :id => 1)
+ assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page', :id => '1')
+ assert_equal '/page/10', rs.generate(:controller => 'content', :action => 'show_page', :id => 10)
+
+ assert_equal({:controller => "content", :action => 'show_page', :id => '1'}, rs.recognize_path("/page"))
+ assert_equal({:controller => "content", :action => 'show_page', :id => '1'}, rs.recognize_path("/page/1"))
+ assert_equal({:controller => "content", :action => 'show_page', :id => '10'}, rs.recognize_path("/page/10"))
+ end
+
+ # For newer revision
+ def test_route_with_text_default
+ rs.draw do |map|
+ map.connect 'page/:id', :controller => 'content', :action => 'show_page', :id => 1
+ map.connect ':controller/:action/:id'
+ end
+
+ assert_equal '/page/foo', rs.generate(:controller => 'content', :action => 'show_page', :id => 'foo')
+ assert_equal({:controller => "content", :action => 'show_page', :id => 'foo'}, rs.recognize_path("/page/foo"))
+
+ token = "\321\202\320\265\320\272\321\201\321\202" # 'text' in russian
+ escaped_token = CGI::escape(token)
+
+ assert_equal '/page/' + escaped_token, rs.generate(:controller => 'content', :action => 'show_page', :id => token)
+ assert_equal({:controller => "content", :action => 'show_page', :id => token}, rs.recognize_path("/page/#{escaped_token}"))
+ end
+
+ def test_action_expiry
+ assert_equal '/content', rs.generate({:controller => 'content'}, {:controller => 'content', :action => 'show'})
+ end
+
+ def test_recognition_with_uppercase_controller_name
+ assert_equal({:controller => "content", :action => 'index'}, rs.recognize_path("/Content"))
+ assert_equal({:controller => "content", :action => 'list'}, rs.recognize_path("/ConTent/list"))
+ assert_equal({:controller => "content", :action => 'show', :id => '10'}, rs.recognize_path("/CONTENT/show/10"))
+
+ # these used to work, before the routes rewrite, but support for this was pulled in the new version...
+ #assert_equal({'controller' => "admin/news_feed", 'action' => 'index'}, rs.recognize_path("Admin/NewsFeed"))
+ #assert_equal({'controller' => "admin/news_feed", 'action' => 'index'}, rs.recognize_path("Admin/News_Feed"))
+ end
+
+ def test_requirement_should_prevent_optional_id
+ rs.draw do |map|
+ map.post 'post/:id', :controller=> 'post', :action=> 'show', :requirements => {:id => /\d+/}
end
+
+ assert_equal '/post/10', rs.generate(:controller => 'post', :action => 'show', :id => 10)
+
assert_raises ActionController::RoutingError do
- set.generate :controller => 'pages', :action => 'show', :id => 10
+ rs.generate(:controller => 'post', :action => 'show')
end
end
- end
- def test_non_path_route_requirements_match_all
- set.draw do |map|
- map.connect 'page/37s', :controller => 'pages', :action => 'show', :name => /(jamis|david)/
+ def test_both_requirement_and_optional
+ rs.draw do |map|
+ map.blog('test/:year', :controller => 'post', :action => 'show',
+ :defaults => { :year => nil },
+ :requirements => { :year => /\d{4}/ }
+ )
+ map.connect ':controller/:action/:id'
+ end
+
+ assert_equal '/test', rs.generate(:controller => 'post', :action => 'show')
+ assert_equal '/test', rs.generate(:controller => 'post', :action => 'show', :year => nil)
+
+ x = setup_for_named_route
+ assert_equal("http://named.route.test/test",
+ x.send(:blog_url))
end
- assert_equal '/page/37s', set.generate(:controller => 'pages', :action => 'show', :name => 'jamis')
- assert_raises ActionController::RoutingError do
- set.generate(:controller => 'pages', :action => 'show', :name => 'not_jamis')
+
+ def test_set_to_nil_forgets
+ rs.draw do |map|
+ map.connect 'pages/:year/:month/:day', :controller => 'content', :action => 'list_pages', :month => nil, :day => nil
+ map.connect ':controller/:action/:id'
+ end
+
+ assert_equal '/pages/2005',
+ rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005)
+ assert_equal '/pages/2005/6',
+ rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005, :month => 6)
+ assert_equal '/pages/2005/6/12',
+ rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005, :month => 6, :day => 12)
+
+ assert_equal '/pages/2005/6/4',
+ rs.generate({:day => 4}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'})
+
+ assert_equal '/pages/2005/6',
+ rs.generate({:day => nil}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'})
+
+ assert_equal '/pages/2005',
+ rs.generate({:day => nil, :month => nil}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'})
end
- assert_raises ActionController::RoutingError do
- set.generate(:controller => 'pages', :action => 'show', :name => 'nor_jamis_and_david')
+
+ def test_url_with_no_action_specified
+ rs.draw do |map|
+ map.connect '', :controller => 'content'
+ map.connect ':controller/:action/:id'
+ end
+
+ assert_equal '/', rs.generate(:controller => 'content', :action => 'index')
+ assert_equal '/', rs.generate(:controller => 'content')
end
- end
-
- def test_recognize_with_encoded_id_and_regex
- set.draw do |map|
- map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /[a-zA-Z0-9\+]+/
+
+ def test_named_url_with_no_action_specified
+ rs.draw do |map|
+ map.home '', :controller => 'content'
+ map.connect ':controller/:action/:id'
+ end
+
+ assert_equal '/', rs.generate(:controller => 'content', :action => 'index')
+ assert_equal '/', rs.generate(:controller => 'content')
+
+ x = setup_for_named_route
+ assert_equal("http://named.route.test/",
+ x.send(:home_url))
end
- assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, set.recognize_path('/page/10'))
- assert_equal({:controller => 'pages', :action => 'show', :id => 'hello+world'}, set.recognize_path('/page/hello+world'))
- end
+ def test_url_generated_when_forgetting_action
+ [{:controller => 'content', :action => 'index'}, {:controller => 'content'}].each do |hash|
+ rs.draw do |map|
+ map.home '', hash
+ map.connect ':controller/:action/:id'
+ end
+ assert_equal '/', rs.generate({:action => nil}, {:controller => 'content', :action => 'hello'})
+ assert_equal '/', rs.generate({:controller => 'content'})
+ assert_equal '/content/hi', rs.generate({:controller => 'content', :action => 'hi'})
+ end
+ end
- def test_recognize_with_conditions
- Object.const_set(:PeopleController, Class.new)
+ def test_named_route_method
+ rs.draw do |map|
+ map.categories 'categories', :controller => 'content', :action => 'categories'
+ map.connect ':controller/:action/:id'
+ end
- set.draw do |map|
- map.with_options(:controller => "people") do |people|
- people.people "/people", :action => "index", :conditions => { :method => :get }
- people.connect "/people", :action => "create", :conditions => { :method => :post }
- people.person "/people/:id", :action => "show", :conditions => { :method => :get }
- people.connect "/people/:id", :action => "update", :conditions => { :method => :put }
- people.connect "/people/:id", :action => "destroy", :conditions => { :method => :delete }
+ assert_equal '/categories', rs.generate(:controller => 'content', :action => 'categories')
+ assert_equal '/content/hi', rs.generate({:controller => 'content', :action => 'hi'})
+ end
+
+ def test_named_routes_array
+ test_named_route_method
+ assert_equal [:categories], rs.named_routes.names
+ end
+
+ def test_nil_defaults
+ rs.draw do |map|
+ map.connect 'journal',
+ :controller => 'content',
+ :action => 'list_journal',
+ :date => nil, :user_id => nil
+ map.connect ':controller/:action/:id'
end
+
+ assert_equal '/journal', rs.generate(:controller => 'content', :action => 'list_journal', :date => nil, :user_id => nil)
end
- request.path = "/people"
- request.method = :get
- assert_nothing_raised { set.recognize(request) }
- assert_equal("index", request.path_parameters[:action])
-
- request.method = :post
- assert_nothing_raised { set.recognize(request) }
- assert_equal("create", request.path_parameters[:action])
-
- request.method = :put
- assert_nothing_raised { set.recognize(request) }
- assert_equal("update", request.path_parameters[:action])
+ def setup_request_method_routes_for(method)
+ @request = ActionController::TestRequest.new
+ @request.env["REQUEST_METHOD"] = method
+ @request.request_uri = "/match"
- begin
- request.method = :bacon
- set.recognize(request)
- flunk 'Should have raised NotImplemented'
- rescue ActionController::NotImplemented => e
- assert_equal [:get, :post, :put, :delete], e.allowed_methods
+ rs.draw do |r|
+ r.connect '/match', :controller => 'books', :action => 'get', :conditions => { :method => :get }
+ r.connect '/match', :controller => 'books', :action => 'post', :conditions => { :method => :post }
+ r.connect '/match', :controller => 'books', :action => 'put', :conditions => { :method => :put }
+ r.connect '/match', :controller => 'books', :action => 'delete', :conditions => { :method => :delete }
+ end
end
- request.path = "/people/5"
- request.method = :get
- assert_nothing_raised { set.recognize(request) }
- assert_equal("show", request.path_parameters[:action])
- assert_equal("5", request.path_parameters[:id])
+ %w(GET POST PUT DELETE).each do |request_method|
+ define_method("test_request_method_recognized_with_#{request_method}") do
+ begin
+ Object.const_set(:BooksController, Class.new(ActionController::Base))
+
+ setup_request_method_routes_for(request_method)
- request.method = :put
- assert_nothing_raised { set.recognize(request) }
- assert_equal("update", request.path_parameters[:action])
- assert_equal("5", request.path_parameters[:id])
+ assert_nothing_raised { rs.recognize(@request) }
+ assert_equal request_method.downcase, @request.path_parameters[:action]
+ ensure
+ Object.send(:remove_const, :BooksController) rescue nil
+ end
+ end
+ end
- request.method = :delete
- assert_nothing_raised { set.recognize(request) }
- assert_equal("destroy", request.path_parameters[:action])
- assert_equal("5", request.path_parameters[:id])
+ def test_subpath_recognized
+ Object.const_set(:SubpathBooksController, Class.new(ActionController::Base))
- begin
- request.method = :post
- set.recognize(request)
- flunk 'Should have raised MethodNotAllowed'
- rescue ActionController::MethodNotAllowed => e
- assert_equal [:get, :put, :delete], e.allowed_methods
+ rs.draw do |r|
+ r.connect '/books/:id/edit', :controller => 'subpath_books', :action => 'edit'
+ r.connect '/items/:id/:action', :controller => 'subpath_books'
+ r.connect '/posts/new/:action', :controller => 'subpath_books'
+ r.connect '/posts/:id', :controller => 'subpath_books', :action => "show"
+ end
+
+ hash = rs.recognize_path "/books/17/edit"
+ assert_not_nil hash
+ assert_equal %w(subpath_books 17 edit), [hash[:controller], hash[:id], hash[:action]]
+
+ hash = rs.recognize_path "/items/3/complete"
+ assert_not_nil hash
+ assert_equal %w(subpath_books 3 complete), [hash[:controller], hash[:id], hash[:action]]
+
+ hash = rs.recognize_path "/posts/new/preview"
+ assert_not_nil hash
+ assert_equal %w(subpath_books preview), [hash[:controller], hash[:action]]
+
+ hash = rs.recognize_path "/posts/7"
+ assert_not_nil hash
+ assert_equal %w(subpath_books show 7), [hash[:controller], hash[:action], hash[:id]]
+ ensure
+ Object.send(:remove_const, :SubpathBooksController) rescue nil
end
- ensure
- Object.send(:remove_const, :PeopleController)
- end
-
- def test_recognize_with_alias_in_conditions
- Object.const_set(:PeopleController, Class.new)
+ def test_subpath_generated
+ Object.const_set(:SubpathBooksController, Class.new(ActionController::Base))
+
+ rs.draw do |r|
+ r.connect '/books/:id/edit', :controller => 'subpath_books', :action => 'edit'
+ r.connect '/items/:id/:action', :controller => 'subpath_books'
+ r.connect '/posts/new/:action', :controller => 'subpath_books'
+ end
- set.draw do |map|
- map.people "/people", :controller => 'people', :action => "index",
- :conditions => { :method => :get }
- map.root :people
+ assert_equal "/books/7/edit", rs.generate(:controller => "subpath_books", :id => 7, :action => "edit")
+ assert_equal "/items/15/complete", rs.generate(:controller => "subpath_books", :id => 15, :action => "complete")
+ assert_equal "/posts/new/preview", rs.generate(:controller => "subpath_books", :action => "preview")
+ ensure
+ Object.send(:remove_const, :SubpathBooksController) rescue nil
end
- request.path = "/people"
- request.method = :get
- assert_nothing_raised { set.recognize(request) }
- assert_equal("people", request.path_parameters[:controller])
- assert_equal("index", request.path_parameters[:action])
+ def test_failed_requirements_raises_exception_with_violated_requirements
+ rs.draw do |r|
+ r.foo_with_requirement 'foos/:id', :controller=>'foos', :requirements=>{:id=>/\d+/}
+ end
- request.path = "/"
- request.method = :get
- assert_nothing_raised { set.recognize(request) }
- assert_equal("people", request.path_parameters[:controller])
- assert_equal("index", request.path_parameters[:action])
- ensure
- Object.send(:remove_const, :PeopleController)
- end
-
- def test_typo_recognition
- Object.const_set(:ArticlesController, Class.new)
-
- set.draw do |map|
- map.connect 'articles/:year/:month/:day/:title',
- :controller => 'articles', :action => 'permalink',
- :year => /\d{4}/, :day => /\d{1,2}/, :month => /\d{1,2}/
- end
-
- request.path = "/articles/2005/11/05/a-very-interesting-article"
- 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])
-
- ensure
- Object.send(:remove_const, :ArticlesController)
+ x = setup_for_named_route
+ assert_raises(ActionController::RoutingError) do
+ x.send(:foo_with_requirement_url, "I am Against the requirements")
+ end
+ end
end
- def test_routing_traversal_does_not_load_extra_classes
- assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"
- set.draw do |map|
- map.connect '/profile', :controller => 'profile'
+ class RouteTest < Test::Unit::TestCase
+ def setup
+ @route = ROUTING::Route.new
end
- request.path = '/profile'
+ def slash_segment(is_optional = false)
+ returning ROUTING::DividerSegment.new('/') do |s|
+ s.is_optional = is_optional
+ end
+ end
- set.recognize(request) rescue nil
-
- assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"
- end
+ def default_route
+ unless defined?(@default_route)
+ @default_route = ROUTING::Route.new
+
+ @default_route.segments << (s = ROUTING::StaticSegment.new)
+ s.value = '/'
+ s.raw = true
+
+ @default_route.segments << (s = ROUTING::DynamicSegment.new)
+ s.key = :controller
+
+ @default_route.segments << slash_segment(:optional)
+ @default_route.segments << (s = ROUTING::DynamicSegment.new)
+ s.key = :action
+ s.default = 'index'
+ s.is_optional = true
- def test_recognize_with_conditions_and_format
- Object.const_set(:PeopleController, Class.new)
+ @default_route.segments << slash_segment(:optional)
+ @default_route.segments << (s = ROUTING::DynamicSegment.new)
+ s.key = :id
+ s.is_optional = true
- set.draw do |map|
- map.with_options(:controller => "people") do |people|
- people.person "/people/:id", :action => "show", :conditions => { :method => :get }
- people.connect "/people/:id", :action => "update", :conditions => { :method => :put }
- people.connect "/people/:id.:_format", :action => "show", :conditions => { :method => :get }
+ @default_route.segments << slash_segment(:optional)
end
+ @default_route
end
- request.path = "/people/5"
- request.method = :get
- assert_nothing_raised { set.recognize(request) }
- assert_equal("show", request.path_parameters[:action])
- assert_equal("5", request.path_parameters[:id])
+ def test_default_route_recognition
+ expected = {:controller => 'accounts', :action => 'show', :id => '10'}
+ assert_equal expected, default_route.recognize('/accounts/show/10')
+ assert_equal expected, default_route.recognize('/accounts/show/10/')
- request.method = :put
- assert_nothing_raised { set.recognize(request) }
- assert_equal("update", request.path_parameters[:action])
+ expected[:id] = 'jamis'
+ assert_equal expected, default_route.recognize('/accounts/show/jamis/')
- request.path = "/people/5.png"
- 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])
- ensure
- Object.send(:remove_const, :PeopleController)
- end
+ expected.delete :id
+ assert_equal expected, default_route.recognize('/accounts/show')
+ assert_equal expected, default_route.recognize('/accounts/show/')
- def test_generate_with_default_action
- set.draw do |map|
- map.connect "/people", :controller => "people"
- map.connect "/people/list", :controller => "people", :action => "list"
+ expected[:action] = 'index'
+ assert_equal expected, default_route.recognize('/accounts/')
+ assert_equal expected, default_route.recognize('/accounts')
+
+ assert_equal nil, default_route.recognize('/')
+ assert_equal nil, default_route.recognize('/accounts/how/goood/it/is/to/be/free')
end
- url = set.generate(:controller => "people", :action => "list")
- assert_equal "/people/list", url
- end
-
- def test_root_map
- Object.const_set(:PeopleController, Class.new)
+ def test_default_route_should_omit_default_action
+ o = {:controller => 'accounts', :action => 'index'}
+ assert_equal '/accounts', default_route.generate(o, o, {})
+ end
- set.draw { |map| map.root :controller => "people" }
+ def test_default_route_should_include_default_action_when_id_present
+ o = {:controller => 'accounts', :action => 'index', :id => '20'}
+ assert_equal '/accounts/index/20', default_route.generate(o, o, {})
+ end
- request.path = ""
- request.method = :get
- assert_nothing_raised { set.recognize(request) }
- assert_equal("people", request.path_parameters[:controller])
- assert_equal("index", request.path_parameters[:action])
- ensure
- Object.send(:remove_const, :PeopleController)
- end
-
-
- def test_namespace
- Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) })
+ def test_default_route_should_work_with_action_but_no_id
+ o = {:controller => 'accounts', :action => 'list_all'}
+ assert_equal '/accounts/list_all', default_route.generate(o, o, {})
+ end
+
+ def test_default_route_should_uri_escape_pluses
+ expected = { :controller => 'accounts', :action => 'show', :id => 'hello world' }
+ assert_equal expected, default_route.recognize('/accounts/show/hello world')
+ assert_equal expected, default_route.recognize('/accounts/show/hello%20world')
+ assert_equal '/accounts/show/hello%20world', default_route.generate(expected, expected, {})
+
+ expected[:id] = 'hello+world'
+ assert_equal expected, default_route.recognize('/accounts/show/hello+world')
+ assert_equal expected, default_route.recognize('/accounts/show/hello%2Bworld')
+ assert_equal '/accounts/show/hello+world', default_route.generate(expected, expected, {})
+ end
- set.draw do |map|
-
- map.namespace 'api' do |api|
- api.route 'inventory', :controller => "products", :action => 'inventory'
+ def test_matches_controller_and_action
+ # requirement_for should only be called for the action and controller _once_
+ @route.expects(:requirement_for).with(:controller).times(1).returns('pages')
+ @route.expects(:requirement_for).with(:action).times(1).returns('show')
+
+ @route.requirements = {:controller => 'pages', :action => 'show'}
+ assert @route.matches_controller_and_action?('pages', 'show')
+ assert !@route.matches_controller_and_action?('not_pages', 'show')
+ assert !@route.matches_controller_and_action?('pages', 'not_show')
+ end
+
+ def test_parameter_shell
+ page_url = ROUTING::Route.new
+ page_url.requirements = {:controller => 'pages', :action => 'show', :id => /\d+/}
+ assert_equal({:controller => 'pages', :action => 'show'}, page_url.parameter_shell)
+ end
+
+ def test_defaults
+ route = ROUTING::RouteBuilder.new.build '/users/:id.:format', :controller => "users", :action => "show", :format => "html"
+ assert_equal(
+ { :controller => "users", :action => "show", :format => "html" },
+ route.defaults)
+ end
+
+ def test_builder_complains_without_controller
+ assert_raises(ArgumentError) do
+ ROUTING::RouteBuilder.new.build '/contact', :contoller => "contact", :action => "index"
end
-
end
- request.path = "/api/inventory"
- request.method = :get
- assert_nothing_raised { set.recognize(request) }
- assert_equal("api/products", request.path_parameters[:controller])
- assert_equal("inventory", request.path_parameters[:action])
- ensure
- Object.send(:remove_const, :Api)
+ def test_significant_keys_for_default_route
+ keys = default_route.significant_keys.sort_by {|k| k.to_s }
+ assert_equal [:action, :controller, :id], keys
+ end
+
+ def test_significant_keys
+ user_url = ROUTING::Route.new
+ user_url.segments << (s = ROUTING::StaticSegment.new)
+ s.value = '/'
+ s.raw = true
+
+ user_url.segments << (s = ROUTING::StaticSegment.new)
+ s.value = 'user'
+
+ user_url.segments << (s = ROUTING::StaticSegment.new)
+ s.value = '/'
+ s.raw = true
+ s.is_optional = true
+
+ user_url.segments << (s = ROUTING::DynamicSegment.new)
+ s.key = :user
+
+ user_url.segments << (s = ROUTING::StaticSegment.new)
+ s.value = '/'
+ s.raw = true
+ s.is_optional = true
+
+ user_url.requirements = {:controller => 'users', :action => 'show'}
+
+ keys = user_url.significant_keys.sort_by { |k| k.to_s }
+ assert_equal [:action, :controller, :user], keys
+ end
+
+ def test_build_empty_query_string
+ assert_equal '', @route.build_query_string({})
+ end
+
+ def test_build_query_string_with_nil_value
+ assert_equal '', @route.build_query_string({:x => nil})
+ end
+
+ def test_simple_build_query_string
+ assert_equal '?x=1&y=2', order_query_string(@route.build_query_string(:x => '1', :y => '2'))
+ end
+
+ def test_convert_ints_build_query_string
+ assert_equal '?x=1&y=2', order_query_string(@route.build_query_string(:x => 1, :y => 2))
+ end
+
+ def test_escape_spaces_build_query_string
+ assert_equal '?x=hello+world&y=goodbye+world', order_query_string(@route.build_query_string(:x => 'hello world', :y => 'goodbye world'))
+ end
+
+ def test_expand_array_build_query_string
+ assert_equal '?x%5B%5D=1&x%5B%5D=2', order_query_string(@route.build_query_string(:x => [1, 2]))
+ end
+
+ def test_escape_spaces_build_query_string_selected_keys
+ assert_equal '?x=hello+world', order_query_string(@route.build_query_string({:x => 'hello world', :y => 'goodbye world'}, [:x]))
+ end
+
+ private
+ def order_query_string(qs)
+ '?' + qs[1..-1].split('&').sort.join('&')
+ end
end
-
- def test_namespaced_root_map
- Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) })
+ class RouteSetTest < Test::Unit::TestCase
+ def set
+ @set ||= ROUTING::RouteSet.new
+ end
+
+ def request
+ @request ||= MockRequest.new(:host => "named.routes.test", :method => :get)
+ end
+
+ def test_generate_extras
+ set.draw { |m| m.connect ':controller/:action/:id' }
+ path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
+ assert_equal "/foo/bar/15", path
+ assert_equal %w(that this), extras.map(&:to_s).sort
+ end
+
+ def test_extra_keys
+ set.draw { |m| m.connect ':controller/:action/:id' }
+ extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
+ assert_equal %w(that this), extras.map(&:to_s).sort
+ end
- set.draw do |map|
-
- map.namespace 'api' do |api|
- api.root :controller => "products"
+ def test_generate_extras_not_first
+ set.draw do |map|
+ map.connect ':controller/:action/:id.:format'
+ map.connect ':controller/:action/:id'
end
-
+ path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
+ assert_equal "/foo/bar/15", path
+ assert_equal %w(that this), extras.map(&:to_s).sort
end
- request.path = "/api"
- request.method = :get
- assert_nothing_raised { set.recognize(request) }
- assert_equal("api/products", request.path_parameters[:controller])
- assert_equal("index", request.path_parameters[:action])
- ensure
- Object.send(:remove_const, :Api)
- end
+ def test_generate_not_first
+ set.draw do |map|
+ map.connect ':controller/:action/:id.:format'
+ map.connect ':controller/:action/:id'
+ end
+ assert_equal "/foo/bar/15?this=hello", set.generate(:controller => "foo", :action => "bar", :id => 15, :this => "hello")
+ end
- def test_generate_finds_best_fit
- set.draw do |map|
- map.connect "/people", :controller => "people", :action => "index"
- map.connect "/ws/people", :controller => "people", :action => "index", :ws => true
+ def test_extra_keys_not_first
+ set.draw do |map|
+ map.connect ':controller/:action/:id.:format'
+ map.connect ':controller/:action/:id'
+ end
+ extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
+ assert_equal %w(that this), extras.map(&:to_s).sort
end
- url = set.generate(:controller => "people", :action => "index", :ws => true)
- assert_equal "/ws/people", url
- end
+ def test_draw
+ assert_equal 0, set.routes.size
+ set.draw do |map|
+ map.connect '/hello/world', :controller => 'a', :action => 'b'
+ end
+ assert_equal 1, set.routes.size
+ end
- def test_generate_changes_controller_module
- set.draw { |map| map.connect ':controller/:action/:id' }
- current = { :controller => "bling/bloop", :action => "bap", :id => 9 }
- url = set.generate({:controller => "foo/bar", :action => "baz", :id => 7}, current)
- assert_equal "/foo/bar/baz/7", url
- end
+ def test_named_draw
+ assert_equal 0, set.routes.size
+ set.draw do |map|
+ map.hello '/hello/world', :controller => 'a', :action => 'b'
+ end
+ assert_equal 1, set.routes.size
+ assert_equal set.routes.first, set.named_routes[:hello]
+ end
- def test_id_is_not_impossibly_sticky
- set.draw do |map|
- map.connect 'foo/:number', :controller => "people", :action => "index"
- map.connect ':controller/:action/:id'
+ def test_later_named_routes_take_precedence
+ set.draw do |map|
+ map.hello '/hello/world', :controller => 'a', :action => 'b'
+ map.hello '/hello', :controller => 'a', :action => 'b'
+ end
+ assert_equal set.routes.last, set.named_routes[:hello]
end
- url = set.generate({:controller => "people", :action => "index", :number => 3},
- {:controller => "people", :action => "index", :id => "21"})
- assert_equal "/foo/3", url
- end
+ def setup_named_route_test
+ set.draw do |map|
+ map.show '/people/:id', :controller => 'people', :action => 'show'
+ map.index '/people', :controller => 'people', :action => 'index'
+ map.multi '/people/go/:foo/:bar/joe/:id', :controller => 'people', :action => 'multi'
+ map.users '/admin/users', :controller => 'admin/users', :action => 'index'
+ end
- def test_id_is_sticky_when_it_ought_to_be
- set.draw do |map|
- map.connect ':controller/:id/:action'
+ klass = Class.new(MockController)
+ set.install_helpers(klass)
+ klass.new(set)
end
- url = set.generate({:action => "destroy"}, {:controller => "people", :action => "show", :id => "7"})
- assert_equal "/people/7/destroy", url
- end
+ def test_named_route_hash_access_method
+ controller = setup_named_route_test
+
+ assert_equal(
+ { :controller => 'people', :action => 'show', :id => 5, :use_route => :show, :only_path => false },
+ controller.send(:hash_for_show_url, :id => 5))
+
+ assert_equal(
+ { :controller => 'people', :action => 'index', :use_route => :index, :only_path => false },
+ controller.send(:hash_for_index_url))
- def test_use_static_path_when_possible
- set.draw do |map|
- map.connect 'about', :controller => "welcome", :action => "about"
- map.connect ':controller/:action/:id'
+ assert_equal(
+ { :controller => 'people', :action => 'show', :id => 5, :use_route => :show, :only_path => true },
+ controller.send(:hash_for_show_path, :id => 5)
+ )
end
- url = set.generate({:controller => "welcome", :action => "about"},
- {:controller => "welcome", :action => "get", :id => "7"})
- assert_equal "/about", url
- end
+ def test_named_route_url_method
+ controller = setup_named_route_test
- def test_generate
- set.draw { |map| map.connect ':controller/:action/:id' }
+ assert_equal "http://named.route.test/people/5", controller.send(:show_url, :id => 5)
+ assert_equal "/people/5", controller.send(:show_path, :id => 5)
- args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" }
- assert_equal "/foo/bar/7?x=y", set.generate(args)
- assert_equal ["/foo/bar/7", [:x]], set.generate_extras(args)
- assert_equal [:x], set.extra_keys(args)
- end
+ assert_equal "http://named.route.test/people", controller.send(:index_url)
+ assert_equal "/people", controller.send(:index_path)
- def test_named_routes_are_never_relative_to_modules
- set.draw do |map|
- map.connect "/connection/manage/:action", :controller => 'connection/manage'
- map.connect "/connection/connection", :controller => "connection/connection"
- map.family_connection "/connection", :controller => "connection"
+ assert_equal "http://named.route.test/admin/users", controller.send(:users_url)
+ assert_equal '/admin/users', controller.send(:users_path)
+ assert_equal '/admin/users', set.generate(controller.send(:hash_for_users_url), {:controller => 'users', :action => 'index'})
end
- url = set.generate({:controller => "connection"}, {:controller => 'connection/manage'})
- assert_equal "/connection/connection", url
+ def test_named_route_url_method_with_anchor
+ controller = setup_named_route_test
- url = set.generate({:use_route => :family_connection, :controller => "connection"}, {:controller => 'connection/manage'})
- assert_equal "/connection", url
- end
-
- def test_action_left_off_when_id_is_recalled
- set.draw do |map|
- map.connect ':controller/:action/:id'
+ assert_equal "http://named.route.test/people/5#location", controller.send(:show_url, :id => 5, :anchor => 'location')
+ assert_equal "/people/5#location", controller.send(:show_path, :id => 5, :anchor => 'location')
+
+ assert_equal "http://named.route.test/people#location", controller.send(:index_url, :anchor => 'location')
+ assert_equal "/people#location", controller.send(:index_path, :anchor => 'location')
+
+ assert_equal "http://named.route.test/admin/users#location", controller.send(:users_url, :anchor => 'location')
+ assert_equal '/admin/users#location', controller.send(:users_path, :anchor => 'location')
+
+ assert_equal "http://named.route.test/people/go/7/hello/joe/5#location",
+ controller.send(:multi_url, 7, "hello", 5, :anchor => 'location')
+
+ assert_equal "http://named.route.test/people/go/7/hello/joe/5?baz=bar#location",
+ controller.send(:multi_url, 7, "hello", 5, :baz => "bar", :anchor => 'location')
+
+ assert_equal "http://named.route.test/people?baz=bar#location",
+ controller.send(:index_url, :baz => "bar", :anchor => 'location')
end
- assert_equal '/post', set.generate(
- {:controller => 'post', :action => 'index'},
- {:controller => 'post', :action => 'show', :id => '10'}
- )
- end
-
- def test_query_params_will_be_shown_when_recalled
- set.draw do |map|
- map.connect 'show_post/:parameter', :controller => 'post', :action => 'show'
- map.connect ':controller/:action/:id'
+
+ def test_named_route_url_method_with_port
+ controller = setup_named_route_test
+ assert_equal "http://named.route.test:8080/people/5", controller.send(:show_url, 5, :port=>8080)
end
- assert_equal '/post/edit?parameter=1', set.generate(
- {:action => 'edit', :parameter => 1},
- {:controller => 'post', :action => 'show', :parameter => 1}
- )
- end
- def test_expiry_determination_should_consider_values_with_to_param
- set.draw { |map| map.connect 'projects/:project_id/:controller/:action' }
- assert_equal '/projects/1/post/show', set.generate(
- {:action => 'show', :project_id => 1},
- {:controller => 'post', :action => 'show', :project_id => '1'})
- end
+ def test_named_route_url_method_with_host
+ controller = setup_named_route_test
+ assert_equal "http://some.example.com/people/5", controller.send(:show_url, 5, :host=>"some.example.com")
+ end
- def test_generate_all
- set.draw do |map|
- map.connect 'show_post/:id', :controller => 'post', :action => 'show'
- map.connect ':controller/:action/:id'
+ def test_named_route_url_method_with_ordered_parameters
+ controller = setup_named_route_test
+ assert_equal "http://named.route.test/people/go/7/hello/joe/5",
+ controller.send(:multi_url, 7, "hello", 5)
end
- all = set.generate(
- {:action => 'show', :id => 10, :generate_all => true},
- {:controller => 'post', :action => 'show'}
- )
- assert_equal 2, all.length
- assert_equal '/show_post/10', all.first
- assert_equal '/post/show/10', all.last
- end
-
- def test_named_route_in_nested_resource
- set.draw do |map|
- map.resources :projects do |project|
- project.milestones 'milestones', :controller => 'milestones', :action => 'index'
- end
- end
-
- request.path = "/projects/1/milestones"
- request.method = :get
- assert_nothing_raised { set.recognize(request) }
- assert_equal("milestones", request.path_parameters[:controller])
- assert_equal("index", request.path_parameters[:action])
- end
-
- def test_setting_root_in_namespace_using_symbol
- assert_nothing_raised do
+
+ def test_named_route_url_method_with_ordered_parameters_and_hash
+ controller = setup_named_route_test
+ assert_equal "http://named.route.test/people/go/7/hello/joe/5?baz=bar",
+ controller.send(:multi_url, 7, "hello", 5, :baz => "bar")
+ end
+
+ def test_named_route_url_method_with_no_positional_arguments
+ controller = setup_named_route_test
+ assert_equal "http://named.route.test/people?baz=bar",
+ controller.send(:index_url, :baz => "bar")
+ end
+
+ def test_draw_default_route
+ ActionController::Routing.with_controllers(['users']) do
+ set.draw do |map|
+ map.connect '/:controller/:action/:id'
+ end
+
+ assert_equal 1, set.routes.size
+ route = set.routes.first
+
+ assert route.segments.last.optional?
+
+ assert_equal '/users/show/10', set.generate(:controller => 'users', :action => 'show', :id => 10)
+ assert_equal '/users/index/10', set.generate(:controller => 'users', :id => 10)
+
+ assert_equal({:controller => 'users', :action => 'index', :id => '10'}, set.recognize_path('/users/index/10'))
+ assert_equal({:controller => 'users', :action => 'index', :id => '10'}, set.recognize_path('/users/index/10/'))
+ end
+ end
+
+ def test_draw_default_route_with_default_controller
+ ActionController::Routing.with_controllers(['users']) do
+ set.draw do |map|
+ map.connect '/:controller/:action/:id', :controller => 'users'
+ end
+ assert_equal({:controller => 'users', :action => 'index'}, set.recognize_path('/'))
+ end
+ end
+
+ def test_route_with_parameter_shell
+ ActionController::Routing.with_controllers(['users', 'pages']) do
+ set.draw do |map|
+ map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+/
+ map.connect '/:controller/:action/:id'
+ end
+
+ assert_equal({:controller => 'pages', :action => 'index'}, set.recognize_path('/pages'))
+ assert_equal({:controller => 'pages', :action => 'index'}, set.recognize_path('/pages/index'))
+ assert_equal({:controller => 'pages', :action => 'list'}, set.recognize_path('/pages/list'))
+
+ assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, set.recognize_path('/pages/show/10'))
+ assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, set.recognize_path('/page/10'))
+ end
+ end
+
+ def test_route_requirements_with_anchor_chars_are_invalid
+ assert_raises ArgumentError do
+ set.draw do |map|
+ map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /^\d+/
+ end
+ end
+ assert_raises ArgumentError do
+ set.draw do |map|
+ map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\A\d+/
+ end
+ end
+ assert_raises ArgumentError do
+ set.draw do |map|
+ map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+$/
+ end
+ end
+ assert_raises ArgumentError do
+ set.draw do |map|
+ map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+\Z/
+ end
+ end
+ assert_raises ArgumentError do
+ set.draw do |map|
+ map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+\z/
+ end
+ end
+ assert_nothing_raised do
+ set.draw do |map|
+ map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+/, :name => /^(david|jamis)/
+ end
+ assert_raises ActionController::RoutingError do
+ set.generate :controller => 'pages', :action => 'show', :id => 10
+ end
+ end
+ end
+
+ def test_non_path_route_requirements_match_all
set.draw do |map|
- map.namespace :admin do |admin|
- admin.root :controller => 'home'
+ map.connect 'page/37s', :controller => 'pages', :action => 'show', :name => /(jamis|david)/
+ end
+ assert_equal '/page/37s', set.generate(:controller => 'pages', :action => 'show', :name => 'jamis')
+ assert_raises ActionController::RoutingError do
+ set.generate(:controller => 'pages', :action => 'show', :name => 'not_jamis')
+ end
+ assert_raises ActionController::RoutingError do
+ set.generate(:controller => 'pages', :action => 'show', :name => 'nor_jamis_and_david')
+ end
+ end
+
+ def test_recognize_with_encoded_id_and_regex
+ set.draw do |map|
+ map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /[a-zA-Z0-9\+]+/
+ end
+
+ assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, set.recognize_path('/page/10'))
+ assert_equal({:controller => 'pages', :action => 'show', :id => 'hello+world'}, set.recognize_path('/page/hello+world'))
+ end
+
+ def test_recognize_with_conditions
+ Object.const_set(:PeopleController, Class.new)
+
+ set.draw do |map|
+ map.with_options(:controller => "people") do |people|
+ people.people "/people", :action => "index", :conditions => { :method => :get }
+ people.connect "/people", :action => "create", :conditions => { :method => :post }
+ people.person "/people/:id", :action => "show", :conditions => { :method => :get }
+ people.connect "/people/:id", :action => "update", :conditions => { :method => :put }
+ people.connect "/people/:id", :action => "destroy", :conditions => { :method => :delete }
end
end
+
+ request.path = "/people"
+ request.method = :get
+ assert_nothing_raised { set.recognize(request) }
+ assert_equal("index", request.path_parameters[:action])
+
+ request.method = :post
+ assert_nothing_raised { set.recognize(request) }
+ assert_equal("create", request.path_parameters[:action])
+
+ request.method = :put
+ assert_nothing_raised { set.recognize(request) }
+ assert_equal("update", request.path_parameters[:action])
+
+ begin
+ request.method = :bacon
+ set.recognize(request)
+ flunk 'Should have raised NotImplemented'
+ rescue ActionController::NotImplemented => e
+ assert_equal [:get, :post, :put, :delete], e.allowed_methods
+ end
+
+ request.path = "/people/5"
+ request.method = :get
+ assert_nothing_raised { set.recognize(request) }
+ assert_equal("show", request.path_parameters[:action])
+ assert_equal("5", request.path_parameters[:id])
+
+ request.method = :put
+ assert_nothing_raised { set.recognize(request) }
+ assert_equal("update", request.path_parameters[:action])
+ assert_equal("5", request.path_parameters[:id])
+
+ request.method = :delete
+ assert_nothing_raised { set.recognize(request) }
+ assert_equal("destroy", request.path_parameters[:action])
+ assert_equal("5", request.path_parameters[:id])
+
+ begin
+ request.method = :post
+ set.recognize(request)
+ flunk 'Should have raised MethodNotAllowed'
+ rescue ActionController::MethodNotAllowed => e
+ assert_equal [:get, :put, :delete], e.allowed_methods
+ end
+
+ ensure
+ Object.send(:remove_const, :PeopleController)
end
- end
-
- def test_setting_root_in_namespace_using_string
- assert_nothing_raised do
+
+ def test_recognize_with_alias_in_conditions
+ Object.const_set(:PeopleController, Class.new)
+
+ set.draw do |map|
+ map.people "/people", :controller => 'people', :action => "index",
+ :conditions => { :method => :get }
+ map.root :people
+ end
+
+ request.path = "/people"
+ request.method = :get
+ assert_nothing_raised { set.recognize(request) }
+ assert_equal("people", request.path_parameters[:controller])
+ assert_equal("index", request.path_parameters[:action])
+
+ request.path = "/"
+ request.method = :get
+ assert_nothing_raised { set.recognize(request) }
+ assert_equal("people", request.path_parameters[:controller])
+ assert_equal("index", request.path_parameters[:action])
+ ensure
+ Object.send(:remove_const, :PeopleController)
+ end
+
+ def test_typo_recognition
+ Object.const_set(:ArticlesController, Class.new)
+
set.draw do |map|
- map.namespace 'admin' do |admin|
- admin.root :controller => 'home'
+ map.connect 'articles/:year/:month/:day/:title',
+ :controller => 'articles', :action => 'permalink',
+ :year => /\d{4}/, :day => /\d{1,2}/, :month => /\d{1,2}/
+ end
+
+ request.path = "/articles/2005/11/05/a-very-interesting-article"
+ 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])
+
+ ensure
+ Object.send(:remove_const, :ArticlesController)
+ end
+
+ def test_routing_traversal_does_not_load_extra_classes
+ assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"
+ set.draw do |map|
+ map.connect '/profile', :controller => 'profile'
+ end
+
+ request.path = '/profile'
+
+ set.recognize(request) rescue nil
+
+ assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"
+ end
+
+ def test_recognize_with_conditions_and_format
+ Object.const_set(:PeopleController, Class.new)
+
+ set.draw do |map|
+ map.with_options(:controller => "people") do |people|
+ people.person "/people/:id", :action => "show", :conditions => { :method => :get }
+ people.connect "/people/:id", :action => "update", :conditions => { :method => :put }
+ people.connect "/people/:id.:_format", :action => "show", :conditions => { :method => :get }
end
end
+
+ request.path = "/people/5"
+ request.method = :get
+ assert_nothing_raised { set.recognize(request) }
+ assert_equal("show", request.path_parameters[:action])
+ assert_equal("5", request.path_parameters[:id])
+
+ request.method = :put
+ assert_nothing_raised { set.recognize(request) }
+ assert_equal("update", request.path_parameters[:action])
+
+ request.path = "/people/5.png"
+ 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])
+ ensure
+ Object.send(:remove_const, :PeopleController)
end
- end
- def test_route_requirements_with_unsupported_regexp_options_must_error
- assert_raises ArgumentError do
+ def test_generate_with_default_action
set.draw do |map|
- map.connect 'page/:name', :controller => 'pages',
- :action => 'show',
- :requirements => {:name => /(david|jamis)/m}
+ map.connect "/people", :controller => "people"
+ map.connect "/people/list", :controller => "people", :action => "list"
end
+
+ url = set.generate(:controller => "people", :action => "list")
+ assert_equal "/people/list", url
end
- end
- def test_route_requirements_with_supported_options_must_not_error
- assert_nothing_raised do
+ def test_root_map
+ Object.const_set(:PeopleController, Class.new)
+
+ set.draw { |map| map.root :controller => "people" }
+
+ request.path = ""
+ request.method = :get
+ assert_nothing_raised { set.recognize(request) }
+ assert_equal("people", request.path_parameters[:controller])
+ assert_equal("index", request.path_parameters[:action])
+ ensure
+ Object.send(:remove_const, :PeopleController)
+ end
+
+ def test_namespace
+ Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) })
+
set.draw do |map|
- map.connect 'page/:name', :controller => 'pages',
- :action => 'show',
- :requirements => {:name => /(david|jamis)/i}
+
+ map.namespace 'api' do |api|
+ api.route 'inventory', :controller => "products", :action => 'inventory'
+ end
+
end
+
+ request.path = "/api/inventory"
+ request.method = :get
+ assert_nothing_raised { set.recognize(request) }
+ assert_equal("api/products", request.path_parameters[:controller])
+ assert_equal("inventory", request.path_parameters[:action])
+ ensure
+ Object.send(:remove_const, :Api)
end
- assert_nothing_raised do
+
+ def test_namespaced_root_map
+ Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) })
+
set.draw do |map|
- map.connect 'page/:name', :controller => 'pages',
- :action => 'show',
- :requirements => {:name => / # Desperately overcommented regexp
- ( #Either
- david #The Creator
- | #Or
- jamis #The Deployer
- )/x}
+
+ map.namespace 'api' do |api|
+ api.root :controller => "products"
+ end
+
end
+
+ request.path = "/api"
+ request.method = :get
+ assert_nothing_raised { set.recognize(request) }
+ assert_equal("api/products", request.path_parameters[:controller])
+ assert_equal("index", request.path_parameters[:action])
+ ensure
+ Object.send(:remove_const, :Api)
end
- end
- def test_route_requirement_recognize_with_ignore_case
- set.draw do |map|
- map.connect 'page/:name', :controller => 'pages',
- :action => 'show',
- :requirements => {:name => /(david|jamis)/i}
+ def test_generate_finds_best_fit
+ set.draw do |map|
+ map.connect "/people", :controller => "people", :action => "index"
+ map.connect "/ws/people", :controller => "people", :action => "index", :ws => true
+ end
+
+ url = set.generate(:controller => "people", :action => "index", :ws => true)
+ assert_equal "/ws/people", url
end
- assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis'))
- assert_raises ActionController::RoutingError do
- set.recognize_path('/page/davidjamis')
+
+ def test_generate_changes_controller_module
+ set.draw { |map| map.connect ':controller/:action/:id' }
+ current = { :controller => "bling/bloop", :action => "bap", :id => 9 }
+ url = set.generate({:controller => "foo/bar", :action => "baz", :id => 7}, current)
+ assert_equal "/foo/bar/baz/7", url
end
- assert_equal({:controller => 'pages', :action => 'show', :name => 'DAVID'}, set.recognize_path('/page/DAVID'))
- end
- def test_route_requirement_generate_with_ignore_case
- set.draw do |map|
- map.connect 'page/:name', :controller => 'pages',
- :action => 'show',
- :requirements => {:name => /(david|jamis)/i}
+ def test_id_is_not_impossibly_sticky
+ set.draw do |map|
+ map.connect 'foo/:number', :controller => "people", :action => "index"
+ map.connect ':controller/:action/:id'
+ end
+
+ url = set.generate({:controller => "people", :action => "index", :number => 3},
+ {:controller => "people", :action => "index", :id => "21"})
+ assert_equal "/foo/3", url
end
- url = set.generate({:controller => 'pages', :action => 'show', :name => 'david'})
- assert_equal "/page/david", url
- assert_raises ActionController::RoutingError do
- url = set.generate({:controller => 'pages', :action => 'show', :name => 'davidjamis'})
+
+ def test_id_is_sticky_when_it_ought_to_be
+ set.draw do |map|
+ map.connect ':controller/:id/:action'
+ end
+
+ url = set.generate({:action => "destroy"}, {:controller => "people", :action => "show", :id => "7"})
+ assert_equal "/people/7/destroy", url
end
- url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
- assert_equal "/page/JAMIS", url
- end
- def test_route_requirement_recognize_with_extended_syntax
- set.draw do |map|
- map.connect 'page/:name', :controller => 'pages',
- :action => 'show',
- :requirements => {:name => / # Desperately overcommented regexp
- ( #Either
- david #The Creator
- | #Or
- jamis #The Deployer
- )/x}
+ def test_use_static_path_when_possible
+ set.draw do |map|
+ map.connect 'about', :controller => "welcome", :action => "about"
+ map.connect ':controller/:action/:id'
+ end
+
+ url = set.generate({:controller => "welcome", :action => "about"},
+ {:controller => "welcome", :action => "get", :id => "7"})
+ assert_equal "/about", url
end
- assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis'))
- assert_equal({:controller => 'pages', :action => 'show', :name => 'david'}, set.recognize_path('/page/david'))
- assert_raises ActionController::RoutingError do
- set.recognize_path('/page/david #The Creator')
+
+ def test_generate
+ set.draw { |map| map.connect ':controller/:action/:id' }
+
+ args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" }
+ assert_equal "/foo/bar/7?x=y", set.generate(args)
+ assert_equal ["/foo/bar/7", [:x]], set.generate_extras(args)
+ assert_equal [:x], set.extra_keys(args)
end
- assert_raises ActionController::RoutingError do
- set.recognize_path('/page/David')
+
+ def test_named_routes_are_never_relative_to_modules
+ set.draw do |map|
+ map.connect "/connection/manage/:action", :controller => 'connection/manage'
+ map.connect "/connection/connection", :controller => "connection/connection"
+ map.family_connection "/connection", :controller => "connection"
+ end
+
+ url = set.generate({:controller => "connection"}, {:controller => 'connection/manage'})
+ assert_equal "/connection/connection", url
+
+ url = set.generate({:use_route => :family_connection, :controller => "connection"}, {:controller => 'connection/manage'})
+ assert_equal "/connection", url
end
- end
- def test_route_requirement_generate_with_extended_syntax
- set.draw do |map|
- map.connect 'page/:name', :controller => 'pages',
- :action => 'show',
- :requirements => {:name => / # Desperately overcommented regexp
- ( #Either
- david #The Creator
- | #Or
- jamis #The Deployer
- )/x}
+ def test_action_left_off_when_id_is_recalled
+ set.draw do |map|
+ map.connect ':controller/:action/:id'
+ end
+ assert_equal '/post', set.generate(
+ {:controller => 'post', :action => 'index'},
+ {:controller => 'post', :action => 'show', :id => '10'}
+ )
end
- url = set.generate({:controller => 'pages', :action => 'show', :name => 'david'})
- assert_equal "/page/david", url
- assert_raises ActionController::RoutingError do
- url = set.generate({:controller => 'pages', :action => 'show', :name => 'davidjamis'})
+
+ def test_query_params_will_be_shown_when_recalled
+ set.draw do |map|
+ map.connect 'show_post/:parameter', :controller => 'post', :action => 'show'
+ map.connect ':controller/:action/:id'
+ end
+ assert_equal '/post/edit?parameter=1', set.generate(
+ {:action => 'edit', :parameter => 1},
+ {:controller => 'post', :action => 'show', :parameter => 1}
+ )
end
- assert_raises ActionController::RoutingError do
- url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
+
+ def test_expiry_determination_should_consider_values_with_to_param
+ set.draw { |map| map.connect 'projects/:project_id/:controller/:action' }
+ assert_equal '/projects/1/post/show', set.generate(
+ {:action => 'show', :project_id => 1},
+ {:controller => 'post', :action => 'show', :project_id => '1'})
end
- end
- def test_route_requirement_generate_with_xi_modifiers
- set.draw do |map|
- map.connect 'page/:name', :controller => 'pages',
- :action => 'show',
- :requirements => {:name => / # Desperately overcommented regexp
- ( #Either
- david #The Creator
- | #Or
- jamis #The Deployer
- )/xi}
+ def test_generate_all
+ set.draw do |map|
+ map.connect 'show_post/:id', :controller => 'post', :action => 'show'
+ map.connect ':controller/:action/:id'
+ end
+ all = set.generate(
+ {:action => 'show', :id => 10, :generate_all => true},
+ {:controller => 'post', :action => 'show'}
+ )
+ assert_equal 2, all.length
+ assert_equal '/show_post/10', all.first
+ assert_equal '/post/show/10', all.last
end
- url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
- assert_equal "/page/JAMIS", url
- end
- def test_route_requirement_recognize_with_xi_modifiers
- set.draw do |map|
- map.connect 'page/:name', :controller => 'pages',
- :action => 'show',
- :requirements => {:name => / # Desperately overcommented regexp
- ( #Either
- david #The Creator
- | #Or
- jamis #The Deployer
- )/xi}
+ def test_named_route_in_nested_resource
+ set.draw do |map|
+ map.resources :projects do |project|
+ project.milestones 'milestones', :controller => 'milestones', :action => 'index'
+ end
+ end
+
+ request.path = "/projects/1/milestones"
+ request.method = :get
+ assert_nothing_raised { set.recognize(request) }
+ assert_equal("milestones", request.path_parameters[:controller])
+ assert_equal("index", request.path_parameters[:action])
end
- assert_equal({:controller => 'pages', :action => 'show', :name => 'JAMIS'}, set.recognize_path('/page/JAMIS'))
- end
-
-end
+ def test_setting_root_in_namespace_using_symbol
+ assert_nothing_raised do
+ set.draw do |map|
+ map.namespace :admin do |admin|
+ admin.root :controller => 'home'
+ end
+ end
+ end
+ end
-class RoutingTest < Test::Unit::TestCase
-
- def test_possible_controllers
- true_controller_paths = ActionController::Routing.controller_paths
+ def test_setting_root_in_namespace_using_string
+ assert_nothing_raised do
+ set.draw do |map|
+ map.namespace 'admin' do |admin|
+ admin.root :controller => 'home'
+ end
+ end
+ end
+ end
- ActionController::Routing.use_controllers! nil
+ def test_route_requirements_with_unsupported_regexp_options_must_error
+ assert_raises ArgumentError do
+ set.draw do |map|
+ map.connect 'page/:name', :controller => 'pages',
+ :action => 'show',
+ :requirements => {:name => /(david|jamis)/m}
+ end
+ end
+ end
- silence_warnings do
- Object.send(:const_set, :RAILS_ROOT, File.dirname(__FILE__) + '/controller_fixtures')
+ def test_route_requirements_with_supported_options_must_not_error
+ assert_nothing_raised do
+ set.draw do |map|
+ map.connect 'page/:name', :controller => 'pages',
+ :action => 'show',
+ :requirements => {:name => /(david|jamis)/i}
+ end
+ end
+ assert_nothing_raised do
+ set.draw do |map|
+ map.connect 'page/:name', :controller => 'pages',
+ :action => 'show',
+ :requirements => {:name => / # Desperately overcommented regexp
+ ( #Either
+ david #The Creator
+ | #Or
+ jamis #The Deployer
+ )/x}
+ end
+ end
end
- ActionController::Routing.controller_paths = [
- RAILS_ROOT, RAILS_ROOT + '/app/controllers', RAILS_ROOT + '/vendor/plugins/bad_plugin/lib'
- ]
-
- assert_equal ["admin/user", "plugin", "user"], ActionController::Routing.possible_controllers.sort
- ensure
- if true_controller_paths
- ActionController::Routing.controller_paths = true_controller_paths
+ def test_route_requirement_recognize_with_ignore_case
+ set.draw do |map|
+ map.connect 'page/:name', :controller => 'pages',
+ :action => 'show',
+ :requirements => {:name => /(david|jamis)/i}
+ end
+ assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis'))
+ assert_raises ActionController::RoutingError do
+ set.recognize_path('/page/davidjamis')
+ end
+ assert_equal({:controller => 'pages', :action => 'show', :name => 'DAVID'}, set.recognize_path('/page/DAVID'))
end
- ActionController::Routing.use_controllers! nil
- Object.send(:remove_const, :RAILS_ROOT) rescue nil
- end
-
- def test_possible_controllers_are_reset_on_each_load
- true_possible_controllers = ActionController::Routing.possible_controllers
- true_controller_paths = ActionController::Routing.controller_paths
-
- ActionController::Routing.use_controllers! nil
- root = File.dirname(__FILE__) + '/controller_fixtures'
-
- ActionController::Routing.controller_paths = []
- assert_equal [], ActionController::Routing.possible_controllers
-
- ActionController::Routing::Routes.load!
- ActionController::Routing.controller_paths = [
- root, root + '/app/controllers', root + '/vendor/plugins/bad_plugin/lib'
- ]
-
- assert_equal ["admin/user", "plugin", "user"], ActionController::Routing.possible_controllers.sort
- ensure
- ActionController::Routing.controller_paths = true_controller_paths
- ActionController::Routing.use_controllers! true_possible_controllers
- Object.send(:remove_const, :RAILS_ROOT) rescue nil
-
- ActionController::Routing::Routes.clear!
- ActionController::Routing::Routes.load_routes!
- end
-
- def test_with_controllers
- c = %w(admin/accounts admin/users account pages)
- ActionController::Routing.with_controllers c do
- assert_equal c, ActionController::Routing.possible_controllers
+
+ def test_route_requirement_generate_with_ignore_case
+ set.draw do |map|
+ map.connect 'page/:name', :controller => 'pages',
+ :action => 'show',
+ :requirements => {:name => /(david|jamis)/i}
+ end
+ url = set.generate({:controller => 'pages', :action => 'show', :name => 'david'})
+ assert_equal "/page/david", url
+ assert_raises ActionController::RoutingError do
+ url = set.generate({:controller => 'pages', :action => 'show', :name => 'davidjamis'})
+ end
+ url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
+ assert_equal "/page/JAMIS", url
end
- end
- def test_normalize_unix_paths
- load_paths = %w(. config/../app/controllers config/../app//helpers script/../config/../vendor/rails/actionpack/lib vendor/rails/railties/builtin/rails_info app/models lib script/../config/../foo/bar/../../app/models .foo/../.bar foo.bar/../config)
- paths = ActionController::Routing.normalize_paths(load_paths)
- 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_route_requirement_recognize_with_extended_syntax
+ set.draw do |map|
+ map.connect 'page/:name', :controller => 'pages',
+ :action => 'show',
+ :requirements => {:name => / # Desperately overcommented regexp
+ ( #Either
+ david #The Creator
+ | #Or
+ jamis #The Deployer
+ )/x}
+ end
+ assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis'))
+ assert_equal({:controller => 'pages', :action => 'show', :name => 'david'}, set.recognize_path('/page/david'))
+ assert_raises ActionController::RoutingError do
+ set.recognize_path('/page/david #The Creator')
+ end
+ assert_raises ActionController::RoutingError do
+ set.recognize_path('/page/David')
+ end
+ 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
+ def test_route_requirement_generate_with_extended_syntax
+ set.draw do |map|
+ map.connect 'page/:name', :controller => 'pages',
+ :action => 'show',
+ :requirements => {:name => / # Desperately overcommented regexp
+ ( #Either
+ david #The Creator
+ | #Or
+ jamis #The Deployer
+ )/x}
+ end
+ url = set.generate({:controller => 'pages', :action => 'show', :name => 'david'})
+ assert_equal "/page/david", url
+ assert_raises ActionController::RoutingError do
+ url = set.generate({:controller => 'pages', :action => 'show', :name => 'davidjamis'})
+ end
+ assert_raises ActionController::RoutingError do
+ url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
+ end
+ end
-end
+ def test_route_requirement_generate_with_xi_modifiers
+ set.draw do |map|
+ map.connect 'page/:name', :controller => 'pages',
+ :action => 'show',
+ :requirements => {:name => / # Desperately overcommented regexp
+ ( #Either
+ david #The Creator
+ | #Or
+ jamis #The Deployer
+ )/xi}
+ end
+ url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
+ assert_equal "/page/JAMIS", url
+ end
-uses_mocha 'route loading' do
- class RouteLoadingTest < Test::Unit::TestCase
+ def test_route_requirement_recognize_with_xi_modifiers
+ set.draw do |map|
+ map.connect 'page/:name', :controller => 'pages',
+ :action => 'show',
+ :requirements => {:name => / # Desperately overcommented regexp
+ ( #Either
+ david #The Creator
+ | #Or
+ jamis #The Deployer
+ )/xi}
+ end
+ assert_equal({:controller => 'pages', :action => 'show', :name => 'JAMIS'}, set.recognize_path('/page/JAMIS'))
+ end
+ end
+ class RouteLoadingTest < Test::Unit::TestCase
def setup
routes.instance_variable_set '@routes_last_modified', nil
silence_warnings { Object.const_set :RAILS_ROOT, '.' }
@@ -2392,12 +2364,12 @@ uses_mocha 'route loading' do
end
def test_adding_inflections_forces_reload
- Inflector::Inflections.instance.expects(:uncountable).with('equipment')
+ ActiveSupport::Inflector::Inflections.instance.expects(:uncountable).with('equipment')
routes.expects(:reload!)
- Inflector.inflections { |inflect| inflect.uncountable('equipment') }
+ ActiveSupport::Inflector.inflections { |inflect| inflect.uncountable('equipment') }
end
-
+
def test_load_with_configuration
routes.configuration_file = "foobarbaz"
File.expects(:stat).returns(@stat)
@@ -2407,9 +2379,8 @@ uses_mocha 'route loading' do
end
private
- def routes
- ActionController::Routing::Routes
- end
-
+ def routes
+ ActionController::Routing::Routes
+ end
end
end
diff --git a/actionpack/test/controller/verification_test.rb b/actionpack/test/controller/verification_test.rb
index d6fde35f83..b289443129 100644
--- a/actionpack/test/controller/verification_test.rb
+++ b/actionpack/test/controller/verification_test.rb
@@ -21,10 +21,10 @@ class VerificationTest < Test::Unit::TestCase
verify :only => :guarded_by_method, :method => :post,
:redirect_to => { :action => "unguarded" }
-
+
verify :only => :guarded_by_xhr, :xhr => true,
:redirect_to => { :action => "unguarded" }
-
+
verify :only => :guarded_by_not_xhr, :xhr => false,
:redirect_to => { :action => "unguarded" }
@@ -39,10 +39,13 @@ class VerificationTest < Test::Unit::TestCase
verify :only => :no_default_action, :params => "santa"
+ verify :only => :guarded_with_back, :method => :post,
+ :redirect_to => :back
+
def guarded_one
render :text => "#{params[:one]}"
end
-
+
def guarded_one_for_named_route_test
render :text => "#{params[:one]}"
end
@@ -70,11 +73,11 @@ class VerificationTest < Test::Unit::TestCase
def guarded_by_method
render :text => "#{request.method}"
end
-
+
def guarded_by_xhr
render :text => "#{request.xhr?}"
end
-
+
def guarded_by_not_xhr
render :text => "#{request.xhr?}"
end
@@ -86,15 +89,19 @@ class VerificationTest < Test::Unit::TestCase
def two_redirects
render :nothing => true
end
-
+
def must_be_post
render :text => "Was a post!"
end
-
+
+ def guarded_with_back
+ render :text => "#{params[:one]}"
+ end
+
def no_default_action
# Will never run
end
-
+
protected
def rescue_action(e) raise end
@@ -109,7 +116,17 @@ class VerificationTest < Test::Unit::TestCase
@response = ActionController::TestResponse.new
ActionController::Routing::Routes.add_named_route :foo, '/foo', :controller => 'test', :action => 'foo'
end
-
+
+ def test_using_symbol_back_with_no_referrer
+ assert_raise(ActionController::RedirectBackError) { get :guarded_with_back }
+ end
+
+ def test_using_symbol_back_redirects_to_referrer
+ @request.env["HTTP_REFERER"] = "/foo"
+ get :guarded_with_back
+ assert_redirected_to '/foo'
+ end
+
def test_no_deprecation_warning_for_named_route
assert_not_deprecated do
get :guarded_one_for_named_route_test, :two => "not one"
@@ -209,44 +226,44 @@ class VerificationTest < Test::Unit::TestCase
get :guarded_by_method
assert_redirected_to :action => "unguarded"
end
-
+
def test_guarded_by_xhr_with_prereqs
xhr :post, :guarded_by_xhr
assert_equal "true", @response.body
end
-
+
def test_guarded_by_xhr_without_prereqs
get :guarded_by_xhr
assert_redirected_to :action => "unguarded"
end
-
+
def test_guarded_by_not_xhr_with_prereqs
get :guarded_by_not_xhr
assert_equal "false", @response.body
end
-
+
def test_guarded_by_not_xhr_without_prereqs
xhr :post, :guarded_by_not_xhr
assert_redirected_to :action => "unguarded"
end
-
+
def test_guarded_post_and_calls_render_succeeds
post :must_be_post
assert_equal "Was a post!", @response.body
end
-
+
def test_default_failure_should_be_a_bad_request
post :no_default_action
assert_response :bad_request
end
-
+
def test_guarded_post_and_calls_render_fails_and_sets_allow_header
get :must_be_post
assert_response 405
assert_equal "Must be post", @response.body
assert_equal "POST", @response.headers["Allow"]
end
-
+
def test_second_redirect
assert_nothing_raised { get :two_redirects }
end
diff --git a/actionpack/test/controller/view_paths_test.rb b/actionpack/test/controller/view_paths_test.rb
index 0516da32d8..1b4c1fae2f 100644
--- a/actionpack/test/controller/view_paths_test.rb
+++ b/actionpack/test/controller/view_paths_test.rb
@@ -1,30 +1,30 @@
require 'abstract_unit'
class ViewLoadPathsTest < Test::Unit::TestCase
-
LOAD_PATH_ROOT = File.join(File.dirname(__FILE__), '..', 'fixtures')
- ActionController::Base.view_paths = [ LOAD_PATH_ROOT ]
+ ActionController::Base.view_paths = [LOAD_PATH_ROOT]
class TestController < ActionController::Base
def self.controller_path() "test" end
def rescue_action(e) raise end
-
+
before_filter :add_view_path, :only => :hello_world_at_request_time
-
+
def hello_world() end
def hello_world_at_request_time() render(:action => 'hello_world') end
+
private
- def add_view_path
- prepend_view_path "#{LOAD_PATH_ROOT}/override"
- end
+ def add_view_path
+ prepend_view_path "#{LOAD_PATH_ROOT}/override"
+ end
end
-
+
class Test::SubController < ActionController::Base
layout 'test/sub'
def hello_world; render(:template => 'test/hello_world'); end
end
-
+
def setup
TestController.view_paths = nil
@@ -41,68 +41,80 @@ class ViewLoadPathsTest < Test::Unit::TestCase
@last_message = nil
ActiveSupport::Deprecation.behavior = Proc.new { |message, callback| @last_message = message }
end
-
+
def teardown
ActiveSupport::Deprecation.behavior = @old_behavior
end
-
+
def test_template_load_path_was_set_correctly
- assert_equal [ LOAD_PATH_ROOT ], @controller.view_paths
+ assert_equal [ LOAD_PATH_ROOT ], @controller.view_paths.map(&:to_s)
end
-
+
def test_controller_appends_view_path_correctly
@controller.append_view_path 'foo'
- assert_equal [LOAD_PATH_ROOT, 'foo'], @controller.view_paths
-
+ assert_equal [LOAD_PATH_ROOT, 'foo'], @controller.view_paths.map(&:to_s)
+
@controller.append_view_path(%w(bar baz))
- assert_equal [LOAD_PATH_ROOT, 'foo', 'bar', 'baz'], @controller.view_paths
+ assert_equal [LOAD_PATH_ROOT, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s)
+
+ @controller.append_view_path(LOAD_PATH_ROOT)
+ assert_equal ['foo', 'bar', 'baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s)
+
+ @controller.append_view_path([LOAD_PATH_ROOT])
+ assert_equal ['foo', 'bar', 'baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s)
end
-
+
def test_controller_prepends_view_path_correctly
@controller.prepend_view_path 'baz'
- assert_equal ['baz', LOAD_PATH_ROOT], @controller.view_paths
-
+ assert_equal ['baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s)
+
@controller.prepend_view_path(%w(foo bar))
- assert_equal ['foo', 'bar', 'baz', LOAD_PATH_ROOT], @controller.view_paths
+ assert_equal ['foo', 'bar', 'baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s)
+
+ @controller.prepend_view_path(LOAD_PATH_ROOT)
+ assert_equal [LOAD_PATH_ROOT, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s)
+
+ @controller.prepend_view_path([LOAD_PATH_ROOT])
+ assert_equal [LOAD_PATH_ROOT, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s)
end
-
+
def test_template_appends_view_path_correctly
@controller.instance_variable_set :@template, ActionView::Base.new(TestController.view_paths, {}, @controller)
class_view_paths = TestController.view_paths
@controller.append_view_path 'foo'
- assert_equal [LOAD_PATH_ROOT, 'foo'], @controller.view_paths
-
+ assert_equal [LOAD_PATH_ROOT, 'foo'], @controller.view_paths.map(&:to_s)
+
@controller.append_view_path(%w(bar baz))
- assert_equal [LOAD_PATH_ROOT, 'foo', 'bar', 'baz'], @controller.view_paths
+ assert_equal [LOAD_PATH_ROOT, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s)
assert_equal class_view_paths, TestController.view_paths
end
-
+
def test_template_prepends_view_path_correctly
@controller.instance_variable_set :@template, ActionView::Base.new(TestController.view_paths, {}, @controller)
class_view_paths = TestController.view_paths
-
+
@controller.prepend_view_path 'baz'
- assert_equal ['baz', LOAD_PATH_ROOT], @controller.view_paths
-
+ assert_equal ['baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s)
+
@controller.prepend_view_path(%w(foo bar))
- assert_equal ['foo', 'bar', 'baz', LOAD_PATH_ROOT], @controller.view_paths
+ assert_equal ['foo', 'bar', 'baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s)
assert_equal class_view_paths, TestController.view_paths
end
-
+
def test_view_paths
get :hello_world
assert_response :success
assert_equal "Hello world!", @response.body
end
-
+
def test_view_paths_override
TestController.prepend_view_path "#{LOAD_PATH_ROOT}/override"
get :hello_world
assert_response :success
assert_equal "Hello overridden world!", @response.body
end
-
+
def test_view_paths_override_for_layouts_in_controllers_with_a_module
@controller = Test::SubController.new
Test::SubController.view_paths = [ "#{LOAD_PATH_ROOT}/override", LOAD_PATH_ROOT, "#{LOAD_PATH_ROOT}/override2" ]
@@ -110,31 +122,44 @@ class ViewLoadPathsTest < Test::Unit::TestCase
assert_response :success
assert_equal "layout: Hello overridden world!", @response.body
end
-
+
def test_view_paths_override_at_request_time
get :hello_world_at_request_time
assert_response :success
assert_equal "Hello overridden world!", @response.body
end
-
+
def test_inheritance
original_load_paths = ActionController::Base.view_paths
-
+
self.class.class_eval %{
class A < ActionController::Base; end
class B < A; end
class C < ActionController::Base; end
}
-
- A.view_paths = [ 'a/path' ]
-
- assert_equal [ 'a/path' ], A.view_paths
- assert_equal A.view_paths, B.view_paths
+
+ A.view_paths = ['a/path']
+
+ assert_equal ['a/path'], A.view_paths.map(&:to_s)
+ assert_equal A.view_paths, B.view_paths
assert_equal original_load_paths, C.view_paths
-
+
C.view_paths = []
assert_nothing_raised { C.view_paths << 'c/path' }
- assert_equal ['c/path'], C.view_paths
+ assert_equal ['c/path'], C.view_paths.map(&:to_s)
+ end
+
+ def test_find_template_file_for_path
+ assert_equal "test/hello_world.erb", @controller.view_paths.find_template_file_for_path("test/hello_world.erb").to_s
+ assert_equal "test/hello.builder", @controller.view_paths.find_template_file_for_path("test/hello.builder").to_s
+ assert_equal nil, @controller.view_paths.find_template_file_for_path("test/missing.erb")
+ end
+
+ def test_view_paths_find_template_file_for_path
+ assert_equal "test/formatted_html_erb.html.erb", @controller.view_paths.find_template_file_for_path("test/formatted_html_erb.html").to_s
+ assert_equal "test/formatted_xml_erb.xml.erb", @controller.view_paths.find_template_file_for_path("test/formatted_xml_erb.xml").to_s
+ assert_equal "test/hello_world.erb", @controller.view_paths.find_template_file_for_path("test/hello_world.html").to_s
+ assert_equal "test/hello_world.erb", @controller.view_paths.find_template_file_for_path("test/hello_world.xml").to_s
+ assert_equal nil, @controller.view_paths.find_template_file_for_path("test/missing.html")
end
-
end
diff --git a/actionpack/test/fixtures/test/block_content_for.erb b/actionpack/test/fixtures/test/block_content_for.erb
deleted file mode 100644
index 9510337365..0000000000
--- a/actionpack/test/fixtures/test/block_content_for.erb
+++ /dev/null
@@ -1,2 +0,0 @@
-<% block_content_for :title do 'Putting stuff in the title!' end %>
-Great stuff! \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/erb_content_for.erb b/actionpack/test/fixtures/test/erb_content_for.erb
deleted file mode 100644
index c3bdd13643..0000000000
--- a/actionpack/test/fixtures/test/erb_content_for.erb
+++ /dev/null
@@ -1,2 +0,0 @@
-<% erb_content_for :title do %>Putting stuff in the title!<% end %>
-Great stuff! \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/non_erb_block_content_for.builder b/actionpack/test/fixtures/test/non_erb_block_content_for.builder
index 6ff6db0f95..a94643561c 100644
--- a/actionpack/test/fixtures/test/non_erb_block_content_for.builder
+++ b/actionpack/test/fixtures/test/non_erb_block_content_for.builder
@@ -1,4 +1,4 @@
content_for :title do
'Putting stuff in the title!'
end
-xml << "\nGreat stuff!" \ No newline at end of file
+xml << "\nGreat stuff!"
diff --git a/actionpack/test/fixtures/test/render_file_from_template.html.erb b/actionpack/test/fixtures/test/render_file_from_template.html.erb
new file mode 100644
index 0000000000..fde9f4bb64
--- /dev/null
+++ b/actionpack/test/fixtures/test/render_file_from_template.html.erb
@@ -0,0 +1 @@
+<%= render :file => @path %> \ No newline at end of file
diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb
index 0a7b19ba96..11b3bdb3fa 100755
--- a/actionpack/test/template/date_helper_test.rb
+++ b/actionpack/test/template/date_helper_test.rb
@@ -1002,17 +1002,15 @@ class DateHelperTest < ActionView::TestCase
@post = Post.new
@post.written_on = Date.new(2004, 6, 15)
- _erbout = ''
-
fields_for :post, @post do |f|
- _erbout.concat f.date_select(:written_on)
+ concat f.date_select(:written_on)
end
expected = "<select id='post_written_on_1i' name='post[written_on(1i)]'>\n<option value='1999'>1999</option>\n<option value='2000'>2000</option>\n<option value='2001'>2001</option>\n<option value='2002'>2002</option>\n<option value='2003'>2003</option>\n<option selected='selected' value='2004'>2004</option>\n<option value='2005'>2005</option>\n<option value='2006'>2006</option>\n<option value='2007'>2007</option>\n<option value='2008'>2008</option>\n<option value='2009'>2009</option>\n</select>\n"
expected << "<select id='post_written_on_2i' name='post[written_on(2i)]'>\n<option value='1'>January</option>\n<option value='2'>February</option>\n<option value='3'>March</option>\n<option value='4'>April</option>\n<option value='5'>May</option>\n<option selected='selected' value='6'>June</option>\n<option value='7'>July</option>\n<option value='8'>August</option>\n<option value='9'>September</option>\n<option value='10'>October</option>\n<option value='11'>November</option>\n<option value='12'>December</option>\n</select>\n"
expected << "<select id='post_written_on_3i' name='post[written_on(3i)]'>\n<option value='1'>1</option>\n<option value='2'>2</option>\n<option value='3'>3</option>\n<option value='4'>4</option>\n<option value='5'>5</option>\n<option value='6'>6</option>\n<option value='7'>7</option>\n<option value='8'>8</option>\n<option value='9'>9</option>\n<option value='10'>10</option>\n<option value='11'>11</option>\n<option value='12'>12</option>\n<option value='13'>13</option>\n<option value='14'>14</option>\n<option selected='selected' value='15'>15</option>\n<option value='16'>16</option>\n<option value='17'>17</option>\n<option value='18'>18</option>\n<option value='19'>19</option>\n<option value='20'>20</option>\n<option value='21'>21</option>\n<option value='22'>22</option>\n<option value='23'>23</option>\n<option value='24'>24</option>\n<option value='25'>25</option>\n<option value='26'>26</option>\n<option value='27'>27</option>\n<option value='28'>28</option>\n<option value='29'>29</option>\n<option value='30'>30</option>\n<option value='31'>31</option>\n</select>\n"
- assert_dom_equal(expected, _erbout)
+ assert_dom_equal(expected, output_buffer)
end
def test_date_select_with_index
@@ -1287,10 +1285,8 @@ class DateHelperTest < ActionView::TestCase
@post = Post.new
@post.updated_at = Time.local(2004, 6, 15, 16, 35)
- _erbout = ''
-
fields_for :post, @post do |f|
- _erbout.concat f.datetime_select(:updated_at)
+ concat f.datetime_select(:updated_at)
end
expected = "<select id='post_updated_at_1i' name='post[updated_at(1i)]'>\n<option value='1999'>1999</option>\n<option value='2000'>2000</option>\n<option value='2001'>2001</option>\n<option value='2002'>2002</option>\n<option value='2003'>2003</option>\n<option selected='selected' value='2004'>2004</option>\n<option value='2005'>2005</option>\n<option value='2006'>2006</option>\n<option value='2007'>2007</option>\n<option value='2008'>2008</option>\n<option value='2009'>2009</option>\n</select>\n"
@@ -1299,7 +1295,7 @@ class DateHelperTest < ActionView::TestCase
expected << " &mdash; <select id='post_updated_at_4i' name='post[updated_at(4i)]'>\n<option value='00'>00</option>\n<option value='01'>01</option>\n<option value='02'>02</option>\n<option value='03'>03</option>\n<option value='04'>04</option>\n<option value='05'>05</option>\n<option value='06'>06</option>\n<option value='07'>07</option>\n<option value='08'>08</option>\n<option value='09'>09</option>\n<option value='10'>10</option>\n<option value='11'>11</option>\n<option value='12'>12</option>\n<option value='13'>13</option>\n<option value='14'>14</option>\n<option value='15'>15</option>\n<option selected='selected' value='16'>16</option>\n<option value='17'>17</option>\n<option value='18'>18</option>\n<option value='19'>19</option>\n<option value='20'>20</option>\n<option value='21'>21</option>\n<option value='22'>22</option>\n<option value='23'>23</option>\n</select>\n"
expected << " : <select id='post_updated_at_5i' name='post[updated_at(5i)]'>\n<option value='00'>00</option>\n<option value='01'>01</option>\n<option value='02'>02</option>\n<option value='03'>03</option>\n<option value='04'>04</option>\n<option value='05'>05</option>\n<option value='06'>06</option>\n<option value='07'>07</option>\n<option value='08'>08</option>\n<option value='09'>09</option>\n<option value='10'>10</option>\n<option value='11'>11</option>\n<option value='12'>12</option>\n<option value='13'>13</option>\n<option value='14'>14</option>\n<option value='15'>15</option>\n<option value='16'>16</option>\n<option value='17'>17</option>\n<option value='18'>18</option>\n<option value='19'>19</option>\n<option value='20'>20</option>\n<option value='21'>21</option>\n<option value='22'>22</option>\n<option value='23'>23</option>\n<option value='24'>24</option>\n<option value='25'>25</option>\n<option value='26'>26</option>\n<option value='27'>27</option>\n<option value='28'>28</option>\n<option value='29'>29</option>\n<option value='30'>30</option>\n<option value='31'>31</option>\n<option value='32'>32</option>\n<option value='33'>33</option>\n<option value='34'>34</option>\n<option selected='selected' value='35'>35</option>\n<option value='36'>36</option>\n<option value='37'>37</option>\n<option value='38'>38</option>\n<option value='39'>39</option>\n<option value='40'>40</option>\n<option value='41'>41</option>\n<option value='42'>42</option>\n<option value='43'>43</option>\n<option value='44'>44</option>\n<option value='45'>45</option>\n<option value='46'>46</option>\n<option value='47'>47</option>\n<option value='48'>48</option>\n<option value='49'>49</option>\n<option value='50'>50</option>\n<option value='51'>51</option>\n<option value='52'>52</option>\n<option value='53'>53</option>\n<option value='54'>54</option>\n<option value='55'>55</option>\n<option value='56'>56</option>\n<option value='57'>57</option>\n<option value='58'>58</option>\n<option value='59'>59</option>\n</select>\n"
- assert_dom_equal(expected, _erbout)
+ assert_dom_equal(expected, output_buffer)
end
def test_date_select_with_zero_value_and_no_start_year
diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb
index af99e6243d..39649c3622 100644
--- a/actionpack/test/template/form_helper_test.rb
+++ b/actionpack/test/template/form_helper_test.rb
@@ -337,14 +337,12 @@ class FormHelperTest < ActionView::TestCase
end
def test_form_for
- _erbout = ''
-
form_for(:post, @post, :html => { :id => 'create-post' }) do |f|
- _erbout.concat f.label(:title)
- _erbout.concat f.text_field(:title)
- _erbout.concat f.text_area(:body)
- _erbout.concat f.check_box(:secret)
- _erbout.concat f.submit('Create post')
+ concat f.label(:title)
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
+ concat f.submit('Create post')
end
expected =
@@ -357,16 +355,14 @@ class FormHelperTest < ActionView::TestCase
"<input name='commit' id='post_submit' type='submit' value='Create post' />" +
"</form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_form_for_with_method
- _erbout = ''
-
form_for(:post, @post, :html => { :id => 'create-post', :method => :put }) do |f|
- _erbout.concat f.text_field(:title)
- _erbout.concat f.text_area(:body)
- _erbout.concat f.check_box(:secret)
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
end
expected =
@@ -378,16 +374,14 @@ class FormHelperTest < ActionView::TestCase
"<input name='post[secret]' type='hidden' value='0' />" +
"</form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_form_for_without_object
- _erbout = ''
-
form_for(:post, :html => { :id => 'create-post' }) do |f|
- _erbout.concat f.text_field(:title)
- _erbout.concat f.text_area(:body)
- _erbout.concat f.check_box(:secret)
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
end
expected =
@@ -398,17 +392,15 @@ class FormHelperTest < ActionView::TestCase
"<input name='post[secret]' type='hidden' value='0' />" +
"</form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_form_for_with_index
- _erbout = ''
-
form_for("post[]", @post) do |f|
- _erbout.concat f.label(:title)
- _erbout.concat f.text_field(:title)
- _erbout.concat f.text_area(:body)
- _erbout.concat f.check_box(:secret)
+ concat f.label(:title)
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
end
expected =
@@ -420,16 +412,14 @@ class FormHelperTest < ActionView::TestCase
"<input name='post[123][secret]' type='hidden' value='0' />" +
"</form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_form_for_with_nil_index_option_override
- _erbout = ''
-
form_for("post[]", @post, :index => nil) do |f|
- _erbout.concat f.text_field(:title)
- _erbout.concat f.text_area(:body)
- _erbout.concat f.check_box(:secret)
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
end
expected =
@@ -440,14 +430,13 @@ class FormHelperTest < ActionView::TestCase
"<input name='post[][secret]' type='hidden' value='0' />" +
"</form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_nested_fields_for
- _erbout = ''
form_for(:post, @post) do |f|
f.fields_for(:comment, @post) do |c|
- _erbout.concat c.text_field(:title)
+ concat c.text_field(:title)
end
end
@@ -455,16 +444,14 @@ class FormHelperTest < ActionView::TestCase
"<input name='post[comment][title]' size='30' type='text' id='post_comment_title' value='Hello World' />" +
"</form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_fields_for
- _erbout = ''
-
fields_for(:post, @post) do |f|
- _erbout.concat f.text_field(:title)
- _erbout.concat f.text_area(:body)
- _erbout.concat f.check_box(:secret)
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
end
expected =
@@ -473,16 +460,14 @@ class FormHelperTest < ActionView::TestCase
"<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" +
"<input name='post[secret]' type='hidden' value='0' />"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_fields_for_with_index
- _erbout = ''
-
fields_for("post[]", @post) do |f|
- _erbout.concat f.text_field(:title)
- _erbout.concat f.text_area(:body)
- _erbout.concat f.check_box(:secret)
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
end
expected =
@@ -491,16 +476,14 @@ class FormHelperTest < ActionView::TestCase
"<input name='post[123][secret]' checked='checked' type='checkbox' id='post_123_secret' value='1' />" +
"<input name='post[123][secret]' type='hidden' value='0' />"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_fields_for_with_nil_index_option_override
- _erbout = ''
-
fields_for("post[]", @post, :index => nil) do |f|
- _erbout.concat f.text_field(:title)
- _erbout.concat f.text_area(:body)
- _erbout.concat f.check_box(:secret)
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
end
expected =
@@ -509,16 +492,14 @@ class FormHelperTest < ActionView::TestCase
"<input name='post[][secret]' checked='checked' type='checkbox' id='post__secret' value='1' />" +
"<input name='post[][secret]' type='hidden' value='0' />"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_fields_for_with_index_option_override
- _erbout = ''
-
fields_for("post[]", @post, :index => "abc") do |f|
- _erbout.concat f.text_field(:title)
- _erbout.concat f.text_area(:body)
- _erbout.concat f.check_box(:secret)
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
end
expected =
@@ -527,15 +508,14 @@ class FormHelperTest < ActionView::TestCase
"<input name='post[abc][secret]' checked='checked' type='checkbox' id='post_abc_secret' value='1' />" +
"<input name='post[abc][secret]' type='hidden' value='0' />"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_fields_for_without_object
- _erbout = ''
fields_for(:post) do |f|
- _erbout.concat f.text_field(:title)
- _erbout.concat f.text_area(:body)
- _erbout.concat f.check_box(:secret)
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
end
expected =
@@ -544,15 +524,14 @@ class FormHelperTest < ActionView::TestCase
"<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" +
"<input name='post[secret]' type='hidden' value='0' />"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_fields_for_with_only_object
- _erbout = ''
fields_for(@post) do |f|
- _erbout.concat f.text_field(:title)
- _erbout.concat f.text_area(:body)
- _erbout.concat f.check_box(:secret)
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
end
expected =
@@ -561,31 +540,29 @@ class FormHelperTest < ActionView::TestCase
"<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" +
"<input name='post[secret]' type='hidden' value='0' />"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_fields_for_object_with_bracketed_name
- _erbout = ''
fields_for("author[post]", @post) do |f|
- _erbout.concat f.label(:title)
- _erbout.concat f.text_field(:title)
+ concat f.label(:title)
+ concat f.text_field(:title)
end
assert_dom_equal "<label for=\"author_post_title\">Title</label>" +
"<input name='author[post][title]' size='30' type='text' id='author_post_title' value='Hello World' />",
- _erbout
+ output_buffer
end
def test_fields_for_object_with_bracketed_name_and_index
- _erbout = ''
fields_for("author[post]", @post, :index => 1) do |f|
- _erbout.concat f.label(:title)
- _erbout.concat f.text_field(:title)
+ concat f.label(:title)
+ concat f.text_field(:title)
end
assert_dom_equal "<label for=\"author_post_1_title\">Title</label>" +
"<input name='author[post][1][title]' size='30' type='text' id='author_post_1_title' value='Hello World' />",
- _erbout
+ output_buffer
end
def test_form_builder_does_not_have_form_for_method
@@ -593,14 +570,12 @@ class FormHelperTest < ActionView::TestCase
end
def test_form_for_and_fields_for
- _erbout = ''
-
form_for(:post, @post, :html => { :id => 'create-post' }) do |post_form|
- _erbout.concat post_form.text_field(:title)
- _erbout.concat post_form.text_area(:body)
+ concat post_form.text_field(:title)
+ concat post_form.text_area(:body)
fields_for(:parent_post, @post) do |parent_fields|
- _erbout.concat parent_fields.check_box(:secret)
+ concat parent_fields.check_box(:secret)
end
end
@@ -612,18 +587,16 @@ class FormHelperTest < ActionView::TestCase
"<input name='parent_post[secret]' type='hidden' value='0' />" +
"</form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_form_for_and_fields_for_with_object
- _erbout = ''
-
form_for(:post, @post, :html => { :id => 'create-post' }) do |post_form|
- _erbout.concat post_form.text_field(:title)
- _erbout.concat post_form.text_area(:body)
+ concat post_form.text_field(:title)
+ concat post_form.text_area(:body)
post_form.fields_for(@comment) do |comment_fields|
- _erbout.concat comment_fields.text_field(:name)
+ concat comment_fields.text_field(:name)
end
end
@@ -634,7 +607,7 @@ class FormHelperTest < ActionView::TestCase
"<input name='post[comment][name]' type='text' id='post_comment_name' value='new comment' size='30' />" +
"</form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
class LabelledFormBuilder < ActionView::Helpers::FormBuilder
@@ -649,12 +622,10 @@ class FormHelperTest < ActionView::TestCase
end
def test_form_for_with_labelled_builder
- _erbout = ''
-
form_for(:post, @post, :builder => LabelledFormBuilder) do |f|
- _erbout.concat f.text_field(:title)
- _erbout.concat f.text_area(:body)
- _erbout.concat f.check_box(:secret)
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
end
expected =
@@ -665,18 +636,17 @@ class FormHelperTest < ActionView::TestCase
"<input name='post[secret]' type='hidden' value='0' /><br/>" +
"</form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_default_form_builder
old_default_form_builder, ActionView::Base.default_form_builder =
ActionView::Base.default_form_builder, LabelledFormBuilder
- _erbout = ''
form_for(:post, @post) do |f|
- _erbout.concat f.text_field(:title)
- _erbout.concat f.text_area(:body)
- _erbout.concat f.check_box(:secret)
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
end
expected =
@@ -687,17 +657,15 @@ class FormHelperTest < ActionView::TestCase
"<input name='post[secret]' type='hidden' value='0' /><br/>" +
"</form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
ensure
ActionView::Base.default_form_builder = old_default_form_builder
end
def test_default_form_builder_with_active_record_helpers
-
- _erbout = ''
form_for(:post, @post) do |f|
- _erbout.concat f.error_message_on('author_name')
- _erbout.concat f.error_messages
+ concat f.error_message_on('author_name')
+ concat f.error_messages
end
expected = %(<form action='http://www.example.com' method='post'>) +
@@ -705,7 +673,7 @@ class FormHelperTest < ActionView::TestCase
%(<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>) +
%(</form>)
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
@@ -713,10 +681,9 @@ class FormHelperTest < ActionView::TestCase
post = @post
@post = nil
- _erbout = ''
form_for(:post, post) do |f|
- _erbout.concat f.error_message_on('author_name')
- _erbout.concat f.error_messages
+ concat f.error_message_on('author_name')
+ concat f.error_messages
end
expected = %(<form action='http://www.example.com' method='post'>) +
@@ -724,19 +691,18 @@ class FormHelperTest < ActionView::TestCase
%(<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>) +
%(</form>)
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
# Perhaps this test should be moved to prototype helper tests.
def test_remote_form_for_with_labelled_builder
self.extend ActionView::Helpers::PrototypeHelper
- _erbout = ''
remote_form_for(:post, @post, :builder => LabelledFormBuilder) do |f|
- _erbout.concat f.text_field(:title)
- _erbout.concat f.text_area(:body)
- _erbout.concat f.check_box(:secret)
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
end
expected =
@@ -747,16 +713,14 @@ class FormHelperTest < ActionView::TestCase
"<input name='post[secret]' type='hidden' value='0' /><br/>" +
"</form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_fields_for_with_labelled_builder
- _erbout = ''
-
fields_for(:post, @post, :builder => LabelledFormBuilder) do |f|
- _erbout.concat f.text_field(:title)
- _erbout.concat f.text_area(:body)
- _erbout.concat f.check_box(:secret)
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
end
expected =
@@ -765,29 +729,23 @@ class FormHelperTest < ActionView::TestCase
"<label for='secret'>Secret:</label> <input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" +
"<input name='post[secret]' type='hidden' value='0' /><br/>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_form_for_with_html_options_adds_options_to_form_tag
- _erbout = ''
-
form_for(:post, @post, :html => {:id => 'some_form', :class => 'some_class'}) do |f| end
expected = "<form action=\"http://www.example.com\" class=\"some_class\" id=\"some_form\" method=\"post\"></form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_form_for_with_string_url_option
- _erbout = ''
-
form_for(:post, @post, :url => 'http://www.otherdomain.com') do |f| end
- assert_equal '<form action="http://www.otherdomain.com" method="post"></form>', _erbout
+ assert_equal '<form action="http://www.otherdomain.com" method="post"></form>', output_buffer
end
def test_form_for_with_hash_url_option
- _erbout = ''
-
form_for(:post, @post, :url => {:controller => 'controller', :action => 'action'}) do |f| end
assert_equal 'controller', @controller.url_for_options[:controller]
@@ -795,26 +753,20 @@ class FormHelperTest < ActionView::TestCase
end
def test_form_for_with_record_url_option
- _erbout = ''
-
form_for(:post, @post, :url => @post) do |f| end
expected = "<form action=\"/posts/123\" method=\"post\"></form>"
- assert_equal expected, _erbout
+ assert_equal expected, output_buffer
end
def test_form_for_with_existing_object
- _erbout = ''
-
form_for(@post) do |f| end
expected = "<form action=\"/posts/123\" class=\"edit_post\" id=\"edit_post_123\" method=\"post\"><div style=\"margin:0;padding:0\"><input name=\"_method\" type=\"hidden\" value=\"put\" /></div></form>"
- assert_equal expected, _erbout
+ assert_equal expected, output_buffer
end
def test_form_for_with_new_object
- _erbout = ''
-
post = Post.new
post.new_record = true
def post.id() nil end
@@ -822,64 +774,61 @@ class FormHelperTest < ActionView::TestCase
form_for(post) do |f| end
expected = "<form action=\"/posts\" class=\"new_post\" id=\"new_post\" method=\"post\"></form>"
- assert_equal expected, _erbout
+ assert_equal expected, output_buffer
end
def test_form_for_with_existing_object_in_list
@post.new_record = false
@comment.save
- _erbout = ''
+
form_for([@post, @comment]) {}
expected = %(<form action="#{comment_path(@post, @comment)}" class="edit_comment" id="edit_comment_1" method="post"><div style="margin:0;padding:0"><input name="_method" type="hidden" value="put" /></div></form>)
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_form_for_with_new_object_in_list
@post.new_record = false
- _erbout = ''
+
form_for([@post, @comment]) {}
expected = %(<form action="#{comments_path(@post)}" class="new_comment" id="new_comment" method="post"></form>)
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_form_for_with_existing_object_and_namespace_in_list
@post.new_record = false
@comment.save
- _erbout = ''
+
form_for([:admin, @post, @comment]) {}
expected = %(<form action="#{admin_comment_path(@post, @comment)}" class="edit_comment" id="edit_comment_1" method="post"><div style="margin:0;padding:0"><input name="_method" type="hidden" value="put" /></div></form>)
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_form_for_with_new_object_and_namespace_in_list
@post.new_record = false
- _erbout = ''
+
form_for([:admin, @post, @comment]) {}
expected = %(<form action="#{admin_comments_path(@post)}" class="new_comment" id="new_comment" method="post"></form>)
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_form_for_with_existing_object_and_custom_url
- _erbout = ''
-
form_for(@post, :url => "/super_posts") do |f| end
expected = "<form action=\"/super_posts\" class=\"edit_post\" id=\"edit_post_123\" method=\"post\"><div style=\"margin:0;padding:0\"><input name=\"_method\" type=\"hidden\" value=\"put\" /></div></form>"
- assert_equal expected, _erbout
+ assert_equal expected, output_buffer
end
def test_remote_form_for_with_html_options_adds_options_to_form_tag
self.extend ActionView::Helpers::PrototypeHelper
- _erbout = ''
remote_form_for(:post, @post, :html => {:id => 'some_form', :class => 'some_class'}) do |f| end
expected = "<form action=\"http://www.example.com\" class=\"some_class\" id=\"some_form\" method=\"post\" onsubmit=\"new Ajax.Request('http://www.example.com', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\"></form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb
index 48a26deea9..3f89a5e426 100644
--- a/actionpack/test/template/form_options_helper_test.rb
+++ b/actionpack/test/template/form_options_helper_test.rb
@@ -20,8 +20,6 @@ class MockTimeZone
end
end
-ActionView::Helpers::FormOptionsHelper::TimeZone = MockTimeZone
-
class FormOptionsHelperTest < ActionView::TestCase
tests ActionView::Helpers::FormOptionsHelper
@@ -31,6 +29,8 @@ class FormOptionsHelperTest < ActionView::TestCase
Country = Struct.new('Country', :country_id, :country_name)
Firm = Struct.new('Firm', :time_zone)
Album = Struct.new('Album', :id, :title, :genre)
+
+ ActiveSupport::TimeZone = MockTimeZone
end
def test_collection_options
@@ -183,7 +183,7 @@ class FormOptionsHelperTest < ActionView::TestCase
end
def test_time_zone_options_with_priority_zones
- zones = [ TimeZone.new( "B" ), TimeZone.new( "E" ) ]
+ zones = [ ActiveSupport::TimeZone.new( "B" ), ActiveSupport::TimeZone.new( "E" ) ]
opts = time_zone_options_for_select( nil, zones )
assert_dom_equal "<option value=\"B\">B</option>\n" +
"<option value=\"E\">E</option>" +
@@ -195,7 +195,7 @@ class FormOptionsHelperTest < ActionView::TestCase
end
def test_time_zone_options_with_selected_priority_zones
- zones = [ TimeZone.new( "B" ), TimeZone.new( "E" ) ]
+ zones = [ ActiveSupport::TimeZone.new( "B" ), ActiveSupport::TimeZone.new( "E" ) ]
opts = time_zone_options_for_select( "E", zones )
assert_dom_equal "<option value=\"B\">B</option>\n" +
"<option value=\"E\" selected=\"selected\">E</option>" +
@@ -207,7 +207,7 @@ class FormOptionsHelperTest < ActionView::TestCase
end
def test_time_zone_options_with_unselected_priority_zones
- zones = [ TimeZone.new( "B" ), TimeZone.new( "E" ) ]
+ zones = [ ActiveSupport::TimeZone.new( "B" ), ActiveSupport::TimeZone.new( "E" ) ]
opts = time_zone_options_for_select( "C", zones )
assert_dom_equal "<option value=\"B\">B</option>\n" +
"<option value=\"E\">E</option>" +
@@ -230,16 +230,14 @@ class FormOptionsHelperTest < ActionView::TestCase
def test_select_under_fields_for
@post = Post.new
@post.category = "<mus>"
-
- _erbout = ''
-
+
fields_for :post, @post do |f|
- _erbout.concat f.select(:category, %w( abe <mus> hest))
+ concat f.select(:category, %w( abe <mus> hest))
end
assert_dom_equal(
"<select id=\"post_category\" name=\"post[category]\"><option value=\"abe\">abe</option>\n<option value=\"&lt;mus&gt;\" selected=\"selected\">&lt;mus&gt;</option>\n<option value=\"hest\">hest</option></select>",
- _erbout
+ output_buffer
)
end
@@ -352,16 +350,14 @@ class FormOptionsHelperTest < ActionView::TestCase
@post = Post.new
@post.author_name = "Babe"
-
- _erbout = ''
-
+
fields_for :post, @post do |f|
- _erbout.concat f.collection_select(:author_name, @posts, :author_name, :author_name)
+ concat f.collection_select(:author_name, @posts, :author_name, :author_name)
end
assert_dom_equal(
"<select id=\"post_author_name\" name=\"post[author_name]\"><option value=\"&lt;Abe&gt;\">&lt;Abe&gt;</option>\n<option value=\"Babe\" selected=\"selected\">Babe</option>\n<option value=\"Cabe\">Cabe</option></select>",
- _erbout
+ output_buffer
)
end
@@ -1194,11 +1190,9 @@ COUNTRIES
def test_time_zone_select_under_fields_for
@firm = Firm.new("D")
-
- _erbout = ''
-
+
fields_for :firm, @firm do |f|
- _erbout.concat f.time_zone_select(:time_zone)
+ concat f.time_zone_select(:time_zone)
end
assert_dom_equal(
@@ -1209,7 +1203,7 @@ COUNTRIES
"<option value=\"D\" selected=\"selected\">D</option>\n" +
"<option value=\"E\">E</option>" +
"</select>",
- _erbout
+ output_buffer
)
end
@@ -1293,7 +1287,7 @@ COUNTRIES
def test_time_zone_select_with_priority_zones
@firm = Firm.new("D")
- zones = [ TimeZone.new("A"), TimeZone.new("D") ]
+ zones = [ ActiveSupport::TimeZone.new("A"), ActiveSupport::TimeZone.new("D") ]
html = time_zone_select("firm", "time_zone", zones )
assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" +
"<option value=\"A\">A</option>\n" +
diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb
index 73a8bd4d87..eabbe9c8a0 100644
--- a/actionpack/test/template/form_tag_helper_test.rb
+++ b/actionpack/test/template/form_tag_helper_test.rb
@@ -35,27 +35,27 @@ class FormTagHelperTest < ActionView::TestCase
expected = %(<form action="http://www.example.com" method="post"><div style='margin:0;padding:0'><input type="hidden" name="_method" value="put" /></div>)
assert_dom_equal expected, actual
end
-
+
def test_form_tag_with_method_delete
actual = form_tag({}, { :method => :delete })
expected = %(<form action="http://www.example.com" method="post"><div style='margin:0;padding:0'><input type="hidden" name="_method" value="delete" /></div>)
assert_dom_equal expected, actual
end
- def test_form_tag_with_block
- _erbout = ''
- form_tag("http://example.com") { _erbout.concat "Hello world!" }
+ def test_form_tag_with_block_in_erb
+ __in_erb_template = ''
+ form_tag("http://example.com") { concat "Hello world!" }
expected = %(<form action="http://example.com" method="post">Hello world!</form>)
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
- def test_form_tag_with_block_and_method
- _erbout = ''
- form_tag("http://example.com", :method => :put) { _erbout.concat "Hello world!" }
+ def test_form_tag_with_block_and_method_in_erb
+ __in_erb_template = ''
+ form_tag("http://example.com", :method => :put) { concat "Hello world!" }
expected = %(<form action="http://example.com" method="post"><div style='margin:0;padding:0'><input type="hidden" name="_method" value="put" /></div>Hello world!</form>)
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_hidden_field_tag
@@ -90,11 +90,11 @@ class FormTagHelperTest < ActionView::TestCase
actual = radio_button_tag("gender", "m") + radio_button_tag("gender", "f")
expected = %(<input id="gender_m" name="gender" type="radio" value="m" /><input id="gender_f" name="gender" type="radio" value="f" />)
assert_dom_equal expected, actual
-
+
actual = radio_button_tag("opinion", "-1") + radio_button_tag("opinion", "1")
expected = %(<input id="opinion_-1" name="opinion" type="radio" value="-1" /><input id="opinion_1" name="opinion" type="radio" value="1" />)
assert_dom_equal expected, actual
-
+
actual = radio_button_tag("person[gender]", "m")
expected = %(<input id="person_gender_m" name="person[gender]" type="radio" value="m" />)
assert_dom_equal expected, actual
@@ -105,13 +105,13 @@ class FormTagHelperTest < ActionView::TestCase
expected = %(<select id="people" name="people"><option>david</option></select>)
assert_dom_equal expected, actual
end
-
+
def test_select_tag_with_multiple
actual = select_tag "colors", "<option>Red</option><option>Blue</option><option>Green</option>", :multiple => :true
expected = %(<select id="colors" multiple="multiple" name="colors"><option>Red</option><option>Blue</option><option>Green</option></select>)
assert_dom_equal expected, actual
end
-
+
def test_select_tag_disabled
actual = select_tag "places", "<option>Home</option><option>Work</option><option>Pub</option>", :disabled => :true
expected = %(<select id="places" disabled="disabled" name="places"><option>Home</option><option>Work</option><option>Pub</option></select>)
@@ -147,37 +147,37 @@ class FormTagHelperTest < ActionView::TestCase
expected = %(<input class="admin" id="title" name="title" type="text" value="Hello!" />)
assert_dom_equal expected, actual
end
-
+
def test_text_field_tag_size_symbol
actual = text_field_tag "title", "Hello!", :size => 75
expected = %(<input id="title" name="title" size="75" type="text" value="Hello!" />)
assert_dom_equal expected, actual
end
-
+
def test_text_field_tag_size_string
actual = text_field_tag "title", "Hello!", "size" => "75"
expected = %(<input id="title" name="title" size="75" type="text" value="Hello!" />)
assert_dom_equal expected, actual
end
-
+
def test_text_field_tag_maxlength_symbol
actual = text_field_tag "title", "Hello!", :maxlength => 75
expected = %(<input id="title" name="title" maxlength="75" type="text" value="Hello!" />)
assert_dom_equal expected, actual
end
-
+
def test_text_field_tag_maxlength_string
actual = text_field_tag "title", "Hello!", "maxlength" => "75"
expected = %(<input id="title" name="title" maxlength="75" type="text" value="Hello!" />)
assert_dom_equal expected, actual
end
-
+
def test_text_field_disabled
actual = text_field_tag "title", "Hello!", :disabled => :true
expected = %(<input id="title" name="title" disabled="disabled" type="text" value="Hello!" />)
assert_dom_equal expected, actual
end
-
+
def test_text_field_tag_with_multiple_options
actual = text_field_tag "title", "Hello!", :size => 70, :maxlength => 80
expected = %(<input id="title" name="title" size="70" maxlength="80" type="text" value="Hello!" />)
@@ -228,29 +228,29 @@ class FormTagHelperTest < ActionView::TestCase
submit_tag("Save", :confirm => "Are you sure?")
)
end
-
+
def test_pass
assert_equal 1, 1
end
- def test_field_set_tag
- _erbout = ''
- field_set_tag("Your details") { _erbout.concat "Hello world!" }
+ def test_field_set_tag_in_erb
+ __in_erb_template = ''
+ field_set_tag("Your details") { concat "Hello world!" }
expected = %(<fieldset><legend>Your details</legend>Hello world!</fieldset>)
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
- _erbout = ''
- field_set_tag { _erbout.concat "Hello world!" }
+ self.output_buffer = ''
+ field_set_tag { concat "Hello world!" }
expected = %(<fieldset>Hello world!</fieldset>)
- assert_dom_equal expected, _erbout
-
- _erbout = ''
- field_set_tag('') { _erbout.concat "Hello world!" }
+ assert_dom_equal expected, output_buffer
+
+ self.output_buffer = ''
+ field_set_tag('') { concat "Hello world!" }
expected = %(<fieldset>Hello world!</fieldset>)
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def protect_against_forgery?
diff --git a/actionpack/test/template/javascript_helper_test.rb b/actionpack/test/template/javascript_helper_test.rb
index f18adb990c..d6d398d224 100644
--- a/actionpack/test/template/javascript_helper_test.rb
+++ b/actionpack/test/template/javascript_helper_test.rb
@@ -48,7 +48,7 @@ class JavaScriptHelperTest < ActionView::TestCase
end
def test_link_to_function_with_href
- assert_dom_equal %(<a href="http://example.com/" onclick="alert('Hello world!'); return false;">Greeting</a>),
+ assert_dom_equal %(<a href="http://example.com/" onclick="alert('Hello world!'); return false;">Greeting</a>),
link_to_function("Greeting", "alert('Hello world!')", :href => 'http://example.com/')
end
@@ -82,8 +82,12 @@ class JavaScriptHelperTest < ActionView::TestCase
end
def test_javascript_tag
+ self.output_buffer = 'foo'
+
assert_dom_equal "<script type=\"text/javascript\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>",
javascript_tag("alert('hello')")
+
+ assert_equal 'foo', output_buffer, 'javascript_tag without a block should not concat to output_buffer'
end
def test_javascript_tag_with_options
@@ -91,16 +95,16 @@ class JavaScriptHelperTest < ActionView::TestCase
javascript_tag("alert('hello')", :id => "the_js_tag")
end
- def test_javascript_tag_with_block
- _erbout = ''
- javascript_tag { _erbout.concat "alert('hello')" }
- assert_dom_equal "<script type=\"text/javascript\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", _erbout
+ def test_javascript_tag_with_block_in_erb
+ __in_erb_template = ''
+ javascript_tag { concat "alert('hello')" }
+ assert_dom_equal "<script type=\"text/javascript\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", output_buffer
end
- def test_javascript_tag_with_block_and_options
- _erbout = ''
- javascript_tag(:id => "the_js_tag") { _erbout.concat "alert('hello')" }
- assert_dom_equal "<script id=\"the_js_tag\" type=\"text/javascript\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", _erbout
+ def test_javascript_tag_with_block_and_options_in_erb
+ __in_erb_template = ''
+ javascript_tag(:id => "the_js_tag") { concat "alert('hello')" }
+ assert_dom_equal "<script id=\"the_js_tag\" type=\"text/javascript\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", output_buffer
end
def test_javascript_cdata_section
diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb
index 53a250f9d5..60b83b476d 100644
--- a/actionpack/test/template/prototype_helper_test.rb
+++ b/actionpack/test/template/prototype_helper_test.rb
@@ -54,7 +54,7 @@ class PrototypeHelperBaseTest < ActionView::TestCase
end
def create_generator
- block = Proc.new { |*args| yield *args if block_given? }
+ block = Proc.new { |*args| yield *args if block_given? }
JavaScriptGenerator.new self, &block
end
end
@@ -70,7 +70,7 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
assert_dom_equal %(<a class=\"fine\" href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true}); return false;\">Remote outauthor</a>),
link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }}, { :class => "fine" })
assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onComplete:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
- link_to_remote("Remote outauthor", :complete => "alert(request.responseText)", :url => { :action => "whatnot" })
+ link_to_remote("Remote outauthor", :complete => "alert(request.responseText)", :url => { :action => "whatnot" })
assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onSuccess:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
link_to_remote("Remote outauthor", :success => "alert(request.responseText)", :url => { :action => "whatnot" })
assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
@@ -78,12 +78,12 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot?a=10&amp;b=20', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
link_to_remote("Remote outauthor", :failure => "alert(request.responseText)", :url => { :action => "whatnot", :a => '10', :b => '20' })
end
-
+
def test_link_to_remote_html_options
assert_dom_equal %(<a class=\"fine\" href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true}); return false;\">Remote outauthor</a>),
link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :html => { :class => "fine" } })
end
-
+
def test_link_to_remote_url_quote_escaping
assert_dom_equal %(<a href="#" onclick="new Ajax.Request('http://www.example.com/whatnot\\\'s', {asynchronous:true, evalScripts:true}); return false;">Remote</a>),
link_to_remote("Remote", { :url => { :action => "whatnot's" } })
@@ -93,14 +93,14 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
assert_dom_equal %(<script type="text/javascript">\n//<![CDATA[\nnew PeriodicalExecuter(function() {new Ajax.Updater('schremser_bier', 'http://www.example.com/mehr_bier', {asynchronous:true, evalScripts:true})}, 10)\n//]]>\n</script>),
periodically_call_remote(:update => "schremser_bier", :url => { :action => "mehr_bier" })
end
-
+
def test_periodically_call_remote_with_frequency
assert_dom_equal(
"<script type=\"text/javascript\">\n//<![CDATA[\nnew PeriodicalExecuter(function() {new Ajax.Request('http://www.example.com/', {asynchronous:true, evalScripts:true})}, 2)\n//]]>\n</script>",
periodically_call_remote(:frequency => 2)
)
end
-
+
def test_form_remote_tag
assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">),
form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast })
@@ -117,53 +117,48 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :html => { :method => :put })
end
- def test_form_remote_tag_with_block
- _erbout = ''
- form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) { _erbout.concat "Hello world!" }
- assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">Hello world!</form>), _erbout
+ def test_form_remote_tag_with_block_in_erb
+ __in_erb_template = ''
+ form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) { concat "Hello world!" }
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">Hello world!</form>), output_buffer
end
def test_remote_form_for_with_record_identification_with_new_record
- _erbout = ''
remote_form_for(@record, {:html => { :id => 'create-author' }}) {}
-
+
expected = %(<form action='#{authors_path}' onsubmit="new Ajax.Request('#{authors_path}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_author' id='create-author' method='post'></form>)
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_remote_form_for_with_record_identification_without_html_options
- _erbout = ''
remote_form_for(@record) {}
-
+
expected = %(<form action='#{authors_path}' onsubmit="new Ajax.Request('#{authors_path}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_author' method='post' id='new_author'></form>)
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_remote_form_for_with_record_identification_with_existing_record
@record.save
- _erbout = ''
remote_form_for(@record) {}
-
+
expected = %(<form action='#{author_path(@record)}' id='edit_author_1' method='post' onsubmit="new Ajax.Request('#{author_path(@record)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='edit_author'><div style='margin:0;padding:0'><input name='_method' type='hidden' value='put' /></div></form>)
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_remote_form_for_with_new_object_in_list
- _erbout = ''
remote_form_for([@author, @article]) {}
-
+
expected = %(<form action='#{author_articles_path(@author)}' onsubmit="new Ajax.Request('#{author_articles_path(@author)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_article' method='post' id='new_article'></form>)
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
-
+
def test_remote_form_for_with_existing_object_in_list
@author.save
@article.save
- _erbout = ''
remote_form_for([@author, @article]) {}
-
+
expected = %(<form action='#{author_article_path(@author, @article)}' id='edit_article_1' method='post' onsubmit="new Ajax.Request('#{author_article_path(@author, @article)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='edit_article'><div style='margin:0;padding:0'><input name='_method' type='hidden' value='put' /></div></form>)
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_on_callbacks
@@ -178,18 +173,18 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({success:'glass_of_beer',failure:'glass_of_water'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
form_remote_tag(:update => { :success => "glass_of_beer", :failure => "glass_of_water" }, :url => { :action => :fast }, callback=>"monkeys();")
end
-
+
#HTTP status codes 200 up to 599 have callbacks
#these should work
100.upto(599) do |callback|
assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
end
-
+
#test 200 and 404
assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on200:function(request){monkeys();}, on404:function(request){bananas();}, parameters:Form.serialize(this)}); return false;">),
form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, 200=>"monkeys();", 404=>"bananas();")
-
+
#these shouldn't
1.upto(99) do |callback|
assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">),
@@ -199,44 +194,44 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">),
form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
end
-
+
#test ultimate combo
assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on200:function(request){monkeys();}, on404:function(request){bananas();}, onComplete:function(request){c();}, onFailure:function(request){f();}, onLoading:function(request){c1()}, onSuccess:function(request){s()}, parameters:Form.serialize(this)}); return false;\">),
form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :loading => "c1()", :success => "s()", :failure => "f();", :complete => "c();", 200=>"monkeys();", 404=>"bananas();")
-
+
end
-
+
def test_submit_to_remote
assert_dom_equal %(<input name=\"More beer!\" onclick=\"new Ajax.Updater('empty_bottle', 'http://www.example.com/', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)}); return false;\" type=\"button\" value=\"1000000\" />),
submit_to_remote("More beer!", 1_000_000, :update => "empty_bottle")
end
-
+
def test_observe_field
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/reorder_if_empty', {asynchronous:true, evalScripts:true, parameters:value})})\n//]]>\n</script>),
observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" })
end
-
+
def test_observe_field_using_with_option
expected = %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/check_value', {asynchronous:true, evalScripts:true, parameters:'id=' + encodeURIComponent(value)})})\n//]]>\n</script>)
assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id')
assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + encodeURIComponent(value)")
end
-
+
def test_observe_field_using_json_in_with_option
expected = %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/check_value', {asynchronous:true, evalScripts:true, parameters:{'id':value}})})\n//]]>\n</script>)
- assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}")
+ assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}")
end
-
+
def test_observe_field_using_function_for_callback
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {alert('Element changed')})\n//]]>\n</script>),
observe_field("glass", :frequency => 5.minutes, :function => "alert('Element changed')")
end
-
+
def test_observe_form
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Observer('cart', 2, function(element, value) {new Ajax.Request('http://www.example.com/cart_changed', {asynchronous:true, evalScripts:true, parameters:value})})\n//]]>\n</script>),
observe_form("cart", :frequency => 2, :url => { :action => "cart_changed" })
end
-
+
def test_observe_form_using_function_for_callback
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Observer('cart', 2, function(element, value) {alert('Form changed')})\n//]]>\n</script>),
observe_form("cart", :frequency => 2, :function => "alert('Form changed')")
@@ -251,7 +246,7 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
block = Proc.new { |page| page.replace_html('foo', 'bar') }
assert_equal create_generator(&block).to_s, update_page(&block)
end
-
+
def test_update_page_tag
block = Proc.new { |page| page.replace_html('foo', 'bar') }
assert_equal javascript_tag(create_generator(&block).to_s), update_page_tag(&block)
@@ -267,15 +262,15 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
def author_path(record)
"/authors/#{record.id}"
end
-
+
def authors_path
"/authors"
end
-
+
def author_articles_path(author)
"/authors/#{author.id}/articles"
end
-
+
def author_article_path(author, article)
"/authors/#{author.id}/articles/#{article.id}"
end
@@ -286,7 +281,7 @@ class JavaScriptGeneratorTest < PrototypeHelperBaseTest
super
@generator = create_generator
end
-
+
def test_insert_html_with_string
assert_equal 'new Insertion.Top("element", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");',
@generator.insert_html(:top, 'element', '<p>This is a test</p>')
@@ -297,70 +292,75 @@ class JavaScriptGeneratorTest < PrototypeHelperBaseTest
assert_equal 'new Insertion.After("element", "\\u003Cp\u003EThis is a test\\u003C/p\u003E");',
@generator.insert_html(:after, 'element', '<p>This is a test</p>')
end
-
+
def test_replace_html_with_string
assert_equal 'Element.update("element", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");',
@generator.replace_html('element', '<p>This is a test</p>')
end
-
+
def test_replace_element_with_string
assert_equal 'Element.replace("element", "\\u003Cdiv id=\"element\"\\u003E\\u003Cp\\u003EThis is a test\\u003C/p\\u003E\\u003C/div\\u003E");',
@generator.replace('element', '<div id="element"><p>This is a test</p></div>')
end
-
+
def test_remove
assert_equal 'Element.remove("foo");',
@generator.remove('foo')
assert_equal '["foo", "bar", "baz"].each(Element.remove);',
@generator.remove('foo', 'bar', 'baz')
end
-
+
def test_show
assert_equal 'Element.show("foo");',
@generator.show('foo')
assert_equal '["foo", "bar", "baz"].each(Element.show);',
- @generator.show('foo', 'bar', 'baz')
+ @generator.show('foo', 'bar', 'baz')
end
-
+
def test_hide
assert_equal 'Element.hide("foo");',
@generator.hide('foo')
assert_equal '["foo", "bar", "baz"].each(Element.hide);',
- @generator.hide('foo', 'bar', 'baz')
+ @generator.hide('foo', 'bar', 'baz')
end
-
+
def test_toggle
assert_equal 'Element.toggle("foo");',
@generator.toggle('foo')
assert_equal '["foo", "bar", "baz"].each(Element.toggle);',
- @generator.toggle('foo', 'bar', 'baz')
+ @generator.toggle('foo', 'bar', 'baz')
end
-
+
def test_alert
assert_equal 'alert("hello");', @generator.alert('hello')
end
-
+
def test_redirect_to
assert_equal 'window.location.href = "http://www.example.com/welcome";',
@generator.redirect_to(:action => 'welcome')
assert_equal 'window.location.href = "http://www.example.com/welcome?a=b&c=d";',
@generator.redirect_to("http://www.example.com/welcome?a=b&c=d")
end
-
+
+ def test_reload
+ assert_equal 'window.location.reload();',
+ @generator.reload
+ end
+
def test_delay
@generator.delay(20) do
@generator.hide('foo')
end
-
+
assert_equal "setTimeout(function() {\n;\nElement.hide(\"foo\");\n}, 20000);", @generator.to_s
end
-
+
def test_to_s
@generator.insert_html(:top, 'element', '<p>This is a test</p>')
@generator.insert_html(:bottom, 'element', '<p>This is a test</p>')
@generator.remove('foo', 'bar')
@generator.replace_html('baz', '<p>This is a test</p>')
-
+
assert_equal <<-EOS.chomp, @generator.to_s
new Insertion.Top("element", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
new Insertion.Bottom("element", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
@@ -382,12 +382,12 @@ Element.update("baz", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
@generator['hello'].hide
assert_equal %($("hello").hide();), @generator.to_s
end
-
+
def test_element_proxy_variable_access
@generator['hello']['style']
assert_equal %($("hello").style;), @generator.to_s
end
-
+
def test_element_proxy_variable_access_with_assignment
@generator['hello']['style']['color'] = 'red'
assert_equal %($("hello").style.color = "red";), @generator.to_s
@@ -402,7 +402,7 @@ Element.update("baz", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
@generator['hello'].hide("first").clean_whitespace
assert_equal %($("hello").hide("first").cleanWhitespace();), @generator.to_s
end
-
+
def test_select_access
assert_equal %($$("div.hello");), @generator.select('div.hello')
end
@@ -411,29 +411,29 @@ Element.update("baz", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
@generator.select('p.welcome b').first.hide
assert_equal %($$("p.welcome b").first().hide();), @generator.to_s
end
-
+
def test_visual_effect
- assert_equal %(new Effect.Puff("blah",{});),
+ assert_equal %(new Effect.Puff("blah",{});),
@generator.visual_effect(:puff,'blah')
- end
-
+ end
+
def test_visual_effect_toggle
- assert_equal %(Effect.toggle("blah",'appear',{});),
+ assert_equal %(Effect.toggle("blah",'appear',{});),
@generator.visual_effect(:toggle_appear,'blah')
end
-
+
def test_sortable
- assert_equal %(Sortable.create("blah", {onUpdate:function(){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize("blah")})}});),
+ assert_equal %(Sortable.create("blah", {onUpdate:function(){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize("blah")})}});),
@generator.sortable('blah', :url => { :action => "order" })
end
-
+
def test_draggable
- assert_equal %(new Draggable("blah", {});),
+ assert_equal %(new Draggable("blah", {});),
@generator.draggable('blah')
end
-
+
def test_drop_receiving
- assert_equal %(Droppables.add("blah", {onDrop:function(element){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:'id=' + encodeURIComponent(element.id)})}});),
+ assert_equal %(Droppables.add("blah", {onDrop:function(element){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:'id=' + encodeURIComponent(element.id)})}});),
@generator.drop_receiving('blah', :url => { :action => "order" })
end
@@ -535,7 +535,7 @@ return array.reverse();
});
EOS
end
-
+
def test_collection_proxy_with_find_all
@generator.select('p').find_all 'a' do |value, index|
@generator << '(value.className == "welcome")'
@@ -547,7 +547,7 @@ return (value.className == "welcome");
});
EOS
end
-
+
def test_collection_proxy_with_in_groups_of
@generator.select('p').in_groups_of('a', 3)
@generator.select('p').in_groups_of('a', 3, 'x')
@@ -556,13 +556,13 @@ var a = $$("p").inGroupsOf(3);
var a = $$("p").inGroupsOf(3, "x");
EOS
end
-
+
def test_collection_proxy_with_each_slice
@generator.select('p').each_slice('a', 3)
@generator.select('p').each_slice('a', 3) do |group, index|
group.reverse
end
-
+
assert_equal <<-EOS.strip, @generator.to_s
var a = $$("p").eachSlice(3);
var a = $$("p").eachSlice(3, function(value, index) {
@@ -570,7 +570,7 @@ return value.reverse();
});
EOS
end
-
+
def test_debug_rjs
ActionView::Base.debug_rjs = true
@generator['welcome'].replace_html 'Welcome'
@@ -578,7 +578,7 @@ return value.reverse();
ensure
ActionView::Base.debug_rjs = false
end
-
+
def test_literal
literal = @generator.literal("function() {}")
assert_equal "function() {}", literal.to_json
@@ -589,7 +589,7 @@ return value.reverse();
@generator.form.focus('my_field')
assert_equal "Form.focus(\"my_field\");", @generator.to_s
end
-
+
def test_call_with_block
@generator.call(:before)
@generator.call(:my_method) do |p|
@@ -602,7 +602,7 @@ return value.reverse();
end
assert_equal "before();\nmy_method(function() { $(\"one\").show();\n$(\"two\").hide(); });\nin_between();\nmy_method_with_arguments(true, \"hello\", function() { $(\"three\").visualEffect(\"highlight\"); });", @generator.to_s
end
-
+
def test_class_proxy_call_with_block
@generator.my_object.my_method do |p|
p[:one].show
diff --git a/actionpack/test/template/record_tag_helper_test.rb b/actionpack/test/template/record_tag_helper_test.rb
index 0afbb54f57..34a200b933 100644
--- a/actionpack/test/template/record_tag_helper_test.rb
+++ b/actionpack/test/template/record_tag_helper_test.rb
@@ -2,7 +2,7 @@ require 'abstract_unit'
class Post
def id
- 45
+ 45
end
def body
"What a wonderful world!"
@@ -15,40 +15,36 @@ class RecordTagHelperTest < ActionView::TestCase
def setup
@post = Post.new
end
-
+
def test_content_tag_for
- _erbout = ''
expected = %(<li class="post bar" id="post_45"></li>)
actual = content_tag_for(:li, @post, :class => 'bar') { }
assert_dom_equal expected, actual
end
-
+
def test_content_tag_for_prefix
- _erbout = ''
expected = %(<ul class="post" id="archived_post_45"></ul>)
actual = content_tag_for(:ul, @post, :archived) { }
- assert_dom_equal expected, actual
+ assert_dom_equal expected, actual
end
-
+
def test_content_tag_for_with_extra_html_tags
- _erbout = ''
expected = %(<tr class="post bar" id="post_45" style='background-color: #f0f0f0'></tr>)
actual = content_tag_for(:tr, @post, {:class => "bar", :style => "background-color: #f0f0f0"}) { }
- assert_dom_equal expected, actual
+ assert_dom_equal expected, actual
end
-
- def test_block_works_with_content_tag_for
- _erbout = ''
+
+ def test_block_works_with_content_tag_for_in_erb
+ __in_erb_template = ''
expected = %(<tr class="post" id="post_45">#{@post.body}</tr>)
- actual = content_tag_for(:tr, @post) { _erbout.concat @post.body }
- assert_dom_equal expected, actual
+ actual = content_tag_for(:tr, @post) { concat @post.body }
+ assert_dom_equal expected, actual
end
-
- def test_div_for
- _erbout = ''
+
+ def test_div_for_in_erb
+ __in_erb_template = ''
expected = %(<div class="post bar" id="post_45">#{@post.body}</div>)
- actual = div_for(@post, :class => "bar") { _erbout.concat @post.body }
+ actual = div_for(@post, :class => "bar") { concat @post.body }
assert_dom_equal expected, actual
- end
-
+ end
end
diff --git a/actionpack/test/template/tag_helper_test.rb b/actionpack/test/template/tag_helper_test.rb
index 4da6116095..fc49d340ef 100644
--- a/actionpack/test/template/tag_helper_test.rb
+++ b/actionpack/test/template/tag_helper_test.rb
@@ -33,24 +33,40 @@ class TagHelperTest < ActionView::TestCase
assert_equal content_tag("a", "Create", "href" => "create"),
content_tag("a", "Create", :href => "create")
end
-
- def test_content_tag_with_block
- _erbout = ''
- content_tag(:div) { _erbout.concat "Hello world!" }
- assert_dom_equal "<div>Hello world!</div>", _erbout
+
+ def test_content_tag_with_block_in_erb
+ __in_erb_template = ''
+ content_tag(:div) { concat "Hello world!" }
+ assert_dom_equal "<div>Hello world!</div>", output_buffer
end
-
- def test_content_tag_with_block_and_options
- _erbout = ''
- content_tag(:div, :class => "green") { _erbout.concat "Hello world!" }
- assert_dom_equal %(<div class="green">Hello world!</div>), _erbout
+
+ def test_content_tag_with_block_and_options_in_erb
+ __in_erb_template = ''
+ content_tag(:div, :class => "green") { concat "Hello world!" }
+ assert_dom_equal %(<div class="green">Hello world!</div>), output_buffer
end
-
- def test_content_tag_with_block_and_options_outside_of_action_view
+
+ def test_content_tag_with_block_and_options_out_of_erb
+ assert_dom_equal %(<div class="green">Hello world!</div>), content_tag(:div, :class => "green") { "Hello world!" }
+ end
+
+ def test_content_tag_with_block_and_options_outside_out_of_erb
assert_equal content_tag("a", "Create", :href => "create"),
- content_tag("a", "href" => "create") { "Create" }
+ content_tag("a", "href" => "create") { "Create" }
end
-
+
+ def test_content_tag_nested_in_content_tag_out_of_erb
+ assert_equal content_tag("p", content_tag("b", "Hello")),
+ content_tag("p") { content_tag("b", "Hello") },
+ output_buffer
+ end
+
+ def test_content_tag_nested_in_content_tag_in_erb
+ __in_erb_template = true
+ content_tag("p") { concat content_tag("b", "Hello") }
+ assert_equal '<p><b>Hello</b></p>', output_buffer
+ end
+
def test_cdata_section
assert_equal "<![CDATA[<hello world>]]>", cdata_section("<hello world>")
end
diff --git a/actionpack/test/template/template_file_test.rb b/actionpack/test/template/template_file_test.rb
new file mode 100644
index 0000000000..d14a966c1c
--- /dev/null
+++ b/actionpack/test/template/template_file_test.rb
@@ -0,0 +1,95 @@
+require 'abstract_unit'
+
+class TemplateFileTest < Test::Unit::TestCase
+ LOAD_PATH_ROOT = File.join(File.dirname(__FILE__), '..', 'fixtures')
+
+ def setup
+ @template = ActionView::TemplateFile.new("test/hello_world.html.erb")
+ @another_template = ActionView::TemplateFile.new("test/hello_world.erb")
+ @file_only = ActionView::TemplateFile.new("hello_world.erb")
+ @full_path = ActionView::TemplateFile.new("/u/app/scales/config/../app/views/test/hello_world.erb", true)
+ @layout = ActionView::TemplateFile.new("layouts/hello")
+ @multipart = ActionView::TemplateFile.new("test_mailer/implicitly_multipart_example.text.html.erb")
+ end
+
+ def test_path
+ assert_equal "test/hello_world.html.erb", @template.path
+ assert_equal "test/hello_world.erb", @another_template.path
+ assert_equal "hello_world.erb", @file_only.path
+ assert_equal "/u/app/scales/config/../app/views/test/hello_world.erb", @full_path.path
+ assert_equal "layouts/hello", @layout.path
+ assert_equal "test_mailer/implicitly_multipart_example.text.html.erb", @multipart.path
+ end
+
+ def test_path_without_extension
+ assert_equal "test/hello_world.html", @template.path_without_extension
+ assert_equal "test/hello_world", @another_template.path_without_extension
+ assert_equal "hello_world", @file_only.path_without_extension
+ assert_equal "layouts/hello", @layout.path_without_extension
+ assert_equal "test_mailer/implicitly_multipart_example.text.html", @multipart.path_without_extension
+ end
+
+ def test_path_without_format_and_extension
+ assert_equal "test/hello_world", @template.path_without_format_and_extension
+ assert_equal "test/hello_world", @another_template.path_without_format_and_extension
+ assert_equal "hello_world", @file_only.path_without_format_and_extension
+ assert_equal "layouts/hello", @layout.path_without_format_and_extension
+ assert_equal "test_mailer/implicitly_multipart_example", @multipart.path_without_format_and_extension
+ end
+
+ def test_name
+ assert_equal "hello_world", @template.name
+ assert_equal "hello_world", @another_template.name
+ assert_equal "hello_world", @file_only.name
+ assert_equal "hello_world", @full_path.name
+ assert_equal "hello", @layout.name
+ assert_equal "implicitly_multipart_example", @multipart.name
+ end
+
+ def test_format
+ assert_equal "html", @template.format
+ assert_equal nil, @another_template.format
+ assert_equal nil, @layout.format
+ assert_equal "text.html", @multipart.format
+ end
+
+ def test_extension
+ assert_equal "erb", @template.extension
+ assert_equal "erb", @another_template.extension
+ assert_equal nil, @layout.extension
+ assert_equal "erb", @multipart.extension
+ end
+
+ def test_format_and_extension
+ assert_equal "html.erb", @template.format_and_extension
+ assert_equal "erb", @another_template.format_and_extension
+ assert_equal nil, @layout.format_and_extension
+ assert_equal "text.html.erb", @multipart.format_and_extension
+ end
+
+ def test_new_file_with_extension
+ file = @template.dup_with_extension(:haml)
+ assert_equal "test/hello_world.html", file.path_without_extension
+ assert_equal "haml", file.extension
+ assert_equal "test/hello_world.html.haml", file.path
+
+ file = @another_template.dup_with_extension(:haml)
+ assert_equal "test/hello_world", file.path_without_extension
+ assert_equal "haml", file.extension
+ assert_equal "test/hello_world.haml", file.path
+
+ file = @another_template.dup_with_extension(nil)
+ assert_equal "test/hello_world", file.path_without_extension
+ assert_equal nil, file.extension
+ assert_equal "test/hello_world", file.path
+ end
+
+ def test_freezes_entire_contents
+ @template.freeze
+ assert @template.frozen?
+ assert @template.base_path.frozen?
+ assert @template.name.frozen?
+ assert @template.format.frozen?
+ assert @template.extension.frozen?
+ end
+end
diff --git a/actionpack/test/template/template_finder_test.rb b/actionpack/test/template/template_finder_test.rb
deleted file mode 100644
index 3d6baff5fb..0000000000
--- a/actionpack/test/template/template_finder_test.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-require 'abstract_unit'
-
-class TemplateFinderTest < Test::Unit::TestCase
-
- LOAD_PATH_ROOT = File.join(File.dirname(__FILE__), '..', 'fixtures')
-
- def setup
- ActionView::TemplateFinder.process_view_paths(LOAD_PATH_ROOT)
- ActionView::Template::register_template_handler :mab, Class.new(ActionView::TemplateHandler)
- @template = ActionView::Base.new
- @finder = ActionView::TemplateFinder.new(@template, LOAD_PATH_ROOT)
- end
-
- def test_should_raise_exception_for_unprocessed_view_path
- assert_raises ActionView::TemplateFinder::InvalidViewPath do
- ActionView::TemplateFinder.new(@template, File.dirname(__FILE__))
- end
- end
-
- def test_should_cache_file_extension_properly
- assert_equal ["builder", "erb", "rhtml", "rjs", "rxml", "mab"].sort,
- ActionView::TemplateFinder.file_extension_cache[LOAD_PATH_ROOT].values.flatten.uniq.sort
-
- assert_equal (Dir.glob("#{LOAD_PATH_ROOT}/**/*/*.{erb,rjs,rhtml,builder,rxml,mab}") |
- Dir.glob("#{LOAD_PATH_ROOT}/**.{erb,rjs,rhtml,builder,rxml,mab}")).size,
- ActionView::TemplateFinder.file_extension_cache[LOAD_PATH_ROOT].keys.size
- end
-
- def test_should_cache_dir_content_properly
- assert ActionView::TemplateFinder.processed_view_paths[LOAD_PATH_ROOT]
- assert_equal (Dir.glob("#{LOAD_PATH_ROOT}/**/*/**") | Dir.glob("#{LOAD_PATH_ROOT}/**")).find_all {|f| !File.directory?(f) }.size,
- ActionView::TemplateFinder.processed_view_paths[LOAD_PATH_ROOT].size
- end
-
- def test_find_template_extension_from_first_render
- assert_nil @finder.send(:find_template_extension_from_first_render)
-
- {
- nil => nil,
- '' => nil,
- 'foo' => nil,
- '/foo' => nil,
- 'foo.rb' => 'rb',
- 'foo.bar.rb' => 'bar.rb',
- 'baz/foo.rb' => 'rb',
- 'baz/foo.bar.rb' => 'bar.rb',
- 'baz/foo.o/foo.rb' => 'rb',
- 'baz/foo.o/foo.bar.rb' => 'bar.rb',
- }.each do |input,expectation|
- @template.instance_variable_set('@first_render', input)
- assert_equal expectation, @finder.send(:find_template_extension_from_first_render)
- end
- end
-
- def test_should_report_file_exists_correctly
- assert_nil @finder.send(:find_template_extension_from_first_render)
- assert_equal false, @finder.send(:file_exists?, 'test.rhtml')
- assert_equal false, @finder.send(:file_exists?, 'test.rb')
-
- @template.instance_variable_set('@first_render', 'foo.rb')
-
- assert_equal 'rb', @finder.send(:find_template_extension_from_first_render)
- assert_equal false, @finder.send(:file_exists?, 'baz')
- assert_equal false, @finder.send(:file_exists?, 'baz.rb')
- end
-
- uses_mocha 'Template finder tests' do
- def test_should_update_extension_cache_when_template_handler_is_registered
- ActionView::TemplateFinder.expects(:update_extension_cache_for).with("funky")
- ActionView::Template::register_template_handler :funky, Class.new(ActionView::TemplateHandler)
- end
- end
-end
diff --git a/actionpack/test/template/template_object_test.rb b/actionpack/test/template/template_object_test.rb
index afb5c5cc16..2cfc4523c6 100644
--- a/actionpack/test/template/template_object_test.rb
+++ b/actionpack/test/template/template_object_test.rb
@@ -2,60 +2,57 @@ require 'abstract_unit'
class TemplateObjectTest < Test::Unit::TestCase
LOAD_PATH_ROOT = File.join(File.dirname(__FILE__), '..', 'fixtures')
- ActionView::TemplateFinder.process_view_paths(LOAD_PATH_ROOT)
-
+
class TemplateTest < Test::Unit::TestCase
def setup
@view = ActionView::Base.new(LOAD_PATH_ROOT)
@path = "test/hello_world.erb"
end
-
+
def test_should_create_valid_template
template = ActionView::Template.new(@view, @path, true)
-
+
assert_kind_of ActionView::TemplateHandlers::ERB, template.handler
- assert_equal "test/hello_world.erb", template.path
+ assert_equal "test/hello_world.erb", template.path.to_s
assert_nil template.instance_variable_get(:"@source")
assert_equal "erb", template.extension
end
-
+
uses_mocha 'Template preparation tests' do
-
def test_should_prepare_template_properly
template = ActionView::Template.new(@view, @path, true)
view = template.instance_variable_get(:"@view")
-
+
view.expects(:evaluate_assigns)
template.handler.expects(:compile_template).with(template)
view.expects(:method_names).returns({})
-
+
template.prepare!
end
-
end
end
-
+
class PartialTemplateTest < Test::Unit::TestCase
def setup
@view = ActionView::Base.new(LOAD_PATH_ROOT)
@path = "test/partial_only"
end
-
+
def test_should_create_valid_partial_template
template = ActionView::PartialTemplate.new(@view, @path, nil)
-
- assert_equal "test/_partial_only", template.path
+
+ assert_equal "test/_partial_only", template.path.path_without_format_and_extension
assert_equal :partial_only, template.variable_name
-
+
assert template.locals.has_key?(:object)
assert template.locals.has_key?(:partial_only)
end
-
+
def test_partial_with_errors
template = ActionView::PartialTemplate.new(@view, 'test/raise', nil)
assert_raise(ActionView::TemplateError) { template.render_template }
end
-
+
uses_mocha 'Partial template preparation tests' do
def test_should_prepare_on_initialization
ActionView::PartialTemplate.any_instance.expects(:prepare!)
@@ -63,7 +60,7 @@ class TemplateObjectTest < Test::Unit::TestCase
end
end
end
-
+
class PartialTemplateFallbackTest < Test::Unit::TestCase
def setup
@view = ActionView::Base.new(LOAD_PATH_ROOT)
@@ -72,7 +69,7 @@ class TemplateObjectTest < Test::Unit::TestCase
def test_default
template = ActionView::PartialTemplate.new(@view, @path, nil)
- assert_equal 'test/_layout_for_partial', template.path
+ assert_equal 'test/_layout_for_partial', template.path.path_without_format_and_extension
assert_equal 'erb', template.extension
assert_equal :html, @view.template_format
end
@@ -80,7 +77,7 @@ class TemplateObjectTest < Test::Unit::TestCase
def test_js
@view.template_format = :js
template = ActionView::PartialTemplate.new(@view, @path, nil)
- assert_equal 'test/_layout_for_partial', template.path
+ assert_equal 'test/_layout_for_partial', template.path.path_without_format_and_extension
assert_equal 'erb', template.extension
assert_equal :html, @view.template_format
end
diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb
index 62cdca03d1..df6be3bb13 100644
--- a/actionpack/test/template/text_helper_test.rb
+++ b/actionpack/test/template/text_helper_test.rb
@@ -11,6 +11,12 @@ class TextHelperTest < ActionView::TestCase
@_cycles = nil if (defined? @_cycles)
end
+ def test_concat
+ self.output_buffer = 'foo'
+ assert_equal 'foobar', concat('bar')
+ assert_equal 'foobar', output_buffer
+ end
+
def test_simple_format
assert_equal "<p></p>", simple_format(nil)
diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb
index d45ea08a6f..44ceed6661 100644
--- a/actionpack/test/template/url_helper_test.rb
+++ b/actionpack/test/template/url_helper_test.rb
@@ -80,7 +80,7 @@ class UrlHelperTest < ActionView::TestCase
def test_link_tag_with_straight_url
assert_dom_equal "<a href=\"http://www.example.com\">Hello</a>", link_to("Hello", "http://www.example.com")
end
-
+
def test_link_tag_without_host_option
ActionController::Base.class_eval { attr_accessor :url }
url = {:controller => 'weblog', :action => 'show'}
@@ -121,7 +121,7 @@ class UrlHelperTest < ActionView::TestCase
@controller.request = RequestMock.new("http://www.example.com/weblog/show", nil, nil, {'HTTP_REFERER' => 'http://www.example.com/referer'})
assert_dom_equal "<a href=\"http://www.example.com/referer\">go back</a>", link_to('go back', :back)
end
-
+
def test_link_tag_with_back_and_no_referer
@controller.request = RequestMock.new("http://www.example.com/weblog/show", nil, nil, {})
assert_dom_equal "<a href=\"javascript:history.back()\">go back</a>", link_to('go back', :back)
@@ -211,7 +211,15 @@ class UrlHelperTest < ActionView::TestCase
def test_link_tag_using_post_javascript_and_popup
assert_raises(ActionView::ActionViewError) { link_to("Hello", "http://www.example.com", :popup => true, :method => :post, :confirm => "Are you serious?") }
end
-
+
+ def test_link_tag_using_block_in_erb
+ __in_erb_template = ''
+
+ link_to("http://example.com") { concat("Example site") }
+
+ assert_equal '<a href="http://example.com">Example site</a>', output_buffer
+ end
+
def test_link_to_unless
assert_equal "Showing", link_to_unless(true, "Showing", :action => "show", :controller => "weblog")
assert_dom_equal "<a href=\"http://www.example.com\">Listing</a>", link_to_unless(false, "Listing", :action => "list", :controller => "weblog")
@@ -285,7 +293,7 @@ class UrlHelperTest < ActionView::TestCase
assert_dom_equal "<a href=\"&#109;&#97;&#105;&#108;&#116;&#111;&#58;%6d%65@%64%6f%6d%61%69%6e.%63%6f%6d\">&#109;&#101;&#40;&#97;&#116;&#41;&#100;&#111;&#109;&#97;&#105;&#110;&#40;&#100;&#111;&#116;&#41;&#99;&#111;&#109;</a>", mail_to("me@domain.com", nil, :encode => "hex", :replace_at => "(at)", :replace_dot => "(dot)")
assert_dom_equal "<script type=\"text/javascript\">eval(unescape('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%22%3e%4d%79%20%65%6d%61%69%6c%3c%2f%61%3e%27%29%3b'))</script>", mail_to("me@domain.com", "My email", :encode => "javascript", :replace_at => "(at)", :replace_dot => "(dot)")
end
-
+
def protect_against_forgery?
false
end
@@ -412,11 +420,11 @@ class Workshop
def initialize(id, new_record)
@id, @new_record = id, new_record
end
-
+
def new_record?
@new_record
end
-
+
def to_s
id.to_s
end
diff --git a/activemodel/Rakefile b/activemodel/Rakefile
index 87e9b547f3..99c9fc3bd1 100644
--- a/activemodel/Rakefile
+++ b/activemodel/Rakefile
@@ -10,7 +10,7 @@ Rake::RDocTask.new { |rdoc|
rdoc.title = "Active Model"
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
rdoc.options << '--charset' << 'utf-8'
- rdoc.template = "#{ENV['template']}.rb" if ENV['template']
+ rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
rdoc.rdoc_files.include('README', 'CHANGES')
rdoc.rdoc_files.include('lib/**/*.rb')
-} \ No newline at end of file
+}
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index a65771648e..4e05d0fcfd 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,5 +1,23 @@
*Edge*
+* Always treat integer :limit as byte length. #420 [Tarmo Tänav]
+
+* Partial updates don't update lock_version if nothing changed. #426 [Daniel Morrison]
+
+* Fix column collision with named_scope and :joins. #46 [Duncan Beevers, Mark Catley]
+
+* db:migrate:down and :up update schema_migrations. #369 [Michael Raidel, RaceCondition]
+
+* PostgreSQL: support :conditions => [':foo::integer', { :foo => 1 }] without treating the ::integer typecast as a bind variable. [Tarmo Tänav]
+
+* MySQL: rename_column preserves column defaults. #466 [Diego Algorta]
+
+* Add :from option to calculations. #397 [Ben Munat]
+
+* Add :validate option to associations to enable/disable the automatic validation of associated models. Resolves #301. [Jan De Poorter]
+
+* PostgreSQL: use 'INSERT ... RETURNING id' for 8.2 and later. [Jeremy Kemper]
+
* Added SQL escaping for :limit and :offset in MySQL [Jonathan Wiess]
diff --git a/activerecord/Rakefile b/activerecord/Rakefile
index fc068b16c3..60b17e02b9 100755
--- a/activerecord/Rakefile
+++ b/activerecord/Rakefile
@@ -141,7 +141,7 @@ Rake::RDocTask.new { |rdoc|
rdoc.title = "Active Record -- Object-relation mapping put on rails"
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
rdoc.options << '--charset' << 'utf-8'
- rdoc.template = "#{ENV['template']}.rb" if ENV['template']
+ rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
rdoc.rdoc_files.include('README', 'RUNNING_UNIT_TESTS', 'CHANGELOG')
rdoc.rdoc_files.include('lib/**/*.rb')
rdoc.rdoc_files.exclude('lib/active_record/vendor/*')
@@ -225,13 +225,13 @@ end
desc "Publish the beta gem"
task :pgem => [:package] do
- Rake::SshFilePublisher.new("davidhh@wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
- `ssh davidhh@wrath.rubyonrails.org './gemupdate.sh'`
+ Rake::SshFilePublisher.new("wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
+ `ssh wrath.rubyonrails.org './gemupdate.sh'`
end
desc "Publish the API documentation"
task :pdoc => [:rdoc] do
- Rake::SshDirPublisher.new("davidhh@wrath.rubyonrails.org", "public_html/ar", "doc").upload
+ Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/ar", "doc").upload
end
desc "Publish the release files to RubyForge."
diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb
index 087ed2a587..194c4ee5db 100644
--- a/activerecord/lib/active_record/association_preload.rb
+++ b/activerecord/lib/active_record/association_preload.rb
@@ -103,10 +103,10 @@ module ActiveRecord
associated_records = reflection.klass.find(:all, :conditions => [conditions, ids],
:include => options[:include],
:joins => "INNER JOIN #{connection.quote_table_name options[:join_table]} as t0 ON #{reflection.klass.quoted_table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}",
- :select => "#{options[:select] || table_name+'.*'}, t0.#{reflection.primary_key_name} as _parent_record_id",
+ :select => "#{options[:select] || table_name+'.*'}, t0.#{reflection.primary_key_name} as the_parent_record_id",
:order => options[:order])
- set_association_collection_records(id_to_record_map, reflection.name, associated_records, '_parent_record_id')
+ set_association_collection_records(id_to_record_map, reflection.name, associated_records, 'the_parent_record_id')
end
def preload_has_one_association(records, reflection, preload_options={})
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 9479296b90..d2253cb61c 100755
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -691,6 +691,7 @@ module ActiveRecord
# association is a polymorphic +belongs_to+.
# * <tt>:uniq</tt> - If true, duplicates will be omitted from the collection. Useful in conjunction with <tt>:through</tt>.
# * <tt>:readonly</tt> - If true, all the associated objects are readonly through the association.
+ # * <tt>:validate</tt> - If false, don't validate the associated objects when saving the parent object. true by default.
#
# Option examples:
# has_many :comments, :order => "posted_on"
@@ -711,7 +712,7 @@ module ActiveRecord
configure_dependency_for_has_many(reflection)
- add_multiple_associated_save_callbacks(reflection.name)
+ add_multiple_associated_save_callbacks(reflection.name) unless options[:validate] == false
add_association_callbacks(reflection.name, reflection.options)
if options[:through]
@@ -770,6 +771,7 @@ module ActiveRecord
# * <tt>:source_type</tt> - Specifies type of the source association used by <tt>has_one :through</tt> queries where the source
# association is a polymorphic +belongs_to+.
# * <tt>:readonly</tt> - If true, the associated object is readonly through the association.
+ # * <tt>:validate</tt> - If false, don't validate the associated object when saving the parent object. +false+ by default.
#
# Option examples:
# has_one :credit_card, :dependent => :destroy # destroys the associated credit card
@@ -800,7 +802,7 @@ module ActiveRecord
end
after_save method_name
- add_single_associated_save_callbacks(reflection.name)
+ add_single_associated_save_callbacks(reflection.name) if options[:validate] == true
association_accessor_methods(reflection, HasOneAssociation)
association_constructor_method(:build, reflection, HasOneAssociation)
association_constructor_method(:create, reflection, HasOneAssociation)
@@ -858,6 +860,7 @@ module ActiveRecord
# Note: If you've enabled the counter cache, then you may want to add the counter cache attribute
# to the +attr_readonly+ list in the associated classes (e.g. <tt>class Post; attr_readonly :comments_count; end</tt>).
# * <tt>:readonly</tt> - If true, the associated object is readonly through the association.
+ # * <tt>:validate</tt> - If false, don't validate the associated objects when saving the parent object. +false+ by default.
#
# Option examples:
# belongs_to :firm, :foreign_key => "client_of"
@@ -938,6 +941,8 @@ module ActiveRecord
)
end
+ add_single_associated_save_callbacks(reflection.name) if options[:validate] == true
+
configure_dependency_for_belongs_to(reflection)
end
@@ -1026,6 +1031,7 @@ module ActiveRecord
# * <tt>:select</tt> - By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if, for example, you want to do a join
# but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error.
# * <tt>:readonly</tt> - If true, all the associated objects are readonly through the association.
+ # * <tt>:validate</tt> - If false, don't validate the associated objects when saving the parent object. +true+ by default.
#
# Option examples:
# has_and_belongs_to_many :projects
@@ -1038,7 +1044,7 @@ module ActiveRecord
def has_and_belongs_to_many(association_id, options = {}, &extension)
reflection = create_has_and_belongs_to_many_reflection(association_id, options, &extension)
- add_multiple_associated_save_callbacks(reflection.name)
+ add_multiple_associated_save_callbacks(reflection.name) unless options[:validate] == false
collection_accessor_methods(reflection, HasAndBelongsToManyAssociation)
# Don't use a before_destroy callback since users' before_destroy
@@ -1344,7 +1350,8 @@ module ActiveRecord
:uniq,
:finder_sql, :counter_sql,
:before_add, :after_add, :before_remove, :after_remove,
- :extend, :readonly
+ :extend, :readonly,
+ :validate
)
options[:extend] = create_extension_modules(association_id, extension, options[:extend])
@@ -1354,7 +1361,7 @@ module ActiveRecord
def create_has_one_reflection(association_id, options)
options.assert_valid_keys(
- :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly
+ :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly, :validate
)
create_reflection(:has_one, association_id, options, self)
@@ -1362,7 +1369,7 @@ module ActiveRecord
def create_has_one_through_reflection(association_id, options)
options.assert_valid_keys(
- :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :through, :source, :source_type
+ :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :through, :source, :source_type, :validate
)
create_reflection(:has_one, association_id, options, self)
end
@@ -1370,7 +1377,7 @@ module ActiveRecord
def create_belongs_to_reflection(association_id, options)
options.assert_valid_keys(
:class_name, :foreign_key, :foreign_type, :remote, :select, :conditions, :include, :dependent,
- :counter_cache, :extend, :polymorphic, :readonly
+ :counter_cache, :extend, :polymorphic, :readonly, :validate
)
reflection = create_reflection(:belongs_to, association_id, options, self)
@@ -1389,7 +1396,8 @@ module ActiveRecord
:uniq,
:finder_sql, :delete_sql, :insert_sql,
:before_add, :after_add, :before_remove, :after_remove,
- :extend, :readonly
+ :extend, :readonly,
+ :validate
)
options[:extend] = create_extension_modules(association_id, extension, options[:extend])
@@ -1507,7 +1515,7 @@ module ActiveRecord
end
def order_tables(options)
- order = options[:order]
+ order = [options[:order], scope(:find, :order) ].join(", ")
return [] unless order && order.is_a?(String)
order.scan(/([\.\w]+).?\./).flatten
end
@@ -1639,7 +1647,9 @@ module ActiveRecord
end
def join_for_table_name(table_name)
- @joins.select{|j|j.aliased_table_name == table_name.gsub(/^\"(.*)\"$/){$1} }.first rescue nil
+ join = (@joins.select{|j|j.aliased_table_name == table_name.gsub(/^\"(.*)\"$/){$1} }.first) rescue nil
+ return join unless join.nil?
+ @joins.select{|j|j.is_a?(JoinAssociation) && j.aliased_join_table_name == table_name.gsub(/^\"(.*)\"$/){$1} }.first rescue nil
end
def joins_for_table_name(table_name)
diff --git a/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb b/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb
index 4fa8e9d0a8..918404eac6 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
@@ -87,6 +87,7 @@ module ActiveRecord
:joins => @join_sql,
:readonly => false,
:order => @reflection.options[:order],
+ :include => @reflection.options[:include],
:limit => @reflection.options[:limit] } }
end
diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb
index f584a97cbb..295beb2966 100644
--- a/activerecord/lib/active_record/associations/has_many_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_association.rb
@@ -100,7 +100,7 @@ module ActiveRecord
create_scoping = {}
set_belongs_to_association_for(create_scoping)
{
- :find => { :conditions => @finder_sql, :readonly => false, :order => @reflection.options[:order], :limit => @reflection.options[:limit] },
+ :find => { :conditions => @finder_sql, :readonly => false, :order => @reflection.options[:order], :limit => @reflection.options[:limit], :include => @reflection.options[:include]},
:create => create_scoping
}
end
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index cfc6a5693a..c2a8d3ec3d 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -372,7 +372,7 @@ module ActiveRecord #:nodoc:
def self.reset_subclasses #:nodoc:
nonreloadables = []
subclasses.each do |klass|
- unless Dependencies.autoloaded? klass
+ unless ActiveSupport::Dependencies.autoloaded? klass
nonreloadables << klass
next
end
@@ -1296,6 +1296,20 @@ module ActiveRecord #:nodoc:
store_full_sti_class ? name : name.demodulize
end
+ # Merges conditions so that the result is a valid +condition+
+ def merge_conditions(*conditions)
+ segments = []
+
+ conditions.each do |condition|
+ unless condition.blank?
+ sql = sanitize_sql(condition)
+ segments << sql unless sql.blank?
+ end
+ end
+
+ "(#{segments.join(') AND (')})" unless segments.empty?
+ end
+
private
def find_initial(options)
options.update(:limit => 1)
@@ -1464,7 +1478,7 @@ module ActiveRecord #:nodoc:
def construct_finder_sql(options)
scope = scope(:find)
- sql = "SELECT #{options[:select] || (scope && scope[:select]) || (options[:joins] && quoted_table_name + '.*') || '*'} "
+ sql = "SELECT #{options[:select] || (scope && scope[:select]) || ((options[:joins] || (scope && scope[:joins])) && quoted_table_name + '.*') || '*'} "
sql << "FROM #{(scope && scope[:from]) || options[:from] || quoted_table_name} "
add_joins!(sql, options, scope)
@@ -1483,20 +1497,6 @@ module ActiveRecord #:nodoc:
(safe_to_array(first) + safe_to_array(second)).uniq
end
- # Merges conditions so that the result is a valid +condition+
- def merge_conditions(*conditions)
- segments = []
-
- conditions.each do |condition|
- unless condition.blank?
- sql = sanitize_sql(condition)
- segments << sql unless sql.blank?
- end
- end
-
- "(#{segments.join(') AND (')})" unless segments.empty?
- end
-
# Object#to_a is deprecated, though it does have the desired behavior
def safe_to_array(o)
case o
@@ -1902,10 +1902,12 @@ module ActiveRecord #:nodoc:
# MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
def compute_type(type_name)
modularized_name = type_name_with_module(type_name)
- begin
- class_eval(modularized_name, __FILE__, __LINE__)
- rescue NameError
- class_eval(type_name, __FILE__, __LINE__)
+ silence_warnings do
+ begin
+ class_eval(modularized_name, __FILE__, __LINE__)
+ rescue NameError
+ class_eval(type_name, __FILE__, __LINE__)
+ end
end
end
@@ -2052,9 +2054,10 @@ module ActiveRecord #:nodoc:
end
def replace_named_bind_variables(statement, bind_vars) #:nodoc:
- statement.gsub(/:([a-zA-Z]\w*)/) do
- match = $1.to_sym
- if bind_vars.include?(match)
+ statement.gsub(/(:?):([a-zA-Z]\w*)/) do
+ if $1 == ':' # skip postgresql casts
+ $& # return the whole match
+ elsif bind_vars.include?(match = $2.to_sym)
quote_bound_value(bind_vars[match])
else
raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}"
@@ -2063,13 +2066,18 @@ module ActiveRecord #:nodoc:
end
def expand_range_bind_variables(bind_vars) #:nodoc:
- bind_vars.sum do |var|
+ expanded = []
+
+ bind_vars.each do |var|
if var.is_a?(Range)
- [var.first, var.last]
+ expanded << var.first
+ expanded << var.last
else
- [var]
+ expanded << var
end
end
+
+ expanded
end
def quote_bound_value(value) #:nodoc:
@@ -2161,11 +2169,11 @@ module ActiveRecord #:nodoc:
def cache_key
case
when new_record?
- "#{self.class.name.tableize}/new"
- when self[:updated_at]
- "#{self.class.name.tableize}/#{id}-#{updated_at.to_s(:number)}"
+ "#{self.class.model_name.cache_key}/new"
+ when timestamp = self[:updated_at]
+ "#{self.class.model_name.cache_key}/#{id}-#{timestamp.to_s(:number)}"
else
- "#{self.class.name.tableize}/#{id}"
+ "#{self.class.model_name.cache_key}/#{id}"
end
end
@@ -2246,12 +2254,12 @@ module ActiveRecord #:nodoc:
end
end
- # Updates a single attribute and saves the record. This is especially useful for boolean flags on existing records.
- # Note: This method is overwritten by the Validation module that'll make sure that updates made with this method
- # aren't subjected to validation checks. Hence, attributes can be updated even if the full object isn't valid.
+ # Updates a single attribute and saves the record without going through the normal validation procedure.
+ # This is especially useful for boolean flags on existing records. The regular +update_attribute+ method
+ # in Base is replaced with this when the validations module is mixed in, which it is by default.
def update_attribute(name, value)
send(name.to_s + '=', value)
- save
+ save(false)
end
# Updates all the attributes from the passed-in Hash and saves the record. If the object is invalid, the saving will
diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb
index 10e8330d1c..2ca1a0aaa3 100644
--- a/activerecord/lib/active_record/calculations.rb
+++ b/activerecord/lib/active_record/calculations.rb
@@ -1,6 +1,6 @@
module ActiveRecord
module Calculations #:nodoc:
- CALCULATIONS_OPTIONS = [:conditions, :joins, :order, :select, :group, :having, :distinct, :limit, :offset, :include]
+ CALCULATIONS_OPTIONS = [:conditions, :joins, :order, :select, :group, :having, :distinct, :limit, :offset, :include, :from]
def self.included(base)
base.extend(ClassMethods)
end
@@ -27,6 +27,8 @@ module ActiveRecord
# * <tt>:select</tt>: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not
# include the joined columns.
# * <tt>:distinct</tt>: Set this to true to make this a distinct calculation, such as SELECT COUNT(DISTINCT posts.id) ...
+ # * <tt>:from</tt> - By default, this is the table name of the class, but can be changed to an alternate table name (or even the name
+ # of a database view).
#
# Examples for counting all:
# Person.count # returns the total count of all people
@@ -71,7 +73,7 @@ module ActiveRecord
#
# Person.sum('age')
def sum(column_name, options = {})
- calculate(:sum, column_name, options) || 0
+ calculate(:sum, column_name, options)
end
# This calculates aggregate values in the given column. Methods for count, sum, average, minimum, and maximum have been added as shortcuts.
@@ -178,8 +180,12 @@ module ActiveRecord
sql = "SELECT COUNT(*) AS #{aggregate_alias}" if use_workaround
sql << ", #{options[:group_field]} AS #{options[:group_alias]}" if options[:group]
- sql << " FROM (SELECT #{distinct}#{column_name}" if use_workaround
- sql << " FROM #{connection.quote_table_name(table_name)} "
+ if options[:from]
+ sql << " FROM #{options[:from]} "
+ else
+ sql << " FROM (SELECT #{distinct}#{column_name}" if use_workaround
+ sql << " FROM #{connection.quote_table_name(table_name)} "
+ end
if merged_includes.any?
join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, merged_includes, options[:joins])
sql << join_dependency.join_associations.collect{|join| join.association_join }.join
@@ -266,6 +272,7 @@ module ActiveRecord
operation = operation.to_s.downcase
case operation
when 'count' then value.to_i
+ when 'sum' then value =~ /\./ ? value.to_f : value.to_i
when 'avg' then value && value.to_f
else column ? column.type_cast(value) : value
end
diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb
index 6c2f65df05..5883cdfbe1 100755
--- a/activerecord/lib/active_record/callbacks.rb
+++ b/activerecord/lib/active_record/callbacks.rb
@@ -293,14 +293,14 @@ module ActiveRecord
private
def callback(method)
- notify(method)
-
result = run_callbacks(method) { |result, object| result == false }
if result != false && respond_to_without_attributes?(method)
result = send(method)
end
+ notify(method)
+
return result
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index a2a1bb8c82..0f60a91ef1 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -331,21 +331,32 @@ module ActiveRecord
end
def assume_migrated_upto_version(version)
+ version = version.to_i
sm_table = quote_table_name(ActiveRecord::Migrator.schema_migrations_table_name)
+
migrated = select_values("SELECT version FROM #{sm_table}").map(&:to_i)
versions = Dir['db/migrate/[0-9]*_*.rb'].map do |filename|
filename.split('/').last.split('_').first.to_i
end
- execute "INSERT INTO #{sm_table} (version) VALUES ('#{version}')" unless migrated.include?(version.to_i)
- (versions - migrated).select { |v| v < version.to_i }.each do |v|
- execute "INSERT INTO #{sm_table} (version) VALUES ('#{v}')"
+ unless migrated.include?(version)
+ execute "INSERT INTO #{sm_table} (version) VALUES ('#{version}')"
+ end
+
+ inserted = Set.new
+ (versions - migrated).each do |v|
+ if inserted.include?(v)
+ raise "Duplicate migration #{v}. Please renumber your migrations to resolve the conflict."
+ elsif v < version
+ execute "INSERT INTO #{sm_table} (version) VALUES ('#{v}')"
+ inserted << v
+ end
end
end
def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
if native = native_database_types[type]
- column_type_sql = native.is_a?(Hash) ? native[:name] : native
+ column_type_sql = (native.is_a?(Hash) ? native[:name] : native).dup
if type == :decimal # ignore limit, use precision and scale
scale ||= native[:scale]
@@ -360,7 +371,7 @@ module ActiveRecord
raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale if specified"
end
- elsif limit ||= native.is_a?(Hash) && native[:limit]
+ elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit])
column_type_sql << "(#{limit})"
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index 653b45021d..dd54950790 100755
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -42,30 +42,6 @@ end
module ActiveRecord
class Base
- def self.require_mysql
- # Include the MySQL driver if one hasn't already been loaded
- unless defined? Mysql
- begin
- require_library_or_gem 'mysql'
- rescue LoadError => cannot_require_mysql
- # Use the bundled Ruby/MySQL driver if no driver is already in place
- begin
- ActiveRecord::Base.logger.info(
- "WARNING: You're using the Ruby-based MySQL library that ships with Rails. This library is not suited for production. " +
- "Please install the C-based MySQL library instead (gem install mysql)."
- ) if ActiveRecord::Base.logger
-
- require 'active_record/vendor/mysql'
- rescue LoadError
- raise cannot_require_mysql
- end
- end
- end
-
- # Define Mysql::Result.all_hashes
- MysqlCompat.define_all_hashes_method!
- end
-
# Establishes a connection to the database that's used by all Active Record objects.
def self.mysql_connection(config) # :nodoc:
config = config.symbolize_keys
@@ -81,7 +57,17 @@ module ActiveRecord
raise ArgumentError, "No database specified. Missing argument: database."
end
- require_mysql
+ # Require the MySQL driver and define Mysql::Result.all_hashes
+ unless defined? Mysql
+ begin
+ require_library_or_gem('mysql')
+ rescue LoadError
+ $stderr.puts '!!! The bundled mysql.rb driver has been removed from Rails 2.2. Please install the mysql gem and try again: gem install mysql.'
+ raise
+ end
+ end
+ MysqlCompat.define_all_hashes_method!
+
mysql = Mysql.init
mysql.ssl_set(config[:sslkey], config[:sslcert], config[:sslca], config[:sslcapath], config[:sslcipher]) if config[:sslkey]
@@ -113,7 +99,8 @@ module ActiveRecord
end
def extract_limit(sql_type)
- if sql_type =~ /blob|text/i
+ case sql_type
+ when /blob|text/i
case sql_type
when /tiny/i
255
@@ -124,6 +111,11 @@ module ActiveRecord
else
super # we could return 65535 here, but we leave it undecorated by default
end
+ when /^bigint/i; 8
+ when /^int/i; 4
+ when /^mediumint/i; 3
+ when /^smallint/i; 2
+ when /^tinyint/i; 1
else
super
end
@@ -165,8 +157,10 @@ module ActiveRecord
#
# ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans = false
class MysqlAdapter < AbstractAdapter
- @@emulate_booleans = true
cattr_accessor :emulate_booleans
+ self.emulate_booleans = true
+
+ ADAPTER_NAME = 'MySQL'.freeze
LOST_CONNECTION_ERROR_MESSAGES = [
"Server shutdown in progress",
@@ -174,7 +168,22 @@ module ActiveRecord
"Lost connection to MySQL server during query",
"MySQL server has gone away" ]
- QUOTED_TRUE, QUOTED_FALSE = '1', '0'
+ QUOTED_TRUE, QUOTED_FALSE = '1'.freeze, '0'.freeze
+
+ NATIVE_DATABASE_TYPES = {
+ :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY".freeze,
+ :string => { :name => "varchar", :limit => 255 },
+ :text => { :name => "text" },
+ :integer => { :name => "int", :limit => 4 },
+ :float => { :name => "float" },
+ :decimal => { :name => "decimal" },
+ :datetime => { :name => "datetime" },
+ :timestamp => { :name => "datetime" },
+ :time => { :name => "time" },
+ :date => { :name => "date" },
+ :binary => { :name => "blob" },
+ :boolean => { :name => "tinyint", :limit => 1 }
+ }
def initialize(connection, logger, connection_options, config)
super(connection, logger)
@@ -184,7 +193,7 @@ module ActiveRecord
end
def adapter_name #:nodoc:
- 'MySQL'
+ ADAPTER_NAME
end
def supports_migrations? #:nodoc:
@@ -192,20 +201,7 @@ module ActiveRecord
end
def native_database_types #:nodoc:
- {
- :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY",
- :string => { :name => "varchar", :limit => 255 },
- :text => { :name => "text" },
- :integer => { :name => "int"},
- :float => { :name => "float" },
- :decimal => { :name => "decimal" },
- :datetime => { :name => "datetime" },
- :timestamp => { :name => "datetime" },
- :time => { :name => "time" },
- :date => { :name => "date" },
- :binary => { :name => "blob" },
- :boolean => { :name => "tinyint", :limit => 1 }
- }
+ NATIVE_DATABASE_TYPES
end
@@ -460,8 +456,16 @@ module ActiveRecord
end
def rename_column(table_name, column_name, new_column_name) #:nodoc:
+ options = {}
+ if column = columns(table_name).find { |c| c.name == column_name.to_s }
+ options[:default] = column.default
+ else
+ raise ActiveRecordError, "No such column: #{table_name}.#{column_name}"
+ end
current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"]
- execute "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}"
+ rename_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}"
+ add_column_options!(rename_column_sql, options)
+ execute(rename_column_sql)
end
# Maps logical Rails types to MySQL-specific data types.
@@ -469,14 +473,11 @@ module ActiveRecord
return super unless type.to_s == 'integer'
case limit
- when 0..3
- "smallint(#{limit})"
- when 4..8
- "int(#{limit})"
- when 9..20
- "bigint(#{limit})"
- else
- 'int(11)'
+ when 1; 'tinyint'
+ when 2; 'smallint'
+ when 3; 'mediumint'
+ when 4, nil; 'int(11)'
+ else; 'bigint'
end
end
@@ -498,12 +499,17 @@ module ActiveRecord
private
def connect
+ @connection.reconnect = true if @connection.respond_to?(:reconnect=)
+
encoding = @config[:encoding]
if encoding
@connection.options(Mysql::SET_CHARSET_NAME, encoding) rescue nil
end
+
@connection.ssl_set(@config[:sslkey], @config[:sslcert], @config[:sslca], @config[:sslcapath], @config[:sslcipher]) if @config[:sslkey]
+
@connection.real_connect(*@connection_options)
+
execute("SET NAMES '#{encoding}'") if encoding
# By default, MySQL 'where id is null' selects the last inserted id.
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 7dc7398b0a..88f703d813 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -47,6 +47,12 @@ module ActiveRecord
end
private
+ def extract_limit(sql_type)
+ return 8 if sql_type =~ /^bigint/i
+ return 2 if sql_type =~ /^smallint/i
+ super
+ end
+
# Extracts the scale from PostgreSQL-specific data types.
def extract_scale(sql_type)
# Money type has a fixed scale of 2.
@@ -238,9 +244,26 @@ module ActiveRecord
# * <tt>:min_messages</tt> - An optional client min messages that is used in a <tt>SET client_min_messages TO <min_messages></tt> call on the connection.
# * <tt>:allow_concurrency</tt> - If true, use async query methods so Ruby threads don't deadlock; otherwise, use blocking query methods.
class PostgreSQLAdapter < AbstractAdapter
+ ADAPTER_NAME = 'PostgreSQL'.freeze
+
+ NATIVE_DATABASE_TYPES = {
+ :primary_key => "serial primary key".freeze,
+ :string => { :name => "character varying", :limit => 255 },
+ :text => { :name => "text" },
+ :integer => { :name => "integer" },
+ :float => { :name => "float" },
+ :decimal => { :name => "decimal" },
+ :datetime => { :name => "timestamp" },
+ :timestamp => { :name => "timestamp" },
+ :time => { :name => "time" },
+ :date => { :name => "date" },
+ :binary => { :name => "bytea" },
+ :boolean => { :name => "boolean" }
+ }
+
# Returns 'PostgreSQL' as adapter name for identification purposes.
def adapter_name
- 'PostgreSQL'
+ ADAPTER_NAME
end
# Initializes and connects a PostgreSQL adapter.
@@ -282,20 +305,7 @@ module ActiveRecord
end
def native_database_types #:nodoc:
- {
- :primary_key => "serial primary key",
- :string => { :name => "character varying", :limit => 255 },
- :text => { :name => "text" },
- :integer => { :name => "integer" },
- :float => { :name => "float" },
- :decimal => { :name => "decimal" },
- :datetime => { :name => "timestamp" },
- :timestamp => { :name => "timestamp" },
- :time => { :name => "time" },
- :date => { :name => "date" },
- :binary => { :name => "bytea" },
- :boolean => { :name => "boolean" }
- }
+ NATIVE_DATABASE_TYPES
end
# Does PostgreSQL support migrations?
@@ -319,6 +329,10 @@ module ActiveRecord
has_support
end
+ def supports_insert_with_returning?
+ postgresql_version >= 80200
+ end
+
# Returns the configured supported identifier length supported by PostgreSQL,
# or report the default of 63 on PostgreSQL 7.x.
def table_alias_length
@@ -411,8 +425,34 @@ module ActiveRecord
# Executes an INSERT query and returns the new record's ID
def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
+ # Extract the table from the insert sql. Yuck.
table = sql.split(" ", 4)[2].gsub('"', '')
- super || pk && last_insert_id(table, sequence_name || default_sequence_name(table, pk))
+
+ # Try an insert with 'returning id' if available (PG >= 8.2)
+ if supports_insert_with_returning?
+ pk, sequence_name = *pk_and_sequence_for(table) unless pk
+ if pk
+ id = select_value("#{sql} RETURNING #{quote_column_name(pk)}")
+ clear_query_cache
+ return id
+ end
+ end
+
+ # Otherwise, insert then grab last_insert_id.
+ if insert_id = super
+ insert_id
+ else
+ # If neither pk nor sequence name is given, look them up.
+ unless pk || sequence_name
+ pk, sequence_name = *pk_and_sequence_for(table)
+ end
+
+ # If a pk is given, fallback to default sequence name.
+ # Don't fetch last insert id for a table without a pk.
+ if pk && sequence_name ||= default_sequence_name(table, pk)
+ last_insert_id(table, sequence_name)
+ end
+ end
end
# create a 2D array representing the result set
@@ -506,7 +546,7 @@ module ActiveRecord
end
end
- execute "CREATE DATABASE #{name}#{option_string}"
+ execute "CREATE DATABASE #{quote_table_name(name)}#{option_string}"
end
# Drops a PostgreSQL database
@@ -514,7 +554,15 @@ module ActiveRecord
# Example:
# drop_database 'matt_development'
def drop_database(name) #:nodoc:
- execute "DROP DATABASE IF EXISTS #{name}"
+ if postgresql_version >= 80200
+ execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
+ else
+ begin
+ execute "DROP DATABASE #{quote_table_name(name)}"
+ rescue ActiveRecord::StatementInvalid
+ @logger.warn "#{name} database doesn't exist." if @logger
+ end
+ end
end
@@ -676,7 +724,7 @@ module ActiveRecord
# Renames a table.
def rename_table(name, new_name)
- execute "ALTER TABLE #{name} RENAME TO #{new_name}"
+ execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
end
# Adds a new column to the named table.
@@ -743,12 +791,10 @@ module ActiveRecord
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
return super unless type.to_s == 'integer'
- if limit.nil? || limit == 4
- 'integer'
- elsif limit < 4
- 'smallint'
- else
- 'bigint'
+ case limit
+ when 1..2; 'smallint'
+ when 3..4, nil; 'integer'
+ when 5..8; 'bigint'
end
end
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index c4cbe5d52f..e19614e31f 100755
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -547,7 +547,7 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash)
@connection, @table_name, @fixture_path, @file_filter = connection, table_name, fixture_path, file_filter
@class_name = class_name ||
(ActiveRecord::Base.pluralize_table_names ? @table_name.singularize.camelize : @table_name.camelize)
- @table_name = ActiveRecord::Base.table_name_prefix + @table_name + ActiveRecord::Base.table_name_suffix
+ @table_name = "#{ActiveRecord::Base.table_name_prefix}#{@table_name}#{ActiveRecord::Base.table_name_suffix}"
@table_name = class_name.table_name if class_name.respond_to?(:table_name)
@connection = class_name.connection if class_name.respond_to?(:connection)
read_fixture_files
diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb
index c66034d18b..ff9899d032 100644
--- a/activerecord/lib/active_record/locking/optimistic.rb
+++ b/activerecord/lib/active_record/locking/optimistic.rb
@@ -68,6 +68,7 @@ module ActiveRecord
def update_with_lock(attribute_names = @attributes.keys) #:nodoc:
return update_without_lock(attribute_names) unless locking_enabled?
+ return 0 if attribute_names.empty?
lock_col = self.class.locking_column
previous_value = send(lock_col).to_i
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index b47b01e99a..e095b3c766 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -399,7 +399,10 @@ module ActiveRecord
def run
target = migrations.detect { |m| m.version == @target_version }
raise UnknownMigrationVersionError.new(@target_version) if target.nil?
- target.migrate(@direction)
+ unless (up? && migrated.include?(target.version.to_i)) || (down? && !migrated.include?(target.version.to_i))
+ target.migrate(@direction)
+ record_version_state_after_migrating(target.version)
+ end
end
def migrate
diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb
index b0c8a8b815..eac61e9e43 100644
--- a/activerecord/lib/active_record/named_scope.rb
+++ b/activerecord/lib/active_record/named_scope.rb
@@ -82,6 +82,7 @@ module ActiveRecord
# expected_options = { :conditions => { :colored => 'red' } }
# assert_equal expected_options, Shirt.colored('red').proxy_options
def named_scope(name, options = {}, &block)
+ name = name.to_sym
scopes[name] = lambda do |parent_scope, *args|
Scope.new(parent_scope, case options
when Hash
diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb
index 6e55e36b7d..25e0e61c69 100644
--- a/activerecord/lib/active_record/observer.rb
+++ b/activerecord/lib/active_record/observer.rb
@@ -189,7 +189,7 @@ module ActiveRecord
def add_observer!(klass)
klass.add_observer(self)
- klass.class_eval 'def after_find() end' unless klass.respond_to?(:after_find)
+ klass.class_eval 'def after_find() end' unless klass.method_defined?(:after_find)
end
end
end
diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb
index 52805ea851..8196442fe5 100755
--- a/activerecord/lib/active_record/validations.rb
+++ b/activerecord/lib/active_record/validations.rb
@@ -277,7 +277,6 @@ module ActiveRecord
base.class_eval do
alias_method_chain :save, :validation
alias_method_chain :save!, :validation
- alias_method_chain :update_attribute, :validation_skipping
end
base.send :include, ActiveSupport::Callbacks
@@ -914,14 +913,6 @@ module ActiveRecord
end
end
- # Updates a single attribute and saves the record without going through the normal validation procedure.
- # This is especially useful for boolean flags on existing records. The regular +update_attribute+ method
- # in Base is replaced with this when the validations module is mixed in, which it is by default.
- def update_attribute_with_validation_skipping(name, value)
- send(name.to_s + '=', value)
- save(false)
- end
-
# Runs +validate+ and +validate_on_create+ or +validate_on_update+ and returns true if no errors were added otherwise false.
def valid?
errors.clear
diff --git a/activerecord/lib/active_record/vendor/db2.rb b/activerecord/lib/active_record/vendor/db2.rb
deleted file mode 100644
index 812c8cc517..0000000000
--- a/activerecord/lib/active_record/vendor/db2.rb
+++ /dev/null
@@ -1,362 +0,0 @@
-require 'db2/db2cli.rb'
-
-module DB2
- module DB2Util
- include DB2CLI
-
- def free() SQLFreeHandle(@handle_type, @handle); end
- def handle() @handle; end
-
- def check_rc(rc)
- if ![SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NO_DATA_FOUND].include?(rc)
- rec = 1
- msg = ''
- loop do
- a = SQLGetDiagRec(@handle_type, @handle, rec, 500)
- break if a[0] != SQL_SUCCESS
- msg << a[3] if !a[3].nil? and a[3] != '' # Create message.
- rec += 1
- end
- raise "DB2 error: #{msg}"
- end
- end
- end
-
- class Environment
- include DB2Util
-
- def initialize
- @handle_type = SQL_HANDLE_ENV
- rc, @handle = SQLAllocHandle(@handle_type, SQL_NULL_HANDLE)
- check_rc(rc)
- end
-
- def data_sources(buffer_length = 1024)
- retval = []
- max_buffer_length = buffer_length
-
- a = SQLDataSources(@handle, SQL_FETCH_FIRST, SQL_MAX_DSN_LENGTH + 1, buffer_length)
- retval << [a[1], a[3]]
- max_buffer_length = [max_buffer_length, a[4]].max
-
- loop do
- a = SQLDataSources(@handle, SQL_FETCH_NEXT, SQL_MAX_DSN_LENGTH + 1, buffer_length)
- break if a[0] == SQL_NO_DATA_FOUND
-
- retval << [a[1], a[3]]
- max_buffer_length = [max_buffer_length, a[4]].max
- end
-
- if max_buffer_length > buffer_length
- get_data_sources(max_buffer_length)
- else
- retval
- end
- end
- end
-
- class Connection
- include DB2Util
-
- def initialize(environment)
- @env = environment
- @handle_type = SQL_HANDLE_DBC
- rc, @handle = SQLAllocHandle(@handle_type, @env.handle)
- check_rc(rc)
- end
-
- def connect(server_name, user_name = '', auth = '')
- check_rc(SQLConnect(@handle, server_name, user_name.to_s, auth.to_s))
- end
-
- def set_connect_attr(attr, value)
- value += "\0" if value.class == String
- check_rc(SQLSetConnectAttr(@handle, attr, value))
- end
-
- def set_auto_commit_on
- set_connect_attr(SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON)
- end
-
- def set_auto_commit_off
- set_connect_attr(SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF)
- end
-
- def disconnect
- check_rc(SQLDisconnect(@handle))
- end
-
- def rollback
- check_rc(SQLEndTran(@handle_type, @handle, SQL_ROLLBACK))
- end
-
- def commit
- check_rc(SQLEndTran(@handle_type, @handle, SQL_COMMIT))
- end
- end
-
- class Statement
- include DB2Util
-
- def initialize(connection)
- @conn = connection
- @handle_type = SQL_HANDLE_STMT
- @parms = [] #yun
- @sql = '' #yun
- @numParms = 0 #yun
- @prepared = false #yun
- @parmArray = [] #yun. attributes of the parameter markers
- rc, @handle = SQLAllocHandle(@handle_type, @conn.handle)
- check_rc(rc)
- end
-
- def columns(table_name, schema_name = '%')
- check_rc(SQLColumns(@handle, '', schema_name.upcase, table_name.upcase, '%'))
- fetch_all
- end
-
- def tables(schema_name = '%')
- check_rc(SQLTables(@handle, '', schema_name.upcase, '%', 'TABLE'))
- fetch_all
- end
-
- def indexes(table_name, schema_name = '')
- check_rc(SQLStatistics(@handle, '', schema_name.upcase, table_name.upcase, SQL_INDEX_ALL, SQL_ENSURE))
- fetch_all
- end
-
- def prepare(sql)
- @sql = sql
- check_rc(SQLPrepare(@handle, sql))
- rc, @numParms = SQLNumParams(@handle) #number of question marks
- check_rc(rc)
- #--------------------------------------------------------------------------
- # parameter attributes are stored in instance variable @parmArray so that
- # they are available when execute method is called.
- #--------------------------------------------------------------------------
- if @numParms > 0 # get parameter marker attributes
- 1.upto(@numParms) do |i| # parameter number starts from 1
- rc, type, size, decimalDigits = SQLDescribeParam(@handle, i)
- check_rc(rc)
- @parmArray << Parameter.new(type, size, decimalDigits)
- end
- end
- @prepared = true
- self
- end
-
- def execute(*parms)
- raise "The statement was not prepared" if @prepared == false
-
- if parms.size == 1 and parms[0].class == Array
- parms = parms[0]
- end
-
- if @numParms != parms.size
- raise "Number of parameters supplied does not match with the SQL statement"
- end
-
- if @numParms > 0 #need to bind parameters
- #--------------------------------------------------------------------
- #calling bindParms may not be safe. Look comment below.
- #--------------------------------------------------------------------
- #bindParms(parms)
-
- valueArray = []
- 1.upto(@numParms) do |i| # parameter number starts from 1
- type = @parmArray[i - 1].class
- size = @parmArray[i - 1].size
- decimalDigits = @parmArray[i - 1].decimalDigits
-
- if parms[i - 1].class == String
- valueArray << parms[i - 1]
- else
- valueArray << parms[i - 1].to_s
- end
-
- rc = SQLBindParameter(@handle, i, type, size, decimalDigits, valueArray[i - 1])
- check_rc(rc)
- end
- end
-
- check_rc(SQLExecute(@handle))
-
- if @numParms != 0
- check_rc(SQLFreeStmt(@handle, SQL_RESET_PARAMS)) # Reset parameters
- end
-
- self
- end
-
- #-------------------------------------------------------------------------------
- # The last argument(value) to SQLBindParameter is a deferred argument, that is,
- # it should be available when SQLExecute is called. Even though "value" is
- # local to bindParms method, it seems that it is available when SQLExecute
- # is called. I am not sure whether it would still work if garbage collection
- # is done between bindParms call and SQLExecute call inside the execute method
- # above.
- #-------------------------------------------------------------------------------
- def bindParms(parms) # This is the real thing. It uses SQLBindParms
- 1.upto(@numParms) do |i| # parameter number starts from 1
- rc, dataType, parmSize, decimalDigits = SQLDescribeParam(@handle, i)
- check_rc(rc)
- if parms[i - 1].class == String
- value = parms[i - 1]
- else
- value = parms[i - 1].to_s
- end
- rc = SQLBindParameter(@handle, i, dataType, parmSize, decimalDigits, value)
- check_rc(rc)
- end
- end
-
- #------------------------------------------------------------------------------
- # bind method does not use DB2's SQLBindParams, but replaces "?" in the
- # SQL statement with the value before passing the SQL statement to DB2.
- # It is not efficient and can handle only strings since it puts everything in
- # quotes.
- #------------------------------------------------------------------------------
- def bind(sql, args) #does not use SQLBindParams
- arg_index = 0
- result = ""
- tokens(sql).each do |part|
- case part
- when '?'
- result << "'" + (args[arg_index]) + "'" #put it into quotes
- arg_index += 1
- when '??'
- result << "?"
- else
- result << part
- end
- end
- if arg_index < args.size
- raise "Too many SQL parameters"
- elsif arg_index > args.size
- raise "Not enough SQL parameters"
- end
- result
- end
-
- ## Break the sql string into parts.
- #
- # This is NOT a full lexer for SQL. It just breaks up the SQL
- # string enough so that question marks, double question marks and
- # quoted strings are separated. This is used when binding
- # arguments to "?" in the SQL string. Note: comments are not
- # handled.
- #
- def tokens(sql)
- toks = sql.scan(/('([^'\\]|''|\\.)*'|"([^"\\]|""|\\.)*"|\?\??|[^'"?]+)/)
- toks.collect { |t| t[0] }
- end
-
- def exec_direct(sql)
- check_rc(SQLExecDirect(@handle, sql))
- self
- end
-
- def set_cursor_name(name)
- check_rc(SQLSetCursorName(@handle, name))
- self
- end
-
- def get_cursor_name
- rc, name = SQLGetCursorName(@handle)
- check_rc(rc)
- name
- end
-
- def row_count
- rc, rowcount = SQLRowCount(@handle)
- check_rc(rc)
- rowcount
- end
-
- def num_result_cols
- rc, cols = SQLNumResultCols(@handle)
- check_rc(rc)
- cols
- end
-
- def fetch_all
- if block_given?
- while row = fetch do
- yield row
- end
- else
- res = []
- while row = fetch do
- res << row
- end
- res
- end
- end
-
- def fetch
- cols = get_col_desc
- rc = SQLFetch(@handle)
- if rc == SQL_NO_DATA_FOUND
- SQLFreeStmt(@handle, SQL_CLOSE) # Close cursor
- SQLFreeStmt(@handle, SQL_RESET_PARAMS) # Reset parameters
- return nil
- end
- raise "ERROR" unless rc == SQL_SUCCESS
-
- retval = []
- cols.each_with_index do |c, i|
- rc, content = SQLGetData(@handle, i + 1, c[1], c[2] + 1) #yun added 1 to c[2]
- retval << adjust_content(content)
- end
- retval
- end
-
- def fetch_as_hash
- cols = get_col_desc
- rc = SQLFetch(@handle)
- if rc == SQL_NO_DATA_FOUND
- SQLFreeStmt(@handle, SQL_CLOSE) # Close cursor
- SQLFreeStmt(@handle, SQL_RESET_PARAMS) # Reset parameters
- return nil
- end
- raise "ERROR" unless rc == SQL_SUCCESS
-
- retval = {}
- cols.each_with_index do |c, i|
- rc, content = SQLGetData(@handle, i + 1, c[1], c[2] + 1) #yun added 1 to c[2]
- retval[c[0]] = adjust_content(content)
- end
- retval
- end
-
- def get_col_desc
- rc, nr_cols = SQLNumResultCols(@handle)
- cols = (1..nr_cols).collect do |c|
- rc, name, bl, type, col_sz = SQLDescribeCol(@handle, c, 1024)
- [name.downcase, type, col_sz]
- end
- end
-
- def adjust_content(c)
- case c.class.to_s
- when 'DB2CLI::NullClass'
- return nil
- when 'DB2CLI::Time'
- "%02d:%02d:%02d" % [c.hour, c.minute, c.second]
- when 'DB2CLI::Date'
- "%04d-%02d-%02d" % [c.year, c.month, c.day]
- when 'DB2CLI::Timestamp'
- "%04d-%02d-%02d %02d:%02d:%02d" % [c.year, c.month, c.day, c.hour, c.minute, c.second]
- else
- return c
- end
- end
- end
-
- class Parameter
- attr_reader :type, :size, :decimalDigits
- def initialize(type, size, decimalDigits)
- @type, @size, @decimalDigits = type, size, decimalDigits
- end
- end
-end
diff --git a/activerecord/lib/active_record/vendor/mysql.rb b/activerecord/lib/active_record/vendor/mysql.rb
deleted file mode 100644
index 1c3294c719..0000000000
--- a/activerecord/lib/active_record/vendor/mysql.rb
+++ /dev/null
@@ -1,1214 +0,0 @@
-# $Id: mysql.rb,v 1.24 2005/02/12 11:37:15 tommy Exp $
-#
-# Copyright (C) 2003-2005 TOMITA Masahiro
-# tommy@tmtm.org
-#
-
-class Mysql
-
- VERSION = "4.0-ruby-0.2.6-plus-changes"
-
- require "socket"
- require "digest/sha1"
-
- MAX_PACKET_LENGTH = 256*256*256-1
- MAX_ALLOWED_PACKET = 1024*1024*1024
-
- MYSQL_UNIX_ADDR = "/tmp/mysql.sock"
- MYSQL_PORT = 3306
- PROTOCOL_VERSION = 10
-
- SCRAMBLE_LENGTH = 20
- SCRAMBLE_LENGTH_323 = 8
-
- # Command
- COM_SLEEP = 0
- COM_QUIT = 1
- COM_INIT_DB = 2
- COM_QUERY = 3
- COM_FIELD_LIST = 4
- COM_CREATE_DB = 5
- COM_DROP_DB = 6
- COM_REFRESH = 7
- COM_SHUTDOWN = 8
- COM_STATISTICS = 9
- COM_PROCESS_INFO = 10
- COM_CONNECT = 11
- COM_PROCESS_KILL = 12
- COM_DEBUG = 13
- COM_PING = 14
- COM_TIME = 15
- COM_DELAYED_INSERT = 16
- COM_CHANGE_USER = 17
- COM_BINLOG_DUMP = 18
- COM_TABLE_DUMP = 19
- COM_CONNECT_OUT = 20
- COM_REGISTER_SLAVE = 21
-
- # Client flag
- CLIENT_LONG_PASSWORD = 1
- CLIENT_FOUND_ROWS = 1 << 1
- CLIENT_LONG_FLAG = 1 << 2
- CLIENT_CONNECT_WITH_DB= 1 << 3
- CLIENT_NO_SCHEMA = 1 << 4
- CLIENT_COMPRESS = 1 << 5
- CLIENT_ODBC = 1 << 6
- CLIENT_LOCAL_FILES = 1 << 7
- CLIENT_IGNORE_SPACE = 1 << 8
- CLIENT_PROTOCOL_41 = 1 << 9
- CLIENT_INTERACTIVE = 1 << 10
- CLIENT_SSL = 1 << 11
- CLIENT_IGNORE_SIGPIPE = 1 << 12
- CLIENT_TRANSACTIONS = 1 << 13
- CLIENT_RESERVED = 1 << 14
- CLIENT_SECURE_CONNECTION = 1 << 15
- CLIENT_CAPABILITIES = CLIENT_LONG_PASSWORD|CLIENT_LONG_FLAG|CLIENT_TRANSACTIONS
- PROTO_AUTH41 = CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION
-
- # Connection Option
- OPT_CONNECT_TIMEOUT = 0
- OPT_COMPRESS = 1
- OPT_NAMED_PIPE = 2
- INIT_COMMAND = 3
- READ_DEFAULT_FILE = 4
- READ_DEFAULT_GROUP = 5
- SET_CHARSET_DIR = 6
- SET_CHARSET_NAME = 7
- OPT_LOCAL_INFILE = 8
-
- # Server Status
- SERVER_STATUS_IN_TRANS = 1
- SERVER_STATUS_AUTOCOMMIT = 2
-
- # Refresh parameter
- REFRESH_GRANT = 1
- REFRESH_LOG = 2
- REFRESH_TABLES = 4
- REFRESH_HOSTS = 8
- REFRESH_STATUS = 16
- REFRESH_THREADS = 32
- REFRESH_SLAVE = 64
- REFRESH_MASTER = 128
-
- def initialize(*args)
- @client_flag = 0
- @max_allowed_packet = MAX_ALLOWED_PACKET
- @query_with_result = true
- @status = :STATUS_READY
- if args[0] != :INIT then
- real_connect(*args)
- end
- end
-
- def real_connect(host=nil, user=nil, passwd=nil, db=nil, port=nil, socket=nil, flag=nil)
- @server_status = SERVER_STATUS_AUTOCOMMIT
- if (host == nil or host == "localhost") and defined? UNIXSocket then
- unix_socket = socket || ENV["MYSQL_UNIX_PORT"] || MYSQL_UNIX_ADDR
- sock = UNIXSocket::new(unix_socket)
- @host_info = Error::err(Error::CR_LOCALHOST_CONNECTION)
- @unix_socket = unix_socket
- else
- sock = TCPSocket::new(host, port||ENV["MYSQL_TCP_PORT"]||(Socket::getservbyname("mysql","tcp") rescue MYSQL_PORT))
- @host_info = sprintf Error::err(Error::CR_TCP_CONNECTION), host
- end
- @host = host ? host.dup : nil
- sock.setsockopt Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true
- @net = Net::new sock
-
- a = read
- @protocol_version = a.slice!(0)
- @server_version, a = a.split(/\0/,2)
- @thread_id, @scramble_buff = a.slice!(0,13).unpack("La8")
- if a.size >= 2 then
- @server_capabilities, = a.slice!(0,2).unpack("v")
- end
- if a.size >= 16 then
- @server_language, @server_status = a.slice!(0,3).unpack("cv")
- end
-
- flag = 0 if flag == nil
- flag |= @client_flag | CLIENT_CAPABILITIES
- flag |= CLIENT_CONNECT_WITH_DB if db
-
- @pre_411 = (0 == @server_capabilities & PROTO_AUTH41)
- if @pre_411
- data = Net::int2str(flag)+Net::int3str(@max_allowed_packet)+
- (user||"")+"\0"+
- scramble(passwd, @scramble_buff, @protocol_version==9)
- else
- dummy, @salt2 = a.unpack("a13a12")
- @scramble_buff += @salt2
- flag |= PROTO_AUTH41
- data = Net::int4str(flag) + Net::int4str(@max_allowed_packet) +
- ([8] + Array.new(23, 0)).pack("c24") + (user||"")+"\0"+
- scramble41(passwd, @scramble_buff)
- end
-
- if db and @server_capabilities & CLIENT_CONNECT_WITH_DB != 0
- data << "\0" if @pre_411
- data << db
- @db = db.dup
- end
- write data
- pkt = read
- handle_auth_fallback(pkt, passwd)
- ObjectSpace.define_finalizer(self, Mysql.finalizer(@net))
- self
- end
- alias :connect :real_connect
-
- def handle_auth_fallback(pkt, passwd)
- # A packet like this means that we need to send an old-format password
- if pkt.size == 1 and pkt[0] == 254 and
- @server_capabilities & CLIENT_SECURE_CONNECTION != 0 then
- data = scramble(passwd, @scramble_buff, @protocol_version == 9)
- write data + "\0"
- read
- end
- end
-
- def escape_string(str)
- Mysql::escape_string str
- end
- alias :quote :escape_string
-
- def get_client_info()
- VERSION
- end
- alias :client_info :get_client_info
-
- def options(option, arg=nil)
- if option == OPT_LOCAL_INFILE then
- if arg == false or arg == 0 then
- @client_flag &= ~CLIENT_LOCAL_FILES
- else
- @client_flag |= CLIENT_LOCAL_FILES
- end
- else
- raise "not implemented"
- end
- end
-
- def real_query(query)
- command COM_QUERY, query, true
- read_query_result
- self
- end
-
- def use_result()
- if @status != :STATUS_GET_RESULT then
- error Error::CR_COMMANDS_OUT_OF_SYNC
- end
- res = Result::new self, @fields, @field_count
- @status = :STATUS_USE_RESULT
- res
- end
-
- def store_result()
- if @status != :STATUS_GET_RESULT then
- error Error::CR_COMMANDS_OUT_OF_SYNC
- end
- @status = :STATUS_READY
- data = read_rows @field_count
- res = Result::new self, @fields, @field_count, data
- @fields = nil
- @affected_rows = data.length
- res
- end
-
- def change_user(user="", passwd="", db="")
- if @pre_411
- data = user+"\0"+scramble(passwd, @scramble_buff, @protocol_version==9)+"\0"+db
- else
- data = user+"\0"+scramble41(passwd, @scramble_buff)+db
- end
- pkt = command COM_CHANGE_USER, data
- handle_auth_fallback(pkt, passwd)
- @user = user
- @passwd = passwd
- @db = db
- end
-
- def character_set_name()
- raise "not implemented"
- end
-
- def close()
- @status = :STATUS_READY
- command COM_QUIT, nil, true
- @net.close
- self
- end
-
- def create_db(db)
- command COM_CREATE_DB, db
- self
- end
-
- def drop_db(db)
- command COM_DROP_DB, db
- self
- end
-
- def dump_debug_info()
- command COM_DEBUG
- self
- end
-
- def get_host_info()
- @host_info
- end
- alias :host_info :get_host_info
-
- def get_proto_info()
- @protocol_version
- end
- alias :proto_info :get_proto_info
-
- def get_server_info()
- @server_version
- end
- alias :server_info :get_server_info
-
- def kill(id)
- command COM_PROCESS_KILL, Net::int4str(id)
- self
- end
-
- def list_dbs(db=nil)
- real_query "show databases #{db}"
- @status = :STATUS_READY
- read_rows(1).flatten
- end
-
- def list_fields(table, field=nil)
- command COM_FIELD_LIST, "#{table}\0#{field}", true
- if @pre_411
- f = read_rows 6
- else
- f = read_rows 7
- end
- fields = unpack_fields(f, @server_capabilities & CLIENT_LONG_FLAG != 0)
- res = Result::new self, fields, f.length
- res.eof = true
- res
- end
-
- def list_processes()
- data = command COM_PROCESS_INFO
- @field_count = get_length data
- if @pre_411
- fields = read_rows 5
- else
- fields = read_rows 7
- end
- @fields = unpack_fields(fields, @server_capabilities & CLIENT_LONG_FLAG != 0)
- @status = :STATUS_GET_RESULT
- store_result
- end
-
- def list_tables(table=nil)
- real_query "show tables #{table}"
- @status = :STATUS_READY
- read_rows(1).flatten
- end
-
- def ping()
- command COM_PING
- self
- end
-
- def query(query)
- real_query query
- if not @query_with_result then
- return self
- end
- if @field_count == 0 then
- return nil
- end
- store_result
- end
-
- def refresh(r)
- command COM_REFRESH, r.chr
- self
- end
-
- def reload()
- refresh REFRESH_GRANT
- self
- end
-
- def select_db(db)
- command COM_INIT_DB, db
- @db = db
- self
- end
-
- def shutdown()
- command COM_SHUTDOWN
- self
- end
-
- def stat()
- command COM_STATISTICS
- end
-
- attr_reader :info, :insert_id, :affected_rows, :field_count, :thread_id
- attr_accessor :query_with_result, :status
-
- def read_one_row(field_count)
- data = read
- if data[0] == 254 and data.length == 1 ## EOF
- return
- elsif data[0] == 254 and data.length == 5
- return
- end
- rec = []
- field_count.times do
- len = get_length data
- if len == nil then
- rec << len
- else
- rec << data.slice!(0,len)
- end
- end
- rec
- end
-
- def skip_result()
- if @status == :STATUS_USE_RESULT then
- loop do
- data = read
- break if data[0] == 254 and data.length == 1
- end
- @status = :STATUS_READY
- end
- end
-
- def inspect()
- "#<#{self.class}>"
- end
-
- private
-
- def read_query_result()
- data = read
- @field_count = get_length(data)
- if @field_count == nil then # LOAD DATA LOCAL INFILE
- File::open(data) do |f|
- write f.read
- end
- write "" # mark EOF
- data = read
- @field_count = get_length(data)
- end
- if @field_count == 0 then
- @affected_rows = get_length(data, true)
- @insert_id = get_length(data, true)
- if @server_capabilities & CLIENT_TRANSACTIONS != 0 then
- a = data.slice!(0,2)
- @server_status = a[0]+a[1]*256
- end
- if data.size > 0 and get_length(data) then
- @info = data
- end
- else
- @extra_info = get_length(data, true)
- if @pre_411
- fields = read_rows(5)
- else
- fields = read_rows(7)
- end
- @fields = unpack_fields(fields, @server_capabilities & CLIENT_LONG_FLAG != 0)
- @status = :STATUS_GET_RESULT
- end
- self
- end
-
- def unpack_fields(data, long_flag_protocol)
- ret = []
- data.each do |f|
- if @pre_411
- table = org_table = f[0]
- name = f[1]
- length = f[2][0]+f[2][1]*256+f[2][2]*256*256
- type = f[3][0]
- if long_flag_protocol then
- flags = f[4][0]+f[4][1]*256
- decimals = f[4][2]
- else
- flags = f[4][0]
- decimals = f[4][1]
- end
- def_value = f[5]
- max_length = 0
- else
- catalog = f[0]
- db = f[1]
- table = f[2]
- org_table = f[3]
- name = f[4]
- org_name = f[5]
- length = f[6][2]+f[6][3]*256+f[6][4]*256*256
- type = f[6][6]
- flags = f[6][7]+f[6][8]*256
- decimals = f[6][9]
- def_value = ""
- max_length = 0
- end
- ret << Field::new(table, org_table, name, length, type, flags, decimals, def_value, max_length)
- end
- ret
- end
-
- def read_rows(field_count)
- ret = []
- while rec = read_one_row(field_count) do
- ret << rec
- end
- ret
- end
-
- def get_length(data, longlong=nil)
- return if data.length == 0
- c = data.slice!(0)
- case c
- when 251
- return nil
- when 252
- a = data.slice!(0,2)
- return a[0]+a[1]*256
- when 253
- a = data.slice!(0,3)
- return a[0]+a[1]*256+a[2]*256**2
- when 254
- a = data.slice!(0,8)
- if longlong then
- return a[0]+a[1]*256+a[2]*256**2+a[3]*256**3+
- a[4]*256**4+a[5]*256**5+a[6]*256**6+a[7]*256**7
- else
- return a[0]+a[1]*256+a[2]*256**2+a[3]*256**3
- end
- else
- c
- end
- end
-
- def command(cmd, arg=nil, skip_check=nil)
- unless @net then
- error Error::CR_SERVER_GONE_ERROR
- end
- if @status != :STATUS_READY then
- error Error::CR_COMMANDS_OUT_OF_SYNC
- end
- @net.clear
- write cmd.chr+(arg||"")
- read unless skip_check
- end
-
- def read()
- unless @net then
- error Error::CR_SERVER_GONE_ERROR
- end
- a = @net.read
- if a[0] == 255 then
- if a.length > 3 then
- @errno = a[1]+a[2]*256
- @error = a[3 .. -1]
- else
- @errno = Error::CR_UNKNOWN_ERROR
- @error = Error::err @errno
- end
- raise Error::new(@errno, @error)
- end
- a
- end
-
- def write(arg)
- unless @net then
- error Error::CR_SERVER_GONE_ERROR
- end
- @net.write arg
- end
-
- def hash_password(password)
- nr = 1345345333
- add = 7
- nr2 = 0x12345671
- password.each_byte do |i|
- next if i == 0x20 or i == 9
- nr ^= (((nr & 63) + add) * i) + (nr << 8)
- nr2 += (nr2 << 8) ^ nr
- add += i
- end
- [nr & ((1 << 31) - 1), nr2 & ((1 << 31) - 1)]
- end
-
- def scramble(password, message, old_ver)
- return "" if password == nil or password == ""
- raise "old version password is not implemented" if old_ver
- hash_pass = hash_password password
- hash_message = hash_password message.slice(0,SCRAMBLE_LENGTH_323)
- rnd = Random::new hash_pass[0] ^ hash_message[0], hash_pass[1] ^ hash_message[1]
- to = []
- 1.upto(SCRAMBLE_LENGTH_323) do
- to << ((rnd.rnd*31)+64).floor
- end
- extra = (rnd.rnd*31).floor
- to.map! do |t| (t ^ extra).chr end
- to.join
- end
-
- def scramble41(password, message)
- return 0x00.chr if password.nil? or password.empty?
- buf = [0x14]
- s1 = Digest::SHA1.digest(password)
- s2 = Digest::SHA1.digest(s1)
- x = Digest::SHA1.digest(message + s2)
- (0..s1.length - 1).each {|i| buf.push(s1[i] ^ x[i])}
- buf.pack("C*")
- end
-
- def error(errno)
- @errno = errno
- @error = Error::err errno
- raise Error::new(@errno, @error)
- end
-
- class Result
- def initialize(mysql, fields, field_count, data=nil)
- @handle = mysql
- @fields = fields
- @field_count = field_count
- @data = data
- @current_field = 0
- @current_row = 0
- @eof = false
- @row_count = 0
- end
- attr_accessor :eof
-
- def data_seek(n)
- @current_row = n
- end
-
- def fetch_field()
- return if @current_field >= @field_count
- f = @fields[@current_field]
- @current_field += 1
- f
- end
-
- def fetch_fields()
- @fields
- end
-
- def fetch_field_direct(n)
- @fields[n]
- end
-
- def fetch_lengths()
- @data ? @data[@current_row].map{|i| i ? i.length : 0} : @lengths
- end
-
- def fetch_row()
- if @data then
- if @current_row >= @data.length then
- @handle.status = :STATUS_READY
- return
- end
- ret = @data[@current_row]
- @current_row += 1
- else
- return if @eof
- ret = @handle.read_one_row @field_count
- if ret == nil then
- @eof = true
- return
- end
- @lengths = ret.map{|i| i ? i.length : 0}
- @row_count += 1
- end
- ret
- end
-
- def fetch_hash(with_table=nil)
- row = fetch_row
- return if row == nil
- hash = {}
- @fields.each_index do |i|
- f = with_table ? @fields[i].table+"."+@fields[i].name : @fields[i].name
- hash[f] = row[i]
- end
- hash
- end
-
- def field_seek(n)
- @current_field = n
- end
-
- def field_tell()
- @current_field
- end
-
- def free()
- @handle.skip_result
- @handle = @fields = @data = nil
- end
-
- def num_fields()
- @field_count
- end
-
- def num_rows()
- @data ? @data.length : @row_count
- end
-
- def row_seek(n)
- @current_row = n
- end
-
- def row_tell()
- @current_row
- end
-
- def each()
- while row = fetch_row do
- yield row
- end
- end
-
- def each_hash(with_table=nil)
- while hash = fetch_hash(with_table) do
- yield hash
- end
- end
-
- def inspect()
- "#<#{self.class}>"
- end
-
- end
-
- class Field
- # Field type
- TYPE_DECIMAL = 0
- TYPE_TINY = 1
- TYPE_SHORT = 2
- TYPE_LONG = 3
- TYPE_FLOAT = 4
- TYPE_DOUBLE = 5
- TYPE_NULL = 6
- TYPE_TIMESTAMP = 7
- TYPE_LONGLONG = 8
- TYPE_INT24 = 9
- TYPE_DATE = 10
- TYPE_TIME = 11
- TYPE_DATETIME = 12
- TYPE_YEAR = 13
- TYPE_NEWDATE = 14
- TYPE_ENUM = 247
- TYPE_SET = 248
- TYPE_TINY_BLOB = 249
- TYPE_MEDIUM_BLOB = 250
- TYPE_LONG_BLOB = 251
- TYPE_BLOB = 252
- TYPE_VAR_STRING = 253
- TYPE_STRING = 254
- TYPE_GEOMETRY = 255
- TYPE_CHAR = TYPE_TINY
- TYPE_INTERVAL = TYPE_ENUM
-
- # Flag
- NOT_NULL_FLAG = 1
- PRI_KEY_FLAG = 2
- UNIQUE_KEY_FLAG = 4
- MULTIPLE_KEY_FLAG = 8
- BLOB_FLAG = 16
- UNSIGNED_FLAG = 32
- ZEROFILL_FLAG = 64
- BINARY_FLAG = 128
- ENUM_FLAG = 256
- AUTO_INCREMENT_FLAG = 512
- TIMESTAMP_FLAG = 1024
- SET_FLAG = 2048
- NUM_FLAG = 32768
- PART_KEY_FLAG = 16384
- GROUP_FLAG = 32768
- UNIQUE_FLAG = 65536
-
- def initialize(table, org_table, name, length, type, flags, decimals, def_value, max_length)
- @table = table
- @org_table = org_table
- @name = name
- @length = length
- @type = type
- @flags = flags
- @decimals = decimals
- @def = def_value
- @max_length = max_length
- if (type <= TYPE_INT24 and (type != TYPE_TIMESTAMP or length == 14 or length == 8)) or type == TYPE_YEAR then
- @flags |= NUM_FLAG
- end
- end
- attr_reader :table, :org_table, :name, :length, :type, :flags, :decimals, :def, :max_length
-
- def inspect()
- "#<#{self.class}:#{@name}>"
- end
- end
-
- class Error < StandardError
- # Server Error
- ER_HASHCHK = 1000
- ER_NISAMCHK = 1001
- ER_NO = 1002
- ER_YES = 1003
- ER_CANT_CREATE_FILE = 1004
- ER_CANT_CREATE_TABLE = 1005
- ER_CANT_CREATE_DB = 1006
- ER_DB_CREATE_EXISTS = 1007
- ER_DB_DROP_EXISTS = 1008
- ER_DB_DROP_DELETE = 1009
- ER_DB_DROP_RMDIR = 1010
- ER_CANT_DELETE_FILE = 1011
- ER_CANT_FIND_SYSTEM_REC = 1012
- ER_CANT_GET_STAT = 1013
- ER_CANT_GET_WD = 1014
- ER_CANT_LOCK = 1015
- ER_CANT_OPEN_FILE = 1016
- ER_FILE_NOT_FOUND = 1017
- ER_CANT_READ_DIR = 1018
- ER_CANT_SET_WD = 1019
- ER_CHECKREAD = 1020
- ER_DISK_FULL = 1021
- ER_DUP_KEY = 1022
- ER_ERROR_ON_CLOSE = 1023
- ER_ERROR_ON_READ = 1024
- ER_ERROR_ON_RENAME = 1025
- ER_ERROR_ON_WRITE = 1026
- ER_FILE_USED = 1027
- ER_FILSORT_ABORT = 1028
- ER_FORM_NOT_FOUND = 1029
- ER_GET_ERRNO = 1030
- ER_ILLEGAL_HA = 1031
- ER_KEY_NOT_FOUND = 1032
- ER_NOT_FORM_FILE = 1033
- ER_NOT_KEYFILE = 1034
- ER_OLD_KEYFILE = 1035
- ER_OPEN_AS_READONLY = 1036
- ER_OUTOFMEMORY = 1037
- ER_OUT_OF_SORTMEMORY = 1038
- ER_UNEXPECTED_EOF = 1039
- ER_CON_COUNT_ERROR = 1040
- ER_OUT_OF_RESOURCES = 1041
- ER_BAD_HOST_ERROR = 1042
- ER_HANDSHAKE_ERROR = 1043
- ER_DBACCESS_DENIED_ERROR = 1044
- ER_ACCESS_DENIED_ERROR = 1045
- ER_NO_DB_ERROR = 1046
- ER_UNKNOWN_COM_ERROR = 1047
- ER_BAD_NULL_ERROR = 1048
- ER_BAD_DB_ERROR = 1049
- ER_TABLE_EXISTS_ERROR = 1050
- ER_BAD_TABLE_ERROR = 1051
- ER_NON_UNIQ_ERROR = 1052
- ER_SERVER_SHUTDOWN = 1053
- ER_BAD_FIELD_ERROR = 1054
- ER_WRONG_FIELD_WITH_GROUP = 1055
- ER_WRONG_GROUP_FIELD = 1056
- ER_WRONG_SUM_SELECT = 1057
- ER_WRONG_VALUE_COUNT = 1058
- ER_TOO_LONG_IDENT = 1059
- ER_DUP_FIELDNAME = 1060
- ER_DUP_KEYNAME = 1061
- ER_DUP_ENTRY = 1062
- ER_WRONG_FIELD_SPEC = 1063
- ER_PARSE_ERROR = 1064
- ER_EMPTY_QUERY = 1065
- ER_NONUNIQ_TABLE = 1066
- ER_INVALID_DEFAULT = 1067
- ER_MULTIPLE_PRI_KEY = 1068
- ER_TOO_MANY_KEYS = 1069
- ER_TOO_MANY_KEY_PARTS = 1070
- ER_TOO_LONG_KEY = 1071
- ER_KEY_COLUMN_DOES_NOT_EXITS = 1072
- ER_BLOB_USED_AS_KEY = 1073
- ER_TOO_BIG_FIELDLENGTH = 1074
- ER_WRONG_AUTO_KEY = 1075
- ER_READY = 1076
- ER_NORMAL_SHUTDOWN = 1077
- ER_GOT_SIGNAL = 1078
- ER_SHUTDOWN_COMPLETE = 1079
- ER_FORCING_CLOSE = 1080
- ER_IPSOCK_ERROR = 1081
- ER_NO_SUCH_INDEX = 1082
- ER_WRONG_FIELD_TERMINATORS = 1083
- ER_BLOBS_AND_NO_TERMINATED = 1084
- ER_TEXTFILE_NOT_READABLE = 1085
- ER_FILE_EXISTS_ERROR = 1086
- ER_LOAD_INFO = 1087
- ER_ALTER_INFO = 1088
- ER_WRONG_SUB_KEY = 1089
- ER_CANT_REMOVE_ALL_FIELDS = 1090
- ER_CANT_DROP_FIELD_OR_KEY = 1091
- ER_INSERT_INFO = 1092
- ER_INSERT_TABLE_USED = 1093
- ER_NO_SUCH_THREAD = 1094
- ER_KILL_DENIED_ERROR = 1095
- ER_NO_TABLES_USED = 1096
- ER_TOO_BIG_SET = 1097
- ER_NO_UNIQUE_LOGFILE = 1098
- ER_TABLE_NOT_LOCKED_FOR_WRITE = 1099
- ER_TABLE_NOT_LOCKED = 1100
- ER_BLOB_CANT_HAVE_DEFAULT = 1101
- ER_WRONG_DB_NAME = 1102
- ER_WRONG_TABLE_NAME = 1103
- ER_TOO_BIG_SELECT = 1104
- ER_UNKNOWN_ERROR = 1105
- ER_UNKNOWN_PROCEDURE = 1106
- ER_WRONG_PARAMCOUNT_TO_PROCEDURE = 1107
- ER_WRONG_PARAMETERS_TO_PROCEDURE = 1108
- ER_UNKNOWN_TABLE = 1109
- ER_FIELD_SPECIFIED_TWICE = 1110
- ER_INVALID_GROUP_FUNC_USE = 1111
- ER_UNSUPPORTED_EXTENSION = 1112
- ER_TABLE_MUST_HAVE_COLUMNS = 1113
- ER_RECORD_FILE_FULL = 1114
- ER_UNKNOWN_CHARACTER_SET = 1115
- ER_TOO_MANY_TABLES = 1116
- ER_TOO_MANY_FIELDS = 1117
- ER_TOO_BIG_ROWSIZE = 1118
- ER_STACK_OVERRUN = 1119
- ER_WRONG_OUTER_JOIN = 1120
- ER_NULL_COLUMN_IN_INDEX = 1121
- ER_CANT_FIND_UDF = 1122
- ER_CANT_INITIALIZE_UDF = 1123
- ER_UDF_NO_PATHS = 1124
- ER_UDF_EXISTS = 1125
- ER_CANT_OPEN_LIBRARY = 1126
- ER_CANT_FIND_DL_ENTRY = 1127
- ER_FUNCTION_NOT_DEFINED = 1128
- ER_HOST_IS_BLOCKED = 1129
- ER_HOST_NOT_PRIVILEGED = 1130
- ER_PASSWORD_ANONYMOUS_USER = 1131
- ER_PASSWORD_NOT_ALLOWED = 1132
- ER_PASSWORD_NO_MATCH = 1133
- ER_UPDATE_INFO = 1134
- ER_CANT_CREATE_THREAD = 1135
- ER_WRONG_VALUE_COUNT_ON_ROW = 1136
- ER_CANT_REOPEN_TABLE = 1137
- ER_INVALID_USE_OF_NULL = 1138
- ER_REGEXP_ERROR = 1139
- ER_MIX_OF_GROUP_FUNC_AND_FIELDS = 1140
- ER_NONEXISTING_GRANT = 1141
- ER_TABLEACCESS_DENIED_ERROR = 1142
- ER_COLUMNACCESS_DENIED_ERROR = 1143
- ER_ILLEGAL_GRANT_FOR_TABLE = 1144
- ER_GRANT_WRONG_HOST_OR_USER = 1145
- ER_NO_SUCH_TABLE = 1146
- ER_NONEXISTING_TABLE_GRANT = 1147
- ER_NOT_ALLOWED_COMMAND = 1148
- ER_SYNTAX_ERROR = 1149
- ER_DELAYED_CANT_CHANGE_LOCK = 1150
- ER_TOO_MANY_DELAYED_THREADS = 1151
- ER_ABORTING_CONNECTION = 1152
- ER_NET_PACKET_TOO_LARGE = 1153
- ER_NET_READ_ERROR_FROM_PIPE = 1154
- ER_NET_FCNTL_ERROR = 1155
- ER_NET_PACKETS_OUT_OF_ORDER = 1156
- ER_NET_UNCOMPRESS_ERROR = 1157
- ER_NET_READ_ERROR = 1158
- ER_NET_READ_INTERRUPTED = 1159
- ER_NET_ERROR_ON_WRITE = 1160
- ER_NET_WRITE_INTERRUPTED = 1161
- ER_TOO_LONG_STRING = 1162
- ER_TABLE_CANT_HANDLE_BLOB = 1163
- ER_TABLE_CANT_HANDLE_AUTO_INCREMENT = 1164
- ER_DELAYED_INSERT_TABLE_LOCKED = 1165
- ER_WRONG_COLUMN_NAME = 1166
- ER_WRONG_KEY_COLUMN = 1167
- ER_WRONG_MRG_TABLE = 1168
- ER_DUP_UNIQUE = 1169
- ER_BLOB_KEY_WITHOUT_LENGTH = 1170
- ER_PRIMARY_CANT_HAVE_NULL = 1171
- ER_TOO_MANY_ROWS = 1172
- ER_REQUIRES_PRIMARY_KEY = 1173
- ER_NO_RAID_COMPILED = 1174
- ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE = 1175
- ER_KEY_DOES_NOT_EXITS = 1176
- ER_CHECK_NO_SUCH_TABLE = 1177
- ER_CHECK_NOT_IMPLEMENTED = 1178
- ER_CANT_DO_THIS_DURING_AN_TRANSACTION = 1179
- ER_ERROR_DURING_COMMIT = 1180
- ER_ERROR_DURING_ROLLBACK = 1181
- ER_ERROR_DURING_FLUSH_LOGS = 1182
- ER_ERROR_DURING_CHECKPOINT = 1183
- ER_NEW_ABORTING_CONNECTION = 1184
- ER_DUMP_NOT_IMPLEMENTED = 1185
- ER_FLUSH_MASTER_BINLOG_CLOSED = 1186
- ER_INDEX_REBUILD = 1187
- ER_MASTER = 1188
- ER_MASTER_NET_READ = 1189
- ER_MASTER_NET_WRITE = 1190
- ER_FT_MATCHING_KEY_NOT_FOUND = 1191
- ER_LOCK_OR_ACTIVE_TRANSACTION = 1192
- ER_UNKNOWN_SYSTEM_VARIABLE = 1193
- ER_CRASHED_ON_USAGE = 1194
- ER_CRASHED_ON_REPAIR = 1195
- ER_WARNING_NOT_COMPLETE_ROLLBACK = 1196
- ER_TRANS_CACHE_FULL = 1197
- ER_SLAVE_MUST_STOP = 1198
- ER_SLAVE_NOT_RUNNING = 1199
- ER_BAD_SLAVE = 1200
- ER_MASTER_INFO = 1201
- ER_SLAVE_THREAD = 1202
- ER_TOO_MANY_USER_CONNECTIONS = 1203
- ER_SET_CONSTANTS_ONLY = 1204
- ER_LOCK_WAIT_TIMEOUT = 1205
- ER_LOCK_TABLE_FULL = 1206
- ER_READ_ONLY_TRANSACTION = 1207
- ER_DROP_DB_WITH_READ_LOCK = 1208
- ER_CREATE_DB_WITH_READ_LOCK = 1209
- ER_WRONG_ARGUMENTS = 1210
- ER_NO_PERMISSION_TO_CREATE_USER = 1211
- ER_UNION_TABLES_IN_DIFFERENT_DIR = 1212
- ER_LOCK_DEADLOCK = 1213
- ER_TABLE_CANT_HANDLE_FULLTEXT = 1214
- ER_CANNOT_ADD_FOREIGN = 1215
- ER_NO_REFERENCED_ROW = 1216
- ER_ROW_IS_REFERENCED = 1217
- ER_CONNECT_TO_MASTER = 1218
- ER_QUERY_ON_MASTER = 1219
- ER_ERROR_WHEN_EXECUTING_COMMAND = 1220
- ER_WRONG_USAGE = 1221
- ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT = 1222
- ER_CANT_UPDATE_WITH_READLOCK = 1223
- ER_MIXING_NOT_ALLOWED = 1224
- ER_DUP_ARGUMENT = 1225
- ER_USER_LIMIT_REACHED = 1226
- ER_SPECIFIC_ACCESS_DENIED_ERROR = 1227
- ER_LOCAL_VARIABLE = 1228
- ER_GLOBAL_VARIABLE = 1229
- ER_NO_DEFAULT = 1230
- ER_WRONG_VALUE_FOR_VAR = 1231
- ER_WRONG_TYPE_FOR_VAR = 1232
- ER_VAR_CANT_BE_READ = 1233
- ER_CANT_USE_OPTION_HERE = 1234
- ER_NOT_SUPPORTED_YET = 1235
- ER_MASTER_FATAL_ERROR_READING_BINLOG = 1236
- ER_SLAVE_IGNORED_TABLE = 1237
- ER_ERROR_MESSAGES = 238
-
- # Client Error
- CR_MIN_ERROR = 2000
- CR_MAX_ERROR = 2999
- CR_UNKNOWN_ERROR = 2000
- CR_SOCKET_CREATE_ERROR = 2001
- CR_CONNECTION_ERROR = 2002
- CR_CONN_HOST_ERROR = 2003
- CR_IPSOCK_ERROR = 2004
- CR_UNKNOWN_HOST = 2005
- CR_SERVER_GONE_ERROR = 2006
- CR_VERSION_ERROR = 2007
- CR_OUT_OF_MEMORY = 2008
- CR_WRONG_HOST_INFO = 2009
- CR_LOCALHOST_CONNECTION = 2010
- CR_TCP_CONNECTION = 2011
- CR_SERVER_HANDSHAKE_ERR = 2012
- CR_SERVER_LOST = 2013
- CR_COMMANDS_OUT_OF_SYNC = 2014
- CR_NAMEDPIPE_CONNECTION = 2015
- CR_NAMEDPIPEWAIT_ERROR = 2016
- CR_NAMEDPIPEOPEN_ERROR = 2017
- CR_NAMEDPIPESETSTATE_ERROR = 2018
- CR_CANT_READ_CHARSET = 2019
- CR_NET_PACKET_TOO_LARGE = 2020
- CR_EMBEDDED_CONNECTION = 2021
- CR_PROBE_SLAVE_STATUS = 2022
- CR_PROBE_SLAVE_HOSTS = 2023
- CR_PROBE_SLAVE_CONNECT = 2024
- CR_PROBE_MASTER_CONNECT = 2025
- CR_SSL_CONNECTION_ERROR = 2026
- CR_MALFORMED_PACKET = 2027
-
- CLIENT_ERRORS = [
- "Unknown MySQL error",
- "Can't create UNIX socket (%d)",
- "Can't connect to local MySQL server through socket '%-.64s' (%d)",
- "Can't connect to MySQL server on '%-.64s' (%d)",
- "Can't create TCP/IP socket (%d)",
- "Unknown MySQL Server Host '%-.64s' (%d)",
- "MySQL server has gone away",
- "Protocol mismatch. Server Version = %d Client Version = %d",
- "MySQL client run out of memory",
- "Wrong host info",
- "Localhost via UNIX socket",
- "%-.64s via TCP/IP",
- "Error in server handshake",
- "Lost connection to MySQL server during query",
- "Commands out of sync; You can't run this command now",
- "%-.64s via named pipe",
- "Can't wait for named pipe to host: %-.64s pipe: %-.32s (%lu)",
- "Can't open named pipe to host: %-.64s pipe: %-.32s (%lu)",
- "Can't set state of named pipe to host: %-.64s pipe: %-.32s (%lu)",
- "Can't initialize character set %-.64s (path: %-.64s)",
- "Got packet bigger than 'max_allowed_packet'",
- "Embedded server",
- "Error on SHOW SLAVE STATUS:",
- "Error on SHOW SLAVE HOSTS:",
- "Error connecting to slave:",
- "Error connecting to master:",
- "SSL connection error",
- "Malformed packet"
- ]
-
- def initialize(errno, error)
- @errno = errno
- @error = error
- super error
- end
- attr_reader :errno, :error
-
- def Error::err(errno)
- CLIENT_ERRORS[errno - Error::CR_MIN_ERROR]
- end
- end
-
- class Net
- def initialize(sock)
- @sock = sock
- @pkt_nr = 0
- end
-
- def clear()
- @pkt_nr = 0
- end
-
- def read()
- buf = []
- len = nil
- @sock.sync = false
- while len == nil or len == MAX_PACKET_LENGTH do
- a = @sock.read(4)
- len = a[0]+a[1]*256+a[2]*256*256
- pkt_nr = a[3]
- if @pkt_nr != pkt_nr then
- raise "Packets out of order: #{@pkt_nr}<>#{pkt_nr}"
- end
- @pkt_nr = @pkt_nr + 1 & 0xff
- buf << @sock.read(len)
- end
- @sock.sync = true
- buf.join
- rescue
- errno = Error::CR_SERVER_LOST
- raise Error::new(errno, Error::err(errno))
- end
-
- def write(data)
- if data.is_a? Array then
- data = data.join
- end
- @sock.sync = false
- ptr = 0
- while data.length >= MAX_PACKET_LENGTH do
- @sock.write Net::int3str(MAX_PACKET_LENGTH)+@pkt_nr.chr+data[ptr, MAX_PACKET_LENGTH]
- @pkt_nr = @pkt_nr + 1 & 0xff
- ptr += MAX_PACKET_LENGTH
- end
- @sock.write Net::int3str(data.length-ptr)+@pkt_nr.chr+data[ptr .. -1]
- @pkt_nr = @pkt_nr + 1 & 0xff
- @sock.sync = true
- @sock.flush
- rescue
- errno = Error::CR_SERVER_LOST
- raise Error::new(errno, Error::err(errno))
- end
-
- def close()
- @sock.close
- end
-
- def Net::int2str(n)
- [n].pack("v")
- end
-
- def Net::int3str(n)
- [n%256, n>>8].pack("cv")
- end
-
- def Net::int4str(n)
- [n].pack("V")
- end
-
- end
-
- class Random
- def initialize(seed1, seed2)
- @max_value = 0x3FFFFFFF
- @seed1 = seed1 % @max_value
- @seed2 = seed2 % @max_value
- end
-
- def rnd()
- @seed1 = (@seed1*3+@seed2) % @max_value
- @seed2 = (@seed1+@seed2+33) % @max_value
- @seed1.to_f / @max_value
- end
- end
-
-end
-
-class << Mysql
- def init()
- Mysql::new :INIT
- end
-
- def real_connect(*args)
- Mysql::new(*args)
- end
- alias :connect :real_connect
-
- def finalizer(net)
- proc {
- net.clear
- begin
- net.write(Mysql::COM_QUIT.chr)
- net.close
- rescue # Ignore IOError if socket is already closed.
- end
- }
- end
-
- def escape_string(str)
- str.gsub(/([\0\n\r\032\'\"\\])/) do
- case $1
- when "\0" then "\\0"
- when "\n" then "\\n"
- when "\r" then "\\r"
- when "\032" then "\\Z"
- else "\\"+$1
- end
- end
- end
- alias :quote :escape_string
-
- def get_client_info()
- Mysql::VERSION
- end
- alias :client_info :get_client_info
-
- def debug(str)
- raise "not implemented"
- end
-end
-
-#
-# for compatibility
-#
-
-MysqlRes = Mysql::Result
-MysqlField = Mysql::Field
-MysqlError = Mysql::Error
diff --git a/activerecord/test/cases/active_schema_test_postgresql.rb b/activerecord/test/cases/active_schema_test_postgresql.rb
index db325e3fb4..af80f724f2 100644
--- a/activerecord/test/cases/active_schema_test_postgresql.rb
+++ b/activerecord/test/cases/active_schema_test_postgresql.rb
@@ -13,8 +13,8 @@ class PostgresqlActiveSchemaTest < Test::Unit::TestCase
end
def test_create_database_with_encoding
- assert_equal "CREATE DATABASE matt ENCODING = 'utf8'", create_database(:matt)
- assert_equal "CREATE DATABASE aimonetti ENCODING = 'latin1'", create_database(:aimonetti, :encoding => :latin1)
+ assert_equal %(CREATE DATABASE "matt" ENCODING = 'utf8'), create_database(:matt)
+ assert_equal %(CREATE DATABASE "aimonetti" ENCODING = 'latin1'), create_database(:aimonetti, :encoding => :latin1)
end
private
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index e0da8bfb7a..9c718c4fef 100755
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -409,4 +409,23 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
sponsor.sponsorable = new_member
assert_equal nil, sponsor.sponsorable_id
end
+
+ def test_save_fails_for_invalid_belongs_to
+ assert log = AuditLog.create(:developer_id=>0,:message=>"")
+
+ log.developer = Developer.new
+ assert !log.developer.valid?
+ assert !log.valid?
+ assert !log.save
+ assert_equal "is invalid", log.errors.on("developer")
+ end
+
+ def test_save_succeeds_for_invalid_belongs_to_with_validate_false
+ assert log = AuditLog.create(:developer_id=>0,:message=>"")
+
+ log.unvalidated_developer = Developer.new
+ assert !log.unvalidated_developer.valid?
+ assert log.valid?
+ assert log.save
+ end
end
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index 3a3358e39b..f65ada550b 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -14,11 +14,14 @@ require 'models/job'
require 'models/subscriber'
require 'models/subscription'
require 'models/book'
+require 'models/developer'
+require 'models/project'
class EagerAssociationTest < ActiveRecord::TestCase
fixtures :posts, :comments, :authors, :categories, :categories_posts,
:companies, :accounts, :tags, :taggings, :people, :readers,
- :owners, :pets, :author_favorites, :jobs, :references, :subscribers, :subscriptions, :books
+ :owners, :pets, :author_favorites, :jobs, :references, :subscribers, :subscriptions, :books,
+ :developers, :projects
def test_loading_with_one_association
posts = Post.find(:all, :include => :comments)
@@ -609,4 +612,12 @@ class EagerAssociationTest < ActiveRecord::TestCase
Comment.find :all, :include => :post
end
end
+
+ def test_conditions_on_join_table_with_include_and_limit
+ assert_equal 3, Developer.find(:all, :include => 'projects', :conditions => 'developers_projects.access_level = 1', :limit => 5).size
+ end
+
+ def test_order_on_join_table_with_include_and_limit
+ assert_equal 5, Developer.find(:all, :include => 'projects', :order => 'developers_projects.joined_on DESC', :limit => 5).size
+ end
end
diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
index 294b993c55..b29df68d22 100644
--- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
@@ -681,4 +681,10 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert_equal developer, project.developers.find(:first)
assert_equal project, developer.projects.find(:first)
end
+
+ def test_dynamic_find_should_respect_association_include
+ # SQL error in sort clause if :include is not included
+ # due to Unknown column 'authors.id'
+ assert Category.find(1).posts_with_authors_sorted_by_author_id.find_by_title('Welcome to the weblog')
+ end
end
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index dbfa025efb..b638143c5a 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -37,15 +37,15 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_counting_with_single_conditions
- assert_equal 2, Firm.find(:first).plain_clients.count(:conditions => '1=1')
+ assert_equal 1, Firm.find(:first).plain_clients.count(:conditions => ['name=?', "Microsoft"])
end
def test_counting_with_single_hash
- assert_equal 2, Firm.find(:first).plain_clients.count(:conditions => '1=1')
+ assert_equal 1, Firm.find(:first).plain_clients.count(:conditions => {:name => "Microsoft"})
end
def test_counting_with_column_name_and_hash
- assert_equal 2, Firm.find(:first).plain_clients.count(:all, :conditions => '1=1')
+ assert_equal 2, Firm.find(:first).plain_clients.count(:name)
end
def test_finding
@@ -342,6 +342,17 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert new_firm.new_record?
end
+ def test_invalid_adding_with_validate_false
+ firm = Firm.find(:first)
+ client = Client.new
+ firm.unvalidated_clients_of_firm << Client.new
+
+ assert firm.valid?
+ assert !client.valid?
+ assert firm.save
+ assert client.new_record?
+ end
+
def test_build
company = companies(:first_firm)
new_client = assert_no_queries { company.clients_of_firm.build("name" => "Another Client") }
diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb
index 05155f6303..be5170f830 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -187,4 +187,10 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
post.people_with_callbacks.clear
assert_equal (%w(Michael David Julian Roger) * 2).sort, log.last(8).collect(&:last).sort
end
+
+ def test_dynamic_find_should_respect_association_include
+ # SQL error in sort clause if :include is not included
+ # due to Unknown column 'comments.id'
+ assert Person.find(1).posts_with_comments_sorted_by_comment_id.find_by_title('Welcome to the weblog')
+ end
end
diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb
index abc7ee7e9d..d3ca0cae41 100755
--- a/activerecord/test/cases/associations/has_one_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_associations_test.rb
@@ -275,6 +275,18 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
assert_equal "is invalid", firm.errors.on("account")
end
+
+ def test_save_succeeds_for_invalid_has_one_with_validate_false
+ firm = Firm.find(:first)
+ assert firm.valid?
+
+ firm.unvalidated_account = Account.new
+
+ assert !firm.unvalidated_account.valid?
+ assert firm.valid?
+ assert firm.save
+ end
+
def test_assignment_before_either_saved
firm = Firm.new("name" => "GlobalMegaCorp")
firm.account = a = Account.new("credit_limit" => 1000)
diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb
index c336fd9afb..7999e29264 100755
--- a/activerecord/test/cases/attribute_methods_test.rb
+++ b/activerecord/test/cases/attribute_methods_test.rb
@@ -137,7 +137,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
end
end
end
-
+
def test_time_attributes_are_retrieved_in_current_time_zone
in_time_zone "Pacific Time (US & Canada)" do
utc_time = Time.utc(2008, 1, 1)
@@ -145,7 +145,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
record[:written_on] = utc_time
assert_equal utc_time, record.written_on # record.written on is equal to (i.e., simultaneous with) utc_time
assert_kind_of ActiveSupport::TimeWithZone, record.written_on # but is a TimeWithZone
- assert_equal TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone # and is in the current Time.zone
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone # and is in the current Time.zone
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time # and represents time values adjusted accordingly
end
end
@@ -156,7 +156,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
record = @target.new
record.written_on = utc_time
assert_equal utc_time, record.written_on
- assert_equal TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
end
end
@@ -168,7 +168,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
record = @target.new
record.written_on = cst_time
assert_equal utc_time, record.written_on
- assert_equal TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
end
end
@@ -181,12 +181,12 @@ class AttributeMethodsTest < ActiveRecord::TestCase
record = @target.new
record.written_on = time_string
assert_equal Time.zone.parse(time_string), record.written_on
- assert_equal TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
end
end
end
-
+
def test_setting_time_zone_aware_attribute_to_blank_string_returns_nil
in_time_zone "Pacific Time (US & Canada)" do
record = @target.new
@@ -202,7 +202,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
record = @target.new
record.written_on = time_string
assert_equal Time.zone.parse(time_string), record.written_on
- assert_equal TimeZone[timezone_offset], record.written_on.time_zone
+ assert_equal ActiveSupport::TimeZone[timezone_offset], record.written_on.time_zone
assert_equal Time.utc(2008, 1, 1), record.written_on.time
end
end
@@ -214,7 +214,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
record = @target.new
record.written_on = utc_time.in_time_zone
assert_equal utc_time, record.written_on
- assert_equal TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
end
end
@@ -223,12 +223,12 @@ class AttributeMethodsTest < ActiveRecord::TestCase
def time_related_columns_on_topic
Topic.columns.select{|c| [:time, :date, :datetime, :timestamp].include?(c.type)}.map(&:name)
end
-
+
def in_time_zone(zone)
old_zone = Time.zone
old_tz = ActiveRecord::Base.time_zone_aware_attributes
- Time.zone = zone ? TimeZone[zone] : nil
+ Time.zone = zone ? ActiveSupport::TimeZone[zone] : nil
ActiveRecord::Base.time_zone_aware_attributes = !zone.nil?
yield
ensure
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index e07ec50c46..a4be629fbd 100755
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -133,19 +133,19 @@ class BasicsTest < ActiveRecord::TestCase
category_attrs = {"name"=>"Test categoty", "type" => nil}
assert_equal category_attrs , category.attributes_before_type_cast
end
-
+
if current_adapter?(:MysqlAdapter)
def test_read_attributes_before_type_cast_on_boolean
bool = Booleantest.create({ "value" => false })
assert_equal 0, bool.attributes_before_type_cast["value"]
end
end
-
+
def test_read_attributes_before_type_cast_on_datetime
developer = Developer.find(:first)
assert_equal developer.created_at.to_s(:db) , developer.attributes_before_type_cast["created_at"]
end
-
+
def test_hash_content
topic = Topic.new
topic.content = { "one" => 1, "two" => 2 }
@@ -251,7 +251,7 @@ class BasicsTest < ActiveRecord::TestCase
topic = Topic.create("title" => "New Topic")
topicReloaded = Topic.find(topic.id)
assert_equal(topic, topicReloaded)
- end
+ end
def test_create_through_factory_with_block
topic = Topic.create("title" => "New Topic") do |t|
@@ -576,7 +576,7 @@ class BasicsTest < ActiveRecord::TestCase
def test_destroy_all
original_count = Topic.count
topics_by_mary = Topic.count(:conditions => mary = "author_name = 'Mary'")
-
+
Topic.destroy_all mary
assert_equal original_count - topics_by_mary, Topic.count
end
@@ -665,7 +665,7 @@ class BasicsTest < ActiveRecord::TestCase
def test_delete_all
assert Topic.count > 0
-
+
assert_equal Topic.count, Topic.delete_all
end
@@ -970,7 +970,7 @@ class BasicsTest < ActiveRecord::TestCase
topic.attributes = attributes
assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
end
-
+
def test_multiparameter_attributes_on_time_with_old_date
attributes = {
"written_on(1i)" => "1850", "written_on(2i)" => "6", "written_on(3i)" => "24",
@@ -998,7 +998,7 @@ class BasicsTest < ActiveRecord::TestCase
def test_multiparameter_attributes_on_time_with_time_zone_aware_attributes
ActiveRecord::Base.time_zone_aware_attributes = true
ActiveRecord::Base.default_timezone = :utc
- Time.zone = TimeZone[-28800]
+ Time.zone = ActiveSupport::TimeZone[-28800]
attributes = {
"written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
"written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
@@ -1016,7 +1016,7 @@ class BasicsTest < ActiveRecord::TestCase
def test_multiparameter_attributes_on_time_with_time_zone_aware_attributes_false
ActiveRecord::Base.time_zone_aware_attributes = false
- Time.zone = TimeZone[-28800]
+ Time.zone = ActiveSupport::TimeZone[-28800]
attributes = {
"written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
"written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
@@ -1032,7 +1032,7 @@ class BasicsTest < ActiveRecord::TestCase
def test_multiparameter_attributes_on_time_with_skip_time_zone_conversion_for_attributes
ActiveRecord::Base.time_zone_aware_attributes = true
ActiveRecord::Base.default_timezone = :utc
- Time.zone = TimeZone[-28800]
+ Time.zone = ActiveSupport::TimeZone[-28800]
Topic.skip_time_zone_conversion_for_attributes = [:written_on]
attributes = {
"written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
@@ -1647,7 +1647,7 @@ class BasicsTest < ActiveRecord::TestCase
last = Developer.find :last
assert_equal last, Developer.find(:first, :order => 'id desc')
end
-
+
def test_last
assert_equal Developer.find(:first, :order => 'id desc'), Developer.last
end
@@ -1655,7 +1655,7 @@ class BasicsTest < ActiveRecord::TestCase
def test_all_with_conditions
assert_equal Developer.find(:all, :order => 'id desc'), Developer.all(:order => 'id desc')
end
-
+
def test_find_ordered_last
last = Developer.find :last, :order => 'developers.salary ASC'
assert_equal last, Developer.find(:all, :order => 'developers.salary ASC').last
@@ -1670,14 +1670,14 @@ class BasicsTest < ActiveRecord::TestCase
last = Developer.find :last, :order => 'developers.name, developers.salary DESC'
assert_equal last, Developer.find(:all, :order => 'developers.name, developers.salary DESC').last
end
-
+
def test_find_scoped_ordered_last
last_developer = Developer.with_scope(:find => { :order => 'developers.salary ASC' }) do
Developer.find(:last)
end
assert_equal last_developer, Developer.find(:all, :order => 'developers.salary ASC').last
end
-
+
def test_abstract_class
assert !ActiveRecord::Base.abstract_class?
assert LoosePerson.abstract_class?
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index a87fc26905..754fd58f35 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -1,6 +1,7 @@
require "cases/helper"
require 'models/company'
require 'models/topic'
+require 'models/edge'
Company.has_many :accounts
@@ -99,6 +100,12 @@ class CalculationsTest < ActiveRecord::TestCase
def test_should_return_zero_if_sum_conditions_return_nothing
assert_equal 0, Account.sum(:credit_limit, :conditions => '1 = 2')
+ assert_equal 0, companies(:rails_core).companies.sum(:id, :conditions => '1 = 2')
+ end
+
+ def test_sum_should_return_valid_values_for_decimals
+ NumericData.create(:bank_balance => 19.83)
+ assert_equal 19.83, NumericData.sum(:bank_balance)
end
def test_should_group_by_summed_field_with_conditions
@@ -266,6 +273,51 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_should_sum_expression
- assert_equal "636", Account.sum("2 * credit_limit")
+ assert_equal 636, Account.sum("2 * credit_limit")
+ end
+
+ def test_count_with_from_option
+ assert_equal Company.count(:all), Company.count(:all, :from => 'companies')
+ assert_equal Account.count(:all, :conditions => "credit_limit = 50"),
+ Account.count(:all, :from => 'accounts', :conditions => "credit_limit = 50")
+ assert_equal Company.count(:type, :conditions => {:type => "Firm"}),
+ Company.count(:type, :conditions => {:type => "Firm"}, :from => 'companies')
+ end
+
+ def test_sum_with_from_option
+ assert_equal Account.sum(:credit_limit), Account.sum(:credit_limit, :from => 'accounts')
+ assert_equal Account.sum(:credit_limit, :conditions => "credit_limit > 50"),
+ Account.sum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
+ end
+
+ def test_average_with_from_option
+ assert_equal Account.average(:credit_limit), Account.average(:credit_limit, :from => 'accounts')
+ assert_equal Account.average(:credit_limit, :conditions => "credit_limit > 50"),
+ Account.average(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
+ end
+
+ def test_minimum_with_from_option
+ assert_equal Account.minimum(:credit_limit), Account.minimum(:credit_limit, :from => 'accounts')
+ assert_equal Account.minimum(:credit_limit, :conditions => "credit_limit > 50"),
+ Account.minimum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
+ end
+
+ def test_maximum_with_from_option
+ assert_equal Account.maximum(:credit_limit), Account.maximum(:credit_limit, :from => 'accounts')
+ assert_equal Account.maximum(:credit_limit, :conditions => "credit_limit > 50"),
+ Account.maximum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
end
+
+ def test_from_option_with_specified_index
+ if Edge.connection.adapter_name == 'MySQL'
+ assert_equal Edge.count(:all), Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)')
+ assert_equal Edge.count(:all, :conditions => 'sink_id < 5'),
+ Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)', :conditions => 'sink_id < 5')
+ end
+ end
+
+ def test_from_option_with_table_different_than_class
+ assert_equal Account.count(:all), Company.count(:all, :from => 'accounts')
+ end
+
end
diff --git a/activerecord/test/cases/callbacks_observers_test.rb b/activerecord/test/cases/callbacks_observers_test.rb
new file mode 100644
index 0000000000..87de524923
--- /dev/null
+++ b/activerecord/test/cases/callbacks_observers_test.rb
@@ -0,0 +1,38 @@
+require "cases/helper"
+
+class Comment < ActiveRecord::Base
+ attr_accessor :callers
+
+ before_validation :record_callers
+
+ def after_validation
+ record_callers
+ end
+
+ def record_callers
+ callers << self.class if callers
+ end
+end
+
+class CommentObserver < ActiveRecord::Observer
+ attr_accessor :callers
+
+ def after_validation(model)
+ callers << self.class if callers
+ end
+end
+
+class CallbacksObserversTest < ActiveRecord::TestCase
+ def test_model_callbacks_fire_before_observers_are_notified
+ callers = []
+
+ comment = Comment.new
+ comment.callers = callers
+
+ CommentObserver.instance.callers = callers
+
+ comment.valid?
+
+ assert_equal [Comment, Comment, CommentObserver], callers, "model callbacks did not fire before observers were notified"
+ end
+end
diff --git a/activerecord/test/cases/database_statements_test.rb b/activerecord/test/cases/database_statements_test.rb
new file mode 100644
index 0000000000..6274d5250f
--- /dev/null
+++ b/activerecord/test/cases/database_statements_test.rb
@@ -0,0 +1,12 @@
+require "cases/helper"
+
+class DatabaseStatementsTest < ActiveRecord::TestCase
+ def setup
+ @connection = ActiveRecord::Base.connection
+ end
+
+ def test_insert_should_return_the_inserted_id
+ id = @connection.insert("INSERT INTO accounts (firm_id,credit_limit) VALUES (42,5000)")
+ assert_not_nil id
+ end
+end
diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb
index c011ffaf57..d70a787208 100644
--- a/activerecord/test/cases/dirty_test.rb
+++ b/activerecord/test/cases/dirty_test.rb
@@ -2,6 +2,7 @@ require 'cases/helper'
require 'models/topic' # For booleans
require 'models/pirate' # For timestamps
require 'models/parrot'
+require 'models/person' # For optimistic locking
class Pirate # Just reopening it, not defining it
attr_accessor :detected_changes_in_after_update # Boolean for if changes are detected
@@ -125,6 +126,24 @@ class DirtyTest < ActiveRecord::TestCase
end
end
+ def test_partial_update_with_optimistic_locking
+ person = Person.new(:first_name => 'foo')
+ old_lock_version = 1
+
+ with_partial_updates Person, false do
+ assert_queries(2) { 2.times { person.save! } }
+ Person.update_all({ :first_name => 'baz' }, :id => person.id)
+ end
+
+ with_partial_updates Person, true do
+ assert_queries(0) { 2.times { person.save! } }
+ assert_equal old_lock_version, person.reload.lock_version
+
+ assert_queries(1) { person.first_name = 'bar'; person.save! }
+ assert_not_equal old_lock_version, person.reload.lock_version
+ end
+ end
+
def test_changed_attributes_should_be_preserved_if_save_failure
pirate = Pirate.new
pirate.parrot_id = 1
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 80936d51f3..f48b62ba6b 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -1,5 +1,6 @@
require "cases/helper"
require 'models/author'
+require 'models/categorization'
require 'models/comment'
require 'models/company'
require 'models/topic'
@@ -394,6 +395,12 @@ class FinderTest < ActiveRecord::TestCase
assert_equal '1,1,1', bind('?', os)
end
+ def test_named_bind_with_postgresql_type_casts
+ l = Proc.new { bind(":a::integer '2009-01-01'::date", :a => '10') }
+ assert_nothing_raised(&l)
+ assert_equal "#{ActiveRecord::Base.quote_value('10')}::integer '2009-01-01'::date", l.call
+ end
+
def test_string_sanitation
assert_not_equal "#{ActiveRecord::Base.connection.quoted_string_prefix}'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1")
assert_equal "#{ActiveRecord::Base.connection.quoted_string_prefix}'something; select table'", ActiveRecord::Base.sanitize("something; select table")
diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb
index f09b617e6d..47fb5c608f 100755
--- a/activerecord/test/cases/inheritance_test.rb
+++ b/activerecord/test/cases/inheritance_test.rb
@@ -223,11 +223,11 @@ class InheritanceComputeTypeTest < ActiveRecord::TestCase
fixtures :companies
def setup
- Dependencies.log_activity = true
+ ActiveSupport::Dependencies.log_activity = true
end
def teardown
- Dependencies.log_activity = false
+ ActiveSupport::Dependencies.log_activity = false
self.class.const_remove :FirmOnTheFly rescue nil
Firm.const_remove :FirmOnTheFly rescue nil
end
diff --git a/activerecord/test/cases/lifecycle_test.rb b/activerecord/test/cases/lifecycle_test.rb
index ddcacacc3a..258f7c7a0f 100755
--- a/activerecord/test/cases/lifecycle_test.rb
+++ b/activerecord/test/cases/lifecycle_test.rb
@@ -2,6 +2,7 @@ require "cases/helper"
require 'models/topic'
require 'models/developer'
require 'models/reply'
+require 'models/minimalistic'
class Topic; def after_find() end end
class Developer; def after_find() end end
@@ -44,6 +45,14 @@ class TopicObserver < ActiveRecord::Observer
end
end
+class MinimalisticObserver < ActiveRecord::Observer
+ attr_reader :minimalistic
+
+ def after_find(minimalistic)
+ @minimalistic = minimalistic
+ end
+end
+
class MultiObserver < ActiveRecord::Observer
attr_reader :record
@@ -134,6 +143,14 @@ class LifecycleTest < ActiveRecord::TestCase
assert_equal developer.name, multi_observer.record.name
end
+ def test_observing_after_find_when_not_defined_on_the_model
+ observer = MinimalisticObserver.instance
+ assert_equal Minimalistic, MinimalisticObserver.observed_class
+
+ minimalistic = Minimalistic.find(1)
+ assert_equal minimalistic, observer.minimalistic
+ end
+
def test_invalid_observer
assert_raise(ArgumentError) { Topic.observers = Object.new; Topic.instantiate_observers }
end
diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb
index 7db6c570b5..701187223f 100644
--- a/activerecord/test/cases/locking_test.rb
+++ b/activerecord/test/cases/locking_test.rb
@@ -29,10 +29,12 @@ class OptimisticLockingTest < ActiveRecord::TestCase
assert_equal 0, p1.lock_version
assert_equal 0, p2.lock_version
+ p1.first_name = 'stu'
p1.save!
assert_equal 1, p1.lock_version
assert_equal 0, p2.lock_version
+ p2.first_name = 'sue'
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
end
@@ -42,11 +44,14 @@ class OptimisticLockingTest < ActiveRecord::TestCase
assert_equal 0, p1.lock_version
assert_equal 0, p2.lock_version
+ p1.first_name = 'stu'
p1.save!
assert_equal 1, p1.lock_version
assert_equal 0, p2.lock_version
+ p2.first_name = 'sue'
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
+ p2.first_name = 'sue2'
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
end
@@ -54,15 +59,18 @@ class OptimisticLockingTest < ActiveRecord::TestCase
p1 = Person.new(:first_name => 'anika')
assert_equal 0, p1.lock_version
+ p1.first_name = 'anika2'
p1.save!
p2 = Person.find(p1.id)
assert_equal 0, p1.lock_version
assert_equal 0, p2.lock_version
+ p1.first_name = 'anika3'
p1.save!
assert_equal 1, p1.lock_version
assert_equal 0, p2.lock_version
+ p2.first_name = 'sue'
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
end
@@ -81,10 +89,12 @@ class OptimisticLockingTest < ActiveRecord::TestCase
assert_equal 0, t1.version
assert_equal 0, t2.version
+ t1.tps_report_number = 700
t1.save!
assert_equal 1, t1.version
assert_equal 0, t2.version
+ t2.tps_report_number = 800
assert_raises(ActiveRecord::StaleObjectError) { t2.save! }
end
@@ -93,6 +103,7 @@ class OptimisticLockingTest < ActiveRecord::TestCase
assert_equal 0, p1.lock_version
assert_equal p1.lock_version, Person.new(p1.attributes).lock_version
+ p1.first_name = 'bianca2'
p1.save!
assert_equal 1, p1.lock_version
assert_equal p1.lock_version, Person.new(p1.attributes).lock_version
@@ -146,6 +157,15 @@ class OptimisticLockingTest < ActiveRecord::TestCase
assert ref.save
end
+ # Useful for partial updates, don't only update the lock_version if there
+ # is nothing else being updated.
+ def test_update_without_attributes_does_not_only_update_lock_version
+ assert_nothing_raised do
+ p1 = Person.new(:first_name => 'anika')
+ p1.send(:update_with_lock, [])
+ end
+ end
+
private
def add_counter_column_to(model)
diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb
index 1a9a875730..d6b3e341df 100644
--- a/activerecord/test/cases/method_scoping_test.rb
+++ b/activerecord/test/cases/method_scoping_test.rb
@@ -87,6 +87,16 @@ class MethodScopingTest < ActiveRecord::TestCase
assert_equal 1, scoped_developers.size
end
+ def test_scoped_find_joins
+ scoped_developers = Developer.with_scope(:find => { :joins => 'JOIN developers_projects ON id = developer_id' } ) do
+ Developer.find(:all, :conditions => 'developers_projects.project_id = 2')
+ end
+ assert scoped_developers.include?(developers(:david))
+ assert !scoped_developers.include?(developers(:jamis))
+ assert_equal 1, scoped_developers.size
+ assert_equal developers(:david).attributes, scoped_developers.first.attributes
+ end
+
def test_scoped_count_include
# with the include, will retrieve only developers for the given project
Developer.with_scope(:find => { :include => :projects }) do
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index f36255e209..908951590c 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -173,6 +173,11 @@ if ActiveRecord::Base.connection.supports_migrations?
assert_equal 'smallint', one.sql_type
assert_equal 'integer', four.sql_type
assert_equal 'bigint', eight.sql_type
+ elsif current_adapter?(:MysqlAdapter)
+ assert_match /^int\(\d+\)/, default.sql_type
+ assert_match /^tinyint\(\d+\)/, one.sql_type
+ assert_match /^int\(\d+\)/, four.sql_type
+ assert_match /^bigint\(\d+\)/, eight.sql_type
elsif current_adapter?(:OracleAdapter)
assert_equal 'NUMBER(38)', default.sql_type
assert_equal 'NUMBER(1)', one.sql_type
@@ -483,6 +488,32 @@ if ActiveRecord::Base.connection.supports_migrations?
end
end
+ def test_rename_column_preserves_default_value_not_null
+ begin
+ default_before = Developer.connection.columns("developers").find { |c| c.name == "salary" }.default
+ assert_equal 70000, default_before
+ Developer.connection.rename_column "developers", "salary", "anual_salary"
+ Developer.reset_column_information
+ assert Developer.column_names.include?("anual_salary")
+ default_after = Developer.connection.columns("developers").find { |c| c.name == "anual_salary" }.default
+ assert_equal 70000, default_after
+ ensure
+ Developer.connection.rename_column "developers", "anual_salary", "salary"
+ Developer.reset_column_information
+ end
+ end
+
+ def test_rename_nonexistent_column
+ ActiveRecord::Base.connection.create_table(:hats) do |table|
+ table.column :hat_name, :string, :default => nil
+ end
+ assert_raises(ActiveRecord::ActiveRecordError) do
+ Person.connection.rename_column "hats", "nonexistent", "should_fail"
+ end
+ ensure
+ ActiveRecord::Base.connection.drop_table(:hats)
+ end
+
def test_rename_column_with_sql_reserved_word
begin
assert_nothing_raised { Person.connection.rename_column "people", "first_name", "group" }
@@ -799,6 +830,21 @@ if ActiveRecord::Base.connection.supports_migrations?
assert !Reminder.table_exists?
end
+ def test_migrator_double_up
+ assert_equal(0, ActiveRecord::Migrator.current_version)
+ ActiveRecord::Migrator.run(:up, MIGRATIONS_ROOT + "/valid", 1)
+ assert_nothing_raised { ActiveRecord::Migrator.run(:up, MIGRATIONS_ROOT + "/valid", 1) }
+ assert_equal(1, ActiveRecord::Migrator.current_version)
+ end
+
+ def test_migrator_double_down
+ assert_equal(0, ActiveRecord::Migrator.current_version)
+ ActiveRecord::Migrator.run(:up, MIGRATIONS_ROOT + "/valid", 1)
+ ActiveRecord::Migrator.run(:down, MIGRATIONS_ROOT + "/valid", 1)
+ assert_nothing_raised { ActiveRecord::Migrator.run(:down, MIGRATIONS_ROOT + "/valid", 1) }
+ assert_equal(0, ActiveRecord::Migrator.current_version)
+ end
+
def test_finds_migrations
migrations = ActiveRecord::Migrator.new(:up, MIGRATIONS_ROOT + "/valid").migrations
[['1', 'people_have_last_names'],
@@ -888,16 +934,6 @@ if ActiveRecord::Base.connection.supports_migrations?
ActiveRecord::Migrator.rollback(MIGRATIONS_ROOT + "/valid")
assert_equal(0, ActiveRecord::Migrator.current_version)
end
-
- def test_migrator_run
- assert_equal(0, ActiveRecord::Migrator.current_version)
- ActiveRecord::Migrator.run(:up, MIGRATIONS_ROOT + "/valid", 3)
- assert_equal(0, ActiveRecord::Migrator.current_version)
-
- assert_equal(0, ActiveRecord::Migrator.current_version)
- ActiveRecord::Migrator.run(:down, MIGRATIONS_ROOT + "/valid", 3)
- assert_equal(0, ActiveRecord::Migrator.current_version)
- end
def test_schema_migrations_table_name
ActiveRecord::Base.table_name_prefix = "prefix_"
diff --git a/activerecord/test/cases/multiple_db_test.rb b/activerecord/test/cases/multiple_db_test.rb
index 236e4710a4..eb3e43c8ac 100644
--- a/activerecord/test/cases/multiple_db_test.rb
+++ b/activerecord/test/cases/multiple_db_test.rb
@@ -51,7 +51,7 @@ class MultipleDbTest < ActiveRecord::TestCase
def test_course_connection_should_survive_dependency_reload
assert Course.connection
- Dependencies.clear
+ ActiveSupport::Dependencies.clear
Object.send(:remove_const, :Course)
require_dependency 'models/course'
diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb
index d890cf7936..393ba086c9 100644
--- a/activerecord/test/cases/named_scope_test.rb
+++ b/activerecord/test/cases/named_scope_test.rb
@@ -6,7 +6,7 @@ require 'models/reply'
require 'models/author'
class NamedScopeTest < ActiveRecord::TestCase
- fixtures :posts, :authors, :topics, :comments
+ fixtures :posts, :authors, :topics, :comments, :author_addresses
def test_implements_enumerable
assert !Topic.find(:all).empty?
@@ -59,6 +59,12 @@ class NamedScopeTest < ActiveRecord::TestCase
assert_equal Topic.count(:conditions => {:approved => true}), Topic.approved.count
end
+ def test_scopes_with_string_name_can_be_composed
+ # NOTE that scopes defined with a string as a name worked on their own
+ # but when called on another scope the other scope was completely replaced
+ assert_equal Topic.replied.approved, Topic.replied.approved_as_string
+ end
+
def test_scopes_are_composable
assert_equal (approved = Topic.find(:all, :conditions => {:approved => true})), Topic.approved
assert_equal (replied = Topic.find(:all, :conditions => 'replies_count > 0')), Topic.replied
@@ -77,6 +83,25 @@ class NamedScopeTest < ActiveRecord::TestCase
assert_equal topics_written_before_the_second, Topic.written_before(topics(:second).written_on)
end
+ def test_scopes_with_joins
+ address = author_addresses(:david_address)
+ posts_with_authors_at_address = Post.find(
+ :all, :joins => 'JOIN authors ON authors.id = posts.author_id',
+ :conditions => [ 'authors.author_address_id = ?', address.id ]
+ )
+ assert_equal posts_with_authors_at_address, Post.with_authors_at_address(address)
+ end
+
+ def test_scopes_with_joins_respects_custom_select
+ address = author_addresses(:david_address)
+ posts_with_authors_at_address_titles = Post.find(:all,
+ :select => 'title',
+ :joins => 'JOIN authors ON authors.id = posts.author_id',
+ :conditions => [ 'authors.author_address_id = ?', address.id ]
+ )
+ assert_equal posts_with_authors_at_address_titles, Post.with_authors_at_address(address).find(:all, :select => 'title')
+ end
+
def test_extensions
assert_equal 1, Topic.anonymous_extension.one
assert_equal 2, Topic.named_extension.two
diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb
index 8b4d232554..0c57b79401 100644
--- a/activerecord/test/cases/reflection_test.rb
+++ b/activerecord/test/cases/reflection_test.rb
@@ -160,9 +160,9 @@ class ReflectionTest < ActiveRecord::TestCase
def test_reflection_of_all_associations
# FIXME these assertions bust a lot
- assert_equal 20, Firm.reflect_on_all_associations.size
- assert_equal 16, Firm.reflect_on_all_associations(:has_many).size
- assert_equal 4, Firm.reflect_on_all_associations(:has_one).size
+ assert_equal 22, Firm.reflect_on_all_associations.size
+ assert_equal 17, Firm.reflect_on_all_associations(:has_many).size
+ assert_equal 5, Firm.reflect_on_all_associations(:has_one).size
assert_equal 0, Firm.reflect_on_all_associations(:belongs_to).size
end
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index c42b0efba0..ee7e285a73 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -72,6 +72,52 @@ class SchemaDumperTest < ActiveRecord::TestCase
assert_match %r{:null => false}, output
end
+ def test_schema_dump_includes_limit_constraint_for_integer_columns
+ stream = StringIO.new
+
+ ActiveRecord::SchemaDumper.ignore_tables = [/^(?!integer_limits)/]
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
+ output = stream.string
+
+ if current_adapter?(:PostgreSQLAdapter)
+ assert_match %r{c_int_1.*:limit => 2}, output
+ assert_match %r{c_int_2.*:limit => 2}, output
+
+ # int 3 is 4 bytes in postgresql
+ assert_match %r{c_int_3.*}, output
+ assert_no_match %r{c_int_3.*:limit}, output
+
+ assert_match %r{c_int_4.*}, output
+ assert_no_match %r{c_int_4.*:limit}, output
+ elsif current_adapter?(:MysqlAdapter)
+ assert_match %r{c_int_1.*:limit => 1}, output
+ assert_match %r{c_int_2.*:limit => 2}, output
+ assert_match %r{c_int_3.*:limit => 3}, output
+
+ assert_match %r{c_int_4.*}, output
+ assert_no_match %r{c_int_4.*:limit}, output
+ elsif current_adapter?(:SQLiteAdapter)
+ assert_match %r{c_int_1.*:limit => 1}, output
+ assert_match %r{c_int_2.*:limit => 2}, output
+ assert_match %r{c_int_3.*:limit => 3}, output
+ assert_match %r{c_int_4.*:limit => 4}, output
+ end
+ assert_match %r{c_int_without_limit.*}, output
+ assert_no_match %r{c_int_without_limit.*:limit}, output
+
+ if current_adapter?(:SQLiteAdapter)
+ assert_match %r{c_int_5.*:limit => 5}, output
+ assert_match %r{c_int_6.*:limit => 6}, output
+ assert_match %r{c_int_7.*:limit => 7}, output
+ assert_match %r{c_int_8.*:limit => 8}, output
+ else
+ assert_match %r{c_int_5.*:limit => 8}, output
+ assert_match %r{c_int_6.*:limit => 8}, output
+ assert_match %r{c_int_7.*:limit => 8}, output
+ assert_match %r{c_int_8.*:limit => 8}, output
+ end
+ end
+
def test_schema_dump_with_string_ignored_table
stream = StringIO.new
diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb
index f63af27403..82e069005a 100644
--- a/activerecord/test/models/author.rb
+++ b/activerecord/test/models/author.rb
@@ -1,6 +1,7 @@
class Author < ActiveRecord::Base
has_many :posts
has_many :posts_with_comments, :include => :comments, :class_name => "Post"
+ has_many :posts_with_comments_sorted_by_comment_id, :include => :comments, :class_name => "Post", :order => 'comments.id'
has_many :posts_with_categories, :include => :categories, :class_name => "Post"
has_many :posts_with_comments_and_categories, :include => [ :comments, :categories ], :order => "posts.id", :class_name => "Post"
has_many :posts_containing_the_letter_a, :class_name => "Post"
diff --git a/activerecord/test/models/category.rb b/activerecord/test/models/category.rb
index f1d2e4805a..1660c61682 100644
--- a/activerecord/test/models/category.rb
+++ b/activerecord/test/models/category.rb
@@ -2,6 +2,7 @@ class Category < ActiveRecord::Base
has_and_belongs_to_many :posts
has_and_belongs_to_many :special_posts, :class_name => "Post"
has_and_belongs_to_many :other_posts, :class_name => "Post"
+ has_and_belongs_to_many :posts_with_authors_sorted_by_author_id, :class_name => "Post", :include => :authors, :order => "authors.id"
has_and_belongs_to_many(:select_testing_posts,
:class_name => 'Post',
diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb
index 70f83fa8e6..9fa810ac68 100755
--- a/activerecord/test/models/company.rb
+++ b/activerecord/test/models/company.rb
@@ -26,6 +26,7 @@ class Firm < Company
"AND (#{QUOTED_TYPE} = 'Client' OR #{QUOTED_TYPE} = 'SpecialClient' OR #{QUOTED_TYPE} = 'VerySpecialClient' )"
has_many :clients_sorted_desc, :class_name => "Client", :order => "id DESC"
has_many :clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id"
+ has_many :unvalidated_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :validate => false
has_many :dependent_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id", :dependent => :destroy
has_many :exclusively_dependent_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id", :dependent => :delete_all
has_many :limited_clients, :class_name => "Client", :order => "id", :limit => 1
@@ -46,7 +47,8 @@ class Firm < Company
has_many :plain_clients, :class_name => 'Client'
has_many :readonly_clients, :class_name => 'Client', :readonly => true
- has_one :account, :foreign_key => "firm_id", :dependent => :destroy
+ has_one :account, :foreign_key => "firm_id", :dependent => :destroy, :validate => true
+ has_one :unvalidated_account, :foreign_key => "firm_id", :class_name => 'Account', :validate => false
has_one :account_with_select, :foreign_key => "firm_id", :select => "id, firm_id", :class_name=>'Account'
has_one :readonly_account, :foreign_key => "firm_id", :class_name => "Account", :readonly => true
end
diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb
index f77fd0e96d..9f26cacdec 100644
--- a/activerecord/test/models/developer.rb
+++ b/activerecord/test/models/developer.rb
@@ -56,7 +56,8 @@ class Developer < ActiveRecord::Base
end
class AuditLog < ActiveRecord::Base
- belongs_to :developer
+ belongs_to :developer, :validate => true
+ belongs_to :unvalidated_developer, :class_name => 'Developer'
end
DeveloperSalary = Struct.new(:amount)
diff --git a/activerecord/test/models/person.rb b/activerecord/test/models/person.rb
index 4f4d695b24..430d0b38f7 100644
--- a/activerecord/test/models/person.rb
+++ b/activerecord/test/models/person.rb
@@ -6,5 +6,5 @@ class Person < ActiveRecord::Base
has_many :references
has_many :jobs, :through => :references
has_one :favourite_reference, :class_name => 'Reference', :conditions => ['favourite=?', true]
-
+ has_many :posts_with_comments_sorted_by_comment_id, :through => :readers, :source => :post, :include => :comments, :order => 'comments.id'
end
diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb
index d9101706b5..3adbc0ce1f 100644
--- a/activerecord/test/models/post.rb
+++ b/activerecord/test/models/post.rb
@@ -1,6 +1,11 @@
class Post < ActiveRecord::Base
named_scope :containing_the_letter_a, :conditions => "body LIKE '%a%'"
-
+ named_scope :with_authors_at_address, lambda { |address| {
+ :conditions => [ 'authors.author_address_id = ?', address.id ],
+ :joins => 'JOIN authors ON authors.id = posts.author_id'
+ }
+ }
+
belongs_to :author do
def greeting
"hello"
diff --git a/activerecord/test/models/topic.rb b/activerecord/test/models/topic.rb
index f63e862cfd..423b6fe52b 100755
--- a/activerecord/test/models/topic.rb
+++ b/activerecord/test/models/topic.rb
@@ -4,6 +4,7 @@ class Topic < ActiveRecord::Base
{ :conditions => ['written_on < ?', time] }
}
named_scope :approved, :conditions => {:approved => true}
+ named_scope 'approved_as_string', :conditions => {:approved => true}
named_scope :replied, :conditions => ['replies_count > 0']
named_scope :anonymous_extension do
def one
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 423929fd55..234c43494a 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -407,6 +407,13 @@ ActiveRecord::Schema.define do
t.column :key, :string
end
+ create_table :integer_limits, :force => true do |t|
+ t.integer :"c_int_without_limit"
+ (1..8).each do |i|
+ t.integer :"c_int_#{i}", :limit => i
+ end
+ end
+
except 'SQLite' do
# fk_test_has_fk should be before fk_test_has_pk
create_table :fk_test_has_fk, :force => true do |t|
diff --git a/activeresource/CHANGELOG b/activeresource/CHANGELOG
index e124e40dd1..673e20de28 100644
--- a/activeresource/CHANGELOG
+++ b/activeresource/CHANGELOG
@@ -1,3 +1,8 @@
+*Edge*
+
+* Fixed Base#exists? to check status code as integer [#299 state:resolved] (Wes Oldenbeuving)
+
+
*2.1.0 (May 31st, 2008)*
* Fixed response logging to use length instead of the entire thing (seangeo) [#27]
diff --git a/activeresource/Rakefile b/activeresource/Rakefile
index 9fd0ec4921..8c3ad36a02 100644
--- a/activeresource/Rakefile
+++ b/activeresource/Rakefile
@@ -42,9 +42,10 @@ Rake::RDocTask.new { |rdoc|
rdoc.title = "Active Resource -- Object-oriented REST services"
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
rdoc.options << '--charset' << 'utf-8'
- rdoc.template = "#{ENV['template']}.rb" if ENV['template']
+ rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
rdoc.rdoc_files.include('README', 'CHANGELOG')
rdoc.rdoc_files.include('lib/**/*.rb')
+ rdoc.rdoc_files.exclude('lib/activeresource.rb')
}
@@ -114,13 +115,13 @@ end
desc "Publish the beta gem"
task :pgem => [:package] do
- Rake::SshFilePublisher.new("davidhh@wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
- `ssh davidhh@wrath.rubyonrails.org './gemupdate.sh'`
+ Rake::SshFilePublisher.new("wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
+ `ssh wrath.rubyonrails.org './gemupdate.sh'`
end
desc "Publish the API documentation"
task :pdoc => [:rdoc] do
- Rake::SshDirPublisher.new("davidhh@wrath.rubyonrails.org", "public_html/ar", "doc").upload
+ Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/ar", "doc").upload
end
desc "Publish the release files to RubyForge."
diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb
index 59e0888c2b..492ab27bef 100644
--- a/activeresource/lib/active_resource/base.rb
+++ b/activeresource/lib/active_resource/base.rb
@@ -538,7 +538,7 @@ module ActiveResource
prefix_options, query_options = split_options(options[:params])
path = element_path(id, prefix_options, query_options)
response = connection.head(path, headers)
- response.code == 200
+ response.code.to_i == 200
end
# id && !find_single(id, options).nil?
rescue ActiveResource::ResourceNotFound
@@ -988,7 +988,11 @@ module ActiveResource
self.class.const_get(resource_name)
end
rescue NameError
- resource = self.class.const_set(resource_name, Class.new(ActiveResource::Base))
+ if self.class.const_defined?(resource_name)
+ resource = self.class.const_get(resource_name)
+ else
+ resource = self.class.const_set(resource_name, Class.new(ActiveResource::Base))
+ end
resource.prefix = self.class.prefix
resource.site = self.class.site
resource
diff --git a/activeresource/test/base_test.rb b/activeresource/test/base_test.rb
index 9e2f6c1831..4addd52636 100644
--- a/activeresource/test/base_test.rb
+++ b/activeresource/test/base_test.rb
@@ -1,5 +1,6 @@
require 'abstract_unit'
require "fixtures/person"
+require "fixtures/customer"
require "fixtures/street_address"
require "fixtures/beast"
@@ -15,6 +16,37 @@ class BaseTest < Test::Unit::TestCase
@people_david = [{ :id => 2, :name => 'David' }].to_xml(:root => 'people')
@addresses = [{ :id => 1, :street => '12345 Street' }].to_xml(:root => 'addresses')
+ # - deep nested resource -
+ # - Luis (Customer)
+ # - JK (Customer::Friend)
+ # - Mateo (Customer::Friend::Brother)
+ # - Edith (Customer::Friend::Brother::Child)
+ # - Martha (Customer::Friend::Brother::Child)
+ # - Felipe (Customer::Friend::Brother)
+ # - Bryan (Customer::Friend::Brother::Child)
+ # - Luke (Customer::Friend::Brother::Child)
+ # - Eduardo (Customer::Friend)
+ # - Sebas (Customer::Friend::Brother)
+ # - Andres (Customer::Friend::Brother::Child)
+ # - Jorge (Customer::Friend::Brother::Child)
+ # - Elsa (Customer::Friend::Brother)
+ # - Natacha (Customer::Friend::Brother::Child)
+ # - Milena (Customer::Friend::Brother)
+ #
+ @luis = {:id => 1, :name => 'Luis',
+ :friends => [{:name => 'JK',
+ :brothers => [{:name => 'Mateo',
+ :children => [{:name => 'Edith'},{:name => 'Martha'}]},
+ {:name => 'Felipe',
+ :children => [{:name => 'Bryan'},{:name => 'Luke'}]}]},
+ {:name => 'Eduardo',
+ :brothers => [{:name => 'Sebas',
+ :children => [{:name => 'Andres'},{:name => 'Jorge'}]},
+ {:name => 'Elsa',
+ :children => [{:name => 'Natacha'}]},
+ {:name => 'Milena',
+ :children => []}]}]}.to_xml(:root => 'customer')
+
ActiveResource::HttpMock.respond_to do |mock|
mock.get "/people/1.xml", {}, @matz
mock.get "/people/2.xml", {}, @david
@@ -46,6 +78,8 @@ class BaseTest < Test::Unit::TestCase
mock.head "/people/1/addresses/2.xml", {}, nil, 404
mock.head "/people/2/addresses/1.xml", {}, nil, 404
mock.head "/people/Greg/addresses/1.xml", {}, nil, 200
+ # customer
+ mock.get "/customers/1.xml", {}, @luis
end
Person.user = nil
@@ -788,4 +822,18 @@ class BaseTest < Test::Unit::TestCase
matz = Person.find(1)
assert_equal '1', matz.to_param
end
+
+ def test_parse_deep_nested_resources
+ luis = Customer.find(1)
+ assert_kind_of Customer, luis
+ luis.friends.each do |friend|
+ assert_kind_of Customer::Friend, friend
+ friend.brothers.each do |brother|
+ assert_kind_of Customer::Friend::Brother, brother
+ brother.children.each do |child|
+ assert_kind_of Customer::Friend::Brother::Child, child
+ end
+ end
+ end
+ end
end
diff --git a/activeresource/test/fixtures/customer.rb b/activeresource/test/fixtures/customer.rb
new file mode 100644
index 0000000000..845d5d11cb
--- /dev/null
+++ b/activeresource/test/fixtures/customer.rb
@@ -0,0 +1,3 @@
+class Customer < ActiveResource::Base
+ self.site = "http://37s.sunrise.i:3000"
+end
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index 690bb987dc..4f61311d95 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -1,3 +1,22 @@
+*Edge*
+
+* Added Array#second through Array#tenth as aliases for Array#[1] through Array#[9] [DHH]
+
+* Added test/do declaration style testing to ActiveSupport::TestCase [DHH via Jay Fields]
+
+* Added Object#present? which is equivalent to !Object#blank? [DHH]
+
+* Added Enumberable#many? to encapsulate collection.size > 1 [DHH/Damian Janowski]
+
+* Add more standard Hash methods to ActiveSupport::OrderedHash [Steve Purcell]
+
+* Namespace Inflector, Dependencies, OrderedOptions, and TimeZone under ActiveSupport [Josh Peek]
+
+* Added StringInquirer for doing things like StringInquirer.new("production").production? # => true and StringInquirer.new("production").development? # => false [DHH]
+
+* Fixed Date#end_of_quarter to not blow up on May 31st [#289 state:resolved] (Danger)
+
+
*2.1.0 (May 31st, 2008)*
* TimeZone#to_s shows offset as GMT instead of UTC, because GMT will be more familiar to end users (see time zone selects used by Windows OS, google.com and yahoo.com.) Reverts [8370] [Geoff Buesing]
@@ -166,7 +185,6 @@
* Introduce ActiveSupport::TimeWithZone, for wrapping Time instances with a TimeZone. Introduce instance methods to Time for creating TimeWithZone instances, and class methods for managing a global time zone. [Geoff Buesing]
->>>>>>> .r8815
* Replace non-dst-aware TimeZone class with dst-aware class from tzinfo_timezone plugin. TimeZone#adjust and #unadjust are no longer available; tzinfo gem must now be present in order to perform time zone calculations, via #local_to_utc and #utc_to_local methods. [Geoff Buesing]
* Extract ActiveSupport::Callbacks from Active Record, test case setup and teardown, and ActionController::Dispatcher. #10727 [Josh Peek]
diff --git a/activesupport/Rakefile b/activesupport/Rakefile
index 38ca03b658..f2885c69a4 100644
--- a/activesupport/Rakefile
+++ b/activesupport/Rakefile
@@ -33,11 +33,11 @@ Rake::RDocTask.new { |rdoc|
rdoc.title = "Active Support -- Utility classes and standard library extensions from Rails"
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.options << '--charset' << 'utf-8'
- rdoc.template = "#{ENV['template']}.rb" if ENV['template']
+ rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
rdoc.rdoc_files.include('README', 'CHANGELOG')
rdoc.rdoc_files.include('lib/active_support.rb')
- rdoc.rdoc_files.include('lib/active_support/*.rb')
rdoc.rdoc_files.include('lib/active_support/**/*.rb')
+ rdoc.rdoc_files.exclude('lib/active_support/vendor/*')
}
spec = Gem::Specification.new do |s|
@@ -65,13 +65,13 @@ end
desc "Publish the beta gem"
task :pgem => [:package] do
- Rake::SshFilePublisher.new("davidhh@wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
- `ssh davidhh@wrath.rubyonrails.org './gemupdate.sh'`
+ Rake::SshFilePublisher.new("wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
+ `ssh wrath.rubyonrails.org './gemupdate.sh'`
end
desc "Publish the API documentation"
task :pdoc => [:rdoc] do
- Rake::SshDirPublisher.new("davidhh@wrath.rubyonrails.org", "public_html/as", "doc").upload
+ Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/as", "doc").upload
end
desc "Publish the release files to RubyForge."
@@ -119,7 +119,7 @@ namespace :tzinfo do
task :copy_definitions => :unpack_gem do
definitions_path = "#{destination_path}/tzinfo/definitions/"
mkdir_p definitions_path
- TimeZone::MAPPING.values.each do |zone|
+ ActiveSupport::TimeZone::MAPPING.values.each do |zone|
subdir = nil
if /\// === zone
subdir = zone.sub(/\w+$/, '')
@@ -172,4 +172,4 @@ namespace :tzinfo do
def excluded_classes
%w(country country_index_definition country_info country_timezone timezone_index_definition timezone_proxy tzdataparser)
end
-end \ No newline at end of file
+end
diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb
index e4cb145c98..1a8603e892 100644
--- a/activesupport/lib/active_support.rb
+++ b/activesupport/lib/active_support.rb
@@ -43,6 +43,8 @@ require 'active_support/ordered_hash'
require 'active_support/ordered_options'
require 'active_support/option_merger'
+require 'active_support/string_inquirer'
+
require 'active_support/values/time_zone'
require 'active_support/duration'
@@ -53,3 +55,7 @@ require 'active_support/multibyte'
require 'active_support/base64'
require 'active_support/time_with_zone'
+
+Inflector = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Inflector', 'ActiveSupport::Inflector')
+Dependencies = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Dependencies', 'ActiveSupport::Dependencies')
+TimeZone = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('TimeZone', 'ActiveSupport::TimeZone')
diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb
index 2f1143e610..3e3dc18263 100644
--- a/activesupport/lib/active_support/cache.rb
+++ b/activesupport/lib/active_support/cache.rb
@@ -19,19 +19,19 @@ module ActiveSupport
def self.expand_cache_key(key, namespace = nil)
expanded_cache_key = namespace ? "#{namespace}/" : ""
-
+
if ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]
expanded_cache_key << "#{ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]}/"
end
expanded_cache_key << case
- when key.respond_to?(:cache_key)
- key.cache_key
- when key.is_a?(Array)
- key.collect { |element| expand_cache_key(element) }.to_param
- when key.respond_to?(:to_param)
- key.to_param
- end
+ when key.respond_to?(:cache_key)
+ key.cache_key
+ when key.is_a?(Array)
+ key.collect { |element| expand_cache_key(element) }.to_param
+ when key
+ key.to_param
+ end.to_s
expanded_cache_key
end
diff --git a/activesupport/lib/active_support/core_ext/array/access.rb b/activesupport/lib/active_support/core_ext/array/access.rb
index 21a8584bb9..4ac95efdc7 100644
--- a/activesupport/lib/active_support/core_ext/array/access.rb
+++ b/activesupport/lib/active_support/core_ext/array/access.rb
@@ -20,6 +20,51 @@ module ActiveSupport #:nodoc:
def to(position)
self[0..position]
end
+
+ # Equal to self[1]
+ def second
+ self[1]
+ end
+
+ # Equal to self[2]
+ def third
+ self[2]
+ end
+
+ # Equal to self[3]
+ def fourth
+ self[3]
+ end
+
+ # Equal to self[4]
+ def fifth
+ self[4]
+ end
+
+ # Equal to self[5]
+ def sixth
+ self[5]
+ end
+
+ # Equal to self[6]
+ def seventh
+ self[6]
+ end
+
+ # Equal to self[7]
+ def eighth
+ self[7]
+ end
+
+ # Equal to self[8]
+ def ninth
+ self[8]
+ end
+
+ # Equal to self[9]
+ def tenth
+ self[9]
+ end
end
end
end
diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb
index a9882828ca..49ada8f174 100644
--- a/activesupport/lib/active_support/core_ext/array/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/array/conversions.rb
@@ -27,7 +27,7 @@ module ActiveSupport #:nodoc:
# Calls <tt>to_param</tt> on all its elements and joins the result with
# slashes. This is used by <tt>url_for</tt> in Action Pack.
def to_param
- map(&:to_param).join '/'
+ collect { |e| e.to_param }.join '/'
end
# Converts an array into a string suitable for use as a URL query string,
@@ -35,7 +35,8 @@ module ActiveSupport #:nodoc:
#
# ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"
def to_query(key)
- collect { |value| value.to_query("#{key}[]") } * '&'
+ prefix = "#{key}[]"
+ collect { |value| value.to_query(prefix) }.join '&'
end
def self.included(base) #:nodoc:
diff --git a/activesupport/lib/active_support/core_ext/blank.rb b/activesupport/lib/active_support/core_ext/blank.rb
index dfe33162e8..4f8dc4e281 100644
--- a/activesupport/lib/active_support/core_ext/blank.rb
+++ b/activesupport/lib/active_support/core_ext/blank.rb
@@ -12,6 +12,11 @@ class Object
def blank?
respond_to?(:empty?) ? empty? : !self
end
+
+ # An object is present if it's not blank.
+ def present?
+ !blank?
+ end
end
class NilClass #:nodoc:
diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb
index 1e2dbf118e..b5180c9592 100644
--- a/activesupport/lib/active_support/core_ext/date/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date/calculations.rb
@@ -184,7 +184,7 @@ module ActiveSupport #:nodoc:
# Returns a new Date/DateTime representing the end of the quarter (last day of march, june, september, december; DateTime objects will have time set to 23:59:59)
def end_of_quarter
- change(:month => [3, 6, 9, 12].detect { |m| m >= self.month }).end_of_month
+ beginning_of_month.change(:month => [3, 6, 9, 12].detect { |m| m >= self.month }).end_of_month
end
alias :at_end_of_quarter :end_of_quarter
diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb
index f1469aa0e3..e451e9933a 100644
--- a/activesupport/lib/active_support/core_ext/enumerable.rb
+++ b/activesupport/lib/active_support/core_ext/enumerable.rb
@@ -1,3 +1,5 @@
+require 'active_support/ordered_hash'
+
module Enumerable
# Ruby 1.8.7 introduces group_by, but the result isn't ordered. Override it.
remove_method(:group_by) if [].respond_to?(:group_by) && RUBY_VERSION < '1.9'
@@ -18,10 +20,19 @@ module Enumerable
# "2006-02-24 -> Transcript, Transcript"
# "2006-02-23 -> Transcript"
def group_by
- inject ActiveSupport::OrderedHash.new do |grouped, element|
- (grouped[yield(element)] ||= []) << element
- grouped
+ assoc = ActiveSupport::OrderedHash.new
+
+ each do |element|
+ key = yield(element)
+
+ if assoc.has_key?(key)
+ assoc[key] << element
+ else
+ assoc[key] = [element]
+ end
end
+
+ assoc
end unless [].respond_to?(:group_by)
# Calculates a sum from the elements. Examples:
@@ -66,4 +77,11 @@ module Enumerable
accum
end
end
+
+ # Returns true if the collection has more than 1 element. Functionally equivalent to collection.size > 1.
+ # Works with a block too ala any?, so people.many? { |p| p.age > 26 } # => returns true if more than 1 person is over 26.
+ def many?(&block)
+ size = block_given? ? select(&block).size : self.size
+ size > 1
+ end
end
diff --git a/activesupport/lib/active_support/core_ext/hash/except.rb b/activesupport/lib/active_support/core_ext/hash/except.rb
index 64d690965a..f26d01553d 100644
--- a/activesupport/lib/active_support/core_ext/hash/except.rb
+++ b/activesupport/lib/active_support/core_ext/hash/except.rb
@@ -10,13 +10,14 @@ module ActiveSupport #:nodoc:
module Except
# Returns a new hash without the given keys.
def except(*keys)
- rejected = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
- reject { |key,| rejected.include?(key) }
+ clone.except!(*keys)
end
# Replaces the hash without the given keys.
def except!(*keys)
- replace(except(*keys))
+ keys.map! { |key| convert_key(key) } if respond_to?(:convert_key)
+ keys.each { |key| delete(key) }
+ self
end
end
end
diff --git a/activesupport/lib/active_support/core_ext/hash/slice.rb b/activesupport/lib/active_support/core_ext/hash/slice.rb
index 6fe5e05330..be4dec6e53 100644
--- a/activesupport/lib/active_support/core_ext/hash/slice.rb
+++ b/activesupport/lib/active_support/core_ext/hash/slice.rb
@@ -1,5 +1,3 @@
-require 'set'
-
module ActiveSupport #:nodoc:
module CoreExtensions #:nodoc:
module Hash #:nodoc:
@@ -14,8 +12,10 @@ module ActiveSupport #:nodoc:
module Slice
# Returns a new hash with only the given keys.
def slice(*keys)
- allowed = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
- reject { |key,| !allowed.include?(key) }
+ keys = keys.map! { |key| convert_key(key) } if respond_to?(:convert_key)
+ hash = {}
+ keys.each { |k| hash[k] = self[k] if has_key?(k) }
+ hash
end
# Replaces the hash with only the given keys.
diff --git a/activesupport/lib/active_support/core_ext/module.rb b/activesupport/lib/active_support/core_ext/module.rb
index da8d5b3762..34fcbd124b 100644
--- a/activesupport/lib/active_support/core_ext/module.rb
+++ b/activesupport/lib/active_support/core_ext/module.rb
@@ -6,3 +6,8 @@ require 'active_support/core_ext/module/delegation'
require 'active_support/core_ext/module/introspection'
require 'active_support/core_ext/module/loading'
require 'active_support/core_ext/module/aliasing'
+require 'active_support/core_ext/module/model_naming'
+
+class Module
+ include ActiveSupport::CoreExt::Module::ModelNaming
+end
diff --git a/activesupport/lib/active_support/core_ext/module/model_naming.rb b/activesupport/lib/active_support/core_ext/module/model_naming.rb
new file mode 100644
index 0000000000..abb02f1f70
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/module/model_naming.rb
@@ -0,0 +1,23 @@
+module ActiveSupport
+ class ModelName < String
+ attr_reader :singular, :plural, :cache_key, :partial_path
+
+ def initialize(name)
+ super
+ @singular = underscore.tr('/', '_').freeze
+ @plural = @singular.pluralize.freeze
+ @cache_key = tableize
+ @partial_path = "#{@cache_key}/#{demodulize.underscore}".freeze
+ end
+ end
+
+ module CoreExt
+ module Module
+ module ModelNaming
+ def model_name
+ @model_name ||= ModelName.new(name)
+ end
+ end
+ 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 43a2be916e..082e98a297 100644
--- a/activesupport/lib/active_support/core_ext/object/extending.rb
+++ b/activesupport/lib/active_support/core_ext/object/extending.rb
@@ -3,17 +3,18 @@ class Object
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 = []
- # 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.
- 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
+ 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
diff --git a/activesupport/lib/active_support/core_ext/string/unicode.rb b/activesupport/lib/active_support/core_ext/string/unicode.rb
index 5e20534d1d..666f7bcb65 100644
--- a/activesupport/lib/active_support/core_ext/string/unicode.rb
+++ b/activesupport/lib/active_support/core_ext/string/unicode.rb
@@ -1,16 +1,16 @@
module ActiveSupport #:nodoc:
module CoreExtensions #:nodoc:
module String #:nodoc:
- unless '1.9'.respond_to?(:force_encoding)
- # Define methods for handling unicode data.
- module Unicode
- def self.append_features(base)
- if '1.8.7'.respond_to?(:chars)
- base.class_eval { remove_method :chars }
- end
- super
+ # Define methods for handling unicode data.
+ module Unicode
+ def self.append_features(base)
+ if '1.8.7 and later'.respond_to?(:chars)
+ base.class_eval { remove_method :chars }
end
+ super
+ end
+ unless '1.9'.respond_to?(:force_encoding)
# +chars+ is a Unicode safe proxy for string methods. It creates and returns an instance of the
# ActiveSupport::Multibyte::Chars class which encapsulates the original string. A Unicode safe version of all
# the String methods are defined on this proxy class. Undefined methods are forwarded to String, so all of the
@@ -44,14 +44,12 @@ module ActiveSupport #:nodoc:
def is_utf8?
ActiveSupport::Multibyte::Handlers::UTF8Handler.consumes?(self)
end
- end
- else
- module Unicode #:nodoc:
- def chars
+ else
+ def chars #:nodoc:
self
end
- def is_utf8?
+ def is_utf8? #:nodoc:
case encoding
when Encoding::UTF_8
valid_encoding?
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index 8f3aa4f848..7a8c4d0326 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -3,458 +3,459 @@ require 'active_support/core_ext/module/attribute_accessors'
require 'active_support/core_ext/load_error'
require 'active_support/core_ext/kernel'
-module Dependencies #:nodoc:
- extend self
-
- # Should we turn on Ruby warnings on the first load of dependent files?
- mattr_accessor :warnings_on_first_load
- self.warnings_on_first_load = false
-
- # All files ever loaded.
- mattr_accessor :history
- self.history = Set.new
-
- # All files currently loaded.
- mattr_accessor :loaded
- self.loaded = Set.new
-
- # Should we load files or require them?
- mattr_accessor :mechanism
- self.mechanism = :load
-
- # The set of directories from which we may automatically load files. Files
- # under these directories will be reloaded on each request in development mode,
- # unless the directory also appears in load_once_paths.
- mattr_accessor :load_paths
- self.load_paths = []
-
- # The set of directories from which automatically loaded constants are loaded
- # only once. All directories in this set must also be present in +load_paths+.
- mattr_accessor :load_once_paths
- self.load_once_paths = []
-
- # An array of qualified constant names that have been loaded. Adding a name to
- # this array will cause it to be unloaded the next time Dependencies are cleared.
- mattr_accessor :autoloaded_constants
- self.autoloaded_constants = []
-
- # An array of constant names that need to be unloaded on every request. Used
- # to allow arbitrary constants to be marked for unloading.
- mattr_accessor :explicitly_unloadable_constants
- self.explicitly_unloadable_constants = []
-
- # Set to true to enable logging of const_missing and file loads
- mattr_accessor :log_activity
- self.log_activity = false
-
- # An internal stack used to record which constants are loaded by any block.
- mattr_accessor :constant_watch_stack
- self.constant_watch_stack = []
-
- def load?
- mechanism == :load
- end
-
- def depend_on(file_name, swallow_load_errors = false)
- path = search_for_file(file_name)
- require_or_load(path || file_name)
- rescue LoadError
- raise unless swallow_load_errors
- end
-
- def associate_with(file_name)
- depend_on(file_name, true)
- end
+module ActiveSupport #:nodoc:
+ module Dependencies #:nodoc:
+ extend self
+
+ # Should we turn on Ruby warnings on the first load of dependent files?
+ mattr_accessor :warnings_on_first_load
+ self.warnings_on_first_load = false
+
+ # All files ever loaded.
+ mattr_accessor :history
+ self.history = Set.new
+
+ # All files currently loaded.
+ mattr_accessor :loaded
+ self.loaded = Set.new
+
+ # Should we load files or require them?
+ mattr_accessor :mechanism
+ self.mechanism = :load
+
+ # The set of directories from which we may automatically load files. Files
+ # under these directories will be reloaded on each request in development mode,
+ # unless the directory also appears in load_once_paths.
+ mattr_accessor :load_paths
+ self.load_paths = []
+
+ # The set of directories from which automatically loaded constants are loaded
+ # only once. All directories in this set must also be present in +load_paths+.
+ mattr_accessor :load_once_paths
+ self.load_once_paths = []
+
+ # An array of qualified constant names that have been loaded. Adding a name to
+ # this array will cause it to be unloaded the next time Dependencies are cleared.
+ mattr_accessor :autoloaded_constants
+ self.autoloaded_constants = []
+
+ # An array of constant names that need to be unloaded on every request. Used
+ # to allow arbitrary constants to be marked for unloading.
+ mattr_accessor :explicitly_unloadable_constants
+ self.explicitly_unloadable_constants = []
+
+ # Set to true to enable logging of const_missing and file loads
+ mattr_accessor :log_activity
+ self.log_activity = false
+
+ # An internal stack used to record which constants are loaded by any block.
+ mattr_accessor :constant_watch_stack
+ self.constant_watch_stack = []
+
+ def load?
+ mechanism == :load
+ end
- def clear
- log_call
- loaded.clear
- remove_unloadable_constants!
- end
+ def depend_on(file_name, swallow_load_errors = false)
+ path = search_for_file(file_name)
+ require_or_load(path || file_name)
+ rescue LoadError
+ raise unless swallow_load_errors
+ end
- def require_or_load(file_name, const_path = nil)
- log_call file_name, const_path
- file_name = $1 if file_name =~ /^(.*)\.rb$/
- expanded = File.expand_path(file_name)
- return if loaded.include?(expanded)
+ def associate_with(file_name)
+ depend_on(file_name, true)
+ end
- # Record that we've seen this file *before* loading it to avoid an
- # infinite loop with mutual dependencies.
- loaded << expanded
+ def clear
+ log_call
+ loaded.clear
+ remove_unloadable_constants!
+ end
- begin
- if load?
- log "loading #{file_name}"
+ def require_or_load(file_name, const_path = nil)
+ log_call file_name, const_path
+ file_name = $1 if file_name =~ /^(.*)\.rb$/
+ expanded = File.expand_path(file_name)
+ return if loaded.include?(expanded)
- # Enable warnings iff this file has not been loaded before and
- # warnings_on_first_load is set.
- load_args = ["#{file_name}.rb"]
- load_args << const_path unless const_path.nil?
+ # Record that we've seen this file *before* loading it to avoid an
+ # infinite loop with mutual dependencies.
+ loaded << expanded
- if !warnings_on_first_load or history.include?(expanded)
- result = load_file(*load_args)
+ begin
+ if load?
+ log "loading #{file_name}"
+
+ # Enable warnings iff this file has not been loaded before and
+ # warnings_on_first_load is set.
+ load_args = ["#{file_name}.rb"]
+ load_args << const_path unless const_path.nil?
+
+ if !warnings_on_first_load or history.include?(expanded)
+ result = load_file(*load_args)
+ else
+ enable_warnings { result = load_file(*load_args) }
+ end
else
- enable_warnings { result = load_file(*load_args) }
+ log "requiring #{file_name}"
+ result = require file_name
end
- else
- log "requiring #{file_name}"
- result = require file_name
+ rescue Exception
+ loaded.delete expanded
+ raise
end
- rescue Exception
- loaded.delete expanded
- raise
- end
- # Record history *after* loading so first load gets warnings.
- history << expanded
- return result
- end
+ # Record history *after* loading so first load gets warnings.
+ history << expanded
+ return result
+ end
- # Is the provided constant path defined?
- def qualified_const_defined?(path)
- raise NameError, "#{path.inspect} is not a valid constant name!" unless
- /^(::)?([A-Z]\w*)(::[A-Z]\w*)*$/ =~ path
+ # Is the provided constant path defined?
+ def qualified_const_defined?(path)
+ raise NameError, "#{path.inspect} is not a valid constant name!" unless
+ /^(::)?([A-Z]\w*)(::[A-Z]\w*)*$/ =~ path
- names = path.to_s.split('::')
- names.shift if names.first.empty?
+ names = path.to_s.split('::')
+ names.shift if names.first.empty?
- # We can't use defined? because it will invoke const_missing for the parent
- # of the name we are checking.
- names.inject(Object) do |mod, name|
- return false unless uninherited_const_defined?(mod, name)
- mod.const_get name
+ # We can't use defined? because it will invoke const_missing for the parent
+ # of the name we are checking.
+ names.inject(Object) do |mod, name|
+ return false unless uninherited_const_defined?(mod, name)
+ mod.const_get name
+ end
+ return true
end
- return true
- end
- if Module.method(:const_defined?).arity == 1
- # Does this module define this constant?
- # Wrapper to accommodate changing Module#const_defined? in Ruby 1.9
- def uninherited_const_defined?(mod, const)
- mod.const_defined?(const)
- end
- else
- def uninherited_const_defined?(mod, const) #:nodoc:
- mod.const_defined?(const, false)
+ if Module.method(:const_defined?).arity == 1
+ # Does this module define this constant?
+ # Wrapper to accomodate changing Module#const_defined? in Ruby 1.9
+ def uninherited_const_defined?(mod, const)
+ mod.const_defined?(const)
+ end
+ else
+ def uninherited_const_defined?(mod, const) #:nodoc:
+ mod.const_defined?(const, false)
+ end
end
- end
-
- # Given +path+, a filesystem path to a ruby file, return an array of constant
- # paths which would cause Dependencies to attempt to load this file.
- def loadable_constants_for_path(path, bases = load_paths)
- path = $1 if path =~ /\A(.*)\.rb\Z/
- expanded_path = File.expand_path(path)
-
- bases.collect do |root|
- expanded_root = File.expand_path(root)
- next unless %r{\A#{Regexp.escape(expanded_root)}(/|\\)} =~ expanded_path
-
- nesting = expanded_path[(expanded_root.size)..-1]
- nesting = nesting[1..-1] if nesting && nesting[0] == ?/
- next if nesting.blank?
-
- [
- nesting.camelize,
- # Special case: application.rb might define ApplicationControlller.
- ('ApplicationController' if nesting == 'application')
- ]
- end.flatten.compact.uniq
- end
- # Search for a file in load_paths matching the provided suffix.
- def search_for_file(path_suffix)
- path_suffix = path_suffix + '.rb' unless path_suffix.ends_with? '.rb'
- load_paths.each do |root|
- path = File.join(root, path_suffix)
- return path if File.file? path
+ # Given +path+, a filesystem path to a ruby file, return an array of constant
+ # paths which would cause Dependencies to attempt to load this file.
+ def loadable_constants_for_path(path, bases = load_paths)
+ path = $1 if path =~ /\A(.*)\.rb\Z/
+ expanded_path = File.expand_path(path)
+
+ bases.collect do |root|
+ expanded_root = File.expand_path(root)
+ next unless %r{\A#{Regexp.escape(expanded_root)}(/|\\)} =~ expanded_path
+
+ nesting = expanded_path[(expanded_root.size)..-1]
+ nesting = nesting[1..-1] if nesting && nesting[0] == ?/
+ next if nesting.blank?
+
+ [
+ nesting.camelize,
+ # Special case: application.rb might define ApplicationControlller.
+ ('ApplicationController' if nesting == 'application')
+ ]
+ end.flatten.compact.uniq
end
- nil # Gee, I sure wish we had first_match ;-)
- end
- # Does the provided path_suffix correspond to an autoloadable module?
- # Instead of returning a boolean, the autoload base for this module is returned.
- def autoloadable_module?(path_suffix)
- load_paths.each do |load_path|
- return load_path if File.directory? File.join(load_path, path_suffix)
+ # Search for a file in load_paths matching the provided suffix.
+ def search_for_file(path_suffix)
+ path_suffix = path_suffix + '.rb' unless path_suffix.ends_with? '.rb'
+ load_paths.each do |root|
+ path = File.join(root, path_suffix)
+ return path if File.file? path
+ end
+ nil # Gee, I sure wish we had first_match ;-)
end
- nil
- end
-
- def load_once_path?(path)
- load_once_paths.any? { |base| path.starts_with? base }
- end
- # Attempt to autoload the provided module name by searching for a directory
- # matching the expect path suffix. If found, the module is created and assigned
- # to +into+'s constants with the name +const_name+. Provided that the directory
- # was loaded from a reloadable base path, it is added to the set of constants
- # that are to be unloaded.
- def autoload_module!(into, const_name, qualified_name, path_suffix)
- return nil unless base_path = autoloadable_module?(path_suffix)
- mod = Module.new
- into.const_set const_name, mod
- autoloaded_constants << qualified_name unless load_once_paths.include?(base_path)
- return mod
- end
-
- # Load the file at the provided path. +const_paths+ is a set of qualified
- # constant names. When loading the file, Dependencies will watch for the
- # addition of these constants. Each that is defined will be marked as
- # autoloaded, and will be removed when Dependencies.clear is next called.
- #
- # If the second parameter is left off, then Dependencies will construct a set
- # of names that the file at +path+ may define. See
- # +loadable_constants_for_path+ for more details.
- def load_file(path, const_paths = loadable_constants_for_path(path))
- log_call path, const_paths
- const_paths = [const_paths].compact unless const_paths.is_a? Array
- parent_paths = const_paths.collect { |const_path| /(.*)::[^:]+\Z/ =~ const_path ? $1 : :Object }
-
- result = nil
- newly_defined_paths = new_constants_in(*parent_paths) do
- result = load_without_new_constant_marking path
+ # Does the provided path_suffix correspond to an autoloadable module?
+ # Instead of returning a boolean, the autoload base for this module is returned.
+ def autoloadable_module?(path_suffix)
+ load_paths.each do |load_path|
+ return load_path if File.directory? File.join(load_path, path_suffix)
+ end
+ nil
end
- autoloaded_constants.concat newly_defined_paths unless load_once_path?(path)
- autoloaded_constants.uniq!
- log "loading #{path} defined #{newly_defined_paths * ', '}" unless newly_defined_paths.empty?
- return result
- end
+ def load_once_path?(path)
+ load_once_paths.any? { |base| path.starts_with? base }
+ end
- # Return the constant path for the provided parent and constant name.
- def qualified_name_for(mod, name)
- mod_name = to_constant_name mod
- (%w(Object Kernel).include? mod_name) ? name.to_s : "#{mod_name}::#{name}"
- end
+ # Attempt to autoload the provided module name by searching for a directory
+ # matching the expect path suffix. If found, the module is created and assigned
+ # to +into+'s constants with the name +const_name+. Provided that the directory
+ # was loaded from a reloadable base path, it is added to the set of constants
+ # that are to be unloaded.
+ def autoload_module!(into, const_name, qualified_name, path_suffix)
+ return nil unless base_path = autoloadable_module?(path_suffix)
+ mod = Module.new
+ into.const_set const_name, mod
+ autoloaded_constants << qualified_name unless load_once_paths.include?(base_path)
+ return mod
+ end
- # Load the constant named +const_name+ which is missing from +from_mod+. If
- # it is not possible to load the constant into from_mod, try its parent module
- # using const_missing.
- def load_missing_constant(from_mod, const_name)
- log_call from_mod, const_name
- if from_mod == Kernel
- if ::Object.const_defined?(const_name)
- log "Returning Object::#{const_name} for Kernel::#{const_name}"
- return ::Object.const_get(const_name)
- else
- log "Substituting Object for Kernel"
- from_mod = Object
+ # Load the file at the provided path. +const_paths+ is a set of qualified
+ # constant names. When loading the file, Dependencies will watch for the
+ # addition of these constants. Each that is defined will be marked as
+ # autoloaded, and will be removed when Dependencies.clear is next called.
+ #
+ # If the second parameter is left off, then Dependencies will construct a set
+ # of names that the file at +path+ may define. See
+ # +loadable_constants_for_path+ for more details.
+ def load_file(path, const_paths = loadable_constants_for_path(path))
+ log_call path, const_paths
+ const_paths = [const_paths].compact unless const_paths.is_a? Array
+ parent_paths = const_paths.collect { |const_path| /(.*)::[^:]+\Z/ =~ const_path ? $1 : :Object }
+
+ result = nil
+ newly_defined_paths = new_constants_in(*parent_paths) do
+ result = load_without_new_constant_marking path
end
- end
- # If we have an anonymous module, all we can do is attempt to load from Object.
- from_mod = Object if from_mod.name.blank?
+ autoloaded_constants.concat newly_defined_paths unless load_once_path?(path)
+ autoloaded_constants.uniq!
+ log "loading #{path} defined #{newly_defined_paths * ', '}" unless newly_defined_paths.empty?
+ return result
+ end
- unless qualified_const_defined?(from_mod.name) && from_mod.name.constantize.object_id == from_mod.object_id
- raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!"
+ # Return the constant path for the provided parent and constant name.
+ def qualified_name_for(mod, name)
+ mod_name = to_constant_name mod
+ (%w(Object Kernel).include? mod_name) ? name.to_s : "#{mod_name}::#{name}"
end
- raise ArgumentError, "#{from_mod} is not missing constant #{const_name}!" if uninherited_const_defined?(from_mod, const_name)
+ # Load the constant named +const_name+ which is missing from +from_mod+. If
+ # it is not possible to load the constant into from_mod, try its parent module
+ # using const_missing.
+ def load_missing_constant(from_mod, const_name)
+ log_call from_mod, const_name
+ if from_mod == Kernel
+ if ::Object.const_defined?(const_name)
+ log "Returning Object::#{const_name} for Kernel::#{const_name}"
+ return ::Object.const_get(const_name)
+ else
+ log "Substituting Object for Kernel"
+ from_mod = Object
+ end
+ end
- qualified_name = qualified_name_for from_mod, const_name
- path_suffix = qualified_name.underscore
- name_error = NameError.new("uninitialized constant #{qualified_name}")
+ # If we have an anonymous module, all we can do is attempt to load from Object.
+ from_mod = Object if from_mod.name.blank?
- file_path = search_for_file(path_suffix)
- if file_path && ! loaded.include?(File.expand_path(file_path)) # We found a matching file to load
- require_or_load file_path
- raise LoadError, "Expected #{file_path} to define #{qualified_name}" unless uninherited_const_defined?(from_mod, const_name)
- return from_mod.const_get(const_name)
- elsif mod = autoload_module!(from_mod, const_name, qualified_name, path_suffix)
- return mod
- elsif (parent = from_mod.parent) && parent != from_mod &&
- ! from_mod.parents.any? { |p| uninherited_const_defined?(p, const_name) }
- # If our parents do not have a constant named +const_name+ then we are free
- # to attempt to load upwards. If they do have such a constant, then this
- # const_missing must be due to from_mod::const_name, which should not
- # return constants from from_mod's parents.
- begin
- return parent.const_missing(const_name)
- rescue NameError => e
- raise unless e.missing_name? qualified_name_for(parent, const_name)
+ unless qualified_const_defined?(from_mod.name) && from_mod.name.constantize.object_id == from_mod.object_id
+ raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!"
+ end
+
+ raise ArgumentError, "#{from_mod} is not missing constant #{const_name}!" if uninherited_const_defined?(from_mod, const_name)
+
+ qualified_name = qualified_name_for from_mod, const_name
+ path_suffix = qualified_name.underscore
+ name_error = NameError.new("uninitialized constant #{qualified_name}")
+
+ file_path = search_for_file(path_suffix)
+ if file_path && ! loaded.include?(File.expand_path(file_path)) # We found a matching file to load
+ require_or_load file_path
+ raise LoadError, "Expected #{file_path} to define #{qualified_name}" unless uninherited_const_defined?(from_mod, const_name)
+ return from_mod.const_get(const_name)
+ elsif mod = autoload_module!(from_mod, const_name, qualified_name, path_suffix)
+ return mod
+ elsif (parent = from_mod.parent) && parent != from_mod &&
+ ! from_mod.parents.any? { |p| uninherited_const_defined?(p, const_name) }
+ # If our parents do not have a constant named +const_name+ then we are free
+ # to attempt to load upwards. If they do have such a constant, then this
+ # const_missing must be due to from_mod::const_name, which should not
+ # return constants from from_mod's parents.
+ begin
+ return parent.const_missing(const_name)
+ rescue NameError => e
+ raise unless e.missing_name? qualified_name_for(parent, const_name)
+ raise name_error
+ end
+ else
raise name_error
end
- else
- raise name_error
end
- end
- # Remove the constants that have been autoloaded, and those that have been
- # marked for unloading.
- def remove_unloadable_constants!
- autoloaded_constants.each { |const| remove_constant const }
- autoloaded_constants.clear
- explicitly_unloadable_constants.each { |const| remove_constant const }
- end
+ # Remove the constants that have been autoloaded, and those that have been
+ # marked for unloading.
+ def remove_unloadable_constants!
+ autoloaded_constants.each { |const| remove_constant const }
+ autoloaded_constants.clear
+ explicitly_unloadable_constants.each { |const| remove_constant const }
+ end
- # Determine if the given constant has been automatically loaded.
- def autoloaded?(desc)
- # No name => anonymous module.
- return false if desc.is_a?(Module) && desc.name.blank?
- name = to_constant_name desc
- return false unless qualified_const_defined? name
- return autoloaded_constants.include?(name)
- end
+ # Determine if the given constant has been automatically loaded.
+ def autoloaded?(desc)
+ # No name => anonymous module.
+ return false if desc.is_a?(Module) && desc.name.blank?
+ name = to_constant_name desc
+ return false unless qualified_const_defined? name
+ return autoloaded_constants.include?(name)
+ end
- # Will the provided constant descriptor be unloaded?
- def will_unload?(const_desc)
- autoloaded?(desc) ||
- explicitly_unloadable_constants.include?(to_constant_name(const_desc))
- end
+ # Will the provided constant descriptor be unloaded?
+ def will_unload?(const_desc)
+ autoloaded?(desc) ||
+ explicitly_unloadable_constants.include?(to_constant_name(const_desc))
+ end
- # Mark the provided constant name for unloading. This constant will be
- # unloaded on each request, not just the next one.
- def mark_for_unload(const_desc)
- name = to_constant_name const_desc
- if explicitly_unloadable_constants.include? name
- return false
- else
- explicitly_unloadable_constants << name
- return true
+ # Mark the provided constant name for unloading. This constant will be
+ # unloaded on each request, not just the next one.
+ def mark_for_unload(const_desc)
+ name = to_constant_name const_desc
+ if explicitly_unloadable_constants.include? name
+ return false
+ else
+ explicitly_unloadable_constants << name
+ return true
+ end
end
- end
- # Run the provided block and detect the new constants that were loaded during
- # its execution. Constants may only be regarded as 'new' once -- so if the
- # block calls +new_constants_in+ again, then the constants defined within the
- # inner call will not be reported in this one.
- #
- # If the provided block does not run to completion, and instead raises an
- # exception, any new constants are regarded as being only partially defined
- # and will be removed immediately.
- def new_constants_in(*descs)
- log_call(*descs)
-
- # Build the watch frames. Each frame is a tuple of
- # [module_name_as_string, constants_defined_elsewhere]
- watch_frames = descs.collect do |desc|
- if desc.is_a? Module
- mod_name = desc.name
- initial_constants = desc.local_constant_names
- elsif desc.is_a?(String) || desc.is_a?(Symbol)
- mod_name = desc.to_s
-
- # Handle the case where the module has yet to be defined.
- initial_constants = if qualified_const_defined?(mod_name)
- mod_name.constantize.local_constant_names
+ # Run the provided block and detect the new constants that were loaded during
+ # its execution. Constants may only be regarded as 'new' once -- so if the
+ # block calls +new_constants_in+ again, then the constants defined within the
+ # inner call will not be reported in this one.
+ #
+ # If the provided block does not run to completion, and instead raises an
+ # exception, any new constants are regarded as being only partially defined
+ # and will be removed immediately.
+ def new_constants_in(*descs)
+ log_call(*descs)
+
+ # Build the watch frames. Each frame is a tuple of
+ # [module_name_as_string, constants_defined_elsewhere]
+ watch_frames = descs.collect do |desc|
+ if desc.is_a? Module
+ mod_name = desc.name
+ initial_constants = desc.local_constant_names
+ elsif desc.is_a?(String) || desc.is_a?(Symbol)
+ mod_name = desc.to_s
+
+ # Handle the case where the module has yet to be defined.
+ initial_constants = if qualified_const_defined?(mod_name)
+ mod_name.constantize.local_constant_names
+ else
+ []
+ end
else
- []
+ raise Argument, "#{desc.inspect} does not describe a module!"
end
- else
- raise Argument, "#{desc.inspect} does not describe a module!"
- end
- [mod_name, initial_constants]
- end
+ [mod_name, initial_constants]
+ end
- constant_watch_stack.concat watch_frames
+ constant_watch_stack.concat watch_frames
- aborting = true
- begin
- yield # Now yield to the code that is to define new constants.
- aborting = false
- ensure
- # Find the new constants.
- new_constants = watch_frames.collect do |mod_name, prior_constants|
- # Module still doesn't exist? Treat it as if it has no constants.
- next [] unless qualified_const_defined?(mod_name)
-
- mod = mod_name.constantize
- next [] unless mod.is_a? Module
- new_constants = mod.local_constant_names - prior_constants
-
- # Make sure no other frames takes credit for these constants.
- constant_watch_stack.each do |frame_name, constants|
- constants.concat new_constants if frame_name == mod_name
+ aborting = true
+ begin
+ yield # Now yield to the code that is to define new constants.
+ aborting = false
+ ensure
+ # Find the new constants.
+ new_constants = watch_frames.collect do |mod_name, prior_constants|
+ # Module still doesn't exist? Treat it as if it has no constants.
+ next [] unless qualified_const_defined?(mod_name)
+
+ mod = mod_name.constantize
+ next [] unless mod.is_a? Module
+ new_constants = mod.local_constant_names - prior_constants
+
+ # Make sure no other frames takes credit for these constants.
+ constant_watch_stack.each do |frame_name, constants|
+ constants.concat new_constants if frame_name == mod_name
+ end
+
+ new_constants.collect do |suffix|
+ mod_name == "Object" ? suffix : "#{mod_name}::#{suffix}"
+ end
+ end.flatten
+
+ log "New constants: #{new_constants * ', '}"
+
+ if aborting
+ log "Error during loading, removing partially loaded constants "
+ new_constants.each { |name| remove_constant name }
+ new_constants.clear
end
+ end
- new_constants.collect do |suffix|
- mod_name == "Object" ? suffix : "#{mod_name}::#{suffix}"
+ return new_constants
+ ensure
+ # Remove the stack frames that we added.
+ if defined?(watch_frames) && ! watch_frames.blank?
+ frame_ids = watch_frames.collect(&:object_id)
+ constant_watch_stack.delete_if do |watch_frame|
+ frame_ids.include? watch_frame.object_id
end
- end.flatten
-
- log "New constants: #{new_constants * ', '}"
-
- if aborting
- log "Error during loading, removing partially loaded constants "
- new_constants.each { |name| remove_constant name }
- new_constants.clear
end
end
- return new_constants
- ensure
- # Remove the stack frames that we added.
- if defined?(watch_frames) && ! watch_frames.blank?
- frame_ids = watch_frames.collect(&:object_id)
- constant_watch_stack.delete_if do |watch_frame|
- frame_ids.include? watch_frame.object_id
+ class LoadingModule #:nodoc:
+ # Old style environment.rb referenced this method directly. Please note, it doesn't
+ # actually *do* anything any more.
+ def self.root(*args)
+ if defined?(RAILS_DEFAULT_LOGGER)
+ RAILS_DEFAULT_LOGGER.warn "Your environment.rb uses the old syntax, it may not continue to work in future releases."
+ RAILS_DEFAULT_LOGGER.warn "For upgrade instructions please see: http://manuals.rubyonrails.com/read/book/19"
+ end
end
end
- end
- class LoadingModule #:nodoc:
- # Old style environment.rb referenced this method directly. Please note, it doesn't
- # actually *do* anything any more.
- def self.root(*args)
- if defined?(RAILS_DEFAULT_LOGGER)
- RAILS_DEFAULT_LOGGER.warn "Your environment.rb uses the old syntax, it may not continue to work in future releases."
- RAILS_DEFAULT_LOGGER.warn "For upgrade instructions please see: http://manuals.rubyonrails.com/read/book/19"
+ # Convert the provided const desc to a qualified constant name (as a string).
+ # A module, class, symbol, or string may be provided.
+ def to_constant_name(desc) #:nodoc:
+ name = case desc
+ when String then desc.starts_with?('::') ? desc[2..-1] : desc
+ when Symbol then desc.to_s
+ when Module
+ raise ArgumentError, "Anonymous modules have no name to be referenced by" if desc.name.blank?
+ desc.name
+ else raise TypeError, "Not a valid constant descriptor: #{desc.inspect}"
end
end
- end
- # Convert the provided const desc to a qualified constant name (as a string).
- # A module, class, symbol, or string may be provided.
- def to_constant_name(desc) #:nodoc:
- name = case desc
- when String then desc.starts_with?('::') ? desc[2..-1] : desc
- when Symbol then desc.to_s
- when Module
- raise ArgumentError, "Anonymous modules have no name to be referenced by" if desc.name.blank?
- desc.name
- else raise TypeError, "Not a valid constant descriptor: #{desc.inspect}"
- end
- end
+ def remove_constant(const) #:nodoc:
+ return false unless qualified_const_defined? const
- def remove_constant(const) #:nodoc:
- return false unless qualified_const_defined? const
+ const = $1 if /\A::(.*)\Z/ =~ const.to_s
+ names = const.to_s.split('::')
+ if names.size == 1 # It's under Object
+ parent = Object
+ else
+ parent = (names[0..-2] * '::').constantize
+ end
- const = $1 if /\A::(.*)\Z/ =~ const.to_s
- names = const.to_s.split('::')
- if names.size == 1 # It's under Object
- parent = Object
- else
- parent = (names[0..-2] * '::').constantize
+ log "removing constant #{const}"
+ parent.instance_eval { remove_const names.last }
+ return true
end
- log "removing constant #{const}"
- parent.instance_eval { remove_const names.last }
- return true
- end
-
-protected
- def log_call(*args)
- if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER && log_activity
- arg_str = args.collect(&:inspect) * ', '
- /in `([a-z_\?\!]+)'/ =~ caller(1).first
- selector = $1 || '<unknown>'
- log "called #{selector}(#{arg_str})"
- end
- end
+ protected
+ def log_call(*args)
+ if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER && log_activity
+ arg_str = args.collect(&:inspect) * ', '
+ /in `([a-z_\?\!]+)'/ =~ caller(1).first
+ selector = $1 || '<unknown>'
+ log "called #{selector}(#{arg_str})"
+ end
+ end
- def log(msg)
- if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER && log_activity
- RAILS_DEFAULT_LOGGER.debug "Dependencies: #{msg}"
- end
+ def log(msg)
+ if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER && log_activity
+ RAILS_DEFAULT_LOGGER.debug "Dependencies: #{msg}"
+ end
+ end
end
-
end
Object.instance_eval do
- define_method(:require_or_load) { |file_name| Dependencies.require_or_load(file_name) } unless Object.respond_to?(:require_or_load)
- define_method(:require_dependency) { |file_name| Dependencies.depend_on(file_name) } unless Object.respond_to?(:require_dependency)
- define_method(:require_association) { |file_name| Dependencies.associate_with(file_name) } unless Object.respond_to?(:require_association)
+ define_method(:require_or_load) { |file_name| ActiveSupport::Dependencies.require_or_load(file_name) } unless Object.respond_to?(:require_or_load)
+ define_method(:require_dependency) { |file_name| ActiveSupport::Dependencies.depend_on(file_name) } unless Object.respond_to?(:require_dependency)
+ define_method(:require_association) { |file_name| ActiveSupport::Dependencies.associate_with(file_name) } unless Object.respond_to?(:require_association)
end
class Module #:nodoc:
@@ -464,7 +465,7 @@ class Module #:nodoc:
# Use const_missing to autoload associations so we don't have to
# require_association when using single-table inheritance.
def const_missing(class_id)
- Dependencies.load_missing_constant self, class_id
+ ActiveSupport::Dependencies.load_missing_constant self, class_id
end
def unloadable(const_desc = self)
@@ -480,15 +481,15 @@ class Class
else
begin
begin
- Dependencies.load_missing_constant self, const_name
+ ActiveSupport::Dependencies.load_missing_constant self, const_name
rescue NameError
parent.send :const_missing, const_name
end
rescue NameError => e
# Make sure that the name we are missing is the one that caused the error
- parent_qualified_name = Dependencies.qualified_name_for parent, const_name
+ parent_qualified_name = ActiveSupport::Dependencies.qualified_name_for parent, const_name
raise unless e.missing_name? parent_qualified_name
- qualified_name = Dependencies.qualified_name_for self, const_name
+ qualified_name = ActiveSupport::Dependencies.qualified_name_for self, const_name
raise NameError.new("uninitialized constant #{qualified_name}").copy_blame!(e)
end
end
@@ -499,14 +500,14 @@ class Object
alias_method :load_without_new_constant_marking, :load
def load(file, *extras) #:nodoc:
- Dependencies.new_constants_in(Object) { super }
+ ActiveSupport::Dependencies.new_constants_in(Object) { super }
rescue Exception => exception # errors from loading file
exception.blame_file! file
raise
end
def require(file, *extras) #:nodoc:
- Dependencies.new_constants_in(Object) { super }
+ ActiveSupport::Dependencies.new_constants_in(Object) { super }
rescue Exception => exception # errors from required file
exception.blame_file! file
raise
@@ -526,7 +527,7 @@ class Object
# Returns true if the constant was not previously marked for unloading, false
# otherwise.
def unloadable(const_desc)
- Dependencies.mark_for_unload const_desc
+ ActiveSupport::Dependencies.mark_for_unload const_desc
end
end
diff --git a/activesupport/lib/active_support/deprecation.rb b/activesupport/lib/active_support/deprecation.rb
index 758aef5445..ebdaf86146 100644
--- a/activesupport/lib/active_support/deprecation.rb
+++ b/activesupport/lib/active_support/deprecation.rb
@@ -144,17 +144,11 @@ module ActiveSupport
end
end
- # Stand-in for <tt>@request</tt>, <tt>@attributes</tt>, <tt>@params</tt>, etc.
- # which emits deprecation warnings on any method call (except +inspect+).
- class DeprecatedInstanceVariableProxy #:nodoc:
+ class DeprecationProxy #:nodoc:
silence_warnings do
instance_methods.each { |m| undef_method m unless m =~ /^__/ }
end
- def initialize(instance, method, var = "@#{method}")
- @instance, @method, @var = instance, method, var
- end
-
# Don't give a deprecation warning on inspect since test/unit and error
# logs rely on it for diagnostics.
def inspect
@@ -166,7 +160,16 @@ module ActiveSupport
warn caller, called, args
target.__send__(called, *args, &block)
end
+ end
+ # Stand-in for <tt>@request</tt>, <tt>@attributes</tt>, <tt>@params</tt>, etc.
+ # which emits deprecation warnings on any method call (except +inspect+).
+ class DeprecatedInstanceVariableProxy < DeprecationProxy #:nodoc:
+ def initialize(instance, method, var = "@#{method}")
+ @instance, @method, @var = instance, method, var
+ end
+
+ private
def target
@instance.__send__(@method)
end
@@ -176,6 +179,21 @@ module ActiveSupport
end
end
+ class DeprecatedConstantProxy < DeprecationProxy #:nodoc:
+ def initialize(old_const, new_const)
+ @old_const = old_const
+ @new_const = new_const
+ end
+
+ private
+ def target
+ @new_const.to_s.constantize
+ end
+
+ def warn(callstack, called, args)
+ ActiveSupport::Deprecation.warn("#{@old_const} is deprecated! Use #{@new_const} instead.", callstack)
+ end
+ end
end
end
diff --git a/activesupport/lib/active_support/inflections.rb b/activesupport/lib/active_support/inflections.rb
index 967722c2bf..b6d276953a 100644
--- a/activesupport/lib/active_support/inflections.rb
+++ b/activesupport/lib/active_support/inflections.rb
@@ -1,53 +1,55 @@
-Inflector.inflections do |inflect|
- inflect.plural(/$/, 's')
- inflect.plural(/s$/i, 's')
- inflect.plural(/(ax|test)is$/i, '\1es')
- inflect.plural(/(octop|vir)us$/i, '\1i')
- inflect.plural(/(alias|status)$/i, '\1es')
- inflect.plural(/(bu)s$/i, '\1ses')
- inflect.plural(/(buffal|tomat)o$/i, '\1oes')
- inflect.plural(/([ti])um$/i, '\1a')
- inflect.plural(/sis$/i, 'ses')
- inflect.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
- inflect.plural(/(hive)$/i, '\1s')
- inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies')
- inflect.plural(/(x|ch|ss|sh)$/i, '\1es')
- inflect.plural(/(matr|vert|ind)(?:ix|ex)$/i, '\1ices')
- inflect.plural(/([m|l])ouse$/i, '\1ice')
- inflect.plural(/^(ox)$/i, '\1en')
- inflect.plural(/(quiz)$/i, '\1zes')
+module ActiveSupport
+ Inflector.inflections do |inflect|
+ inflect.plural(/$/, 's')
+ inflect.plural(/s$/i, 's')
+ inflect.plural(/(ax|test)is$/i, '\1es')
+ inflect.plural(/(octop|vir)us$/i, '\1i')
+ inflect.plural(/(alias|status)$/i, '\1es')
+ inflect.plural(/(bu)s$/i, '\1ses')
+ inflect.plural(/(buffal|tomat)o$/i, '\1oes')
+ inflect.plural(/([ti])um$/i, '\1a')
+ inflect.plural(/sis$/i, 'ses')
+ inflect.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
+ inflect.plural(/(hive)$/i, '\1s')
+ inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies')
+ inflect.plural(/(x|ch|ss|sh)$/i, '\1es')
+ inflect.plural(/(matr|vert|ind)(?:ix|ex)$/i, '\1ices')
+ inflect.plural(/([m|l])ouse$/i, '\1ice')
+ inflect.plural(/^(ox)$/i, '\1en')
+ inflect.plural(/(quiz)$/i, '\1zes')
- inflect.singular(/s$/i, '')
- inflect.singular(/(n)ews$/i, '\1ews')
- inflect.singular(/([ti])a$/i, '\1um')
- inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, '\1\2sis')
- inflect.singular(/(^analy)ses$/i, '\1sis')
- inflect.singular(/([^f])ves$/i, '\1fe')
- inflect.singular(/(hive)s$/i, '\1')
- inflect.singular(/(tive)s$/i, '\1')
- inflect.singular(/([lr])ves$/i, '\1f')
- inflect.singular(/([^aeiouy]|qu)ies$/i, '\1y')
- inflect.singular(/(s)eries$/i, '\1eries')
- inflect.singular(/(m)ovies$/i, '\1ovie')
- inflect.singular(/(x|ch|ss|sh)es$/i, '\1')
- inflect.singular(/([m|l])ice$/i, '\1ouse')
- inflect.singular(/(bus)es$/i, '\1')
- inflect.singular(/(o)es$/i, '\1')
- inflect.singular(/(shoe)s$/i, '\1')
- inflect.singular(/(cris|ax|test)es$/i, '\1is')
- inflect.singular(/(octop|vir)i$/i, '\1us')
- inflect.singular(/(alias|status)es$/i, '\1')
- inflect.singular(/^(ox)en/i, '\1')
- inflect.singular(/(vert|ind)ices$/i, '\1ex')
- inflect.singular(/(matr)ices$/i, '\1ix')
- inflect.singular(/(quiz)zes$/i, '\1')
+ inflect.singular(/s$/i, '')
+ inflect.singular(/(n)ews$/i, '\1ews')
+ inflect.singular(/([ti])a$/i, '\1um')
+ inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, '\1\2sis')
+ inflect.singular(/(^analy)ses$/i, '\1sis')
+ inflect.singular(/([^f])ves$/i, '\1fe')
+ inflect.singular(/(hive)s$/i, '\1')
+ inflect.singular(/(tive)s$/i, '\1')
+ inflect.singular(/([lr])ves$/i, '\1f')
+ inflect.singular(/([^aeiouy]|qu)ies$/i, '\1y')
+ inflect.singular(/(s)eries$/i, '\1eries')
+ inflect.singular(/(m)ovies$/i, '\1ovie')
+ inflect.singular(/(x|ch|ss|sh)es$/i, '\1')
+ inflect.singular(/([m|l])ice$/i, '\1ouse')
+ inflect.singular(/(bus)es$/i, '\1')
+ inflect.singular(/(o)es$/i, '\1')
+ inflect.singular(/(shoe)s$/i, '\1')
+ inflect.singular(/(cris|ax|test)es$/i, '\1is')
+ inflect.singular(/(octop|vir)i$/i, '\1us')
+ inflect.singular(/(alias|status)es$/i, '\1')
+ inflect.singular(/^(ox)en/i, '\1')
+ inflect.singular(/(vert|ind)ices$/i, '\1ex')
+ inflect.singular(/(matr)ices$/i, '\1ix')
+ inflect.singular(/(quiz)zes$/i, '\1')
- inflect.irregular('person', 'people')
- inflect.irregular('man', 'men')
- inflect.irregular('child', 'children')
- inflect.irregular('sex', 'sexes')
- inflect.irregular('move', 'moves')
- inflect.irregular('cow', 'kine')
+ inflect.irregular('person', 'people')
+ inflect.irregular('man', 'men')
+ inflect.irregular('child', 'children')
+ inflect.irregular('sex', 'sexes')
+ inflect.irregular('move', 'moves')
+ inflect.irregular('cow', 'kine')
- inflect.uncountable(%w(equipment information rice money species series fish sheep))
+ inflect.uncountable(%w(equipment information rice money species series fish sheep))
+ end
end
diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb
index d7f44cb2b9..47bd6e1767 100644
--- a/activesupport/lib/active_support/inflector.rb
+++ b/activesupport/lib/active_support/inflector.rb
@@ -1,308 +1,310 @@
require 'singleton'
-# The Inflector transforms words from singular to plural, class names to table names, modularized class names to ones without,
-# and class names to foreign keys. The default inflections for pluralization, singularization, and uncountable words are kept
-# in inflections.rb.
-#
-# The Rails core team has stated patches for the inflections library will not be accepted
-# in order to avoid breaking legacy applications which may be relying on errant inflections.
-# If you discover an incorrect inflection and require it for your application, you'll need
-# to correct it yourself (explained below).
-module Inflector
- # A singleton instance of this class is yielded by Inflector.inflections, which can then be used to specify additional
- # inflection rules. Examples:
+module ActiveSupport
+ # The Inflector transforms words from singular to plural, class names to table names, modularized class names to ones without,
+ # and class names to foreign keys. The default inflections for pluralization, singularization, and uncountable words are kept
+ # in inflections.rb.
#
- # Inflector.inflections do |inflect|
- # inflect.plural /^(ox)$/i, '\1\2en'
- # inflect.singular /^(ox)en/i, '\1'
- #
- # inflect.irregular 'octopus', 'octopi'
- #
- # inflect.uncountable "equipment"
- # end
- #
- # New rules are added at the top. So in the example above, the irregular rule for octopus will now be the first of the
- # pluralization and singularization rules that is runs. This guarantees that your rules run before any of the rules that may
- # already have been loaded.
- class Inflections
- include Singleton
+ # The Rails core team has stated patches for the inflections library will not be accepted
+ # in order to avoid breaking legacy applications which may be relying on errant inflections.
+ # If you discover an incorrect inflection and require it for your application, you'll need
+ # to correct it yourself (explained below).
+ module Inflector
+ extend self
- attr_reader :plurals, :singulars, :uncountables
+ # A singleton instance of this class is yielded by Inflector.inflections, which can then be used to specify additional
+ # inflection rules. Examples:
+ #
+ # ActiveSupport::Inflector.inflections do |inflect|
+ # inflect.plural /^(ox)$/i, '\1\2en'
+ # inflect.singular /^(ox)en/i, '\1'
+ #
+ # inflect.irregular 'octopus', 'octopi'
+ #
+ # inflect.uncountable "equipment"
+ # end
+ #
+ # New rules are added at the top. So in the example above, the irregular rule for octopus will now be the first of the
+ # pluralization and singularization rules that is runs. This guarantees that your rules run before any of the rules that may
+ # already have been loaded.
+ class Inflections
+ include Singleton
- def initialize
- @plurals, @singulars, @uncountables = [], [], []
- end
+ attr_reader :plurals, :singulars, :uncountables
+
+ def initialize
+ @plurals, @singulars, @uncountables = [], [], []
+ end
+
+ # Specifies a new pluralization rule and its replacement. The rule can either be a string or a regular expression.
+ # The replacement should always be a string that may include references to the matched data from the rule.
+ def plural(rule, replacement)
+ @plurals.insert(0, [rule, replacement])
+ end
+
+ # Specifies a new singularization rule and its replacement. The rule can either be a string or a regular expression.
+ # The replacement should always be a string that may include references to the matched data from the rule.
+ def singular(rule, replacement)
+ @singulars.insert(0, [rule, replacement])
+ end
+
+ # Specifies a new irregular that applies to both pluralization and singularization at the same time. This can only be used
+ # for strings, not regular expressions. You simply pass the irregular in singular and plural form.
+ #
+ # Examples:
+ # irregular 'octopus', 'octopi'
+ # irregular 'person', 'people'
+ def irregular(singular, plural)
+ if singular[0,1].upcase == plural[0,1].upcase
+ plural(Regexp.new("(#{singular[0,1]})#{singular[1..-1]}$", "i"), '\1' + plural[1..-1])
+ singular(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + singular[1..-1])
+ else
+ plural(Regexp.new("#{singular[0,1].upcase}(?i)#{singular[1..-1]}$"), plural[0,1].upcase + plural[1..-1])
+ plural(Regexp.new("#{singular[0,1].downcase}(?i)#{singular[1..-1]}$"), plural[0,1].downcase + plural[1..-1])
+ singular(Regexp.new("#{plural[0,1].upcase}(?i)#{plural[1..-1]}$"), singular[0,1].upcase + singular[1..-1])
+ singular(Regexp.new("#{plural[0,1].downcase}(?i)#{plural[1..-1]}$"), singular[0,1].downcase + singular[1..-1])
+ end
+ end
- # Specifies a new pluralization rule and its replacement. The rule can either be a string or a regular expression.
- # The replacement should always be a string that may include references to the matched data from the rule.
- def plural(rule, replacement)
- @plurals.insert(0, [rule, replacement])
+ # Add uncountable words that shouldn't be attempted inflected.
+ #
+ # Examples:
+ # uncountable "money"
+ # uncountable "money", "information"
+ # uncountable %w( money information rice )
+ def uncountable(*words)
+ (@uncountables << words).flatten!
+ end
+
+ # Clears the loaded inflections within a given scope (default is <tt>:all</tt>).
+ # Give the scope as a symbol of the inflection type, the options are: <tt>:plurals</tt>,
+ # <tt>:singulars</tt>, <tt>:uncountables</tt>.
+ #
+ # Examples:
+ # clear :all
+ # clear :plurals
+ def clear(scope = :all)
+ case scope
+ when :all
+ @plurals, @singulars, @uncountables = [], [], []
+ else
+ instance_variable_set "@#{scope}", []
+ end
+ end
end
- # Specifies a new singularization rule and its replacement. The rule can either be a string or a regular expression.
- # The replacement should always be a string that may include references to the matched data from the rule.
- def singular(rule, replacement)
- @singulars.insert(0, [rule, replacement])
+ # Yields a singleton instance of Inflector::Inflections so you can specify additional
+ # inflector rules.
+ #
+ # Example:
+ # ActiveSupport::Inflector.inflections do |inflect|
+ # inflect.uncountable "rails"
+ # end
+ def inflections
+ if block_given?
+ yield Inflections.instance
+ else
+ Inflections.instance
+ end
end
- # Specifies a new irregular that applies to both pluralization and singularization at the same time. This can only be used
- # for strings, not regular expressions. You simply pass the irregular in singular and plural form.
+ # Returns the plural form of the word in the string.
#
# Examples:
- # irregular 'octopus', 'octopi'
- # irregular 'person', 'people'
- def irregular(singular, plural)
- if singular[0,1].upcase == plural[0,1].upcase
- plural(Regexp.new("(#{singular[0,1]})#{singular[1..-1]}$", "i"), '\1' + plural[1..-1])
- singular(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + singular[1..-1])
+ # "post".pluralize # => "posts"
+ # "octopus".pluralize # => "octopi"
+ # "sheep".pluralize # => "sheep"
+ # "words".pluralize # => "words"
+ # "the blue mailman".pluralize # => "the blue mailmen"
+ # "CamelOctopus".pluralize # => "CamelOctopi"
+ def pluralize(word)
+ result = word.to_s.dup
+
+ if word.empty? || inflections.uncountables.include?(result.downcase)
+ result
else
- plural(Regexp.new("#{singular[0,1].upcase}(?i)#{singular[1..-1]}$"), plural[0,1].upcase + plural[1..-1])
- plural(Regexp.new("#{singular[0,1].downcase}(?i)#{singular[1..-1]}$"), plural[0,1].downcase + plural[1..-1])
- singular(Regexp.new("#{plural[0,1].upcase}(?i)#{plural[1..-1]}$"), singular[0,1].upcase + singular[1..-1])
- singular(Regexp.new("#{plural[0,1].downcase}(?i)#{plural[1..-1]}$"), singular[0,1].downcase + singular[1..-1])
+ inflections.plurals.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
+ result
end
end
- # Add uncountable words that shouldn't be attempted inflected.
+ # The reverse of +pluralize+, returns the singular form of a word in a string.
#
# Examples:
- # uncountable "money"
- # uncountable "money", "information"
- # uncountable %w( money information rice )
- def uncountable(*words)
- (@uncountables << words).flatten!
+ # "posts".singularize # => "post"
+ # "octopi".singularize # => "octopus"
+ # "sheep".singluarize # => "sheep"
+ # "word".singularize # => "word"
+ # "the blue mailmen".singularize # => "the blue mailman"
+ # "CamelOctopi".singularize # => "CamelOctopus"
+ def singularize(word)
+ result = word.to_s.dup
+
+ if inflections.uncountables.include?(result.downcase)
+ result
+ else
+ inflections.singulars.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
+ result
+ end
end
- # Clears the loaded inflections within a given scope (default is <tt>:all</tt>).
- # Give the scope as a symbol of the inflection type, the options are: <tt>:plurals</tt>,
- # <tt>:singulars</tt>, <tt>:uncountables</tt>.
+ # By default, +camelize+ converts strings to UpperCamelCase. If the argument to +camelize+
+ # is set to <tt>:lower</tt> then +camelize+ produces lowerCamelCase.
+ #
+ # +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
#
# Examples:
- # clear :all
- # clear :plurals
- def clear(scope = :all)
- case scope
- when :all
- @plurals, @singulars, @uncountables = [], [], []
- else
- instance_variable_set "@#{scope}", []
+ # "active_record".camelize # => "ActiveRecord"
+ # "active_record".camelize(:lower) # => "activeRecord"
+ # "active_record/errors".camelize # => "ActiveRecord::Errors"
+ # "active_record/errors".camelize(:lower) # => "activeRecord::Errors"
+ def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
+ if first_letter_in_uppercase
+ lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
+ else
+ lower_case_and_underscored_word.first + camelize(lower_case_and_underscored_word)[1..-1]
end
end
- end
-
- extend self
- # Yields a singleton instance of Inflector::Inflections so you can specify additional
- # inflector rules.
- #
- # Example:
- # Inflector.inflections do |inflect|
- # inflect.uncountable "rails"
- # end
- def inflections
- if block_given?
- yield Inflections.instance
- else
- Inflections.instance
+ # Capitalizes all the words and replaces some characters in the string to create
+ # a nicer looking title. +titleize+ is meant for creating pretty output. It is not
+ # used in the Rails internals.
+ #
+ # +titleize+ is also aliased as as +titlecase+.
+ #
+ # Examples:
+ # "man from the boondocks".titleize # => "Man From The Boondocks"
+ # "x-men: the last stand".titleize # => "X Men: The Last Stand"
+ def titleize(word)
+ humanize(underscore(word)).gsub(/\b('?[a-z])/) { $1.capitalize }
end
- end
-
- # Returns the plural form of the word in the string.
- #
- # Examples:
- # "post".pluralize # => "posts"
- # "octopus".pluralize # => "octopi"
- # "sheep".pluralize # => "sheep"
- # "words".pluralize # => "words"
- # "the blue mailman".pluralize # => "the blue mailmen"
- # "CamelOctopus".pluralize # => "CamelOctopi"
- def pluralize(word)
- result = word.to_s.dup
- if word.empty? || inflections.uncountables.include?(result.downcase)
- result
- else
- inflections.plurals.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
- result
+ # The reverse of +camelize+. Makes an underscored, lowercase form from the expression in the string.
+ #
+ # Changes '::' to '/' to convert namespaces to paths.
+ #
+ # Examples:
+ # "ActiveRecord".underscore # => "active_record"
+ # "ActiveRecord::Errors".underscore # => active_record/errors
+ def underscore(camel_cased_word)
+ camel_cased_word.to_s.gsub(/::/, '/').
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
+ tr("-", "_").
+ downcase
end
- end
-
- # The reverse of +pluralize+, returns the singular form of a word in a string.
- #
- # Examples:
- # "posts".singularize # => "post"
- # "octopi".singularize # => "octopus"
- # "sheep".singularize # => "sheep"
- # "word".singularize # => "word"
- # "the blue mailmen".singularize # => "the blue mailman"
- # "CamelOctopi".singularize # => "CamelOctopus"
- def singularize(word)
- result = word.to_s.dup
- if inflections.uncountables.include?(result.downcase)
- result
- else
- inflections.singulars.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
- result
+ # Replaces underscores with dashes in the string.
+ #
+ # Example:
+ # "puni_puni" # => "puni-puni"
+ def dasherize(underscored_word)
+ underscored_word.gsub(/_/, '-')
end
- end
- # By default, +camelize+ converts strings to UpperCamelCase. If the argument to +camelize+
- # is set to <tt>:lower</tt> then +camelize+ produces lowerCamelCase.
- #
- # +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
- #
- # Examples:
- # "active_record".camelize # => "ActiveRecord"
- # "active_record".camelize(:lower) # => "activeRecord"
- # "active_record/errors".camelize # => "ActiveRecord::Errors"
- # "active_record/errors".camelize(:lower) # => "activeRecord::Errors"
- def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
- if first_letter_in_uppercase
- lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
- else
- lower_case_and_underscored_word.first + camelize(lower_case_and_underscored_word)[1..-1]
+ # Capitalizes the first word and turns underscores into spaces and strips a
+ # trailing "_id", if any. Like +titleize+, this is meant for creating pretty output.
+ #
+ # Examples:
+ # "employee_salary" # => "Employee salary"
+ # "author_id" # => "Author"
+ def humanize(lower_case_and_underscored_word)
+ lower_case_and_underscored_word.to_s.gsub(/_id$/, "").gsub(/_/, " ").capitalize
end
- end
- # Capitalizes all the words and replaces some characters in the string to create
- # a nicer looking title. +titleize+ is meant for creating pretty output. It is not
- # used in the Rails internals.
- #
- # +titleize+ is also aliased as as +titlecase+.
- #
- # Examples:
- # "man from the boondocks".titleize # => "Man From The Boondocks"
- # "x-men: the last stand".titleize # => "X Men: The Last Stand"
- def titleize(word)
- humanize(underscore(word)).gsub(/\b('?[a-z])/) { $1.capitalize }
- end
-
- # The reverse of +camelize+. Makes an underscored, lowercase form from the expression in the string.
- #
- # Changes '::' to '/' to convert namespaces to paths.
- #
- # Examples:
- # "ActiveRecord".underscore # => "active_record"
- # "ActiveRecord::Errors".underscore # => active_record/errors
- def underscore(camel_cased_word)
- camel_cased_word.to_s.gsub(/::/, '/').
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
- tr("-", "_").
- downcase
- end
-
- # Replaces underscores with dashes in the string.
- #
- # Example:
- # "puni_puni" # => "puni-puni"
- def dasherize(underscored_word)
- underscored_word.gsub(/_/, '-')
- end
-
- # Capitalizes the first word and turns underscores into spaces and strips a
- # trailing "_id", if any. Like +titleize+, this is meant for creating pretty output.
- #
- # Examples:
- # "employee_salary" # => "Employee salary"
- # "author_id" # => "Author"
- def humanize(lower_case_and_underscored_word)
- lower_case_and_underscored_word.to_s.gsub(/_id$/, "").gsub(/_/, " ").capitalize
- end
+ # Removes the module part from the expression in the string.
+ #
+ # Examples:
+ # "ActiveRecord::CoreExtensions::String::Inflections".demodulize # => "Inflections"
+ # "Inflections".demodulize # => "Inflections"
+ def demodulize(class_name_in_module)
+ class_name_in_module.to_s.gsub(/^.*::/, '')
+ end
- # Removes the module part from the expression in the string.
- #
- # Examples:
- # "ActiveRecord::CoreExtensions::String::Inflections".demodulize # => "Inflections"
- # "Inflections".demodulize # => "Inflections"
- def demodulize(class_name_in_module)
- class_name_in_module.to_s.gsub(/^.*::/, '')
- end
+ # Create the name of a table like Rails does for models to table names. This method
+ # uses the +pluralize+ method on the last word in the string.
+ #
+ # Examples
+ # "RawScaledScorer".tableize # => "raw_scaled_scorers"
+ # "egg_and_ham".tableize # => "egg_and_hams"
+ # "fancyCategory".tableize # => "fancy_categories"
+ def tableize(class_name)
+ pluralize(underscore(class_name))
+ end
- # Create the name of a table like Rails does for models to table names. This method
- # uses the +pluralize+ method on the last word in the string.
- #
- # Examples
- # "RawScaledScorer".tableize # => "raw_scaled_scorers"
- # "egg_and_ham".tableize # => "egg_and_hams"
- # "fancyCategory".tableize # => "fancy_categories"
- def tableize(class_name)
- pluralize(underscore(class_name))
- end
+ # Create a class name from a plural table name like Rails does for table names to models.
+ # Note that this returns a string and not a Class. (To convert to an actual class
+ # follow +classify+ with +constantize+.)
+ #
+ # Examples:
+ # "egg_and_hams".classify # => "EggAndHam"
+ # "posts".classify # => "Post"
+ #
+ # Singular names are not handled correctly:
+ # "business".classify # => "Busines"
+ def classify(table_name)
+ # strip out any leading schema name
+ camelize(singularize(table_name.to_s.sub(/.*\./, '')))
+ end
- # Create a class name from a plural table name like Rails does for table names to models.
- # Note that this returns a string and not a Class. (To convert to an actual class
- # follow +classify+ with +constantize+.)
- #
- # Examples:
- # "egg_and_hams".classify # => "EggAndHam"
- # "posts".classify # => "Post"
- #
- # Singular names are not handled correctly:
- # "business".classify # => "Busines"
- def classify(table_name)
- # strip out any leading schema name
- camelize(singularize(table_name.to_s.sub(/.*\./, '')))
- end
+ # Creates a foreign key name from a class name.
+ # +separate_class_name_and_id_with_underscore+ sets whether
+ # the method should put '_' between the name and 'id'.
+ #
+ # Examples:
+ # "Message".foreign_key # => "message_id"
+ # "Message".foreign_key(false) # => "messageid"
+ # "Admin::Post".foreign_key # => "post_id"
+ def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
+ underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
+ end
- # Creates a foreign key name from a class name.
- # +separate_class_name_and_id_with_underscore+ sets whether
- # the method should put '_' between the name and 'id'.
- #
- # Examples:
- # "Message".foreign_key # => "message_id"
- # "Message".foreign_key(false) # => "messageid"
- # "Admin::Post".foreign_key # => "post_id"
- def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
- underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
- end
+ # Tries to find a constant with the name specified in the argument string:
+ #
+ # "Module".constantize # => Module
+ # "Test::Unit".constantize # => Test::Unit
+ #
+ # The name is assumed to be the one of a top-level constant, no matter whether
+ # it starts with "::" or not. No lexical context is taken into account:
+ #
+ # C = 'outside'
+ # module M
+ # C = 'inside'
+ # C # => 'inside'
+ # "C".constantize # => 'outside', same as ::C
+ # end
+ #
+ # NameError is raised when the name is not in CamelCase or the constant is
+ # unknown.
+ def constantize(camel_cased_word)
+ unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word
+ raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
+ end
- # Tries to find a constant with the name specified in the argument string:
- #
- # "Module".constantize # => Module
- # "Test::Unit".constantize # => Test::Unit
- #
- # The name is assumed to be the one of a top-level constant, no matter whether
- # it starts with "::" or not. No lexical context is taken into account:
- #
- # C = 'outside'
- # module M
- # C = 'inside'
- # C # => 'inside'
- # "C".constantize # => 'outside', same as ::C
- # end
- #
- # NameError is raised when the name is not in CamelCase or the constant is
- # unknown.
- def constantize(camel_cased_word)
- unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word
- raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
+ Object.module_eval("::#{$1}", __FILE__, __LINE__)
end
- Object.module_eval("::#{$1}", __FILE__, __LINE__)
- end
-
- # Turns a number into an ordinal string used to denote the position in an
- # ordered sequence such as 1st, 2nd, 3rd, 4th.
- #
- # Examples:
- # ordinalize(1) # => "1st"
- # ordinalize(2) # => "2nd"
- # ordinalize(1002) # => "1002nd"
- # ordinalize(1003) # => "1003rd"
- def ordinalize(number)
- if (11..13).include?(number.to_i % 100)
- "#{number}th"
- else
- case number.to_i % 10
- when 1; "#{number}st"
- when 2; "#{number}nd"
- when 3; "#{number}rd"
- else "#{number}th"
+ # Turns a number into an ordinal string used to denote the position in an
+ # ordered sequence such as 1st, 2nd, 3rd, 4th.
+ #
+ # Examples:
+ # ordinalize(1) # => "1st"
+ # ordinalize(2) # => "2nd"
+ # ordinalize(1002) # => "1002nd"
+ # ordinalize(1003) # => "1003rd"
+ def ordinalize(number)
+ if (11..13).include?(number.to_i % 100)
+ "#{number}th"
+ else
+ case number.to_i % 10
+ when 1; "#{number}st"
+ when 2; "#{number}nd"
+ when 3; "#{number}rd"
+ else "#{number}th"
+ end
end
end
end
end
-require File.dirname(__FILE__) + '/inflections'
+require 'active_support/inflections'
diff --git a/activesupport/lib/active_support/ordered_hash.rb b/activesupport/lib/active_support/ordered_hash.rb
index 6993621ef9..9757054e43 100644
--- a/activesupport/lib/active_support/ordered_hash.rb
+++ b/activesupport/lib/active_support/ordered_hash.rb
@@ -12,6 +12,7 @@ module ActiveSupport
else
self << [key, value]
end
+ value
end
def [](key)
@@ -38,6 +39,20 @@ module ActiveSupport
each { |array| hash[array[0]] = array[1] }
end
end
+
+ def has_key?(k)
+ !assoc(k).nil?
+ end
+
+ alias_method :key?, :has_key?
+ alias_method :include?, :has_key?
+ alias_method :member?, :has_key?
+
+ def has_value?(v)
+ any? { |key, value| value == v }
+ end
+
+ alias_method :value?, :has_value?
end
end
end
diff --git a/activesupport/lib/active_support/ordered_options.rb b/activesupport/lib/active_support/ordered_options.rb
index 306376e9ae..642045186f 100644
--- a/activesupport/lib/active_support/ordered_options.rb
+++ b/activesupport/lib/active_support/ordered_options.rb
@@ -1,17 +1,19 @@
-class OrderedOptions < ActiveSupport::OrderedHash #:nodoc:
- def []=(key, value)
- super(key.to_sym, value)
- end
+module ActiveSupport #:nodoc:
+ class OrderedOptions < OrderedHash #:nodoc:
+ def []=(key, value)
+ super(key.to_sym, value)
+ end
- def [](key)
- super(key.to_sym)
- end
+ def [](key)
+ super(key.to_sym)
+ end
- def method_missing(name, *args)
- if name.to_s =~ /(.*)=$/
- self[$1.to_sym] = args.first
- else
- self[name]
+ def method_missing(name, *args)
+ if name.to_s =~ /(.*)=$/
+ self[$1.to_sym] = args.first
+ else
+ self[name]
+ end
end
end
end
diff --git a/activesupport/lib/active_support/string_inquirer.rb b/activesupport/lib/active_support/string_inquirer.rb
new file mode 100644
index 0000000000..65545748df
--- /dev/null
+++ b/activesupport/lib/active_support/string_inquirer.rb
@@ -0,0 +1,11 @@
+module ActiveSupport
+ class StringInquirer < String
+ def method_missing(method_name, *arguments)
+ if method_name.to_s.ends_with?("?")
+ self == method_name.to_s[0..-2]
+ else
+ super
+ end
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb
index 67cde1556c..2fd02d5313 100644
--- a/activesupport/lib/active_support/test_case.rb
+++ b/activesupport/lib/active_support/test_case.rb
@@ -9,5 +9,14 @@ end
module ActiveSupport
class TestCase < Test::Unit::TestCase
+ # test "verify something" do
+ # ...
+ # end
+ def self.test(name, &block)
+ test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
+ defined = instance_method(test_name) rescue false
+ raise "#{test_name} is already defined in #{self}" if defined
+ define_method(test_name, &block)
+ end
end
end
diff --git a/activesupport/lib/active_support/testing/performance.rb b/activesupport/lib/active_support/testing/performance.rb
new file mode 100644
index 0000000000..5f2027eb3b
--- /dev/null
+++ b/activesupport/lib/active_support/testing/performance.rb
@@ -0,0 +1,397 @@
+require 'rubygems'
+gem 'ruby-prof', '>= 0.6.1'
+require 'ruby-prof'
+
+require 'fileutils'
+require 'rails/version'
+
+module ActiveSupport
+ module Testing
+ module Performance
+ DEFAULTS =
+ if benchmark = ARGV.include?('--benchmark') # HAX for rake test
+ { :benchmark => true,
+ :runs => 10,
+ :metrics => [:process_time, :memory, :objects, :gc_runs, :gc_time],
+ :output => 'tmp/performance' }
+ else
+ { :benchmark => false,
+ :runs => 1,
+ :min_percent => 0.02,
+ :metrics => [:process_time, :memory, :objects],
+ :formats => [:flat, :graph_html, :call_tree],
+ :output => 'tmp/performance' }
+ end
+
+ def self.included(base)
+ base.class_inheritable_hash :profile_options
+ base.profile_options = DEFAULTS.dup
+ end
+
+ def full_test_name
+ "#{self.class.name}##{method_name}"
+ end
+
+ def run(result)
+ return if method_name =~ /^default_test$/
+
+ yield(self.class::STARTED, name)
+ @_result = result
+
+ run_warmup
+ profile_options[:metrics].each do |metric_name|
+ if klass = Metrics[metric_name.to_sym]
+ run_profile(klass.new)
+ result.add_run
+ else
+ $stderr.puts '%20s: unsupported' % metric_name.to_s
+ end
+ end
+
+ yield(self.class::FINISHED, name)
+ end
+
+ def run_test(metric, mode)
+ run_callbacks :setup
+ setup
+ metric.send(mode) { __send__ @method_name }
+ rescue ::Test::Unit::AssertionFailedError => e
+ add_failure(e.message, e.backtrace)
+ rescue StandardError, ScriptError
+ add_error($!)
+ ensure
+ begin
+ teardown
+ run_callbacks :teardown, :enumerator => :reverse_each
+ rescue ::Test::Unit::AssertionFailedError => e
+ add_failure(e.message, e.backtrace)
+ rescue StandardError, ScriptError
+ add_error($!)
+ end
+ end
+
+ protected
+ def run_warmup
+ 5.times { GC.start }
+
+ time = Metrics::Time.new
+ run_test(time, :benchmark)
+ puts "%s (%s warmup)" % [full_test_name, time.format(time.total)]
+
+ 5.times { GC.start }
+ end
+
+ def run_profile(metric)
+ klass = profile_options[:benchmark] ? Benchmarker : Profiler
+ performer = klass.new(self, metric)
+
+ performer.run
+ puts performer.report
+ performer.record
+ end
+
+ class Performer
+ delegate :run_test, :profile_options, :full_test_name, :to => :@harness
+
+ def initialize(harness, metric)
+ @harness, @metric = harness, metric
+ end
+
+ def report
+ rate = @total / profile_options[:runs]
+ '%20s: %s' % [@metric.name, @metric.format(rate)]
+ end
+
+ protected
+ def output_filename
+ "#{profile_options[:output]}/#{full_test_name}_#{@metric.name}"
+ end
+ end
+
+ class Benchmarker < Performer
+ def run
+ profile_options[:runs].to_i.times { run_test(@metric, :benchmark) }
+ @total = @metric.total
+ end
+
+ def record
+ avg = @metric.total / profile_options[:runs].to_i
+ now = Time.now.utc.xmlschema
+ with_output_file do |file|
+ file.puts "#{avg},#{now},#{environment}"
+ end
+ end
+
+ def environment
+ unless defined? @env
+ app = "#{$1}.#{$2}" if `git branch -v` =~ /^\* (\S+)\s+(\S+)/
+
+ rails = Rails::VERSION::STRING
+ if File.directory?('vendor/rails/.git')
+ Dir.chdir('vendor/rails') do
+ rails += ".#{$1}.#{$2}" if `git branch -v` =~ /^\* (\S+)\s+(\S+)/
+ end
+ end
+
+ ruby = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
+ ruby += "-#{RUBY_VERSION}.#{RUBY_PATCHLEVEL}"
+
+ @env = [app, rails, ruby, RUBY_PLATFORM] * ','
+ end
+
+ @env
+ end
+
+ protected
+ HEADER = 'measurement,created_at,app,rails,ruby,platform'
+
+ def with_output_file
+ fname = output_filename
+
+ if new = !File.exist?(fname)
+ FileUtils.mkdir_p(File.dirname(fname))
+ end
+
+ File.open(fname, 'ab') do |file|
+ file.puts(HEADER) if new
+ yield file
+ end
+ end
+
+ def output_filename
+ "#{super}.csv"
+ end
+ end
+
+ class Profiler < Performer
+ def run
+ RubyProf.measure_mode = @metric.measure_mode
+ RubyProf.start
+ RubyProf.pause
+ profile_options[:runs].to_i.times { run_test(@metric, :profile) }
+ @data = RubyProf.stop
+ @total = @data.threads.values.sum(0) { |method_infos| method_infos.sort.last.total_time }
+ end
+
+ def record
+ klasses = profile_options[:formats].map { |f| RubyProf.const_get("#{f.to_s.camelize}Printer") }.compact
+
+ klasses.each do |klass|
+ fname = output_filename(klass)
+ FileUtils.mkdir_p(File.dirname(fname))
+ File.open(fname, 'wb') do |file|
+ klass.new(@data).print(file, profile_options.slice(:min_percent))
+ end
+ end
+ end
+
+ protected
+ def output_filename(printer_class)
+ suffix =
+ case printer_class.name.demodulize
+ when 'FlatPrinter'; 'flat.txt'
+ when 'GraphPrinter'; 'graph.txt'
+ when 'GraphHtmlPrinter'; 'graph.html'
+ when 'CallTreePrinter'; 'tree.txt'
+ else printer_class.name.sub(/Printer$/, '').underscore
+ end
+
+ "#{super()}_#{suffix}"
+ end
+ end
+
+ module Metrics
+ def self.[](name)
+ klass = const_get(name.to_s.camelize)
+ klass if klass::Mode
+ rescue NameError
+ nil
+ end
+
+ class Base
+ attr_reader :total
+
+ def initialize
+ @total = 0
+ end
+
+ def name
+ @name ||= self.class.name.demodulize.underscore
+ end
+
+ def measure_mode
+ self.class::Mode
+ end
+
+ def measure
+ 0
+ end
+
+ def benchmark
+ with_gc_stats do
+ before = measure
+ yield
+ @total += (measure - before)
+ end
+ end
+
+ def profile
+ RubyProf.resume
+ yield
+ ensure
+ RubyProf.pause
+ end
+
+ protected
+ if GC.respond_to?(:enable_stats)
+ def with_gc_stats
+ GC.enable_stats
+ yield
+ ensure
+ GC.disable_stats
+ end
+ else
+ def with_gc_stats
+ yield
+ end
+ end
+ end
+
+ class Time < Base
+ def measure
+ ::Time.now.to_f
+ end
+
+ def format(measurement)
+ if measurement < 2
+ '%d ms' % (measurement * 1000)
+ else
+ '%.2f sec' % measurement
+ end
+ end
+ end
+
+ class ProcessTime < Time
+ Mode = RubyProf::PROCESS_TIME
+
+ def measure
+ RubyProf.measure_process_time
+ end
+ end
+
+ class WallTime < Time
+ Mode = RubyProf::WALL_TIME
+
+ def measure
+ RubyProf.measure_wall_time
+ end
+ end
+
+ class CpuTime < Time
+ Mode = RubyProf::CPU_TIME if RubyProf.const_defined?(:CPU_TIME)
+
+ def initialize(*args)
+ # FIXME: yeah my CPU is 2.33 GHz
+ RubyProf.cpu_frequency = 2.33e9
+ super
+ end
+
+ def measure
+ RubyProf.measure_cpu_time
+ end
+ end
+
+ class Memory < Base
+ Mode = RubyProf::MEMORY if RubyProf.const_defined?(:MEMORY)
+
+ # ruby-prof wrapper
+ if RubyProf.respond_to?(:measure_memory)
+ def measure
+ RubyProf.measure_memory / 1024.0
+ end
+
+ # Ruby 1.8 + adymo patch
+ elsif GC.respond_to?(:allocated_size)
+ def measure
+ GC.allocated_size / 1024.0
+ end
+
+ # Ruby 1.8 + lloyd patch
+ elsif GC.respond_to?(:heap_info)
+ def measure
+ GC.heap_info['heap_current_memory'] / 1024.0
+ end
+
+ # Ruby 1.9 unpatched
+ elsif GC.respond_to?(:malloc_allocated_size)
+ def measure
+ GC.malloc_allocated_size / 1024.0
+ end
+ end
+
+ def format(measurement)
+ '%.2f KB' % measurement
+ end
+ end
+
+ class Objects < Base
+ Mode = RubyProf::ALLOCATIONS if RubyProf.const_defined?(:ALLOCATIONS)
+
+ if RubyProf.respond_to?(:measure_allocations)
+ def measure
+ RubyProf.measure_allocations
+ end
+ elsif ObjectSpace.respond_to?(:allocated_objects)
+ def measure
+ ObjectSpace.allocated_objects
+ end
+ end
+
+ def format(measurement)
+ measurement.to_i.to_s
+ end
+ end
+
+ class GcRuns < Base
+ Mode = RubyProf::GC_RUNS if RubyProf.const_defined?(:GC_RUNS)
+
+ if RubyProf.respond_to?(:measure_gc_runs)
+ def measure
+ RubyProf.measure_gc_runs
+ end
+ elsif GC.respond_to?(:collections)
+ def measure
+ GC.collections
+ end
+ elsif GC.respond_to?(:heap_info)
+ def measure
+ GC.heap_info['num_gc_passes']
+ end
+ end
+
+ def format(measurement)
+ measurement.to_i.to_s
+ end
+ end
+
+ class GcTime < Base
+ Mode = RubyProf::GC_TIME if RubyProf.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
diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb
index ed8e34510a..21d71eb92a 100644
--- a/activesupport/lib/active_support/testing/setup_and_teardown.rb
+++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb
@@ -10,19 +10,43 @@ module ActiveSupport
end
def self.included(base)
- base.send :include, ActiveSupport::Callbacks
- base.define_callbacks :setup, :teardown
+ base.class_eval do
+ include ActiveSupport::Callbacks
+ define_callbacks :setup, :teardown
+ if defined?(::Mini)
+ alias_method :run, :run_with_callbacks_and_miniunit
+ else
+ begin
+ require 'mocha'
+ alias_method :run, :run_with_callbacks_and_mocha
+ rescue LoadError
+ alias_method :run, :run_with_callbacks_and_testunit
+ end
+ end
+ end
+ end
+
+ def run_with_callbacks_and_miniunit(runner)
+ result = '.'
begin
- require 'mocha'
- base.alias_method_chain :run, :callbacks_and_mocha
- rescue LoadError
- base.alias_method_chain :run, :callbacks
+ run_callbacks :setup
+ result = super
+ rescue Exception => e
+ result = runner.puke(self.class, self.name, e)
+ ensure
+ begin
+ teardown
+ run_callbacks :teardown, :enumerator => :reverse_each
+ rescue Exception => e
+ result = runner.puke(self.class, self.name, e)
+ end
end
+ result
end
# This redefinition is unfortunate but test/unit shows us no alternative.
- def run_with_callbacks(result) #:nodoc:
+ def run_with_callbacks_and_testunit(result) #:nodoc:
return if @method_name.to_s == "default_test"
yield(Test::Unit::TestCase::STARTED, name)
diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb
index 64d734f039..5b2d42aa3c 100644
--- a/activesupport/lib/active_support/values/time_zone.rb
+++ b/activesupport/lib/active_support/values/time_zone.rb
@@ -4,7 +4,7 @@
# * Retrieve and display zones with a friendlier name (e.g., "Eastern Time (US & Canada)" instead of "America/New_York").
# * Lazily load TZInfo::Timezone instances only when they're needed.
# * Create ActiveSupport::TimeWithZone instances via TimeZone's +local+, +parse+, +at+ and +now+ methods.
-#
+#
# If you set <tt>config.time_zone</tt> in the Rails Initializer, you can access this TimeZone object via <tt>Time.zone</tt>:
#
# # environment.rb:
@@ -16,379 +16,381 @@
# Time.zone.name # => "Eastern Time (US & Canada)"
# Time.zone.now # => Sun, 18 May 2008 14:30:44 EDT -04:00
#
-# The version of TZInfo bundled with Active Support only includes the definitions necessary to support the zones
+# The version of TZInfo bundled with Active Support only includes the definitions necessary to support the zones
# defined by the TimeZone class. If you need to use zones that aren't defined by TimeZone, you'll need to install the TZInfo gem
# (if a recent version of the gem is installed locally, this will be used instead of the bundled version.)
-class TimeZone
- unless const_defined?(:MAPPING)
- # Keys are Rails TimeZone names, values are TZInfo identifiers
- MAPPING = {
- "International Date Line West" => "Pacific/Midway",
- "Midway Island" => "Pacific/Midway",
- "Samoa" => "Pacific/Pago_Pago",
- "Hawaii" => "Pacific/Honolulu",
- "Alaska" => "America/Juneau",
- "Pacific Time (US & Canada)" => "America/Los_Angeles",
- "Tijuana" => "America/Tijuana",
- "Mountain Time (US & Canada)" => "America/Denver",
- "Arizona" => "America/Phoenix",
- "Chihuahua" => "America/Chihuahua",
- "Mazatlan" => "America/Mazatlan",
- "Central Time (US & Canada)" => "America/Chicago",
- "Saskatchewan" => "America/Regina",
- "Guadalajara" => "America/Mexico_City",
- "Mexico City" => "America/Mexico_City",
- "Monterrey" => "America/Monterrey",
- "Central America" => "America/Guatemala",
- "Eastern Time (US & Canada)" => "America/New_York",
- "Indiana (East)" => "America/Indiana/Indianapolis",
- "Bogota" => "America/Bogota",
- "Lima" => "America/Lima",
- "Quito" => "America/Lima",
- "Atlantic Time (Canada)" => "America/Halifax",
- "Caracas" => "America/Caracas",
- "La Paz" => "America/La_Paz",
- "Santiago" => "America/Santiago",
- "Newfoundland" => "America/St_Johns",
- "Brasilia" => "America/Argentina/Buenos_Aires",
- "Buenos Aires" => "America/Argentina/Buenos_Aires",
- "Georgetown" => "America/Argentina/San_Juan",
- "Greenland" => "America/Godthab",
- "Mid-Atlantic" => "Atlantic/South_Georgia",
- "Azores" => "Atlantic/Azores",
- "Cape Verde Is." => "Atlantic/Cape_Verde",
- "Dublin" => "Europe/Dublin",
- "Edinburgh" => "Europe/Dublin",
- "Lisbon" => "Europe/Lisbon",
- "London" => "Europe/London",
- "Casablanca" => "Africa/Casablanca",
- "Monrovia" => "Africa/Monrovia",
- "UTC" => "Etc/UTC",
- "Belgrade" => "Europe/Belgrade",
- "Bratislava" => "Europe/Bratislava",
- "Budapest" => "Europe/Budapest",
- "Ljubljana" => "Europe/Ljubljana",
- "Prague" => "Europe/Prague",
- "Sarajevo" => "Europe/Sarajevo",
- "Skopje" => "Europe/Skopje",
- "Warsaw" => "Europe/Warsaw",
- "Zagreb" => "Europe/Zagreb",
- "Brussels" => "Europe/Brussels",
- "Copenhagen" => "Europe/Copenhagen",
- "Madrid" => "Europe/Madrid",
- "Paris" => "Europe/Paris",
- "Amsterdam" => "Europe/Amsterdam",
- "Berlin" => "Europe/Berlin",
- "Bern" => "Europe/Berlin",
- "Rome" => "Europe/Rome",
- "Stockholm" => "Europe/Stockholm",
- "Vienna" => "Europe/Vienna",
- "West Central Africa" => "Africa/Algiers",
- "Bucharest" => "Europe/Bucharest",
- "Cairo" => "Africa/Cairo",
- "Helsinki" => "Europe/Helsinki",
- "Kyev" => "Europe/Kiev",
- "Riga" => "Europe/Riga",
- "Sofia" => "Europe/Sofia",
- "Tallinn" => "Europe/Tallinn",
- "Vilnius" => "Europe/Vilnius",
- "Athens" => "Europe/Athens",
- "Istanbul" => "Europe/Istanbul",
- "Minsk" => "Europe/Minsk",
- "Jerusalem" => "Asia/Jerusalem",
- "Harare" => "Africa/Harare",
- "Pretoria" => "Africa/Johannesburg",
- "Moscow" => "Europe/Moscow",
- "St. Petersburg" => "Europe/Moscow",
- "Volgograd" => "Europe/Moscow",
- "Kuwait" => "Asia/Kuwait",
- "Riyadh" => "Asia/Riyadh",
- "Nairobi" => "Africa/Nairobi",
- "Baghdad" => "Asia/Baghdad",
- "Tehran" => "Asia/Tehran",
- "Abu Dhabi" => "Asia/Muscat",
- "Muscat" => "Asia/Muscat",
- "Baku" => "Asia/Baku",
- "Tbilisi" => "Asia/Tbilisi",
- "Yerevan" => "Asia/Yerevan",
- "Kabul" => "Asia/Kabul",
- "Ekaterinburg" => "Asia/Yekaterinburg",
- "Islamabad" => "Asia/Karachi",
- "Karachi" => "Asia/Karachi",
- "Tashkent" => "Asia/Tashkent",
- "Chennai" => "Asia/Kolkata",
- "Kolkata" => "Asia/Kolkata",
- "Mumbai" => "Asia/Kolkata",
- "New Delhi" => "Asia/Kolkata",
- "Kathmandu" => "Asia/Katmandu",
- "Astana" => "Asia/Dhaka",
- "Dhaka" => "Asia/Dhaka",
- "Sri Jayawardenepura" => "Asia/Dhaka",
- "Almaty" => "Asia/Almaty",
- "Novosibirsk" => "Asia/Novosibirsk",
- "Rangoon" => "Asia/Rangoon",
- "Bangkok" => "Asia/Bangkok",
- "Hanoi" => "Asia/Bangkok",
- "Jakarta" => "Asia/Jakarta",
- "Krasnoyarsk" => "Asia/Krasnoyarsk",
- "Beijing" => "Asia/Shanghai",
- "Chongqing" => "Asia/Chongqing",
- "Hong Kong" => "Asia/Hong_Kong",
- "Urumqi" => "Asia/Urumqi",
- "Kuala Lumpur" => "Asia/Kuala_Lumpur",
- "Singapore" => "Asia/Singapore",
- "Taipei" => "Asia/Taipei",
- "Perth" => "Australia/Perth",
- "Irkutsk" => "Asia/Irkutsk",
- "Ulaan Bataar" => "Asia/Ulaanbaatar",
- "Seoul" => "Asia/Seoul",
- "Osaka" => "Asia/Tokyo",
- "Sapporo" => "Asia/Tokyo",
- "Tokyo" => "Asia/Tokyo",
- "Yakutsk" => "Asia/Yakutsk",
- "Darwin" => "Australia/Darwin",
- "Adelaide" => "Australia/Adelaide",
- "Canberra" => "Australia/Melbourne",
- "Melbourne" => "Australia/Melbourne",
- "Sydney" => "Australia/Sydney",
- "Brisbane" => "Australia/Brisbane",
- "Hobart" => "Australia/Hobart",
- "Vladivostok" => "Asia/Vladivostok",
- "Guam" => "Pacific/Guam",
- "Port Moresby" => "Pacific/Port_Moresby",
- "Magadan" => "Asia/Magadan",
- "Solomon Is." => "Asia/Magadan",
- "New Caledonia" => "Pacific/Noumea",
- "Fiji" => "Pacific/Fiji",
- "Kamchatka" => "Asia/Kamchatka",
- "Marshall Is." => "Pacific/Majuro",
- "Auckland" => "Pacific/Auckland",
- "Wellington" => "Pacific/Auckland",
- "Nuku'alofa" => "Pacific/Tongatapu"
- }.each { |name, zone| name.freeze; zone.freeze }
- MAPPING.freeze
- end
-
- include Comparable
- attr_reader :name
+module ActiveSupport
+ class TimeZone
+ unless const_defined?(:MAPPING)
+ # Keys are Rails TimeZone names, values are TZInfo identifiers
+ MAPPING = {
+ "International Date Line West" => "Pacific/Midway",
+ "Midway Island" => "Pacific/Midway",
+ "Samoa" => "Pacific/Pago_Pago",
+ "Hawaii" => "Pacific/Honolulu",
+ "Alaska" => "America/Juneau",
+ "Pacific Time (US & Canada)" => "America/Los_Angeles",
+ "Tijuana" => "America/Tijuana",
+ "Mountain Time (US & Canada)" => "America/Denver",
+ "Arizona" => "America/Phoenix",
+ "Chihuahua" => "America/Chihuahua",
+ "Mazatlan" => "America/Mazatlan",
+ "Central Time (US & Canada)" => "America/Chicago",
+ "Saskatchewan" => "America/Regina",
+ "Guadalajara" => "America/Mexico_City",
+ "Mexico City" => "America/Mexico_City",
+ "Monterrey" => "America/Monterrey",
+ "Central America" => "America/Guatemala",
+ "Eastern Time (US & Canada)" => "America/New_York",
+ "Indiana (East)" => "America/Indiana/Indianapolis",
+ "Bogota" => "America/Bogota",
+ "Lima" => "America/Lima",
+ "Quito" => "America/Lima",
+ "Atlantic Time (Canada)" => "America/Halifax",
+ "Caracas" => "America/Caracas",
+ "La Paz" => "America/La_Paz",
+ "Santiago" => "America/Santiago",
+ "Newfoundland" => "America/St_Johns",
+ "Brasilia" => "America/Argentina/Buenos_Aires",
+ "Buenos Aires" => "America/Argentina/Buenos_Aires",
+ "Georgetown" => "America/Argentina/San_Juan",
+ "Greenland" => "America/Godthab",
+ "Mid-Atlantic" => "Atlantic/South_Georgia",
+ "Azores" => "Atlantic/Azores",
+ "Cape Verde Is." => "Atlantic/Cape_Verde",
+ "Dublin" => "Europe/Dublin",
+ "Edinburgh" => "Europe/Dublin",
+ "Lisbon" => "Europe/Lisbon",
+ "London" => "Europe/London",
+ "Casablanca" => "Africa/Casablanca",
+ "Monrovia" => "Africa/Monrovia",
+ "UTC" => "Etc/UTC",
+ "Belgrade" => "Europe/Belgrade",
+ "Bratislava" => "Europe/Bratislava",
+ "Budapest" => "Europe/Budapest",
+ "Ljubljana" => "Europe/Ljubljana",
+ "Prague" => "Europe/Prague",
+ "Sarajevo" => "Europe/Sarajevo",
+ "Skopje" => "Europe/Skopje",
+ "Warsaw" => "Europe/Warsaw",
+ "Zagreb" => "Europe/Zagreb",
+ "Brussels" => "Europe/Brussels",
+ "Copenhagen" => "Europe/Copenhagen",
+ "Madrid" => "Europe/Madrid",
+ "Paris" => "Europe/Paris",
+ "Amsterdam" => "Europe/Amsterdam",
+ "Berlin" => "Europe/Berlin",
+ "Bern" => "Europe/Berlin",
+ "Rome" => "Europe/Rome",
+ "Stockholm" => "Europe/Stockholm",
+ "Vienna" => "Europe/Vienna",
+ "West Central Africa" => "Africa/Algiers",
+ "Bucharest" => "Europe/Bucharest",
+ "Cairo" => "Africa/Cairo",
+ "Helsinki" => "Europe/Helsinki",
+ "Kyev" => "Europe/Kiev",
+ "Riga" => "Europe/Riga",
+ "Sofia" => "Europe/Sofia",
+ "Tallinn" => "Europe/Tallinn",
+ "Vilnius" => "Europe/Vilnius",
+ "Athens" => "Europe/Athens",
+ "Istanbul" => "Europe/Istanbul",
+ "Minsk" => "Europe/Minsk",
+ "Jerusalem" => "Asia/Jerusalem",
+ "Harare" => "Africa/Harare",
+ "Pretoria" => "Africa/Johannesburg",
+ "Moscow" => "Europe/Moscow",
+ "St. Petersburg" => "Europe/Moscow",
+ "Volgograd" => "Europe/Moscow",
+ "Kuwait" => "Asia/Kuwait",
+ "Riyadh" => "Asia/Riyadh",
+ "Nairobi" => "Africa/Nairobi",
+ "Baghdad" => "Asia/Baghdad",
+ "Tehran" => "Asia/Tehran",
+ "Abu Dhabi" => "Asia/Muscat",
+ "Muscat" => "Asia/Muscat",
+ "Baku" => "Asia/Baku",
+ "Tbilisi" => "Asia/Tbilisi",
+ "Yerevan" => "Asia/Yerevan",
+ "Kabul" => "Asia/Kabul",
+ "Ekaterinburg" => "Asia/Yekaterinburg",
+ "Islamabad" => "Asia/Karachi",
+ "Karachi" => "Asia/Karachi",
+ "Tashkent" => "Asia/Tashkent",
+ "Chennai" => "Asia/Kolkata",
+ "Kolkata" => "Asia/Kolkata",
+ "Mumbai" => "Asia/Kolkata",
+ "New Delhi" => "Asia/Kolkata",
+ "Kathmandu" => "Asia/Katmandu",
+ "Astana" => "Asia/Dhaka",
+ "Dhaka" => "Asia/Dhaka",
+ "Sri Jayawardenepura" => "Asia/Dhaka",
+ "Almaty" => "Asia/Almaty",
+ "Novosibirsk" => "Asia/Novosibirsk",
+ "Rangoon" => "Asia/Rangoon",
+ "Bangkok" => "Asia/Bangkok",
+ "Hanoi" => "Asia/Bangkok",
+ "Jakarta" => "Asia/Jakarta",
+ "Krasnoyarsk" => "Asia/Krasnoyarsk",
+ "Beijing" => "Asia/Shanghai",
+ "Chongqing" => "Asia/Chongqing",
+ "Hong Kong" => "Asia/Hong_Kong",
+ "Urumqi" => "Asia/Urumqi",
+ "Kuala Lumpur" => "Asia/Kuala_Lumpur",
+ "Singapore" => "Asia/Singapore",
+ "Taipei" => "Asia/Taipei",
+ "Perth" => "Australia/Perth",
+ "Irkutsk" => "Asia/Irkutsk",
+ "Ulaan Bataar" => "Asia/Ulaanbaatar",
+ "Seoul" => "Asia/Seoul",
+ "Osaka" => "Asia/Tokyo",
+ "Sapporo" => "Asia/Tokyo",
+ "Tokyo" => "Asia/Tokyo",
+ "Yakutsk" => "Asia/Yakutsk",
+ "Darwin" => "Australia/Darwin",
+ "Adelaide" => "Australia/Adelaide",
+ "Canberra" => "Australia/Melbourne",
+ "Melbourne" => "Australia/Melbourne",
+ "Sydney" => "Australia/Sydney",
+ "Brisbane" => "Australia/Brisbane",
+ "Hobart" => "Australia/Hobart",
+ "Vladivostok" => "Asia/Vladivostok",
+ "Guam" => "Pacific/Guam",
+ "Port Moresby" => "Pacific/Port_Moresby",
+ "Magadan" => "Asia/Magadan",
+ "Solomon Is." => "Asia/Magadan",
+ "New Caledonia" => "Pacific/Noumea",
+ "Fiji" => "Pacific/Fiji",
+ "Kamchatka" => "Asia/Kamchatka",
+ "Marshall Is." => "Pacific/Majuro",
+ "Auckland" => "Pacific/Auckland",
+ "Wellington" => "Pacific/Auckland",
+ "Nuku'alofa" => "Pacific/Tongatapu"
+ }.each { |name, zone| name.freeze; zone.freeze }
+ MAPPING.freeze
+ end
- # Create a new TimeZone object with the given name and offset. The
- # offset is the number of seconds that this time zone is offset from UTC
- # (GMT). Seconds were chosen as the offset unit because that is the unit that
- # Ruby uses to represent time zone offsets (see Time#utc_offset).
- def initialize(name, utc_offset, tzinfo = nil)
- @name = name
- @utc_offset = utc_offset
- @tzinfo = tzinfo
- end
+ include Comparable
+ attr_reader :name
- def utc_offset
- @utc_offset ||= tzinfo.current_period.utc_offset
- end
-
- # Returns the offset of this time zone as a formatted string, of the
- # format "+HH:MM".
- def formatted_offset(colon=true, alternate_utc_string = nil)
- utc_offset == 0 && alternate_utc_string || utc_offset.to_utc_offset_s(colon)
- end
+ # Create a new TimeZone object with the given name and offset. The
+ # offset is the number of seconds that this time zone is offset from UTC
+ # (GMT). Seconds were chosen as the offset unit because that is the unit that
+ # Ruby uses to represent time zone offsets (see Time#utc_offset).
+ def initialize(name, utc_offset, tzinfo = nil)
+ @name = name
+ @utc_offset = utc_offset
+ @tzinfo = tzinfo
+ end
- # Compare this time zone to the parameter. The two are compared first on
- # their offsets, and then by name.
- def <=>(zone)
- result = (utc_offset <=> zone.utc_offset)
- result = (name <=> zone.name) if result == 0
- result
- end
+ def utc_offset
+ @utc_offset ||= tzinfo.current_period.utc_offset
+ end
- # Returns a textual representation of this time zone.
- def to_s
- "(GMT#{formatted_offset}) #{name}"
- end
+ # Returns the offset of this time zone as a formatted string, of the
+ # format "+HH:MM".
+ def formatted_offset(colon=true, alternate_utc_string = nil)
+ utc_offset == 0 && alternate_utc_string || utc_offset.to_utc_offset_s(colon)
+ end
- # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from given values. Example:
- #
- # Time.zone = "Hawaii" # => "Hawaii"
- # Time.zone.local(2007, 2, 1, 15, 30, 45) # => Thu, 01 Feb 2007 15:30:45 HST -10:00
- def local(*args)
- time = Time.utc_time(*args)
- ActiveSupport::TimeWithZone.new(nil, self, time)
- end
+ # Compare this time zone to the parameter. The two are comapred first on
+ # their offsets, and then by name.
+ def <=>(zone)
+ result = (utc_offset <=> zone.utc_offset)
+ result = (name <=> zone.name) if result == 0
+ result
+ end
- # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from number of seconds since the Unix epoch. Example:
- #
- # Time.zone = "Hawaii" # => "Hawaii"
- # Time.utc(2000).to_f # => 946684800.0
- # Time.zone.at(946684800.0) # => Fri, 31 Dec 1999 14:00:00 HST -10:00
- def at(secs)
- utc = Time.at(secs).utc rescue DateTime.civil(1970).since(secs)
- utc.in_time_zone(self)
- end
+ # Returns a textual representation of this time zone.
+ def to_s
+ "(GMT#{formatted_offset}) #{name}"
+ end
- # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from parsed string. Example:
- #
- # Time.zone = "Hawaii" # => "Hawaii"
- # Time.zone.parse('1999-12-31 14:00:00') # => Fri, 31 Dec 1999 14:00:00 HST -10:00
- #
- # If upper components are missing from the string, they are supplied from TimeZone#now:
- #
- # Time.zone.now # => Fri, 31 Dec 1999 14:00:00 HST -10:00
- # Time.zone.parse('22:30:00') # => Fri, 31 Dec 1999 22:30:00 HST -10:00
- def parse(str, now=now)
- date_parts = Date._parse(str)
- return if date_parts.blank?
- time = Time.parse(str, now) rescue DateTime.parse(str)
- if date_parts[:offset].nil?
+ # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from given values. Example:
+ #
+ # Time.zone = "Hawaii" # => "Hawaii"
+ # Time.zone.local(2007, 2, 1, 15, 30, 45) # => Thu, 01 Feb 2007 15:30:45 HST -10:00
+ def local(*args)
+ time = Time.utc_time(*args)
ActiveSupport::TimeWithZone.new(nil, self, time)
- else
- time.in_time_zone(self)
end
- end
- # Returns an ActiveSupport::TimeWithZone instance representing the current time
- # in the time zone represented by +self+. Example:
- #
- # Time.zone = 'Hawaii' # => "Hawaii"
- # Time.zone.now # => Wed, 23 Jan 2008 20:24:27 HST -10:00
- def now
- Time.now.utc.in_time_zone(self)
- end
+ # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from number of seconds since the Unix epoch. Example:
+ #
+ # Time.zone = "Hawaii" # => "Hawaii"
+ # Time.utc(2000).to_f # => 946684800.0
+ # Time.zone.at(946684800.0) # => Fri, 31 Dec 1999 14:00:00 HST -10:00
+ def at(secs)
+ utc = Time.at(secs).utc rescue DateTime.civil(1970).since(secs)
+ utc.in_time_zone(self)
+ end
- # Return the current date in this time zone.
- def today
- tzinfo.now.to_date
- end
+ # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from parsed string. Example:
+ #
+ # Time.zone = "Hawaii" # => "Hawaii"
+ # Time.zone.parse('1999-12-31 14:00:00') # => Fri, 31 Dec 1999 14:00:00 HST -10:00
+ #
+ # If upper components are missing from the string, they are supplied from TimeZone#now:
+ #
+ # Time.zone.now # => Fri, 31 Dec 1999 14:00:00 HST -10:00
+ # Time.zone.parse('22:30:00') # => Fri, 31 Dec 1999 22:30:00 HST -10:00
+ def parse(str, now=now)
+ date_parts = Date._parse(str)
+ return if date_parts.blank?
+ time = Time.parse(str, now) rescue DateTime.parse(str)
+ if date_parts[:offset].nil?
+ ActiveSupport::TimeWithZone.new(nil, self, time)
+ else
+ time.in_time_zone(self)
+ end
+ end
- # Adjust the given time to the simultaneous time in the time zone represented by +self+. Returns a
- # Time.utc() instance -- if you want an ActiveSupport::TimeWithZone instance, use Time#in_time_zone() instead.
- def utc_to_local(time)
- tzinfo.utc_to_local(time)
- end
+ # Returns an ActiveSupport::TimeWithZone instance representing the current time
+ # in the time zone represented by +self+. Example:
+ #
+ # Time.zone = 'Hawaii' # => "Hawaii"
+ # Time.zone.now # => Wed, 23 Jan 2008 20:24:27 HST -10:00
+ def now
+ Time.now.utc.in_time_zone(self)
+ end
- # Adjust the given time to the simultaneous time in UTC. Returns a Time.utc() instance.
- def local_to_utc(time, dst=true)
- tzinfo.local_to_utc(time, dst)
- end
+ # Return the current date in this time zone.
+ def today
+ tzinfo.now.to_date
+ end
- # Available so that TimeZone instances respond like TZInfo::Timezone instances
- def period_for_utc(time)
- tzinfo.period_for_utc(time)
- end
+ # Adjust the given time to the simultaneous time in the time zone represented by +self+. Returns a
+ # Time.utc() instance -- if you want an ActiveSupport::TimeWithZone instance, use Time#in_time_zone() instead.
+ def utc_to_local(time)
+ tzinfo.utc_to_local(time)
+ end
- # Available so that TimeZone instances respond like TZInfo::Timezone instances
- def period_for_local(time, dst=true)
- tzinfo.period_for_local(time, dst)
- end
+ # Adjust the given time to the simultaneous time in UTC. Returns a Time.utc() instance.
+ def local_to_utc(time, dst=true)
+ tzinfo.local_to_utc(time, dst)
+ end
- # TODO: Preload instead of lazy load for thread safety
- def tzinfo
- @tzinfo ||= TZInfo::Timezone.get(MAPPING[name])
- end
+ # Available so that TimeZone instances respond like TZInfo::Timezone instances
+ def period_for_utc(time)
+ tzinfo.period_for_utc(time)
+ end
- unless const_defined?(:ZONES)
- ZONES = []
- ZONES_MAP = {}
- [[-39_600, "International Date Line West", "Midway Island", "Samoa" ],
- [-36_000, "Hawaii" ],
- [-32_400, "Alaska" ],
- [-28_800, "Pacific Time (US & Canada)", "Tijuana" ],
- [-25_200, "Mountain Time (US & Canada)", "Chihuahua", "Mazatlan",
- "Arizona" ],
- [-21_600, "Central Time (US & Canada)", "Saskatchewan", "Guadalajara",
- "Mexico City", "Monterrey", "Central America" ],
- [-18_000, "Eastern Time (US & Canada)", "Indiana (East)", "Bogota",
- "Lima", "Quito" ],
- [-14_400, "Atlantic Time (Canada)", "Caracas", "La Paz", "Santiago" ],
- [-12_600, "Newfoundland" ],
- [-10_800, "Brasilia", "Buenos Aires", "Georgetown", "Greenland" ],
- [ -7_200, "Mid-Atlantic" ],
- [ -3_600, "Azores", "Cape Verde Is." ],
- [ 0, "Dublin", "Edinburgh", "Lisbon", "London", "Casablanca",
- "Monrovia", "UTC" ],
- [ 3_600, "Belgrade", "Bratislava", "Budapest", "Ljubljana", "Prague",
- "Sarajevo", "Skopje", "Warsaw", "Zagreb", "Brussels",
- "Copenhagen", "Madrid", "Paris", "Amsterdam", "Berlin",
- "Bern", "Rome", "Stockholm", "Vienna",
- "West Central Africa" ],
- [ 7_200, "Bucharest", "Cairo", "Helsinki", "Kyev", "Riga", "Sofia",
- "Tallinn", "Vilnius", "Athens", "Istanbul", "Minsk",
- "Jerusalem", "Harare", "Pretoria" ],
- [ 10_800, "Moscow", "St. Petersburg", "Volgograd", "Kuwait", "Riyadh",
- "Nairobi", "Baghdad" ],
- [ 12_600, "Tehran" ],
- [ 14_400, "Abu Dhabi", "Muscat", "Baku", "Tbilisi", "Yerevan" ],
- [ 16_200, "Kabul" ],
- [ 18_000, "Ekaterinburg", "Islamabad", "Karachi", "Tashkent" ],
- [ 19_800, "Chennai", "Kolkata", "Mumbai", "New Delhi" ],
- [ 20_700, "Kathmandu" ],
- [ 21_600, "Astana", "Dhaka", "Sri Jayawardenepura", "Almaty",
- "Novosibirsk" ],
- [ 23_400, "Rangoon" ],
- [ 25_200, "Bangkok", "Hanoi", "Jakarta", "Krasnoyarsk" ],
- [ 28_800, "Beijing", "Chongqing", "Hong Kong", "Urumqi",
- "Kuala Lumpur", "Singapore", "Taipei", "Perth", "Irkutsk",
- "Ulaan Bataar" ],
- [ 32_400, "Seoul", "Osaka", "Sapporo", "Tokyo", "Yakutsk" ],
- [ 34_200, "Darwin", "Adelaide" ],
- [ 36_000, "Canberra", "Melbourne", "Sydney", "Brisbane", "Hobart",
- "Vladivostok", "Guam", "Port Moresby" ],
- [ 39_600, "Magadan", "Solomon Is.", "New Caledonia" ],
- [ 43_200, "Fiji", "Kamchatka", "Marshall Is.", "Auckland",
- "Wellington" ],
- [ 46_800, "Nuku'alofa" ]].
- each do |offset, *places|
- places.each do |place|
- place.freeze
- zone = new(place, offset)
- ZONES << zone
- ZONES_MAP[place] = zone
- end
+ # Available so that TimeZone instances respond like TZInfo::Timezone instances
+ def period_for_local(time, dst=true)
+ tzinfo.period_for_local(time, dst)
end
- ZONES.sort!
- ZONES.freeze
- ZONES_MAP.freeze
- US_ZONES = ZONES.find_all { |z| z.name =~ /US|Arizona|Indiana|Hawaii|Alaska/ }
- US_ZONES.freeze
- end
+ # TODO: Preload instead of lazy load for thread safety
+ def tzinfo
+ @tzinfo ||= TZInfo::Timezone.get(MAPPING[name])
+ end
- class << self
- alias_method :create, :new
+ unless const_defined?(:ZONES)
+ ZONES = []
+ ZONES_MAP = {}
+ [[-39_600, "International Date Line West", "Midway Island", "Samoa" ],
+ [-36_000, "Hawaii" ],
+ [-32_400, "Alaska" ],
+ [-28_800, "Pacific Time (US & Canada)", "Tijuana" ],
+ [-25_200, "Mountain Time (US & Canada)", "Chihuahua", "Mazatlan",
+ "Arizona" ],
+ [-21_600, "Central Time (US & Canada)", "Saskatchewan", "Guadalajara",
+ "Mexico City", "Monterrey", "Central America" ],
+ [-18_000, "Eastern Time (US & Canada)", "Indiana (East)", "Bogota",
+ "Lima", "Quito" ],
+ [-14_400, "Atlantic Time (Canada)", "Caracas", "La Paz", "Santiago" ],
+ [-12_600, "Newfoundland" ],
+ [-10_800, "Brasilia", "Buenos Aires", "Georgetown", "Greenland" ],
+ [ -7_200, "Mid-Atlantic" ],
+ [ -3_600, "Azores", "Cape Verde Is." ],
+ [ 0, "Dublin", "Edinburgh", "Lisbon", "London", "Casablanca",
+ "Monrovia", "UTC" ],
+ [ 3_600, "Belgrade", "Bratislava", "Budapest", "Ljubljana", "Prague",
+ "Sarajevo", "Skopje", "Warsaw", "Zagreb", "Brussels",
+ "Copenhagen", "Madrid", "Paris", "Amsterdam", "Berlin",
+ "Bern", "Rome", "Stockholm", "Vienna",
+ "West Central Africa" ],
+ [ 7_200, "Bucharest", "Cairo", "Helsinki", "Kyev", "Riga", "Sofia",
+ "Tallinn", "Vilnius", "Athens", "Istanbul", "Minsk",
+ "Jerusalem", "Harare", "Pretoria" ],
+ [ 10_800, "Moscow", "St. Petersburg", "Volgograd", "Kuwait", "Riyadh",
+ "Nairobi", "Baghdad" ],
+ [ 12_600, "Tehran" ],
+ [ 14_400, "Abu Dhabi", "Muscat", "Baku", "Tbilisi", "Yerevan" ],
+ [ 16_200, "Kabul" ],
+ [ 18_000, "Ekaterinburg", "Islamabad", "Karachi", "Tashkent" ],
+ [ 19_800, "Chennai", "Kolkata", "Mumbai", "New Delhi" ],
+ [ 20_700, "Kathmandu" ],
+ [ 21_600, "Astana", "Dhaka", "Sri Jayawardenepura", "Almaty",
+ "Novosibirsk" ],
+ [ 23_400, "Rangoon" ],
+ [ 25_200, "Bangkok", "Hanoi", "Jakarta", "Krasnoyarsk" ],
+ [ 28_800, "Beijing", "Chongqing", "Hong Kong", "Urumqi",
+ "Kuala Lumpur", "Singapore", "Taipei", "Perth", "Irkutsk",
+ "Ulaan Bataar" ],
+ [ 32_400, "Seoul", "Osaka", "Sapporo", "Tokyo", "Yakutsk" ],
+ [ 34_200, "Darwin", "Adelaide" ],
+ [ 36_000, "Canberra", "Melbourne", "Sydney", "Brisbane", "Hobart",
+ "Vladivostok", "Guam", "Port Moresby" ],
+ [ 39_600, "Magadan", "Solomon Is.", "New Caledonia" ],
+ [ 43_200, "Fiji", "Kamchatka", "Marshall Is.", "Auckland",
+ "Wellington" ],
+ [ 46_800, "Nuku'alofa" ]].
+ each do |offset, *places|
+ places.each do |place|
+ place.freeze
+ zone = new(place, offset)
+ ZONES << zone
+ ZONES_MAP[place] = zone
+ end
+ end
+ ZONES.sort!
+ ZONES.freeze
+ ZONES_MAP.freeze
- # Return a TimeZone instance with the given name, or +nil+ if no
- # such TimeZone instance exists. (This exists to support the use of
- # this class with the +composed_of+ macro.)
- def new(name)
- self[name]
+ US_ZONES = ZONES.find_all { |z| z.name =~ /US|Arizona|Indiana|Hawaii|Alaska/ }
+ US_ZONES.freeze
end
- # Return an array of all TimeZone objects. There are multiple
- # TimeZone objects per time zone, in many cases, to make it easier
- # for users to find their own time zone.
- def all
- ZONES
- end
+ class << self
+ alias_method :create, :new
- # Locate a specific time zone object. If the argument is a string, it
- # is interpreted to mean the name of the timezone to locate. If it is a
- # numeric value it is either the hour offset, or the second offset, of the
- # timezone to find. (The first one with that offset will be returned.)
- # Returns +nil+ if no such time zone is known to the system.
- def [](arg)
- case arg
- when String
- ZONES_MAP[arg]
- when Numeric, ActiveSupport::Duration
- arg *= 3600 if arg.abs <= 13
- all.find { |z| z.utc_offset == arg.to_i }
- else
- raise ArgumentError, "invalid argument to TimeZone[]: #{arg.inspect}"
+ # Return a TimeZone instance with the given name, or +nil+ if no
+ # such TimeZone instance exists. (This exists to support the use of
+ # this class with the +composed_of+ macro.)
+ def new(name)
+ self[name]
end
- end
- # A convenience method for returning a collection of TimeZone objects
- # for time zones in the USA.
- def us_zones
- US_ZONES
+ # Return an array of all TimeZone objects. There are multiple
+ # TimeZone objects per time zone, in many cases, to make it easier
+ # for users to find their own time zone.
+ def all
+ ZONES
+ end
+
+ # Locate a specific time zone object. If the argument is a string, it
+ # is interpreted to mean the name of the timezone to locate. If it is a
+ # numeric value it is either the hour offset, or the second offset, of the
+ # timezone to find. (The first one with that offset will be returned.)
+ # Returns +nil+ if no such time zone is known to the system.
+ def [](arg)
+ case arg
+ when String
+ ZONES_MAP[arg]
+ when Numeric, ActiveSupport::Duration
+ arg *= 3600 if arg.abs <= 13
+ all.find { |z| z.utc_offset == arg.to_i }
+ else
+ raise ArgumentError, "invalid argument to TimeZone[]: #{arg.inspect}"
+ end
+ end
+
+ # A convenience method for returning a collection of TimeZone objects
+ # for time zones in the USA.
+ def us_zones
+ US_ZONES
+ end
end
end
end
diff --git a/activesupport/lib/active_support/vendor.rb b/activesupport/lib/active_support/vendor.rb
index cdbcedc75a..a02e42f791 100644
--- a/activesupport/lib/active_support/vendor.rb
+++ b/activesupport/lib/active_support/vendor.rb
@@ -20,7 +20,7 @@ rescue Gem::LoadError
end
begin
- gem 'tzinfo', '~> 0.3.8'
+ gem 'tzinfo', '~> 0.3.9'
rescue Gem::LoadError
- $:.unshift "#{File.dirname(__FILE__)}/vendor/tzinfo-0.3.8"
+ $:.unshift "#{File.dirname(__FILE__)}/vendor/tzinfo-0.3.9"
end \ No newline at end of file
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/offset_rationals.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/offset_rationals.rb
deleted file mode 100644
index 32fa4123f1..0000000000
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/offset_rationals.rb
+++ /dev/null
@@ -1,95 +0,0 @@
-#--
-# Copyright (c) 2006 Philip Ross
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#++
-
-module TZInfo
-
- # Provides a method for getting Rationals for a timezone offset in seconds.
- # Pre-reduced rationals are returned for all the half-hour intervals between
- # -14 and +14 hours to avoid having to call gcd at runtime.
- module OffsetRationals #:nodoc:
- @@rational_cache = {
- -50400 => Rational(-7,12),
- -48600 => Rational(-9,16),
- -46800 => Rational(-13,24),
- -45000 => Rational(-25,48),
- -43200 => Rational(-1,2),
- -41400 => Rational(-23,48),
- -39600 => Rational(-11,24),
- -37800 => Rational(-7,16),
- -36000 => Rational(-5,12),
- -34200 => Rational(-19,48),
- -32400 => Rational(-3,8),
- -30600 => Rational(-17,48),
- -28800 => Rational(-1,3),
- -27000 => Rational(-5,16),
- -25200 => Rational(-7,24),
- -23400 => Rational(-13,48),
- -21600 => Rational(-1,4),
- -19800 => Rational(-11,48),
- -18000 => Rational(-5,24),
- -16200 => Rational(-3,16),
- -14400 => Rational(-1,6),
- -12600 => Rational(-7,48),
- -10800 => Rational(-1,8),
- -9000 => Rational(-5,48),
- -7200 => Rational(-1,12),
- -5400 => Rational(-1,16),
- -3600 => Rational(-1,24),
- -1800 => Rational(-1,48),
- 0 => Rational(0,1),
- 1800 => Rational(1,48),
- 3600 => Rational(1,24),
- 5400 => Rational(1,16),
- 7200 => Rational(1,12),
- 9000 => Rational(5,48),
- 10800 => Rational(1,8),
- 12600 => Rational(7,48),
- 14400 => Rational(1,6),
- 16200 => Rational(3,16),
- 18000 => Rational(5,24),
- 19800 => Rational(11,48),
- 21600 => Rational(1,4),
- 23400 => Rational(13,48),
- 25200 => Rational(7,24),
- 27000 => Rational(5,16),
- 28800 => Rational(1,3),
- 30600 => Rational(17,48),
- 32400 => Rational(3,8),
- 34200 => Rational(19,48),
- 36000 => Rational(5,12),
- 37800 => Rational(7,16),
- 39600 => Rational(11,24),
- 41400 => Rational(23,48),
- 43200 => Rational(1,2),
- 45000 => Rational(25,48),
- 46800 => Rational(13,24),
- 48600 => Rational(9,16),
- 50400 => Rational(7,12)}
-
- # Returns a Rational expressing the fraction of a day that offset in
- # seconds represents (i.e. equivalent to Rational(offset, 86400)).
- def rational_for_offset(offset)
- @@rational_cache[offset] || Rational(offset, 86400)
- end
- module_function :rational_for_offset
- end
-end
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo.rb
index c8bdbeec5d..c8bdbeec5d 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone.rb
index 2510e90b5b..2510e90b5b 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone_info.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone_info.rb
index d2a6620dd2..ad907af360 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone_info.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone_info.rb
@@ -40,6 +40,8 @@ module TZInfo
super(identifier)
@offsets = {}
@transitions = []
+ @previous_offset = nil
+ @transitions_index = nil
end
# Defines a offset. The id uniquely identifies this offset within the
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Algiers.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Algiers.rb
index 8c5f25577f..8c5f25577f 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Algiers.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Algiers.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Cairo.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Cairo.rb
index 6e6daf3522..6e6daf3522 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Cairo.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Cairo.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Casablanca.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Casablanca.rb
index 10d28e7613..dddf533f61 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Casablanca.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Casablanca.rb
@@ -31,6 +31,8 @@ module TZInfo
tz.transition 1978, 8, :o1, 271033200
tz.transition 1984, 3, :o3, 448243200
tz.transition 1985, 12, :o1, 504918000
+ tz.transition 2008, 6, :o2, 1212278400
+ tz.transition 2008, 9, :o1, 1222556400
end
end
end
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Harare.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Harare.rb
index 070c95ae0f..070c95ae0f 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Harare.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Harare.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Johannesburg.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Johannesburg.rb
index f0af0d8e33..f0af0d8e33 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Johannesburg.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Johannesburg.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Monrovia.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Monrovia.rb
index 40e711fa44..40e711fa44 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Monrovia.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Monrovia.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Nairobi.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Nairobi.rb
index 7b0a2f43be..7b0a2f43be 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Nairobi.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Nairobi.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Argentina/Buenos_Aires.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Argentina/Buenos_Aires.rb
index 7536f7553c..7536f7553c 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Argentina/Buenos_Aires.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Argentina/Buenos_Aires.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Argentina/San_Juan.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Argentina/San_Juan.rb
index a5413612ee..a5413612ee 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Argentina/San_Juan.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Argentina/San_Juan.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Bogota.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Bogota.rb
index ef96435c6a..ef96435c6a 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Bogota.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Bogota.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Caracas.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Caracas.rb
index 27392a540a..27392a540a 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Caracas.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Caracas.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Chicago.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Chicago.rb
index 0996857cf0..0996857cf0 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Chicago.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Chicago.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Chihuahua.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Chihuahua.rb
index 1710b57c79..1710b57c79 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Chihuahua.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Chihuahua.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Denver.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Denver.rb
index 1c1efb5ff3..1c1efb5ff3 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Denver.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Denver.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Godthab.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Godthab.rb
index 1e05518b0d..1e05518b0d 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Godthab.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Godthab.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Guatemala.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Guatemala.rb
index a2bf73401c..a2bf73401c 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Guatemala.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Guatemala.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Halifax.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Halifax.rb
index d25ae775b3..d25ae775b3 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Halifax.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Halifax.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Indiana/Indianapolis.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Indiana/Indianapolis.rb
index f1430f6c24..f1430f6c24 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Indiana/Indianapolis.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Indiana/Indianapolis.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Juneau.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Juneau.rb
index f646f3f54a..f646f3f54a 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Juneau.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Juneau.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/La_Paz.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/La_Paz.rb
index 45c907899f..45c907899f 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/La_Paz.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/La_Paz.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Lima.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Lima.rb
index af68ac29f7..af68ac29f7 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Lima.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Lima.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Los_Angeles.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Los_Angeles.rb
index 16007fd675..16007fd675 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Los_Angeles.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Los_Angeles.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Mazatlan.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Mazatlan.rb
index ba9e6efcf1..ba9e6efcf1 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Mazatlan.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Mazatlan.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Mexico_City.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Mexico_City.rb
index 2347fce647..2347fce647 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Mexico_City.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Mexico_City.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Monterrey.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Monterrey.rb
index 5816a9eab1..5816a9eab1 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Monterrey.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Monterrey.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/New_York.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/New_York.rb
index 7d802bd2de..7d802bd2de 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/New_York.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/New_York.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Phoenix.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Phoenix.rb
index b514e0c0f9..b514e0c0f9 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Phoenix.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Phoenix.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Regina.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Regina.rb
index ebdb68814a..ebdb68814a 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Regina.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Regina.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Santiago.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Santiago.rb
index 0287c9ebc4..0287c9ebc4 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Santiago.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Santiago.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/St_Johns.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/St_Johns.rb
index e4a3599d35..e4a3599d35 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/St_Johns.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/St_Johns.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Tijuana.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Tijuana.rb
index 423059da46..423059da46 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Tijuana.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Tijuana.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Almaty.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Almaty.rb
index 9ee18970f1..9ee18970f1 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Almaty.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Almaty.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Baghdad.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Baghdad.rb
index 774dca1587..774dca1587 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Baghdad.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Baghdad.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Baku.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Baku.rb
index e86340ebfa..e86340ebfa 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Baku.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Baku.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Bangkok.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Bangkok.rb
index 139194e5e5..139194e5e5 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Bangkok.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Bangkok.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Chongqing.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Chongqing.rb
index 8c94b4ba86..8c94b4ba86 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Chongqing.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Chongqing.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Dhaka.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Dhaka.rb
index ccd0265503..ccd0265503 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Dhaka.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Dhaka.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Hong_Kong.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Hong_Kong.rb
index f1edd75ac8..f1edd75ac8 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Hong_Kong.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Hong_Kong.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Irkutsk.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Irkutsk.rb
index 2d47d9580b..2d47d9580b 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Irkutsk.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Irkutsk.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Jakarta.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Jakarta.rb
index cc58fa173b..cc58fa173b 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Jakarta.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Jakarta.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Jerusalem.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Jerusalem.rb
index 9b737b899e..9b737b899e 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Jerusalem.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Jerusalem.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kabul.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kabul.rb
index 669c09790a..669c09790a 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kabul.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kabul.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kamchatka.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kamchatka.rb
index 2f1690b3a9..2f1690b3a9 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kamchatka.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kamchatka.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Karachi.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Karachi.rb
index baa0d41d73..bd7656ef2f 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Karachi.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Karachi.rb
@@ -21,6 +21,8 @@ module TZInfo
tz.transition 1971, 3, :o4, 38775600
tz.transition 2002, 4, :o5, 1018119660
tz.transition 2002, 10, :o4, 1033840860
+ tz.transition 2008, 5, :o5, 1212260400
+ tz.transition 2008, 8, :o4, 1220205600
end
end
end
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Katmandu.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Katmandu.rb
index 37dbea1f41..37dbea1f41 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Katmandu.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Katmandu.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kolkata.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kolkata.rb
index 1b6ffbd59d..1b6ffbd59d 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kolkata.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kolkata.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Krasnoyarsk.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Krasnoyarsk.rb
index d6c503c155..d6c503c155 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Krasnoyarsk.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Krasnoyarsk.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kuala_Lumpur.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kuala_Lumpur.rb
index 77a0c206fa..77a0c206fa 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kuala_Lumpur.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kuala_Lumpur.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kuwait.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kuwait.rb
index 5bd5283197..5bd5283197 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kuwait.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kuwait.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Magadan.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Magadan.rb
index 302093693e..302093693e 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Magadan.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Magadan.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Muscat.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Muscat.rb
index 604f651dfa..604f651dfa 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Muscat.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Muscat.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Novosibirsk.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Novosibirsk.rb
index a4e7796e75..a4e7796e75 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Novosibirsk.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Novosibirsk.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Rangoon.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Rangoon.rb
index 759b82d77a..759b82d77a 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Rangoon.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Rangoon.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Riyadh.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Riyadh.rb
index 7add410620..7add410620 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Riyadh.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Riyadh.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Seoul.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Seoul.rb
index 795d2a75df..795d2a75df 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Seoul.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Seoul.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Shanghai.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Shanghai.rb
index 34b13d59ae..34b13d59ae 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Shanghai.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Shanghai.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Singapore.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Singapore.rb
index b323a78f74..b323a78f74 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Singapore.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Singapore.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Taipei.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Taipei.rb
index 3ba12108fb..3ba12108fb 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Taipei.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Taipei.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tashkent.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tashkent.rb
index c205c7934d..c205c7934d 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tashkent.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tashkent.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tbilisi.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tbilisi.rb
index 15792a5651..15792a5651 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tbilisi.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tbilisi.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tehran.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tehran.rb
index d8df964a46..d8df964a46 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tehran.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tehran.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tokyo.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tokyo.rb
index 51c9e16421..51c9e16421 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tokyo.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tokyo.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Ulaanbaatar.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Ulaanbaatar.rb
index 2854f5c5fd..2854f5c5fd 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Ulaanbaatar.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Ulaanbaatar.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Urumqi.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Urumqi.rb
index d793ff1341..d793ff1341 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Urumqi.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Urumqi.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Vladivostok.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Vladivostok.rb
index bd9e3d60ec..bd9e3d60ec 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Vladivostok.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Vladivostok.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Yakutsk.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Yakutsk.rb
index 56435a788f..56435a788f 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Yakutsk.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Yakutsk.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Yekaterinburg.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Yekaterinburg.rb
index 8ef8df4a41..8ef8df4a41 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Yekaterinburg.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Yekaterinburg.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Yerevan.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Yerevan.rb
index e7f160861f..e7f160861f 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Yerevan.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Yerevan.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Atlantic/Azores.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Atlantic/Azores.rb
index 1bd16a75ac..1bd16a75ac 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Atlantic/Azores.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Atlantic/Azores.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Atlantic/Cape_Verde.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Atlantic/Cape_Verde.rb
index 61c8c15043..61c8c15043 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Atlantic/Cape_Verde.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Atlantic/Cape_Verde.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Atlantic/South_Georgia.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Atlantic/South_Georgia.rb
index 6a4cbafb9f..6a4cbafb9f 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Atlantic/South_Georgia.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Atlantic/South_Georgia.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Adelaide.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Adelaide.rb
index c5d561cc1e..c5d561cc1e 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Adelaide.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Adelaide.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Brisbane.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Brisbane.rb
index dd85ddae94..dd85ddae94 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Brisbane.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Brisbane.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Darwin.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Darwin.rb
index 17de88124d..17de88124d 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Darwin.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Darwin.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Hobart.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Hobart.rb
index 11384b9840..11384b9840 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Hobart.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Hobart.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Melbourne.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Melbourne.rb
index c1304488ea..c1304488ea 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Melbourne.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Melbourne.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Perth.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Perth.rb
index d9e66f14a8..d9e66f14a8 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Perth.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Perth.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Sydney.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Sydney.rb
index 9062bd7c3c..9062bd7c3c 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Sydney.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Sydney.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Etc/UTC.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Etc/UTC.rb
index 28b2c6a04c..28b2c6a04c 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Etc/UTC.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Etc/UTC.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Amsterdam.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Amsterdam.rb
index 2d0c95c4bc..2d0c95c4bc 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Amsterdam.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Amsterdam.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Athens.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Athens.rb
index 4e21e535ca..4e21e535ca 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Athens.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Athens.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Belgrade.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Belgrade.rb
index 4dbd893d75..4dbd893d75 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Belgrade.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Belgrade.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Berlin.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Berlin.rb
index de2e4d951c..de2e4d951c 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Berlin.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Berlin.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Bratislava.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Bratislava.rb
index 7a731a0b6a..7a731a0b6a 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Bratislava.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Bratislava.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Brussels.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Brussels.rb
index 6b0a242944..6b0a242944 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Brussels.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Brussels.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Bucharest.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Bucharest.rb
index 521c3c932e..521c3c932e 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Bucharest.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Bucharest.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Budapest.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Budapest.rb
index 1f3a9738b7..1f3a9738b7 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Budapest.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Budapest.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Copenhagen.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Copenhagen.rb
index 47cbaf14a7..47cbaf14a7 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Copenhagen.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Copenhagen.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Dublin.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Dublin.rb
index 0560bb5436..0560bb5436 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Dublin.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Dublin.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Helsinki.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Helsinki.rb
index 13a806bcc7..13a806bcc7 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Helsinki.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Helsinki.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Istanbul.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Istanbul.rb
index 8306c47536..8306c47536 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Istanbul.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Istanbul.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Kiev.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Kiev.rb
index 513d3308be..513d3308be 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Kiev.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Kiev.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Lisbon.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Lisbon.rb
index 1c6d2a3d30..1c6d2a3d30 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Lisbon.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Lisbon.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Ljubljana.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Ljubljana.rb
index a9828e6ef8..a9828e6ef8 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Ljubljana.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Ljubljana.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/London.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/London.rb
index 64ce41e900..64ce41e900 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/London.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/London.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Madrid.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Madrid.rb
index 1fb568239a..1fb568239a 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Madrid.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Madrid.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Minsk.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Minsk.rb
index fa15816cc8..fa15816cc8 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Minsk.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Minsk.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Moscow.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Moscow.rb
index ef269b675b..ef269b675b 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Moscow.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Moscow.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Paris.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Paris.rb
index e3236c0ba1..e3236c0ba1 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Paris.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Paris.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Prague.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Prague.rb
index bcabee96c1..bcabee96c1 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Prague.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Prague.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Riga.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Riga.rb
index 784837f758..784837f758 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Riga.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Riga.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Rome.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Rome.rb
index aa7b43d9d2..aa7b43d9d2 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Rome.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Rome.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Sarajevo.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Sarajevo.rb
index 068c5fe6ad..068c5fe6ad 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Sarajevo.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Sarajevo.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Skopje.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Skopje.rb
index 10b71f285e..10b71f285e 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Skopje.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Skopje.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Sofia.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Sofia.rb
index 38a70eceb9..38a70eceb9 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Sofia.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Sofia.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Stockholm.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Stockholm.rb
index 43db70fa61..43db70fa61 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Stockholm.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Stockholm.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Tallinn.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Tallinn.rb
index de5a8569f3..de5a8569f3 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Tallinn.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Tallinn.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Vienna.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Vienna.rb
index 990aabab66..990aabab66 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Vienna.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Vienna.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Vilnius.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Vilnius.rb
index d89d095a75..d89d095a75 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Vilnius.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Vilnius.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Warsaw.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Warsaw.rb
index 7fa51c2691..7fa51c2691 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Warsaw.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Warsaw.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Zagreb.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Zagreb.rb
index ecdd903d28..ecdd903d28 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Zagreb.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Zagreb.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Auckland.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Auckland.rb
index a524fd6b6b..a524fd6b6b 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Auckland.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Auckland.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Fiji.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Fiji.rb
index 5fe9bbd9a6..5fe9bbd9a6 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Fiji.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Fiji.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Guam.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Guam.rb
index d4c1a0a682..d4c1a0a682 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Guam.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Guam.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Honolulu.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Honolulu.rb
index 204b226537..204b226537 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Honolulu.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Honolulu.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Majuro.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Majuro.rb
index 32adad92c1..32adad92c1 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Majuro.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Majuro.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Midway.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Midway.rb
index 97784fcc10..97784fcc10 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Midway.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Midway.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Noumea.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Noumea.rb
index 70173db8ab..70173db8ab 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Noumea.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Noumea.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Pago_Pago.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Pago_Pago.rb
index c8fcd7d527..c8fcd7d527 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Pago_Pago.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Pago_Pago.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Port_Moresby.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Port_Moresby.rb
index f06cf6d54f..f06cf6d54f 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Port_Moresby.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Port_Moresby.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Tongatapu.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Tongatapu.rb
index 7578d92f38..7578d92f38 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Tongatapu.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Tongatapu.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/info_timezone.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/info_timezone.rb
index 001303c594..001303c594 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/info_timezone.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/info_timezone.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/linked_timezone.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/linked_timezone.rb
index c757485b84..c757485b84 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/linked_timezone.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/linked_timezone.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/linked_timezone_info.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/linked_timezone_info.rb
index 8197ff3e81..8197ff3e81 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/linked_timezone_info.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/linked_timezone_info.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/offset_rationals.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/offset_rationals.rb
new file mode 100644
index 0000000000..c79eedb7ef
--- /dev/null
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/offset_rationals.rb
@@ -0,0 +1,95 @@
+#--
+# Copyright (c) 2006 Philip Ross
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#++
+
+module TZInfo
+
+ # Provides a method for getting Rationals for a timezone offset in seconds.
+ # Pre-reduced rationals are returned for all the half-hour intervals between
+ # -14 and +14 hours to avoid having to call gcd at runtime.
+ module OffsetRationals #:nodoc:
+ @@rational_cache = {
+ -50400 => Rational.send(:new!, -7,12),
+ -48600 => Rational.send(:new!, -9,16),
+ -46800 => Rational.send(:new!, -13,24),
+ -45000 => Rational.send(:new!, -25,48),
+ -43200 => Rational.send(:new!, -1,2),
+ -41400 => Rational.send(:new!, -23,48),
+ -39600 => Rational.send(:new!, -11,24),
+ -37800 => Rational.send(:new!, -7,16),
+ -36000 => Rational.send(:new!, -5,12),
+ -34200 => Rational.send(:new!, -19,48),
+ -32400 => Rational.send(:new!, -3,8),
+ -30600 => Rational.send(:new!, -17,48),
+ -28800 => Rational.send(:new!, -1,3),
+ -27000 => Rational.send(:new!, -5,16),
+ -25200 => Rational.send(:new!, -7,24),
+ -23400 => Rational.send(:new!, -13,48),
+ -21600 => Rational.send(:new!, -1,4),
+ -19800 => Rational.send(:new!, -11,48),
+ -18000 => Rational.send(:new!, -5,24),
+ -16200 => Rational.send(:new!, -3,16),
+ -14400 => Rational.send(:new!, -1,6),
+ -12600 => Rational.send(:new!, -7,48),
+ -10800 => Rational.send(:new!, -1,8),
+ -9000 => Rational.send(:new!, -5,48),
+ -7200 => Rational.send(:new!, -1,12),
+ -5400 => Rational.send(:new!, -1,16),
+ -3600 => Rational.send(:new!, -1,24),
+ -1800 => Rational.send(:new!, -1,48),
+ 0 => Rational.send(:new!, 0,1),
+ 1800 => Rational.send(:new!, 1,48),
+ 3600 => Rational.send(:new!, 1,24),
+ 5400 => Rational.send(:new!, 1,16),
+ 7200 => Rational.send(:new!, 1,12),
+ 9000 => Rational.send(:new!, 5,48),
+ 10800 => Rational.send(:new!, 1,8),
+ 12600 => Rational.send(:new!, 7,48),
+ 14400 => Rational.send(:new!, 1,6),
+ 16200 => Rational.send(:new!, 3,16),
+ 18000 => Rational.send(:new!, 5,24),
+ 19800 => Rational.send(:new!, 11,48),
+ 21600 => Rational.send(:new!, 1,4),
+ 23400 => Rational.send(:new!, 13,48),
+ 25200 => Rational.send(:new!, 7,24),
+ 27000 => Rational.send(:new!, 5,16),
+ 28800 => Rational.send(:new!, 1,3),
+ 30600 => Rational.send(:new!, 17,48),
+ 32400 => Rational.send(:new!, 3,8),
+ 34200 => Rational.send(:new!, 19,48),
+ 36000 => Rational.send(:new!, 5,12),
+ 37800 => Rational.send(:new!, 7,16),
+ 39600 => Rational.send(:new!, 11,24),
+ 41400 => Rational.send(:new!, 23,48),
+ 43200 => Rational.send(:new!, 1,2),
+ 45000 => Rational.send(:new!, 25,48),
+ 46800 => Rational.send(:new!, 13,24),
+ 48600 => Rational.send(:new!, 9,16),
+ 50400 => Rational.send(:new!, 7,12)}
+
+ # Returns a Rational expressing the fraction of a day that offset in
+ # seconds represents (i.e. equivalent to Rational(offset, 86400)).
+ def rational_for_offset(offset)
+ @@rational_cache[offset] || Rational(offset, 86400)
+ end
+ module_function :rational_for_offset
+ end
+end
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/time_or_datetime.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/time_or_datetime.rb
index 264517f3ee..264517f3ee 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/time_or_datetime.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/time_or_datetime.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone.rb
index 910eefca02..eb9ede2ab9 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone.rb
@@ -371,8 +371,8 @@ module TZInfo
# type as utc. Any timezone information in utc is ignored (it is treated as
# a UTC time).
def utc_to_local(utc)
- TimeOrDateTime.wrap(utc) {|utc|
- period_for_utc(utc).to_local(utc)
+ TimeOrDateTime.wrap(utc) {|wrapped|
+ period_for_utc(wrapped).to_local(wrapped)
}
end
@@ -410,14 +410,14 @@ module TZInfo
# single period to use to convert the time or return nil or an empty array
# to cause an AmbiguousTime exception to be raised.
def local_to_utc(local, dst = nil)
- TimeOrDateTime.wrap(local) {|local|
+ TimeOrDateTime.wrap(local) {|wrapped|
if block_given?
- period = period_for_local(local, dst) {|periods| yield periods }
+ period = period_for_local(wrapped, dst) {|periods| yield periods }
else
- period = period_for_local(local, dst)
+ period = period_for_local(wrapped, dst)
end
- period.to_utc(local)
+ period.to_utc(wrapped)
}
end
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_definition.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_definition.rb
index 39ca8bfa53..39ca8bfa53 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_definition.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_definition.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_info.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_info.rb
index 68e38c35fb..68e38c35fb 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_info.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_info.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_offset_info.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_offset_info.rb
index 913c4164af..6a0bbca46f 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_offset_info.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_offset_info.rb
@@ -56,15 +56,15 @@ module TZInfo
# Converts a UTC DateTime to local time based on the offset of this period.
def to_local(utc)
- TimeOrDateTime.wrap(utc) {|utc|
- utc + @utc_total_offset
+ TimeOrDateTime.wrap(utc) {|wrapped|
+ wrapped + @utc_total_offset
}
end
# Converts a local DateTime to UTC based on the offset of this period.
def to_utc(local)
- TimeOrDateTime.wrap(local) {|local|
- local - @utc_total_offset
+ TimeOrDateTime.wrap(local) {|wrapped|
+ wrapped - @utc_total_offset
}
end
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_period.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_period.rb
index 00888fcfdc..00888fcfdc 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_period.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_period.rb
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_transition_info.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_transition_info.rb
index 146c131708..781764f0b0 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_transition_info.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_transition_info.rb
@@ -48,7 +48,7 @@ module TZInfo
# seconds since the epoch. If denominator is specified numerator_or_time
# and denominator are used to create a DateTime as follows:
#
- # DateTime.new!(Rational.new!(numerator_or_time, denominator), 0, Date::ITALY)
+ # DateTime.new!(Rational.send(:new!, numerator_or_time, denominator), 0, Date::ITALY)
#
# For performance reasons, the numerator and denominator must be specified
# in their lowest form.
@@ -70,7 +70,7 @@ module TZInfo
unless @denominator
@at = TimeOrDateTime.new(@numerator_or_time)
else
- r = Rational.new!(@numerator_or_time, @denominator)
+ r = Rational.send(:new!, @numerator_or_time, @denominator)
# Ruby 1.8.6 introduced new! and deprecated new0.
# Ruby 1.9.0 removed new0.
diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb
index 09b56525e0..f3220d27aa 100644
--- a/activesupport/test/caching_test.rb
+++ b/activesupport/test/caching_test.rb
@@ -1,5 +1,11 @@
require 'abstract_unit'
+class CacheKeyTest < Test::Unit::TestCase
+ def test_expand_cache_key
+ assert_equal 'name/1/2/true', ActiveSupport::Cache.expand_cache_key([1, '2', true], :name)
+ end
+end
+
class CacheStoreSettingTest < Test::Unit::TestCase
def test_file_fragment_cache_store
store = ActiveSupport::Cache.lookup_store :file_store, "/path/to/cache/directory"
diff --git a/activesupport/test/core_ext/array_ext_test.rb b/activesupport/test/core_ext/array_ext_test.rb
index ccab0f70d0..7563be44f8 100644
--- a/activesupport/test/core_ext/array_ext_test.rb
+++ b/activesupport/test/core_ext/array_ext_test.rb
@@ -13,6 +13,20 @@ class ArrayExtAccessTests < Test::Unit::TestCase
assert_equal %w( a b c ), %w( a b c d ).to(2)
assert_equal %w( a b c d ), %w( a b c d ).to(10)
end
+
+ def test_second_through_tenth
+ array = (1..10).to_a
+
+ assert_equal array[1], array.second
+ assert_equal array[2], array.third
+ assert_equal array[3], array.fourth
+ assert_equal array[4], array.fifth
+ assert_equal array[5], array.sixth
+ assert_equal array[6], array.seventh
+ assert_equal array[7], array.eighth
+ assert_equal array[8], array.ninth
+ assert_equal array[9], array.tenth
+ end
end
class ArrayExtToParamTests < Test::Unit::TestCase
@@ -21,7 +35,7 @@ class ArrayExtToParamTests < Test::Unit::TestCase
"#{self}1"
end
end
-
+
def test_string_array
assert_equal '', %w().to_param
assert_equal 'hello/world', %w(hello world).to_param
@@ -31,7 +45,7 @@ class ArrayExtToParamTests < Test::Unit::TestCase
def test_number_array
assert_equal '10/20', [10, 20].to_param
end
-
+
def test_to_param_array
assert_equal 'custom1/param1', [ToParam.new('custom'), ToParam.new('param')].to_param
end
@@ -222,6 +236,11 @@ class ArrayToXmlTests < Test::Unit::TestCase
assert xml.include?(%(<count>2</count>)), xml
end
+
+ def test_to_xml_with_empty
+ xml = [].to_xml
+ assert_match(/type="array"\/>/, xml)
+ end
end
class ArrayExtractOptionsTests < Test::Unit::TestCase
@@ -234,17 +253,15 @@ class ArrayExtractOptionsTests < Test::Unit::TestCase
end
uses_mocha "ArrayExtRandomTests" do
+ class ArrayExtRandomTests < Test::Unit::TestCase
+ def test_random_element_from_array
+ assert_nil [].rand
-class ArrayExtRandomTests < Test::Unit::TestCase
- def test_random_element_from_array
- assert_nil [].rand
-
- Kernel.expects(:rand).with(1).returns(0)
- assert_equal 'x', ['x'].rand
+ Kernel.expects(:rand).with(1).returns(0)
+ assert_equal 'x', ['x'].rand
- Kernel.expects(:rand).with(3).returns(1)
- assert_equal 2, [1, 2, 3].rand
+ Kernel.expects(:rand).with(3).returns(1)
+ assert_equal 2, [1, 2, 3].rand
+ end
end
end
-
-end
diff --git a/activesupport/test/core_ext/bigdecimal.rb b/activesupport/test/core_ext/bigdecimal.rb
index 0417a2bca0..9faad9146f 100644
--- a/activesupport/test/core_ext/bigdecimal.rb
+++ b/activesupport/test/core_ext/bigdecimal.rb
@@ -5,5 +5,6 @@ class BigDecimalTest < Test::Unit::TestCase
assert_equal("--- 100000.30020320320000000000000000000000000000001\n", BigDecimal.new('100000.30020320320000000000000000000000000000001').to_yaml)
assert_equal("--- .Inf\n", BigDecimal.new('Infinity').to_yaml)
assert_equal("--- .NaN\n", BigDecimal.new('NaN').to_yaml)
+ assert_equal("--- -.Inf\n", BigDecimal.new('-Infinity').to_yaml)
end
end \ No newline at end of file
diff --git a/activesupport/test/core_ext/blank_test.rb b/activesupport/test/core_ext/blank_test.rb
index 061d940383..00fea74639 100644
--- a/activesupport/test/core_ext/blank_test.rb
+++ b/activesupport/test/core_ext/blank_test.rb
@@ -16,4 +16,9 @@ class BlankTest < Test::Unit::TestCase
BLANK.each { |v| assert v.blank?, "#{v.inspect} should be blank" }
NOT.each { |v| assert !v.blank?, "#{v.inspect} should not be blank" }
end
+
+ def test_present
+ BLANK.each { |v| assert !v.present?, "#{v.inspect} should not be present" }
+ NOT.each { |v| assert v.present?, "#{v.inspect} should be present" }
+ end
end
diff --git a/activesupport/test/core_ext/class_test.rb b/activesupport/test/core_ext/class_test.rb
index 0346fad190..9c6071d478 100644
--- a/activesupport/test/core_ext/class_test.rb
+++ b/activesupport/test/core_ext/class_test.rb
@@ -38,9 +38,9 @@ class ClassTest < Test::Unit::TestCase
@parent = eval("class D; end; D")
@sub = eval("class E < D; end; E")
@subofsub = eval("class F < E; end; F")
- assert @parent.subclasses.all? { |i| [@sub.to_s, @subofsub.to_s].include?(i) }
assert_equal 2, @parent.subclasses.size
assert_equal [@subofsub.to_s], @sub.subclasses
assert_equal [], @subofsub.subclasses
+ assert_equal [@sub.to_s, @subofsub.to_s].sort, @parent.subclasses.sort
end
end
diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb
index 5925ae3a61..ddfe1f904f 100644
--- a/activesupport/test/core_ext/date_ext_test.rb
+++ b/activesupport/test/core_ext/date_ext_test.rb
@@ -76,6 +76,7 @@ class DateExtCalculationsTest < Test::Unit::TestCase
assert_equal Date.new(2008,3,31), Date.new(2008,3,31).end_of_quarter
assert_equal Date.new(2008,12,31), Date.new(2008,10,8).end_of_quarter
assert_equal Date.new(2008,6,30), Date.new(2008,4,14).end_of_quarter
+ assert_equal Date.new(2008,6,30), Date.new(2008,5,31).end_of_quarter
assert_equal Date.new(2008,9,30), Date.new(2008,8,21).end_of_quarter
end
@@ -171,7 +172,7 @@ class DateExtCalculationsTest < Test::Unit::TestCase
def test_last_month_on_31st
assert_equal Date.new(2004, 2, 29), Date.new(2004, 3, 31).last_month
- end
+ end
def test_yesterday_constructor
assert_equal Date.today - 1, Date.yesterday
@@ -196,7 +197,11 @@ class DateExtCalculationsTest < Test::Unit::TestCase
def test_end_of_day
assert_equal Time.local(2005,2,21,23,59,59), Date.new(2005,2,21).end_of_day
end
-
+
+ def test_date_acts_like_date
+ assert Date.new.acts_like_date?
+ end
+
def test_xmlschema
with_env_tz 'US/Eastern' do
assert_match(/^1980-02-28T00:00:00-05:?00$/, Date.new(1980, 2, 28).xmlschema)
@@ -208,7 +213,7 @@ class DateExtCalculationsTest < Test::Unit::TestCase
end
end
end
-
+
uses_mocha 'TestDateCurrent' do
def test_current_returns_date_today_when_zone_default_not_set
with_env_tz 'US/Central' do
@@ -217,10 +222,10 @@ class DateExtCalculationsTest < Test::Unit::TestCase
assert_equal Date.new(1999, 12, 31), Date.current
end
end
-
+
def test_current_returns_time_zone_today_when_zone_default_set
silence_warnings do # silence warnings raised by tzinfo gem
- Time.zone_default = TimeZone['Eastern Time (US & Canada)']
+ Time.zone_default = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
with_env_tz 'US/Central' do
Time.stubs(:now).returns Time.local(1999, 12, 31, 23)
assert_equal Date.new(1999, 12, 31), Date.today
@@ -238,5 +243,5 @@ class DateExtCalculationsTest < Test::Unit::TestCase
yield
ensure
old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
- end
+ end
end
diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb
index ed45daf403..854a3a05e1 100644
--- a/activesupport/test/core_ext/date_time_ext_test.rb
+++ b/activesupport/test/core_ext/date_time_ext_test.rb
@@ -219,14 +219,14 @@ class DateTimeExtCalculationsTest < Test::Unit::TestCase
assert_equal Rational(-6, 24), DateTime.local_offset
end
end
-
+
def test_utc?
assert_equal true, DateTime.civil(2005, 2, 21, 10, 11, 12).utc?
assert_equal true, DateTime.civil(2005, 2, 21, 10, 11, 12, 0).utc?
assert_equal false, DateTime.civil(2005, 2, 21, 10, 11, 12, 0.25).utc?
assert_equal false, DateTime.civil(2005, 2, 21, 10, 11, 12, -0.25).utc?
end
-
+
def test_utc_offset
assert_equal 0, DateTime.civil(2005, 2, 21, 10, 11, 12).utc_offset
assert_equal 0, DateTime.civil(2005, 2, 21, 10, 11, 12, 0).utc_offset
@@ -234,7 +234,7 @@ class DateTimeExtCalculationsTest < Test::Unit::TestCase
assert_equal( -21600, DateTime.civil(2005, 2, 21, 10, 11, 12, -0.25).utc_offset )
assert_equal( -18000, DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-5, 24)).utc_offset )
end
-
+
def test_utc
assert_equal DateTime.civil(2005, 2, 21, 16, 11, 12, 0), DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc
assert_equal DateTime.civil(2005, 2, 21, 15, 11, 12, 0), DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-5, 24)).utc
@@ -242,37 +242,37 @@ class DateTimeExtCalculationsTest < Test::Unit::TestCase
assert_equal DateTime.civil(2005, 2, 21, 9, 11, 12, 0), DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(1, 24)).utc
assert_equal DateTime.civil(2005, 2, 21, 9, 11, 12, 0), DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(1, 24)).getutc
end
-
+
def test_formatted_offset_with_utc
assert_equal '+00:00', DateTime.civil(2000).formatted_offset
assert_equal '+0000', DateTime.civil(2000).formatted_offset(false)
assert_equal 'UTC', DateTime.civil(2000).formatted_offset(true, 'UTC')
end
-
+
def test_formatted_offset_with_local
dt = DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-5, 24))
assert_equal '-05:00', dt.formatted_offset
assert_equal '-0500', dt.formatted_offset(false)
end
-
+
def test_compare_with_time
assert_equal 1, DateTime.civil(2000) <=> Time.utc(1999, 12, 31, 23, 59, 59)
assert_equal 0, DateTime.civil(2000) <=> Time.utc(2000, 1, 1, 0, 0, 0)
assert_equal(-1, DateTime.civil(2000) <=> Time.utc(2000, 1, 1, 0, 0, 1))
end
-
+
def test_compare_with_datetime
assert_equal 1, DateTime.civil(2000) <=> DateTime.civil(1999, 12, 31, 23, 59, 59)
assert_equal 0, DateTime.civil(2000) <=> DateTime.civil(2000, 1, 1, 0, 0, 0)
assert_equal(-1, DateTime.civil(2000) <=> DateTime.civil(2000, 1, 1, 0, 0, 1))
end
-
+
def test_compare_with_time_with_zone
- assert_equal 1, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59), TimeZone['UTC'] )
- assert_equal 0, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0), TimeZone['UTC'] )
- assert_equal(-1, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1), TimeZone['UTC'] ))
+ assert_equal 1, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59), ActiveSupport::TimeZone['UTC'] )
+ assert_equal 0, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['UTC'] )
+ assert_equal(-1, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1), ActiveSupport::TimeZone['UTC'] ))
end
-
+
def test_to_f
assert_equal 946684800.0, DateTime.civil(2000).to_f
assert_equal 946684800.0, DateTime.civil(1999,12,31,19,0,0,Rational(-5,24)).to_f
diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb
index 7b17fe71db..f802ed8760 100644
--- a/activesupport/test/core_ext/duration_test.rb
+++ b/activesupport/test/core_ext/duration_test.rb
@@ -29,7 +29,7 @@ class DurationTest < Test::Unit::TestCase
flunk("ArgumentError should be raised, but we got #{$!.class} instead")
end
end
-
+
uses_mocha 'TestDurationSinceAndAgoWithCurrentTime' do
def test_since_and_ago_anchored_to_time_now_when_time_zone_default_not_set
Time.zone_default = nil
@@ -43,10 +43,10 @@ class DurationTest < Test::Unit::TestCase
assert_equal Time.local(1999,12,31,23,59,55), 5.seconds.ago
end
end
-
+
def test_since_and_ago_anchored_to_time_zone_now_when_time_zone_default_set
silence_warnings do # silence warnings raised by tzinfo gem
- Time.zone_default = TimeZone['Eastern Time (US & Canada)']
+ Time.zone_default = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
with_env_tz 'US/Eastern' do
Time.stubs(:now).returns Time.local(2000)
# since
@@ -63,7 +63,7 @@ class DurationTest < Test::Unit::TestCase
Time.zone_default = nil
end
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 f5facd54ad..2315d8f3db 100644
--- a/activesupport/test/core_ext/enumerable_test.rb
+++ b/activesupport/test/core_ext/enumerable_test.rb
@@ -63,4 +63,15 @@ class EnumerableTests < Test::Unit::TestCase
assert_equal({ 5 => payments[0], 15 => payments[1], 10 => payments[2] },
payments.index_by { |p| p.price })
end
+
+ def test_many
+ assert ![].many?
+ assert ![ 1 ].many?
+ assert [ 1, 2 ].many?
+
+ assert ![].many? {|x| x > 1 }
+ assert ![ 2 ].many? {|x| x > 1 }
+ assert ![ 1, 2 ].many? {|x| x > 1 }
+ assert [ 1, 2, 2 ].many? {|x| x > 1 }
+ end
end
diff --git a/activesupport/test/core_ext/module/model_naming_test.rb b/activesupport/test/core_ext/module/model_naming_test.rb
new file mode 100644
index 0000000000..fc73fa5c36
--- /dev/null
+++ b/activesupport/test/core_ext/module/model_naming_test.rb
@@ -0,0 +1,19 @@
+require 'abstract_unit'
+
+class ModelNamingTest < Test::Unit::TestCase
+ def setup
+ @name = ActiveSupport::ModelName.new('Post::TrackBack')
+ end
+
+ def test_singular
+ assert_equal 'post_track_back', @name.singular
+ end
+
+ def test_plural
+ assert_equal 'post_track_backs', @name.plural
+ end
+
+ def test_partial_path
+ assert_equal 'post/track_backs/track_back', @name.partial_path
+ end
+end
diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb
index e53b7193ea..17a0968c0e 100644
--- a/activesupport/test/core_ext/time_ext_test.rb
+++ b/activesupport/test/core_ext/time_ext_test.rb
@@ -449,7 +449,7 @@ class TimeExtCalculationsTest < Test::Unit::TestCase
assert_equal "17:44", time.to_s(:time)
assert_equal "February 21, 2005 17:44", time.to_s(:long)
assert_equal "February 21st, 2005 17:44", time.to_s(:long_ordinal)
- with_env_tz "UTC" do
+ with_env_tz "UTC" do
assert_equal "Mon, 21 Feb 2005 17:44:30 +0000", time.to_s(:rfc822)
end
end
@@ -505,13 +505,13 @@ class TimeExtCalculationsTest < Test::Unit::TestCase
assert_equal 30, Time.days_in_month(11, 2005)
assert_equal 31, Time.days_in_month(12, 2005)
end
-
+
uses_mocha 'TestTimeDaysInMonthWithoutYearArg' do
def test_days_in_month_feb_in_common_year_without_year_arg
Time.stubs(:now).returns(Time.utc(2007))
assert_equal 28, Time.days_in_month(2)
end
-
+
def test_days_in_month_feb_in_leap_year_without_year_arg
Time.stubs(:now).returns(Time.utc(2008))
assert_equal 29, Time.days_in_month(2)
@@ -559,13 +559,13 @@ class TimeExtCalculationsTest < Test::Unit::TestCase
def test_acts_like_time
assert Time.new.acts_like_time?
end
-
+
def test_formatted_offset_with_utc
assert_equal '+00:00', Time.utc(2000).formatted_offset
assert_equal '+0000', Time.utc(2000).formatted_offset(false)
assert_equal 'UTC', Time.utc(2000).formatted_offset(true, 'UTC')
end
-
+
def test_formatted_offset_with_local
with_env_tz 'US/Eastern' do
assert_equal '-05:00', Time.local(2000).formatted_offset
@@ -574,27 +574,27 @@ class TimeExtCalculationsTest < Test::Unit::TestCase
assert_equal '-0400', Time.local(2000, 7).formatted_offset(false)
end
end
-
+
def test_compare_with_time
assert_equal 1, Time.utc(2000) <=> Time.utc(1999, 12, 31, 23, 59, 59, 999)
assert_equal 0, Time.utc(2000) <=> Time.utc(2000, 1, 1, 0, 0, 0)
assert_equal(-1, Time.utc(2000) <=> Time.utc(2000, 1, 1, 0, 0, 0, 001))
end
-
+
def test_compare_with_datetime
assert_equal 1, Time.utc(2000) <=> DateTime.civil(1999, 12, 31, 23, 59, 59)
assert_equal 0, Time.utc(2000) <=> DateTime.civil(2000, 1, 1, 0, 0, 0)
assert_equal(-1, Time.utc(2000) <=> DateTime.civil(2000, 1, 1, 0, 0, 1))
end
-
+
def test_compare_with_time_with_zone
- assert_equal 1, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59), TimeZone['UTC'] )
- assert_equal 0, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0), TimeZone['UTC'] )
- assert_equal(-1, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1), TimeZone['UTC'] ))
+ assert_equal 1, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59), ActiveSupport::TimeZone['UTC'] )
+ assert_equal 0, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['UTC'] )
+ assert_equal(-1, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1), ActiveSupport::TimeZone['UTC'] ))
end
-
+
def test_minus_with_time_with_zone
- assert_equal 86_400.0, Time.utc(2000, 1, 2) - ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), TimeZone['UTC'] )
+ assert_equal 86_400.0, Time.utc(2000, 1, 2) - ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone['UTC'] )
end
def test_time_created_with_local_constructor_cannot_represent_times_during_hour_skipped_by_dst
@@ -608,7 +608,7 @@ class TimeExtCalculationsTest < Test::Unit::TestCase
def test_case_equality
assert Time === Time.utc(2000)
- assert Time === ActiveSupport::TimeWithZone.new(Time.utc(2000), TimeZone['UTC'])
+ assert Time === ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC'])
assert_equal false, Time === DateTime.civil(2000)
end
diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb
index c373bca88d..0977cd8e50 100644
--- a/activesupport/test/core_ext/time_with_zone_test.rb
+++ b/activesupport/test/core_ext/time_with_zone_test.rb
@@ -1,10 +1,10 @@
require 'abstract_unit'
-
+
class TimeWithZoneTest < Test::Unit::TestCase
def setup
@utc = Time.utc(2000, 1, 1, 0)
- @time_zone = TimeZone['Eastern Time (US & Canada)']
+ @time_zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
@twz = ActiveSupport::TimeWithZone.new(@utc, @time_zone)
end
@@ -21,114 +21,114 @@ class TimeWithZoneTest < Test::Unit::TestCase
def test_time_zone
assert_equal @time_zone, @twz.time_zone
end
-
+
def test_in_time_zone
Time.use_zone 'Alaska' do
- assert_equal ActiveSupport::TimeWithZone.new(@utc, TimeZone['Alaska']), @twz.in_time_zone
+ assert_equal ActiveSupport::TimeWithZone.new(@utc, ActiveSupport::TimeZone['Alaska']), @twz.in_time_zone
end
end
def test_in_time_zone_with_argument
- assert_equal ActiveSupport::TimeWithZone.new(@utc, TimeZone['Alaska']), @twz.in_time_zone('Alaska')
+ assert_equal ActiveSupport::TimeWithZone.new(@utc, ActiveSupport::TimeZone['Alaska']), @twz.in_time_zone('Alaska')
end
-
+
def test_in_time_zone_with_new_zone_equal_to_old_zone_does_not_create_new_object
- assert_equal @twz.object_id, @twz.in_time_zone(TimeZone['Eastern Time (US & Canada)']).object_id
+ assert_equal @twz.object_id, @twz.in_time_zone(ActiveSupport::TimeZone['Eastern Time (US & Canada)']).object_id
end
def test_utc?
assert_equal false, @twz.utc?
- assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), TimeZone['UTC']).utc?
+ assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC']).utc?
end
-
+
def test_formatted_offset
silence_warnings do # silence warnings raised by tzinfo gem
assert_equal '-05:00', @twz.formatted_offset
assert_equal '-04:00', ActiveSupport::TimeWithZone.new(Time.utc(2000, 6), @time_zone).formatted_offset #dst
end
end
-
+
def test_dst?
silence_warnings do # silence warnings raised by tzinfo gem
assert_equal false, @twz.dst?
assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000, 6), @time_zone).dst?
end
end
-
+
def test_zone
silence_warnings do # silence warnings raised by tzinfo gem
assert_equal 'EST', @twz.zone
assert_equal 'EDT', ActiveSupport::TimeWithZone.new(Time.utc(2000, 6), @time_zone).zone #dst
end
end
-
+
def test_to_json
silence_warnings do # silence warnings raised by tzinfo gem
assert_equal "\"1999/12/31 19:00:00 -0500\"", @twz.to_json
end
end
-
+
def test_to_json_with_use_standard_json_time_format_config_set_to_true
old, ActiveSupport.use_standard_json_time_format = ActiveSupport.use_standard_json_time_format, true
assert_equal "\"1999-12-31T19:00:00-05:00\"", @twz.to_json
ensure
ActiveSupport.use_standard_json_time_format = old
end
-
+
def test_strftime
silence_warnings do # silence warnings raised by tzinfo gem
assert_equal '1999-12-31 19:00:00 EST -0500', @twz.strftime('%Y-%m-%d %H:%M:%S %Z %z')
end
end
-
+
def test_inspect
silence_warnings do # silence warnings raised by tzinfo gem
assert_equal 'Fri, 31 Dec 1999 19:00:00 EST -05:00', @twz.inspect
end
end
-
+
def test_to_s
silence_warnings do # silence warnings raised by tzinfo gem
assert_equal '1999-12-31 19:00:00 -0500', @twz.to_s
end
end
-
+
def test_to_s_db
silence_warnings do # silence warnings raised by tzinfo gem
assert_equal '2000-01-01 00:00:00', @twz.to_s(:db)
end
end
-
+
def test_xmlschema
silence_warnings do # silence warnings raised by tzinfo gem
assert_equal "1999-12-31T19:00:00-05:00", @twz.xmlschema
end
end
-
+
def test_to_yaml
silence_warnings do # silence warnings raised by tzinfo gem
assert_equal "--- 1999-12-31 19:00:00 -05:00\n", @twz.to_yaml
end
end
-
+
def test_ruby_to_yaml
silence_warnings do
assert_equal "--- \n:twz: 2000-01-01 00:00:00 Z\n", {:twz => @twz}.to_yaml
end
end
-
+
def test_httpdate
silence_warnings do # silence warnings raised by tzinfo gem
assert_equal 'Sat, 01 Jan 2000 00:00:00 GMT', @twz.httpdate
end
end
-
+
def test_rfc2822
silence_warnings do # silence warnings raised by tzinfo gem
assert_equal "Fri, 31 Dec 1999 19:00:00 -0500", @twz.rfc2822
end
end
-
+
def test_compare_with_time
assert_equal 1, @twz <=> Time.utc(1999, 12, 31, 23, 59, 59)
assert_equal 0, @twz <=> Time.utc(2000, 1, 1, 0, 0, 0)
@@ -142,27 +142,27 @@ class TimeWithZoneTest < Test::Unit::TestCase
end
def test_compare_with_time_with_zone
- assert_equal 1, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59), TimeZone['UTC'] )
- assert_equal 0, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0), TimeZone['UTC'] )
- assert_equal(-1, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1), TimeZone['UTC'] ))
+ assert_equal 1, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59), ActiveSupport::TimeZone['UTC'] )
+ assert_equal 0, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['UTC'] )
+ assert_equal(-1, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1), ActiveSupport::TimeZone['UTC'] ))
end
-
+
def test_between?
assert @twz.between?(Time.utc(1999,12,31,23,59,59), Time.utc(2000,1,1,0,0,1))
assert_equal false, @twz.between?(Time.utc(2000,1,1,0,0,1), Time.utc(2000,1,1,0,0,2))
end
-
+
def test_eql?
assert @twz.eql?(Time.utc(2000))
- assert @twz.eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), TimeZone["Hawaii"]) )
+ assert @twz.eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Hawaii"]) )
end
-
+
def test_plus_with_integer
silence_warnings do # silence warnings raised by tzinfo gem
assert_equal Time.utc(1999, 12, 31, 19, 0 ,5), (@twz + 5).time
end
end
-
+
def test_plus_with_integer_when_self_wraps_datetime
silence_warnings do # silence warnings raised by tzinfo gem
datetime = DateTime.civil(2000, 1, 1, 0)
@@ -170,26 +170,26 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal DateTime.civil(1999, 12, 31, 19, 0 ,5), (twz + 5).time
end
end
-
+
def test_plus_when_crossing_time_class_limit
silence_warnings do # silence warnings raised by tzinfo gem
twz = ActiveSupport::TimeWithZone.new(Time.utc(2038, 1, 19), @time_zone)
assert_equal [0, 0, 19, 19, 1, 2038], (twz + 86_400).to_a[0,6]
end
end
-
+
def test_plus_with_duration
silence_warnings do # silence warnings raised by tzinfo gem
assert_equal Time.utc(2000, 1, 5, 19, 0 ,0), (@twz + 5.days).time
end
end
-
+
def test_minus_with_integer
silence_warnings do # silence warnings raised by tzinfo gem
assert_equal Time.utc(1999, 12, 31, 18, 59 ,55), (@twz - 5).time
end
end
-
+
def test_minus_with_integer_when_self_wraps_datetime
silence_warnings do # silence warnings raised by tzinfo gem
datetime = DateTime.civil(2000, 1, 1, 0)
@@ -197,24 +197,24 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal DateTime.civil(1999, 12, 31, 18, 59 ,55), (twz - 5).time
end
end
-
+
def test_minus_with_duration
silence_warnings do # silence warnings raised by tzinfo gem
assert_equal Time.utc(1999, 12, 26, 19, 0 ,0), (@twz - 5.days).time
end
end
-
+
def test_minus_with_time
- assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), TimeZone['UTC'] ) - Time.utc(2000, 1, 1)
- assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), TimeZone['Hawaii'] ) - Time.utc(2000, 1, 1)
+ assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone['UTC'] ) - Time.utc(2000, 1, 1)
+ assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone['Hawaii'] ) - Time.utc(2000, 1, 1)
end
-
+
def test_minus_with_time_with_zone
- twz1 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), TimeZone['UTC'] )
- twz2 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), TimeZone['UTC'] )
+ twz1 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone['UTC'] )
+ twz2 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone['UTC'] )
assert_equal 86_400.0, twz2 - twz1
end
-
+
def test_plus_and_minus_enforce_spring_dst_rules
silence_warnings do # silence warnings raised by tzinfo gem
utc = Time.utc(2006,4,2,6,59,59) # == Apr 2 2006 01:59:59 EST; i.e., 1 second before daylight savings start
@@ -232,7 +232,7 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal 'EST', twz.zone
end
end
-
+
def test_plus_and_minus_enforce_fall_dst_rules
silence_warnings do # silence warnings raised by tzinfo gem
utc = Time.utc(2006,10,29,5,59,59) # == Oct 29 2006 01:59:59 EST; i.e., 1 second before daylight savings end
@@ -250,25 +250,25 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal 'EDT', twz.zone
end
end
-
+
def test_to_a
silence_warnings do # silence warnings raised by tzinfo gem
- assert_equal [45, 30, 5, 1, 2, 2000, 2, 32, false, "HST"], ActiveSupport::TimeWithZone.new( Time.utc(2000, 2, 1, 15, 30, 45), TimeZone['Hawaii'] ).to_a
+ assert_equal [45, 30, 5, 1, 2, 2000, 2, 32, false, "HST"], ActiveSupport::TimeWithZone.new( Time.utc(2000, 2, 1, 15, 30, 45), ActiveSupport::TimeZone['Hawaii'] ).to_a
end
end
-
+
def test_to_f
- result = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), TimeZone['Hawaii'] ).to_f
+ result = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone['Hawaii'] ).to_f
assert_equal 946684800.0, result
assert result.is_a?(Float)
end
-
+
def test_to_i
- result = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), TimeZone['Hawaii'] ).to_i
+ result = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone['Hawaii'] ).to_i
assert_equal 946684800, result
assert result.is_a?(Integer)
end
-
+
def test_to_time
assert_equal @twz, @twz.to_time
end
@@ -276,55 +276,55 @@ class TimeWithZoneTest < Test::Unit::TestCase
def test_to_date
silence_warnings do # silence warnings raised by tzinfo gem
# 1 sec before midnight Jan 1 EST
- assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 4, 59, 59), TimeZone['Eastern Time (US & Canada)'] ).to_date
+ assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 4, 59, 59), ActiveSupport::TimeZone['Eastern Time (US & Canada)'] ).to_date
# midnight Jan 1 EST
- assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 5, 0, 0), TimeZone['Eastern Time (US & Canada)'] ).to_date
+ assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 5, 0, 0), ActiveSupport::TimeZone['Eastern Time (US & Canada)'] ).to_date
# 1 sec before midnight Jan 2 EST
- assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 4, 59, 59), TimeZone['Eastern Time (US & Canada)'] ).to_date
+ assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 4, 59, 59), ActiveSupport::TimeZone['Eastern Time (US & Canada)'] ).to_date
# midnight Jan 2 EST
- assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 5, 0, 0), TimeZone['Eastern Time (US & Canada)'] ).to_date
+ assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 5, 0, 0), ActiveSupport::TimeZone['Eastern Time (US & Canada)'] ).to_date
end
end
-
+
def test_to_datetime
silence_warnings do # silence warnings raised by tzinfo gem
assert_equal DateTime.civil(1999, 12, 31, 19, 0, 0, Rational(-18_000, 86_400)), @twz.to_datetime
end
end
-
+
def test_acts_like_time
assert @twz.acts_like?(:time)
assert ActiveSupport::TimeWithZone.new(DateTime.civil(2000), @time_zone).acts_like?(:time)
end
-
+
def test_acts_like_date
assert_equal false, @twz.acts_like?(:date)
assert_equal false, ActiveSupport::TimeWithZone.new(DateTime.civil(2000), @time_zone).acts_like?(:date)
end
-
+
def test_is_a
assert @twz.is_a?(Time)
assert @twz.kind_of?(Time)
assert @twz.is_a?(ActiveSupport::TimeWithZone)
end
-
+
def test_method_missing_with_time_return_value
silence_warnings do # silence warnings raised by tzinfo gem
assert_instance_of ActiveSupport::TimeWithZone, @twz.months_since(1)
assert_equal Time.utc(2000, 1, 31, 19, 0 ,0), @twz.months_since(1).time
end
end
-
+
def test_marshal_dump_and_load
silence_warnings do # silence warnings raised by tzinfo gem
marshal_str = Marshal.dump(@twz)
mtime = Marshal.load(marshal_str)
assert_equal Time.utc(2000, 1, 1, 0), mtime.utc
- assert_equal TimeZone['Eastern Time (US & Canada)'], mtime.time_zone
+ assert_equal ActiveSupport::TimeZone['Eastern Time (US & Canada)'], mtime.time_zone
assert_equal Time.utc(1999, 12, 31, 19), mtime.time
end
end
-
+
def test_marshal_dump_and_load_with_tzinfo_identifier
silence_warnings do # silence warnings raised by tzinfo gem
twz = ActiveSupport::TimeWithZone.new(@utc, TZInfo::Timezone.get('America/New_York'))
@@ -335,35 +335,37 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal Time.utc(1999, 12, 31, 19), mtime.time
end
end
-
- def test_method_missing_with_non_time_return_value
- silence_warnings do # silence warnings raised by tzinfo gem
- @twz.time.expects(:foo).returns('bar')
- assert_equal 'bar', @twz.foo
+
+ uses_mocha 'TestDatePartValueMethods' do
+ def test_method_missing_with_non_time_return_value
+ silence_warnings do # silence warnings raised by tzinfo gem
+ @twz.time.expects(:foo).returns('bar')
+ assert_equal 'bar', @twz.foo
+ end
end
- end
-
- def test_date_part_value_methods
- silence_warnings do # silence warnings raised by tzinfo gem
- twz = ActiveSupport::TimeWithZone.new(Time.utc(1999,12,31,19,18,17,500), @time_zone)
- twz.stubs(:method_missing).returns(nil) #ensure these methods are defined directly on class
- assert_equal 1999, twz.year
- assert_equal 12, twz.month
- assert_equal 31, twz.day
- assert_equal 14, twz.hour
- assert_equal 18, twz.min
- assert_equal 17, twz.sec
- assert_equal 500, twz.usec
+
+ def test_date_part_value_methods
+ silence_warnings do # silence warnings raised by tzinfo gem
+ twz = ActiveSupport::TimeWithZone.new(Time.utc(1999,12,31,19,18,17,500), @time_zone)
+ twz.stubs(:method_missing).returns(nil) #ensure these methods are defined directly on class
+ assert_equal 1999, twz.year
+ assert_equal 12, twz.month
+ assert_equal 31, twz.day
+ assert_equal 14, twz.hour
+ assert_equal 18, twz.min
+ assert_equal 17, twz.sec
+ assert_equal 500, twz.usec
+ end
end
end
-
+
def test_usec_returns_0_when_datetime_is_wrapped
silence_warnings do # silence warnings raised by tzinfo gem
twz = ActiveSupport::TimeWithZone.new(DateTime.civil(2000), @time_zone)
assert_equal 0, twz.usec
end
end
-
+
def test_utc_to_local_conversion_saves_period_in_instance_variable
silence_warnings do # silence warnings raised by tzinfo gem
assert_nil @twz.instance_variable_get('@period')
@@ -371,14 +373,14 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_kind_of TZInfo::TimezonePeriod, @twz.instance_variable_get('@period')
end
end
-
+
def test_instance_created_with_local_time_returns_correct_utc_time
silence_warnings do # silence warnings raised by tzinfo gem
twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(1999, 12, 31, 19))
assert_equal Time.utc(2000), twz.utc
end
end
-
+
def test_instance_created_with_local_time_enforces_spring_dst_rules
silence_warnings do # silence warnings raised by tzinfo gem
twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,4,2,2)) # first second of DST
@@ -387,7 +389,7 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal 'EDT', twz.zone
end
end
-
+
def test_instance_created_with_local_time_enforces_fall_dst_rules
silence_warnings do # silence warnings raised by tzinfo gem
twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,10,29,1)) # 1AM can be either DST or non-DST; we'll pick DST
@@ -396,14 +398,14 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal 'EDT', twz.zone
end
end
-
+
def test_ruby_19_weekday_name_query_methods
ruby_19_or_greater = RUBY_VERSION >= '1.9'
%w(sunday? monday? tuesday? wednesday? thursday? friday? saturday?).each do |name|
assert_equal ruby_19_or_greater, @twz.respond_to?(name)
end
end
-
+
def test_utc_to_local_conversion_with_far_future_datetime
silence_warnings do # silence warnings raised by tzinfo gem
assert_equal [0,0,19,31,12,2049], ActiveSupport::TimeWithZone.new(DateTime.civil(2050), @time_zone).to_a[0,6]
@@ -415,7 +417,7 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal DateTime.civil(2050).to_f, ActiveSupport::TimeWithZone.new(nil, @time_zone, DateTime.civil(2049,12,31,19)).to_f
end
end
-
+
def test_change
assert_equal "Fri, 31 Dec 1999 19:00:00 EST -05:00", @twz.inspect
assert_equal "Mon, 31 Dec 2001 19:00:00 EST -05:00", @twz.change(:year => 2001).inspect
@@ -426,7 +428,7 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal "Fri, 31 Dec 1999 19:15:00 EST -05:00", @twz.change(:min => 15).inspect
assert_equal "Fri, 31 Dec 1999 19:00:30 EST -05:00", @twz.change(:sec => 30).inspect
end
-
+
def test_advance
assert_equal "Fri, 31 Dec 1999 19:00:00 EST -05:00", @twz.inspect
assert_equal "Mon, 31 Dec 2001 19:00:00 EST -05:00", @twz.advance(:years => 2).inspect
@@ -436,77 +438,77 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal "Fri, 31 Dec 1999 19:15:00 EST -05:00", @twz.advance(:minutes => 15).inspect
assert_equal "Fri, 31 Dec 1999 19:00:30 EST -05:00", @twz.advance(:seconds => 30).inspect
end
-
+
def beginning_of_year
assert_equal "Fri, 31 Dec 1999 19:00:00 EST -05:00", @twz.inspect
assert_equal "Fri, 01 Jan 1999 00:00:00 EST -05:00", @twz.beginning_of_year.inspect
end
-
+
def end_of_year
assert_equal "Fri, 31 Dec 1999 19:00:00 EST -05:00", @twz.inspect
assert_equal "Fri, 31 Dec 1999 23:59:59 EST -05:00", @twz.end_of_year.inspect
end
-
+
def beginning_of_month
assert_equal "Fri, 31 Dec 1999 19:00:00 EST -05:00", @twz.inspect
assert_equal "Fri, 01 Dec 1999 00:00:00 EST -05:00", @twz.beginning_of_month.inspect
end
-
+
def end_of_month
assert_equal "Fri, 31 Dec 1999 19:00:00 EST -05:00", @twz.inspect
assert_equal "Fri, 31 Dec 1999 23:59:59 EST -05:00", @twz.end_of_month.inspect
end
-
+
def beginning_of_day
assert_equal "Fri, 31 Dec 1999 19:00:00 EST -05:00", @twz.inspect
assert_equal "Fri, 31 Dec 1999 00:00:00 EST -05:00", @twz.beginning_of_day.inspect
end
-
+
def end_of_day
assert_equal "Fri, 31 Dec 1999 19:00:00 EST -05:00", @twz.inspect
assert_equal "Fri, 31 Dec 1999 23:59:59 EST -05:00", @twz.end_of_day.inspect
end
-
+
def test_since
assert_equal "Fri, 31 Dec 1999 19:00:01 EST -05:00", @twz.since(1).inspect
end
-
+
def test_ago
assert_equal "Fri, 31 Dec 1999 18:59:59 EST -05:00", @twz.ago(1).inspect
end
-
+
def test_seconds_since_midnight
assert_equal 19 * 60 * 60, @twz.seconds_since_midnight
end
-
+
def test_advance_1_year_from_leap_day
twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2004,2,29))
assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.advance(:years => 1).inspect
assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.years_since(1).inspect
assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", (twz + 1.year).inspect
end
-
+
def test_advance_1_month_from_last_day_of_january
twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2005,1,31))
assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.advance(:months => 1).inspect
assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.months_since(1).inspect
assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", (twz + 1.month).inspect
end
-
+
def test_advance_1_month_from_last_day_of_january_during_leap_year
twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2000,1,31))
assert_equal "Tue, 29 Feb 2000 00:00:00 EST -05:00", twz.advance(:months => 1).inspect
assert_equal "Tue, 29 Feb 2000 00:00:00 EST -05:00", twz.months_since(1).inspect
assert_equal "Tue, 29 Feb 2000 00:00:00 EST -05:00", (twz + 1.month).inspect
end
-
+
def test_advance_1_month_into_spring_dst_gap
twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,3,2,2))
assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.advance(:months => 1).inspect
assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.months_since(1).inspect
assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", (twz + 1.month).inspect
end
-
+
def test_advance_1_second_into_spring_dst_gap
twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,4,2,1,59,59))
assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.advance(:seconds => 1).inspect
@@ -519,11 +521,11 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < Test::Unit::TestCase
def setup
@t, @dt = Time.utc(2000), DateTime.civil(2000)
end
-
+
def teardown
Time.zone = nil
end
-
+
def test_in_time_zone
silence_warnings do # silence warnings raised by tzinfo gem
Time.use_zone 'Alaska' do
@@ -554,7 +556,7 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < Test::Unit::TestCase
end
end
end
-
+
def test_in_time_zone_with_time_local_instance
silence_warnings do # silence warnings raised by tzinfo gem
with_env_tz 'US/Eastern' do
@@ -563,85 +565,85 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < Test::Unit::TestCase
end
end
end
-
+
def test_use_zone
Time.zone = 'Alaska'
Time.use_zone 'Hawaii' do
- assert_equal TimeZone['Hawaii'], Time.zone
+ assert_equal ActiveSupport::TimeZone['Hawaii'], Time.zone
end
- assert_equal TimeZone['Alaska'], Time.zone
+ assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone
end
-
+
def test_use_zone_with_exception_raised
Time.zone = 'Alaska'
assert_raises RuntimeError do
Time.use_zone('Hawaii') { raise RuntimeError }
end
- assert_equal TimeZone['Alaska'], Time.zone
+ assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone
end
-
+
def test_time_zone_getter_and_setter
- Time.zone = TimeZone['Alaska']
- assert_equal TimeZone['Alaska'], Time.zone
+ Time.zone = ActiveSupport::TimeZone['Alaska']
+ assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone
Time.zone = 'Alaska'
- assert_equal TimeZone['Alaska'], Time.zone
+ assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone
Time.zone = -9.hours
- assert_equal TimeZone['Alaska'], Time.zone
+ assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone
Time.zone = nil
assert_equal nil, Time.zone
end
-
+
def test_time_zone_getter_and_setter_with_zone_default
- Time.zone_default = TimeZone['Alaska']
- assert_equal TimeZone['Alaska'], Time.zone
- Time.zone = TimeZone['Hawaii']
- assert_equal TimeZone['Hawaii'], Time.zone
+ Time.zone_default = ActiveSupport::TimeZone['Alaska']
+ assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone
+ Time.zone = ActiveSupport::TimeZone['Hawaii']
+ assert_equal ActiveSupport::TimeZone['Hawaii'], Time.zone
Time.zone = nil
- assert_equal TimeZone['Alaska'], Time.zone
+ assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone
ensure
Time.zone_default = nil
end
-
+
def test_time_zone_setter_is_thread_safe
Time.use_zone 'Paris' do
t1 = Thread.new { Time.zone = 'Alaska' }.join
t2 = Thread.new { Time.zone = 'Hawaii' }.join
assert t1.stop?, "Thread 1 did not finish running"
assert t2.stop?, "Thread 2 did not finish running"
- assert_equal TimeZone['Paris'], Time.zone
- assert_equal TimeZone['Alaska'], t1[:time_zone]
- assert_equal TimeZone['Hawaii'], t2[:time_zone]
+ assert_equal ActiveSupport::TimeZone['Paris'], Time.zone
+ assert_equal ActiveSupport::TimeZone['Alaska'], t1[:time_zone]
+ assert_equal ActiveSupport::TimeZone['Hawaii'], t2[:time_zone]
end
end
-
+
def test_time_zone_setter_with_tzinfo_timezone_object_wraps_in_rails_time_zone
silence_warnings do # silence warnings raised by tzinfo gem
tzinfo = TZInfo::Timezone.get('America/New_York')
Time.zone = tzinfo
- assert_kind_of TimeZone, Time.zone
+ assert_kind_of ActiveSupport::TimeZone, Time.zone
assert_equal tzinfo, Time.zone.tzinfo
assert_equal 'America/New_York', Time.zone.name
assert_equal(-18_000, Time.zone.utc_offset)
end
end
-
+
def test_time_zone_setter_with_tzinfo_timezone_identifier_does_lookup_and_wraps_in_rails_time_zone
silence_warnings do # silence warnings raised by tzinfo gem
Time.zone = 'America/New_York'
- assert_kind_of TimeZone, Time.zone
+ assert_kind_of ActiveSupport::TimeZone, Time.zone
assert_equal 'America/New_York', Time.zone.tzinfo.name
assert_equal 'America/New_York', Time.zone.name
assert_equal(-18_000, Time.zone.utc_offset)
end
end
-
+
def test_time_zone_setter_with_non_identifying_argument_returns_nil
Time.zone = 'foo'
assert_equal nil, Time.zone
Time.zone = -15.hours
assert_equal nil, Time.zone
end
-
+
uses_mocha 'TestTimeCurrent' do
def test_current_returns_time_now_when_zone_default_not_set
with_env_tz 'US/Eastern' do
@@ -650,10 +652,10 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < Test::Unit::TestCase
assert_equal Time.local(2000), Time.current
end
end
-
+
def test_current_returns_time_zone_now_when_zone_default_set
silence_warnings do # silence warnings raised by tzinfo gem
- Time.zone_default = TimeZone['Eastern Time (US & Canada)']
+ Time.zone_default = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
with_env_tz 'US/Eastern' do
Time.stubs(:now).returns Time.local(2000)
assert_equal true, Time.current.is_a?(ActiveSupport::TimeWithZone)
@@ -665,7 +667,7 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < Test::Unit::TestCase
Time.zone_default = nil
end
end
-
+
protected
def with_env_tz(new_tz = 'US/Eastern')
old_tz, ENV['TZ'] = ENV['TZ'], new_tz
diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb
index 0309ab6858..038547a862 100644
--- a/activesupport/test/dependencies_test.rb
+++ b/activesupport/test/dependencies_test.rb
@@ -15,31 +15,31 @@ end
class DependenciesTest < Test::Unit::TestCase
def teardown
- Dependencies.clear
+ ActiveSupport::Dependencies.clear
end
def with_loading(*from)
- old_mechanism, Dependencies.mechanism = Dependencies.mechanism, :load
+ old_mechanism, ActiveSupport::Dependencies.mechanism = ActiveSupport::Dependencies.mechanism, :load
dir = File.dirname(__FILE__)
- prior_load_paths = Dependencies.load_paths
- Dependencies.load_paths = from.collect { |f| "#{dir}/#{f}" }
+ prior_load_paths = ActiveSupport::Dependencies.load_paths
+ ActiveSupport::Dependencies.load_paths = from.collect { |f| "#{dir}/#{f}" }
yield
ensure
- Dependencies.load_paths = prior_load_paths
- Dependencies.mechanism = old_mechanism
- Dependencies.explicitly_unloadable_constants = []
+ ActiveSupport::Dependencies.load_paths = prior_load_paths
+ ActiveSupport::Dependencies.mechanism = old_mechanism
+ ActiveSupport::Dependencies.explicitly_unloadable_constants = []
end
def test_tracking_loaded_files
require_dependency 'dependencies/service_one'
require_dependency 'dependencies/service_two'
- assert_equal 2, Dependencies.loaded.size
+ assert_equal 2, ActiveSupport::Dependencies.loaded.size
end
def test_tracking_identical_loaded_files
require_dependency 'dependencies/service_one'
require_dependency 'dependencies/service_one'
- assert_equal 1, Dependencies.loaded.size
+ assert_equal 1, ActiveSupport::Dependencies.loaded.size
end
def test_missing_dependency_raises_missing_source_file
@@ -64,46 +64,46 @@ class DependenciesTest < Test::Unit::TestCase
end
assert_equal count + 1, $raises_exception_load_count
- assert !Dependencies.loaded.include?(filename)
- assert !Dependencies.history.include?(filename)
+ assert !ActiveSupport::Dependencies.loaded.include?(filename)
+ assert !ActiveSupport::Dependencies.history.include?(filename)
end
end
end
def test_warnings_should_be_enabled_on_first_load
with_loading 'dependencies' do
- old_warnings, Dependencies.warnings_on_first_load = Dependencies.warnings_on_first_load, true
+ old_warnings, ActiveSupport::Dependencies.warnings_on_first_load = ActiveSupport::Dependencies.warnings_on_first_load, true
filename = "check_warnings"
expanded = File.expand_path("test/dependencies/#{filename}")
$check_warnings_load_count = 0
- assert !Dependencies.loaded.include?(expanded)
- assert !Dependencies.history.include?(expanded)
+ assert !ActiveSupport::Dependencies.loaded.include?(expanded)
+ assert !ActiveSupport::Dependencies.history.include?(expanded)
silence_warnings { require_dependency filename }
assert_equal 1, $check_warnings_load_count
assert_equal true, $checked_verbose, 'On first load warnings should be enabled.'
- assert Dependencies.loaded.include?(expanded)
- Dependencies.clear
- assert !Dependencies.loaded.include?(expanded)
- assert Dependencies.history.include?(expanded)
+ assert ActiveSupport::Dependencies.loaded.include?(expanded)
+ ActiveSupport::Dependencies.clear
+ assert !ActiveSupport::Dependencies.loaded.include?(expanded)
+ assert ActiveSupport::Dependencies.history.include?(expanded)
silence_warnings { require_dependency filename }
assert_equal 2, $check_warnings_load_count
assert_equal nil, $checked_verbose, 'After first load warnings should be left alone.'
- assert Dependencies.loaded.include?(expanded)
- Dependencies.clear
- assert !Dependencies.loaded.include?(expanded)
- assert Dependencies.history.include?(expanded)
+ assert ActiveSupport::Dependencies.loaded.include?(expanded)
+ ActiveSupport::Dependencies.clear
+ assert !ActiveSupport::Dependencies.loaded.include?(expanded)
+ assert ActiveSupport::Dependencies.history.include?(expanded)
enable_warnings { require_dependency filename }
assert_equal 3, $check_warnings_load_count
assert_equal true, $checked_verbose, 'After first load warnings should be left alone.'
- assert Dependencies.loaded.include?(expanded)
+ assert ActiveSupport::Dependencies.loaded.include?(expanded)
end
end
@@ -113,7 +113,7 @@ class DependenciesTest < Test::Unit::TestCase
assert_nothing_raised { require_dependency 'mutual_one' }
assert_equal 2, $mutual_dependencies_count
- Dependencies.clear
+ ActiveSupport::Dependencies.clear
$mutual_dependencies_count = 0
assert_nothing_raised { require_dependency 'mutual_two' }
@@ -239,7 +239,7 @@ class DependenciesTest < Test::Unit::TestCase
end
def test_loadable_constants_for_path_should_handle_empty_autoloads
- assert_equal [], Dependencies.loadable_constants_for_path('hello')
+ assert_equal [], ActiveSupport::Dependencies.loadable_constants_for_path('hello')
end
def test_loadable_constants_for_path_should_handle_relative_paths
@@ -247,7 +247,7 @@ class DependenciesTest < Test::Unit::TestCase
relative_root = File.dirname(__FILE__) + '/dependencies'
['', '/'].each do |suffix|
with_loading fake_root + suffix do
- assert_equal ["A::B"], Dependencies.loadable_constants_for_path(relative_root + '/a/b')
+ assert_equal ["A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(relative_root + '/a/b')
end
end
end
@@ -255,106 +255,106 @@ class DependenciesTest < Test::Unit::TestCase
def test_loadable_constants_for_path_should_provide_all_results
fake_root = '/usr/apps/backpack'
with_loading fake_root, fake_root + '/lib' do
- root = Dependencies.load_paths.first
- assert_equal ["Lib::A::B", "A::B"], Dependencies.loadable_constants_for_path(root + '/lib/a/b')
+ root = ActiveSupport::Dependencies.load_paths.first
+ assert_equal ["Lib::A::B", "A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(root + '/lib/a/b')
end
end
def test_loadable_constants_for_path_should_uniq_results
fake_root = '/usr/apps/backpack/lib'
with_loading fake_root, fake_root + '/' do
- root = Dependencies.load_paths.first
- assert_equal ["A::B"], Dependencies.loadable_constants_for_path(root + '/a/b')
+ root = ActiveSupport::Dependencies.load_paths.first
+ assert_equal ["A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(root + '/a/b')
end
end
def test_loadable_constants_with_load_path_without_trailing_slash
path = File.dirname(__FILE__) + '/autoloading_fixtures/class_folder/inline_class.rb'
with_loading 'autoloading_fixtures/class/' do
- assert_equal [], Dependencies.loadable_constants_for_path(path)
+ assert_equal [], ActiveSupport::Dependencies.loadable_constants_for_path(path)
end
end
def test_qualified_const_defined
- assert Dependencies.qualified_const_defined?("Object")
- assert Dependencies.qualified_const_defined?("::Object")
- assert Dependencies.qualified_const_defined?("::Object::Kernel")
- assert Dependencies.qualified_const_defined?("::Object::Dependencies")
- assert Dependencies.qualified_const_defined?("::Test::Unit::TestCase")
+ assert ActiveSupport::Dependencies.qualified_const_defined?("Object")
+ assert ActiveSupport::Dependencies.qualified_const_defined?("::Object")
+ assert ActiveSupport::Dependencies.qualified_const_defined?("::Object::Kernel")
+ assert ActiveSupport::Dependencies.qualified_const_defined?("::Object::Dependencies")
+ assert ActiveSupport::Dependencies.qualified_const_defined?("::Test::Unit::TestCase")
end
def test_qualified_const_defined_should_not_call_method_missing
ModuleWithMissing.missing_count = 0
- assert ! Dependencies.qualified_const_defined?("ModuleWithMissing::A")
+ assert ! ActiveSupport::Dependencies.qualified_const_defined?("ModuleWithMissing::A")
assert_equal 0, ModuleWithMissing.missing_count
- assert ! Dependencies.qualified_const_defined?("ModuleWithMissing::A::B")
+ assert ! ActiveSupport::Dependencies.qualified_const_defined?("ModuleWithMissing::A::B")
assert_equal 0, ModuleWithMissing.missing_count
end
def test_autoloaded?
with_loading 'autoloading_fixtures' do
- assert ! Dependencies.autoloaded?("ModuleFolder")
- assert ! Dependencies.autoloaded?("ModuleFolder::NestedClass")
+ assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
+ assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
- assert Dependencies.autoloaded?(ModuleFolder)
+ assert ActiveSupport::Dependencies.autoloaded?(ModuleFolder)
- assert Dependencies.autoloaded?("ModuleFolder")
- assert ! Dependencies.autoloaded?("ModuleFolder::NestedClass")
+ assert ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
+ assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
- assert Dependencies.autoloaded?(ModuleFolder::NestedClass)
+ assert ActiveSupport::Dependencies.autoloaded?(ModuleFolder::NestedClass)
- assert Dependencies.autoloaded?("ModuleFolder")
- assert Dependencies.autoloaded?("ModuleFolder::NestedClass")
+ assert ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
+ assert ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
- assert Dependencies.autoloaded?("::ModuleFolder")
- assert Dependencies.autoloaded?(:ModuleFolder)
+ assert ActiveSupport::Dependencies.autoloaded?("::ModuleFolder")
+ assert ActiveSupport::Dependencies.autoloaded?(:ModuleFolder)
# Anonymous modules aren't autoloaded.
- assert !Dependencies.autoloaded?(Module.new)
+ assert !ActiveSupport::Dependencies.autoloaded?(Module.new)
nil_name = Module.new
def nil_name.name() nil end
- assert !Dependencies.autoloaded?(nil_name)
+ assert !ActiveSupport::Dependencies.autoloaded?(nil_name)
Object.class_eval { remove_const :ModuleFolder }
end
end
def test_qualified_name_for
- assert_equal "A", Dependencies.qualified_name_for(Object, :A)
- assert_equal "A", Dependencies.qualified_name_for(:Object, :A)
- assert_equal "A", Dependencies.qualified_name_for("Object", :A)
- assert_equal "A", Dependencies.qualified_name_for("::Object", :A)
- assert_equal "A", Dependencies.qualified_name_for("::Kernel", :A)
+ assert_equal "A", ActiveSupport::Dependencies.qualified_name_for(Object, :A)
+ assert_equal "A", ActiveSupport::Dependencies.qualified_name_for(:Object, :A)
+ assert_equal "A", ActiveSupport::Dependencies.qualified_name_for("Object", :A)
+ assert_equal "A", ActiveSupport::Dependencies.qualified_name_for("::Object", :A)
+ assert_equal "A", ActiveSupport::Dependencies.qualified_name_for("::Kernel", :A)
- assert_equal "Dependencies::A", Dependencies.qualified_name_for(:Dependencies, :A)
- assert_equal "Dependencies::A", Dependencies.qualified_name_for(Dependencies, :A)
+ assert_equal "ActiveSupport::Dependencies::A", ActiveSupport::Dependencies.qualified_name_for(:'ActiveSupport::Dependencies', :A)
+ assert_equal "ActiveSupport::Dependencies::A", ActiveSupport::Dependencies.qualified_name_for(ActiveSupport::Dependencies, :A)
end
def test_file_search
with_loading 'dependencies' do
- root = Dependencies.load_paths.first
- assert_equal nil, Dependencies.search_for_file('service_three')
- assert_equal nil, Dependencies.search_for_file('service_three.rb')
- assert_equal root + '/service_one.rb', Dependencies.search_for_file('service_one')
- assert_equal root + '/service_one.rb', Dependencies.search_for_file('service_one.rb')
+ root = ActiveSupport::Dependencies.load_paths.first
+ assert_equal nil, ActiveSupport::Dependencies.search_for_file('service_three')
+ assert_equal nil, ActiveSupport::Dependencies.search_for_file('service_three.rb')
+ assert_equal root + '/service_one.rb', ActiveSupport::Dependencies.search_for_file('service_one')
+ assert_equal root + '/service_one.rb', ActiveSupport::Dependencies.search_for_file('service_one.rb')
end
end
def test_file_search_uses_first_in_load_path
with_loading 'dependencies', 'autoloading_fixtures' do
- deps, autoload = Dependencies.load_paths
+ deps, autoload = ActiveSupport::Dependencies.load_paths
assert_match %r/dependencies/, deps
assert_match %r/autoloading_fixtures/, autoload
- assert_equal deps + '/conflict.rb', Dependencies.search_for_file('conflict')
+ assert_equal deps + '/conflict.rb', ActiveSupport::Dependencies.search_for_file('conflict')
end
with_loading 'autoloading_fixtures', 'dependencies' do
- autoload, deps = Dependencies.load_paths
+ autoload, deps = ActiveSupport::Dependencies.load_paths
assert_match %r/dependencies/, deps
assert_match %r/autoloading_fixtures/, autoload
- assert_equal autoload + '/conflict.rb', Dependencies.search_for_file('conflict')
+ assert_equal autoload + '/conflict.rb', ActiveSupport::Dependencies.search_for_file('conflict')
end
end
@@ -383,7 +383,7 @@ class DependenciesTest < Test::Unit::TestCase
with_loading 'autoloading_fixtures' do
require_dependency '././counting_loader'
assert_equal 1, $counting_loaded_times
- assert_raises(ArgumentError) { Dependencies.load_missing_constant Object, :CountingLoader }
+ assert_raises(ArgumentError) { ActiveSupport::Dependencies.load_missing_constant Object, :CountingLoader }
assert_equal 1, $counting_loaded_times
end
end
@@ -407,12 +407,12 @@ class DependenciesTest < Test::Unit::TestCase
def test_removal_from_tree_should_be_detected
with_loading 'dependencies' do
- root = Dependencies.load_paths.first
+ root = ActiveSupport::Dependencies.load_paths.first
c = ServiceOne
- Dependencies.clear
+ ActiveSupport::Dependencies.clear
assert ! defined?(ServiceOne)
begin
- Dependencies.load_missing_constant(c, :FakeMissing)
+ ActiveSupport::Dependencies.load_missing_constant(c, :FakeMissing)
flunk "Expected exception"
rescue ArgumentError => e
assert_match %r{ServiceOne has been removed from the module tree}i, e.message
@@ -430,25 +430,25 @@ class DependenciesTest < Test::Unit::TestCase
def test_load_once_paths_do_not_add_to_autoloaded_constants
with_loading 'autoloading_fixtures' do
- Dependencies.load_once_paths = Dependencies.load_paths.dup
+ ActiveSupport::Dependencies.load_once_paths = ActiveSupport::Dependencies.load_paths.dup
- assert ! Dependencies.autoloaded?("ModuleFolder")
- assert ! Dependencies.autoloaded?("ModuleFolder::NestedClass")
- assert ! Dependencies.autoloaded?(ModuleFolder)
+ assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
+ assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
+ assert ! ActiveSupport::Dependencies.autoloaded?(ModuleFolder)
1 if ModuleFolder::NestedClass # 1 if to avoid warning
- assert ! Dependencies.autoloaded?(ModuleFolder::NestedClass)
+ assert ! ActiveSupport::Dependencies.autoloaded?(ModuleFolder::NestedClass)
end
ensure
Object.class_eval { remove_const :ModuleFolder }
- Dependencies.load_once_paths = []
+ ActiveSupport::Dependencies.load_once_paths = []
end
def test_application_should_special_case_application_controller
with_loading 'autoloading_fixtures' do
require_dependency 'application'
assert_equal 10, ApplicationController
- assert Dependencies.autoloaded?(:ApplicationController)
+ assert ActiveSupport::Dependencies.autoloaded?(:ApplicationController)
end
end
@@ -463,15 +463,15 @@ class DependenciesTest < Test::Unit::TestCase
def test_preexisting_constants_are_not_marked_as_autoloaded
with_loading 'autoloading_fixtures' do
require_dependency 'e'
- assert Dependencies.autoloaded?(:E)
- Dependencies.clear
+ assert ActiveSupport::Dependencies.autoloaded?(:E)
+ ActiveSupport::Dependencies.clear
end
Object.const_set :E, Class.new
with_loading 'autoloading_fixtures' do
require_dependency 'e'
- assert ! Dependencies.autoloaded?(:E), "E shouldn't be marked autoloaded!"
- Dependencies.clear
+ assert ! ActiveSupport::Dependencies.autoloaded?(:E), "E shouldn't be marked autoloaded!"
+ ActiveSupport::Dependencies.clear
end
ensure
@@ -483,11 +483,11 @@ class DependenciesTest < Test::Unit::TestCase
Object.const_set :M, Module.new
M.unloadable
- Dependencies.clear
+ ActiveSupport::Dependencies.clear
assert ! defined?(M)
Object.const_set :M, Module.new
- Dependencies.clear
+ ActiveSupport::Dependencies.clear
assert ! defined?(M), "Dependencies should unload unloadable constants each time"
end
end
@@ -508,24 +508,24 @@ class DependenciesTest < Test::Unit::TestCase
end
def test_new_contants_in_without_constants
- assert_equal [], (Dependencies.new_constants_in(Object) { })
- assert Dependencies.constant_watch_stack.empty?
+ assert_equal [], (ActiveSupport::Dependencies.new_constants_in(Object) { })
+ assert ActiveSupport::Dependencies.constant_watch_stack.empty?
end
def test_new_constants_in_with_a_single_constant
- assert_equal ["Hello"], Dependencies.new_constants_in(Object) {
+ assert_equal ["Hello"], ActiveSupport::Dependencies.new_constants_in(Object) {
Object.const_set :Hello, 10
}.map(&:to_s)
- assert Dependencies.constant_watch_stack.empty?
+ assert ActiveSupport::Dependencies.constant_watch_stack.empty?
ensure
Object.class_eval { remove_const :Hello }
end
def test_new_constants_in_with_nesting
- outer = Dependencies.new_constants_in(Object) do
+ outer = ActiveSupport::Dependencies.new_constants_in(Object) do
Object.const_set :OuterBefore, 10
- assert_equal ["Inner"], Dependencies.new_constants_in(Object) {
+ assert_equal ["Inner"], ActiveSupport::Dependencies.new_constants_in(Object) {
Object.const_set :Inner, 20
}.map(&:to_s)
@@ -533,7 +533,7 @@ class DependenciesTest < Test::Unit::TestCase
end
assert_equal ["OuterAfter", "OuterBefore"], outer.sort.map(&:to_s)
- assert Dependencies.constant_watch_stack.empty?
+ assert ActiveSupport::Dependencies.constant_watch_stack.empty?
ensure
%w(OuterBefore Inner OuterAfter).each do |name|
Object.class_eval { remove_const name if const_defined?(name) }
@@ -543,10 +543,10 @@ class DependenciesTest < Test::Unit::TestCase
def test_new_constants_in_module
Object.const_set :M, Module.new
- outer = Dependencies.new_constants_in(M) do
+ outer = ActiveSupport::Dependencies.new_constants_in(M) do
M.const_set :OuterBefore, 10
- inner = Dependencies.new_constants_in(M) do
+ inner = ActiveSupport::Dependencies.new_constants_in(M) do
M.const_set :Inner, 20
end
assert_equal ["M::Inner"], inner
@@ -554,17 +554,17 @@ class DependenciesTest < Test::Unit::TestCase
M.const_set :OuterAfter, 30
end
assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort
- assert Dependencies.constant_watch_stack.empty?
+ assert ActiveSupport::Dependencies.constant_watch_stack.empty?
ensure
Object.class_eval { remove_const :M }
end
def test_new_constants_in_module_using_name
- outer = Dependencies.new_constants_in(:M) do
+ outer = ActiveSupport::Dependencies.new_constants_in(:M) do
Object.const_set :M, Module.new
M.const_set :OuterBefore, 10
- inner = Dependencies.new_constants_in(:M) do
+ inner = ActiveSupport::Dependencies.new_constants_in(:M) do
M.const_set :Inner, 20
end
assert_equal ["M::Inner"], inner
@@ -572,13 +572,13 @@ class DependenciesTest < Test::Unit::TestCase
M.const_set :OuterAfter, 30
end
assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort
- assert Dependencies.constant_watch_stack.empty?
+ assert ActiveSupport::Dependencies.constant_watch_stack.empty?
ensure
Object.class_eval { remove_const :M }
end
def test_new_constants_in_with_inherited_constants
- m = Dependencies.new_constants_in(:Object) do
+ m = ActiveSupport::Dependencies.new_constants_in(:Object) do
Object.class_eval { include ModuleWithConstant }
end
assert_equal [], m
@@ -586,7 +586,7 @@ class DependenciesTest < Test::Unit::TestCase
def test_new_constants_in_with_illegal_module_name_raises_correct_error
assert_raises(NameError) do
- Dependencies.new_constants_in("Illegal-Name") {}
+ ActiveSupport::Dependencies.new_constants_in("Illegal-Name") {}
end
end
@@ -598,10 +598,10 @@ class DependenciesTest < Test::Unit::TestCase
require_dependency 'multiple_constant_file'
assert defined?(MultipleConstantFile)
assert defined?(SiblingConstant)
- assert Dependencies.autoloaded?(:MultipleConstantFile)
- assert Dependencies.autoloaded?(:SiblingConstant)
+ assert ActiveSupport::Dependencies.autoloaded?(:MultipleConstantFile)
+ assert ActiveSupport::Dependencies.autoloaded?(:SiblingConstant)
- Dependencies.clear
+ ActiveSupport::Dependencies.clear
assert ! defined?(MultipleConstantFile)
assert ! defined?(SiblingConstant)
@@ -617,10 +617,10 @@ class DependenciesTest < Test::Unit::TestCase
assert defined?(MultipleConstantFile)
assert defined?(SiblingConstant)
- assert Dependencies.autoloaded?(:MultipleConstantFile)
- assert Dependencies.autoloaded?(:SiblingConstant)
+ assert ActiveSupport::Dependencies.autoloaded?(:MultipleConstantFile)
+ assert ActiveSupport::Dependencies.autoloaded?(:SiblingConstant)
- Dependencies.clear
+ ActiveSupport::Dependencies.clear
assert ! defined?(MultipleConstantFile)
assert ! defined?(SiblingConstant)
@@ -636,10 +636,10 @@ class DependenciesTest < Test::Unit::TestCase
assert defined?(ClassFolder::NestedClass)
assert defined?(ClassFolder::SiblingClass)
- assert Dependencies.autoloaded?("ClassFolder::NestedClass")
- assert Dependencies.autoloaded?("ClassFolder::SiblingClass")
+ assert ActiveSupport::Dependencies.autoloaded?("ClassFolder::NestedClass")
+ assert ActiveSupport::Dependencies.autoloaded?("ClassFolder::SiblingClass")
- Dependencies.clear
+ ActiveSupport::Dependencies.clear
assert ! defined?(ClassFolder::NestedClass)
assert ! defined?(ClassFolder::SiblingClass)
@@ -655,10 +655,10 @@ class DependenciesTest < Test::Unit::TestCase
assert defined?(ClassFolder::NestedClass)
assert defined?(ClassFolder::SiblingClass)
- assert Dependencies.autoloaded?("ClassFolder::NestedClass")
- assert Dependencies.autoloaded?("ClassFolder::SiblingClass")
+ assert ActiveSupport::Dependencies.autoloaded?("ClassFolder::NestedClass")
+ assert ActiveSupport::Dependencies.autoloaded?("ClassFolder::SiblingClass")
- Dependencies.clear
+ ActiveSupport::Dependencies.clear
assert ! defined?(ClassFolder::NestedClass)
assert ! defined?(ClassFolder::SiblingClass)
@@ -693,7 +693,7 @@ class DependenciesTest < Test::Unit::TestCase
def test_autoload_doesnt_shadow_error_when_mechanism_not_set_to_load
with_loading 'autoloading_fixtures' do
- Dependencies.mechanism = :require
+ ActiveSupport::Dependencies.mechanism = :require
2.times do
assert_raise(NameError) {"RaisesNameError".constantize}
end
@@ -727,39 +727,39 @@ class DependenciesTest < Test::Unit::TestCase
def test_remove_constant_handles_double_colon_at_start
Object.const_set 'DeleteMe', Module.new
DeleteMe.const_set 'OrMe', Module.new
- Dependencies.remove_constant "::DeleteMe::OrMe"
+ ActiveSupport::Dependencies.remove_constant "::DeleteMe::OrMe"
assert ! defined?(DeleteMe::OrMe)
assert defined?(DeleteMe)
- Dependencies.remove_constant "::DeleteMe"
+ ActiveSupport::Dependencies.remove_constant "::DeleteMe"
assert ! defined?(DeleteMe)
end
def test_load_once_constants_should_not_be_unloaded
with_loading 'autoloading_fixtures' do
- Dependencies.load_once_paths = Dependencies.load_paths
+ ActiveSupport::Dependencies.load_once_paths = ActiveSupport::Dependencies.load_paths
::A.to_s
assert defined?(A)
- Dependencies.clear
+ ActiveSupport::Dependencies.clear
assert defined?(A)
end
ensure
- Dependencies.load_once_paths = []
+ ActiveSupport::Dependencies.load_once_paths = []
Object.class_eval { remove_const :A if const_defined?(:A) }
end
def test_load_once_paths_should_behave_when_recursively_loading
with_loading 'dependencies', 'autoloading_fixtures' do
- Dependencies.load_once_paths = [Dependencies.load_paths.last]
+ ActiveSupport::Dependencies.load_once_paths = [ActiveSupport::Dependencies.load_paths.last]
assert !defined?(CrossSiteDependency)
assert_nothing_raised { CrossSiteDepender.nil? }
assert defined?(CrossSiteDependency)
- assert !Dependencies.autoloaded?(CrossSiteDependency),
+ assert !ActiveSupport::Dependencies.autoloaded?(CrossSiteDependency),
"CrossSiteDependency shouldn't be marked as autoloaded!"
- Dependencies.clear
+ ActiveSupport::Dependencies.clear
assert defined?(CrossSiteDependency),
"CrossSiteDependency shouldn't have been unloaded!"
end
ensure
- Dependencies.load_once_paths = []
+ ActiveSupport::Dependencies.load_once_paths = []
end
end
diff --git a/activesupport/test/deprecation_test.rb b/activesupport/test/deprecation_test.rb
index ebfa405947..27e9573ce2 100644
--- a/activesupport/test/deprecation_test.rb
+++ b/activesupport/test/deprecation_test.rb
@@ -24,6 +24,11 @@ class Deprecatee
def d; end
def e; end
deprecate :a, :b, :c => :e, :d => "you now need to do something extra for this one"
+
+ module B
+ C = 1
+ end
+ A = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Deprecatee::A', 'Deprecatee::B::C')
end
@@ -83,6 +88,11 @@ class DeprecationTest < Test::Unit::TestCase
assert_not_deprecated { assert_equal @dtc.request.inspect, @dtc.old_request.inspect }
end
+ def test_deprecated_constant_proxy
+ assert_not_deprecated { Deprecatee::B::C }
+ assert_deprecated('Deprecatee::A') { assert_equal Deprecatee::B::C, Deprecatee::A }
+ end
+
def test_assert_deprecation_without_match
assert_deprecated do
@dtc.partially
diff --git a/activesupport/test/gzip_test.rb b/activesupport/test/gzip_test.rb
new file mode 100644
index 0000000000..2a24c0bd0d
--- /dev/null
+++ b/activesupport/test/gzip_test.rb
@@ -0,0 +1,7 @@
+require 'abstract_unit'
+
+class GzipTest < Test::Unit::TestCase
+ def test_compress_should_decompress_to_the_same_value
+ assert_equal "Hello World", ActiveSupport::Gzip.decompress(ActiveSupport::Gzip.compress("Hello World"))
+ end
+end \ No newline at end of file
diff --git a/activesupport/test/inflector_test.rb b/activesupport/test/inflector_test.rb
index 26af245ff7..4ce9cbb705 100644
--- a/activesupport/test/inflector_test.rb
+++ b/activesupport/test/inflector_test.rb
@@ -12,188 +12,188 @@ class InflectorTest < Test::Unit::TestCase
include InflectorTestCases
def test_pluralize_plurals
- assert_equal "plurals", Inflector.pluralize("plurals")
- assert_equal "Plurals", Inflector.pluralize("Plurals")
+ assert_equal "plurals", ActiveSupport::Inflector.pluralize("plurals")
+ assert_equal "Plurals", ActiveSupport::Inflector.pluralize("Plurals")
end
def test_pluralize_empty_string
- assert_equal "", Inflector.pluralize("")
+ assert_equal "", ActiveSupport::Inflector.pluralize("")
end
SingularToPlural.each do |singular, plural|
define_method "test_pluralize_#{singular}" do
- assert_equal(plural, Inflector.pluralize(singular))
- assert_equal(plural.capitalize, Inflector.pluralize(singular.capitalize))
+ assert_equal(plural, ActiveSupport::Inflector.pluralize(singular))
+ assert_equal(plural.capitalize, ActiveSupport::Inflector.pluralize(singular.capitalize))
end
end
SingularToPlural.each do |singular, plural|
define_method "test_singularize_#{plural}" do
- assert_equal(singular, Inflector.singularize(plural))
- assert_equal(singular.capitalize, Inflector.singularize(plural.capitalize))
+ assert_equal(singular, ActiveSupport::Inflector.singularize(plural))
+ assert_equal(singular.capitalize, ActiveSupport::Inflector.singularize(plural.capitalize))
end
end
MixtureToTitleCase.each do |before, titleized|
define_method "test_titleize_#{before}" do
- assert_equal(titleized, Inflector.titleize(before))
+ assert_equal(titleized, ActiveSupport::Inflector.titleize(before))
end
end
def test_camelize
CamelToUnderscore.each do |camel, underscore|
- assert_equal(camel, Inflector.camelize(underscore))
+ assert_equal(camel, ActiveSupport::Inflector.camelize(underscore))
end
end
def test_underscore
CamelToUnderscore.each do |camel, underscore|
- assert_equal(underscore, Inflector.underscore(camel))
+ assert_equal(underscore, ActiveSupport::Inflector.underscore(camel))
end
CamelToUnderscoreWithoutReverse.each do |camel, underscore|
- assert_equal(underscore, Inflector.underscore(camel))
+ assert_equal(underscore, ActiveSupport::Inflector.underscore(camel))
end
end
def test_camelize_with_module
CamelWithModuleToUnderscoreWithSlash.each do |camel, underscore|
- assert_equal(camel, Inflector.camelize(underscore))
+ assert_equal(camel, ActiveSupport::Inflector.camelize(underscore))
end
end
def test_underscore_with_slashes
CamelWithModuleToUnderscoreWithSlash.each do |camel, underscore|
- assert_equal(underscore, Inflector.underscore(camel))
+ assert_equal(underscore, ActiveSupport::Inflector.underscore(camel))
end
end
def test_demodulize
- assert_equal "Account", Inflector.demodulize("MyApplication::Billing::Account")
+ assert_equal "Account", ActiveSupport::Inflector.demodulize("MyApplication::Billing::Account")
end
def test_foreign_key
ClassNameToForeignKeyWithUnderscore.each do |klass, foreign_key|
- assert_equal(foreign_key, Inflector.foreign_key(klass))
+ assert_equal(foreign_key, ActiveSupport::Inflector.foreign_key(klass))
end
ClassNameToForeignKeyWithoutUnderscore.each do |klass, foreign_key|
- assert_equal(foreign_key, Inflector.foreign_key(klass, false))
+ assert_equal(foreign_key, ActiveSupport::Inflector.foreign_key(klass, false))
end
end
def test_tableize
ClassNameToTableName.each do |class_name, table_name|
- assert_equal(table_name, Inflector.tableize(class_name))
+ assert_equal(table_name, ActiveSupport::Inflector.tableize(class_name))
end
end
def test_classify
ClassNameToTableName.each do |class_name, table_name|
- assert_equal(class_name, Inflector.classify(table_name))
- assert_equal(class_name, Inflector.classify("table_prefix." + table_name))
+ assert_equal(class_name, ActiveSupport::Inflector.classify(table_name))
+ assert_equal(class_name, ActiveSupport::Inflector.classify("table_prefix." + table_name))
end
end
def test_classify_with_symbol
assert_nothing_raised do
- assert_equal 'FooBar', Inflector.classify(:foo_bars)
+ assert_equal 'FooBar', ActiveSupport::Inflector.classify(:foo_bars)
end
end
def test_classify_with_leading_schema_name
- assert_equal 'FooBar', Inflector.classify('schema.foo_bar')
+ assert_equal 'FooBar', ActiveSupport::Inflector.classify('schema.foo_bar')
end
def test_humanize
UnderscoreToHuman.each do |underscore, human|
- assert_equal(human, Inflector.humanize(underscore))
+ assert_equal(human, ActiveSupport::Inflector.humanize(underscore))
end
end
def test_constantize
- assert_nothing_raised { assert_equal Ace::Base::Case, Inflector.constantize("Ace::Base::Case") }
- assert_nothing_raised { assert_equal Ace::Base::Case, Inflector.constantize("::Ace::Base::Case") }
- assert_nothing_raised { assert_equal InflectorTest, Inflector.constantize("InflectorTest") }
- assert_nothing_raised { assert_equal InflectorTest, Inflector.constantize("::InflectorTest") }
- assert_raises(NameError) { Inflector.constantize("UnknownClass") }
- assert_raises(NameError) { Inflector.constantize("An invalid string") }
- assert_raises(NameError) { Inflector.constantize("InvalidClass\n") }
+ assert_nothing_raised { assert_equal Ace::Base::Case, ActiveSupport::Inflector.constantize("Ace::Base::Case") }
+ assert_nothing_raised { assert_equal Ace::Base::Case, ActiveSupport::Inflector.constantize("::Ace::Base::Case") }
+ assert_nothing_raised { assert_equal InflectorTest, ActiveSupport::Inflector.constantize("InflectorTest") }
+ assert_nothing_raised { assert_equal InflectorTest, ActiveSupport::Inflector.constantize("::InflectorTest") }
+ assert_raises(NameError) { ActiveSupport::Inflector.constantize("UnknownClass") }
+ assert_raises(NameError) { ActiveSupport::Inflector.constantize("An invalid string") }
+ assert_raises(NameError) { ActiveSupport::Inflector.constantize("InvalidClass\n") }
end
def test_constantize_does_lexical_lookup
- assert_raises(NameError) { Inflector.constantize("Ace::Base::InflectorTest") }
+ assert_raises(NameError) { ActiveSupport::Inflector.constantize("Ace::Base::InflectorTest") }
end
def test_ordinal
OrdinalNumbers.each do |number, ordinalized|
- assert_equal(ordinalized, Inflector.ordinalize(number))
+ assert_equal(ordinalized, ActiveSupport::Inflector.ordinalize(number))
end
end
def test_dasherize
UnderscoresToDashes.each do |underscored, dasherized|
- assert_equal(dasherized, Inflector.dasherize(underscored))
+ assert_equal(dasherized, ActiveSupport::Inflector.dasherize(underscored))
end
end
def test_underscore_as_reverse_of_dasherize
UnderscoresToDashes.each do |underscored, dasherized|
- assert_equal(underscored, Inflector.underscore(Inflector.dasherize(underscored)))
+ assert_equal(underscored, ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.dasherize(underscored)))
end
end
def test_underscore_to_lower_camel
UnderscoreToLowerCamel.each do |underscored, lower_camel|
- assert_equal(lower_camel, Inflector.camelize(underscored, false))
+ assert_equal(lower_camel, ActiveSupport::Inflector.camelize(underscored, false))
end
end
-
+
%w{plurals singulars uncountables}.each do |inflection_type|
class_eval "
def test_clear_#{inflection_type}
- cached_values = Inflector.inflections.#{inflection_type}
- Inflector.inflections.clear :#{inflection_type}
- assert Inflector.inflections.#{inflection_type}.empty?, \"#{inflection_type} inflections should be empty after clear :#{inflection_type}\"
- Inflector.inflections.instance_variable_set :@#{inflection_type}, cached_values
+ cached_values = ActiveSupport::Inflector.inflections.#{inflection_type}
+ ActiveSupport::Inflector.inflections.clear :#{inflection_type}
+ assert ActiveSupport::Inflector.inflections.#{inflection_type}.empty?, \"#{inflection_type} inflections should be empty after clear :#{inflection_type}\"
+ ActiveSupport::Inflector.inflections.instance_variable_set :@#{inflection_type}, cached_values
end
"
end
-
+
def test_clear_all
- cached_values = Inflector.inflections.plurals, Inflector.inflections.singulars, Inflector.inflections.uncountables
- Inflector.inflections.clear :all
- assert Inflector.inflections.plurals.empty?
- assert Inflector.inflections.singulars.empty?
- assert Inflector.inflections.uncountables.empty?
- Inflector.inflections.instance_variable_set :@plurals, cached_values[0]
- Inflector.inflections.instance_variable_set :@singulars, cached_values[1]
- Inflector.inflections.instance_variable_set :@uncountables, cached_values[2]
- end
-
+ cached_values = ActiveSupport::Inflector.inflections.plurals, ActiveSupport::Inflector.inflections.singulars, ActiveSupport::Inflector.inflections.uncountables
+ ActiveSupport::Inflector.inflections.clear :all
+ assert ActiveSupport::Inflector.inflections.plurals.empty?
+ assert ActiveSupport::Inflector.inflections.singulars.empty?
+ assert ActiveSupport::Inflector.inflections.uncountables.empty?
+ ActiveSupport::Inflector.inflections.instance_variable_set :@plurals, cached_values[0]
+ ActiveSupport::Inflector.inflections.instance_variable_set :@singulars, cached_values[1]
+ ActiveSupport::Inflector.inflections.instance_variable_set :@uncountables, cached_values[2]
+ end
+
def test_clear_with_default
- cached_values = Inflector.inflections.plurals, Inflector.inflections.singulars, Inflector.inflections.uncountables
- Inflector.inflections.clear
- assert Inflector.inflections.plurals.empty?
- assert Inflector.inflections.singulars.empty?
- assert Inflector.inflections.uncountables.empty?
- Inflector.inflections.instance_variable_set :@plurals, cached_values[0]
- Inflector.inflections.instance_variable_set :@singulars, cached_values[1]
- Inflector.inflections.instance_variable_set :@uncountables, cached_values[2]
+ cached_values = ActiveSupport::Inflector.inflections.plurals, ActiveSupport::Inflector.inflections.singulars, ActiveSupport::Inflector.inflections.uncountables
+ ActiveSupport::Inflector.inflections.clear
+ assert ActiveSupport::Inflector.inflections.plurals.empty?
+ assert ActiveSupport::Inflector.inflections.singulars.empty?
+ assert ActiveSupport::Inflector.inflections.uncountables.empty?
+ ActiveSupport::Inflector.inflections.instance_variable_set :@plurals, cached_values[0]
+ ActiveSupport::Inflector.inflections.instance_variable_set :@singulars, cached_values[1]
+ ActiveSupport::Inflector.inflections.instance_variable_set :@uncountables, cached_values[2]
end
Irregularities.each do |irregularity|
singular, plural = *irregularity
- Inflector.inflections do |inflect|
+ ActiveSupport::Inflector.inflections do |inflect|
define_method("test_irregularity_between_#{singular}_and_#{plural}") do
inflect.irregular(singular, plural)
- assert_equal singular, Inflector.singularize(plural)
- assert_equal plural, Inflector.pluralize(singular)
+ assert_equal singular, ActiveSupport::Inflector.singularize(plural)
+ assert_equal plural, ActiveSupport::Inflector.pluralize(singular)
end
end
end
[ :all, [] ].each do |scope|
- Inflector.inflections do |inflect|
+ ActiveSupport::Inflector.inflections do |inflect|
define_method("test_clear_inflections_with_#{scope.kind_of?(Array) ? "no_arguments" : scope}") do
# save all the inflections
singulars, plurals, uncountables = inflect.singulars, inflect.plurals, inflect.uncountables
@@ -218,7 +218,7 @@ class InflectorTest < Test::Unit::TestCase
end
{ :singulars => :singular, :plurals => :plural, :uncountables => :uncountable }.each do |scope, method|
- Inflector.inflections do |inflect|
+ ActiveSupport::Inflector.inflections do |inflect|
define_method("test_clear_inflections_with_#{scope}") do
# save the inflections
values = inflect.send(scope)
diff --git a/activesupport/test/ordered_hash_test.rb b/activesupport/test/ordered_hash_test.rb
index 14be48724e..98a6ad6b26 100644
--- a/activesupport/test/ordered_hash_test.rb
+++ b/activesupport/test/ordered_hash_test.rb
@@ -42,4 +42,23 @@ class OrderedHashTest < Test::Unit::TestCase
assert_nil @ordered_hash.delete(bad_key)
end
+
+ def test_has_key
+ assert_equal true, @ordered_hash.has_key?('blue')
+ assert_equal true, @ordered_hash.key?('blue')
+ assert_equal true, @ordered_hash.include?('blue')
+ assert_equal true, @ordered_hash.member?('blue')
+
+ assert_equal false, @ordered_hash.has_key?('indigo')
+ assert_equal false, @ordered_hash.key?('indigo')
+ assert_equal false, @ordered_hash.include?('indigo')
+ assert_equal false, @ordered_hash.member?('indigo')
+ end
+
+ def test_has_value
+ assert_equal true, @ordered_hash.has_value?('000099')
+ assert_equal true, @ordered_hash.value?('000099')
+ assert_equal false, @ordered_hash.has_value?('ABCABC')
+ assert_equal false, @ordered_hash.value?('ABCABC')
+ end
end
diff --git a/activesupport/test/ordered_options_test.rb b/activesupport/test/ordered_options_test.rb
index fb7a58d0b0..e48425ca25 100644
--- a/activesupport/test/ordered_options_test.rb
+++ b/activesupport/test/ordered_options_test.rb
@@ -2,7 +2,7 @@ require 'abstract_unit'
class OrderedOptionsTest < Test::Unit::TestCase
def test_usage
- a = OrderedOptions.new
+ a = ActiveSupport::OrderedOptions.new
assert_nil a[:not_set]
@@ -20,7 +20,7 @@ class OrderedOptionsTest < Test::Unit::TestCase
end
def test_looping
- a = OrderedOptions.new
+ a = ActiveSupport::OrderedOptions.new
a[:allow_concurreny] = true
a["else_where"] = 56
@@ -34,7 +34,7 @@ class OrderedOptionsTest < Test::Unit::TestCase
end
def test_method_access
- a = OrderedOptions.new
+ a = ActiveSupport::OrderedOptions.new
assert_nil a.not_set
diff --git a/activesupport/test/string_inquirer_test.rb b/activesupport/test/string_inquirer_test.rb
new file mode 100644
index 0000000000..dda7850e6b
--- /dev/null
+++ b/activesupport/test/string_inquirer_test.rb
@@ -0,0 +1,15 @@
+require 'abstract_unit'
+
+class StringInquirerTest < Test::Unit::TestCase
+ def test_match
+ assert ActiveSupport::StringInquirer.new("production").production?
+ end
+
+ def test_miss
+ assert !ActiveSupport::StringInquirer.new("production").development?
+ end
+
+ def test_missing_question_mark
+ assert_raises(NoMethodError) { ActiveSupport::StringInquirer.new("production").production }
+ end
+end
diff --git a/activesupport/test/test_test.rb b/activesupport/test/test_test.rb
index 1e75e18602..26a45af255 100644
--- a/activesupport/test/test_test.rb
+++ b/activesupport/test/test_test.rb
@@ -84,6 +84,12 @@ class SetupAndTeardownTest < Test::Unit::TestCase
assert_equal [:foo, :sentinel, :foo], self.class.teardown_callback_chain.map(&:method)
end
+ def setup
+ end
+
+ def teardown
+ end
+
protected
def reset_callback_record
@called_back = []
diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb
index f3069b589b..b42dcd17f8 100644
--- a/activesupport/test/time_zone_test.rb
+++ b/activesupport/test/time_zone_test.rb
@@ -1,10 +1,9 @@
require 'abstract_unit'
class TimeZoneTest < Test::Unit::TestCase
-
def test_utc_to_local
silence_warnings do # silence warnings raised by tzinfo gem
- zone = TimeZone['Eastern Time (US & Canada)']
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
assert_equal Time.utc(1999, 12, 31, 19), zone.utc_to_local(Time.utc(2000, 1)) # standard offset -0500
assert_equal Time.utc(2000, 6, 30, 20), zone.utc_to_local(Time.utc(2000, 7)) # dst offset -0400
end
@@ -12,41 +11,41 @@ class TimeZoneTest < Test::Unit::TestCase
def test_local_to_utc
silence_warnings do # silence warnings raised by tzinfo gem
- zone = TimeZone['Eastern Time (US & Canada)']
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
assert_equal Time.utc(2000, 1, 1, 5), zone.local_to_utc(Time.utc(2000, 1)) # standard offset -0500
assert_equal Time.utc(2000, 7, 1, 4), zone.local_to_utc(Time.utc(2000, 7)) # dst offset -0400
end
end
-
+
def test_period_for_local
silence_warnings do # silence warnings raised by tzinfo gem
- zone = TimeZone['Eastern Time (US & Canada)']
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
assert_instance_of TZInfo::TimezonePeriod, zone.period_for_local(Time.utc(2000))
end
end
-
- TimeZone::MAPPING.keys.each do |name|
+
+ ActiveSupport::TimeZone::MAPPING.keys.each do |name|
define_method("test_map_#{name.downcase.gsub(/[^a-z]/, '_')}_to_tzinfo") do
silence_warnings do # silence warnings raised by tzinfo gem
- zone = TimeZone[name]
+ zone = ActiveSupport::TimeZone[name]
assert zone.tzinfo.respond_to?(:period_for_local)
end
end
end
def test_from_integer_to_map
- assert_instance_of TimeZone, TimeZone[-28800] # PST
+ assert_instance_of ActiveSupport::TimeZone, ActiveSupport::TimeZone[-28800] # PST
end
def test_from_duration_to_map
- assert_instance_of TimeZone, TimeZone[-480.minutes] # PST
+ assert_instance_of ActiveSupport::TimeZone, ActiveSupport::TimeZone[-480.minutes] # PST
end
- TimeZone.all.each do |zone|
+ ActiveSupport::TimeZone.all.each do |zone|
name = zone.name.downcase.gsub(/[^a-z]/, '_')
define_method("test_from_#{name}_to_map") do
silence_warnings do # silence warnings raised by tzinfo gem
- assert_instance_of TimeZone, TimeZone[zone.name]
+ assert_instance_of ActiveSupport::TimeZone, ActiveSupport::TimeZone[zone.name]
end
end
@@ -62,62 +61,62 @@ class TimeZoneTest < Test::Unit::TestCase
def test_now
with_env_tz 'US/Eastern' do
Time.stubs(:now).returns(Time.local(2000))
- zone = TimeZone['Eastern Time (US & Canada)']
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
assert_instance_of ActiveSupport::TimeWithZone, zone.now
assert_equal Time.utc(2000,1,1,5), zone.now.utc
assert_equal Time.utc(2000), zone.now.time
assert_equal zone, zone.now.time_zone
end
end
-
+
def test_now_enforces_spring_dst_rules
with_env_tz 'US/Eastern' do
Time.stubs(:now).returns(Time.local(2006,4,2,2)) # 2AM springs forward to 3AM
- zone = TimeZone['Eastern Time (US & Canada)']
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
assert_equal Time.utc(2006,4,2,3), zone.now.time
assert_equal true, zone.now.dst?
end
end
-
+
def test_now_enforces_fall_dst_rules
with_env_tz 'US/Eastern' do
Time.stubs(:now).returns(Time.at(1162098000)) # equivalent to 1AM DST
- zone = TimeZone['Eastern Time (US & Canada)']
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
assert_equal Time.utc(2006,10,29,1), zone.now.time
assert_equal true, zone.now.dst?
end
end
-
+
def test_today
Time.stubs(:now).returns(Time.utc(2000, 1, 1, 4, 59, 59)) # 1 sec before midnight Jan 1 EST
- assert_equal Date.new(1999, 12, 31), TimeZone['Eastern Time (US & Canada)'].today
+ assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].today
Time.stubs(:now).returns(Time.utc(2000, 1, 1, 5)) # midnight Jan 1 EST
- assert_equal Date.new(2000, 1, 1), TimeZone['Eastern Time (US & Canada)'].today
+ assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].today
Time.stubs(:now).returns(Time.utc(2000, 1, 2, 4, 59, 59)) # 1 sec before midnight Jan 2 EST
- assert_equal Date.new(2000, 1, 1), TimeZone['Eastern Time (US & Canada)'].today
+ assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].today
Time.stubs(:now).returns(Time.utc(2000, 1, 2, 5)) # midnight Jan 2 EST
- assert_equal Date.new(2000, 1, 2), TimeZone['Eastern Time (US & Canada)'].today
+ assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].today
end
end
-
+
def test_local
silence_warnings do # silence warnings raised by tzinfo gem
- time = TimeZone["Hawaii"].local(2007, 2, 5, 15, 30, 45)
+ time = ActiveSupport::TimeZone["Hawaii"].local(2007, 2, 5, 15, 30, 45)
assert_equal Time.utc(2007, 2, 5, 15, 30, 45), time.time
- assert_equal TimeZone["Hawaii"], time.time_zone
+ assert_equal ActiveSupport::TimeZone["Hawaii"], time.time_zone
end
end
def test_local_with_old_date
silence_warnings do # silence warnings raised by tzinfo gem
- time = TimeZone["Hawaii"].local(1850, 2, 5, 15, 30, 45)
+ time = ActiveSupport::TimeZone["Hawaii"].local(1850, 2, 5, 15, 30, 45)
assert_equal [45,30,15,5,2,1850], time.to_a[0,6]
- assert_equal TimeZone["Hawaii"], time.time_zone
+ assert_equal ActiveSupport::TimeZone["Hawaii"], time.time_zone
end
end
def test_local_enforces_spring_dst_rules
- zone = TimeZone['Eastern Time (US & Canada)']
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
twz = zone.local(2006,4,2,1,59,59) # 1 second before DST start
assert_equal Time.utc(2006,4,2,1,59,59), twz.time
assert_equal Time.utc(2006,4,2,6,59,59), twz.utc
@@ -138,16 +137,16 @@ class TimeZoneTest < Test::Unit::TestCase
def test_local_enforces_fall_dst_rules
# 1AM during fall DST transition is ambiguous, it could be either DST or non-DST 1AM
# Mirroring Time.local behavior, this method selects the DST time
- zone = TimeZone['Eastern Time (US & Canada)']
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
twz = zone.local(2006,10,29,1)
assert_equal Time.utc(2006,10,29,1), twz.time
assert_equal Time.utc(2006,10,29,5), twz.utc
- assert_equal true, twz.dst?
+ assert_equal true, twz.dst?
assert_equal 'EDT', twz.zone
end
def test_at
- zone = TimeZone['Eastern Time (US & Canada)']
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
secs = 946684800.0
twz = zone.at(secs)
assert_equal Time.utc(1999,12,31,19), twz.time
@@ -157,7 +156,7 @@ class TimeZoneTest < Test::Unit::TestCase
end
def test_at_with_old_date
- zone = TimeZone['Eastern Time (US & Canada)']
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
secs = DateTime.civil(1850).to_f
twz = zone.at(secs)
assert_equal [1850, 1, 1, 0], [twz.utc.year, twz.utc.mon, twz.utc.day, twz.utc.hour]
@@ -166,7 +165,7 @@ class TimeZoneTest < Test::Unit::TestCase
end
def test_parse
- zone = TimeZone['Eastern Time (US & Canada)']
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
twz = zone.parse('1999-12-31 19:00:00')
assert_equal Time.utc(1999,12,31,19), twz.time
assert_equal Time.utc(2000), twz.utc
@@ -175,7 +174,7 @@ class TimeZoneTest < Test::Unit::TestCase
def test_parse_string_with_timezone
(-11..13).each do |timezone_offset|
- zone = TimeZone[timezone_offset]
+ zone = ActiveSupport::TimeZone[timezone_offset]
twz = zone.parse('1999-12-31 19:00:00')
assert_equal twz, zone.parse(twz.to_s)
end
@@ -183,25 +182,25 @@ class TimeZoneTest < Test::Unit::TestCase
def test_parse_with_old_date
silence_warnings do # silence warnings raised by tzinfo gem
- zone = TimeZone['Eastern Time (US & Canada)']
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
twz = zone.parse('1850-12-31 19:00:00')
assert_equal [0,0,19,31,12,1850], twz.to_a[0,6]
assert_equal zone, twz.time_zone
end
end
-
+
def test_parse_far_future_date_with_time_zone_offset_in_string
silence_warnings do # silence warnings raised by tzinfo gem
- zone = TimeZone['Eastern Time (US & Canada)']
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
twz = zone.parse('2050-12-31 19:00:00 -10:00') # i.e., 2050-01-01 05:00:00 UTC
assert_equal [0,0,0,1,1,2051], twz.to_a[0,6]
assert_equal zone, twz.time_zone
end
end
-
+
def test_parse_returns_nil_when_string_without_date_information_is_passed_in
silence_warnings do # silence warnings raised by tzinfo gem
- zone = TimeZone['Eastern Time (US & Canada)']
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
assert_nil zone.parse('foobar')
assert_nil zone.parse(' ')
end
@@ -209,80 +208,80 @@ class TimeZoneTest < Test::Unit::TestCase
uses_mocha 'TestParseWithIncompleteDate' do
def test_parse_with_incomplete_date
- zone = TimeZone['Eastern Time (US & Canada)']
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
zone.stubs(:now).returns zone.local(1999,12,31)
twz = zone.parse('19:00:00')
assert_equal Time.utc(1999,12,31,19), twz.time
end
end
-
+
def test_utc_offset_lazy_loaded_from_tzinfo_when_not_passed_in_to_initialize
silence_warnings do # silence warnings raised by tzinfo gem
tzinfo = TZInfo::Timezone.get('America/New_York')
- zone = TimeZone.create(tzinfo.name, nil, tzinfo)
+ zone = ActiveSupport::TimeZone.create(tzinfo.name, nil, tzinfo)
assert_equal nil, zone.instance_variable_get('@utc_offset')
assert_equal(-18_000, zone.utc_offset)
end
end
-
+
def test_formatted_offset_positive
- zone = TimeZone['Moscow']
+ zone = ActiveSupport::TimeZone['Moscow']
assert_equal "+03:00", zone.formatted_offset
assert_equal "+0300", zone.formatted_offset(false)
end
-
+
def test_formatted_offset_negative
- zone = TimeZone['Eastern Time (US & Canada)']
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
assert_equal "-05:00", zone.formatted_offset
assert_equal "-0500", zone.formatted_offset(false)
end
-
+
def test_formatted_offset_zero
- zone = TimeZone['London']
+ zone = ActiveSupport::TimeZone['London']
assert_equal "+00:00", zone.formatted_offset
assert_equal "UTC", zone.formatted_offset(true, 'UTC')
end
-
+
def test_zone_compare
- zone1 = TimeZone['Central Time (US & Canada)'] # offset -0600
- zone2 = TimeZone['Eastern Time (US & Canada)'] # offset -0500
+ zone1 = ActiveSupport::TimeZone['Central Time (US & Canada)'] # offset -0600
+ zone2 = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] # offset -0500
assert zone1 < zone2
assert zone2 > zone1
assert zone1 == zone1
end
-
+
def test_to_s
- assert_equal "(GMT+03:00) Moscow", TimeZone['Moscow'].to_s
+ assert_equal "(GMT+03:00) Moscow", ActiveSupport::TimeZone['Moscow'].to_s
end
-
+
def test_all_sorted
- all = TimeZone.all
+ all = ActiveSupport::TimeZone.all
1.upto( all.length-1 ) do |i|
assert all[i-1] < all[i]
end
end
-
+
def test_index
- assert_nil TimeZone["bogus"]
- assert_instance_of TimeZone, TimeZone["Central Time (US & Canada)"]
- assert_instance_of TimeZone, TimeZone[8]
- assert_raises(ArgumentError) { TimeZone[false] }
+ assert_nil ActiveSupport::TimeZone["bogus"]
+ assert_instance_of ActiveSupport::TimeZone, ActiveSupport::TimeZone["Central Time (US & Canada)"]
+ assert_instance_of ActiveSupport::TimeZone, ActiveSupport::TimeZone[8]
+ assert_raises(ArgumentError) { ActiveSupport::TimeZone[false] }
end
-
+
def test_new
- assert_equal TimeZone["Central Time (US & Canada)"], TimeZone.new("Central Time (US & Canada)")
+ assert_equal ActiveSupport::TimeZone["Central Time (US & Canada)"], ActiveSupport::TimeZone.new("Central Time (US & Canada)")
end
-
+
def test_us_zones
- assert TimeZone.us_zones.include?(TimeZone["Hawaii"])
- assert !TimeZone.us_zones.include?(TimeZone["Kuala Lumpur"])
- end
-
+ assert ActiveSupport::TimeZone.us_zones.include?(ActiveSupport::TimeZone["Hawaii"])
+ assert !ActiveSupport::TimeZone.us_zones.include?(ActiveSupport::TimeZone["Kuala Lumpur"])
+ end
+
protected
def with_env_tz(new_tz = 'US/Eastern')
old_tz, ENV['TZ'] = ENV['TZ'], new_tz
yield
ensure
old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
- end
+ end
end
diff --git a/doc/template/horo.rb b/doc/template/horo.rb
new file mode 100644
index 0000000000..e028422a2e
--- /dev/null
+++ b/doc/template/horo.rb
@@ -0,0 +1,613 @@
+# Horo RDoc template
+# Author: Hongli Lai - http://izumi.plan99.net/blog/
+#
+# Based on the Jamis template:
+# http://weblog.jamisbuck.org/2005/4/8/rdoc-template
+
+if defined?(RDoc::Diagram)
+ RDoc::Diagram.class_eval do
+ remove_const(:FONT)
+ const_set(:FONT, "\"Bitstream Vera Sans\"")
+ end
+end
+
+module RDoc
+module Page
+
+FONTS = "\"Bitstream Vera Sans\", Verdana, Arial, Helvetica, sans-serif"
+
+STYLE = <<CSS
+a {
+ color: #00F;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #77F;
+ text-decoration: underline;
+}
+
+body, td, p {
+ font-family: %fonts%;
+ background: #FFF;
+ color: #000;
+ margin: 0px;
+ font-size: small;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+#content {
+ margin: 2em;
+ margin-left: 3.5em;
+ margin-right: 3.5em;
+}
+
+#description p {
+ margin-bottom: 0.5em;
+}
+
+.sectiontitle {
+ margin-top: 1em;
+ margin-bottom: 1em;
+ padding: 0.5em;
+ padding-left: 2em;
+ background: #005;
+ color: #FFF;
+ font-weight: bold;
+}
+
+.attr-rw {
+ padding-left: 1em;
+ padding-right: 1em;
+ text-align: center;
+ color: #055;
+}
+
+.attr-name {
+ font-weight: bold;
+}
+
+.attr-desc {
+}
+
+.attr-value {
+ font-family: monospace;
+}
+
+.file-title-prefix {
+ font-size: large;
+}
+
+.file-title {
+ font-size: large;
+ font-weight: bold;
+ background: #005;
+ color: #FFF;
+}
+
+.banner {
+ background: #005;
+ color: #FFF;
+ border: 1px solid black;
+ padding: 1em;
+}
+
+.banner td {
+ background: transparent;
+ color: #FFF;
+}
+
+h1 a, h2 a, .sectiontitle a, .banner a {
+ color: #FF0;
+}
+
+h1 a:hover, h2 a:hover, .sectiontitle a:hover, .banner a:hover {
+ color: #FF7;
+}
+
+.dyn-source {
+ display: none;
+ background: #fffde8;
+ color: #000;
+ border: #ffe0bb dotted 1px;
+ margin: 0.5em 2em 0.5em 2em;
+ padding: 0.5em;
+}
+
+.dyn-source .cmt {
+ color: #00F;
+ font-style: italic;
+}
+
+.dyn-source .kw {
+ color: #070;
+ font-weight: bold;
+}
+
+.method {
+ margin-left: 1em;
+ margin-right: 1em;
+ margin-bottom: 1em;
+}
+
+.description pre {
+ padding: 0.5em;
+ border: #ffe0bb dotted 1px;
+ background: #fffde8;
+}
+
+.method .title {
+ font-family: monospace;
+ font-size: large;
+ border-bottom: 1px dashed black;
+ margin-bottom: 0.3em;
+ padding-bottom: 0.1em;
+}
+
+.method .description, .method .sourcecode {
+ margin-left: 1em;
+}
+
+.description p, .sourcecode p {
+ margin-bottom: 0.5em;
+}
+
+.method .sourcecode p.source-link {
+ text-indent: 0em;
+ margin-top: 0.5em;
+}
+
+.method .aka {
+ margin-top: 0.3em;
+ margin-left: 1em;
+ font-style: italic;
+ text-indent: 2em;
+}
+
+h1 {
+ padding: 1em;
+ margin-left: -1.5em;
+ font-size: x-large;
+ font-weight: bold;
+ color: #FFF;
+ background: #007;
+}
+
+h2 {
+ padding: 0.5em 1em 0.5em 1em;
+ margin-left: -1.5em;
+ font-size: large;
+ font-weight: bold;
+ color: #FFF;
+ background: #009;
+}
+
+h3, h4, h5, h6 {
+ color: #220088;
+ border-bottom: #5522bb solid 1px;
+}
+
+.sourcecode > pre {
+ padding: 0.5em;
+ border: 1px dotted black;
+ background: #FFE;
+}
+
+dt {
+ font-weight: bold
+}
+
+dd {
+ margin-bottom: 0.7em;
+}
+CSS
+
+XHTML_PREAMBLE = %{<?xml version="1.0" encoding="%charset%"?>
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+}
+
+XHTML_FRAMESET_PREAMBLE = %{
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
+}
+
+HEADER = XHTML_PREAMBLE + <<ENDHEADER
+<html>
+ <head>
+ <title>%title%</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
+ <link rel="stylesheet" href="%style_url%" type="text/css" media="screen" />
+
+ <script language="JavaScript" type="text/javascript">
+ // <![CDATA[
+
+ function toggleSource( id )
+ {
+ var elem
+ var link
+
+ if( document.getElementById )
+ {
+ elem = document.getElementById( id )
+ link = document.getElementById( "l_" + id )
+ }
+ else if ( document.all )
+ {
+ elem = eval( "document.all." + id )
+ link = eval( "document.all.l_" + id )
+ }
+ else
+ return false;
+
+ if( elem.style.display == "block" )
+ {
+ elem.style.display = "none"
+ link.innerHTML = "show source"
+ }
+ else
+ {
+ elem.style.display = "block"
+ link.innerHTML = "hide source"
+ }
+ }
+
+ function openCode( url )
+ {
+ window.open( url, "SOURCE_CODE", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=480,width=750" ).focus();
+ }
+ // ]]>
+ </script>
+ </head>
+
+ <body>
+ENDHEADER
+
+FILE_PAGE = <<HTML
+<table border='0' cellpadding='0' cellspacing='0' width="100%" class='banner'>
+ <tr><td>
+ <table width="100%" border='0' cellpadding='0' cellspacing='0'><tr>
+ <td class="file-title" colspan="2"><span class="file-title-prefix">File</span><br />%short_name%</td>
+ <td align="right">
+ <table border='0' cellspacing="0" cellpadding="2">
+ <tr>
+ <td>Path:</td>
+ <td>%full_path%
+IF:cvsurl
+ &nbsp;(<a href="%cvsurl%">CVS</a>)
+ENDIF:cvsurl
+ </td>
+ </tr>
+ <tr>
+ <td>Modified:</td>
+ <td>%dtm_modified%</td>
+ </tr>
+ </table>
+ </td></tr>
+ </table>
+ </td></tr>
+</table><br />
+HTML
+
+###################################################################
+
+CLASS_PAGE = <<HTML
+<table width="100%" border='0' cellpadding='0' cellspacing='0' class='banner'><tr>
+ <td class="file-title"><span class="file-title-prefix">%classmod%</span><br />%full_name%</td>
+ <td align="right">
+ <table cellspacing="0" cellpadding="2">
+ <tr valign="top">
+ <td>In:</td>
+ <td>
+START:infiles
+HREF:full_path_url:full_path:
+IF:cvsurl
+&nbsp;(<a href="%cvsurl%">CVS</a>)
+ENDIF:cvsurl
+END:infiles
+ </td>
+ </tr>
+IF:parent
+ <tr>
+ <td>Parent:</td>
+ <td>
+IF:par_url
+ <a href="%par_url%">
+ENDIF:par_url
+%parent%
+IF:par_url
+ </a>
+ENDIF:par_url
+ </td>
+ </tr>
+ENDIF:parent
+ </table>
+ </td>
+ </tr>
+ </table>
+HTML
+
+###################################################################
+
+METHOD_LIST = <<HTML
+ <div id="content">
+IF:diagram
+ <table cellpadding='0' cellspacing='0' border='0' width="100%"><tr><td align="center">
+ %diagram%
+ </td></tr></table>
+ENDIF:diagram
+
+IF:description
+ <div class="description">%description%</div>
+ENDIF:description
+
+IF:requires
+ <div class="sectiontitle">Required Files</div>
+ <ul>
+START:requires
+ <li>HREF:aref:name:</li>
+END:requires
+ </ul>
+ENDIF:requires
+
+IF:toc
+ <div class="sectiontitle">Contents</div>
+ <ul>
+START:toc
+ <li><a href="#%href%">%secname%</a></li>
+END:toc
+ </ul>
+ENDIF:toc
+
+IF:methods
+ <div class="sectiontitle">Methods</div>
+ <ul>
+START:methods
+ <li>HREF:aref:name:</li>
+END:methods
+ </ul>
+ENDIF:methods
+
+IF:includes
+<div class="sectiontitle">Included Modules</div>
+<ul>
+START:includes
+ <li>HREF:aref:name:</li>
+END:includes
+</ul>
+ENDIF:includes
+
+START:sections
+IF:sectitle
+<div class="sectiontitle"><a name="%secsequence%">%sectitle%</a></div>
+IF:seccomment
+<div class="description">
+%seccomment%
+</div>
+ENDIF:seccomment
+ENDIF:sectitle
+
+IF:classlist
+ <div class="sectiontitle">Classes and Modules</div>
+ %classlist%
+ENDIF:classlist
+
+IF:constants
+ <div class="sectiontitle">Constants</div>
+ <table border='0' cellpadding='5'>
+START:constants
+ <tr valign='top'>
+ <td class="attr-name">%name%</td>
+ <td>=</td>
+ <td class="attr-value">%value%</td>
+ </tr>
+IF:desc
+ <tr valign='top'>
+ <td>&nbsp;</td>
+ <td colspan="2" class="attr-desc">%desc%</td>
+ </tr>
+ENDIF:desc
+END:constants
+ </table>
+ENDIF:constants
+
+IF:attributes
+ <div class="sectiontitle">Attributes</div>
+ <table border='0' cellpadding='5'>
+START:attributes
+ <tr valign='top'>
+ <td class='attr-rw'>
+IF:rw
+[%rw%]
+ENDIF:rw
+ </td>
+ <td class='attr-name'>%name%</td>
+ <td class='attr-desc'>%a_desc%</td>
+ </tr>
+END:attributes
+ </table>
+ENDIF:attributes
+
+IF:method_list
+START:method_list
+IF:methods
+<div class="sectiontitle">%type% %category% methods</div>
+START:methods
+<div class="method">
+ <div class="title">
+IF:callseq
+ <a name="%aref%"></a><b>%callseq%</b>
+ENDIF:callseq
+IFNOT:callseq
+ <a name="%aref%"></a><b>%name%</b>%params%
+ENDIF:callseq
+IF:codeurl
+[&nbsp;<a href="%codeurl%" target="SOURCE_CODE" onclick="javascript:openCode('%codeurl%'); return false;">source</a>&nbsp;]
+ENDIF:codeurl
+ </div>
+IF:m_desc
+ <div class="description">
+ %m_desc%
+ </div>
+ENDIF:m_desc
+IF:aka
+<div class="aka">
+ This method is also aliased as
+START:aka
+ <a href="%aref%">%name%</a>
+END:aka
+</div>
+ENDIF:aka
+IF:sourcecode
+<div class="sourcecode">
+ <p class="source-link">[ <a href="javascript:toggleSource('%aref%_source')" id="l_%aref%_source">show source</a> ]</p>
+ <div id="%aref%_source" class="dyn-source">
+<pre>
+%sourcecode%
+</pre>
+ </div>
+</div>
+ENDIF:sourcecode
+</div>
+END:methods
+ENDIF:methods
+END:method_list
+ENDIF:method_list
+END:sections
+</div>
+HTML
+
+FOOTER = <<ENDFOOTER
+ </body>
+</html>
+ENDFOOTER
+
+BODY = HEADER + <<ENDBODY
+ !INCLUDE! <!-- banner header -->
+
+ <div id="bodyContent">
+ #{METHOD_LIST}
+ </div>
+
+ #{FOOTER}
+ENDBODY
+
+########################## Source code ##########################
+
+SRC_PAGE = XHTML_PREAMBLE + <<HTML
+<html>
+<head><title>%title%</title>
+<meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
+<style type="text/css">
+.ruby-comment { color: green; font-style: italic }
+.ruby-constant { color: #4433aa; font-weight: bold; }
+.ruby-identifier { color: #222222; }
+.ruby-ivar { color: #2233dd; }
+.ruby-keyword { color: #3333FF; font-weight: bold }
+.ruby-node { color: #777777; }
+.ruby-operator { color: #111111; }
+.ruby-regexp { color: #662222; }
+.ruby-value { color: #662222; font-style: italic }
+ .kw { color: #3333FF; font-weight: bold }
+ .cmt { color: green; font-style: italic }
+ .str { color: #662222; font-style: italic }
+ .re { color: #662222; }
+</style>
+</head>
+<body bgcolor="white">
+<pre>%code%</pre>
+</body>
+</html>
+HTML
+
+########################## Index ################################
+
+FR_INDEX_BODY = <<HTML
+!INCLUDE!
+HTML
+
+FILE_INDEX = XHTML_PREAMBLE + <<HTML
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
+<title>Index</title>
+<style type="text/css">
+<!--
+ body {
+ background-color: #EEE;
+ font-family: #{FONTS};
+ color: #000;
+ margin: 0px;
+ }
+ .banner {
+ background: #005;
+ color: #FFF;
+ padding: 0.2em;
+ font-size: small;
+ font-weight: bold;
+ text-align: center;
+ }
+ .entries {
+ margin: 0.25em 1em 0 1em;
+ font-size: x-small;
+ }
+ a {
+ color: #00F;
+ text-decoration: none;
+ white-space: nowrap;
+ }
+ a:hover {
+ color: #77F;
+ text-decoration: underline;
+ }
+-->
+</style>
+<base target="docwin" />
+</head>
+<body>
+<div class="banner">%list_title%</div>
+<div class="entries">
+START:entries
+<a href="%href%">%name%</a><br />
+END:entries
+</div>
+</body></html>
+HTML
+
+CLASS_INDEX = FILE_INDEX
+METHOD_INDEX = FILE_INDEX
+
+INDEX = XHTML_FRAMESET_PREAMBLE + <<HTML
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>%title%</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
+</head>
+
+<frameset cols="20%,*">
+ <frameset rows="15%,55%,30%">
+ <frame src="fr_file_index.html" title="Files" name="Files" />
+ <frame src="fr_class_index.html" name="Classes" />
+ <frame src="fr_method_index.html" name="Methods" />
+ </frameset>
+ <frame src="%initial_page%" name="docwin" />
+ <noframes>
+ <body bgcolor="white">
+ Click <a href="html/index.html">here</a> for a non-frames
+ version of this page.
+ </body>
+ </noframes>
+</frameset>
+
+</html>
+HTML
+
+end
+end
+
diff --git a/railties/CHANGELOG b/railties/CHANGELOG
index fe517755ef..7e5c35da15 100644
--- a/railties/CHANGELOG
+++ b/railties/CHANGELOG
@@ -1,3 +1,20 @@
+*Edge*
+
+* Fix script/about in production mode. #370 [Cheah Chu Yeow, Xavier Noria, David Krmpotic]
+
+* Add the gem load paths before the framework is loaded, so certain gems like RedCloth and BlueCloth can be frozen.
+
+* Fix discrepancies with loading rails/init.rb from gems.
+
+* Plugins check for the gem init path (rails/init.rb) before the standard plugin init path (init.rb) [Jacek Becela]
+
+* Changed all generated tests to use the test/do declaration style [DHH]
+
+* Wrapped Rails.env in StringInquirer so you can do Rails.env.development? [DHH]
+
+* Fixed that RailsInfoController wasn't considering all requests local in development mode (Edgard Castro) [#310 state:resolved]
+
+
*2.1.0 (May 31st, 2008)*
* script/dbconsole fires up the command-line database client. #102 [Steve Purcell]
diff --git a/railties/Rakefile b/railties/Rakefile
index a1d1095c37..f64b60b0dd 100644
--- a/railties/Rakefile
+++ b/railties/Rakefile
@@ -264,9 +264,10 @@ Rake::RDocTask.new { |rdoc|
rdoc.title = "Railties -- Gluing the Engine to the Rails"
rdoc.options << '--line-numbers' << '--inline-source' << '--accessor' << 'cattr_accessor=object'
rdoc.options << '--charset' << 'utf-8'
- rdoc.template = "#{ENV['template']}.rb" if ENV['template']
+ rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
rdoc.rdoc_files.include('README', 'CHANGELOG')
rdoc.rdoc_files.include('lib/*.rb')
+ rdoc.rdoc_files.include('lib/rails/*.rb')
rdoc.rdoc_files.include('lib/rails_generator/*.rb')
rdoc.rdoc_files.include('lib/commands/**/*.rb')
}
@@ -331,10 +332,15 @@ end
# Publishing -------------------------------------------------------
-desc "Publish the API documentation"
+desc "Publish the rails gem"
task :pgem => [:gem] do
- Rake::SshFilePublisher.new("davidhh@wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
- `ssh davidhh@wrath.rubyonrails.org './gemupdate.sh'`
+ Rake::SshFilePublisher.new("wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
+ `ssh wrath.rubyonrails.org './gemupdate.sh'`
+end
+
+desc "Publish the API documentation"
+task :pdoc => :rdoc do
+ # railties API isn't separately published
end
desc "Publish the release files to RubyForge."
diff --git a/railties/bin/about b/railties/bin/about
index cd38a32abf..ed8deb0dfc 100644
--- a/railties/bin/about
+++ b/railties/bin/about
@@ -1,3 +1,4 @@
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
-require 'commands/about'
+$LOAD_PATH.unshift "#{RAILTIES_PATH}/builtin/rails_info"
+require 'commands/about' \ No newline at end of file
diff --git a/railties/builtin/rails_info/rails/info_controller.rb b/railties/builtin/rails_info/rails/info_controller.rb
index 39f8b1f120..05745d606d 100644
--- a/railties/builtin/rails_info/rails/info_controller.rb
+++ b/railties/builtin/rails_info/rails/info_controller.rb
@@ -1,6 +1,6 @@
class Rails::InfoController < ActionController::Base
def properties
- if local_request?
+ if consider_all_requests_local || local_request?
render :inline => Rails::Info.to_html
else
render :text => '<p>For security purposes, this information is only available to local requests.</p>', :status => 500
diff --git a/railties/configs/initializers/inflections.rb b/railties/configs/initializers/inflections.rb
index 09158b865c..d531b8bb82 100644
--- a/railties/configs/initializers/inflections.rb
+++ b/railties/configs/initializers/inflections.rb
@@ -2,7 +2,7 @@
# Add new inflection rules using the following format
# (all these examples are active by default):
-# Inflector.inflections do |inflect|
+# ActiveSupport::Inflector.inflections do |inflect|
# inflect.plural /^(ox)$/i, '\1en'
# inflect.singular /^(ox)en/i, '\1'
# inflect.irregular 'person', 'people'
diff --git a/railties/configs/initializers/new_rails_defaults.rb b/railties/configs/initializers/new_rails_defaults.rb
index 5e60c0ade4..78e0117cc4 100644
--- a/railties/configs/initializers/new_rails_defaults.rb
+++ b/railties/configs/initializers/new_rails_defaults.rb
@@ -1,11 +1,13 @@
# These settings change the behavior of Rails 2 apps and will be defaults
# for Rails 3. You can remove this initializer when Rails 3 is released.
-# Include Active Record class name as root for JSON serialized output.
-ActiveRecord::Base.include_root_in_json = true
+if defined?(ActiveRecord)
+ # Include Active Record class name as root for JSON serialized output.
+ ActiveRecord::Base.include_root_in_json = true
-# Store the full class name (including module namespace) in STI type column.
-ActiveRecord::Base.store_full_sti_class = true
+ # Store the full class name (including module namespace) in STI type column.
+ ActiveRecord::Base.store_full_sti_class = true
+end
# Use ISO 8601 format for JSON serialized times and dates.
ActiveSupport.use_standard_json_time_format = true
diff --git a/railties/helpers/performance_test.rb b/railties/helpers/performance_test.rb
new file mode 100644
index 0000000000..7c89816570
--- /dev/null
+++ b/railties/helpers/performance_test.rb
@@ -0,0 +1,8 @@
+require 'performance/test_helper'
+
+# Profiling results for each test method are written to tmp/performance.
+class BrowsingTest < ActionController::PerformanceTest
+ def test_homepage
+ get '/'
+ end
+end
diff --git a/railties/helpers/performance_test_helper.rb b/railties/helpers/performance_test_helper.rb
new file mode 100644
index 0000000000..3c4c7fb740
--- /dev/null
+++ b/railties/helpers/performance_test_helper.rb
@@ -0,0 +1,6 @@
+require 'test_helper'
+require 'action_controller/performance_test'
+
+ActionController::Base.perform_caching = true
+ActiveSupport::Dependencies.mechanism = :require
+Rails.logger.level = ActiveSupport::BufferedLogger::INFO
diff --git a/railties/lib/commands/about.rb b/railties/lib/commands/about.rb
index 313bc18c6a..7f53ac8a2e 100644
--- a/railties/lib/commands/about.rb
+++ b/railties/lib/commands/about.rb
@@ -1,2 +1,3 @@
require 'environment'
+require 'rails/info'
puts Rails::Info
diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb
index ec065e6f3c..bcf4cea10f 100644
--- a/railties/lib/initializer.rb
+++ b/railties/lib/initializer.rb
@@ -37,7 +37,7 @@ module Rails
end
def env
- RAILS_ENV
+ ActiveSupport::StringInquirer.new(RAILS_ENV)
end
def cache
@@ -79,7 +79,10 @@ module Rails
# The set of loaded plugins.
attr_reader :loaded_plugins
-
+
+ # Whether or not all the gem dependencies have been met
+ attr_reader :gems_dependencies_loaded
+
# Runs the initializer. By default, this will invoke the #process method,
# which simply executes all of the initialization routines. Alternately,
# you can specify explicitly which initialization routine you want:
@@ -110,10 +113,10 @@ module Rails
check_ruby_version
install_gem_spec_stubs
set_load_path
-
+ add_gem_load_paths
+
require_frameworks
set_autoload_paths
- add_gem_load_paths
add_plugin_load_paths
load_environment
@@ -201,10 +204,10 @@ module Rails
# Set the paths from which Rails will automatically load source files, and
# the load_once paths.
def set_autoload_paths
- Dependencies.load_paths = configuration.load_paths.uniq
- Dependencies.load_once_paths = configuration.load_once_paths.uniq
+ ActiveSupport::Dependencies.load_paths = configuration.load_paths.uniq
+ ActiveSupport::Dependencies.load_once_paths = configuration.load_once_paths.uniq
- extra = Dependencies.load_once_paths - Dependencies.load_paths
+ extra = ActiveSupport::Dependencies.load_once_paths - ActiveSupport::Dependencies.load_paths
unless extra.empty?
abort <<-end_error
load_once_paths must be a subset of the load_paths.
@@ -231,7 +234,7 @@ module Rails
end
# Adds all load paths from plugins to the global set of load paths, so that
- # code from plugins can be required (explicitly or automatically via Dependencies).
+ # code from plugins can be required (explicitly or automatically via ActiveSupport::Dependencies).
def add_plugin_load_paths
plugin_loader.add_plugin_load_paths
end
@@ -239,12 +242,12 @@ module Rails
def add_gem_load_paths
unless @configuration.gems.empty?
require "rubygems"
- @configuration.gems.each &:add_load_paths
+ @configuration.gems.each { |gem| gem.add_load_paths }
end
end
def load_gems
- @configuration.gems.each(&:load)
+ @configuration.gems.each { |gem| gem.load }
end
def check_gem_dependencies
@@ -307,7 +310,7 @@ module Rails
end
def load_observers
- if @gems_dependencies_loaded && configuration.frameworks.include?(:active_record)
+ if gems_dependencies_loaded && configuration.frameworks.include?(:active_record)
ActiveRecord::Base.instantiate_observers
end
end
@@ -413,7 +416,7 @@ module Rails
# Sets the dependency loading mechanism based on the value of
# Configuration#cache_classes.
def initialize_dependency_mechanism
- Dependencies.mechanism = configuration.cache_classes ? :require : :load
+ ActiveSupport::Dependencies.mechanism = configuration.cache_classes ? :require : :load
end
# Loads support for "whiny nil" (noisy warnings when methods are invoked
@@ -463,7 +466,7 @@ module Rails
# Fires the user-supplied after_initialize block (Configuration#after_initialize)
def after_initialize
- if @gems_dependencies_loaded
+ if gems_dependencies_loaded
configuration.after_initialize_blocks.each do |block|
block.call
end
@@ -471,7 +474,7 @@ module Rails
end
def load_application_initializers
- if @gems_dependencies_loaded
+ if gems_dependencies_loaded
Dir["#{configuration.root_path}/config/initializers/**/*.rb"].sort.each do |initializer|
load(initializer)
end
@@ -599,12 +602,12 @@ module Rails
# If <tt>reload_plugins?</tt> is false, add this to your plugin's <tt>init.rb</tt>
# to make it reloadable:
#
- # Dependencies.load_once_paths.delete lib_path
+ # ActiveSupport::Dependencies.load_once_paths.delete lib_path
#
# If <tt>reload_plugins?</tt> is true, add this to your plugin's <tt>init.rb</tt>
# to only load it once:
#
- # Dependencies.load_once_paths << lib_path
+ # ActiveSupport::Dependencies.load_once_paths << lib_path
#
attr_accessor :reload_plugins
diff --git a/railties/lib/rails/gem_dependency.rb b/railties/lib/rails/gem_dependency.rb
index 9f088a18dd..f8d97840c1 100644
--- a/railties/lib/rails/gem_dependency.rb
+++ b/railties/lib/rails/gem_dependency.rb
@@ -23,9 +23,13 @@ module Rails
@unpack_directory = nil
end
+ def unpacked_paths
+ Dir[File.join(self.class.unpacked_path, "#{@name}-#{@version || "*"}")]
+ end
+
def add_load_paths
return if @loaded || @load_paths_added
- unpacked_paths = Dir[File.join(self.class.unpacked_path, "#{@name}-#{@version || "*"}")]
+ unpacked_paths = self.unpacked_paths
if unpacked_paths.empty?
args = [@name]
args << @requirement.to_s if @requirement
@@ -39,7 +43,7 @@ module Rails
@load_paths_added = true
rescue Gem::LoadError
end
-
+
def dependencies
all_dependencies = specification.dependencies.map do |dependency|
GemDependency.new(dependency.name, :requirement => dependency.version_requirements)
@@ -47,7 +51,7 @@ module Rails
all_dependencies += all_dependencies.map(&:dependencies).flatten
all_dependencies.uniq
end
-
+
def gem_dir(base_directory)
File.join(base_directory, specification.full_name)
end
@@ -78,13 +82,13 @@ module Rails
puts cmd
puts %x(#{cmd})
end
-
+
def unpack_to(directory)
FileUtils.mkdir_p directory
Dir.chdir directory do
Gem::GemRunner.new.run(unpack_command)
end
-
+
# copy the gem's specification into GEMDIR/.specification so that
# we can access information about the gem on deployment systems
# without having the gem installed
@@ -98,27 +102,26 @@ module Rails
self.name == other.name && self.requirement == other.requirement
end
-private ###################################################################
-
def specification
@spec ||= Gem.source_index.search(Gem::Dependency.new(@name, @requirement)).sort_by { |s| s.version }.last
end
-
- def gem_command
- RUBY_PLATFORM =~ /win32/ ? 'gem.bat' : 'gem'
- end
- def install_command
- cmd = %w(install) << @name
- cmd << "--version" << %("#{@requirement.to_s}") if @requirement
- cmd << "--source" << @source if @source
- cmd
- end
-
- def unpack_command
- cmd = %w(unpack) << @name
- cmd << "--version" << "#{@requirement.to_s}" if @requirement
- cmd
- end
+ private
+ def gem_command
+ RUBY_PLATFORM =~ /win32/ ? 'gem.bat' : 'gem'
+ end
+
+ def install_command
+ cmd = %w(install) << @name
+ cmd << "--version" << %("#{@requirement.to_s}") if @requirement
+ cmd << "--source" << @source if @source
+ cmd
+ end
+
+ def unpack_command
+ cmd = %w(unpack) << @name
+ cmd << "--version" << %("#{@requirement.to_s}") if @requirement
+ cmd
+ 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 256f4b0132..b8b2b57038 100644
--- a/railties/lib/rails/plugin.rb
+++ b/railties/lib/rails/plugin.rb
@@ -74,10 +74,18 @@ module Rails
File.join(directory, 'lib')
end
- def init_path
+ def classic_init_path
File.join(directory, 'init.rb')
end
+ def gem_init_path
+ File.join(directory, 'rails', 'init.rb')
+ end
+
+ def init_path
+ File.file?(gem_init_path) ? gem_init_path : classic_init_path
+ end
+
def has_lib_directory?
File.directory?(lib_path)
end
@@ -87,14 +95,14 @@ module Rails
end
def evaluate_init_rb(initializer)
- if has_init_file?
- silence_warnings do
- # Allow plugins to reference the current configuration object
- config = initializer.configuration
-
- eval(IO.read(init_path), binding, init_path)
- end
- end
+ if has_init_file?
+ silence_warnings do
+ # Allow plugins to reference the current configuration object
+ config = initializer.configuration
+
+ eval(IO.read(init_path), binding, init_path)
+ end
+ end
end
end
@@ -103,8 +111,9 @@ module Rails
# to Dependencies.load_paths.
class GemPlugin < Plugin
# Initialize this plugin from a Gem::Specification.
- def initialize(spec)
- super(File.join(spec.full_gem_path))
+ def initialize(spec, gem)
+ directory = (gem.frozen? && gem.unpacked_paths.first) || File.join(spec.full_gem_path)
+ super(directory)
@name = spec.name
end
diff --git a/railties/lib/rails/plugin/loader.rb b/railties/lib/rails/plugin/loader.rb
index 1e542dd038..948d497007 100644
--- a/railties/lib/rails/plugin/loader.rb
+++ b/railties/lib/rails/plugin/loader.rb
@@ -45,9 +45,9 @@ module Rails
plugins.each do |plugin|
plugin.load_paths.each do |path|
$LOAD_PATH.insert(application_lib_index + 1, path)
- Dependencies.load_paths << path
+ ActiveSupport::Dependencies.load_paths << path
unless Rails.configuration.reload_plugins?
- Dependencies.load_once_paths << path
+ ActiveSupport::Dependencies.load_once_paths << path
end
end
end
diff --git a/railties/lib/rails/plugin/locator.rb b/railties/lib/rails/plugin/locator.rb
index f06a51a572..79c07fccd1 100644
--- a/railties/lib/rails/plugin/locator.rb
+++ b/railties/lib/rails/plugin/locator.rb
@@ -78,8 +78,9 @@ module Rails
# a <tt>rails/init.rb</tt> file.
class GemLocator < Locator
def plugins
- specs = initializer.configuration.gems.map(&:specification)
- specs += Gem.loaded_specs.values.select do |spec|
+ gem_index = initializer.configuration.gems.inject({}) { |memo, gem| memo.update gem.specification => gem }
+ specs = gem_index.keys
+ specs += Gem.loaded_specs.values.select do |spec|
spec.loaded_from && # prune stubs
File.exist?(File.join(spec.full_gem_path, "rails", "init.rb"))
end
@@ -91,7 +92,7 @@ module Rails
deps.add(*specs) unless specs.empty?
deps.dependency_order.collect do |spec|
- Rails::GemPlugin.new(spec)
+ Rails::GemPlugin.new(spec, gem_index[spec])
end
end
end
diff --git a/railties/lib/rails_generator/generators/applications/app/app_generator.rb b/railties/lib/rails_generator/generators/applications/app/app_generator.rb
index 2f2dd82682..80e8eabfd3 100644
--- a/railties/lib/rails_generator/generators/applications/app/app_generator.rb
+++ b/railties/lib/rails_generator/generators/applications/app/app_generator.rb
@@ -51,6 +51,8 @@ class AppGenerator < Rails::Generator::Base
m.template "helpers/application.rb", "app/controllers/application.rb", :assigns => { :app_name => @app_name, :app_secret => md5.hexdigest }
m.template "helpers/application_helper.rb", "app/helpers/application_helper.rb"
m.template "helpers/test_helper.rb", "test/test_helper.rb"
+ m.template "helpers/performance_test_helper.rb", "test/performance/test_helper.rb"
+ m.template "helpers/performance_test.rb", "test/performance/browsing_test.rb"
# database.yml and routes.rb
m.template "configs/databases/#{options[:db]}.yml", "config/database.yml", :assigns => {
@@ -155,6 +157,7 @@ class AppGenerator < Rails::Generator::Base
test/fixtures
test/functional
test/integration
+ test/performance
test/unit
vendor
vendor/plugins
diff --git a/railties/lib/rails_generator/generators/components/controller/templates/functional_test.rb b/railties/lib/rails_generator/generators/components/controller/templates/functional_test.rb
index 38e0ae7123..62fa5d86fd 100644
--- a/railties/lib/rails_generator/generators/components/controller/templates/functional_test.rb
+++ b/railties/lib/rails_generator/generators/components/controller/templates/functional_test.rb
@@ -2,7 +2,7 @@ require 'test_helper'
class <%= class_name %>ControllerTest < ActionController::TestCase
# Replace this with your real tests.
- def test_truth
+ test "the truth" do
assert true
end
end
diff --git a/railties/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb b/railties/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb
index 149b987d81..2c57158b1c 100644
--- a/railties/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb
+++ b/railties/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb
@@ -1,10 +1,10 @@
require 'test_helper'
class <%= class_name %>Test < ActionController::IntegrationTest
- # fixtures :your, :models
+ fixtures :all
# Replace this with your real tests.
- def test_truth
+ test "the truth" do
assert true
end
end
diff --git a/railties/lib/rails_generator/generators/components/mailer/templates/unit_test.rb b/railties/lib/rails_generator/generators/components/mailer/templates/unit_test.rb
index 0b4b2ec60a..1b7bcfef08 100644
--- a/railties/lib/rails_generator/generators/components/mailer/templates/unit_test.rb
+++ b/railties/lib/rails_generator/generators/components/mailer/templates/unit_test.rb
@@ -3,7 +3,7 @@ require 'test_helper'
class <%= class_name %>Test < ActionMailer::TestCase
tests <%= class_name %>
<% for action in actions -%>
- def test_<%= action %>
+ test "<%= action %>" do
@expected.subject = '<%= class_name %>#<%= action %>'
@expected.body = read_fixture('<%= action %>')
@expected.date = Time.now
@@ -14,7 +14,7 @@ class <%= class_name %>Test < ActionMailer::TestCase
<% end -%>
<% if actions.blank? -%>
# replace this with your real tests
- def test_truth
+ test "the truth" do
assert true
end
<% end -%>
diff --git a/railties/lib/rails_generator/generators/components/model/templates/unit_test.rb b/railties/lib/rails_generator/generators/components/model/templates/unit_test.rb
index 96bd34adab..3e0bc29d3a 100644
--- a/railties/lib/rails_generator/generators/components/model/templates/unit_test.rb
+++ b/railties/lib/rails_generator/generators/components/model/templates/unit_test.rb
@@ -2,7 +2,7 @@ require 'test_helper'
class <%= class_name %>Test < ActiveSupport::TestCase
# Replace this with your real tests.
- def test_truth
+ test "the truth" do
assert true
end
end
diff --git a/railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb b/railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb
index 1faf8ed9ac..cae38e9a2a 100644
--- a/railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb
+++ b/railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb
@@ -2,7 +2,7 @@ require 'test_helper'
class <%= class_name %>ObserverTest < Test::Unit::TestCase
# Replace this with your real tests.
- def test_truth
+ test "the truth" do
assert true
end
end
diff --git a/railties/lib/rails_generator/generators/components/performance_test/USAGE b/railties/lib/rails_generator/generators/components/performance_test/USAGE
new file mode 100644
index 0000000000..d84051eb02
--- /dev/null
+++ b/railties/lib/rails_generator/generators/components/performance_test/USAGE
@@ -0,0 +1,8 @@
+Description:
+ Stubs out a new performance test. Pass the name of the test, either
+ CamelCased or under_scored, as an argument. The new test class is
+ generated in test/performance/testname_test.rb
+
+Example:
+ `./script/generate performance_test GeneralStories` creates a GeneralStories
+ performance test in test/performance/general_stories_test.rb
diff --git a/railties/lib/rails_generator/generators/components/performance_test/performance_test_generator.rb b/railties/lib/rails_generator/generators/components/performance_test/performance_test_generator.rb
new file mode 100644
index 0000000000..fbcc1cf683
--- /dev/null
+++ b/railties/lib/rails_generator/generators/components/performance_test/performance_test_generator.rb
@@ -0,0 +1,16 @@
+class PerformanceTestGenerator < Rails::Generator::NamedBase
+ default_options :skip_migration => false
+
+ def manifest
+ record do |m|
+ # Check for class naming collisions.
+ m.class_collisions class_path, class_name, "#{class_name}Test"
+
+ # performance test directory
+ m.directory File.join('test/performance', class_path)
+
+ # performance test stub
+ m.template 'performance_test.rb', File.join('test/performance', class_path, "#{file_name}_test.rb")
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/performance_test/templates/performance_test.rb b/railties/lib/rails_generator/generators/components/performance_test/templates/performance_test.rb
new file mode 100644
index 0000000000..352ff48054
--- /dev/null
+++ b/railties/lib/rails_generator/generators/components/performance_test/templates/performance_test.rb
@@ -0,0 +1,8 @@
+require 'performance/test_helper'
+
+class <%= class_name %>Test < ActionController::PerformanceTest
+ # Replace this with your real tests.
+ def test_homepage
+ get '/'
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb b/railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb
index 9028b84b7d..6ede6ef1d2 100644
--- a/railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb
+++ b/railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb
@@ -2,7 +2,7 @@ require 'test/unit'
class <%= class_name %>Test < Test::Unit::TestCase
# Replace this with your real tests.
- def test_this_plugin
- flunk
+ test "the truth" do
+ assert true
end
end
diff --git a/railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb b/railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb
index fbb69fcca7..b1bb1dacbf 100644
--- a/railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb
+++ b/railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb
@@ -2,7 +2,7 @@ require 'test_helper'
class <%= controller_class_name %>ControllerTest < ActionController::TestCase
# Replace this with your real tests.
- def test_truth
+ test "the truth" do
assert true
end
end
diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb b/railties/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb
index 3b430a2061..2d9d635944 100644
--- a/railties/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb
+++ b/railties/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb
@@ -1,18 +1,18 @@
require 'test_helper'
class <%= controller_class_name %>ControllerTest < ActionController::TestCase
- def test_should_get_index
+ test "should get index" do
get :index
assert_response :success
assert_not_nil assigns(:<%= table_name %>)
end
- def test_should_get_new
+ test "should get new" do
get :new
assert_response :success
end
- def test_should_create_<%= file_name %>
+ test "should create <%= file_name %>" do
assert_difference('<%= class_name %>.count') do
post :create, :<%= file_name %> => { }
end
@@ -20,22 +20,22 @@ class <%= controller_class_name %>ControllerTest < ActionController::TestCase
assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>))
end
- def test_should_show_<%= file_name %>
+ test "should show <%= file_name %>" do
get :show, :id => <%= table_name %>(:one).id
assert_response :success
end
- def test_should_get_edit
+ test "should get edit" do
get :edit, :id => <%= table_name %>(:one).id
assert_response :success
end
- def test_should_update_<%= file_name %>
+ test "should update <%= file_name %>" do
put :update, :id => <%= table_name %>(:one).id, :<%= file_name %> => { }
assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>))
end
- def test_should_destroy_<%= file_name %>
+ test "should destroy <%= file_name %>" do
assert_difference('<%= class_name %>.count', -1) do
delete :destroy, :id => <%= table_name %>(:one).id
end
diff --git a/railties/lib/tasks/databases.rake b/railties/lib/tasks/databases.rake
index 8077d0a401..75fba8b45a 100644
--- a/railties/lib/tasks/databases.rake
+++ b/railties/lib/tasks/databases.rake
@@ -264,13 +264,15 @@ namespace :db do
end
namespace :test do
- desc "Recreate the test database from the current environment's database schema"
- task :clone => %w(db:schema:dump db:test:purge) do
+ desc "Recreate the test database from the current schema.rb"
+ task :load => 'db:test:purge' do
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
ActiveRecord::Schema.verbose = false
Rake::Task["db:schema:load"].invoke
end
+ desc "Recreate the test database from the current environment's database schema"
+ task :clone => %w(db:schema:dump db:test:load)
desc "Recreate the test databases from the development structure"
task :clone_structure => [ "db:structure:dump", "db:test:purge" ] do
@@ -337,10 +339,10 @@ namespace :db do
end
end
- desc 'Prepare the test database and load the schema'
- task :prepare => %w(environment db:abort_if_pending_migrations) do
+ desc 'Check for pending migrations and load the test schema'
+ task :prepare => 'db:abort_if_pending_migrations' do
if defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
- Rake::Task[{ :sql => "db:test:clone_structure", :ruby => "db:test:clone" }[ActiveRecord::Base.schema_format]].invoke
+ Rake::Task[{ :sql => "db:test:clone_structure", :ruby => "db:test:load" }[ActiveRecord::Base.schema_format]].invoke
end
end
end
diff --git a/railties/lib/tasks/rails.rb b/railties/lib/tasks/rails.rb
index bfcf5bc493..8c2b7f9bde 100644
--- a/railties/lib/tasks/rails.rb
+++ b/railties/lib/tasks/rails.rb
@@ -4,5 +4,5 @@ $VERBOSE = nil
Dir["#{File.dirname(__FILE__)}/*.rake"].each { |ext| load ext }
# Load any custom rakefile extensions
-Dir["#{RAILS_ROOT}/lib/tasks/**/*.rake"].sort.each { |ext| load ext }
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/tasks/testing.rake b/railties/lib/tasks/testing.rake
index cc2376cbb3..c8ba6eed94 100644
--- a/railties/lib/tasks/testing.rake
+++ b/railties/lib/tasks/testing.rake
@@ -103,6 +103,21 @@ namespace :test do
end
Rake::Task['test:integration'].comment = "Run the integration tests in test/integration"
+ Rake::TestTask.new(:benchmark => 'db:test:prepare') do |t|
+ t.libs << 'test'
+ t.pattern = 'test/performance/**/*_test.rb'
+ t.verbose = true
+ t.options = '-- --benchmark'
+ end
+ Rake::Task['test:benchmark'].comment = 'Benchmark the performance tests'
+
+ Rake::TestTask.new(:profile => 'db:test:prepare') do |t|
+ t.libs << 'test'
+ t.pattern = 'test/performance/**/*_test.rb'
+ t.verbose = true
+ end
+ Rake::Task['test:profile'].comment = 'Profile the performance tests'
+
Rake::TestTask.new(:plugins => :environment) do |t|
t.libs << "test"
diff --git a/railties/lib/test_help.rb b/railties/lib/test_help.rb
index 22ce9ab609..3cc61d7932 100644
--- a/railties/lib/test_help.rb
+++ b/railties/lib/test_help.rb
@@ -8,7 +8,6 @@ require 'test/unit'
require 'active_support/test_case'
require 'active_record/fixtures'
require 'action_controller/test_case'
-require 'action_controller/test_process'
require 'action_controller/integration'
require 'action_mailer/test_case' if defined?(ActionMailer)
@@ -25,4 +24,4 @@ begin
Debugger.settings[:autoeval] = true if Debugger.respond_to?(:settings)
rescue LoadError
# ruby-debug wasn't available so neither can the debugging be
-end \ No newline at end of file
+end
diff --git a/railties/lib/webrick_server.rb b/railties/lib/webrick_server.rb
index ad4ca926ba..2f60151b22 100644
--- a/railties/lib/webrick_server.rb
+++ b/railties/lib/webrick_server.rb
@@ -43,8 +43,6 @@ end
# can change this behavior by setting ActionController::Base.allow_concurrency
# to true.
class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet
- REQUEST_MUTEX = Mutex.new
-
# Start the WEBrick server with the given options, mounting the
# DispatchServlet at <tt>/</tt>.
def self.dispatch(options = {})
@@ -73,15 +71,8 @@ class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet
def service(req, res) #:nodoc:
unless handle_file(req, res)
- begin
- REQUEST_MUTEX.lock unless ActionController::Base.allow_concurrency
- unless handle_dispatch(req, res)
- raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found."
- end
- ensure
- unless ActionController::Base.allow_concurrency
- REQUEST_MUTEX.unlock if REQUEST_MUTEX.locked?
- end
+ unless handle_dispatch(req, res)
+ raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found."
end
end
end
diff --git a/railties/test/fixtures/plugins/default/gemlike/init.rb b/railties/test/fixtures/plugins/default/gemlike/init.rb
new file mode 100644
index 0000000000..6a771b5b68
--- /dev/null
+++ b/railties/test/fixtures/plugins/default/gemlike/init.rb
@@ -0,0 +1 @@
+raise 'This init.rb should not be evaluated because rails/init.rb exists'
diff --git a/railties/test/fixtures/plugins/default/gemlike/lib/gemlike.rb b/railties/test/fixtures/plugins/default/gemlike/lib/gemlike.rb
new file mode 100644
index 0000000000..2088103e45
--- /dev/null
+++ b/railties/test/fixtures/plugins/default/gemlike/lib/gemlike.rb
@@ -0,0 +1,2 @@
+module Gemlike
+end \ No newline at end of file
diff --git a/railties/test/fixtures/plugins/default/gemlike/rails/init.rb b/railties/test/fixtures/plugins/default/gemlike/rails/init.rb
new file mode 100644
index 0000000000..171a293eb3
--- /dev/null
+++ b/railties/test/fixtures/plugins/default/gemlike/rails/init.rb
@@ -0,0 +1,7 @@
+# I have access to my directory and the Rails config.
+raise 'directory expected but undefined in init.rb' unless defined? directory
+raise 'config expected but undefined in init.rb' unless defined? config
+
+# My lib/ dir must be in the load path.
+require 'gemlike'
+raise 'missing mixin from my lib/ dir' unless defined? Gemlike
diff --git a/railties/test/gem_dependency_test.rb b/railties/test/gem_dependency_test.rb
index 3ae0189327..b5946aa7b8 100644
--- a/railties/test/gem_dependency_test.rb
+++ b/railties/test/gem_dependency_test.rb
@@ -10,13 +10,13 @@ uses_mocha "Plugin Tests" do
@gem = Rails::GemDependency.new "hpricot"
@gem_with_source = Rails::GemDependency.new "hpricot", :source => "http://code.whytheluckystiff.net"
@gem_with_version = Rails::GemDependency.new "hpricot", :version => "= 0.6"
- @gem_with_lib = Rails::GemDependency.new "aws-s3", :lib => "aws/s3"
+ @gem_with_lib = Rails::GemDependency.new "aws-s3", :lib => "aws/s3"
end
def test_configuration_adds_gem_dependency
config = Rails::Configuration.new
config.gem "aws-s3", :lib => "aws/s3", :version => "0.4.0"
- assert_equal [["install", "aws-s3", "--version", "= 0.4.0"]], config.gems.collect(&:install_command)
+ assert_equal [["install", "aws-s3", "--version", '"= 0.4.0"']], config.gems.collect(&:install_command)
end
def test_gem_creates_install_command
@@ -28,7 +28,7 @@ uses_mocha "Plugin Tests" do
end
def test_gem_with_version_creates_install_command
- assert_equal ["install", "hpricot", "--version", "= 0.6"], @gem_with_version.install_command
+ assert_equal ["install", "hpricot", "--version", '"= 0.6"'], @gem_with_version.install_command
end
def test_gem_creates_unpack_command
@@ -36,26 +36,26 @@ uses_mocha "Plugin Tests" do
end
def test_gem_with_version_unpack_install_command
- assert_equal ["unpack", "hpricot", "--version", "= 0.6"], @gem_with_version.unpack_command
+ assert_equal ["unpack", "hpricot", "--version", '"= 0.6"'], @gem_with_version.unpack_command
end
def test_gem_adds_load_paths
@gem.expects(:gem).with(@gem.name)
@gem.add_load_paths
end
-
+
def test_gem_with_version_adds_load_paths
@gem_with_version.expects(:gem).with(@gem_with_version.name, @gem_with_version.requirement.to_s)
@gem_with_version.add_load_paths
end
-
+
def test_gem_loading
@gem.expects(:gem).with(@gem.name)
@gem.expects(:require).with(@gem.name)
@gem.add_load_paths
@gem.load
end
-
+
def test_gem_with_lib_loading
@gem_with_lib.expects(:gem).with(@gem_with_lib.name)
@gem_with_lib.expects(:require).with(@gem_with_lib.lib)
@@ -63,4 +63,4 @@ uses_mocha "Plugin Tests" do
@gem_with_lib.load
end
end
-end \ No newline at end of file
+end
diff --git a/railties/test/initializer_test.rb b/railties/test/initializer_test.rb
index 0df0164ca6..dee7abe05f 100644
--- a/railties/test/initializer_test.rb
+++ b/railties/test/initializer_test.rb
@@ -30,64 +30,66 @@ class Initializer_load_environment_Test < Test::Unit::TestCase
end
-class Initializer_after_initialize_with_blocks_environment_Test < Test::Unit::TestCase
- def setup
- config = ConfigurationMock.new("")
- config.after_initialize do
- $test_after_initialize_block1 = "success"
- end
- config.after_initialize do
- $test_after_initialize_block2 = "congratulations"
- end
- assert_nil $test_after_initialize_block1
- assert_nil $test_after_initialize_block2
-
- Rails::Initializer.run(:after_initialize, config)
- end
-
- def teardown
- $test_after_initialize_block1 = nil
- $test_after_initialize_block2 = nil
- end
+uses_mocha 'Initializer after_initialize' do
+ class Initializer_after_initialize_with_blocks_environment_Test < Test::Unit::TestCase
+ def setup
+ config = ConfigurationMock.new("")
+ config.after_initialize do
+ $test_after_initialize_block1 = "success"
+ end
+ config.after_initialize do
+ $test_after_initialize_block2 = "congratulations"
+ end
+ assert_nil $test_after_initialize_block1
+ assert_nil $test_after_initialize_block2
- def test_should_have_called_the_first_after_initialize_block
- assert_equal "success", $test_after_initialize_block1
- end
-
- def test_should_have_called_the_second_after_initialize_block
- assert_equal "congratulations", $test_after_initialize_block2
- end
-end
-
-class Initializer_after_initialize_with_no_block_environment_Test < Test::Unit::TestCase
+ Rails::Initializer.any_instance.expects(:gems_dependencies_loaded).returns(true)
+ Rails::Initializer.run(:after_initialize, config)
+ end
- def setup
- config = ConfigurationMock.new("")
- config.after_initialize do
- $test_after_initialize_block1 = "success"
+ def teardown
+ $test_after_initialize_block1 = nil
+ $test_after_initialize_block2 = nil
end
- config.after_initialize # don't pass a block, this is what we're testing!
- config.after_initialize do
- $test_after_initialize_block2 = "congratulations"
- end
- assert_nil $test_after_initialize_block1
- Rails::Initializer.run(:after_initialize, config)
- end
+ def test_should_have_called_the_first_after_initialize_block
+ assert_equal "success", $test_after_initialize_block1
+ end
- def teardown
- $test_after_initialize_block1 = nil
- $test_after_initialize_block2 = nil
+ def test_should_have_called_the_second_after_initialize_block
+ assert_equal "congratulations", $test_after_initialize_block2
+ end
end
- def test_should_have_called_the_first_after_initialize_block
- assert_equal "success", $test_after_initialize_block1, "should still get set"
- end
+ class Initializer_after_initialize_with_no_block_environment_Test < Test::Unit::TestCase
+ def setup
+ config = ConfigurationMock.new("")
+ config.after_initialize do
+ $test_after_initialize_block1 = "success"
+ end
+ config.after_initialize # don't pass a block, this is what we're testing!
+ config.after_initialize do
+ $test_after_initialize_block2 = "congratulations"
+ end
+ assert_nil $test_after_initialize_block1
- def test_should_have_called_the_second_after_initialize_block
- assert_equal "congratulations", $test_after_initialize_block2
- end
+ Rails::Initializer.any_instance.expects(:gems_dependencies_loaded).returns(true)
+ Rails::Initializer.run(:after_initialize, config)
+ end
+
+ def teardown
+ $test_after_initialize_block1 = nil
+ $test_after_initialize_block2 = nil
+ end
+ def test_should_have_called_the_first_after_initialize_block
+ assert_equal "success", $test_after_initialize_block1, "should still get set"
+ end
+
+ def test_should_have_called_the_second_after_initialize_block
+ assert_equal "congratulations", $test_after_initialize_block2
+ end
+ end
end
uses_mocha 'framework paths' do
@@ -95,7 +97,7 @@ uses_mocha 'framework paths' do
def setup
@config = Rails::Configuration.new
@config.frameworks.clear
-
+
File.stubs(:directory?).returns(true)
@config.stubs(:framework_root_path).returns('')
end
@@ -112,7 +114,7 @@ uses_mocha 'framework paths' do
def test_actioncontroller_or_actionview_add_actionpack
@config.frameworks << :action_controller
assert_framework_path '/actionpack/lib'
-
+
@config.frameworks = [:action_view]
assert_framework_path '/actionpack/lib'
end
@@ -171,7 +173,7 @@ uses_mocha "Initializer plugin loading tests" do
def test_all_plugins_are_loaded_when_registered_plugin_list_is_untouched
failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
load_plugins!
- assert_plugins [:a, :acts_as_chunky_bacon, :plugin_with_no_lib_dir, :stubby], @initializer.loaded_plugins, failure_tip
+ assert_plugins [:a, :acts_as_chunky_bacon, :gemlike, :plugin_with_no_lib_dir, :stubby], @initializer.loaded_plugins, failure_tip
end
def test_all_plugins_loaded_when_all_is_used
@@ -179,7 +181,7 @@ uses_mocha "Initializer plugin loading tests" do
only_load_the_following_plugins! plugin_names
load_plugins!
failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
- assert_plugins [:stubby, :acts_as_chunky_bacon, :a, :plugin_with_no_lib_dir], @initializer.loaded_plugins, failure_tip
+ assert_plugins [:stubby, :acts_as_chunky_bacon, :a, :gemlike, :plugin_with_no_lib_dir], @initializer.loaded_plugins, failure_tip
end
def test_all_plugins_loaded_after_all
@@ -187,7 +189,7 @@ uses_mocha "Initializer plugin loading tests" do
only_load_the_following_plugins! plugin_names
load_plugins!
failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
- assert_plugins [:stubby, :a, :plugin_with_no_lib_dir, :acts_as_chunky_bacon], @initializer.loaded_plugins, failure_tip
+ assert_plugins [:stubby, :a, :gemlike, :plugin_with_no_lib_dir, :acts_as_chunky_bacon], @initializer.loaded_plugins, failure_tip
end
def test_plugin_names_may_be_strings
@@ -204,22 +206,22 @@ uses_mocha "Initializer plugin loading tests" do
load_plugins!
end
end
-
+
def test_should_ensure_all_loaded_plugins_load_paths_are_added_to_the_load_path
only_load_the_following_plugins! [:stubby, :acts_as_chunky_bacon]
@initializer.add_plugin_load_paths
-
+
assert $LOAD_PATH.include?(File.join(plugin_fixture_path('default/stubby'), 'lib'))
assert $LOAD_PATH.include?(File.join(plugin_fixture_path('default/acts/acts_as_chunky_bacon'), 'lib'))
end
-
+
private
-
+
def load_plugins!
@initializer.add_plugin_load_paths
@initializer.load_plugins
end
end
-
-end
+
+end
diff --git a/railties/test/plugin_loader_test.rb b/railties/test/plugin_loader_test.rb
index 41bd6ec7ea..f429bae15c 100644
--- a/railties/test/plugin_loader_test.rb
+++ b/railties/test/plugin_loader_test.rb
@@ -48,16 +48,16 @@ uses_mocha "Plugin Loader Tests" do
end
def test_should_find_all_availble_plugins_and_return_as_all_plugins
- assert_plugins [:stubby, :plugin_with_no_lib_dir, :acts_as_chunky_bacon, :a], @loader.all_plugins.reverse, @failure_tip
+ assert_plugins [:stubby, :plugin_with_no_lib_dir, :gemlike, :acts_as_chunky_bacon, :a], @loader.all_plugins.reverse, @failure_tip
end
def test_should_return_all_plugins_as_plugins_when_registered_plugin_list_is_untouched
- assert_plugins [:a, :acts_as_chunky_bacon, :plugin_with_no_lib_dir, :stubby], @loader.plugins, @failure_tip
+ assert_plugins [:a, :acts_as_chunky_bacon, :gemlike, :plugin_with_no_lib_dir, :stubby], @loader.plugins, @failure_tip
end
def test_should_return_all_plugins_as_plugins_when_registered_plugin_list_is_nil
@configuration.plugins = nil
- assert_plugins [:a, :acts_as_chunky_bacon, :plugin_with_no_lib_dir, :stubby], @loader.plugins, @failure_tip
+ assert_plugins [:a, :acts_as_chunky_bacon, :gemlike, :plugin_with_no_lib_dir, :stubby], @loader.plugins, @failure_tip
end
def test_should_return_specific_plugins_named_in_config_plugins_array_if_set
@@ -74,17 +74,17 @@ uses_mocha "Plugin Loader Tests" do
def test_should_load_all_plugins_in_natural_order_when_all_is_used
only_load_the_following_plugins! [:all]
- assert_plugins [:a, :acts_as_chunky_bacon, :plugin_with_no_lib_dir, :stubby], @loader.plugins, @failure_tip
+ assert_plugins [:a, :acts_as_chunky_bacon, :gemlike, :plugin_with_no_lib_dir, :stubby], @loader.plugins, @failure_tip
end
def test_should_load_specified_plugins_in_order_and_then_all_remaining_plugins_when_all_is_used
only_load_the_following_plugins! [:stubby, :acts_as_chunky_bacon, :all]
- assert_plugins [:stubby, :acts_as_chunky_bacon, :a, :plugin_with_no_lib_dir], @loader.plugins, @failure_tip
+ assert_plugins [:stubby, :acts_as_chunky_bacon, :a, :gemlike, :plugin_with_no_lib_dir], @loader.plugins, @failure_tip
end
def test_should_be_able_to_specify_loading_of_plugins_loaded_after_all
only_load_the_following_plugins! [:stubby, :all, :acts_as_chunky_bacon]
- assert_plugins [:stubby, :a, :plugin_with_no_lib_dir, :acts_as_chunky_bacon], @loader.plugins, @failure_tip
+ assert_plugins [:stubby, :a, :gemlike, :plugin_with_no_lib_dir, :acts_as_chunky_bacon], @loader.plugins, @failure_tip
end
def test_should_accept_plugin_names_given_as_strings
@@ -94,7 +94,7 @@ uses_mocha "Plugin Loader Tests" do
def test_should_add_plugin_load_paths_to_global_LOAD_PATH_array
only_load_the_following_plugins! [:stubby, :acts_as_chunky_bacon]
- stubbed_application_lib_index_in_LOAD_PATHS = 5
+ stubbed_application_lib_index_in_LOAD_PATHS = 4
@loader.stubs(:application_lib_index).returns(stubbed_application_lib_index_in_LOAD_PATHS)
@loader.add_plugin_load_paths
@@ -108,8 +108,8 @@ uses_mocha "Plugin Loader Tests" do
@loader.add_plugin_load_paths
- assert Dependencies.load_paths.include?(File.join(plugin_fixture_path('default/stubby'), 'lib'))
- assert Dependencies.load_paths.include?(File.join(plugin_fixture_path('default/acts/acts_as_chunky_bacon'), 'lib'))
+ assert ActiveSupport::Dependencies.load_paths.include?(File.join(plugin_fixture_path('default/stubby'), 'lib'))
+ assert ActiveSupport::Dependencies.load_paths.include?(File.join(plugin_fixture_path('default/acts/acts_as_chunky_bacon'), 'lib'))
end
def test_should_add_plugin_load_paths_to_Dependencies_load_once_paths
@@ -117,8 +117,8 @@ uses_mocha "Plugin Loader Tests" do
@loader.add_plugin_load_paths
- assert Dependencies.load_once_paths.include?(File.join(plugin_fixture_path('default/stubby'), 'lib'))
- assert Dependencies.load_once_paths.include?(File.join(plugin_fixture_path('default/acts/acts_as_chunky_bacon'), 'lib'))
+ assert ActiveSupport::Dependencies.load_once_paths.include?(File.join(plugin_fixture_path('default/stubby'), 'lib'))
+ assert ActiveSupport::Dependencies.load_once_paths.include?(File.join(plugin_fixture_path('default/acts/acts_as_chunky_bacon'), 'lib'))
end
def test_should_add_all_load_paths_from_a_plugin_to_LOAD_PATH_array
diff --git a/railties/test/plugin_locator_test.rb b/railties/test/plugin_locator_test.rb
index 5f1dd991ea..363fa27f15 100644
--- a/railties/test/plugin_locator_test.rb
+++ b/railties/test/plugin_locator_test.rb
@@ -47,12 +47,12 @@ uses_mocha "Plugin Locator Tests" do
end
def test_should_return_all_plugins_found_under_the_set_plugin_paths
- assert_equal ["a", "acts_as_chunky_bacon", "plugin_with_no_lib_dir", "stubby"].sort, @locator.plugins.map(&:name).sort
+ assert_equal ["a", "acts_as_chunky_bacon", "gemlike", "plugin_with_no_lib_dir", "stubby"].sort, @locator.plugins.map(&:name).sort
end
def test_should_find_plugins_only_under_the_plugin_paths_set_in_configuration
@configuration.plugin_paths = [File.join(plugin_fixture_root_path, "default")]
- assert_equal ["acts_as_chunky_bacon", "plugin_with_no_lib_dir", "stubby"].sort, @locator.plugins.map(&:name).sort
+ assert_equal ["acts_as_chunky_bacon", "gemlike", "plugin_with_no_lib_dir", "stubby"].sort, @locator.plugins.map(&:name).sort
@configuration.plugin_paths = [File.join(plugin_fixture_root_path, "alternate")]
assert_equal ["a"], @locator.plugins.map(&:name)
diff --git a/railties/test/plugin_test.rb b/railties/test/plugin_test.rb
index 1445338f14..50124240a5 100644
--- a/railties/test/plugin_test.rb
+++ b/railties/test/plugin_test.rb
@@ -5,9 +5,10 @@ uses_mocha "Plugin Tests" do
class PluginTest < Test::Unit::TestCase
def setup
- @initializer = Rails::Initializer.new(Rails::Configuration.new)
- @valid_plugin_path = plugin_fixture_path('default/stubby')
- @empty_plugin_path = plugin_fixture_path('default/empty')
+ @initializer = Rails::Initializer.new(Rails::Configuration.new)
+ @valid_plugin_path = plugin_fixture_path('default/stubby')
+ @empty_plugin_path = plugin_fixture_path('default/empty')
+ @gemlike_plugin_path = plugin_fixture_path('default/gemlike')
end
def test_should_determine_plugin_name_from_the_directory_of_the_plugin
@@ -70,7 +71,14 @@ uses_mocha "Plugin Tests" do
plugin.stubs(:evaluate_init_rb)
plugin.send(:load, @initializer)
end
-
+
+ # This path is fine so nothing is raised
+ assert_nothing_raised do
+ plugin = plugin_for(@gemlike_plugin_path)
+ plugin.stubs(:evaluate_init_rb)
+ plugin.send(:load, @initializer)
+ end
+
# This is an empty path so it raises
assert_raises(LoadError) do
plugin = plugin_for(@empty_plugin_path)
diff --git a/railties/test/rails_info_controller_test.rb b/railties/test/rails_info_controller_test.rb
index 17c7d9deea..e1872ebf33 100644
--- a/railties/test/rails_info_controller_test.rb
+++ b/railties/test/rails_info_controller_test.rb
@@ -30,6 +30,8 @@ class Rails::InfoControllerTest < Test::Unit::TestCase
@controller = Rails::InfoController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
+
+ ActionController::Base.consider_all_requests_local = true
end
def test_rails_info_properties_table_rendered_for_local_request
@@ -41,6 +43,8 @@ class Rails::InfoControllerTest < Test::Unit::TestCase
def test_rails_info_properties_error_rendered_for_non_local_request
Rails::InfoController.local_request = false
+ ActionController::Base.consider_all_requests_local = false
+
get :properties
assert_tag :tag => 'p'
assert_response 500