From 5292899c9ae6e52715568021ebe46ed8b1b31bd1 Mon Sep 17 00:00:00 2001 From: Jacques Distler Date: Sat, 17 May 2008 23:22:34 -0500 Subject: [PATCH] Rails 2.1 RC1 Updated Instiki to Rails 2.1 RC1 (aka 2.0.991). --- app/controllers/admin_controller.rb | 2 - config/boot.rb | 142 +- config/environment.rb | 5 +- test/functional/admin_controller_test.rb | 1 + test/test_helper.rb | 2 - vendor/rails/actionmailer/CHANGELOG | 11 + vendor/rails/actionmailer/MIT-LICENSE | 2 +- vendor/rails/actionmailer/Rakefile | 5 +- .../rails/actionmailer/lib/action_mailer.rb | 2 +- .../lib/action_mailer/adv_attr_accessor.rb | 2 +- .../actionmailer/lib/action_mailer/base.rb | 97 +- .../actionmailer/lib/action_mailer/helpers.rb | 12 +- .../actionmailer/lib/action_mailer/quoting.rb | 2 + .../lib/action_mailer/test_case.rb | 25 +- .../actionmailer/lib/action_mailer/vendor.rb | 4 +- .../vendor/tmail-1.1.0/tmail/Makefile | 19 - .../vendor/tmail-1.1.0/tmail/address.rb | 245 -- .../vendor/tmail-1.1.0/tmail/facade.rb | 552 ----- .../vendor/tmail-1.1.0/tmail/info.rb | 35 - .../vendor/tmail-1.1.0/tmail/interface.rb | 540 ----- .../vendor/tmail-1.1.0/tmail/parser.y | 381 --- .../vendor/tmail-1.1.0/tmail/tmail.rb | 1 - .../{tmail-1.1.0 => tmail-1.2.2}/tmail.rb | 1 + .../vendor/tmail-1.2.2/tmail/address.rb | 426 ++++ .../tmail/attachments.rb | 5 +- .../tmail/base64.rb | 14 +- .../tmail/compat.rb | 14 +- .../tmail/config.rb | 8 +- .../tmail/core_extensions.rb | 32 +- .../tmail/encode.rb | 176 +- .../tmail/header.rb | 53 +- .../vendor/tmail-1.2.2/tmail/index.rb | 9 + .../vendor/tmail-1.2.2/tmail/interface.rb | 1125 +++++++++ .../tmail/loader.rb | 2 + .../tmail/mail.rb | 134 +- .../tmail/mailbox.rb | 86 +- .../vendor/tmail-1.2.2/tmail/main.rb | 6 + .../tmail/mbox.rb | 2 + .../{tmail-1.1.0 => tmail-1.2.2}/tmail/net.rb | 66 +- .../tmail/obsolete.rb | 19 +- .../tmail/parser.rb | 1 + .../tmail/port.rb | 0 .../tmail/quoting.rb | 36 +- .../vendor/tmail-1.2.2/tmail/require_arch.rb | 58 + .../tmail/scanner.rb | 18 +- .../tmail/scanner_r.rb | 34 +- .../tmail/stringio.rb | 1 + .../tmail/utils.rb | 126 +- .../tmail/version.rb | 9 +- .../actionmailer/lib/action_mailer/version.rb | 2 +- .../actionmailer/test/delivery_method_test.rb | 2 +- ...ltipart_with_template_path_with_dots.rhtml | 0 .../test/fixtures/raw_base64_decoded_string | Bin 8576 -> 0 bytes .../test/fixtures/raw_base64_encoded_string | 1 - .../test/fixtures/second_mailer/share.rhtml | 0 .../test/fixtures/templates/signed_up.rhtml | 0 ...implicitly_multipart_example.ignored.rhtml | 0 ...plicitly_multipart_example.text.html.rhtml | 0 ...licitly_multipart_example.text.plain.rhtml | 0 ...plicitly_multipart_example.text.yaml.rhtml | 0 .../test/fixtures/test_mailer/signed_up.rhtml | 0 .../test_mailer/signed_up_with_url.rhtml | 0 .../actionmailer/test/mail_helper_test.rb | 2 +- .../actionmailer/test/mail_render_test.rb | 2 +- .../actionmailer/test/mail_service_test.rb | 26 +- .../rails/actionmailer/test/quoting_test.rb | 51 +- .../actionmailer/test/test_helper_test.rb | 16 +- vendor/rails/actionmailer/test/tmail_test.rb | 2 +- vendor/rails/actionmailer/test/url_test.rb | 4 +- vendor/rails/actionpack/CHANGELOG | 189 ++ vendor/rails/actionpack/MIT-LICENSE | 2 +- vendor/rails/actionpack/README | 2 +- vendor/rails/actionpack/Rakefile | 9 +- .../rails/actionpack/lib/action_controller.rb | 4 +- .../assertions/response_assertions.rb | 8 +- .../assertions/routing_assertions.rb | 7 +- .../assertions/selector_assertions.rb | 31 +- .../actionpack/lib/action_controller/base.rb | 182 +- .../lib/action_controller/benchmarking.rb | 6 +- .../lib/action_controller/caching.rb | 697 +----- .../lib/action_controller/caching/actions.rb | 143 ++ .../action_controller/caching/fragments.rb | 127 + .../lib/action_controller/caching/pages.rb | 154 ++ .../action_controller/caching/sql_cache.rb | 18 + .../lib/action_controller/caching/sweeping.rb | 97 + .../lib/action_controller/cgi_ext/cookie.rb | 9 +- .../lib/action_controller/cgi_process.rb | 7 +- .../lib/action_controller/components.rb | 13 +- .../lib/action_controller/cookies.rb | 50 +- .../lib/action_controller/dispatcher.rb | 135 +- .../lib/action_controller/filters.rb | 680 +++--- .../actionpack/lib/action_controller/flash.rb | 7 +- .../lib/action_controller/headers.rb | 31 + .../lib/action_controller/helpers.rb | 21 +- .../action_controller/http_authentication.rb | 8 +- .../lib/action_controller/integration.rb | 61 +- .../lib/action_controller/layout.rb | 92 +- .../lib/action_controller/mime_responds.rb | 8 +- .../lib/action_controller/mime_type.rb | 12 +- .../action_controller/polymorphic_routes.rb | 119 +- .../action_controller/record_identifier.rb | 22 +- .../lib/action_controller/request.rb | 91 +- .../request_forgery_protection.rb | 86 +- .../lib/action_controller/request_profiler.rb | 36 +- .../lib/action_controller/rescue.rb | 44 +- .../lib/action_controller/resources.rb | 83 +- .../lib/action_controller/routing.rb | 1347 +---------- .../lib/action_controller/routing/builder.rb | 204 ++ .../optimisations.rb} | 25 +- .../routing/recognition_optimisation.rb | 158 ++ .../lib/action_controller/routing/route.rb | 240 ++ .../action_controller/routing/route_set.rb | 435 ++++ .../action_controller/routing/routing_ext.rb | 46 + .../lib/action_controller/routing/segments.rb | 282 +++ .../session/active_record_store.rb | 32 +- .../action_controller/session/cookie_store.rb | 33 +- .../action_controller/session_management.rb | 13 +- .../lib/action_controller/streaming.rb | 76 +- .../templates/rescues/_trace.erb | 10 +- .../lib/action_controller/test_case.rb | 54 +- .../lib/action_controller/test_process.rb | 73 +- .../lib/action_controller/url_rewriter.rb | 81 +- .../vendor/html-scanner/html/sanitizer.rb | 4 +- .../vendor/html-scanner/html/tokenizer.rb | 2 +- .../lib/action_controller/verification.rb | 132 +- vendor/rails/actionpack/lib/action_pack.rb | 2 +- .../actionpack/lib/action_pack/version.rb | 2 +- vendor/rails/actionpack/lib/action_view.rb | 14 +- .../rails/actionpack/lib/action_view/base.rb | 449 +--- .../helpers/active_record_helper.rb | 147 +- .../action_view/helpers/asset_tag_helper.rb | 139 +- .../action_view/helpers/atom_feed_helper.rb | 68 +- .../action_view/helpers/benchmark_helper.rb | 8 +- .../lib/action_view/helpers/cache_helper.rb | 5 +- .../lib/action_view/helpers/capture_helper.rb | 3 +- .../lib/action_view/helpers/date_helper.rb | 182 +- .../lib/action_view/helpers/form_helper.rb | 109 +- .../helpers/form_options_helper.rb | 32 +- .../action_view/helpers/form_tag_helper.rb | 45 +- .../helpers/javascripts/controls.js | 2 +- .../helpers/javascripts/dragdrop.js | 2 +- .../helpers/javascripts/effects.js | 2 +- .../lib/action_view/helpers/number_helper.rb | 15 +- .../action_view/helpers/prototype_helper.rb | 80 +- .../action_view/helpers/record_tag_helper.rb | 2 +- .../action_view/helpers/sanitize_helper.rb | 9 +- .../helpers/scriptaculous_helper.rb | 41 +- .../lib/action_view/helpers/text_helper.rb | 167 +- .../lib/action_view/helpers/url_helper.rb | 60 +- .../lib/action_view/inline_template.rb | 20 + .../lib/action_view/partial_template.rb | 70 + .../actionpack/lib/action_view/partials.rb | 108 +- .../actionpack/lib/action_view/template.rb | 127 + .../lib/action_view/template_error.rb | 28 +- .../lib/action_view/template_finder.rb | 177 ++ .../lib/action_view/template_handler.rb | 19 +- .../action_view/template_handlers/builder.rb | 12 +- .../template_handlers/compilable.rb | 128 + .../lib/action_view/template_handlers/erb.rb | 39 +- .../lib/action_view/template_handlers/rjs.rb | 15 +- .../actionpack/lib/action_view/test_case.rb | 64 + vendor/rails/actionpack/test/abstract_unit.rb | 2 +- .../rails/actionpack/test/action_view_test.rb | 44 - .../actionpack/test/active_record_unit.rb | 9 +- .../activerecord/active_record_store_test.rb | 5 +- ...partial_with_record_identification_test.rb | 201 +- vendor/rails/actionpack/test/adv_attr_test.rb | 20 + .../controller/action_pack_assertions_test.rb | 20 +- .../test/controller/addresses_render_test.rb | 2 +- .../test/controller/assert_select_test.rb | 19 +- .../actionpack/test/controller/base_test.rb | 55 +- .../test/controller/benchmark_test.rb | 3 +- .../test/controller/caching_test.rb | 231 +- .../test/controller/capture_test.rb | 2 +- .../actionpack/test/controller/cgi_test.rb | 9 +- .../test/controller/components_test.rb | 2 +- .../test/controller/content_type_test.rb | 4 +- .../actionpack/test/controller/cookie_test.rb | 9 +- .../test/controller/custom_handler_test.rb | 24 +- .../deprecated_base_methods_test.rb | 2 +- .../test/controller/dispatcher_test.rb | 80 +- .../test/controller/fake_controllers.rb | 17 + .../actionpack/test/controller/fake_models.rb | 6 + .../test/controller/filter_params_test.rb | 2 +- .../test/controller/filters_test.rb | 63 +- .../actionpack/test/controller/flash_test.rb | 4 +- .../controller/fragment_store_setting_test.rb | 47 - .../actionpack/test/controller/header_test.rb | 14 + .../actionpack/test/controller/helper_test.rb | 32 +- .../controller/html-scanner/document_test.rb | 3 +- .../test/controller/html-scanner/node_test.rb | 3 +- .../controller/html-scanner/sanitizer_test.rb | 21 +- .../controller/html-scanner/tag_node_test.rb | 3 +- .../controller/html-scanner/text_node_test.rb | 5 +- .../controller/html-scanner/tokenizer_test.rb | 10 +- .../controller/http_authentication_test.rb | 2 +- .../test/controller/integration_test.rb | 31 +- .../controller/integration_upload_test.rb | 43 + .../actionpack/test/controller/layout_test.rb | 32 +- .../test/controller/mime_responds_test.rb | 46 +- .../test/controller/mime_type_test.rb | 14 +- .../test/controller/new_render_test.rb | 166 +- .../controller/polymorphic_routes_test.rb | 199 +- .../test/controller/record_identifier_test.rb | 40 +- .../test/controller/redirect_test.rb | 33 +- .../actionpack/test/controller/render_test.rb | 93 +- .../request_forgery_protection_test.rb | 35 +- .../test/controller/request_test.rb | 108 +- .../actionpack/test/controller/rescue_test.rb | 28 +- .../test/controller/resources_test.rb | 116 +- .../test/controller/routing_test.rb | 251 +- .../test/controller/selector_test.rb | 4 +- .../test/controller/send_file_test.rb | 17 +- .../controller/session/cookie_store_test.rb | 4 +- .../session/mem_cache_store_test.rb | 7 +- .../test/controller/session_fixation_test.rb | 2 +- .../controller/session_management_test.rb | 24 +- .../actionpack/test/controller/test_test.rb | 59 +- .../test/controller/url_rewriter_test.rb | 74 +- .../test/controller/verification_test.rb | 2 +- .../test/controller/view_paths_test.rb | 27 +- .../test/controller/webservice_test.rb | 51 +- .../bad_customers/_bad_customer.html.erb | 1 + .../rails/actionpack/test/fixtures/company.rb | 1 + .../fixtures/customers/_customer.html.erb | 1 + .../test/fixtures/db_definitions/sqlite.sql | 6 + .../fixtures/functional_caching/_partial.erb | 3 + .../fragment_cached.html.erb | 2 + ...html_fragment_cached_with_partial.html.erb | 1 + .../js_fragment_cached_with_partial.js.rjs | 1 + .../good_customers/_good_customer.html.erb | 1 + .../fixtures/layout_tests/layouts/symlinked | 1 + .../fixtures/layouts/block_with_layout.erb | 3 + .../fixtures/layouts/partial_with_layout.erb | 3 + .../rails/actionpack/test/fixtures/mascot.rb | 3 + .../actionpack/test/fixtures/mascots.yml | 4 + .../test/fixtures/mascots/_mascot.html.erb | 1 + .../fixtures/multipart/boundary_problem_file | 10 + .../public/javascripts/application.js | 1 + .../fixtures/public/javascripts/controls.js | 1 + .../fixtures/public/javascripts/dragdrop.js | 1 + .../fixtures/public/javascripts/effects.js | 1 + .../fixtures/public/javascripts/prototype.js | 1 + .../public/javascripts/version.1.0.js | 1 + .../public/stylesheets/version.1.0.css | 1 + .../rails/actionpack/test/fixtures/reply.rb | 1 + .../actionpack/test/fixtures/shared.html.erb | 1 + .../symlink_parent/symlinked_layout.erb | 5 + .../test/fixtures/test/_customer_counter.erb | 1 + .../actionpack/test/fixtures/test/_form.erb | 1 + .../test/fixtures/test/_labelling_form.erb | 1 + .../test/fixtures/test/_raise.html.erb | 1 + .../test/fixtures/test/greeting.js.rjs | 1 + .../test/fixtures/topics/_topic.html.erb | 1 + .../template/active_record_helper_test.rb | 33 +- .../test/template/asset_tag_helper_test.rb | 147 +- .../test/template/atom_feed_helper_test.rb | 84 +- .../test/template/benchmark_helper_test.rb | 32 +- .../test/template/compiled_templates_test.rb | 215 +- .../test/template/date_helper_test.rb | 648 +++-- .../actionpack/test/template/erb_util_test.rb | 52 +- .../test/template/form_helper_test.rb | 247 +- .../test/template/form_options_helper_test.rb | 54 +- .../test/template/form_tag_helper_test.rb | 37 +- .../test/template/javascript_helper_test.rb | 12 +- .../test/template/number_helper_test.rb | 10 +- .../test/template/prototype_helper_test.rb | 60 +- .../test/template/record_tag_helper_test.rb | 54 + .../test/template/sanitize_helper_test.rb | 11 +- .../template/scriptaculous_helper_test.rb | 20 +- .../test/template/tag_helper_test.rb | 9 +- .../test/template/template_finder_test.rb | 73 + .../test/template/template_object_test.rb | 95 + .../actionpack/test/template/test_test.rb | 56 + .../test/template/text_helper_test.rb | 81 +- .../test/template/url_helper_test.rb | 20 +- .../rails/actionpack/test/testing_sandbox.rb | 12 +- vendor/rails/activerecord/CHANGELOG | 188 +- vendor/rails/activerecord/MIT-LICENSE | 2 +- vendor/rails/activerecord/README | 49 +- vendor/rails/activerecord/RUNNING_UNIT_TESTS | 11 +- vendor/rails/activerecord/Rakefile | 46 +- .../rails/activerecord/lib/active_record.rb | 10 +- .../lib/active_record/aggregations.rb | 17 +- .../lib/active_record/association_preload.rb | 277 +++ .../lib/active_record/associations.rb | 1008 +++++--- .../associations/association_collection.rb | 164 +- .../associations/association_proxy.rb | 73 +- .../associations/belongs_to_association.rb | 5 +- .../has_and_belongs_to_many_association.rb | 100 +- .../associations/has_many_association.rb | 79 +- .../has_many_through_association.rb | 210 +- .../associations/has_one_association.rb | 9 +- .../has_one_through_association.rb | 28 + .../lib/active_record/attribute_methods.rb | 49 +- .../activerecord/lib/active_record/base.rb | 643 +++-- .../lib/active_record/calculations.rb | 28 +- .../lib/active_record/callbacks.rb | 45 +- .../abstract/connection_specification.rb | 5 +- .../abstract/query_cache.rb | 6 + .../abstract/schema_definitions.rb | 221 +- .../abstract/schema_statements.rb | 187 +- .../connection_adapters/abstract_adapter.rb | 9 +- .../connection_adapters/mysql_adapter.rb | 78 +- .../connection_adapters/postgresql_adapter.rb | 185 +- .../connection_adapters/sqlite3_adapter.rb | 2 +- .../connection_adapters/sqlite_adapter.rb | 43 +- .../activerecord/lib/active_record/dirty.rb | 142 ++ .../lib/active_record/fixtures.rb | 270 +-- .../lib/active_record/locking/optimistic.rb | 11 +- .../lib/active_record/locking/pessimistic.rb | 4 +- .../lib/active_record/migration.rb | 235 +- .../lib/active_record/named_scope.rb | 139 ++ .../lib/active_record/observer.rb | 22 +- .../lib/active_record/reflection.rb | 48 +- .../activerecord/lib/active_record/schema.rb | 17 +- .../lib/active_record/schema_dumper.rb | 6 +- .../lib/active_record/serialization.rb | 10 +- .../serializers/json_serializer.rb | 65 +- .../serializers/xml_serializer.rb | 75 +- .../lib/active_record/test_case.rb | 36 + .../lib/active_record/timestamp.rb | 8 +- .../lib/active_record/transactions.rb | 10 +- .../lib/active_record/validations.rb | 436 ++-- .../activerecord/lib/active_record/version.rb | 2 +- .../test/aaa_create_tables_test.rb | 72 - .../rails/activerecord/test/abstract_unit.rb | 84 - .../test/active_schema_test_mysql.rb | 43 - vendor/rails/activerecord/test/all.sh | 8 - .../test/{fixtures => assets}/example.log | 0 .../test/{fixtures => assets}/flowers.jpg | Bin .../test/association_inheritance_reload.rb | 14 - .../activerecord/test/associations_test.rb | 2147 ----------------- .../test/cases/aaa_create_tables_test.rb | 24 + .../test/cases/active_schema_test_mysql.rb | 86 + .../cases/active_schema_test_postgresql.rb | 24 + .../test/{ => cases}/adapter_test.rb | 28 +- .../{ => cases}/adapter_test_sqlserver.rb | 190 +- .../test/{ => cases}/aggregations_test.rb | 40 +- .../test/{ => cases}/ar_schema_test.rb | 12 +- .../belongs_to_associations_test.rb | 380 +++ .../associations/callbacks_test.rb | 34 +- .../cascaded_eager_loading_test.rb | 35 +- .../eager_load_nested_include_test.rb | 83 + .../eager_singularization_test.rb | 10 +- .../{ => cases}/associations/eager_test.rb | 268 +- .../associations/extension_test.rb | 16 +- ...s_and_belongs_to_many_associations_test.rb | 682 ++++++ .../has_many_associations_test.rb | 860 +++++++ .../has_many_through_associations_test.rb | 189 ++ .../associations/has_one_associations_test.rb | 318 +++ .../has_one_through_associations_test.rb | 74 + .../inner_join_association_test.rb | 40 +- .../associations/join_model_test.rb | 220 +- .../test/cases/associations_test.rb | 250 ++ .../{ => cases}/attribute_methods_test.rb | 114 +- .../test/{ => cases}/base_test.rb | 595 +++-- .../test/{ => cases}/binary_test.rb | 10 +- .../test/{ => cases}/calculations_test.rb | 68 +- .../test/{ => cases}/callbacks_test.rb | 14 +- .../class_inheritable_attributes_test.rb | 6 +- .../test/{ => cases}/column_alias_test.rb | 6 +- .../{ => cases}/connection_test_firebird.rb | 4 +- .../test/{ => cases}/connection_test_mysql.rb | 4 +- .../{ => cases}/copy_table_test_sqlite.rb | 26 +- .../{ => cases}/datatype_test_postgresql.rb | 8 +- .../test/{ => cases}/date_time_test.rb | 10 +- .../test/{ => cases}/default_test_firebird.rb | 6 +- .../test/{ => cases}/defaults_test.rb | 12 +- .../{ => cases}/deprecated_finder_test.rb | 6 +- .../activerecord/test/cases/dirty_test.rb | 126 + .../test/cases/finder_respond_to_test.rb | 76 + .../test/{ => cases}/finder_test.rb | 291 ++- .../test/{ => cases}/fixtures_test.rb | 182 +- .../rails/activerecord/test/cases/helper.rb | 47 + .../test/{ => cases}/inheritance_test.rb | 34 +- .../test/cases/invalid_date_test.rb | 24 + .../{ => cases}/json_serialization_test.rb | 45 +- .../test/{ => cases}/lifecycle_test.rb | 29 +- .../test/{ => cases}/locking_test.rb | 27 +- .../test/{ => cases}/method_scoping_test.rb | 96 +- .../test/{ => cases}/migration_test.rb | 542 ++++- .../{ => cases}/migration_test_firebird.rb | 6 +- .../test/{ => cases}/mixin_test.rb | 13 +- .../test/{ => cases}/modules_test.rb | 17 +- .../test/{ => cases}/multiple_db_test.rb | 10 +- .../test/cases/named_scope_test.rb | 121 + .../activerecord/test/{ => cases}/pk_test.rb | 20 +- .../test/{ => cases}/query_cache_test.rb | 40 +- .../test/{ => cases}/readonly_test.rb | 22 +- .../test/{ => cases}/reflection_test.rb | 26 +- .../{ => cases}/reserved_word_test_mysql.rb | 9 +- .../schema_authorization_test_postgresql.rb | 10 +- .../test/cases/schema_dumper_test.rb | 138 ++ .../test/cases/schema_test_postgresql.rb | 102 + .../test/{ => cases}/serialization_test.rb | 14 +- .../test/{ => cases}/synonym_test_oracle.rb | 10 +- .../{ => cases}/table_name_test_sqlserver.rb | 6 +- .../{ => cases}/threaded_connections_test.rb | 14 +- .../test/{ => cases}/transactions_test.rb | 10 +- .../test/{ => cases}/unconnected_test.rb | 4 +- .../test/{ => cases}/validations_test.rb | 250 +- .../{ => cases}/xml_serialization_test.rb | 22 +- vendor/rails/activerecord/test/config.rb | 5 + .../test/connections/native_db2/connection.rb | 2 +- .../connections/native_firebird/connection.rb | 2 +- .../native_frontbase/connection.rb | 2 +- .../connections/native_mysql/connection.rb | 2 +- .../connections/native_openbase/connection.rb | 2 +- .../connections/native_oracle/connection.rb | 2 +- .../native_postgresql/connection.rb | 4 +- .../connections/native_sqlite/connection.rb | 4 +- .../connections/native_sqlite3/connection.rb | 4 +- .../native_sqlite3/in_memory_connection.rb | 6 +- .../connections/native_sybase/connection.rb | 2 +- .../activerecord/test/fixtures/.gitignore | 1 + .../test/fixtures/author_addresses.yml | 5 + .../activerecord/test/fixtures/authors.yml | 2 + .../bad_fixtures/attr_with_numeric_first_char | 1 - .../fixtures/bad_fixtures/attr_with_spaces | 1 - .../test/fixtures/bad_fixtures/blank_line | 3 - .../bad_fixtures/duplicate_attributes | 3 - .../test/fixtures/bad_fixtures/missing_value | 1 - .../activerecord/test/fixtures/clubs.yml | 6 + .../test/fixtures/db_definitions/db2.drop.sql | 33 - .../test/fixtures/db_definitions/db2.sql | 235 -- .../fixtures/db_definitions/db22.drop.sql | 2 - .../test/fixtures/db_definitions/db22.sql | 5 - .../fixtures/db_definitions/firebird.drop.sql | 65 - .../test/fixtures/db_definitions/firebird.sql | 310 --- .../db_definitions/firebird2.drop.sql | 2 - .../fixtures/db_definitions/firebird2.sql | 6 - .../db_definitions/frontbase.drop.sql | 33 - .../fixtures/db_definitions/frontbase.sql | 273 --- .../db_definitions/frontbase2.drop.sql | 1 - .../fixtures/db_definitions/frontbase2.sql | 4 - .../fixtures/db_definitions/openbase.drop.sql | 2 - .../test/fixtures/db_definitions/openbase.sql | 318 --- .../db_definitions/openbase2.drop.sql | 2 - .../fixtures/db_definitions/openbase2.sql | 7 - .../fixtures/db_definitions/oracle.drop.sql | 67 - .../test/fixtures/db_definitions/oracle.sql | 330 --- .../fixtures/db_definitions/oracle2.drop.sql | 2 - .../test/fixtures/db_definitions/oracle2.sql | 6 - .../db_definitions/postgresql.drop.sql | 44 - .../fixtures/db_definitions/postgresql.sql | 292 --- .../db_definitions/postgresql2.drop.sql | 2 - .../fixtures/db_definitions/postgresql2.sql | 4 - .../test/fixtures/db_definitions/schema.rb | 354 --- .../test/fixtures/db_definitions/schema2.rb | 11 - .../fixtures/db_definitions/sqlite.drop.sql | 33 - .../test/fixtures/db_definitions/sqlite.sql | 219 -- .../fixtures/db_definitions/sqlite2.drop.sql | 2 - .../test/fixtures/db_definitions/sqlite2.sql | 5 - .../fixtures/db_definitions/sybase.drop.sql | 35 - .../test/fixtures/db_definitions/sybase.sql | 222 -- .../fixtures/db_definitions/sybase2.drop.sql | 4 - .../test/fixtures/db_definitions/sybase2.sql | 5 - .../david_action_controller | 3 - .../developers_projects/david_active_record | 3 - .../developers_projects/jamis_active_record | 2 - .../rails/activerecord/test/fixtures/jobs.yml | 7 + .../activerecord/test/fixtures/members.yml | 4 + .../test/fixtures/memberships.yml | 20 + .../activerecord/test/fixtures/owners.yml | 7 + .../activerecord/test/fixtures/people.yml | 5 +- .../activerecord/test/fixtures/person.rb | 4 - .../rails/activerecord/test/fixtures/pets.yml | 14 + .../activerecord/test/fixtures/pirate.rb | 5 - .../activerecord/test/fixtures/posts.yml | 1 + .../test/fixtures/price_estimates.yml | 7 + .../activerecord/test/fixtures/readers.yml | 5 + .../activerecord/test/fixtures/references.yml | 17 + .../activerecord/test/fixtures/sponsors.yml | 9 + .../test/fixtures/subscribers.yml | 7 + .../test/fixtures/subscribers/first | 2 - .../test/fixtures/subscribers/second | 2 - .../test/fixtures/subscriptions.yml | 12 + .../activerecord/test/fixtures/taggings.yml | 5 +- .../activerecord/test/fixtures/topics.yml | 24 +- .../test/fixtures/warehouse-things.yml | 3 + .../decimal}/1_give_me_big_numbers.rb | 0 .../duplicate}/1_people_have_last_names.rb | 2 +- .../duplicate}/2_we_need_reminders.rb | 2 +- .../duplicate}/3_foo.rb | 0 .../duplicate}/3_innocent_jointable.rb | 0 .../duplicate_names/20080507052938_chunky.rb | 7 + .../duplicate_names/20080507053028_chunky.rb | 7 + .../pass_1}/3_innocent_jointable.rb | 0 .../pass_2}/1_people_have_last_names.rb | 2 +- .../pass_2/3_innocent_jointable.rb} | 0 .../pass_3}/1_people_have_last_names.rb | 2 +- .../interleaved/pass_3/2_i_raise_on_down.rb | 8 + .../pass_3/3_innocent_jointable.rb | 12 + .../missing}/1000_people_have_middle_names.rb | 2 +- .../missing/1_people_have_last_names.rb | 9 + .../missing}/3_we_need_reminders.rb | 2 +- .../missing/4_innocent_jointable.rb | 12 + .../valid/1_people_have_last_names.rb | 9 + .../valid}/2_we_need_reminders.rb | 2 +- .../migrations/valid/3_innocent_jointable.rb | 12 + .../test/{fixtures => models}/author.rb | 34 +- .../test/{fixtures => models}/auto_id.rb | 0 .../test/{fixtures => models}/binary.rb | 0 .../test/{fixtures => models}/book.rb | 0 .../{fixtures => models}/categorization.rb | 0 .../test/{fixtures => models}/category.rb | 13 +- .../test/{fixtures => models}/citation.rb | 0 vendor/rails/activerecord/test/models/club.rb | 7 + .../test/{fixtures => models}/column_name.rb | 0 .../test/{fixtures => models}/comment.rb | 8 +- .../test/{fixtures => models}/company.rb | 15 +- .../{fixtures => models}/company_in_module.rb | 8 +- .../test/{fixtures => models}/computer.rb | 1 - .../test/{fixtures => models}/contact.rb | 2 +- .../test/{fixtures => models}/course.rb | 0 .../test/{fixtures => models}/customer.rb | 16 +- .../test/{fixtures => models}/default.rb | 0 .../test/{fixtures => models}/developer.rb | 24 +- .../test/{fixtures => models}/edge.rb | 0 .../test/{fixtures => models}/entrant.rb | 0 vendor/rails/activerecord/test/models/guid.rb | 2 + .../test/{fixtures => models}/item.rb | 0 vendor/rails/activerecord/test/models/job.rb | 5 + .../test/{fixtures => models}/joke.rb | 0 .../test/{fixtures => models}/keyboard.rb | 0 .../test/{fixtures => models}/legacy_thing.rb | 0 .../test/{fixtures => models}/matey.rb | 0 .../rails/activerecord/test/models/member.rb | 9 + .../activerecord/test/models/membership.rb | 9 + .../test/{fixtures => models}/minimalistic.rb | 0 .../{fixtures => models}/mixed_case_monkey.rb | 0 .../test/{fixtures => models}/movie.rb | 0 .../test/{fixtures => models}/order.rb | 4 +- .../rails/activerecord/test/models/owner.rb | 4 + .../test/{fixtures => models}/parrot.rb | 0 .../rails/activerecord/test/models/person.rb | 10 + vendor/rails/activerecord/test/models/pet.rb | 4 + .../rails/activerecord/test/models/pirate.rb | 7 + .../test/{fixtures => models}/post.rb | 25 +- .../test/models/price_estimate.rb | 3 + .../test/{fixtures => models}/project.rb | 1 + .../test/{fixtures => models}/reader.rb | 0 .../activerecord/test/models/reference.rb | 4 + .../test/{fixtures => models}/reply.rb | 12 +- .../test/{fixtures => models}/ship.rb | 0 .../rails/activerecord/test/models/sponsor.rb | 4 + .../test/{fixtures => models}/subject.rb | 0 .../test/{fixtures => models}/subscriber.rb | 2 + .../activerecord/test/models/subscription.rb | 4 + .../test/{fixtures => models}/tag.rb | 0 .../test/{fixtures => models}/tagging.rb | 0 .../test/{fixtures => models}/task.rb | 0 .../test/{fixtures => models}/topic.rb | 36 +- .../test/{fixtures => models}/treasure.rb | 2 + .../test/{fixtures => models}/vertex.rb | 0 .../test/models/warehouse_thing.rb | 5 + .../test/schema/mysql_specific_schema.rb | 12 + .../test/schema/postgresql_specific_schema.rb | 103 + .../rails/activerecord/test/schema/schema.rb | 421 ++++ .../rails/activerecord/test/schema/schema2.rb | 6 + .../test/schema/sqlite_specific_schema.rb | 25 + .../test/schema/sqlserver_specific_schema.rb | 5 + .../activerecord/test/schema_dumper_test.rb | 131 - .../test/schema_test_postgresql.rb | 64 - vendor/rails/activeresource/CHANGELOG | 23 + vendor/rails/activeresource/Rakefile | 6 +- .../activeresource/lib/active_resource.rb | 2 +- .../lib/active_resource/base.rb | 432 ++-- .../lib/active_resource/connection.rb | 47 +- .../lib/active_resource/custom_methods.rb | 102 +- .../lib/active_resource/http_mock.rb | 17 +- .../lib/active_resource/version.rb | 2 +- .../activeresource/test/abstract_unit.rb | 14 +- .../activeresource/test/authorization_test.rb | 50 +- .../test/base/custom_methods_test.rb | 9 +- .../activeresource/test/base/equality_test.rb | 2 +- .../activeresource/test/base/load_test.rb | 37 +- .../activeresource/test/base_errors_test.rb | 2 +- vendor/rails/activeresource/test/base_test.rb | 391 ++- .../activeresource/test/connection_test.rb | 24 +- .../rails/activeresource/test/format_test.rb | 45 +- .../rails/activeresource/test/setter_trap.rb | 2 +- vendor/rails/activesupport/CHANGELOG | 191 +- vendor/rails/activesupport/MIT-LICENSE | 2 +- vendor/rails/activesupport/Rakefile | 94 +- .../rails/activesupport/lib/active_support.rb | 7 +- .../lib/active_support/base64.rb | 22 + .../lib/active_support/basic_object.rb | 27 +- .../lib/active_support/buffered_logger.rb | 20 +- .../activesupport/lib/active_support/cache.rb | 141 ++ .../cache/compressed_mem_cache_store.rb | 15 + .../lib/active_support/cache/drb_store.rb | 15 + .../lib/active_support/cache/file_store.rb | 65 + .../active_support/cache/mem_cache_store.rb | 94 + .../lib/active_support/cache/memory_store.rb | 33 + .../lib/active_support/callbacks.rb | 275 +++ .../active_support/core_ext/array/access.rb | 6 +- .../core_ext/array/conversions.rb | 94 +- .../core_ext/array/extract_options.rb | 3 +- .../active_support/core_ext/array/grouping.rb | 11 +- .../core_ext/array/random_access.rb | 2 +- .../lib/active_support/core_ext/base64.rb | 4 + .../core_ext/base64/encoding.rb | 13 + .../lib/active_support/core_ext/benchmark.rb | 12 + .../lib/active_support/core_ext/bigdecimal.rb | 4 + .../core_ext/bigdecimal/conversions.rb | 43 +- .../lib/active_support/core_ext/blank.rb | 7 +- .../core_ext/class/attribute_accessors.rb | 8 +- .../core_ext/class/delegating_attributes.rb | 8 +- .../active_support/core_ext/class/removal.rb | 26 + .../core_ext/date/calculations.rb | 29 +- .../core_ext/date/conversions.rb | 17 +- .../lib/active_support/core_ext/date_time.rb | 2 + .../core_ext/date_time/calculations.rb | 39 +- .../core_ext/date_time/conversions.rb | 60 +- .../lib/active_support/core_ext/enumerable.rb | 32 +- .../lib/active_support/core_ext/exception.rb | 8 + .../lib/active_support/core_ext/file.rb | 12 +- .../core_ext/hash/conversions.rb | 35 +- .../core_ext/hash/indifferent_access.rb | 35 + .../lib/active_support/core_ext/hash/keys.rb | 14 +- .../core_ext/hash/reverse_merge.rb | 5 +- .../core_ext/integer/even_odd.rb | 11 +- .../core_ext/integer/inflections.rb | 1 - .../core_ext/kernel/daemonizing.rb | 12 +- .../core_ext/kernel/reporting.rb | 8 + .../core_ext/module/attr_internal.rb | 3 +- .../core_ext/module/attribute_accessors.rb | 12 +- .../core_ext/module/delegation.rb | 8 +- .../core_ext/module/inclusion.rb | 19 + .../core_ext/module/introspection.rb | 72 +- .../active_support/core_ext/module/loading.rb | 10 + .../lib/active_support/core_ext/numeric.rb | 4 +- .../core_ext/numeric/conversions.rb | 19 + .../core_ext/object/instance_variables.rb | 52 + .../lib/active_support/core_ext/process.rb | 1 + .../active_support/core_ext/process/daemon.rb | 25 + .../core_ext/range/blockless_step.rb | 22 +- .../core_ext/range/conversions.rb | 7 +- .../core_ext/range/include_range.rb | 8 + .../active_support/core_ext/range/overlaps.rb | 3 + .../lib/active_support/core_ext/string.rb | 15 +- .../active_support/core_ext/string/access.rb | 120 +- .../core_ext/string/conversions.rb | 8 +- .../active_support/core_ext/string/filters.rb | 26 + .../core_ext/string/inflections.rb | 121 +- .../core_ext/string/iterators.rb | 4 + .../core_ext/string/starts_ends_with.rb | 16 +- .../active_support/core_ext/string/unicode.rb | 92 +- .../lib/active_support/core_ext/symbol.rb | 2 +- .../core_ext/test/unit/assertions.rb | 8 +- .../lib/active_support/core_ext/time.rb | 2 + .../core_ext/time/calculations.rb | 98 +- .../core_ext/time/conversions.rb | 71 +- .../lib/active_support/core_ext/time/zones.rb | 75 + .../lib/active_support/dependencies.rb | 155 +- .../lib/active_support/deprecation.rb | 14 + .../lib/active_support/duration.rb | 8 +- .../activesupport/lib/active_support/gzip.rb | 25 + .../lib/active_support/inflector.rb | 45 +- .../activesupport/lib/active_support/json.rb | 42 +- .../lib/active_support/json/decoding.rb | 13 +- .../lib/active_support/json/encoders/date.rb | 13 +- .../active_support/json/encoders/date_time.rb | 13 +- .../json/encoders/enumerable.rb | 4 +- .../lib/active_support/json/encoders/hash.rb | 9 +- .../active_support/json/encoders/object.rb | 2 +- .../active_support/json/encoders/string.rb | 10 +- .../lib/active_support/json/encoders/time.rb | 13 +- .../lib/active_support/json/encoding.rb | 1 - .../lib/active_support/multibyte/chars.rb | 10 +- .../multibyte/handlers/utf8_handler.rb | 4 +- .../lib/active_support/ordered_options.rb | 12 + .../lib/active_support/test_case.rb | 12 +- .../lib/active_support/testing.rb | 1 - .../lib/active_support/testing/default.rb | 9 +- .../testing/setup_and_teardown.rb | 85 + .../lib/active_support/time_with_zone.rb | 256 ++ .../lib/active_support/values/time_zone.rb | 433 +++- .../lib/active_support/vendor.rb | 12 + .../vendor/memcache-client-1.5.0/memcache.rb | 849 +++++++ .../vendor/tzinfo-0.3.8/tzinfo.rb | 33 + .../tzinfo-0.3.8/tzinfo/data_timezone.rb | 47 + .../tzinfo-0.3.8/tzinfo/data_timezone_info.rb | 226 ++ .../tzinfo/definitions/Africa/Algiers.rb | 55 + .../tzinfo/definitions/Africa/Cairo.rb | 219 ++ .../tzinfo/definitions/Africa/Casablanca.rb | 38 + .../tzinfo/definitions/Africa/Harare.rb | 18 + .../tzinfo/definitions/Africa/Johannesburg.rb | 25 + .../tzinfo/definitions/Africa/Monrovia.rb | 22 + .../tzinfo/definitions/Africa/Nairobi.rb | 23 + .../America/Argentina/Buenos_Aires.rb | 166 ++ .../definitions/America/Argentina/San_Juan.rb | 170 ++ .../tzinfo/definitions/America/Bogota.rb | 23 + .../tzinfo/definitions/America/Caracas.rb | 23 + .../tzinfo/definitions/America/Chicago.rb | 283 +++ .../tzinfo/definitions/America/Chihuahua.rb | 136 ++ .../tzinfo/definitions/America/Denver.rb | 204 ++ .../tzinfo/definitions/America/Godthab.rb | 161 ++ .../tzinfo/definitions/America/Guatemala.rb | 27 + .../tzinfo/definitions/America/Halifax.rb | 274 +++ .../America/Indiana/Indianapolis.rb | 149 ++ .../tzinfo/definitions/America/Juneau.rb | 194 ++ .../tzinfo/definitions/America/La_Paz.rb | 22 + .../tzinfo/definitions/America/Lima.rb | 35 + .../tzinfo/definitions/America/Los_Angeles.rb | 232 ++ .../tzinfo/definitions/America/Mazatlan.rb | 139 ++ .../tzinfo/definitions/America/Mexico_City.rb | 144 ++ .../tzinfo/definitions/America/Monterrey.rb | 131 + .../tzinfo/definitions/America/New_York.rb | 282 +++ .../tzinfo/definitions/America/Phoenix.rb | 30 + .../tzinfo/definitions/America/Regina.rb | 74 + .../tzinfo/definitions/America/Santiago.rb | 205 ++ .../tzinfo/definitions/America/St_Johns.rb | 288 +++ .../tzinfo/definitions/America/Tijuana.rb | 196 ++ .../tzinfo/definitions/Asia/Almaty.rb | 67 + .../tzinfo/definitions/Asia/Baghdad.rb | 73 + .../tzinfo/definitions/Asia/Baku.rb | 161 ++ .../tzinfo/definitions/Asia/Bangkok.rb | 20 + .../tzinfo/definitions/Asia/Chongqing.rb | 33 + .../tzinfo/definitions/Asia/Dhaka.rb | 27 + .../tzinfo/definitions/Asia/Hong_Kong.rb | 87 + .../tzinfo/definitions/Asia/Irkutsk.rb | 165 ++ .../tzinfo/definitions/Asia/Jakarta.rb | 30 + .../tzinfo/definitions/Asia/Jerusalem.rb | 163 ++ .../tzinfo/definitions/Asia/Kabul.rb | 20 + .../tzinfo/definitions/Asia/Kamchatka.rb | 163 ++ .../tzinfo/definitions/Asia/Karachi.rb | 28 + .../tzinfo/definitions/Asia/Katmandu.rb | 20 + .../tzinfo/definitions/Asia/Kolkata.rb | 25 + .../tzinfo/definitions/Asia/Krasnoyarsk.rb | 163 ++ .../tzinfo/definitions/Asia/Kuala_Lumpur.rb | 31 + .../tzinfo/definitions/Asia/Kuwait.rb | 18 + .../tzinfo/definitions/Asia/Magadan.rb | 163 ++ .../tzinfo/definitions/Asia/Muscat.rb | 18 + .../tzinfo/definitions/Asia/Novosibirsk.rb | 164 ++ .../tzinfo/definitions/Asia/Rangoon.rb | 24 + .../tzinfo/definitions/Asia/Riyadh.rb | 18 + .../tzinfo/definitions/Asia/Seoul.rb | 34 + .../tzinfo/definitions/Asia/Shanghai.rb | 35 + .../tzinfo/definitions/Asia/Singapore.rb | 33 + .../tzinfo/definitions/Asia/Taipei.rb | 59 + .../tzinfo/definitions/Asia/Tashkent.rb | 47 + .../tzinfo/definitions/Asia/Tbilisi.rb | 78 + .../tzinfo/definitions/Asia/Tehran.rb | 121 + .../tzinfo/definitions/Asia/Tokyo.rb | 30 + .../tzinfo/definitions/Asia/Ulaanbaatar.rb | 65 + .../tzinfo/definitions/Asia/Urumqi.rb | 33 + .../tzinfo/definitions/Asia/Vladivostok.rb | 164 ++ .../tzinfo/definitions/Asia/Yakutsk.rb | 163 ++ .../tzinfo/definitions/Asia/Yekaterinburg.rb | 165 ++ .../tzinfo/definitions/Asia/Yerevan.rb | 165 ++ .../tzinfo/definitions/Atlantic/Azores.rb | 270 +++ .../tzinfo/definitions/Atlantic/Cape_Verde.rb | 23 + .../definitions/Atlantic/South_Georgia.rb | 18 + .../tzinfo/definitions/Australia/Adelaide.rb | 187 ++ .../tzinfo/definitions/Australia/Brisbane.rb | 35 + .../tzinfo/definitions/Australia/Darwin.rb | 29 + .../tzinfo/definitions/Australia/Hobart.rb | 193 ++ .../tzinfo/definitions/Australia/Melbourne.rb | 185 ++ .../tzinfo/definitions/Australia/Perth.rb | 37 + .../tzinfo/definitions/Australia/Sydney.rb | 185 ++ .../tzinfo/definitions/Etc/UTC.rb | 16 + .../tzinfo/definitions/Europe/Amsterdam.rb | 228 ++ .../tzinfo/definitions/Europe/Athens.rb | 185 ++ .../tzinfo/definitions/Europe/Belgrade.rb | 163 ++ .../tzinfo/definitions/Europe/Berlin.rb | 188 ++ .../tzinfo/definitions/Europe/Bratislava.rb | 13 + .../tzinfo/definitions/Europe/Brussels.rb | 232 ++ .../tzinfo/definitions/Europe/Bucharest.rb | 181 ++ .../tzinfo/definitions/Europe/Budapest.rb | 197 ++ .../tzinfo/definitions/Europe/Copenhagen.rb | 179 ++ .../tzinfo/definitions/Europe/Dublin.rb | 276 +++ .../tzinfo/definitions/Europe/Helsinki.rb | 163 ++ .../tzinfo/definitions/Europe/Istanbul.rb | 218 ++ .../tzinfo/definitions/Europe/Kiev.rb | 168 ++ .../tzinfo/definitions/Europe/Lisbon.rb | 268 ++ .../tzinfo/definitions/Europe/Ljubljana.rb | 13 + .../tzinfo/definitions/Europe/London.rb | 288 +++ .../tzinfo/definitions/Europe/Madrid.rb | 211 ++ .../tzinfo/definitions/Europe/Minsk.rb | 170 ++ .../tzinfo/definitions/Europe/Moscow.rb | 181 ++ .../tzinfo/definitions/Europe/Paris.rb | 232 ++ .../tzinfo/definitions/Europe/Prague.rb | 187 ++ .../tzinfo/definitions/Europe/Riga.rb | 176 ++ .../tzinfo/definitions/Europe/Rome.rb | 215 ++ .../tzinfo/definitions/Europe/Sarajevo.rb | 13 + .../tzinfo/definitions/Europe/Skopje.rb | 13 + .../tzinfo/definitions/Europe/Sofia.rb | 173 ++ .../tzinfo/definitions/Europe/Stockholm.rb | 165 ++ .../tzinfo/definitions/Europe/Tallinn.rb | 172 ++ .../tzinfo/definitions/Europe/Vienna.rb | 183 ++ .../tzinfo/definitions/Europe/Vilnius.rb | 170 ++ .../tzinfo/definitions/Europe/Warsaw.rb | 212 ++ .../tzinfo/definitions/Europe/Zagreb.rb | 13 + .../tzinfo/definitions/Pacific/Auckland.rb | 202 ++ .../tzinfo/definitions/Pacific/Fiji.rb | 23 + .../tzinfo/definitions/Pacific/Guam.rb | 22 + .../tzinfo/definitions/Pacific/Honolulu.rb | 28 + .../tzinfo/definitions/Pacific/Majuro.rb | 20 + .../tzinfo/definitions/Pacific/Midway.rb | 25 + .../tzinfo/definitions/Pacific/Noumea.rb | 25 + .../tzinfo/definitions/Pacific/Pago_Pago.rb | 26 + .../definitions/Pacific/Port_Moresby.rb | 20 + .../tzinfo/definitions/Pacific/Tongatapu.rb | 27 + .../tzinfo-0.3.8/tzinfo/info_timezone.rb | 52 + .../tzinfo-0.3.8/tzinfo/linked_timezone.rb | 51 + .../tzinfo/linked_timezone_info.rb | 44 + .../tzinfo-0.3.8/tzinfo/offset_rationals.rb | 95 + .../tzinfo-0.3.8/tzinfo/time_or_datetime.rb | 292 +++ .../vendor/tzinfo-0.3.8/tzinfo/timezone.rb | 508 ++++ .../tzinfo/timezone_definition.rb | 56 + .../tzinfo-0.3.8/tzinfo/timezone_info.rb | 40 + .../tzinfo/timezone_offset_info.rb | 94 + .../tzinfo-0.3.8/tzinfo/timezone_period.rb | 198 ++ .../tzinfo/timezone_transition_info.rb | 138 ++ .../lib/active_support/version.rb | 2 +- .../lib/active_support/whiny_nil.rb | 40 +- .../rails/activesupport/test/abstract_unit.rb | 18 +- .../test/buffered_logger_test.rb | 13 +- .../rails/activesupport/test/caching_test.rb | 66 + .../activesupport/test/callbacks_test.rb | 148 ++ .../activesupport/test/clean_logger_test.rb | 2 +- .../test/core_ext/array_ext_test.rb | 2 +- .../test/core_ext/base64_ext_test.rb | 8 + .../activesupport/test/core_ext/bigdecimal.rb | 9 + .../activesupport/test/core_ext/blank_test.rb | 2 +- .../test/core_ext/cgi_ext_test.rb | 2 +- .../core_ext/class/attribute_accessor_test.rb | 4 +- .../class_inheritable_attributes_test.rb | 2 +- .../class/delegating_attributes_test.rb | 22 +- .../activesupport/test/core_ext/class_test.rb | 2 +- .../test/core_ext/date_ext_test.rb | 52 +- .../test/core_ext/date_time_ext_test.rb | 68 +- .../test/core_ext/duplicable_test.rb | 2 +- .../test/core_ext/duration_test.rb | 55 +- .../test/core_ext/enumerable_test.rb | 11 +- .../test/core_ext/exception_test.rb | 6 +- .../activesupport/test/core_ext/file_test.rb | 2 +- .../test/core_ext/float_ext_test.rb | 2 +- .../test/core_ext/hash_ext_test.rb | 48 +- .../test/core_ext/integer_ext_test.rb | 2 +- .../test/core_ext/kernel_test.rb | 2 +- ...load_error_tests.rb => load_error_test.rb} | 2 +- .../module/attr_accessor_with_default_test.rb | 4 +- .../core_ext/module/attr_internal_test.rb | 2 +- .../module/attribute_accessor_test.rb | 2 +- .../module/attribute_aliasing_test.rb | 2 +- .../test/core_ext/module_test.rb | 2 +- .../test/core_ext/name_error_test.rb | 2 +- .../test/core_ext/numeric_ext_test.rb | 21 +- .../core_ext/object_and_class_ext_test.rb | 6 +- .../test/core_ext/pathname_test.rb | 2 +- .../activesupport/test/core_ext/proc_test.rb | 2 +- .../test/core_ext/range_ext_test.rb | 2 +- .../test/core_ext/string_ext_test.rb | 37 +- .../test/core_ext/symbol_test.rb | 2 +- .../test/core_ext/time_ext_test.rb | 258 +- .../test/core_ext/time_with_zone_test.rb | 669 +++++ .../activesupport/test/dependencies_test.rb | 12 +- .../activesupport/test/deprecation_test.rb | 12 +- .../activesupport/test/inflector_test.rb | 12 +- .../test/inflector_test_cases.rb | 5 +- .../activesupport/test/json/decoding_test.rb | 2 +- .../activesupport/test/json/encoding_test.rb | 21 +- .../test/multibyte_chars_test.rb | 25 +- .../test/multibyte_conformance.rb | 9 +- .../test/multibyte_handler_test.rb | 7 +- .../activesupport/test/option_merger_test.rb | 2 +- .../test/ordered_options_test.rb | 15 +- vendor/rails/activesupport/test/test_test.rb | 49 +- .../activesupport/test/time_zone_test.rb | 312 ++- .../activesupport/test/whiny_nil_test.rb | 2 +- vendor/rails/railties/CHANGELOG | 128 + vendor/rails/railties/MIT-LICENSE | 2 +- vendor/rails/railties/README | 65 +- vendor/rails/railties/Rakefile | 26 +- vendor/rails/railties/bin/dbconsole | 3 + .../railties/builtin/rails_info/rails/info.rb | 42 +- .../initializers/new_rails_defaults.rb | 15 + vendor/rails/railties/configs/routes.rb | 6 + vendor/rails/railties/dispatches/gateway.cgi | 4 +- vendor/rails/railties/environments/boot.rb | 4 +- .../railties/environments/development.rb | 1 - .../railties/environments/environment.rb | 18 +- .../rails/railties/environments/production.rb | 3 + vendor/rails/railties/helpers/application.rb | 5 + vendor/rails/railties/html/images/rails.png | Bin 1787 -> 6646 bytes vendor/rails/railties/html/index.html | 15 +- .../railties/html/javascripts/controls.js | 2 +- .../railties/html/javascripts/dragdrop.js | 2 +- .../railties/html/javascripts/effects.js | 2 +- vendor/rails/railties/lib/commands/console.rb | 6 +- .../rails/railties/lib/commands/dbconsole.rb | 56 + .../lib/commands/performance/profiler.rb | 2 +- vendor/rails/railties/lib/commands/plugin.rb | 29 +- vendor/rails/railties/lib/commands/server.rb | 4 +- .../railties/lib/commands/servers/mongrel.rb | 16 +- .../lib/commands/servers/new_mongrel.rb | 16 + vendor/rails/railties/lib/console_app.rb | 4 +- vendor/rails/railties/lib/dispatcher.rb | 2 +- vendor/rails/railties/lib/fcgi_handler.rb | 46 +- vendor/rails/railties/lib/initializer.rb | 285 ++- .../rails/railties/lib/rails/gem_builder.rb | 21 + .../railties/lib/rails/gem_dependency.rb | 117 + .../lib/rails/mongrel_server/commands.rb | 342 +++ .../lib/rails/mongrel_server/handler.rb | 55 + vendor/rails/railties/lib/rails/plugin.rb | 58 +- .../rails/railties/lib/rails/plugin/loader.rb | 4 +- .../railties/lib/rails/plugin/locator.rb | 22 +- vendor/rails/railties/lib/rails/version.rb | 2 +- .../railties/lib/rails_generator/commands.rb | 89 +- .../applications/app/app_generator.rb | 19 +- .../controller/templates/controller.rb | 5 +- .../controller/templates/functional_test.rb | 2 +- .../templates/integration_test.rb | 2 +- .../components/mailer/mailer_generator.rb | 8 +- .../components/mailer/templates/mailer.rb | 14 +- .../components/mailer/templates/unit_test.rb | 2 +- .../components/model/templates/unit_test.rb | 2 +- .../observer/templates/unit_test.rb | 2 +- .../resource/templates/functional_test.rb | 2 +- .../components/scaffold/scaffold_generator.rb | 4 +- .../scaffold/templates/functional_test.rb | 2 +- .../components/scaffold/templates/style.css | 20 - .../scaffold/templates/view_edit.html.erb | 7 +- .../scaffold/templates/view_new.html.erb | 7 +- .../railties/lib/rails_generator/lookup.rb | 10 +- .../railties/lib/rails_generator/options.rb | 7 + .../railties/lib/rails_generator/scripts.rb | 13 +- .../rails_generator/secret_key_generator.rb | 20 +- .../rails/railties/lib/tasks/databases.rake | 102 +- .../railties/lib/tasks/documentation.rake | 4 +- .../rails/railties/lib/tasks/framework.rake | 48 +- vendor/rails/railties/lib/tasks/gems.rake | 58 + vendor/rails/railties/lib/tasks/misc.rake | 47 + vendor/rails/railties/lib/tasks/testing.rake | 6 +- vendor/rails/railties/lib/test_help.rb | 8 + vendor/rails/railties/lib/webrick_server.rb | 7 +- vendor/rails/railties/pkg/rails-2.0.2.gem | Bin 183808 -> 0 bytes vendor/rails/railties/test/boot_test.rb | 4 +- .../rails/railties/test/console_app_test.rb | 23 +- .../railties/test/fcgi_dispatcher_test.rb | 50 +- .../about_yml_plugins/bad_about_yml/about.yml | 1 + .../about_yml_plugins/bad_about_yml/init.rb | 1 + .../plugin_without_about_yml/init.rb | 1 + .../missing_class/templates/.gitignore} | 0 .../missing_generator/templates/.gitignore} | 0 .../generators/missing_templates/.gitignore} | 0 .../a/generators/a_generator/a_generator.rb | 4 + .../plugins/alternate/a/lib/.gitignore} | 0 .../acts/acts_as_chunky_bacon/lib/.gitignore} | 0 .../plugins/default/empty/.gitignore} | 0 .../fixtures/plugins/default/stubby/about.yml | 2 + .../stubby_generator/stubby_generator.rb | 4 + .../railties/test/gem_dependency_test.rb | 66 + .../railties/test/generator_lookup_test.rb | 40 + .../test/generators/generator_test_helper.rb | 178 +- .../generators/rails_mailer_generator_test.rb | 29 + .../generators/rails_model_generator_test.rb | 85 +- .../rails_resource_generator_test.rb | 85 +- .../rails_scaffold_generator_test.rb | 92 +- .../rails/railties/test/initializer_test.rb | 9 +- .../rails/railties/test/plugin_loader_test.rb | 94 +- .../railties/test/plugin_locator_test.rb | 8 +- vendor/rails/railties/test/plugin_test.rb | 22 +- .../railties/test/rails_generator_test.rb | 24 +- .../test/rails_info_controller_test.rb | 2 +- vendor/rails/railties/test/rails_info_test.rb | 70 +- .../test/secret_key_generation_test.rb | 9 + 971 files changed, 46318 insertions(+), 17450 deletions(-) delete mode 100644 vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/Makefile delete mode 100755 vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/address.rb delete mode 100755 vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/facade.rb delete mode 100755 vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/info.rb delete mode 100644 vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/interface.rb delete mode 100644 vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/parser.y delete mode 100755 vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/tmail.rb rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail.rb (83%) mode change 100755 => 100644 create mode 100644 vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/address.rb rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/attachments.rb (86%) rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/base64.rb (97%) mode change 100755 => 100644 rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/compat.rb (70%) rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/config.rb (97%) mode change 100755 => 100644 rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/core_extensions.rb (65%) rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/encode.rb (66%) mode change 100755 => 100644 rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/header.rb (89%) mode change 100755 => 100644 create mode 100644 vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/index.rb create mode 100644 vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/interface.rb rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/loader.rb (52%) mode change 100755 => 100644 rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/mail.rb (68%) mode change 100755 => 100644 rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/mailbox.rb (80%) mode change 100755 => 100644 create mode 100644 vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/main.rb rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/mbox.rb (52%) mode change 100755 => 100644 rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/net.rb (86%) mode change 100755 => 100644 rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/obsolete.rb (94%) mode change 100755 => 100644 rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/parser.rb (99%) mode change 100755 => 100644 rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/port.rb (100%) mode change 100755 => 100644 rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/quoting.rb (82%) create mode 100644 vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/require_arch.rb rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/scanner.rb (72%) mode change 100755 => 100644 rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/scanner_r.rb (91%) mode change 100755 => 100644 rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/stringio.rb (99%) mode change 100755 => 100644 rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/utils.rb (60%) mode change 100755 => 100644 rename vendor/rails/actionmailer/lib/action_mailer/vendor/{tmail-1.1.0 => tmail-1.2.2}/tmail/version.rb (94%) delete mode 100644 vendor/rails/actionmailer/test/fixtures/path.with.dots/multipart_with_template_path_with_dots.rhtml delete mode 100644 vendor/rails/actionmailer/test/fixtures/raw_base64_decoded_string delete mode 100644 vendor/rails/actionmailer/test/fixtures/raw_base64_encoded_string delete mode 100644 vendor/rails/actionmailer/test/fixtures/second_mailer/share.rhtml delete mode 100644 vendor/rails/actionmailer/test/fixtures/templates/signed_up.rhtml delete mode 100644 vendor/rails/actionmailer/test/fixtures/test_mailer/implicitly_multipart_example.ignored.rhtml delete mode 100644 vendor/rails/actionmailer/test/fixtures/test_mailer/implicitly_multipart_example.text.html.rhtml delete mode 100644 vendor/rails/actionmailer/test/fixtures/test_mailer/implicitly_multipart_example.text.plain.rhtml delete mode 100644 vendor/rails/actionmailer/test/fixtures/test_mailer/implicitly_multipart_example.text.yaml.rhtml delete mode 100644 vendor/rails/actionmailer/test/fixtures/test_mailer/signed_up.rhtml delete mode 100644 vendor/rails/actionmailer/test/fixtures/test_mailer/signed_up_with_url.rhtml create mode 100644 vendor/rails/actionpack/lib/action_controller/caching/actions.rb create mode 100644 vendor/rails/actionpack/lib/action_controller/caching/fragments.rb create mode 100644 vendor/rails/actionpack/lib/action_controller/caching/pages.rb create mode 100644 vendor/rails/actionpack/lib/action_controller/caching/sql_cache.rb create mode 100644 vendor/rails/actionpack/lib/action_controller/caching/sweeping.rb create mode 100644 vendor/rails/actionpack/lib/action_controller/headers.rb create mode 100644 vendor/rails/actionpack/lib/action_controller/routing/builder.rb rename vendor/rails/actionpack/lib/action_controller/{routing_optimisation.rb => routing/optimisations.rb} (73%) create mode 100644 vendor/rails/actionpack/lib/action_controller/routing/recognition_optimisation.rb create mode 100644 vendor/rails/actionpack/lib/action_controller/routing/route.rb create mode 100644 vendor/rails/actionpack/lib/action_controller/routing/route_set.rb create mode 100644 vendor/rails/actionpack/lib/action_controller/routing/routing_ext.rb create mode 100644 vendor/rails/actionpack/lib/action_controller/routing/segments.rb create mode 100644 vendor/rails/actionpack/lib/action_view/inline_template.rb create mode 100644 vendor/rails/actionpack/lib/action_view/partial_template.rb create mode 100644 vendor/rails/actionpack/lib/action_view/template.rb create mode 100644 vendor/rails/actionpack/lib/action_view/template_finder.rb create mode 100644 vendor/rails/actionpack/lib/action_view/template_handlers/compilable.rb create mode 100644 vendor/rails/actionpack/lib/action_view/test_case.rb delete mode 100644 vendor/rails/actionpack/test/action_view_test.rb create mode 100644 vendor/rails/actionpack/test/adv_attr_test.rb delete mode 100644 vendor/rails/actionpack/test/controller/fragment_store_setting_test.rb create mode 100644 vendor/rails/actionpack/test/controller/header_test.rb create mode 100644 vendor/rails/actionpack/test/controller/integration_upload_test.rb create mode 100644 vendor/rails/actionpack/test/fixtures/bad_customers/_bad_customer.html.erb create mode 100644 vendor/rails/actionpack/test/fixtures/customers/_customer.html.erb create mode 100644 vendor/rails/actionpack/test/fixtures/functional_caching/_partial.erb create mode 100644 vendor/rails/actionpack/test/fixtures/functional_caching/fragment_cached.html.erb create mode 100644 vendor/rails/actionpack/test/fixtures/functional_caching/html_fragment_cached_with_partial.html.erb create mode 100644 vendor/rails/actionpack/test/fixtures/functional_caching/js_fragment_cached_with_partial.js.rjs create mode 100644 vendor/rails/actionpack/test/fixtures/good_customers/_good_customer.html.erb create mode 120000 vendor/rails/actionpack/test/fixtures/layout_tests/layouts/symlinked create mode 100644 vendor/rails/actionpack/test/fixtures/layouts/block_with_layout.erb create mode 100644 vendor/rails/actionpack/test/fixtures/layouts/partial_with_layout.erb create mode 100644 vendor/rails/actionpack/test/fixtures/mascot.rb create mode 100644 vendor/rails/actionpack/test/fixtures/mascots.yml create mode 100644 vendor/rails/actionpack/test/fixtures/mascots/_mascot.html.erb create mode 100644 vendor/rails/actionpack/test/fixtures/multipart/boundary_problem_file create mode 100644 vendor/rails/actionpack/test/fixtures/public/javascripts/controls.js create mode 100644 vendor/rails/actionpack/test/fixtures/public/javascripts/dragdrop.js create mode 100644 vendor/rails/actionpack/test/fixtures/public/javascripts/effects.js create mode 100644 vendor/rails/actionpack/test/fixtures/public/javascripts/prototype.js create mode 100644 vendor/rails/actionpack/test/fixtures/public/javascripts/version.1.0.js create mode 100644 vendor/rails/actionpack/test/fixtures/public/stylesheets/version.1.0.css create mode 100644 vendor/rails/actionpack/test/fixtures/shared.html.erb create mode 100644 vendor/rails/actionpack/test/fixtures/symlink_parent/symlinked_layout.erb create mode 100644 vendor/rails/actionpack/test/fixtures/test/_customer_counter.erb create mode 100644 vendor/rails/actionpack/test/fixtures/test/_form.erb create mode 100644 vendor/rails/actionpack/test/fixtures/test/_labelling_form.erb create mode 100644 vendor/rails/actionpack/test/fixtures/test/_raise.html.erb create mode 100644 vendor/rails/actionpack/test/fixtures/test/greeting.js.rjs create mode 100644 vendor/rails/actionpack/test/fixtures/topics/_topic.html.erb create mode 100644 vendor/rails/actionpack/test/template/record_tag_helper_test.rb create mode 100644 vendor/rails/actionpack/test/template/template_finder_test.rb create mode 100644 vendor/rails/actionpack/test/template/template_object_test.rb create mode 100644 vendor/rails/actionpack/test/template/test_test.rb create mode 100644 vendor/rails/activerecord/lib/active_record/association_preload.rb mode change 100755 => 100644 vendor/rails/activerecord/lib/active_record/associations.rb create mode 100644 vendor/rails/activerecord/lib/active_record/associations/has_one_through_association.rb create mode 100644 vendor/rails/activerecord/lib/active_record/dirty.rb create mode 100644 vendor/rails/activerecord/lib/active_record/named_scope.rb create mode 100644 vendor/rails/activerecord/lib/active_record/test_case.rb delete mode 100644 vendor/rails/activerecord/test/aaa_create_tables_test.rb delete mode 100755 vendor/rails/activerecord/test/abstract_unit.rb delete mode 100644 vendor/rails/activerecord/test/active_schema_test_mysql.rb delete mode 100755 vendor/rails/activerecord/test/all.sh rename vendor/rails/activerecord/test/{fixtures => assets}/example.log (100%) rename vendor/rails/activerecord/test/{fixtures => assets}/flowers.jpg (100%) delete mode 100644 vendor/rails/activerecord/test/association_inheritance_reload.rb delete mode 100755 vendor/rails/activerecord/test/associations_test.rb create mode 100644 vendor/rails/activerecord/test/cases/aaa_create_tables_test.rb create mode 100644 vendor/rails/activerecord/test/cases/active_schema_test_mysql.rb create mode 100644 vendor/rails/activerecord/test/cases/active_schema_test_postgresql.rb rename vendor/rails/activerecord/test/{ => cases}/adapter_test.rb (85%) rename vendor/rails/activerecord/test/{ => cases}/adapter_test_sqlserver.rb (88%) rename vendor/rails/activerecord/test/{ => cases}/aggregations_test.rb (91%) rename vendor/rails/activerecord/test/{ => cases}/ar_schema_test.rb (68%) create mode 100644 vendor/rails/activerecord/test/cases/associations/belongs_to_associations_test.rb rename vendor/rails/activerecord/test/{ => cases}/associations/callbacks_test.rb (88%) rename vendor/rails/activerecord/test/{ => cases}/associations/cascaded_eager_loading_test.rb (87%) create mode 100644 vendor/rails/activerecord/test/cases/associations/eager_load_nested_include_test.rb rename vendor/rails/activerecord/test/{ => cases}/associations/eager_singularization_test.rb (97%) rename vendor/rails/activerecord/test/{ => cases}/associations/eager_test.rb (69%) rename vendor/rails/activerecord/test/{ => cases}/associations/extension_test.rb (89%) create mode 100644 vendor/rails/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb create mode 100644 vendor/rails/activerecord/test/cases/associations/has_many_associations_test.rb create mode 100644 vendor/rails/activerecord/test/cases/associations/has_many_through_associations_test.rb create mode 100644 vendor/rails/activerecord/test/cases/associations/has_one_associations_test.rb create mode 100644 vendor/rails/activerecord/test/cases/associations/has_one_through_associations_test.rb rename vendor/rails/activerecord/test/{ => cases}/associations/inner_join_association_test.rb (80%) rename vendor/rails/activerecord/test/{ => cases}/associations/join_model_test.rb (76%) create mode 100755 vendor/rails/activerecord/test/cases/associations_test.rb rename vendor/rails/activerecord/test/{ => cases}/attribute_methods_test.rb (57%) rename vendor/rails/activerecord/test/{ => cases}/base_test.rb (81%) rename vendor/rails/activerecord/test/{ => cases}/binary_test.rb (77%) rename vendor/rails/activerecord/test/{ => cases}/calculations_test.rb (88%) rename vendor/rails/activerecord/test/{ => cases}/callbacks_test.rb (99%) rename vendor/rails/activerecord/test/{ => cases}/class_inheritable_attributes_test.rb (88%) rename vendor/rails/activerecord/test/{ => cases}/column_alias_test.rb (78%) rename vendor/rails/activerecord/test/{ => cases}/connection_test_firebird.rb (63%) rename vendor/rails/activerecord/test/{ => cases}/connection_test_mysql.rb (87%) rename vendor/rails/activerecord/test/{ => cases}/copy_table_test_sqlite.rb (92%) rename vendor/rails/activerecord/test/{ => cases}/datatype_test_postgresql.rb (98%) rename vendor/rails/activerecord/test/{ => cases}/date_time_test.rb (86%) rename vendor/rails/activerecord/test/{ => cases}/default_test_firebird.rb (83%) rename vendor/rails/activerecord/test/{ => cases}/defaults_test.rb (85%) rename vendor/rails/activerecord/test/{ => cases}/deprecated_finder_test.rb (89%) create mode 100644 vendor/rails/activerecord/test/cases/dirty_test.rb create mode 100644 vendor/rails/activerecord/test/cases/finder_respond_to_test.rb rename vendor/rails/activerecord/test/{ => cases}/finder_test.rb (69%) rename vendor/rails/activerecord/test/{ => cases}/fixtures_test.rb (78%) create mode 100644 vendor/rails/activerecord/test/cases/helper.rb rename vendor/rails/activerecord/test/{ => cases}/inheritance_test.rb (96%) create mode 100644 vendor/rails/activerecord/test/cases/invalid_date_test.rb rename vendor/rails/activerecord/test/{ => cases}/json_serialization_test.rb (82%) rename vendor/rails/activerecord/test/{ => cases}/lifecycle_test.rb (83%) rename vendor/rails/activerecord/test/{ => cases}/locking_test.rb (94%) rename vendor/rails/activerecord/test/{ => cases}/method_scoping_test.rb (91%) rename vendor/rails/activerecord/test/{ => cases}/migration_test.rb (67%) rename vendor/rails/activerecord/test/{ => cases}/migration_test_firebird.rb (97%) rename vendor/rails/activerecord/test/{ => cases}/mixin_test.rb (95%) rename vendor/rails/activerecord/test/{ => cases}/modules_test.rb (72%) rename vendor/rails/activerecord/test/{ => cases}/multiple_db_test.rb (89%) create mode 100644 vendor/rails/activerecord/test/cases/named_scope_test.rb rename vendor/rails/activerecord/test/{ => cases}/pk_test.rb (91%) rename vendor/rails/activerecord/test/{ => cases}/query_cache_test.rb (68%) rename vendor/rails/activerecord/test/{ => cases}/readonly_test.rb (88%) rename vendor/rails/activerecord/test/{ => cases}/reflection_test.rb (93%) rename vendor/rails/activerecord/test/{ => cases}/reserved_word_test_mysql.rb (96%) rename vendor/rails/activerecord/test/{ => cases}/schema_authorization_test_postgresql.rb (90%) create mode 100644 vendor/rails/activerecord/test/cases/schema_dumper_test.rb create mode 100644 vendor/rails/activerecord/test/cases/schema_test_postgresql.rb rename vendor/rails/activerecord/test/{ => cases}/serialization_test.rb (93%) rename vendor/rails/activerecord/test/{ => cases}/synonym_test_oracle.rb (70%) rename vendor/rails/activerecord/test/{ => cases}/table_name_test_sqlserver.rb (82%) rename vendor/rails/activerecord/test/{ => cases}/threaded_connections_test.rb (89%) rename vendor/rails/activerecord/test/{ => cases}/transactions_test.rb (98%) rename vendor/rails/activerecord/test/{ => cases}/unconnected_test.rb (89%) rename vendor/rails/activerecord/test/{ => cases}/validations_test.rb (88%) rename vendor/rails/activerecord/test/{ => cases}/xml_serialization_test.rb (94%) create mode 100644 vendor/rails/activerecord/test/config.rb create mode 100644 vendor/rails/activerecord/test/fixtures/.gitignore create mode 100644 vendor/rails/activerecord/test/fixtures/author_addresses.yml delete mode 100644 vendor/rails/activerecord/test/fixtures/bad_fixtures/attr_with_numeric_first_char delete mode 100644 vendor/rails/activerecord/test/fixtures/bad_fixtures/attr_with_spaces delete mode 100644 vendor/rails/activerecord/test/fixtures/bad_fixtures/blank_line delete mode 100644 vendor/rails/activerecord/test/fixtures/bad_fixtures/duplicate_attributes delete mode 100644 vendor/rails/activerecord/test/fixtures/bad_fixtures/missing_value create mode 100644 vendor/rails/activerecord/test/fixtures/clubs.yml delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/db2.drop.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/db2.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/db22.drop.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/db22.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/firebird.drop.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/firebird.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/firebird2.drop.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/firebird2.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/frontbase.drop.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/frontbase.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/frontbase2.drop.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/frontbase2.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/openbase.drop.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/openbase.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/openbase2.drop.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/openbase2.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/oracle.drop.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/oracle.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/oracle2.drop.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/oracle2.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/postgresql.drop.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/postgresql.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/postgresql2.drop.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/postgresql2.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/schema.rb delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/schema2.rb delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/sqlite.drop.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/sqlite.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/sqlite2.drop.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/sqlite2.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/sybase.drop.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/sybase.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/sybase2.drop.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/db_definitions/sybase2.sql delete mode 100644 vendor/rails/activerecord/test/fixtures/developers_projects/david_action_controller delete mode 100644 vendor/rails/activerecord/test/fixtures/developers_projects/david_active_record delete mode 100644 vendor/rails/activerecord/test/fixtures/developers_projects/jamis_active_record create mode 100644 vendor/rails/activerecord/test/fixtures/jobs.yml create mode 100644 vendor/rails/activerecord/test/fixtures/members.yml create mode 100644 vendor/rails/activerecord/test/fixtures/memberships.yml create mode 100644 vendor/rails/activerecord/test/fixtures/owners.yml delete mode 100644 vendor/rails/activerecord/test/fixtures/person.rb create mode 100644 vendor/rails/activerecord/test/fixtures/pets.yml delete mode 100644 vendor/rails/activerecord/test/fixtures/pirate.rb create mode 100644 vendor/rails/activerecord/test/fixtures/price_estimates.yml create mode 100644 vendor/rails/activerecord/test/fixtures/references.yml create mode 100644 vendor/rails/activerecord/test/fixtures/sponsors.yml create mode 100644 vendor/rails/activerecord/test/fixtures/subscribers.yml delete mode 100644 vendor/rails/activerecord/test/fixtures/subscribers/first delete mode 100644 vendor/rails/activerecord/test/fixtures/subscribers/second create mode 100644 vendor/rails/activerecord/test/fixtures/subscriptions.yml create mode 100644 vendor/rails/activerecord/test/fixtures/warehouse-things.yml rename vendor/rails/activerecord/test/{fixtures/migrations_with_decimal => migrations/decimal}/1_give_me_big_numbers.rb (100%) rename vendor/rails/activerecord/test/{fixtures/migrations => migrations/duplicate}/1_people_have_last_names.rb (98%) rename vendor/rails/activerecord/test/{fixtures/migrations_with_duplicate => migrations/duplicate}/2_we_need_reminders.rb (98%) rename vendor/rails/activerecord/test/{fixtures/migrations_with_duplicate => migrations/duplicate}/3_foo.rb (100%) rename vendor/rails/activerecord/test/{fixtures/migrations => migrations/duplicate}/3_innocent_jointable.rb (100%) create mode 100644 vendor/rails/activerecord/test/migrations/duplicate_names/20080507052938_chunky.rb create mode 100644 vendor/rails/activerecord/test/migrations/duplicate_names/20080507053028_chunky.rb rename vendor/rails/activerecord/test/{fixtures/migrations_with_duplicate => migrations/interleaved/pass_1}/3_innocent_jointable.rb (100%) rename vendor/rails/activerecord/test/{fixtures/migrations_with_duplicate => migrations/interleaved/pass_2}/1_people_have_last_names.rb (98%) rename vendor/rails/activerecord/test/{fixtures/migrations_with_missing_versions/4_innocent_jointable.rb => migrations/interleaved/pass_2/3_innocent_jointable.rb} (100%) rename vendor/rails/activerecord/test/{fixtures/migrations_with_missing_versions => migrations/interleaved/pass_3}/1_people_have_last_names.rb (98%) create mode 100644 vendor/rails/activerecord/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb create mode 100644 vendor/rails/activerecord/test/migrations/interleaved/pass_3/3_innocent_jointable.rb rename vendor/rails/activerecord/test/{fixtures/migrations_with_missing_versions => migrations/missing}/1000_people_have_middle_names.rb (98%) create mode 100644 vendor/rails/activerecord/test/migrations/missing/1_people_have_last_names.rb rename vendor/rails/activerecord/test/{fixtures/migrations_with_missing_versions => migrations/missing}/3_we_need_reminders.rb (98%) create mode 100644 vendor/rails/activerecord/test/migrations/missing/4_innocent_jointable.rb create mode 100644 vendor/rails/activerecord/test/migrations/valid/1_people_have_last_names.rb rename vendor/rails/activerecord/test/{fixtures/migrations => migrations/valid}/2_we_need_reminders.rb (98%) create mode 100644 vendor/rails/activerecord/test/migrations/valid/3_innocent_jointable.rb rename vendor/rails/activerecord/test/{fixtures => models}/author.rb (78%) rename vendor/rails/activerecord/test/{fixtures => models}/auto_id.rb (100%) rename vendor/rails/activerecord/test/{fixtures => models}/binary.rb (100%) rename vendor/rails/activerecord/test/{fixtures => models}/book.rb (100%) rename vendor/rails/activerecord/test/{fixtures => models}/categorization.rb (100%) rename vendor/rails/activerecord/test/{fixtures => models}/category.rb (79%) rename vendor/rails/activerecord/test/{fixtures => models}/citation.rb (100%) create mode 100644 vendor/rails/activerecord/test/models/club.rb rename vendor/rails/activerecord/test/{fixtures => models}/column_name.rb (100%) rename vendor/rails/activerecord/test/{fixtures => models}/comment.rb (74%) rename vendor/rails/activerecord/test/{fixtures => models}/company.rb (94%) rename vendor/rails/activerecord/test/{fixtures => models}/company_in_module.rb (97%) rename vendor/rails/activerecord/test/{fixtures => models}/computer.rb (98%) rename vendor/rails/activerecord/test/{fixtures => models}/contact.rb (99%) rename vendor/rails/activerecord/test/{fixtures => models}/course.rb (100%) rename vendor/rails/activerecord/test/{fixtures => models}/customer.rb (97%) rename vendor/rails/activerecord/test/{fixtures => models}/default.rb (100%) rename vendor/rails/activerecord/test/{fixtures => models}/developer.rb (79%) rename vendor/rails/activerecord/test/{fixtures => models}/edge.rb (100%) rename vendor/rails/activerecord/test/{fixtures => models}/entrant.rb (100%) create mode 100644 vendor/rails/activerecord/test/models/guid.rb rename vendor/rails/activerecord/test/{fixtures => models}/item.rb (100%) create mode 100644 vendor/rails/activerecord/test/models/job.rb rename vendor/rails/activerecord/test/{fixtures => models}/joke.rb (100%) rename vendor/rails/activerecord/test/{fixtures => models}/keyboard.rb (100%) rename vendor/rails/activerecord/test/{fixtures => models}/legacy_thing.rb (100%) rename vendor/rails/activerecord/test/{fixtures => models}/matey.rb (100%) create mode 100644 vendor/rails/activerecord/test/models/member.rb create mode 100644 vendor/rails/activerecord/test/models/membership.rb rename vendor/rails/activerecord/test/{fixtures => models}/minimalistic.rb (100%) rename vendor/rails/activerecord/test/{fixtures => models}/mixed_case_monkey.rb (100%) rename vendor/rails/activerecord/test/{fixtures => models}/movie.rb (100%) rename vendor/rails/activerecord/test/{fixtures => models}/order.rb (76%) create mode 100644 vendor/rails/activerecord/test/models/owner.rb rename vendor/rails/activerecord/test/{fixtures => models}/parrot.rb (100%) create mode 100644 vendor/rails/activerecord/test/models/person.rb create mode 100644 vendor/rails/activerecord/test/models/pet.rb create mode 100644 vendor/rails/activerecord/test/models/pirate.rb rename vendor/rails/activerecord/test/{fixtures => models}/post.rb (63%) create mode 100644 vendor/rails/activerecord/test/models/price_estimate.rb rename vendor/rails/activerecord/test/{fixtures => models}/project.rb (95%) rename vendor/rails/activerecord/test/{fixtures => models}/reader.rb (100%) create mode 100644 vendor/rails/activerecord/test/models/reference.rb rename vendor/rails/activerecord/test/{fixtures => models}/reply.rb (91%) rename vendor/rails/activerecord/test/{fixtures => models}/ship.rb (100%) create mode 100644 vendor/rails/activerecord/test/models/sponsor.rb rename vendor/rails/activerecord/test/{fixtures => models}/subject.rb (100%) rename vendor/rails/activerecord/test/{fixtures => models}/subscriber.rb (60%) create mode 100644 vendor/rails/activerecord/test/models/subscription.rb rename vendor/rails/activerecord/test/{fixtures => models}/tag.rb (100%) rename vendor/rails/activerecord/test/{fixtures => models}/tagging.rb (100%) rename vendor/rails/activerecord/test/{fixtures => models}/task.rb (100%) rename vendor/rails/activerecord/test/{fixtures => models}/topic.rb (52%) rename vendor/rails/activerecord/test/{fixtures => models}/treasure.rb (70%) rename vendor/rails/activerecord/test/{fixtures => models}/vertex.rb (100%) create mode 100644 vendor/rails/activerecord/test/models/warehouse_thing.rb create mode 100644 vendor/rails/activerecord/test/schema/mysql_specific_schema.rb create mode 100644 vendor/rails/activerecord/test/schema/postgresql_specific_schema.rb create mode 100644 vendor/rails/activerecord/test/schema/schema.rb create mode 100644 vendor/rails/activerecord/test/schema/schema2.rb create mode 100644 vendor/rails/activerecord/test/schema/sqlite_specific_schema.rb create mode 100644 vendor/rails/activerecord/test/schema/sqlserver_specific_schema.rb delete mode 100644 vendor/rails/activerecord/test/schema_dumper_test.rb delete mode 100644 vendor/rails/activerecord/test/schema_test_postgresql.rb create mode 100644 vendor/rails/activesupport/lib/active_support/base64.rb create mode 100644 vendor/rails/activesupport/lib/active_support/cache.rb create mode 100644 vendor/rails/activesupport/lib/active_support/cache/compressed_mem_cache_store.rb create mode 100644 vendor/rails/activesupport/lib/active_support/cache/drb_store.rb create mode 100644 vendor/rails/activesupport/lib/active_support/cache/file_store.rb create mode 100644 vendor/rails/activesupport/lib/active_support/cache/mem_cache_store.rb create mode 100644 vendor/rails/activesupport/lib/active_support/cache/memory_store.rb create mode 100644 vendor/rails/activesupport/lib/active_support/callbacks.rb create mode 100644 vendor/rails/activesupport/lib/active_support/core_ext/base64.rb create mode 100644 vendor/rails/activesupport/lib/active_support/core_ext/base64/encoding.rb create mode 100644 vendor/rails/activesupport/lib/active_support/core_ext/benchmark.rb create mode 100644 vendor/rails/activesupport/lib/active_support/core_ext/numeric/conversions.rb create mode 100644 vendor/rails/activesupport/lib/active_support/core_ext/process.rb create mode 100644 vendor/rails/activesupport/lib/active_support/core_ext/process/daemon.rb create mode 100644 vendor/rails/activesupport/lib/active_support/core_ext/string/filters.rb create mode 100644 vendor/rails/activesupport/lib/active_support/core_ext/time/zones.rb create mode 100644 vendor/rails/activesupport/lib/active_support/gzip.rb delete mode 100644 vendor/rails/activesupport/lib/active_support/testing.rb create mode 100644 vendor/rails/activesupport/lib/active_support/testing/setup_and_teardown.rb create mode 100644 vendor/rails/activesupport/lib/active_support/time_with_zone.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone_info.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Algiers.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Cairo.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Casablanca.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Harare.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Johannesburg.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Monrovia.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Africa/Nairobi.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Argentina/Buenos_Aires.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Argentina/San_Juan.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Bogota.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Caracas.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Chicago.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Chihuahua.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Denver.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Godthab.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Guatemala.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Halifax.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Indiana/Indianapolis.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Juneau.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/La_Paz.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Lima.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Los_Angeles.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Mazatlan.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Mexico_City.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Monterrey.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/New_York.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Phoenix.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Regina.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Santiago.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/St_Johns.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/America/Tijuana.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Almaty.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Baghdad.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Baku.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Bangkok.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Chongqing.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Dhaka.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Hong_Kong.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Irkutsk.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Jakarta.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Jerusalem.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kabul.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kamchatka.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Karachi.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Katmandu.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kolkata.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Krasnoyarsk.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kuala_Lumpur.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Kuwait.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Magadan.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Muscat.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Novosibirsk.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Rangoon.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Riyadh.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Seoul.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Shanghai.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Singapore.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Taipei.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tashkent.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tbilisi.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tehran.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Tokyo.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Ulaanbaatar.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Urumqi.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Vladivostok.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Yakutsk.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Yekaterinburg.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Asia/Yerevan.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Atlantic/Azores.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Atlantic/Cape_Verde.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Atlantic/South_Georgia.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Adelaide.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Brisbane.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Darwin.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Hobart.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Melbourne.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Perth.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Australia/Sydney.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Etc/UTC.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Amsterdam.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Athens.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Belgrade.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Berlin.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Bratislava.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Brussels.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Bucharest.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Budapest.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Copenhagen.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Dublin.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Helsinki.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Istanbul.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Kiev.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Lisbon.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Ljubljana.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/London.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Madrid.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Minsk.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Moscow.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Paris.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Prague.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Riga.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Rome.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Sarajevo.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Skopje.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Sofia.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Stockholm.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Tallinn.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Vienna.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Vilnius.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Warsaw.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Europe/Zagreb.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Auckland.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Fiji.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Guam.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Honolulu.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Majuro.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Midway.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Noumea.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Pago_Pago.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Port_Moresby.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/definitions/Pacific/Tongatapu.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/info_timezone.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/linked_timezone.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/linked_timezone_info.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/offset_rationals.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/time_or_datetime.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_definition.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_info.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_offset_info.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_period.rb create mode 100644 vendor/rails/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_transition_info.rb create mode 100644 vendor/rails/activesupport/test/caching_test.rb create mode 100644 vendor/rails/activesupport/test/callbacks_test.rb create mode 100644 vendor/rails/activesupport/test/core_ext/base64_ext_test.rb create mode 100644 vendor/rails/activesupport/test/core_ext/bigdecimal.rb rename vendor/rails/activesupport/test/core_ext/{load_error_tests.rb => load_error_test.rb} (88%) create mode 100644 vendor/rails/activesupport/test/core_ext/time_with_zone_test.rb create mode 100755 vendor/rails/railties/bin/dbconsole create mode 100644 vendor/rails/railties/configs/initializers/new_rails_defaults.rb create mode 100644 vendor/rails/railties/lib/commands/dbconsole.rb create mode 100644 vendor/rails/railties/lib/commands/servers/new_mongrel.rb create mode 100644 vendor/rails/railties/lib/rails/gem_builder.rb create mode 100644 vendor/rails/railties/lib/rails/gem_dependency.rb create mode 100644 vendor/rails/railties/lib/rails/mongrel_server/commands.rb create mode 100644 vendor/rails/railties/lib/rails/mongrel_server/handler.rb create mode 100644 vendor/rails/railties/lib/tasks/gems.rake delete mode 100644 vendor/rails/railties/pkg/rails-2.0.2.gem create mode 100644 vendor/rails/railties/test/fixtures/about_yml_plugins/bad_about_yml/about.yml create mode 100644 vendor/rails/railties/test/fixtures/about_yml_plugins/bad_about_yml/init.rb create mode 100644 vendor/rails/railties/test/fixtures/about_yml_plugins/plugin_without_about_yml/init.rb rename vendor/rails/{actionmailer/test/fixtures/first_mailer/share.rhtml => railties/test/fixtures/lib/generators/missing_class/templates/.gitignore} (100%) rename vendor/rails/{actionmailer/test/fixtures/helper_mailer/use_example_helper.rhtml => railties/test/fixtures/lib/generators/missing_generator/templates/.gitignore} (100%) rename vendor/rails/{actionmailer/test/fixtures/helper_mailer/use_helper.rhtml => railties/test/fixtures/lib/generators/missing_templates/.gitignore} (100%) create mode 100644 vendor/rails/railties/test/fixtures/plugins/alternate/a/generators/a_generator/a_generator.rb rename vendor/rails/{actionmailer/test/fixtures/helper_mailer/use_helper_method.rhtml => railties/test/fixtures/plugins/alternate/a/lib/.gitignore} (100%) rename vendor/rails/{actionmailer/test/fixtures/helper_mailer/use_mail_helper.rhtml => railties/test/fixtures/plugins/default/acts/acts_as_chunky_bacon/lib/.gitignore} (100%) rename vendor/rails/{actionmailer/test/fixtures/path.with.dots/funky_path_mailer/multipart_with_template_path_with_dots.rhtml => railties/test/fixtures/plugins/default/empty/.gitignore} (100%) create mode 100644 vendor/rails/railties/test/fixtures/plugins/default/stubby/about.yml create mode 100644 vendor/rails/railties/test/fixtures/plugins/default/stubby/generators/stubby_generator/stubby_generator.rb create mode 100644 vendor/rails/railties/test/gem_dependency_test.rb create mode 100644 vendor/rails/railties/test/generator_lookup_test.rb create mode 100644 vendor/rails/railties/test/generators/rails_mailer_generator_test.rb diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb index e41aa5c5..e013853f 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin_controller.rb @@ -1,5 +1,3 @@ -require 'application' - class AdminController < ApplicationController layout 'default' diff --git a/config/boot.rb b/config/boot.rb index 1e2a6418..cd21fb9e 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,45 +1,109 @@ -# Don't change this file. Configuration is done in config/environment.rb and config/environments/*.rb +# Don't change this file! +# Configure your app in config/environment.rb and config/environments/*.rb -unless defined?(RAILS_ROOT) - root_path = File.join(File.dirname(__FILE__), '..') +RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT) - unless RUBY_PLATFORM =~ /mswin32/ - require 'pathname' - root_path = Pathname.new(root_path).cleanpath(true).to_s - end - - RAILS_ROOT = root_path -end - -unless defined?(Rails::Initializer) - if File.directory?("#{RAILS_ROOT}/vendor/rails") - require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer" - else - require 'rubygems' - - environment_without_comments = IO.readlines(File.dirname(__FILE__) + '/environment.rb').reject { |l| l =~ /^#/ }.join - environment_without_comments =~ /[^#]RAILS_GEM_VERSION = '([\d.]+)'/ - rails_gem_version = $1 - - if version = defined?(RAILS_GEM_VERSION) ? RAILS_GEM_VERSION : rails_gem_version - # Asking for 1.1.6 will give you 1.1.6.5206, if available -- makes it easier to use beta gems - rails_gem = Gem.cache.search('rails', "~>#{version}.0").sort_by { |g| g.version.version }.last - - if rails_gem - gem "rails", "=#{rails_gem.version.version}" - require rails_gem.full_gem_path + '/lib/initializer' - else - STDERR.puts %(Cannot find gem for Rails ~>#{version}.0: - Install the missing gem with 'gem install -v=#{version} rails', or - change environment.rb to define RAILS_GEM_VERSION with your desired version. - ) - exit 1 +module Rails + class << self + def boot! + unless booted? + preinitialize + pick_boot.run end - else - gem "rails" - require 'initializer' + end + + def booted? + defined? Rails::Initializer + end + + def pick_boot + (vendor_rails? ? VendorBoot : GemBoot).new + end + + def vendor_rails? + File.exist?("#{RAILS_ROOT}/vendor/rails") + end + + def preinitialize + load(preinitializer_path) if File.exist?(preinitializer_path) + end + + def preinitializer_path + "#{RAILS_ROOT}/config/preinitializer.rb" end end - Rails::Initializer.run(:set_load_path) -end \ No newline at end of file + class Boot + def run + load_initializer + Rails::Initializer.run(:set_load_path) + end + end + + class VendorBoot < Boot + def load_initializer + require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer" + Rails::Initializer.run(:install_gem_spec_stubs) + end + end + + class GemBoot < Boot + def load_initializer + self.class.load_rubygems + load_rails_gem + require 'initializer' + end + + def load_rails_gem + if version = self.class.gem_version + gem 'rails', version + else + gem 'rails' + end + rescue Gem::LoadError => load_error + $stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.) + exit 1 + end + + class << self + def rubygems_version + Gem::RubyGemsVersion if defined? Gem::RubyGemsVersion + end + + def gem_version + if defined? RAILS_GEM_VERSION + RAILS_GEM_VERSION + elsif ENV.include?('RAILS_GEM_VERSION') + ENV['RAILS_GEM_VERSION'] + else + parse_gem_version(read_environment_rb) + end + end + + def load_rubygems + require 'rubygems' + + unless rubygems_version >= '0.9.4' + $stderr.puts %(Rails requires RubyGems >= 0.9.4 (you have #{rubygems_version}). Please `gem update --system` and try again.) + exit 1 + end + + rescue LoadError + $stderr.puts %(Rails requires RubyGems >= 0.9.4. Please install RubyGems and try again: http://rubygems.rubyforge.org) + exit 1 + end + + def parse_gem_version(text) + $1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/ + end + + private + def read_environment_rb + File.read("#{RAILS_ROOT}/config/environment.rb") + end + end + end +end + +# All that for this: +Rails.boot! diff --git a/config/environment.rb b/config/environment.rb index b111acb4..fa5b06c2 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -30,6 +30,9 @@ Rails::Initializer.run do |config| ##### } + # Don't do file system STAT calls to check to see if the templates have changed. + #config.action_view.cache_template_loading = true + # Skip frameworks you're not going to use config.frameworks -= [ :action_web_service, :action_mailer ] @@ -39,7 +42,7 @@ Rails::Initializer.run do |config| # Enable page/fragment caching by setting a file-based store # (remember to create the caching directory and make it readable to the application) - config.action_controller.fragment_cache_store = :file_store, "#{RAILS_ROOT}/cache" + config.action_controller.cache_store = :file_store, "#{RAILS_ROOT}/cache" # Activate observers that should always be running config.active_record.observers = :page_observer diff --git a/test/functional/admin_controller_test.rb b/test/functional/admin_controller_test.rb index 0656f815..b8594572 100644 --- a/test/functional/admin_controller_test.rb +++ b/test/functional/admin_controller_test.rb @@ -10,6 +10,7 @@ class AdminControllerTest < Test::Unit::TestCase fixtures :webs, :pages, :revisions, :system, :wiki_references def setup + require 'action_controller/test_process' @controller = AdminController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new diff --git a/test/test_helper.rb b/test/test_helper.rb index 0cecb06a..aa0cf1d1 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -3,11 +3,9 @@ ENV['RAILS_ENV'] = 'test' # Expand the path to environment so that Ruby does not load it multiple times # File.expand_path can be removed if Ruby 1.9 is in use. require File.expand_path(File.dirname(__FILE__) + '/../config/environment') -require 'application' require 'test/unit' require 'active_record/fixtures' -require 'action_controller/test_process' require 'wiki_content' require 'url_generator' require 'digest/sha1' diff --git a/vendor/rails/actionmailer/CHANGELOG b/vendor/rails/actionmailer/CHANGELOG index 8ba3ccde..b2ce462f 100644 --- a/vendor/rails/actionmailer/CHANGELOG +++ b/vendor/rails/actionmailer/CHANGELOG @@ -1,3 +1,14 @@ +*2.1.0 RC1 (May 11th, 2008)* + +* Fixed that a return-path header would be ignored #7572 [joost] + +* Less verbose mail logging: just recipients for :info log level; the whole email for :debug only. #8000 [iaddict, Tarmo Tänav] + +* Updated TMail to version 1.2.1 [raasdnil] + +* Fixed that you don't have to call super in ActionMailer::TestCase#setup #10406 [jamesgolick] + + *2.0.2* (December 16th, 2007) * Included in Rails 2.0.2 diff --git a/vendor/rails/actionmailer/MIT-LICENSE b/vendor/rails/actionmailer/MIT-LICENSE index 007cc942..13c90d46 100644 --- a/vendor/rails/actionmailer/MIT-LICENSE +++ b/vendor/rails/actionmailer/MIT-LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2007 David Heinemeier Hansson +Copyright (c) 2004-2008 David Heinemeier Hansson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/vendor/rails/actionmailer/Rakefile b/vendor/rails/actionmailer/Rakefile index 4622871a..22ed3964 100755 --- a/vendor/rails/actionmailer/Rakefile +++ b/vendor/rails/actionmailer/Rakefile @@ -4,7 +4,7 @@ require 'rake/testtask' require 'rake/rdoctask' require 'rake/packagetask' require 'rake/gempackagetask' -require 'rake/contrib/rubyforgepublisher' +require 'rake/contrib/sshpublisher' require File.join(File.dirname(__FILE__), 'lib', 'action_mailer', 'version') PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : '' @@ -55,7 +55,7 @@ spec = Gem::Specification.new do |s| s.rubyforge_project = "actionmailer" s.homepage = "http://www.rubyonrails.org" - s.add_dependency('actionpack', '= 2.0.2' + PKG_BUILD) + s.add_dependency('actionpack', '= 2.0.991' + PKG_BUILD) s.has_rdoc = true s.requirements << 'none' @@ -87,6 +87,7 @@ end desc "Publish the release files to RubyForge." task :release => [ :package ] do require 'rubyforge' + require 'rake/contrib/rubyforgepublisher' packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" } diff --git a/vendor/rails/actionmailer/lib/action_mailer.rb b/vendor/rails/actionmailer/lib/action_mailer.rb index ec803f5a..2e324d46 100755 --- a/vendor/rails/actionmailer/lib/action_mailer.rb +++ b/vendor/rails/actionmailer/lib/action_mailer.rb @@ -1,5 +1,5 @@ #-- -# Copyright (c) 2004-2007 David Heinemeier Hansson +# Copyright (c) 2004-2008 David Heinemeier Hansson # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the diff --git a/vendor/rails/actionmailer/lib/action_mailer/adv_attr_accessor.rb b/vendor/rails/actionmailer/lib/action_mailer/adv_attr_accessor.rb index cfd72301..e77029af 100644 --- a/vendor/rails/actionmailer/lib/action_mailer/adv_attr_accessor.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/adv_attr_accessor.rb @@ -16,7 +16,7 @@ module ActionMailer define_method(name) do |*parameters| raise ArgumentError, "expected 0 or 1 parameters" unless parameters.length <= 1 if parameters.empty? - if instance_variables.include?(ivar) + if instance_variable_names.include?(ivar) instance_variable_get(ivar) end else diff --git a/vendor/rails/actionmailer/lib/action_mailer/base.rb b/vendor/rails/actionmailer/lib/action_mailer/base.rb index b15c010e..a3762bf8 100644 --- a/vendor/rails/actionmailer/lib/action_mailer/base.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/base.rb @@ -40,10 +40,14 @@ module ActionMailer #:nodoc: # * content_type - Specify the content type of the message. Defaults to text/plain. # * headers - Specify additional headers to be set for the message, e.g. headers 'X-Mail-Count' => 107370. # + # When a headers 'return-path' is specified, that value will be used as the 'envelope from' + # address. Setting this is useful when you want delivery notifications sent to a different address than + # the one in from. + # # The body method has special behavior. It takes a hash which generates an instance variable # named after each key in the hash containing the value that that key points to. # - # So, for example, body "account" => recipient would result + # So, for example, body :account => recipient would result # in an instance variable @account with the value of recipient being accessible in the # view. # @@ -69,21 +73,36 @@ module ActionMailer #:nodoc: # <%= truncate(note.body, 25) %> # # - # = Generating URLs for mailer views + # = Generating URLs + # + # URLs can be generated in mailer views using url_for or named routes. + # Unlike controllers from Action Pack, the mailer instance doesn't have any context about the incoming request, + # so you'll need to provide all of the details needed to generate a URL. # - # If your view includes URLs from the application, you need to use url_for in the mailing method instead of the view. - # Unlike controllers from Action Pack, the mailer instance doesn't have any context about the incoming request. That's - # why you need to jump this little hoop and supply all the details needed for the URL. Example: + # When using url_for you'll need to provide the :host, :controller, and :action: + # + # <%= url_for(:host => "example.com", :controller => "welcome", :action => "greeting") %> # - # def signup_notification(recipient) - # recipients recipient.email_address_with_name - # from "system@example.com" - # subject "New account information" - # body :account => recipient, - # :home_page => url_for(:host => "example.com", :controller => "welcome", :action => "greeting") - # end + # When using named routes you only need to supply the :host: + # + # <%= users_url(:host => "example.com") %> # - # You can now access @home_page in the template and get http://example.com/welcome/greeting. + # You will want to avoid using the name_of_route_path form of named routes because it doesn't make sense to + # generate relative URLs in email messages. + # + # It is also possible to set a default host that will be used in all mailers by setting the :host option in + # the ActionMailer::Base.default_url_options hash as follows: + # + # ActionMailer::Base.default_url_options[:host] = "example.com" + # + # This can also be set as a configuration option in config/environment.rb: + # + # config.action_mailer.default_url_options = { :host => "example.com" } + # + # If you do decide to set a default :host for your mailers you will want to use the + # :only_path => false option when using url_for. This will ensure that absolute URLs are generated because + # the url_for view helper will, by default, generate relative URLs when a :host option isn't + # explicitly provided. # # = Sending mail # @@ -179,31 +198,32 @@ module ActionMailer #:nodoc: # # These options are specified on the class level, like ActionMailer::Base.template_root = "/my/templates" # - # * template_root - template root determines the base from which template references will be made. + # * template_root - Determines the base from which template references will be made. # # * logger - the logger is used for generating information on the mailing run if available. # Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers. # - # * smtp_settings - Allows detailed configuration for :smtp delivery method: - # * :address Allows you to use a remote mail server. Just change it from its default "localhost" setting. - # * :port On the off chance that your mail server doesn't run on port 25, you can change it. - # * :domain If you need to specify a HELO domain, you can do it here. - # * :user_name If your mail server requires authentication, set the username in this setting. - # * :password If your mail server requires authentication, set the password in this setting. - # * :authentication If your mail server requires authentication, you need to specify the authentication type here. - # This is a symbol and one of :plain, :login, :cram_md5 + # * smtp_settings - Allows detailed configuration for :smtp delivery method: + # * :address - Allows you to use a remote mail server. Just change it from its default "localhost" setting. + # * :port - On the off chance that your mail server doesn't run on port 25, you can change it. + # * :domain - If you need to specify a HELO domain, you can do it here. + # * :user_name - If your mail server requires authentication, set the username in this setting. + # * :password - If your mail server requires authentication, set the password in this setting. + # * :authentication - If your mail server requires authentication, you need to specify the authentication type here. + # This is a symbol and one of :plain, :login, :cram_md5 # - # * sendmail_settings - Allows you to override options for the :sendmail delivery method - # * :location The location of the sendmail executable, defaults to "/usr/sbin/sendmail" - # * :arguments The command line arguments - # * raise_delivery_errors - whether or not errors should be raised if the email fails to be delivered. + # * sendmail_settings - Allows you to override options for the :sendmail delivery method + # * :location - The location of the sendmail executable, defaults to "/usr/sbin/sendmail" + # * :arguments - The command line arguments # - # * delivery_method - Defines a delivery method. Possible values are :smtp (default), :sendmail, and :test. + # * raise_delivery_errors - Whether or not errors should be raised if the email fails to be delivered. # - # * perform_deliveries - Determines whether deliver_* methods are actually carried out. By default they are, + # * delivery_method - Defines a delivery method. Possible values are :smtp (default), :sendmail, and :test. + # + # * perform_deliveries - Determines whether deliver_* methods are actually carried out. By default they are, # but this can be turned off to help functional testing. # - # * deliveries - Keeps an array of all the emails sent out through the Action Mailer with delivery_method :test. Most useful + # * deliveries - Keeps an array of all the emails sent out through the Action Mailer with delivery_method :test. Most useful # for unit and functional testing. # # * default_charset - The default charset used for the body and to encode the subject. Defaults to UTF-8. You can also @@ -387,12 +407,17 @@ module ActionMailer #:nodoc: # templating language other than rhtml or rxml are supported. # To use this, include in your template-language plugin's init # code or on a per-application basis, this can be invoked from - # config/environment.rb: + # config/environment.rb: # # ActionMailer::Base.register_template_extension('haml') def register_template_extension(extension) template_extensions << extension end + + def template_root=(root) + write_inheritable_attribute(:template_root, root) + ActionView::TemplateFinder.process_view_paths(root) + end end # Instantiate a new mailer object. If +method_name+ is not +nil+, the mailer @@ -463,7 +488,10 @@ module ActionMailer #:nodoc: # no alternate has been given as the parameter, this will fail. def deliver!(mail = @mail) raise "no mail object available for delivery!" unless mail - logger.info "Sent mail:\n #{mail.encoded}" unless logger.nil? + unless logger.nil? + logger.info "Sent mail to #{Array(recipients).join(', ')}" + logger.debug "\n#{mail.encoded}" + end begin __send__("perform_delivery_#{delivery_method}", mail) if perform_deliveries @@ -582,15 +610,18 @@ module ActionMailer #:nodoc: def perform_delivery_smtp(mail) destinations = mail.destinations mail.ready_to_send + sender = mail['return-path'] || mail.from Net::SMTP.start(smtp_settings[:address], smtp_settings[:port], smtp_settings[:domain], smtp_settings[:user_name], smtp_settings[:password], smtp_settings[:authentication]) do |smtp| - smtp.sendmail(mail.encoded, mail.from, destinations) + smtp.sendmail(mail.encoded, sender, destinations) end end def perform_delivery_sendmail(mail) - IO.popen("#{sendmail_settings[:location]} #{sendmail_settings[:arguments]}","w+") do |sm| + sendmail_args = sendmail_settings[:arguments] + sendmail_args += " -f \"#{mail['return-path']}\"" if mail['return-path'] + IO.popen("#{sendmail_settings[:location]} #{sendmail_args}","w+") do |sm| sm.print(mail.encoded.gsub(/\r/, '')) sm.flush end diff --git a/vendor/rails/actionmailer/lib/action_mailer/helpers.rb b/vendor/rails/actionmailer/lib/action_mailer/helpers.rb index 7777d16d..3e5ed9e9 100644 --- a/vendor/rails/actionmailer/lib/action_mailer/helpers.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/helpers.rb @@ -22,7 +22,7 @@ module ActionMailer module ClassMethods # Makes all the (instance) methods in the helper module available to templates rendered through this controller. - # See ActionView::Helpers (link:classes/ActionView/Helpers.html) for more about making your own helper modules + # See ActionView::Helpers (link:classes/ActionView/Helpers.html) for more about making your own helper modules # available to the templates. def add_template_helper(helper_module) #:nodoc: master_helper_module.module_eval "include #{helper_module}" @@ -45,7 +45,7 @@ module ActionMailer when String, Symbol file_name = arg.to_s.underscore + '_helper' class_name = file_name.camelize - + begin require_dependency(file_name) rescue LoadError => load_error @@ -87,17 +87,17 @@ module ActionMailer attrs.flatten.each { |attr| helper_method(attr, "#{attr}=") } end - private + private def inherited_with_helper(child) inherited_without_helper(child) begin child.master_helper_module = Module.new child.master_helper_module.send! :include, master_helper_module - child.helper child.name.underscore + child.helper child.name.to_s.underscore rescue MissingSourceFile => e - raise unless e.is_missing?("helpers/#{child.name.underscore}_helper") + raise unless e.is_missing?("helpers/#{child.name.to_s.underscore}_helper") end - end + end end private diff --git a/vendor/rails/actionmailer/lib/action_mailer/quoting.rb b/vendor/rails/actionmailer/lib/action_mailer/quoting.rb index d6e04e4d..b2224327 100644 --- a/vendor/rails/actionmailer/lib/action_mailer/quoting.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/quoting.rb @@ -24,6 +24,8 @@ module ActionMailer # Quote the given text if it contains any "illegal" characters def quote_if_necessary(text, charset) + text = text.dup.force_encoding(Encoding::ASCII_8BIT) if text.respond_to?(:force_encoding) + (text =~ CHARS_NEEDING_QUOTING) ? quoted_printable(text, charset) : text diff --git a/vendor/rails/actionmailer/lib/action_mailer/test_case.rb b/vendor/rails/actionmailer/lib/action_mailer/test_case.rb index cc75b392..d474afe3 100644 --- a/vendor/rails/actionmailer/lib/action_mailer/test_case.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/test_case.rb @@ -8,11 +8,13 @@ module ActionMailer "test case definition" end end - # New Test Super class for forward compatibility. - # To override + class TestCase < ActiveSupport::TestCase include ActionMailer::Quoting + setup :initialize_test_deliveries + setup :set_expected_mail + class << self def tests(mailer) write_inheritable_attribute(:mailer_class, mailer) @@ -33,15 +35,18 @@ module ActionMailer end end - def setup - ActionMailer::Base.delivery_method = :test - ActionMailer::Base.perform_deliveries = true - ActionMailer::Base.deliveries = [] + protected + def initialize_test_deliveries + ActionMailer::Base.delivery_method = :test + ActionMailer::Base.perform_deliveries = true + ActionMailer::Base.deliveries = [] + end - @expected = TMail::Mail.new - @expected.set_content_type "text", "plain", { "charset" => charset } - @expected.mime_version = '1.0' - end + def set_expected_mail + @expected = TMail::Mail.new + @expected.set_content_type "text", "plain", { "charset" => charset } + @expected.mime_version = '1.0' + end private def charset diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor.rb index 0ad7386f..56a2858b 100644 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor.rb @@ -2,9 +2,9 @@ require 'rubygems' begin - gem 'tmail', '~> 1.1.0' + gem 'tmail', '~> 1.2.2' rescue Gem::LoadError - $:.unshift "#{File.dirname(__FILE__)}/vendor/tmail-1.1.0" + $:.unshift "#{File.dirname(__FILE__)}/vendor/tmail-1.2.2" end begin diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/Makefile b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/Makefile deleted file mode 100644 index 346353b8..00000000 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# -# lib/tmail/Makefile -# - -debug: - rm -f parser.rb - make parser.rb DEBUG=true - -parser.rb: parser.y - if [ "$(DEBUG)" = true ]; then \ - racc -v -g -o$@ parser.y ;\ - else \ - racc -E -o$@ parser.y ;\ - fi - -clean: - rm -f parser.rb parser.output - -distclean: clean diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/address.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/address.rb deleted file mode 100755 index 224ed709..00000000 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/address.rb +++ /dev/null @@ -1,245 +0,0 @@ -=begin rdoc - -= Address handling class - -=end -# -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# 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. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -require 'tmail/encode' -require 'tmail/parser' - - -module TMail - - class Address - - include TextUtils - - def Address.parse( str ) - Parser.parse :ADDRESS, str - end - - def address_group? - false - end - - def initialize( local, domain ) - if domain - domain.each do |s| - raise SyntaxError, 'empty word in domain' if s.empty? - end - end - - @local = local - @domain = domain - @name = nil - @routes = [] - end - - attr_reader :name - - def name=( str ) - @name = str - @name = nil if str and str.empty? - end - - alias phrase name - alias phrase= name= - - attr_reader :routes - - def inspect - "#<#{self.class} #{address()}>" - end - - def local - return nil unless @local - return '""' if @local.size == 1 and @local[0].empty? - @local.map {|i| quote_atom(i) }.join('.') - end - - def domain - return nil unless @domain - join_domain(@domain) - end - - def spec - s = self.local - d = self.domain - if s and d - s + '@' + d - else - s - end - end - - alias address spec - - def ==( other ) - other.respond_to? :spec and self.spec == other.spec - end - - alias eql? == - - def hash - @local.hash ^ @domain.hash - end - - def dup - obj = self.class.new(@local.dup, @domain.dup) - obj.name = @name.dup if @name - obj.routes.replace @routes - obj - end - - include StrategyInterface - - def accept( strategy, dummy1 = nil, dummy2 = nil ) - unless @local - strategy.meta '<>' # empty return-path - return - end - - spec_p = (not @name and @routes.empty?) - if @name - strategy.phrase @name - strategy.space - end - tmp = spec_p ? '' : '<' - unless @routes.empty? - tmp << @routes.map {|i| '@' + i }.join(',') << ':' - end - tmp << self.spec - tmp << '>' unless spec_p - strategy.meta tmp - strategy.lwsp '' - end - - end - - - class AddressGroup - - include Enumerable - - def address_group? - true - end - - def initialize( name, addrs ) - @name = name - @addresses = addrs - end - - attr_reader :name - - def ==( other ) - other.respond_to? :to_a and @addresses == other.to_a - end - - alias eql? == - - def hash - map {|i| i.hash }.hash - end - - def []( idx ) - @addresses[idx] - end - - def size - @addresses.size - end - - def empty? - @addresses.empty? - end - - def each( &block ) - @addresses.each(&block) - end - - def to_a - @addresses.dup - end - - alias to_ary to_a - - def include?( a ) - @addresses.include? a - end - - def flatten - set = [] - @addresses.each do |a| - if a.respond_to? :flatten - set.concat a.flatten - else - set.push a - end - end - set - end - - def each_address( &block ) - flatten.each(&block) - end - - def add( a ) - @addresses.push a - end - - alias push add - - def delete( a ) - @addresses.delete a - end - - include StrategyInterface - - def accept( strategy, dummy1 = nil, dummy2 = nil ) - strategy.phrase @name - strategy.meta ':' - strategy.space - first = true - each do |mbox| - if first - first = false - else - strategy.meta ',' - end - strategy.space - mbox.accept strategy - end - strategy.meta ';' - strategy.lwsp '' - end - - end - -end # module TMail diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/facade.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/facade.rb deleted file mode 100755 index 1ecd64bf..00000000 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/facade.rb +++ /dev/null @@ -1,552 +0,0 @@ -# -# facade.rb -# -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# 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. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -require 'tmail/utils' - - -module TMail - - class Mail - - def header_string( name, default = nil ) - h = @header[name.downcase] or return default - h.to_s - end - - ### - ### attributes - ### - - include TextUtils - - def set_string_array_attr( key, strs ) - strs.flatten! - if strs.empty? - @header.delete key.downcase - else - store key, strs.join(', ') - end - strs - end - private :set_string_array_attr - - def set_string_attr( key, str ) - if str - store key, str - else - @header.delete key.downcase - end - str - end - private :set_string_attr - - def set_addrfield( name, arg ) - if arg - h = HeaderField.internal_new(name, @config) - h.addrs.replace [arg].flatten - @header[name] = h - else - @header.delete name - end - arg - end - private :set_addrfield - - def addrs2specs( addrs ) - return nil unless addrs - list = addrs.map {|addr| - if addr.address_group? - then addr.map {|a| a.spec } - else addr.spec - end - }.flatten - return nil if list.empty? - list - end - private :addrs2specs - - - # - # date time - # - - def date( default = nil ) - if h = @header['date'] - h.date - else - default - end - end - - def date=( time ) - if time - store 'Date', time2str(time) - else - @header.delete 'date' - end - time - end - - def strftime( fmt, default = nil ) - if t = date - t.strftime(fmt) - else - default - end - end - - - # - # destination - # - - def to_addrs( default = nil ) - if h = @header['to'] - h.addrs - else - default - end - end - - def cc_addrs( default = nil ) - if h = @header['cc'] - h.addrs - else - default - end - end - - def bcc_addrs( default = nil ) - if h = @header['bcc'] - h.addrs - else - default - end - end - - def to_addrs=( arg ) - set_addrfield 'to', arg - end - - def cc_addrs=( arg ) - set_addrfield 'cc', arg - end - - def bcc_addrs=( arg ) - set_addrfield 'bcc', arg - end - - def to( default = nil ) - addrs2specs(to_addrs(nil)) || default - end - - def cc( default = nil ) - addrs2specs(cc_addrs(nil)) || default - end - - def bcc( default = nil ) - addrs2specs(bcc_addrs(nil)) || default - end - - def to=( *strs ) - set_string_array_attr 'To', strs - end - - def cc=( *strs ) - set_string_array_attr 'Cc', strs - end - - def bcc=( *strs ) - set_string_array_attr 'Bcc', strs - end - - - # - # originator - # - - def from_addrs( default = nil ) - if h = @header['from'] - h.addrs - else - default - end - end - - def from_addrs=( arg ) - set_addrfield 'from', arg - end - - def from( default = nil ) - addrs2specs(from_addrs(nil)) || default - end - - def from=( *strs ) - set_string_array_attr 'From', strs - end - - def friendly_from( default = nil ) - h = @header['from'] - a, = h.addrs - return default unless a - return a.phrase if a.phrase - return h.comments.join(' ') unless h.comments.empty? - a.spec - end - - - def reply_to_addrs( default = nil ) - if h = @header['reply-to'] - h.addrs - else - default - end - end - - def reply_to_addrs=( arg ) - set_addrfield 'reply-to', arg - end - - def reply_to( default = nil ) - addrs2specs(reply_to_addrs(nil)) || default - end - - def reply_to=( *strs ) - set_string_array_attr 'Reply-To', strs - end - - - def sender_addr( default = nil ) - f = @header['sender'] or return default - f.addr or return default - end - - def sender_addr=( addr ) - if addr - h = HeaderField.internal_new('sender', @config) - h.addr = addr - @header['sender'] = h - else - @header.delete 'sender' - end - addr - end - - def sender( default ) - f = @header['sender'] or return default - a = f.addr or return default - a.spec - end - - def sender=( str ) - set_string_attr 'Sender', str - end - - - # - # subject - # - - def subject( default = nil ) - if h = @header['subject'] - h.body - else - default - end - end - alias quoted_subject subject - - def subject=( str ) - set_string_attr 'Subject', str - end - - - # - # identity & threading - # - - def message_id( default = nil ) - if h = @header['message-id'] - h.id || default - else - default - end - end - - def message_id=( str ) - set_string_attr 'Message-Id', str - end - - def in_reply_to( default = nil ) - if h = @header['in-reply-to'] - h.ids - else - default - end - end - - def in_reply_to=( *idstrs ) - set_string_array_attr 'In-Reply-To', idstrs - end - - def references( default = nil ) - if h = @header['references'] - h.refs - else - default - end - end - - def references=( *strs ) - set_string_array_attr 'References', strs - end - - - # - # MIME headers - # - - def mime_version( default = nil ) - if h = @header['mime-version'] - h.version || default - else - default - end - end - - def mime_version=( m, opt = nil ) - if opt - if h = @header['mime-version'] - h.major = m - h.minor = opt - else - store 'Mime-Version', "#{m}.#{opt}" - end - else - store 'Mime-Version', m - end - m - end - - - def content_type( default = nil ) - if h = @header['content-type'] - h.content_type || default - else - default - end - end - - def main_type( default = nil ) - if h = @header['content-type'] - h.main_type || default - else - default - end - end - - def sub_type( default = nil ) - if h = @header['content-type'] - h.sub_type || default - else - default - end - end - - def set_content_type( str, sub = nil, param = nil ) - if sub - main, sub = str, sub - else - main, sub = str.split(%r, 2) - raise ArgumentError, "sub type missing: #{str.inspect}" unless sub - end - if h = @header['content-type'] - h.main_type = main - h.sub_type = sub - h.params.clear - else - store 'Content-Type', "#{main}/#{sub}" - end - @header['content-type'].params.replace param if param - - str - end - - alias content_type= set_content_type - - def type_param( name, default = nil ) - if h = @header['content-type'] - h[name] || default - else - default - end - end - - def charset( default = nil ) - if h = @header['content-type'] - h['charset'] or default - else - default - end - end - - def charset=( str ) - if str - if h = @header[ 'content-type' ] - h['charset'] = str - else - store 'Content-Type', "text/plain; charset=#{str}" - end - end - str - end - - - def transfer_encoding( default = nil ) - if h = @header['content-transfer-encoding'] - h.encoding || default - else - default - end - end - - def transfer_encoding=( str ) - set_string_attr 'Content-Transfer-Encoding', str - end - - alias encoding transfer_encoding - alias encoding= transfer_encoding= - alias content_transfer_encoding transfer_encoding - alias content_transfer_encoding= transfer_encoding= - - - def disposition( default = nil ) - if h = @header['content-disposition'] - h.disposition || default - else - default - end - end - - alias content_disposition disposition - - def set_disposition( str, params = nil ) - if h = @header['content-disposition'] - h.disposition = str - h.params.clear - else - store('Content-Disposition', str) - h = @header['content-disposition'] - end - h.params.replace params if params - end - - alias disposition= set_disposition - alias set_content_disposition set_disposition - alias content_disposition= set_disposition - - def disposition_param( name, default = nil ) - if h = @header['content-disposition'] - h[name] || default - else - default - end - end - - ### - ### utils - ### - - def create_reply - mail = TMail::Mail.parse('') - mail.subject = 'Re: ' + subject('').sub(/\A(?:\[[^\]]+\])?(?:\s*Re:)*\s*/i, '') - mail.to_addrs = reply_addresses([]) - mail.in_reply_to = [message_id(nil)].compact - mail.references = references([]) + [message_id(nil)].compact - mail.mime_version = '1.0' - mail - end - - - def base64_encode - store 'Content-Transfer-Encoding', 'Base64' - self.body = Base64.folding_encode(self.body) - end - - def base64_decode - if /base64/i === self.transfer_encoding('') - store 'Content-Transfer-Encoding', '8bit' - self.body = Base64.decode(self.body, @config.strict_base64decode?) - end - end - - - def destinations( default = nil ) - ret = [] - %w( to cc bcc ).each do |nm| - if h = @header[nm] - h.addrs.each {|i| ret.push i.address } - end - end - ret.empty? ? default : ret - end - - def each_destination( &block ) - destinations([]).each do |i| - if Address === i - yield i - else - i.each(&block) - end - end - end - - alias each_dest each_destination - - - def reply_addresses( default = nil ) - reply_to_addrs(nil) or from_addrs(nil) or default - end - - def error_reply_addresses( default = nil ) - if s = sender(nil) - [s] - else - from_addrs(default) - end - end - - - def multipart? - main_type('').downcase == 'multipart' - end - - end # class Mail - -end # module TMail diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/info.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/info.rb deleted file mode 100755 index 5c115d58..00000000 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/info.rb +++ /dev/null @@ -1,35 +0,0 @@ -# -# info.rb -# -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# 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. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -module TMail - - Version = '0.10.7' - Copyright = 'Copyright (c) 1998-2002 Minero Aoki' - -end diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/interface.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/interface.rb deleted file mode 100644 index 957e8997..00000000 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/interface.rb +++ /dev/null @@ -1,540 +0,0 @@ -=begin rdoc - -= Facade.rb Provides an interface to the TMail object - -=end -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# 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. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -require 'tmail/utils' - -module TMail - - class Mail - - def header_string( name, default = nil ) - h = @header[name.downcase] or return default - h.to_s - end - - ### - ### attributes - ### - - include TextUtils - - def set_string_array_attr( key, strs ) - strs.flatten! - if strs.empty? - @header.delete key.downcase - else - store key, strs.join(', ') - end - strs - end - private :set_string_array_attr - - def set_string_attr( key, str ) - if str - store key, str - else - @header.delete key.downcase - end - str - end - private :set_string_attr - - def set_addrfield( name, arg ) - if arg - h = HeaderField.internal_new(name, @config) - h.addrs.replace [arg].flatten - @header[name] = h - else - @header.delete name - end - arg - end - private :set_addrfield - - def addrs2specs( addrs ) - return nil unless addrs - list = addrs.map {|addr| - if addr.address_group? - then addr.map {|a| a.spec } - else addr.spec - end - }.flatten - return nil if list.empty? - list - end - private :addrs2specs - - # - # date time - # - - def date( default = nil ) - if h = @header['date'] - h.date - else - default - end - end - - def date=( time ) - if time - store 'Date', time2str(time) - else - @header.delete 'date' - end - time - end - - def strftime( fmt, default = nil ) - if t = date - t.strftime(fmt) - else - default - end - end - - # - # destination - # - - def to_addrs( default = nil ) - if h = @header['to'] - h.addrs - else - default - end - end - - def cc_addrs( default = nil ) - if h = @header['cc'] - h.addrs - else - default - end - end - - def bcc_addrs( default = nil ) - if h = @header['bcc'] - h.addrs - else - default - end - end - - def to_addrs=( arg ) - set_addrfield 'to', arg - end - - def cc_addrs=( arg ) - set_addrfield 'cc', arg - end - - def bcc_addrs=( arg ) - set_addrfield 'bcc', arg - end - - def to( default = nil ) - addrs2specs(to_addrs(nil)) || default - end - - def cc( default = nil ) - addrs2specs(cc_addrs(nil)) || default - end - - def bcc( default = nil ) - addrs2specs(bcc_addrs(nil)) || default - end - - def to=( *strs ) - set_string_array_attr 'To', strs - end - - def cc=( *strs ) - set_string_array_attr 'Cc', strs - end - - def bcc=( *strs ) - set_string_array_attr 'Bcc', strs - end - - # - # originator - # - - def from_addrs( default = nil ) - if h = @header['from'] - h.addrs - else - default - end - end - - def from_addrs=( arg ) - set_addrfield 'from', arg - end - - def from( default = nil ) - addrs2specs(from_addrs(nil)) || default - end - - def from=( *strs ) - set_string_array_attr 'From', strs - end - - def friendly_from( default = nil ) - h = @header['from'] - a, = h.addrs - return default unless a - return a.phrase if a.phrase - return h.comments.join(' ') unless h.comments.empty? - a.spec - end - - - def reply_to_addrs( default = nil ) - if h = @header['reply-to'] - h.addrs - else - default - end - end - - def reply_to_addrs=( arg ) - set_addrfield 'reply-to', arg - end - - def reply_to( default = nil ) - addrs2specs(reply_to_addrs(nil)) || default - end - - def reply_to=( *strs ) - set_string_array_attr 'Reply-To', strs - end - - - def sender_addr( default = nil ) - f = @header['sender'] or return default - f.addr or return default - end - - def sender_addr=( addr ) - if addr - h = HeaderField.internal_new('sender', @config) - h.addr = addr - @header['sender'] = h - else - @header.delete 'sender' - end - addr - end - - def sender( default ) - f = @header['sender'] or return default - a = f.addr or return default - a.spec - end - - def sender=( str ) - set_string_attr 'Sender', str - end - - - # - # subject - # - - def subject( default = nil ) - if h = @header['subject'] - h.body - else - default - end - end - alias quoted_subject subject - - def subject=( str ) - set_string_attr 'Subject', str - end - - # - # identity & threading - # - - def message_id( default = nil ) - if h = @header['message-id'] - h.id || default - else - default - end - end - - def message_id=( str ) - set_string_attr 'Message-Id', str - end - - def in_reply_to( default = nil ) - if h = @header['in-reply-to'] - h.ids - else - default - end - end - - def in_reply_to=( *idstrs ) - set_string_array_attr 'In-Reply-To', idstrs - end - - def references( default = nil ) - if h = @header['references'] - h.refs - else - default - end - end - - def references=( *strs ) - set_string_array_attr 'References', strs - end - - # - # MIME headers - # - - def mime_version( default = nil ) - if h = @header['mime-version'] - h.version || default - else - default - end - end - - def mime_version=( m, opt = nil ) - if opt - if h = @header['mime-version'] - h.major = m - h.minor = opt - else - store 'Mime-Version', "#{m}.#{opt}" - end - else - store 'Mime-Version', m - end - m - end - - def content_type( default = nil ) - if h = @header['content-type'] - h.content_type || default - else - default - end - end - - def main_type( default = nil ) - if h = @header['content-type'] - h.main_type || default - else - default - end - end - - def sub_type( default = nil ) - if h = @header['content-type'] - h.sub_type || default - else - default - end - end - - def set_content_type( str, sub = nil, param = nil ) - if sub - main, sub = str, sub - else - main, sub = str.split(%r, 2) - raise ArgumentError, "sub type missing: #{str.inspect}" unless sub - end - if h = @header['content-type'] - h.main_type = main - h.sub_type = sub - h.params.clear - else - store 'Content-Type', "#{main}/#{sub}" - end - @header['content-type'].params.replace param if param - str - end - - alias content_type= set_content_type - - def type_param( name, default = nil ) - if h = @header['content-type'] - h[name] || default - else - default - end - end - - def charset( default = nil ) - if h = @header['content-type'] - h['charset'] or default - else - default - end - end - - def charset=( str ) - if str - if h = @header[ 'content-type' ] - h['charset'] = str - else - store 'Content-Type', "text/plain; charset=#{str}" - end - end - str - end - - def transfer_encoding( default = nil ) - if h = @header['content-transfer-encoding'] - h.encoding || default - else - default - end - end - - def transfer_encoding=( str ) - set_string_attr 'Content-Transfer-Encoding', str - end - - alias encoding transfer_encoding - alias encoding= transfer_encoding= - alias content_transfer_encoding transfer_encoding - alias content_transfer_encoding= transfer_encoding= - - def disposition( default = nil ) - if h = @header['content-disposition'] - h.disposition || default - else - default - end - end - - alias content_disposition disposition - - def set_disposition( str, params = nil ) - if h = @header['content-disposition'] - h.disposition = str - h.params.clear - else - store('Content-Disposition', str) - h = @header['content-disposition'] - end - h.params.replace params if params - end - - alias disposition= set_disposition - alias set_content_disposition set_disposition - alias content_disposition= set_disposition - - def disposition_param( name, default = nil ) - if h = @header['content-disposition'] - h[name] || default - else - default - end - end - - ### - ### utils - ### - - def create_reply - mail = TMail::Mail.parse('') - mail.subject = 'Re: ' + subject('').sub(/\A(?:\[[^\]]+\])?(?:\s*Re:)*\s*/i, '') - mail.to_addrs = reply_addresses([]) - mail.in_reply_to = [message_id(nil)].compact - mail.references = references([]) + [message_id(nil)].compact - mail.mime_version = '1.0' - mail - end - - def base64_encode - store 'Content-Transfer-Encoding', 'Base64' - self.body = Base64.folding_encode(self.body) - end - - def base64_decode - if /base64/i === self.transfer_encoding('') - store 'Content-Transfer-Encoding', '8bit' - self.body = Base64.decode(self.body, @config.strict_base64decode?) - end - end - - def destinations( default = nil ) - ret = [] - %w( to cc bcc ).each do |nm| - if h = @header[nm] - h.addrs.each {|i| ret.push i.address } - end - end - ret.empty? ? default : ret - end - - def each_destination( &block ) - destinations([]).each do |i| - if Address === i - yield i - else - i.each(&block) - end - end - end - - alias each_dest each_destination - - def reply_addresses( default = nil ) - reply_to_addrs(nil) or from_addrs(nil) or default - end - - def error_reply_addresses( default = nil ) - if s = sender(nil) - [s] - else - from_addrs(default) - end - end - - def multipart? - main_type('').downcase == 'multipart' - end - - end # class Mail - -end # module TMail diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/parser.y b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/parser.y deleted file mode 100644 index 77a14577..00000000 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/parser.y +++ /dev/null @@ -1,381 +0,0 @@ -# -# parser.y -# -# Copyright (c) 1998-2007 Minero Aoki -# -# This program is free software. -# You can distribute/modify this program under the terms of -# the GNU Lesser General Public License version 2.1. -# - -class TMail::Parser - - options no_result_var - -rule - - content : DATETIME datetime { val[1] } - | RECEIVED received { val[1] } - | MADDRESS addrs_TOP { val[1] } - | RETPATH retpath { val[1] } - | KEYWORDS keys { val[1] } - | ENCRYPTED enc { val[1] } - | MIMEVERSION version { val[1] } - | CTYPE ctype { val[1] } - | CENCODING cencode { val[1] } - | CDISPOSITION cdisp { val[1] } - | ADDRESS addr_TOP { val[1] } - | MAILBOX mbox { val[1] } - - datetime : day DIGIT ATOM DIGIT hour zone - # 0 1 2 3 4 5 - # date month year - { - t = Time.gm(val[3].to_i, val[2], val[1].to_i, 0, 0, 0) - (t + val[4] - val[5]).localtime - } - - day : /* none */ - | ATOM ',' - - hour : DIGIT ':' DIGIT - { - (val[0].to_i * 60 * 60) + - (val[2].to_i * 60) - } - | DIGIT ':' DIGIT ':' DIGIT - { - (val[0].to_i * 60 * 60) + - (val[2].to_i * 60) + - (val[4].to_i) - } - - zone : ATOM - { - timezone_string_to_unixtime(val[0]) - } - - received : from by via with id for received_datetime - { - val - } - - from : /* none */ - | FROM received_domain - { - val[1] - } - - by : /* none */ - | BY received_domain - { - val[1] - } - - received_domain - : domain - { - join_domain(val[0]) - } - | domain '@' domain - { - join_domain(val[2]) - } - | domain DOMLIT - { - join_domain(val[0]) - } - - via : /* none */ - | VIA ATOM - { - val[1] - } - - with : /* none */ - { - [] - } - | with WITH ATOM - { - val[0].push val[2] - val[0] - } - - id : /* none */ - | ID msgid - { - val[1] - } - | ID ATOM - { - val[1] - } - - for : /* none */ - | FOR received_addrspec - { - val[1] - } - - received_addrspec - : routeaddr - { - val[0].spec - } - | spec - { - val[0].spec - } - - received_datetime - : /* none */ - | ';' datetime - { - val[1] - } - - addrs_TOP : addrs - | group_bare - | addrs commas group_bare - - addr_TOP : mbox - | group - | group_bare - - retpath : addrs_TOP - | '<' '>' { [ Address.new(nil, nil) ] } - - addrs : addr - { - val - } - | addrs commas addr - { - val[0].push val[2] - val[0] - } - - addr : mbox - | group - - mboxes : mbox - { - val - } - | mboxes commas mbox - { - val[0].push val[2] - val[0] - } - - mbox : spec - | routeaddr - | addr_phrase routeaddr - { - val[1].phrase = Decoder.decode(val[0]) - val[1] - } - - group : group_bare ';' - - group_bare: addr_phrase ':' mboxes - { - AddressGroup.new(val[0], val[2]) - } - | addr_phrase ':' { AddressGroup.new(val[0], []) } - - addr_phrase - : local_head { val[0].join('.') } - | addr_phrase local_head { val[0] << ' ' << val[1].join('.') } - - routeaddr : '<' routes spec '>' - { - val[2].routes.replace val[1] - val[2] - } - | '<' spec '>' - { - val[1] - } - - routes : at_domains ':' - - at_domains: '@' domain { [ val[1].join('.') ] } - | at_domains ',' '@' domain { val[0].push val[3].join('.'); val[0] } - - spec : local '@' domain { Address.new( val[0], val[2] ) } - | local { Address.new( val[0], nil ) } - - local: local_head - | local_head '.' { val[0].push ''; val[0] } - - local_head: word - { val } - | local_head dots word - { - val[1].times do - val[0].push '' - end - val[0].push val[2] - val[0] - } - - domain : domword - { val } - | domain dots domword - { - val[1].times do - val[0].push '' - end - val[0].push val[2] - val[0] - } - - dots : '.' { 0 } - | '.' '.' { 1 } - - word : atom - | QUOTED - | DIGIT - - domword : atom - | DOMLIT - | DIGIT - - commas : ',' - | commas ',' - - msgid : '<' spec '>' - { - val[1] = val[1].spec - val.join('') - } - - keys : phrase { val } - | keys ',' phrase { val[0].push val[2]; val[0] } - - phrase : word - | phrase word { val[0] << ' ' << val[1] } - - enc : word - { - val.push nil - val - } - | word word - { - val - } - - version : DIGIT '.' DIGIT - { - [ val[0].to_i, val[2].to_i ] - } - - ctype : TOKEN '/' TOKEN params opt_semicolon - { - [ val[0].downcase, val[2].downcase, decode_params(val[3]) ] - } - | TOKEN params opt_semicolon - { - [ val[0].downcase, nil, decode_params(val[1]) ] - } - - params : /* none */ - { - {} - } - | params ';' TOKEN '=' QUOTED - { - val[0][ val[2].downcase ] = ('"' + val[4].to_s + '"') - val[0] - } - | params ';' TOKEN '=' TOKEN - { - val[0][ val[2].downcase ] = val[4] - val[0] - } - - cencode : TOKEN - { - val[0].downcase - } - - cdisp : TOKEN params opt_semicolon - { - [ val[0].downcase, decode_params(val[1]) ] - } - - opt_semicolon - : - | ';' - - atom : ATOM - | FROM - | BY - | VIA - | WITH - | ID - | FOR - -end - - ----- header -# -# parser.rb -# -# Copyright (c) 1998-2007 Minero Aoki -# -# This program is free software. -# You can distribute/modify this program under the terms of -# the GNU Lesser General Public License version 2.1. -# - -require 'tmail/scanner' -require 'tmail/utils' - ----- inner - - include TextUtils - - def self.parse( ident, str, cmt = nil ) - new.parse(ident, str, cmt) - end - - MAILP_DEBUG = false - - def initialize - self.debug = MAILP_DEBUG - end - - def debug=( flag ) - @yydebug = flag && Racc_debug_parser - @scanner_debug = flag - end - - def debug - @yydebug - end - - def parse( ident, str, comments = nil ) - @scanner = Scanner.new(str, ident, comments) - @scanner.debug = @scanner_debug - @first = [ident, ident] - result = yyparse(self, :parse_in) - comments.map! {|c| to_kcode(c) } if comments - result - end - - private - - def parse_in( &block ) - yield @first - @scanner.scan(&block) - end - - def on_error( t, val, vstack ) - raise SyntaxError, "parse error on token #{racc_token2str t}" - end - diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/tmail.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/tmail.rb deleted file mode 100755 index 57ed3cc5..00000000 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/tmail.rb +++ /dev/null @@ -1 +0,0 @@ -require 'tmail' diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail.rb old mode 100755 new mode 100644 similarity index 83% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail.rb index 7de18501..18003659 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail.rb @@ -2,3 +2,4 @@ require 'tmail/version' require 'tmail/mail' require 'tmail/mailbox' require 'tmail/core_extensions' +require 'tmail/net' diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/address.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/address.rb new file mode 100644 index 00000000..fa8e5bcd --- /dev/null +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/address.rb @@ -0,0 +1,426 @@ +=begin rdoc + += Address handling class + +=end +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# 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. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + +require 'tmail/encode' +require 'tmail/parser' + + +module TMail + + # = Class Address + # + # Provides a complete handling library for email addresses. Can parse a string of an + # address directly or take in preformatted addresses themseleves. Allows you to add + # and remove phrases from the front of the address and provides a compare function for + # email addresses. + # + # == Parsing and Handling a Valid Address: + # + # Just pass the email address in as a string to Address.parse: + # + # email = TMail::Address.parse('Mikel Lindsaar ) + # #=> # + # email.address + # #=> "mikel@lindsaar.net" + # email.local + # #=> "mikel" + # email.domain + # #=> "lindsaar.net" + # email.name # Aliased as phrase as well + # #=> "Mikel Lindsaar" + # + # == Detecting an Invalid Address + # + # If you want to check the syntactical validity of an email address, just pass it to + # Address.parse and catch any SyntaxError: + # + # begin + # TMail::Mail.parse("mikel 2@@@@@ me .com") + # rescue TMail::SyntaxError + # puts("Invalid Email Address Detected") + # else + # puts("Address is valid") + # end + # #=> "Invalid Email Address Detected" + class Address + + include TextUtils #:nodoc: + + # Sometimes you need to parse an address, TMail can do it for you and provide you with + # a fairly robust method of detecting a valid address. + # + # Takes in a string, returns a TMail::Address object. + # + # Raises a TMail::SyntaxError on invalid email format + def Address.parse( str ) + Parser.parse :ADDRESS, special_quote_address(str) + end + + def Address.special_quote_address(str) #:nodoc: + # Takes a string which is an address and adds quotation marks to special + # edge case methods that the RACC parser can not handle. + # + # Right now just handles two edge cases: + # + # Full stop as the last character of the display name: + # Mikel L. + # Returns: + # "Mikel L." + # + # Unquoted @ symbol in the display name: + # mikel@me.com + # Returns: + # "mikel@me.com" + # + # Any other address not matching these patterns just gets returned as is. + case + # This handles the missing "" in an older version of Apple Mail.app + # around the display name when the display name contains a '@' + # like 'mikel@me.com ' + # Just quotes it to: '"mikel@me.com" ' + when str =~ /\A([^"].+@.+[^"])\s(<.*?>)\Z/ + return "\"#{$1}\" #{$2}" + # This handles cases where 'Mikel A. ' which is a trailing + # full stop before the address section. Just quotes it to + # '"Mikel A. " + when str =~ /\A(.*?\.)\s(<.*?>)\Z/ + return "\"#{$1}\" #{$2}" + else + str + end + end + + def address_group? #:nodoc: + false + end + + # Address.new(local, domain) + # + # Accepts: + # + # * local - Left of the at symbol + # + # * domain - Array of the domain split at the periods. + # + # For example: + # + # Address.new("mikel", ["lindsaar", "net"]) + # #=> "#" + def initialize( local, domain ) + if domain + domain.each do |s| + raise SyntaxError, 'empty word in domain' if s.empty? + end + end + + # This is to catch an unquoted "@" symbol in the local part of the + # address. Handles addresses like <"@"@me.com> and makes sure they + # stay like <"@"@me.com> (previously were becomming <@@me.com>) + if local && (local.join == '@' || local.join =~ /\A[^"].*?@.*?[^"]\Z/) + @local = "\"#{local.join}\"" + else + @local = local + end + + @domain = domain + @name = nil + @routes = [] + end + + # Provides the name or 'phrase' of the email address. + # + # For Example: + # + # email = TMail::Address.parse("Mikel Lindsaar ") + # email.name + # #=> "Mikel Lindsaar" + def name + @name + end + + # Setter method for the name or phrase of the email + # + # For Example: + # + # email = TMail::Address.parse("mikel@lindsaar.net") + # email.name + # #=> nil + # email.name = "Mikel Lindsaar" + # email.to_s + # #=> "Mikel Lindsaar " + def name=( str ) + @name = str + @name = nil if str and str.empty? + end + + #:stopdoc: + alias phrase name + alias phrase= name= + #:startdoc: + + # This is still here from RFC 822, and is now obsolete per RFC2822 Section 4. + # + # "When interpreting addresses, the route portion SHOULD be ignored." + # + # It is still here, so you can access it. + # + # Routes return the route portion at the front of the email address, if any. + # + # For Example: + # email = TMail::Address.parse( "<@sa,@another:Mikel@me.com>") + # => # + # email.to_s + # => "<@sa,@another:Mikel@me.com>" + # email.routes + # => ["sa", "another"] + def routes + @routes + end + + def inspect #:nodoc: + "#<#{self.class} #{address()}>" + end + + # Returns the local part of the email address + # + # For Example: + # + # email = TMail::Address.parse("mikel@lindsaar.net") + # email.local + # #=> "mikel" + def local + return nil unless @local + return '""' if @local.size == 1 and @local[0].empty? + # Check to see if it is an array before trying to map it + if @local.respond_to?(:map) + @local.map {|i| quote_atom(i) }.join('.') + else + quote_atom(@local) + end + end + + # Returns the domain part of the email address + # + # For Example: + # + # email = TMail::Address.parse("mikel@lindsaar.net") + # email.local + # #=> "lindsaar.net" + def domain + return nil unless @domain + join_domain(@domain) + end + + # Returns the full specific address itself + # + # For Example: + # + # email = TMail::Address.parse("mikel@lindsaar.net") + # email.address + # #=> "mikel@lindsaar.net" + def spec + s = self.local + d = self.domain + if s and d + s + '@' + d + else + s + end + end + + alias address spec + + # Provides == function to the email. Only checks the actual address + # and ignores the name/phrase component + # + # For Example + # + # addr1 = TMail::Address.parse("My Address ") + # #=> "#" + # addr2 = TMail::Address.parse("Another ") + # #=> "#" + # addr1 == addr2 + # #=> true + def ==( other ) + other.respond_to? :spec and self.spec == other.spec + end + + alias eql? == + + # Provides a unique hash value for this record against the local and domain + # parts, ignores the name/phrase value + # + # email = TMail::Address.parse("mikel@lindsaar.net") + # email.hash + # #=> 18767598 + def hash + @local.hash ^ @domain.hash + end + + # Duplicates a TMail::Address object returning the duplicate + # + # addr1 = TMail::Address.parse("mikel@lindsaar.net") + # addr2 = addr1.dup + # addr1.id == addr2.id + # #=> false + def dup + obj = self.class.new(@local.dup, @domain.dup) + obj.name = @name.dup if @name + obj.routes.replace @routes + obj + end + + include StrategyInterface #:nodoc: + + def accept( strategy, dummy1 = nil, dummy2 = nil ) #:nodoc: + unless @local + strategy.meta '<>' # empty return-path + return + end + + spec_p = (not @name and @routes.empty?) + if @name + strategy.phrase @name + strategy.space + end + tmp = spec_p ? '' : '<' + unless @routes.empty? + tmp << @routes.map {|i| '@' + i }.join(',') << ':' + end + tmp << self.spec + tmp << '>' unless spec_p + strategy.meta tmp + strategy.lwsp '' + end + + end + + + class AddressGroup + + include Enumerable + + def address_group? + true + end + + def initialize( name, addrs ) + @name = name + @addresses = addrs + end + + attr_reader :name + + def ==( other ) + other.respond_to? :to_a and @addresses == other.to_a + end + + alias eql? == + + def hash + map {|i| i.hash }.hash + end + + def []( idx ) + @addresses[idx] + end + + def size + @addresses.size + end + + def empty? + @addresses.empty? + end + + def each( &block ) + @addresses.each(&block) + end + + def to_a + @addresses.dup + end + + alias to_ary to_a + + def include?( a ) + @addresses.include? a + end + + def flatten + set = [] + @addresses.each do |a| + if a.respond_to? :flatten + set.concat a.flatten + else + set.push a + end + end + set + end + + def each_address( &block ) + flatten.each(&block) + end + + def add( a ) + @addresses.push a + end + + alias push add + + def delete( a ) + @addresses.delete a + end + + include StrategyInterface + + def accept( strategy, dummy1 = nil, dummy2 = nil ) + strategy.phrase @name + strategy.meta ':' + strategy.space + first = true + each do |mbox| + if first + first = false + else + strategy.meta ',' + end + strategy.space + mbox.accept strategy + end + strategy.meta ';' + strategy.lwsp '' + end + + end + +end # module TMail diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/attachments.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/attachments.rb similarity index 86% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/attachments.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/attachments.rb index a8b8017c..5dc5efae 100644 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/attachments.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/attachments.rb @@ -1,6 +1,6 @@ =begin rdoc -= Attachment handling class += Attachment handling file =end @@ -17,8 +17,7 @@ module TMail end def attachment?(part) - (part['content-disposition'] && part['content-disposition'].disposition == "attachment") || - part.header['content-type'].main_type != "text" + part.disposition_is_attachment? || part.content_type_is_text? end def attachments diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/base64.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/base64.rb old mode 100755 new mode 100644 similarity index 97% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/base64.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/base64.rb index e99b6b0b..e294c629 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/base64.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/base64.rb @@ -1,9 +1,4 @@ -# = TITLE: -# -# Base64 -# -# = COPYRIGHT: -# +#-- # Copyright (c) 1998-2003 Minero Aoki # # Permission is hereby granted, free of charge, to any person obtaining @@ -27,10 +22,9 @@ # # Note: Originally licensed under LGPL v2+. Using MIT license for Rails # with permission of Minero Aoki. - -# +#++ +#:stopdoc: module TMail - module Base64 module_function @@ -48,5 +42,5 @@ module TMail end end - end +#:startdoc: diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/compat.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/compat.rb similarity index 70% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/compat.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/compat.rb index 9d2aa837..1275df79 100644 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/compat.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/compat.rb @@ -1,17 +1,18 @@ -unless Enumerable.method_defined?(:map) - module Enumerable +#:stopdoc: +unless Enumerable.method_defined?(:map) + module Enumerable #:nodoc: alias map collect end end unless Enumerable.method_defined?(:select) - module Enumerable + module Enumerable #:nodoc: alias select find_all end end unless Enumerable.method_defined?(:reject) - module Enumerable + module Enumerable #:nodoc: def reject result = [] each do |i| @@ -23,7 +24,7 @@ unless Enumerable.method_defined?(:reject) end unless Enumerable.method_defined?(:sort_by) - module Enumerable + module Enumerable #:nodoc: def sort_by map {|i| [yield(i), i] }.sort.map {|val, i| i } end @@ -31,9 +32,10 @@ unless Enumerable.method_defined?(:sort_by) end unless File.respond_to?(:read) - def File.read(fname) + def File.read(fname) #:nodoc: File.open(fname) {|f| return f.read } end end +#:startdoc: \ No newline at end of file diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/config.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/config.rb old mode 100755 new mode 100644 similarity index 97% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/config.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/config.rb index 4b253d2b..3a876dcd --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/config.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/config.rb @@ -1,8 +1,3 @@ -=begin rdoc - -= Configuration Class - -=end #-- # Copyright (c) 1998-2003 Minero Aoki # @@ -28,7 +23,7 @@ # Note: Originally licensed under LGPL v2+. Using MIT license for Rails # with permission of Minero Aoki. #++ - +#:stopdoc: module TMail class Config @@ -69,3 +64,4 @@ module TMail end end +#:startdoc: \ No newline at end of file diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/core_extensions.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/core_extensions.rb similarity index 65% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/core_extensions.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/core_extensions.rb index cc24e977..da62c33b 100644 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/core_extensions.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/core_extensions.rb @@ -1,14 +1,9 @@ -=begin rdoc - -= Ruby on Rails Core Extensions - -provides .blank? - -=end -unless Object.respond_to?(:blank?) #:nodoc: - # Check first to see if we are in a Rails environment, no need to - # define these methods if we are +#:stopdoc: +unless Object.respond_to?(:blank?) class Object + # Check first to see if we are in a Rails environment, no need to + # define these methods if we are + # An object is blank if it's nil, empty, or a whitespace string. # For example, "", " ", nil, [], and {} are blank. # @@ -27,41 +22,42 @@ unless Object.respond_to?(:blank?) #:nodoc: end end - class NilClass #:nodoc: + class NilClass def blank? true end end - class FalseClass #:nodoc: + class FalseClass def blank? true end end - class TrueClass #:nodoc: + class TrueClass def blank? false end end - class Array #:nodoc: + class Array alias_method :blank?, :empty? end - class Hash #:nodoc: + class Hash alias_method :blank?, :empty? end - class String #:nodoc: + class String def blank? empty? || strip.empty? end end - class Numeric #:nodoc: + class Numeric def blank? false end end -end \ No newline at end of file +end +#:startdoc: \ No newline at end of file diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/encode.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/encode.rb old mode 100755 new mode 100644 similarity index 66% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/encode.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/encode.rb index 0721a254..63bccce4 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/encode.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/encode.rb @@ -1,41 +1,45 @@ -=begin rdoc - -= Text Encoding class - -=end #-- -# Copyright (c) 1998-2003 Minero Aoki +# = COPYRIGHT: # -# 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: +# Copyright (c) 1998-2003 Minero Aoki # -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. +# 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 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. +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. # -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. +# 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. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. #++ - +#:stopdoc: require 'nkf' -require 'tmail/base64.rb' +require 'tmail/base64' require 'tmail/stringio' require 'tmail/utils' +#:startdoc: module TMail + + #:stopdoc: + class << self + attr_accessor :KCODE + end + self.KCODE = 'NONE' module StrategyInterface @@ -52,27 +56,52 @@ module TMail end end module_function :create_dest - + + #:startdoc: + # Returns the TMail object encoded and ready to be sent via SMTP etc. + # You should call this before you are packaging up your email to + # correctly escape all the values that need escaping in the email, line + # wrap the email etc. + # + # It is also a good idea to call this before you marshal or serialize + # a TMail object. + # + # For Example: + # + # email = TMail::Load(my_email_file) + # email_to_send = email.encoded def encoded( eol = "\r\n", charset = 'j', dest = nil ) accept_strategy Encoder, eol, charset, dest end - + + # Returns the TMail object decoded and ready to be used by you, your + # program etc. + # + # You should call this before you are packaging up your email to + # correctly escape all the values that need escaping in the email, line + # wrap the email etc. + # + # For Example: + # + # email = TMail::Load(my_email_file) + # email_to_send = email.encoded def decoded( eol = "\n", charset = 'e', dest = nil ) # Turn the E-Mail into a string and return it with all # encoded characters decoded. alias for to_s accept_strategy Decoder, eol, charset, dest end - + alias to_s decoded - - def accept_strategy( klass, eol, charset, dest = nil ) + + def accept_strategy( klass, eol, charset, dest = nil ) #:nodoc: dest ||= '' accept klass.new( create_dest(dest), charset, eol ) dest end - + end + #:stopdoc: ### ### MIME B encoding decoder @@ -91,8 +120,8 @@ module TMail } def self.decode( str, encoding = nil ) - encoding ||= (OUTPUT_ENCODING[$KCODE] || 'j') - opt = '-m' + encoding + encoding ||= (OUTPUT_ENCODING[TMail.KCODE] || 'j') + opt = '-mS' + encoding str.gsub(ENCODED_WORDS) {|s| NKF.nkf(opt, s) } end @@ -121,7 +150,7 @@ module TMail def header_body( str ) @f << decode(str) end - + def space @f << ' ' end @@ -131,7 +160,7 @@ module TMail def lwsp( str ) @f << str end - + def meta( str ) @f << str end @@ -182,7 +211,8 @@ module TMail end SPACER = "\t" - MAX_LINE_LEN = 70 + MAX_LINE_LEN = 78 + RFC_2822_MAX_LENGTH = 998 OPTIONS = { 'EUC' => '-Ej -m0', @@ -193,8 +223,9 @@ module TMail def initialize( dest = nil, encoding = nil, eol = "\r\n", limit = nil ) @f = StrategyInterface.create_dest(dest) - @opt = OPTIONS[$KCODE] + @opt = OPTIONS[TMail.KCODE] @eol = eol + @folded = false @preserve_quotes = true reset end @@ -202,7 +233,7 @@ module TMail def preserve_quotes=( bool ) @preserve_quotes end - + def preserve_quotes @preserve_quotes end @@ -367,18 +398,23 @@ module TMail end def concat_A_S( types, strs ) + if RUBY_VERSION < '1.9' + a = ?a; s = ?s + else + a = 'a'.ord; s = 's'.ord + end i = 0 types.each_byte do |t| case t - when ?a then add_text strs[i] - when ?s then add_lwsp strs[i] + when a then add_text strs[i] + when s then add_lwsp strs[i] else raise "TMail FATAL: unknown flag: #{t.chr}" end i += 1 end end - + METHOD_ID = { ?j => :extract_J, ?e => :extract_E, @@ -451,31 +487,75 @@ module TMail # puts '---- lwsp -------------------------------------' # puts "+ #{lwsp.inspect}" fold if restsize() <= 0 - flush + flush(@folded) @lwsp = lwsp end - def flush + def flush(folded = false) # puts '---- flush ----' # puts "spc >>>#{@lwsp.inspect}<<<" # puts "txt >>>#{@text.inspect}<<<" @f << @lwsp << @text - @curlen += (@lwsp.size + @text.size) + if folded + @curlen = 0 + else + @curlen += (@lwsp.size + @text.size) + end @text = '' @lwsp = '' end def fold # puts '---- fold ----' - @f << @eol + unless @f.string =~ /^.*?:$/ + @f << @eol + @lwsp = SPACER + else + fold_header + @folded = true + end @curlen = 0 - @lwsp = SPACER + end + + def fold_header + # Called because line is too long - so we need to wrap. + # First look for whitespace in the text + # if it has text, fold there + # check the remaining text, if too long, fold again + # if it doesn't, then don't fold unless the line goes beyond 998 chars + + # Check the text to see if there is whitespace, or if not + @wrapped_text = [] + until @text.blank? + fold_the_string + end + @text = @wrapped_text.join("#{@eol}#{SPACER}") + end + + def fold_the_string + whitespace_location = @text =~ /\s/ || @text.length + # Is the location of the whitespace shorter than the RCF_2822_MAX_LENGTH? + # if there is no whitespace in the string, then this + unless mazsize(whitespace_location) <= 0 + @text.strip! + @wrapped_text << @text.slice!(0...whitespace_location) + # If it is not less, we have to wrap it destructively + else + slice_point = RFC_2822_MAX_LENGTH - @curlen - @lwsp.length + @text.strip! + @wrapped_text << @text.slice!(0...slice_point) + end end def restsize MAX_LINE_LEN - (@curlen + @lwsp.size + @text.size) end - end + def mazsize(whitespace_location) + # Per RFC2822, the maximum length of a line is 998 chars + RFC_2822_MAX_LENGTH - (@curlen + @lwsp.size + whitespace_location) + end + end + #:startdoc: end # module TMail diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/header.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/header.rb old mode 100755 new mode 100644 similarity index 89% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/header.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/header.rb index 41c371f3..9153dcd7 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/header.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/header.rb @@ -1,11 +1,3 @@ -=begin rdoc - -= Header handling class - -=end -# RFC #822 ftp://ftp.isi.edu/in-notes/rfc822.txt -# -# #-- # Copyright (c) 1998-2003 Minero Aoki # @@ -38,9 +30,10 @@ require 'tmail/parser' require 'tmail/config' require 'tmail/utils' - +#:startdoc: module TMail + # Provides methods to handle and manipulate headers in the email class HeaderField include TextUtils @@ -54,8 +47,40 @@ module TMail klass.newobj body, conf end + # Returns a HeaderField object matching the header you specify in the "name" param. + # Requires an initialized TMail::Port to be passed in. + # + # The method searches the header of the Port you pass into it to find a match on + # the header line you pass. Once a match is found, it will unwrap the matching line + # as needed to return an initialized HeaderField object. + # + # If you want to get the Envelope sender of the email object, pass in "EnvelopeSender", + # if you want the From address of the email itself, pass in 'From'. + # + # This is because a mailbox doesn't have the : after the From that designates the + # beginning of the envelope sender (which can be different to the from address of + # the emial) + # + # Other fields can be passed as normal, "Reply-To", "Received" etc. + # + # Note: Change of behaviour in 1.2.1 => returns nil if it does not find the specified + # header field, otherwise returns an instantiated object of the correct header class + # + # For example: + # port = TMail::FilePort.new("/test/fixtures/raw_email_simple") + # h = TMail::HeaderField.new_from_port(port, "From") + # h.addrs.to_s #=> "Mikel Lindsaar " + # h = TMail::HeaderField.new_from_port(port, "EvelopeSender") + # h.addrs.to_s #=> "mike@anotherplace.com.au" + # h = TMail::HeaderField.new_from_port(port, "SomeWeirdHeaderField") + # h #=> nil def new_from_port( port, name, conf = DEFAULT_CONFIG ) - re = Regep.new('\A(' + Regexp.quote(name) + '):', 'i') + if name == "EnvelopeSender" + name = "From" + re = Regexp.new('\A(From) ', 'i') + else + re = Regexp.new('\A(' + Regexp.quote(name) + '):', 'i') + end str = nil port.ropen {|f| f.each do |line| @@ -66,7 +91,7 @@ module TMail end end } - new(name, str, Config.to_config(conf)) + new(name, str, Config.to_config(conf)) if str end def internal_new( name, conf ) @@ -182,7 +207,11 @@ module TMail def comments ensure_parsed - @comments + if @comments[0] + [Decoder.decode(@comments[0])] + else + @comments + end end private diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/index.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/index.rb new file mode 100644 index 00000000..554e2fd6 --- /dev/null +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/index.rb @@ -0,0 +1,9 @@ +#:stopdoc: +# This is here for Rolls. +# Rolls uses this instead of lib/tmail.rb. + +require 'tmail/version' +require 'tmail/mail' +require 'tmail/mailbox' +require 'tmail/core_extensions' +#:startdoc: \ No newline at end of file diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/interface.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/interface.rb new file mode 100644 index 00000000..206653bd --- /dev/null +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/interface.rb @@ -0,0 +1,1125 @@ +=begin rdoc + += interface.rb Provides an interface to the TMail object + +=end +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# 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. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + +# TMail::Mail objects get accessed primarily through the methods in this file. +# +# + +require 'tmail/utils' + +module TMail + + class Mail + + # Allows you to query the mail object with a string to get the contents + # of the field you want. + # + # Returns a string of the exact contnts of the field + # + # mail.from = "mikel " + # mail.header_string("From") #=> "mikel " + def header_string( name, default = nil ) + h = @header[name.downcase] or return default + h.to_s + end + + #:stopdoc: + #-- + #== Attributes + + include TextUtils + + def set_string_array_attr( key, strs ) + strs.flatten! + if strs.empty? + @header.delete key.downcase + else + store key, strs.join(', ') + end + strs + end + private :set_string_array_attr + + def set_string_attr( key, str ) + if str + store key, str + else + @header.delete key.downcase + end + str + end + private :set_string_attr + + def set_addrfield( name, arg ) + if arg + h = HeaderField.internal_new(name, @config) + h.addrs.replace [arg].flatten + @header[name] = h + else + @header.delete name + end + arg + end + private :set_addrfield + + def addrs2specs( addrs ) + return nil unless addrs + list = addrs.map {|addr| + if addr.address_group? + then addr.map {|a| a.spec } + else addr.spec + end + }.flatten + return nil if list.empty? + list + end + private :addrs2specs + + #:startdoc: + + #== Date and Time methods + + # Returns the date of the email message as per the "date" header value or returns + # nil by default (if no date field exists). + # + # You can also pass whatever default you want into this method and it will return + # that instead of nil if there is no date already set. + def date( default = nil ) + if h = @header['date'] + h.date + else + default + end + end + + # Destructively sets the date of the mail object with the passed Time instance, + # returns a Time instance set to the date/time of the mail + # + # Example: + # + # now = Time.now + # mail.date = now + # mail.date #=> Sat Nov 03 18:47:50 +1100 2007 + # mail.date.class #=> Time + def date=( time ) + if time + store 'Date', time2str(time) + else + @header.delete 'date' + end + time + end + + # Returns the time of the mail message formatted to your taste using a + # strftime format string. If no date set returns nil by default or whatever value + # you pass as the second optional parameter. + # + # time = Time.now # (on Nov 16 2007) + # mail.date = time + # mail.strftime("%D") #=> "11/16/07" + def strftime( fmt, default = nil ) + if t = date + t.strftime(fmt) + else + default + end + end + + #== Destination methods + + # Return a TMail::Addresses instance for each entry in the "To:" field of the mail object header. + # + # If the "To:" field does not exist, will return nil by default or the value you + # pass as the optional parameter. + # + # Example: + # + # mail = TMail::Mail.new + # mail.to_addrs #=> nil + # mail.to_addrs([]) #=> [] + # mail.to = "Mikel , another Mikel " + # mail.to_addrs #=> [#, #] + def to_addrs( default = nil ) + if h = @header['to'] + h.addrs + else + default + end + end + + # Return a TMail::Addresses instance for each entry in the "Cc:" field of the mail object header. + # + # If the "Cc:" field does not exist, will return nil by default or the value you + # pass as the optional parameter. + # + # Example: + # + # mail = TMail::Mail.new + # mail.cc_addrs #=> nil + # mail.cc_addrs([]) #=> [] + # mail.cc = "Mikel , another Mikel " + # mail.cc_addrs #=> [#, #] + def cc_addrs( default = nil ) + if h = @header['cc'] + h.addrs + else + default + end + end + + # Return a TMail::Addresses instance for each entry in the "Bcc:" field of the mail object header. + # + # If the "Bcc:" field does not exist, will return nil by default or the value you + # pass as the optional parameter. + # + # Example: + # + # mail = TMail::Mail.new + # mail.bcc_addrs #=> nil + # mail.bcc_addrs([]) #=> [] + # mail.bcc = "Mikel , another Mikel " + # mail.bcc_addrs #=> [#, #] + def bcc_addrs( default = nil ) + if h = @header['bcc'] + h.addrs + else + default + end + end + + # Destructively set the to field of the "To:" header to equal the passed in string. + # + # TMail will parse your contents and turn each valid email address into a TMail::Address + # object before assigning it to the mail message. + # + # Example: + # + # mail = TMail::Mail.new + # mail.to = "Mikel , another Mikel " + # mail.to_addrs #=> [#, #] + def to_addrs=( arg ) + set_addrfield 'to', arg + end + + # Destructively set the to field of the "Cc:" header to equal the passed in string. + # + # TMail will parse your contents and turn each valid email address into a TMail::Address + # object before assigning it to the mail message. + # + # Example: + # + # mail = TMail::Mail.new + # mail.cc = "Mikel , another Mikel " + # mail.cc_addrs #=> [#, #] + def cc_addrs=( arg ) + set_addrfield 'cc', arg + end + + # Destructively set the to field of the "Bcc:" header to equal the passed in string. + # + # TMail will parse your contents and turn each valid email address into a TMail::Address + # object before assigning it to the mail message. + # + # Example: + # + # mail = TMail::Mail.new + # mail.bcc = "Mikel , another Mikel " + # mail.bcc_addrs #=> [#, #] + def bcc_addrs=( arg ) + set_addrfield 'bcc', arg + end + + # Returns who the email is to as an Array of email addresses as opposed to an Array of + # TMail::Address objects which is what Mail#to_addrs returns + # + # Example: + # + # mail = TMail::Mail.new + # mail.to = "Mikel , another Mikel " + # mail.to #=> ["mikel@me.org", "mikel@you.org"] + def to( default = nil ) + addrs2specs(to_addrs(nil)) || default + end + + # Returns who the email cc'd as an Array of email addresses as opposed to an Array of + # TMail::Address objects which is what Mail#to_addrs returns + # + # Example: + # + # mail = TMail::Mail.new + # mail.cc = "Mikel , another Mikel " + # mail.cc #=> ["mikel@me.org", "mikel@you.org"] + def cc( default = nil ) + addrs2specs(cc_addrs(nil)) || default + end + + # Returns who the email bcc'd as an Array of email addresses as opposed to an Array of + # TMail::Address objects which is what Mail#to_addrs returns + # + # Example: + # + # mail = TMail::Mail.new + # mail.bcc = "Mikel , another Mikel " + # mail.bcc #=> ["mikel@me.org", "mikel@you.org"] + def bcc( default = nil ) + addrs2specs(bcc_addrs(nil)) || default + end + + # Destructively sets the "To:" field to the passed array of strings (which should be valid + # email addresses) + # + # Example: + # + # mail = TMail::Mail.new + # mail.to = ["mikel@abc.com", "Mikel "] + # mail.to #=> ["mikel@abc.org", "mikel@xyz.org"] + # mail['to'].to_s #=> "mikel@abc.com, Mikel " + def to=( *strs ) + set_string_array_attr 'To', strs + end + + # Destructively sets the "Cc:" field to the passed array of strings (which should be valid + # email addresses) + # + # Example: + # + # mail = TMail::Mail.new + # mail.cc = ["mikel@abc.com", "Mikel "] + # mail.cc #=> ["mikel@abc.org", "mikel@xyz.org"] + # mail['cc'].to_s #=> "mikel@abc.com, Mikel " + def cc=( *strs ) + set_string_array_attr 'Cc', strs + end + + # Destructively sets the "Bcc:" field to the passed array of strings (which should be valid + # email addresses) + # + # Example: + # + # mail = TMail::Mail.new + # mail.bcc = ["mikel@abc.com", "Mikel "] + # mail.bcc #=> ["mikel@abc.org", "mikel@xyz.org"] + # mail['bcc'].to_s #=> "mikel@abc.com, Mikel " + def bcc=( *strs ) + set_string_array_attr 'Bcc', strs + end + + #== Originator methods + + # Return a TMail::Addresses instance for each entry in the "From:" field of the mail object header. + # + # If the "From:" field does not exist, will return nil by default or the value you + # pass as the optional parameter. + # + # Example: + # + # mail = TMail::Mail.new + # mail.from_addrs #=> nil + # mail.from_addrs([]) #=> [] + # mail.from = "Mikel , another Mikel " + # mail.from_addrs #=> [#, #] + def from_addrs( default = nil ) + if h = @header['from'] + h.addrs + else + default + end + end + + # Destructively set the to value of the "From:" header to equal the passed in string. + # + # TMail will parse your contents and turn each valid email address into a TMail::Address + # object before assigning it to the mail message. + # + # Example: + # + # mail = TMail::Mail.new + # mail.from_addrs = "Mikel , another Mikel " + # mail.from_addrs #=> [#, #] + def from_addrs=( arg ) + set_addrfield 'from', arg + end + + # Returns who the email is from as an Array of email address strings instead to an Array of + # TMail::Address objects which is what Mail#from_addrs returns + # + # Example: + # + # mail = TMail::Mail.new + # mail.from = "Mikel , another Mikel " + # mail.from #=> ["mikel@me.org", "mikel@you.org"] + def from( default = nil ) + addrs2specs(from_addrs(nil)) || default + end + + # Destructively sets the "From:" field to the passed array of strings (which should be valid + # email addresses) + # + # Example: + # + # mail = TMail::Mail.new + # mail.from = ["mikel@abc.com", "Mikel "] + # mail.from #=> ["mikel@abc.org", "mikel@xyz.org"] + # mail['from'].to_s #=> "mikel@abc.com, Mikel " + def from=( *strs ) + set_string_array_attr 'From', strs + end + + # Returns the "friendly" human readable part of the address + # + # Example: + # + # mail = TMail::Mail.new + # mail.from = "Mikel Lindsaar " + # mail.friendly_from #=> "Mikel Lindsaar" + def friendly_from( default = nil ) + h = @header['from'] + a, = h.addrs + return default unless a + return a.phrase if a.phrase + return h.comments.join(' ') unless h.comments.empty? + a.spec + end + + # Return a TMail::Addresses instance for each entry in the "Reply-To:" field of the mail object header. + # + # If the "Reply-To:" field does not exist, will return nil by default or the value you + # pass as the optional parameter. + # + # Example: + # + # mail = TMail::Mail.new + # mail.reply_to_addrs #=> nil + # mail.reply_to_addrs([]) #=> [] + # mail.reply_to = "Mikel , another Mikel " + # mail.reply_to_addrs #=> [#, #] + def reply_to_addrs( default = nil ) + if h = @header['reply-to'] + h.addrs.blank? ? default : h.addrs + else + default + end + end + + # Destructively set the to value of the "Reply-To:" header to equal the passed in argument. + # + # TMail will parse your contents and turn each valid email address into a TMail::Address + # object before assigning it to the mail message. + # + # Example: + # + # mail = TMail::Mail.new + # mail.reply_to_addrs = "Mikel , another Mikel " + # mail.reply_to_addrs #=> [#, #] + def reply_to_addrs=( arg ) + set_addrfield 'reply-to', arg + end + + # Returns who the email is from as an Array of email address strings instead to an Array of + # TMail::Address objects which is what Mail#reply_to_addrs returns + # + # Example: + # + # mail = TMail::Mail.new + # mail.reply_to = "Mikel , another Mikel " + # mail.reply_to #=> ["mikel@me.org", "mikel@you.org"] + def reply_to( default = nil ) + addrs2specs(reply_to_addrs(nil)) || default + end + + # Destructively sets the "Reply-To:" field to the passed array of strings (which should be valid + # email addresses) + # + # Example: + # + # mail = TMail::Mail.new + # mail.reply_to = ["mikel@abc.com", "Mikel "] + # mail.reply_to #=> ["mikel@abc.org", "mikel@xyz.org"] + # mail['reply_to'].to_s #=> "mikel@abc.com, Mikel " + def reply_to=( *strs ) + set_string_array_attr 'Reply-To', strs + end + + # Return a TMail::Addresses instance of the "Sender:" field of the mail object header. + # + # If the "Sender:" field does not exist, will return nil by default or the value you + # pass as the optional parameter. + # + # Example: + # + # mail = TMail::Mail.new + # mail.sender #=> nil + # mail.sender([]) #=> [] + # mail.sender = "Mikel " + # mail.reply_to_addrs #=> [#] + def sender_addr( default = nil ) + f = @header['sender'] or return default + f.addr or return default + end + + # Destructively set the to value of the "Sender:" header to equal the passed in argument. + # + # TMail will parse your contents and turn each valid email address into a TMail::Address + # object before assigning it to the mail message. + # + # Example: + # + # mail = TMail::Mail.new + # mail.sender_addrs = "Mikel , another Mikel " + # mail.sender_addrs #=> [#, #] + def sender_addr=( addr ) + if addr + h = HeaderField.internal_new('sender', @config) + h.addr = addr + @header['sender'] = h + else + @header.delete 'sender' + end + addr + end + + # Returns who the sender of this mail is as string instead to an Array of + # TMail::Address objects which is what Mail#sender_addr returns + # + # Example: + # + # mail = TMail::Mail.new + # mail.sender = "Mikel " + # mail.sender #=> "mikel@me.org" + def sender( default = nil ) + f = @header['sender'] or return default + a = f.addr or return default + a.spec + end + + # Destructively sets the "Sender:" field to the passed string (which should be a valid + # email address) + # + # Example: + # + # mail = TMail::Mail.new + # mail.sender = "mikel@abc.com" + # mail.sender #=> "mikel@abc.org" + # mail['sender'].to_s #=> "mikel@abc.com" + def sender=( str ) + set_string_attr 'Sender', str + end + + #== Subject methods + + # Returns the subject of the mail instance. + # + # If the subject field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.subject #=> nil + # mail.subject("") #=> "" + # mail.subject = "Hello" + # mail.subject #=> "Hello" + def subject( default = nil ) + if h = @header['subject'] + h.body + else + default + end + end + alias quoted_subject subject + + # Destructively sets the passed string as the subject of the mail message. + # + # Example + # + # mail = TMail::Mail.new + # mail.subject #=> "This subject" + # mail.subject = "Another subject" + # mail.subject #=> "Another subject" + def subject=( str ) + set_string_attr 'Subject', str + end + + #== Message Identity & Threading Methods + + # Returns the message ID for this mail object instance. + # + # If the message_id field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.message_id #=> nil + # mail.message_id(TMail.new_message_id) #=> "<47404c5326d9c_2ad4fbb80161@baci.local.tmail>" + # mail.message_id = TMail.new_message_id + # mail.message_id #=> "<47404c5326d9c_2ad4fbb80161@baci.local.tmail>" + def message_id( default = nil ) + if h = @header['message-id'] + h.id || default + else + default + end + end + + # Destructively sets the message ID of the mail object instance to the passed in string + # + # Example: + # + # mail = TMail::Mail.new + # mail.message_id = "this_is_my_badly_formatted_message_id" + # mail.message_id #=> "this_is_my_badly_formatted_message_id" + def message_id=( str ) + set_string_attr 'Message-Id', str + end + + # Returns the "In-Reply-To:" field contents as an array of this mail instance if it exists + # + # If the in_reply_to field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.in_reply_to #=> nil + # mail.in_reply_to([]) #=> [] + # TMail::Mail.load("../test/fixtures/raw_email_reply") + # mail.in_reply_to #=> ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] + def in_reply_to( default = nil ) + if h = @header['in-reply-to'] + h.ids + else + default + end + end + + # Destructively sets the value of the "In-Reply-To:" field of an email. + # + # Accepts an array of a single string of a message id + # + # Example: + # + # mail = TMail::Mail.new + # mail.in_reply_to = ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] + # mail.in_reply_to #=> ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] + def in_reply_to=( *idstrs ) + set_string_array_attr 'In-Reply-To', idstrs + end + + # Returns the references of this email (prior messages relating to this message) + # as an array of message ID strings. Useful when you are trying to thread an + # email. + # + # If the references field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.references #=> nil + # mail.references([]) #=> [] + # mail = TMail::Mail.load("../test/fixtures/raw_email_reply") + # mail.references #=> ["<473FF3B8.9020707@xxx.org>", "<348F04F142D69C21-291E56D292BC@xxxx.net>"] + def references( default = nil ) + if h = @header['references'] + h.refs + else + default + end + end + + # Destructively sets the value of the "References:" field of an email. + # + # Accepts an array of strings of message IDs + # + # Example: + # + # mail = TMail::Mail.new + # mail.references = ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] + # mail.references #=> ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] + def references=( *strs ) + set_string_array_attr 'References', strs + end + + #== MIME header methods + + # Returns the listed MIME version of this email from the "Mime-Version:" header field + # + # If the mime_version field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.mime_version #=> nil + # mail.mime_version([]) #=> [] + # mail = TMail::Mail.load("../test/fixtures/raw_email") + # mail.mime_version #=> "1.0" + def mime_version( default = nil ) + if h = @header['mime-version'] + h.version || default + else + default + end + end + + def mime_version=( m, opt = nil ) + if opt + if h = @header['mime-version'] + h.major = m + h.minor = opt + else + store 'Mime-Version', "#{m}.#{opt}" + end + else + store 'Mime-Version', m + end + m + end + + # Returns the current "Content-Type" of the mail instance. + # + # If the content_type field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.content_type #=> nil + # mail.content_type([]) #=> [] + # mail = TMail::Mail.load("../test/fixtures/raw_email") + # mail.content_type #=> "text/plain" + def content_type( default = nil ) + if h = @header['content-type'] + h.content_type || default + else + default + end + end + + # Returns the current main type of the "Content-Type" of the mail instance. + # + # If the content_type field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.main_type #=> nil + # mail.main_type([]) #=> [] + # mail = TMail::Mail.load("../test/fixtures/raw_email") + # mail.main_type #=> "text" + def main_type( default = nil ) + if h = @header['content-type'] + h.main_type || default + else + default + end + end + + # Returns the current sub type of the "Content-Type" of the mail instance. + # + # If the content_type field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.sub_type #=> nil + # mail.sub_type([]) #=> [] + # mail = TMail::Mail.load("../test/fixtures/raw_email") + # mail.sub_type #=> "plain" + def sub_type( default = nil ) + if h = @header['content-type'] + h.sub_type || default + else + default + end + end + + # Destructively sets the "Content-Type:" header field of this mail object + # + # Allows you to set the main type, sub type as well as parameters to the field. + # The main type and sub type need to be a string. + # + # The optional params hash can be passed with keys as symbols and values as a string, + # or strings as keys and values. + # + # Example: + # + # mail = TMail::Mail.new + # mail.set_content_type("text", "plain") + # mail.to_s #=> "Content-Type: text/plain\n\n" + # + # mail.set_content_type("text", "plain", {:charset => "EUC-KR", :format => "flowed"}) + # mail.to_s #=> "Content-Type: text/plain; charset=EUC-KR; format=flowed\n\n" + # + # mail.set_content_type("text", "plain", {"charset" => "EUC-KR", "format" => "flowed"}) + # mail.to_s #=> "Content-Type: text/plain; charset=EUC-KR; format=flowed\n\n" + def set_content_type( str, sub = nil, param = nil ) + if sub + main, sub = str, sub + else + main, sub = str.split(%r, 2) + raise ArgumentError, "sub type missing: #{str.inspect}" unless sub + end + if h = @header['content-type'] + h.main_type = main + h.sub_type = sub + h.params.clear + else + store 'Content-Type', "#{main}/#{sub}" + end + @header['content-type'].params.replace param if param + str + end + + alias content_type= set_content_type + + # Returns the named type parameter as a string, from the "Content-Type:" header. + # + # Example: + # + # mail = TMail::Mail.new + # mail.type_param("charset") #=> nil + # mail.type_param("charset", []) #=> [] + # mail.set_content_type("text", "plain", {:charset => "EUC-KR", :format => "flowed"}) + # mail.type_param("charset") #=> "EUC-KR" + # mail.type_param("format") #=> "flowed" + def type_param( name, default = nil ) + if h = @header['content-type'] + h[name] || default + else + default + end + end + + # Returns the character set of the email. Returns nil if no encoding set or returns + # whatever default you pass as a parameter - note passing the parameter does NOT change + # the mail object in any way. + # + # Example: + # + # mail = TMail::Mail.load("path_to/utf8_email") + # mail.charset #=> "UTF-8" + # + # mail = TMail::Mail.new + # mail.charset #=> nil + # mail.charset("US-ASCII") #=> "US-ASCII" + def charset( default = nil ) + if h = @header['content-type'] + h['charset'] or default + else + default + end + end + + # Destructively sets the character set used by this mail object to the passed string, you + # should note though that this does nothing to the mail body, just changes the header + # value, you will need to transliterate the body as well to match whatever you put + # in this header value if you are changing character sets. + # + # Example: + # + # mail = TMail::Mail.new + # mail.charset #=> nil + # mail.charset = "UTF-8" + # mail.charset #=> "UTF-8" + def charset=( str ) + if str + if h = @header[ 'content-type' ] + h['charset'] = str + else + store 'Content-Type', "text/plain; charset=#{str}" + end + end + str + end + + # Returns the transfer encoding of the email. Returns nil if no encoding set or returns + # whatever default you pass as a parameter - note passing the parameter does NOT change + # the mail object in any way. + # + # Example: + # + # mail = TMail::Mail.load("path_to/base64_encoded_email") + # mail.transfer_encoding #=> "base64" + # + # mail = TMail::Mail.new + # mail.transfer_encoding #=> nil + # mail.transfer_encoding("base64") #=> "base64" + def transfer_encoding( default = nil ) + if h = @header['content-transfer-encoding'] + h.encoding || default + else + default + end + end + + # Destructively sets the transfer encoding of the mail object to the passed string, you + # should note though that this does nothing to the mail body, just changes the header + # value, you will need to encode or decode the body as well to match whatever you put + # in this header value. + # + # Example: + # + # mail = TMail::Mail.new + # mail.transfer_encoding #=> nil + # mail.transfer_encoding = "base64" + # mail.transfer_encoding #=> "base64" + def transfer_encoding=( str ) + set_string_attr 'Content-Transfer-Encoding', str + end + + alias encoding transfer_encoding + alias encoding= transfer_encoding= + alias content_transfer_encoding transfer_encoding + alias content_transfer_encoding= transfer_encoding= + + # Returns the content-disposition of the mail object, returns nil or the passed + # default value if given + # + # Example: + # + # mail = TMail::Mail.load("path_to/raw_mail_with_attachment") + # mail.disposition #=> "attachment" + # + # mail = TMail::Mail.load("path_to/plain_simple_email") + # mail.disposition #=> nil + # mail.disposition(false) #=> false + def disposition( default = nil ) + if h = @header['content-disposition'] + h.disposition || default + else + default + end + end + + alias content_disposition disposition + + # Allows you to set the content-disposition of the mail object. Accepts a type + # and a hash of parameters. + # + # Example: + # + # mail.set_disposition("attachment", {:filename => "test.rb"}) + # mail.disposition #=> "attachment" + # mail['content-disposition'].to_s #=> "attachment; filename=test.rb" + def set_disposition( str, params = nil ) + if h = @header['content-disposition'] + h.disposition = str + h.params.clear + else + store('Content-Disposition', str) + h = @header['content-disposition'] + end + h.params.replace params if params + end + + alias disposition= set_disposition + alias set_content_disposition set_disposition + alias content_disposition= set_disposition + + # Returns the value of a parameter in an existing content-disposition header + # + # Example: + # + # mail.set_disposition("attachment", {:filename => "test.rb"}) + # mail['content-disposition'].to_s #=> "attachment; filename=test.rb" + # mail.disposition_param("filename") #=> "test.rb" + # mail.disposition_param("missing_param_key") #=> nil + # mail.disposition_param("missing_param_key", false) #=> false + # mail.disposition_param("missing_param_key", "Nothing to see here") #=> "Nothing to see here" + def disposition_param( name, default = nil ) + if h = @header['content-disposition'] + h[name] || default + else + default + end + end + + # Convert the Mail object's body into a Base64 encoded email + # returning the modified Mail object + def base64_encode! + store 'Content-Transfer-Encoding', 'Base64' + self.body = base64_encode + end + + # Return the result of encoding the TMail::Mail object body + # without altering the current body + def base64_encode + Base64.folding_encode(self.body) + end + + # Convert the Mail object's body into a Base64 decoded email + # returning the modified Mail object + def base64_decode! + if /base64/i === self.transfer_encoding('') + store 'Content-Transfer-Encoding', '8bit' + self.body = base64_decode + end + end + + # Returns the result of decoding the TMail::Mail object body + # without altering the current body + def base64_decode + Base64.decode(self.body, @config.strict_base64decode?) + end + + # Returns an array of each destination in the email message including to: cc: or bcc: + # + # Example: + # + # mail.to = "Mikel " + # mail.cc = "Trans " + # mail.bcc = "bob " + # mail.destinations #=> ["mikel@lindsaar.net", "t@t.com", "bob@me.com"] + def destinations( default = nil ) + ret = [] + %w( to cc bcc ).each do |nm| + if h = @header[nm] + h.addrs.each {|i| ret.push i.address } + end + end + ret.empty? ? default : ret + end + + # Yields a block of destination, yielding each as a string. + # (from the destinations example) + # mail.each_destination { |d| puts "#{d.class}: #{d}" } + # String: mikel@lindsaar.net + # String: t@t.com + # String: bob@me.com + def each_destination( &block ) + destinations([]).each do |i| + if Address === i + yield i + else + i.each(&block) + end + end + end + + alias each_dest each_destination + + # Returns an array of reply to addresses that the Mail object has, + # or if the Mail message has no reply-to, returns an array of the + # Mail objects from addresses. Else returns the default which can + # either be passed as a parameter or defaults to nil + # + # Example: + # mail.from = "Mikel " + # mail.reply_to = nil + # mail.reply_addresses #=> [""] + # + def reply_addresses( default = nil ) + reply_to_addrs(nil) or from_addrs(nil) or default + end + + # Returns the "sender" field as an array -> useful to find out who to + # send an error email to. + def error_reply_addresses( default = nil ) + if s = sender(nil) + [s] + else + from_addrs(default) + end + end + + # Returns true if the Mail object is a multipart message + def multipart? + main_type('').downcase == 'multipart' + end + + # Creates a new email in reply to self. Sets the In-Reply-To and + # References headers for you automagically. + # + # Example: + # mail = TMail::Mail.load("my_email") + # reply_email = mail.create_reply + # reply_email.class #=> TMail::Mail + # reply_email.references #=> [""] + # reply_email.in_reply_to #=> [""] + def create_reply + setup_reply create_empty_mail() + end + + # Creates a new email in reply to self. Sets the In-Reply-To and + # References headers for you automagically. + # + # Example: + # mail = TMail::Mail.load("my_email") + # forward_email = mail.create_forward + # forward_email.class #=> TMail::Mail + # forward_email.content_type #=> "multipart/mixed" + # forward_email.body #=> "Attachment: (unnamed)" + # forward_email.encoded #=> Returns the original email as a MIME attachment + def create_forward + setup_forward create_empty_mail() + end + + #:stopdoc: + private + + def create_empty_mail + self.class.new(StringPort.new(''), @config) + end + + def setup_reply( mail ) + if tmp = reply_addresses(nil) + mail.to_addrs = tmp + end + + mid = message_id(nil) + tmp = references(nil) || [] + tmp.push mid if mid + mail.in_reply_to = [mid] if mid + mail.references = tmp unless tmp.empty? + mail.subject = 'Re: ' + subject('').sub(/\A(?:\[[^\]]+\])?(?:\s*Re:)*\s*/i, '') + mail.mime_version = '1.0' + mail + end + + def setup_forward( mail ) + m = Mail.new(StringPort.new('')) + m.body = decoded + m.set_content_type 'message', 'rfc822' + m.encoding = encoding('7bit') + mail.parts.push m + # call encoded to reparse the message + mail.encoded + mail + end + + #:startdoc: + end # class Mail + +end # module TMail diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/loader.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/loader.rb old mode 100755 new mode 100644 similarity index 52% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/loader.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/loader.rb index 79073154..6c0e2511 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/loader.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/loader.rb @@ -1 +1,3 @@ +#:stopdoc: require 'tmail/mailbox' +#:startdoc: \ No newline at end of file diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/mail.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mail.rb old mode 100755 new mode 100644 similarity index 68% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/mail.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mail.rb index d10275b7..fef6b01c --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/mail.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mail.rb @@ -29,6 +29,8 @@ # with permission of Minero Aoki. #++ + + require 'tmail/interface' require 'tmail/encode' require 'tmail/header' @@ -41,23 +43,89 @@ require 'socket' module TMail + # == Mail Class + # + # Accessing a TMail object done via the TMail::Mail class. As email can be fairly complex + # creatures, you will find a large amount of accessor and setter methods in this class! + # + # Most of the below methods handle the header, in fact, what TMail does best is handle the + # header of the email object. There are only a few methods that deal directly with the body + # of the email, such as base64_encode and base64_decode. + # + # === Using TMail inside your code + # + # The usual way is to install the gem (see the {README}[link:/README] on how to do this) and + # then put at the top of your class: + # + # require 'tmail' + # + # You can then create a new TMail object in your code with: + # + # @email = TMail::Mail.new + # + # Or if you have an email as a string, you can initialize a new TMail::Mail object and get it + # to parse that string for you like so: + # + # @email = TMail::Mail.parse(email_text) + # + # You can also read a single email off the disk, for example: + # + # @email = TMail::Mail.load('filename.txt') + # + # Also, you can read a mailbox (usual unix mbox format) and end up with an array of TMail + # objects by doing something like this: + # + # # Note, we pass true as the last variable to open the mailbox read only + # mailbox = TMail::UNIXMbox.new("mailbox", nil, true) + # @emails = [] + # mailbox.each_port { |m| @emails << TMail::Mail.new(m) } + # class Mail class << self + + # Opens an email that has been saved out as a file by itself. + # + # This function will read a file non-destructively and then parse + # the contents and return a TMail::Mail object. + # + # Does not handle multiple email mailboxes (like a unix mbox) for that + # use the TMail::UNIXMbox class. + # + # Example: + # mail = TMail::Mail.load('filename') + # def load( fname ) new(FilePort.new(fname)) end alias load_from load alias loadfrom load - + + # Parses an email from the supplied string and returns a TMail::Mail + # object. + # + # Example: + # require 'rubygems'; require 'tmail' + # email_string =< # bodyport=nil> + # mail.body + # #=> "Hello there Mikel!\n\n" def parse( str ) new(StringPort.new(str)) end end - def initialize( port = nil, conf = DEFAULT_CONFIG ) + def initialize( port = nil, conf = DEFAULT_CONFIG ) #:nodoc: @port = port || StringPort.new @config = Config.to_config(conf) @@ -73,6 +141,12 @@ module TMail } end + # Provides access to the port this email is using to hold it's data + # + # Example: + # mail = TMail::Mail.parse(email_string) + # mail.port + # #=> # attr_reader :port def inspect @@ -162,6 +236,14 @@ module TMail @header.dup end + # Returns a TMail::AddressHeader object of the field you are querying. + # Examples: + # @mail['from'] #=> # + # @mail['to'] #=> # + # + # You can get the string value of this by passing "to_s" to the query: + # Example: + # @mail['to'].to_s #=> "mikel@test.com.au" def []( key ) @header[key.downcase] end @@ -172,6 +254,19 @@ module TMail alias fetch [] + # Allows you to set or delete TMail header objects at will. + # Eamples: + # @mail = TMail::Mail.new + # @mail['to'].to_s # => 'mikel@test.com.au' + # @mail['to'] = 'mikel@elsewhere.org' + # @mail['to'].to_s # => 'mikel@elsewhere.org' + # @mail.encoded # => "To: mikel@elsewhere.org\r\n\r\n" + # @mail['to'] = nil + # @mail['to'].to_s # => nil + # @mail.encoded # => "\r\n" + # + # Note: setting mail[] = nil actualy deletes the header field in question from the object, + # it does not just set the value of the hash to nil def []=( key, val ) dkey = key.downcase @@ -203,7 +298,14 @@ module TMail end alias store []= - + + # Allows you to loop through each header in the TMail::Mail object in a block + # Example: + # @mail['to'] = 'mikel@elsewhere.org' + # @mail['from'] = 'me@me.com' + # @mail.each_header { |k,v| puts "#{k} = #{v}" } + # # => from = me@me.com + # # => to = mikel@elsewhere.org def each_header @header.each do |key, val| [val].flatten.each {|v| yield key, v } @@ -350,10 +452,12 @@ module TMail end def quoted_body - parse_body - @body_port.ropen {|f| - return f.read - } + body_port.ropen {|f| return f.read } + end + + def quoted_body= str + body_port.wopen { |f| f.write str } + str end def body=( str ) @@ -375,8 +479,8 @@ module TMail str end - alias preamble body - alias preamble= body= + alias preamble quoted_body + alias preamble= quoted_body= def epilogue parse_body @@ -397,6 +501,18 @@ module TMail def each_part( &block ) parts().each(&block) end + + # Returns true if the content type of this part of the email is + # a disposition attachment + def disposition_is_attachment? + (self['content-disposition'] && self['content-disposition'].disposition == "attachment") + end + + # Returns true if this part's content main type is text, else returns false. + # By main type is meant "text/plain" is text. "text/html" is text + def content_type_is_text? + self.header['content-type'] && (self.header['content-type'].main_type != "text") + end private diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/mailbox.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mailbox.rb old mode 100755 new mode 100644 similarity index 80% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/mailbox.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mailbox.rb index bb7a460e..b0bc6a7f --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/mailbox.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mailbox.rb @@ -150,9 +150,78 @@ module TMail class UNIXMbox + class << self + alias newobj new + end + + # Creates a new mailbox object that you can iterate through to collect the + # emails from with "each_port". + # + # You need to pass it a filename of a unix mailbox format file, the format of this + # file can be researched at this page at {wikipedia}[link:http://en.wikipedia.org/wiki/Mbox] + # + # ==== Parameters + # + # +filename+: The filename of the mailbox you want to open + # + # +tmpdir+: Can be set to override TMail using the system environment's temp dir. TMail will first + # use the temp dir specified by you (if any) or then the temp dir specified in the Environment's TEMP + # value then the value in the Environment's TMP value or failing all of the above, '/tmp' + # + # +readonly+: If set to false, each email you take from the mail box will be removed from the mailbox. + # default is *false* - ie, it *WILL* truncate your mailbox file to ZERO once it has read the emails out. + # + # ==== Options: + # + # None + # + # ==== Examples: + # + # # First show using readonly true: + # + # require 'ftools' + # File.size("../test/fixtures/mailbox") + # #=> 20426 + # + # mailbox = TMail::UNIXMbox.new("../test/fixtures/mailbox", nil, true) + # #=> # + # + # mailbox.each_port do |port| + # mail = TMail::Mail.new(port) + # puts mail.subject + # end + # #Testing mailbox 1 + # #Testing mailbox 2 + # #Testing mailbox 3 + # #Testing mailbox 4 + # require 'ftools' + # File.size?("../test/fixtures/mailbox") + # #=> 20426 + # + # # Now show with readonly set to the default false + # + # mailbox = TMail::UNIXMbox.new("../test/fixtures/mailbox") + # #=> # + # + # mailbox.each_port do |port| + # mail = TMail::Mail.new(port) + # puts mail.subject + # end + # #Testing mailbox 1 + # #Testing mailbox 2 + # #Testing mailbox 3 + # #Testing mailbox 4 + # + # File.size?("../test/fixtures/mailbox") + # #=> nil + def UNIXMbox.new( filename, tmpdir = nil, readonly = false ) + tmpdir = ENV['TEMP'] || ENV['TMP'] || '/tmp' + newobj(filename, "#{tmpdir}/ruby_tmail_#{$$}_#{rand()}", readonly, false) + end + def UNIXMbox.lock( fname ) begin - f = File.open(fname) + f = File.open(fname, 'r+') f.flock File::LOCK_EX yield f ensure @@ -161,15 +230,6 @@ module TMail end end - class << self - alias newobj new - end - - def UNIXMbox.new( fname, tmpdir = nil, readonly = false ) - tmpdir = ENV['TEMP'] || ENV['TMP'] || '/tmp' - newobj(fname, "#{tmpdir}/ruby_tmail_#{$$}_#{rand()}", readonly, false) - end - def UNIXMbox.static_new( fname, dir, readonly = false ) newobj(fname, dir, readonly, true) end @@ -213,13 +273,13 @@ module TMail fromaddr(), TextUtils.time2str(File.mtime(port.filename)) end - def UNIXMbox.fromaddr + def UNIXMbox.fromaddr(port) h = HeaderField.new_from_port(port, 'Return-Path') || - HeaderField.new_from_port(port, 'From') or return 'nobody' + HeaderField.new_from_port(port, 'From') || + HeaderField.new_from_port(port, 'EnvelopeSender') or return 'nobody' a = h.addrs[0] or return 'nobody' a.spec end - private_class_method :fromaddr def close return if @closed diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/main.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/main.rb new file mode 100644 index 00000000..e5277279 --- /dev/null +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/main.rb @@ -0,0 +1,6 @@ +#:stopdoc: +require 'tmail/version' +require 'tmail/mail' +require 'tmail/mailbox' +require 'tmail/core_extensions' +#:startdoc: \ No newline at end of file diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/mbox.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mbox.rb old mode 100755 new mode 100644 similarity index 52% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/mbox.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mbox.rb index 79073154..6c0e2511 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/mbox.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mbox.rb @@ -1 +1,3 @@ +#:stopdoc: require 'tmail/mailbox' +#:startdoc: \ No newline at end of file diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/net.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/net.rb old mode 100755 new mode 100644 similarity index 86% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/net.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/net.rb index 50b1dd95..65147228 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/net.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/net.rb @@ -1,8 +1,3 @@ -=begin rdoc - -= Net provides SMTP wrapping - -=end #-- # Copyright (c) 1998-2003 Minero Aoki # @@ -29,13 +24,14 @@ # with permission of Minero Aoki. #++ +#:stopdoc: require 'nkf' - +#:startdoc: module TMail class Mail - + def send_to( smtp ) do_send_to(smtp) do ready_to_send @@ -128,45 +124,10 @@ module TMail 'using C.T.Encoding with multipart mail is not permitted' end end - - def create_empty_mail - self.class.new(StringPort.new(''), @config) - end - - def create_reply - setup_reply create_empty_mail() - end - - def setup_reply( m ) - if tmp = reply_addresses(nil) - m.to_addrs = tmp - end - - mid = message_id(nil) - tmp = references(nil) || [] - tmp.push mid if mid - m.in_reply_to = [mid] if mid - m.references = tmp unless tmp.empty? - m.subject = 'Re: ' + subject('').sub(/\A(?:\s*re:)+/i, '') - - m - end - - def create_forward - setup_forward create_empty_mail() - end - - def setup_forward( mail ) - m = Mail.new(StringPort.new('')) - m.body = decoded - m.set_content_type 'message', 'rfc822' - m.encoding = encoding('7bit') - mail.parts.push m - end end - + #:stopdoc: class DeleteFields NOSEND_FIELDS = %w( @@ -190,8 +151,9 @@ module TMail end end + #:startdoc: - + #:stopdoc: class AddMessageId def initialize( fqdn = nil ) @@ -205,8 +167,9 @@ module TMail end end + #:startdoc: - + #:stopdoc: class AddDate def exec( mail ) @@ -214,8 +177,9 @@ module TMail end end + #:startdoc: - + #:stopdoc: class MimeEncodeAuto def initialize( s = nil, m = nil ) @@ -233,8 +197,9 @@ module TMail end end - + #:startdoc: + #:stopdoc: class MimeEncodeSingle def exec( mail ) @@ -260,8 +225,9 @@ module TMail end end - - + #:startdoc: + + #:stopdoc: class MimeEncodeMulti def exec( mail, top = true ) @@ -278,5 +244,5 @@ module TMail end end - + #:startdoc: end # module TMail diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/obsolete.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/obsolete.rb old mode 100755 new mode 100644 similarity index 94% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/obsolete.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/obsolete.rb index b871510b..22b0a126 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/obsolete.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/obsolete.rb @@ -2,6 +2,9 @@ = Obsolete methods that are depriciated +If you really want to see them, go to lib/tmail/obsolete.rb and view to your +heart's content. + =end #-- # Copyright (c) 1998-2003 Minero Aoki @@ -28,10 +31,9 @@ # Note: Originally licensed under LGPL v2+. Using MIT license for Rails # with permission of Minero Aoki. #++ +#:stopdoc: +module TMail #:nodoc: -module TMail - - # mail.rb class Mail alias include? key? alias has_key? key? @@ -51,8 +53,6 @@ module TMail alias has_value? value? end - - # facade.rb class Mail def from_addr( default = nil ) addr, = from_addrs(nil) @@ -83,13 +83,11 @@ module TMail alias each_dest each_destination end - - # address.rb class Address alias route routes alias addr spec - def spec=( str ) + def spec=( str ) @local, @domain = str.split(/@/,2).map {|s| s.split(/\./) } end @@ -97,8 +95,6 @@ module TMail alias address= spec= end - - # mbox.rb class MhMailbox alias new_mail new_port alias each_mail each_port @@ -115,8 +111,6 @@ module TMail alias each_newmail each_new_port end - - # utils.rb extend TextUtils class << self @@ -135,3 +129,4 @@ module TMail end end # module TMail +#:startdoc: \ No newline at end of file diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/parser.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/parser.rb old mode 100755 new mode 100644 similarity index 99% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/parser.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/parser.rb index 5deb0ff6..ab1a8284 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/parser.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/parser.rb @@ -1,3 +1,4 @@ +#:stopdoc: # DO NOT MODIFY!!!! # This file is automatically generated by racc 1.4.5 # from racc grammer file "parser.y". diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/port.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/port.rb old mode 100755 new mode 100644 similarity index 100% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/port.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/port.rb diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/quoting.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/quoting.rb similarity index 82% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/quoting.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/quoting.rb index 0b2d11c3..cb9f4288 100644 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/quoting.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/quoting.rb @@ -13,12 +13,12 @@ module TMail from_charset = sub_header("content-type", "charset") case (content_transfer_encoding || "7bit").downcase when "quoted-printable" - # the default charset is set to iso-8859-1 instead of 'us-ascii'. + # the default charset is set to iso-8859-1 instead of 'us-ascii'. # This is needed as many mailer do not set the charset but send in ISO. This is only used if no charset is set. if !from_charset.blank? && from_charset.downcase == 'us-ascii' from_charset = 'iso-8859-1' end - + Unquoter.unquote_quoted_printable_and_convert_to(quoted_body, to_charset, from_charset, true) when "base64" @@ -35,9 +35,9 @@ module TMail def body(to_charset = 'utf-8', &block) attachment_presenter = block || Proc.new { |file_name| "Attachment: #{file_name}\n" } - + if multipart? - parts.collect { |part| + parts.collect { |part| header = part["content-type"] if part.multipart? @@ -81,13 +81,13 @@ module TMail end end end - + def unquote_quoted_printable_and_convert_to(text, to, from, preserve_underscores=false) text = text.gsub(/_/, " ") unless preserve_underscores text = text.gsub(/\r\n|\r/, "\n") # normalize newlines convert_to(text.unpack("M*").first, to, from) end - + def unquote_base64_and_convert_to(text, to, from) convert_to(Base64.decode(text), to, from) end @@ -116,27 +116,3 @@ module TMail end end end - -if __FILE__ == $0 - require 'test/unit' - - class TC_Unquoter < Test::Unit::TestCase - def test_unquote_quoted_printable - a ="=?ISO-8859-1?Q?[166417]_Bekr=E6ftelse_fra_Rejsefeber?=" - b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8') - assert_equal "[166417] Bekr\303\246ftelse fra Rejsefeber", b - end - - def test_unquote_base64 - a ="=?ISO-8859-1?B?WzE2NjQxN10gQmVrcuZmdGVsc2UgZnJhIFJlanNlZmViZXI=?=" - b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8') - assert_equal "[166417] Bekr\303\246ftelse fra Rejsefeber", b - end - - def test_unquote_without_charset - a ="[166417]_Bekr=E6ftelse_fra_Rejsefeber" - b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8') - assert_equal "[166417]_Bekr=E6ftelse_fra_Rejsefeber", b - end - end -end diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/require_arch.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/require_arch.rb new file mode 100644 index 00000000..b4fffb8a --- /dev/null +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/require_arch.rb @@ -0,0 +1,58 @@ +#:stopdoc: +require 'rbconfig' + +# Attempts to require anative extension. +# Falls back to pure-ruby version, if it fails. +# +# This uses Config::CONFIG['arch'] from rbconfig. + +def require_arch(fname) + arch = Config::CONFIG['arch'] + begin + path = File.join("tmail", arch, fname) + require path + rescue LoadError => e + # try pre-built Windows binaries + if arch =~ /mswin/ + require File.join("tmail", 'mswin32', fname) + else + raise e + end + end +end + + +# def require_arch(fname) +# dext = Config::CONFIG['DLEXT'] +# begin +# if File.extname(fname) == dext +# path = fname +# else +# path = File.join("tmail","#{fname}.#{dext}") +# end +# require path +# rescue LoadError => e +# begin +# arch = Config::CONFIG['arch'] +# path = File.join("tmail", arch, "#{fname}.#{dext}") +# require path +# rescue LoadError +# case path +# when /i686/ +# path.sub!('i686', 'i586') +# when /i586/ +# path.sub!('i586', 'i486') +# when /i486/ +# path.sub!('i486', 'i386') +# else +# begin +# require fname + '.rb' +# rescue LoadError +# raise e +# end +# end +# retry +# end +# end +# end +#:startdoc: \ No newline at end of file diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/scanner.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner.rb old mode 100755 new mode 100644 similarity index 72% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/scanner.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner.rb index 9216b430..a5d01396 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/scanner.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner.rb @@ -28,16 +28,22 @@ # Note: Originally licensed under LGPL v2+. Using MIT license for Rails # with permission of Minero Aoki. #++ - +#:stopdoc: +#require 'tmail/require_arch' require 'tmail/utils' +require 'tmail/config' module TMail - require 'tmail/scanner_r.rb' + # NOTE: It woiuld be nice if these two libs could boith be called "tmailscanner", and + # the native extension would have precedence. However RubyGems boffs that up b/c + # it does not gaurantee load_path order. begin - raise LoadError, 'Turn off Ruby extention by user choice' if ENV['NORUBYEXT'] - require 'tmail/scanner_c.so' - Scanner = Scanner_C + raise LoadError, 'Turned off native extentions by user choice' if ENV['NORUBYEXT'] + require('tmail/tmailscanner') # c extension + Scanner = TMailScanner rescue LoadError - Scanner = Scanner_R + require 'tmail/scanner_r' + Scanner = TMailScanner end end +#:stopdoc: \ No newline at end of file diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/scanner_r.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner_r.rb old mode 100755 new mode 100644 similarity index 91% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/scanner_r.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner_r.rb index d9169c53..f2075502 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/scanner_r.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner_r.rb @@ -1,4 +1,3 @@ -# # scanner_r.rb # #-- @@ -26,15 +25,14 @@ # Note: Originally licensed under LGPL v2+. Using MIT license for Rails # with permission of Minero Aoki. #++ - +#:stopdoc: require 'tmail/config' - module TMail - class Scanner_R + class TMailScanner - Version = '0.10.7' + Version = '1.2.3' Version.freeze MIME_HEADERS = { @@ -46,14 +44,13 @@ module TMail alnum = 'a-zA-Z0-9' atomsyms = %q[ _#!$%&`'*+-{|}~^/=? ].strip tokensyms = %q[ _#!$%&`'*+-{|}~^@. ].strip - atomchars = alnum + Regexp.quote(atomsyms) tokenchars = alnum + Regexp.quote(tokensyms) iso2022str = '\e(?!\(B)..(?:[^\e]+|\e(?!\(B)..)*\e\(B' - eucstr = '(?:[\xa1-\xfe][\xa1-\xfe])+' - sjisstr = '(?:[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc])+' - utf8str = '(?:[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf][\x80-\xbf])+' + eucstr = "(?:[\xa1-\xfe][\xa1-\xfe])+" + sjisstr = "(?:[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc])+" + utf8str = "(?:[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf][\x80-\xbf])+" quoted_with_iso2022 = /\A(?:[^\\\e"]+|#{iso2022str})+/n domlit_with_iso2022 = /\A(?:[^\\\e\]]+|#{iso2022str})+/n @@ -107,7 +104,7 @@ module TMail @received = (scantype == :RECEIVED) @is_mime_header = MIME_HEADERS[scantype] - atom, token, @quoted_re, @domlit_re, @comment_re = PATTERN_TABLE[$KCODE] + atom, token, @quoted_re, @domlit_re, @comment_re = PATTERN_TABLE[TMail.KCODE] @word_re = (MIME_HEADERS[scantype] ? token : atom) end @@ -147,34 +144,34 @@ module TMail if s = readstr(@word_re) if @is_mime_header - yield :TOKEN, s + yield [:TOKEN, s] else # atom if /\A\d+\z/ === s - yield :DIGIT, s + yield [:DIGIT, s] elsif @received - yield RECV_TOKEN[s.downcase] || :ATOM, s + yield [RECV_TOKEN[s.downcase] || :ATOM, s] else - yield :ATOM, s + yield [:ATOM, s] end end elsif skip(/\A"/) - yield :QUOTED, scan_quoted_word() + yield [:QUOTED, scan_quoted_word()] elsif skip(/\A\[/) - yield :DOMLIT, scan_domain_literal() + yield [:DOMLIT, scan_domain_literal()] elsif skip(/\A\(/) @comments.push scan_comment() else c = readchar() - yield c, c + yield [c, c] end end - yield false, '$' + yield [false, '$'] end def scan_quoted_word @@ -261,3 +258,4 @@ module TMail end end # module TMail +#:startdoc: \ No newline at end of file diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/stringio.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/stringio.rb old mode 100755 new mode 100644 similarity index 99% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/stringio.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/stringio.rb index 3817850f..83573987 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/stringio.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/stringio.rb @@ -1,3 +1,4 @@ +# encoding: utf-8 =begin rdoc = String handling class diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/utils.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/utils.rb old mode 100755 new mode 100644 similarity index 60% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/utils.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/utils.rb index 016330ff..9a3afe89 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/utils.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/utils.rb @@ -1,8 +1,3 @@ -=begin rdoc - -= General Purpose TMail Utilities - -=end #-- # Copyright (c) 1998-2003 Minero Aoki # @@ -29,21 +24,73 @@ # with permission of Minero Aoki. #++ +# = TMail - The EMail Swiss Army Knife for Ruby +# +# The TMail library provides you with a very complete way to handle and manipulate EMails +# from within your Ruby programs. +# +# Used as the backbone for email handling by the Ruby on Rails and Nitro web frameworks as +# well as a bunch of other Ruby apps including the Ruby-Talk mailing list to newsgroup email +# gateway, it is a proven and reliable email handler that won't let you down. +# +# Originally created by Minero Aoki, TMail has been recently picked up by Mikel Lindsaar and +# is being actively maintained. Numerous backlogged bug fixes have been applied as well as +# Ruby 1.9 compatibility and a swath of documentation to boot. +# +# TMail allows you to treat an email totally as an object and allow you to get on with your +# own programming without having to worry about crafting the perfect email address validation +# parser, or assembling an email from all it's component parts. +# +# TMail handles the most complex part of the email - the header. It generates and parses +# headers and provides you with instant access to their innards through simple and logically +# named accessor and setter methods. +# +# TMail also provides a wrapper to Net/SMTP as well as Unix Mailbox handling methods to +# directly read emails from your unix mailbox, parse them and use them. +# +# Following is the comprehensive list of methods to access TMail::Mail objects. You can also +# check out TMail::Mail, TMail::Address and TMail::Headers for other lists. module TMail + # Provides an exception to throw on errors in Syntax within TMail's parsers class SyntaxError < StandardError; end - + # Provides a new email boundary to separate parts of the email. This is a random + # string based off the current time, so should be fairly unique. + # + # For Example: + # + # TMail.new_boundary + # #=> "mimepart_47bf656968207_25a8fbb80114" + # TMail.new_boundary + # #=> "mimepart_47bf66051de4_25a8fbb80240" def TMail.new_boundary 'mimepart_' + random_tag end + # Provides a new email message ID. You can use this to generate unique email message + # id's for your email so you can track them. + # + # Optionally takes a fully qualified domain name (default to the current hostname + # returned by Socket.gethostname) that will be appended to the message ID. + # + # For Example: + # + # email.message_id = TMail.new_message_id + # #=> "<47bf66845380e_25a8fbb80332@baci.local.tmail>" + # email.to_s + # #=> "Message-Id: <47bf668b633f1_25a8fbb80475@baci.local.tmail>\n\n" + # email.message_id = TMail.new_message_id("lindsaar.net") + # #=> "<47bf668b633f1_25a8fbb80475@lindsaar.net.tmail>" + # email.to_s + # #=> "Message-Id: <47bf668b633f1_25a8fbb80475@lindsaar.net.tmail>\n\n" def TMail.new_message_id( fqdn = nil ) fqdn ||= ::Socket.gethostname "<#{random_tag()}@#{fqdn}.tmail>" end - def TMail.random_tag + #:stopdoc: + def TMail.random_tag #:nodoc: @uniq += 1 t = Time.now sprintf('%x%x_%x%x%d%x', @@ -54,50 +101,55 @@ module TMail @uniq = 0 + #:startdoc: + + # Text Utils provides a namespace to define TOKENs, ATOMs, PHRASEs and CONTROL characters that + # are OK per RFC 2822. + # + # It also provides methods you can call to determine if a string is safe module TextUtils - # Defines characters per RFC that are OK for TOKENs, ATOMs, PHRASEs and CONTROL characters. - - aspecial = '()<>[]:;.\\,"' - tspecial = '()<>[];:\\,"/?=' - lwsp = " \t\r\n" - control = '\x00-\x1f\x7f-\xff' + aspecial = %Q|()<>[]:;.\\,"| + tspecial = %Q|()<>[];:\\,"/?=| + lwsp = %Q| \t\r\n| + control = %Q|\x00-\x1f\x7f-\xff| + + CONTROL_CHAR = /[#{control}]/n ATOM_UNSAFE = /[#{Regexp.quote aspecial}#{control}#{lwsp}]/n PHRASE_UNSAFE = /[#{Regexp.quote aspecial}#{control}]/n TOKEN_UNSAFE = /[#{Regexp.quote tspecial}#{control}#{lwsp}]/n - CONTROL_CHAR = /[#{control}]/n + # Returns true if the string supplied is free from characters not allowed as an ATOM def atom_safe?( str ) - # Returns true if the string supplied is free from characters not allowed as an ATOM not ATOM_UNSAFE === str end + # If the string supplied has ATOM unsafe characters in it, will return the string quoted + # in double quotes, otherwise returns the string unmodified def quote_atom( str ) - # If the string supplied has ATOM unsafe characters in it, will return the string quoted - # in double quotes, otherwise returns the string unmodified (ATOM_UNSAFE === str) ? dquote(str) : str end + # If the string supplied has PHRASE unsafe characters in it, will return the string quoted + # in double quotes, otherwise returns the string unmodified def quote_phrase( str ) - # If the string supplied has PHRASE unsafe characters in it, will return the string quoted - # in double quotes, otherwise returns the string unmodified (PHRASE_UNSAFE === str) ? dquote(str) : str end + # Returns true if the string supplied is free from characters not allowed as a TOKEN def token_safe?( str ) - # Returns true if the string supplied is free from characters not allowed as a TOKEN not TOKEN_UNSAFE === str end + # If the string supplied has TOKEN unsafe characters in it, will return the string quoted + # in double quotes, otherwise returns the string unmodified def quote_token( str ) - # If the string supplied has TOKEN unsafe characters in it, will return the string quoted - # in double quotes, otherwise returns the string unmodified (TOKEN_UNSAFE === str) ? dquote(str) : str end - def dquote( str ) - # Wraps supplied string in double quotes unless it is already wrapped - # Returns double quoted string + # Wraps supplied string in double quotes unless it is already wrapped + # Returns double quoted string + def dquote( str ) #:nodoc: unless str =~ /^".*?"$/ '"' + str.gsub(/["\\]/n) {|s| '\\' + s } + '"' else @@ -106,12 +158,14 @@ module TMail end private :dquote + # Unwraps supplied string from inside double quotes + # Returns unquoted string def unquote( str ) - # Unwraps supplied string from inside double quotes - # Returns unquoted string str =~ /^"(.*?)"$/ ? $1 : str end + # Provides a method to join a domain name by it's parts and also makes it + # ATOM safe by quoting it as needed def join_domain( arr ) arr.map {|i| if /\A\[.*\]\z/ === i @@ -122,7 +176,7 @@ module TMail }.join('.') end - + #:stopdoc: ZONESTR_TABLE = { 'jst' => 9 * 60, 'eet' => 2 * 60, @@ -168,9 +222,10 @@ module TMail 'y' => 12 * 60, 'z' => 0 * 60 } + #:startdoc: + # Takes a time zone string from an EMail and converts it to Unix Time (seconds) def timezone_string_to_unixtime( str ) - # Takes a time zone string from an EMail and converts it to Unix Time (seconds) if m = /([\+\-])(\d\d?)(\d\d)/.match(str) sec = (m[2].to_i * 60 + m[3].to_i) * 60 m[1] == '-' ? -sec : sec @@ -181,7 +236,7 @@ module TMail end end - + #:stopdoc: WDAY = %w( Sun Mon Tue Wed Thu Fri Sat TMailBUG ) MONTH = %w( TMailBUG Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec TMailBUG ) @@ -201,7 +256,7 @@ module TMail MESSAGE_ID = /<[^\@>]+\@[^>\@]+>/ - + def message_id?( str ) MESSAGE_ID === str end @@ -239,7 +294,7 @@ module TMail } def to_kcode( str ) - flag = NKF_FLAGS[$KCODE] or return str + flag = NKF_FLAGS[TMail.KCODE] or return str NKF.nkf(flag, str) end @@ -248,8 +303,7 @@ module TMail def decode_RFC2231( str ) m = RFC2231_ENCODED.match(str) or return str begin - NKF.nkf(NKF_FLAGS[$KCODE], - m.post_match.gsub(/%[\da-f]{2}/in) {|s| s[1,2].hex.chr }) + to_kcode(m.post_match.gsub(/%[\da-f]{2}/in) {|s| s[1,2].hex.chr }) rescue m.post_match.gsub(/%[\da-f]{2}/in, "") end @@ -263,7 +317,7 @@ module TMail preamble = $1 remainder = $2 if remainder =~ /;/ - remainder =~ /^(.*)(;.*)$/m + remainder =~ /^(.*?)(;.*)$/m boundary_text = $1 post = $2.chomp else @@ -275,6 +329,8 @@ module TMail end end end + #:startdoc: + end diff --git a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/version.rb b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/version.rb similarity index 94% rename from vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/version.rb rename to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/version.rb index 14df4b06..6bf8cc80 100644 --- a/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.1.0/tmail/version.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/version.rb @@ -27,11 +27,12 @@ # with permission of Minero Aoki. #++ -module TMail #:nodoc: - module VERSION #:nodoc: +#:stopdoc: +module TMail + module VERSION MAJOR = 1 - MINOR = 1 - TINY = 1 + MINOR = 2 + TINY = 2 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/vendor/rails/actionmailer/lib/action_mailer/version.rb b/vendor/rails/actionmailer/lib/action_mailer/version.rb index 954a4727..88b9a3c2 100644 --- a/vendor/rails/actionmailer/lib/action_mailer/version.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/version.rb @@ -2,7 +2,7 @@ module ActionMailer module VERSION #:nodoc: MAJOR = 2 MINOR = 0 - TINY = 2 + TINY = 991 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/vendor/rails/actionmailer/test/delivery_method_test.rb b/vendor/rails/actionmailer/test/delivery_method_test.rb index ebee2356..0731512e 100644 --- a/vendor/rails/actionmailer/test/delivery_method_test.rb +++ b/vendor/rails/actionmailer/test/delivery_method_test.rb @@ -1,4 +1,4 @@ -require "#{File.dirname(__FILE__)}/abstract_unit" +require 'abstract_unit' class DefaultDeliveryMethodMailer < ActionMailer::Base end diff --git a/vendor/rails/actionmailer/test/fixtures/path.with.dots/multipart_with_template_path_with_dots.rhtml b/vendor/rails/actionmailer/test/fixtures/path.with.dots/multipart_with_template_path_with_dots.rhtml deleted file mode 100644 index e69de29b..00000000 diff --git a/vendor/rails/actionmailer/test/fixtures/raw_base64_decoded_string b/vendor/rails/actionmailer/test/fixtures/raw_base64_decoded_string deleted file mode 100644 index 99b00ea162eef0f50ed252afba0c7a768ad1b561..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8576 zcmY+IcRbaP_s8FNxqBGd=~8Ak8FkaOMd~Wqag~*oS!8t0Y*J)LvZZS#k!zE6Wi{+F z(nqdjM0J0C|NNc*&Uw5Z=Z`b~c)kqJ8)#@cnt<*AdjP=x7khjAyF2X7?|YlyH#axg zE6absEbT2Xv*+ga=I4JbF0wzq-}&@@etv#$YKlEM!I~KVIX=2KI>H_r+8i0)8tmKa z>t*+Ju{+zpcXw}gGlqtS_S@TbS{t@nTQ^!?vR^i?wzcgw*0CBJ+uPe$8yi{mFW5Cz zYxUKeH8ra>HSE&T`I_geRVCj`O4dqB*x5rX&+=zWp1pYSf}NecnV-LspSO^ox0;j5 zevmw$lew9Zv6Asw><`W`E zlM`6c(b?JAd-v{+CEQ<$ieiU^%tb}bM&I2GySow^IvH_~?e9Mu613;cg53v&E09%!)4yxeZtH6KPP9V*Y#<4 z_j~v5b$WZRU3Zvsa-4E<9CC4)ceJVW^qjM^p0l~KY)P50wr-_T7cQF&SY4dBa+zUm z*=K%!*2JvD#%9J?cf`cR#l>aPP;XxMOq;Rs2c6SQ^4T|fdfhrY@6V_#tC9xJo}JLt z%rG>ZS5kVfr1VKartb9VAr+O^YKos^WG-F0)O6}(rMmj8q{x)CC{tRxK|x{qgzTKC z=#b>`dO5KQ1?L=bdG5&Ms&UFh3 zCCbQDiwO+zn__dX#Gc1#}bOt(=@mM+FP{ z2r4QnZ*a(Z0$~IROu>NXcziDsSO9=-IQ$ubP>Kg$BRE^(@Vf#6xdc=z0>~i{8WD&Z zB(ezsG{Eth1mq9^WZ>~B1VS|eC_y4S!Qf0BPznd$06;DR5k?^7!GR_Kh{E9>A`p)d zpc(*3LIOz$L@5CH;&9OjL=+Op27pim;@Gic{s=_UKk>g500IEO1px4PJn;WR^cNJy z11JHq|11CRCjbN+xPcHhq8D~VA-HAi`sqbo_X)?1^Nebr_9XJFxX<+07WbtRbrXco z*F76}D0QXMZlJDY@Uh~Jw|VF5ONVnc{MTm&>dQu-kfTsXjT_3xij5x1TzlJ4Fv)Co&D zdd7RmZH!3!)MWuPN;A_l$vYECxF&d2=ITk?AsR?!THc;ye%FUczF<=U!1zc(%`|`! zDMS(0bqPS4FIzl*eqL97q~6t(jCm}AusxLT`CG zAoQgpNn^<_2ouZi(!8h~f*=DJ*Po8YYV$|dOcP)=`#AN@1xP%gY+-#F;;dMlqPZlc zlC1pJt^RY$57FX9<+kX5>yqd1GF35=mmW@+u8A8tv)Uh(%4xCt>j9wI{B9(3oabP; z$k9g1CHChBx&)vyq+_Zwpn9W1)u;38aQf|~_)BtV)gEo6X|rRc5S^hD^+em0asPBw zCEGt)b2?51`!s&tZ6(y4gradgx?potIm0EVBH_+TJf2|MQ8!x8)cVFzrG=zJ6gIjm zQ>v#Y?tXjxDj{Ap%w>N)MNg`4+u+SV{yGRD#NG3=*A>y)kFW6Gq+!}9xq6=+z3?ws1f$^&1|MF z?l@Ugx`aQZUPxWUcH?4ysMZ$%8yzsLk9>6HJBQNm^>IC8mtwDnsDbWr(-G1p>D$-2 z+tzzAAOE`!0#nS*VtA>c5eC8+vT75?@3-sjOnzzR?$uLe9oA{9u61p$NCtlYbwN2m zt>u&VcmnHd!_5=)M%na972y2$(f#|cO1i+7#JgI|HJS8 zG_yxSET_UeUj$}Q%BO3AUilIiiWea4)T@dwiYL^QZ2~WDtliu7d!FGovh*jzw z$<2bEY>h|>Dl8V+^m%ahi*IVk+G6BI*O5*x|H}V$BKK7XJdq z|F)va)2;MIV=JK^Gbo6pBUIuRBje*QV7t)C+r)$^QjkfvF+Vc)oBM?52st^y6E2Oa z@oeGX^fmp<>CV-Q0^@PL-jl|BC;}+ds>0aTt(3n9;84vr!?-u;Ce*gVwZ8a5ZL|h6 zVI9lrfgghJM0>an+R`}xR~|ID za#fHTe^=vk@x+ZX#g{EA55240X@=sWfUTg7;W9wOe@g| zBtBMgZ%F(2LSk*wBa2#2ZZ0$mABJ$>INrakY=~%pk?~tTu}%@1XY+k`>OQ#}ireVM zYUfWJJesYC_TP5Xxvseo+s*|EzUSqs zlfGBYxa$osknX#huXOrd+eY1n?E9w6006b>tS|Z_YyEQYT8?}_ckzd>*U((HrN-u> z(M%7!8^numzUwx_7Rf%?%W7`VDWW5hJ==nW7QgOd;YF&vfBtK^2PhTSSvNx=C_pPe5~zM$Tl#0zc>T#1C`=P!++EZwuA zUx+tg+IgElR6n&L*fgDDbD#ZR~s-pbi%eMiBpJFyICt%>fAidos+ADiqUm&0R~pznYU&f>+eHqmvkS7Z!ya5w8!9o@%xzV zLE>j>$C@I&yN@5`>kWOgWtM(|3gyRbrJ;q0fI1cKM&)?P4PS=9YZN^eSMS_24Edmp zKH?Jsf8hC+H!z{hYKISEVMu@#-a>15x=UDuTr zF}+n}kys2Q;`%=PmL)sRQamUUVrDOzMM!^qGtN-%2nAWafOtcdKP zCGwRezPN)BERB1_CpVaRt2dKCOUPH+7eo}W8&MRsQ`DJ;K7N5K)dnn=3btiDBoN$~s z8C9D^WkaGYmcU_5coaPi8yuxH?fUmBevSYID4=v2=3IA*u(e@DAu71rutm{(xrrFF ze>cX0^MG6K@G+sY8Gk^q)c6(PylcrJP5AvIW6Rn6fD!`-#oDfFN)&SVrNL1HX|DiD zb&cDGu1G-uIOc3 z&!ZCuj7Or;fA4sNNvH49abJnPy3@F?9Gs>;*$%~cIwO7ePQHQwgqWq7`#C_K9Un=J zGRg8G;h46gI+%}|euvC_Rc??T4Q55mJ$Ey?iXy%2lj~mU^oR`h@Pk~hGb}OBt9~Z1 z3&p%Nic9?}Hu4I$06(ck;9UB3%J*tfp9TTO%6H7Ns*TC7h(vk=fjfbo;*`uW9p}@U zX+3)+C=<}tfnEkUycQm2Fp;%sPljm;M(UVLRKVjYl%=cH6jpJd;_y;DCn#bTu=U~4B2l2kzD*$&yvd*i>_z2CDq4FM$R%md*9f&3qLZYM6Uqy$$6nBoP&+EwJ4QWcP zY|<0LM6sN1Zu!~~G;bjd6ez|_8Vcju$W;gmKLjffnk)FuxG6fSqC@zMZp7JI6qn#u zdTUZq)%@t9NfxH%B-}$gP5NU2`yIr{UCe|C@B&~P+m^EwXszxU!agh>xbR}Sh0nlX ziDkW`Xml>I=~FK5l@O+bP2up|%CG!tL?M{=reQuUAcGxSD$8IF^e|sy#FuTc><0!qTOQ$My- zy*$ygvD0IvekQSr_cd
iy%BDlzLGa)kD27Dvvh%kWWY}J={>GS_efKkAk2DaT4 z%?JKP{WhG^?B+i1B90YB*$XGIVLlu-zZ2@DkR7ykF5a+TXL{w8jrP;<(FP?mC%YQZ z_z?oSg@BexM(>0$w-hQLtY6<9S=39Pkge;=$2?>+c^tr?ophvW7%Otn^xNSq41& zUEh9CK2q_oA@UfF(RHMS1osA!AIugjKNTJ8v>Vm|nDL4U9ZBQ%!U0 zX8XKSB0~;!G!K>K+Dh3x5mn)@Y=Z%Y!&buin^cMl+F#WsA^Wo4lROYbfm9rw$7Wq?H+{h1WYcd#=Ym&hM2VB*s3 zh%*HA0}At!HL8ck+|TWlNy6i=xwC9=_`9zg&y;*CM3+&J+%(RJt7_VIq`yzk6}-Z~ z3hdA5CGm+9e)N!D+bQoD+m0_;a%Dsw9O>VDB_k`PR{bYiBFh#=uw4~^yp|<=u~Y7* z+Lc|Kh^9V0r1#wyhKK`bmGMt4Z8}}aGd<5UwOc<4({)N`E&qUXV)|ycWH_~YQHNBBL)fD;dHl7dYbZfp3K*WrVT zE41O&hV+%5Tb>Q*@#-^IBOKCoh}iK%3pK7&c-Hb%;E}r8t6;k?H*GD|hPqB+GTaFA zcFx6S4~`SUuP*Ju(8Bh?7v(GxrMOp{FfYE#R2liYh2W|58?iSK3P z{F^4?))~%2iI>u@GA%nJ1-pyucPI@#*Bw;|_X_Uymz^8pwv8`Ye8-mi=rXW?$&h&< zY1a@)im)ear`e(&4Emo5<{w$Iw)jeMU4w58K8Z&bsC{icJDOYY+1g;uVAy#sKD4Wv z6Y8V#XGrg)A8wd}>XOduDMU8`*r-3t;VT0kSMib;&Q6gVMhTcHI*vsggA5^Qunbh{eAkDM`s}siyJRD<}^o@2y3-9>#O3E1T8tMWSI?F!jj1P z+xkgKwa3m~ux%WACuQbWxc%1{!j9*}YTzcaQHL$UTKm4Hl(vp}!cY6u3xJBb`rguuZ2<7!hFjE%j?brXp7d zH`ZH@x}YvCwQg+R7bi$xoQu3bICGESn6Tlzo00Wr@O)}yc;iipzY)$}n`RbCe!#Prdm?#8%w@XO@In>WiPNS4mc* z=jw-kJsAM0GC&?;2ND{yS`OP#&Tpj-02geFEWgV+8ZN{M-6&LgAGfti!;MWmTfB?) zJGM7P3Xe8eiIc0)J8Wwu{NX){o-15w3PD|^aEg<6?bzI37OxTR{r(blYEH)id_YK! z(;{T~xHKGb$z$)o4_-2G2$Dstk@4so5C59={8efHTuZV7YEvmm{0CId0AR2~>pB3a zcJLH;YpFx!xMb;@3;L1tINyN!7f|ge#F1WtQCgx=WR@D&(|)s+3pr4^r0q=48I6Fm z^KHjhvHT4ldM_$G9;@CYm2717MhU){GY`4?P01_AJiqbzWGgS4S1qf?s>LebxCv+9 z68QBZvO-`QbRjGn+AT$Po6`zYl^vNy4{qw?4s(1wpN?XS9tQ0UcXc}#TuX-_za8hO z8nD;FS)5*LR^q4)%QEKC5w6ULn{rk^5I}TG9~x#Q=0BZ&iQX&xusrT zA1}@BN>n!XKGi30$IA16@T+COUhJ$os9EkGJezvdC;|){B8-0F?@9aO5dulT#P@F z8Tg-dUj}DVx5}l+gd}Z+vuvm;MH?=zstaXH#orga{r=Z^k-`~ALt+2cAwOx8d>dmE zpfMUXUqB*PDyJMWWl=i%}JeRmmGm!fz`nG0}?_G z-qt1QhR|Sbr{YwD(>F<78mk2%{l2T`@3LpMN}VH=oGn~(UutRO7leqoWIc(n@8K#! zcR*53b@zjl^%Tudd%s$}XcJ9lb>xb)%?9@g|NR}6AotwEVD+14=kD_ARlR`|+$KC` zUsBKQ7wT>(^)`!bOQ}thQZzZ@uLCWHl5IcjVQ!)r>!)M3w<3!L`&jf_Mb~(Gg&dqX z2YxN+;?!2CQCQ^(qDZpJR5K}fSz+{df)oR=Pf?OmY`gpIMc+dJO=IeEJANrzt#t9z z?%^>M7I>Db^@DyKclrxaD}3qxlXF38Ovb(B&yQV2{D*Sqh52LETa^ld5V#%{EcZ0x zcxy+56QYZ|nizZPnJCtUP8D3DcCc04m{GoNkl$a*IDRjVVkCKVQT1s$O|^1pYi8bx z+I^S;%@O6y(BX9_0I*%=eSb6qvqI)jAT1(I6rUcMitWJIq{Z`jK81Z^#ws^-L^}|= z_=Z?8dB0k;!!sSeJTgr3krL9(2h8;}En3>j5p}D(llNT~?by^<3K0$9R;V$@e~!f& zPDJv*LBy(t7Ny;XcJXm#_p8#1Fe$RSC&Vja6eyR`kE?a~D#@^me#*#;MmkatXwfI6 z7Lmr}60Xw1=wo`KkUP=NvLViqno^E%y|o+isVsfDfC!Wg5G8)ndcefyN4gcz#k^-8f33u$x%<1;PJD8N&lQE zI~x|s^S3-&6r+vMKca&VqMM6M5aAkW+Bhd4h=6%xoHwPI^RgMiZg3g~hj)Lk!X7#MT$$-r*i}hrhco zIgE!vcrb=qD&N>h%l{8cB|?@)01g#55XMGv@kk!Ijjxx*L8eFGoC+aQ@7F{1XS(3! zjBbh8h#*@QxV!0nPh7rd5<46w$ zVW@>&Bw^o2_&C}z%U@7Qs|X~8?ks;Nd+=2FbF8Q5jl+cL?voVl%z96-T1eqPqnw6N zEp!sMWsDr50|ncj|MZMe0se|duxo8VC=D9B%SavjW^bV0GIm^QJ8UrYI=92Gw^}YL zx%V-y8sh?^N6KkXJ-G-(TFwMM4S<~hK&b9J%oifFFmrkYe&X)9X>VXn;Mqv-G{!qi zk%$*n7a~RP5!=LwKXMhA5opyzFi*cq`EkV!IH?dc-K*9lz@kA(0GQ6PH^aq>#91wX z_2vMW)rRZsm#=4IwSE?PoZYk;Kjj63&zvBfKUwT;4TC> zSZXtPbsNAyF%oUQ05*1EfVk2Cj)0lZ$6U!^DTbrVoqv|7;*TB$>S|d1>-o7%a^o?& zSEM=>gt8)!aMJw?HfI2Y1_Q*i;1kF9=LQd18!kbNK#{1xC3OaXQ4FjUBCc6J0iIZD zff8NY<~QschXk0kT9tnXbtz~xL<;~DX&W3wV5V5at#~@$9=--}NKw5Y8c+ZPkQSb3 z1$F)-aBlL>qVspJ-qifht_u5;;-lM5$7#UhJ`(8to8Xc9+3!ytPXiyH1MQFJewM*$ zpvwG> collection of heterogeneous elements. #11491 [Zach Dennis] + +* Avoid remote_ip spoofing. [Brian Candler] + +* Added support for regexp flags like ignoring case in the :requirements part of routes declarations #11421 [NeilW] + +* Fixed that ActionController::Base#read_multipart would fail if boundary was exactly 10240 bytes #10886 [ariejan] + +* Fixed HTML::Tokenizer (used in sanitize helper) didn't handle unclosed CDATA tags #10071 [esad, packagethief] + +* Improve documentation. [Radar, Jan De Poorter, chuyeow, xaviershay, danger, miloops, Xavier Noria, Sunny Ripert] + +* Fixed that FormHelper#radio_button would produce invalid ids #11298 [harlancrystal] + +* Added :confirm option to submit_tag #11415 [miloops] + +* Fixed NumberHelper#number_with_precision to properly round in a way that works equally on Mac, Windows, Linux (closes #11409, #8275, #10090, #8027) [zhangyuanyi] + +* Allow the #simple_format text_helper to take an html_options hash for each paragraph. #2448 [Francois Beausoleil, thechrisoshow] + +* Fix regression from filter refactoring where re-adding a skipped filter resulted in it being called twice. [rick] + +* Refactor filters to use Active Support callbacks. #11235 [Josh Peek] + +* Fixed that polymorphic routes would modify the input array #11363 [thomas.lee] + +* Added :format option to NumberHelper#number_to_currency to enable better localization support #11149 [lylo] + +* Fixed that TextHelper#excerpt would include one character too many #11268 [Irfy] + +* Fix more obscure nested parameter hash parsing bug. #10797 [thomas.lee] + +* Added ActionView::Helpers::register_javascript/stylesheet_expansion to make it easier for plugin developers to inject multiple assets. #10350 [lotswholetime] + +* Fix nested parameter hash parsing bug. #10797 [thomas.lee] + +* Allow using named routes in ActionController::TestCase before any request has been made. Closes #11273 [alloy] + +* Fixed that sweepers defined by cache_sweeper will be added regardless of the perform_caching setting. Instead, control whether the sweeper should be run with the perform_caching setting. This makes testing easier when you want to turn perform_caching on/off [DHH] + +* Make MimeResponds::Responder#any work without explicit types. Closes #11140 [jaw6] + +* Better error message for type conflicts when parsing params. Closes #7962 [spicycode, matt] + +* Remove unused ActionController::Base.template_class. Closes #10787 [Pratik] + +* Moved template handlers related code from ActionView::Base to ActionView::Template. [Pratik] + +* Tests for div_for and content_tag_for helpers. Closes #11223 [thechrisoshow] + +* Allow file uploads in Integration Tests. Closes #11091 [RubyRedRick] + +* Refactor partial rendering into a PartialTemplate class. [Pratik] + +* Added that requests with JavaScript as the priority mime type in the accept header and no format extension in the parameters will be treated as though their format was :js when it comes to determining which template to render. This makes it possible for JS requests to automatically render action.js.rjs files without an explicit respond_to block [DHH] + +* Tests for distance_of_time_in_words with TimeWithZone instances. Closes #10914 [ernesto.jimenez] + +* Remove support for multivalued (e.g., '&'-delimited) cookies. [Jamis Buck] + +* Fix problem with render :partial collections, records, and locals. #11057 [lotswholetime] + +* Added support for naming concrete classes in sweeper declarations [DHH] + +* Remove ERB trim variables from trace template in case ActionView::Base.erb_trim_mode is changed in the application. #10098 [tpope, kampers] + +* Fix typo in form_helper documentation. #10650 [xaviershay, kampers] + +* Fix bug with setting Request#format= after the getter has cached the value. #10889 [cch1] + +* Correct inconsistencies in RequestForgeryProtection docs. #11032 [mislav] + +* Introduce a Template class to ActionView. #11024 [lifofifo] + +* Introduce the :index option for form_for and fields_for to simplify multi-model forms (see http://railscasts.com/episodes/75). #9883 [rmm5t] + +* Introduce map.resources :cards, :as => 'tarjetas' to use a custom resource name in the URL: cards_path == '/tarjetas'. #10578 [blj] + +* TestSession supports indifferent access. #7372 [tamc, Arsen7, mhackett, julik, jean.helou] + +* Make assert_routing aware of the HTTP method used. #8039 [mpalmer] + e.g. assert_routing({ :method => 'put', :path => '/product/321' }, { :controller => "product", :action => "update", :id => "321" }) + +* Make map.root accept a single symbol as an argument to declare an alias. #10818 [bscofield] + + e.g. map.dashboard '/dashboard', :controller=>'dashboard' + map.root :dashboard + +* Handle corner case with image_tag when passed 'messed up' image names. #9018 [duncanbeevers, mpalmer] + +* Add label_tag helper for generating elements. #10802 [DefV] + +* Introduce TemplateFinder to handle view paths and lookups. #10800 [Pratik Naik] + +* Performance: optimize route recognition. Large speedup for apps with many resource routes. #10835 [oleganza] + +* Make render :partial recognise form builders and use the _form partial. #10814 [djanowski] + +* Allow users to declare other namespaces when using the atom feed helpers. #10304 [david.calavera] + +* Introduce send_file :x_sendfile => true to send an X-Sendfile response header. [Jeremy Kemper] + +* Fixed ActionView::Helpers::ActiveRecordHelper::form for when protect_from_forgery is used #10739 [jeremyevans] + +* Provide nicer access to HTTP Headers. Instead of request.env["HTTP_REFERRER"] you can now use request.headers["Referrer"]. [Koz] + +* UrlWriter respects relative_url_root. #10748 [Cheah Chu Yeow] + +* The asset_host block takes the controller request as an optional second argument. Example: use a single asset host for SSL requests. #10549 [Cheah Chu Yeow, Peter B, Tom Taylor] + +* Support render :text => nil. #6684 [tjennings, PotatoSalad, Cheah Chu Yeow] + +* assert_response failures include the exception message. #10688 [Seth Rasmussen] + +* All fragment cache keys are now by default prefixed with the "views/" namespace [DHH] + +* Moved the caching stores from ActionController::Caching::Fragments::* to ActiveSupport::Cache::*. If you're explicitly referring to a store, like ActionController::Caching::Fragments::MemoryStore, you need to update that reference with ActiveSupport::Cache::MemoryStore [DHH] + +* Deprecated ActionController::Base.fragment_cache_store for ActionController::Base.cache_store [DHH] + +* Made fragment caching in views work for rjs and builder as well #6642 [zsombor] + +* Fixed rendering of partials with layout when done from site layout #9209 [antramm] + +* Fix atom_feed_helper to comply with the atom spec. Closes #10672 [xaviershay] + + * The tags created do not contain a date (http://feedvalidator.org/docs/error/InvalidTAG.html) + * IDs are not guaranteed unique + * A default self link was not provided, contrary to the documentation + * NOTE: This changes tags for existing atom entries, but at least they validate now. + +* Correct indentation in tests. Closes #10671 [l.guidi] + +* Fix that auto_link looks for ='s in url paths (Amazon urls have them). Closes #10640 [bgreenlee] + +* Ensure that test case setup is run even if overridden. #10382 [Josh Peek] + +* Fix HTML Sanitizer to allow trailing spaces in CSS style attributes. Closes #10566 [wesley.moxam] + +* Add :default option to time_zone_select. #10590 [Matt Aimonetti] + + *2.0.2* (December 16th, 2007) * Added delete_via_redirect and put_via_redirect to integration testing #10497 [philodespotos] diff --git a/vendor/rails/actionpack/MIT-LICENSE b/vendor/rails/actionpack/MIT-LICENSE index 007cc942..13c90d46 100644 --- a/vendor/rails/actionpack/MIT-LICENSE +++ b/vendor/rails/actionpack/MIT-LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2007 David Heinemeier Hansson +Copyright (c) 2004-2008 David Heinemeier Hansson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/vendor/rails/actionpack/README b/vendor/rails/actionpack/README index 72f0f624..2746c3cc 100644 --- a/vendor/rails/actionpack/README +++ b/vendor/rails/actionpack/README @@ -97,7 +97,7 @@ A short rundown of the major features: class WeblogController < ActionController::Base before_filter :authenticate, :cache, :audit - after_filter { |c| c.response.body = GZip::compress(c.response.body) } + after_filter { |c| c.response.body = Gzip::compress(c.response.body) } after_filter LocalizeFilter def index diff --git a/vendor/rails/actionpack/Rakefile b/vendor/rails/actionpack/Rakefile index 1b1d9a17..0147a5c1 100644 --- a/vendor/rails/actionpack/Rakefile +++ b/vendor/rails/actionpack/Rakefile @@ -4,7 +4,7 @@ require 'rake/testtask' require 'rake/rdoctask' require 'rake/packagetask' require 'rake/gempackagetask' -require 'rake/contrib/rubyforgepublisher' +require 'rake/contrib/sshpublisher' require File.join(File.dirname(__FILE__), 'lib', 'action_pack', 'version') PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : '' @@ -27,9 +27,9 @@ task :test => [:test_action_pack, :test_active_record_integration] Rake::TestTask.new(:test_action_pack) { |t| t.libs << "test" -# make sure we include the controller tests (c*) first as on some systems +# make sure we include the tests in alphabetical order as on some systems # this will not happen automatically and the tests (as a whole) will error - t.test_files=Dir.glob( "test/c*/**/*_test.rb" ) + Dir.glob( "test/[ft]*/*_test.rb" ) + t.test_files=Dir.glob( "test/[cft]*/**/*_test.rb" ).sort # t.pattern = 'test/*/*_test.rb' t.verbose = true } @@ -76,7 +76,7 @@ spec = Gem::Specification.new do |s| s.has_rdoc = true s.requirements << 'none' - s.add_dependency('activesupport', '= 2.0.2' + PKG_BUILD) + s.add_dependency('activesupport', '= 2.0.991' + PKG_BUILD) s.require_path = 'lib' s.autorequire = 'action_controller' @@ -144,6 +144,7 @@ end desc "Publish the release files to RubyForge." task :release => [ :package ] do require 'rubyforge' + require 'rake/contrib/rubyforgepublisher' packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" } diff --git a/vendor/rails/actionpack/lib/action_controller.rb b/vendor/rails/actionpack/lib/action_controller.rb index e7a9eba5..810a5fb9 100755 --- a/vendor/rails/actionpack/lib/action_controller.rb +++ b/vendor/rails/actionpack/lib/action_controller.rb @@ -1,5 +1,5 @@ #-- -# Copyright (c) 2004-2007 David Heinemeier Hansson +# Copyright (c) 2004-2008 David Heinemeier Hansson # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -55,9 +55,9 @@ require 'action_controller/http_authentication' require 'action_controller/components' require 'action_controller/record_identifier' require 'action_controller/request_forgery_protection' +require 'action_controller/headers' require 'action_view' -ActionController::Base.template_class = ActionView::Base ActionController::Base.class_eval do include ActionController::Flash diff --git a/vendor/rails/actionpack/lib/action_controller/assertions/response_assertions.rb b/vendor/rails/actionpack/lib/action_controller/assertions/response_assertions.rb index 42bd7fb3..c5fc6c79 100644 --- a/vendor/rails/actionpack/lib/action_controller/assertions/response_assertions.rb +++ b/vendor/rails/actionpack/lib/action_controller/assertions/response_assertions.rb @@ -33,7 +33,13 @@ module ActionController elsif type.is_a?(Symbol) && @response.response_code == ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE[type] assert_block("") { true } # to count the assertion else - assert_block(build_message(message, "Expected response to be a , but was ", type, @response.response_code)) { false } + if @response.error? + exception = @response.template.instance_variable_get(:@exception) + exception_message = exception && exception.message + assert_block(build_message(message, "Expected response to be a , but was \n", type, @response.response_code, exception_message.to_s)) { false } + else + assert_block(build_message(message, "Expected response to be a , but was ", type, @response.response_code)) { false } + end end end end diff --git a/vendor/rails/actionpack/lib/action_controller/assertions/routing_assertions.rb b/vendor/rails/actionpack/lib/action_controller/assertions/routing_assertions.rb index 9bff2832..2acd0032 100644 --- a/vendor/rails/actionpack/lib/action_controller/assertions/routing_assertions.rb +++ b/vendor/rails/actionpack/lib/action_controller/assertions/routing_assertions.rb @@ -114,6 +114,9 @@ module ActionController # # # Tests a route, providing a defaults hash # assert_routing 'controller/action/9', {:id => "9", :item => "square"}, {:controller => "controller", :action => "action"}, {}, {:item => "square"} + # + # # Tests a route with a HTTP method + # assert_routing({ :method => 'put', :path => '/product/321' }, { :controller => "product", :action => "update", :id => "321" }) def assert_routing(path, options, defaults={}, extras={}, message=nil) assert_recognizes(options, path, extras, message) @@ -122,7 +125,7 @@ module ActionController options[:controller] = "/#{controller}" end - assert_generates(path, options, defaults, extras, message) + assert_generates(path.is_a?(Hash) ? path[:path] : path, options, defaults, extras, message) end private @@ -140,4 +143,4 @@ module ActionController end end end -end \ No newline at end of file +end diff --git a/vendor/rails/actionpack/lib/action_controller/assertions/selector_assertions.rb b/vendor/rails/actionpack/lib/action_controller/assertions/selector_assertions.rb index 573405c0..9ef093ac 100644 --- a/vendor/rails/actionpack/lib/action_controller/assertions/selector_assertions.rb +++ b/vendor/rails/actionpack/lib/action_controller/assertions/selector_assertions.rb @@ -21,11 +21,11 @@ module ActionController # from the response HTML or elements selected by the enclosing assertion. # # In addition to HTML responses, you can make the following assertions: - # * #assert_select_rjs -- Assertions on HTML content of RJS update and + # * +assert_select_rjs+ - Assertions on HTML content of RJS update and # insertion operations. - # * #assert_select_encoded -- Assertions on HTML encoded inside XML, + # * +assert_select_encoded+ - Assertions on HTML encoded inside XML, # for example for dealing with feed item descriptions. - # * #assert_select_email -- Assertions on the HTML body of an e-mail. + # * +assert_select_email+ - Assertions on the HTML body of an e-mail. # # Also see HTML::Selector to learn how to use selectors. module SelectorAssertions @@ -136,27 +136,27 @@ module ActionController # === Equality Tests # # The equality test may be one of the following: - # * true -- Assertion is true if at least one element selected. - # * false -- Assertion is true if no element selected. - # * String/Regexp -- Assertion is true if the text value of at least + # * true - Assertion is true if at least one element selected. + # * false - Assertion is true if no element selected. + # * String/Regexp - Assertion is true if the text value of at least # one element matches the string or regular expression. - # * Integer -- Assertion is true if exactly that number of + # * Integer - Assertion is true if exactly that number of # elements are selected. - # * Range -- Assertion is true if the number of selected + # * Range - Assertion is true if the number of selected # elements fit the range. # If no equality test specified, the assertion is true if at least one # element selected. # # To perform more than one equality tests, use a hash with the following keys: - # * :text -- Narrow the selection to elements that have this text + # * :text - Narrow the selection to elements that have this text # value (string or regexp). - # * :html -- Narrow the selection to elements that have this HTML + # * :html - Narrow the selection to elements that have this HTML # content (string or regexp). - # * :count -- Assertion is true if the number of selected elements + # * :count - Assertion is true if the number of selected elements # is equal to this value. - # * :minimum -- Assertion is true if the number of selected + # * :minimum - Assertion is true if the number of selected # elements is at least this value. - # * :maximum -- Assertion is true if the number of selected + # * :maximum - Assertion is true if the number of selected # elements is at most this value. # # If the method is called with a block, once all equality tests are @@ -263,12 +263,15 @@ module ActionController if match_with = equals[:text] matches.delete_if do |match| text = "" + text.force_encoding(match_with.encoding) if text.respond_to?(:force_encoding) stack = match.children.reverse while node = stack.pop if node.tag? stack.concat node.children.reverse else - text << node.content + content = node.content + content.force_encoding(match_with.encoding) if content.respond_to?(:force_encoding) + text << content end end text.strip! unless NO_STRIP.include?(match.name) diff --git a/vendor/rails/actionpack/lib/action_controller/base.rb b/vendor/rails/actionpack/lib/action_controller/base.rb index ff77e036..e1bf005f 100755 --- a/vendor/rails/actionpack/lib/action_controller/base.rb +++ b/vendor/rails/actionpack/lib/action_controller/base.rb @@ -5,6 +5,7 @@ require 'action_controller/routing' require 'action_controller/resources' require 'action_controller/url_rewriter' require 'action_controller/status_codes' +require 'action_view' require 'drb' require 'set' @@ -15,9 +16,6 @@ module ActionController #:nodoc: class SessionRestoreError < ActionControllerError #:nodoc: end - class MissingTemplate < ActionControllerError #:nodoc: - end - class RenderError < ActionControllerError #:nodoc: end @@ -161,28 +159,34 @@ module ActionController #:nodoc: # # Hello #{session[:person]} # - # For removing objects from the session, you can either assign a single key to nil, like session[:person] = nil, or you can - # remove the entire session with reset_session. + # For removing objects from the session, you can either assign a single key to +nil+: # - # Sessions are stored in a browser cookie that's cryptographically signed, but unencrypted, by default. This prevents - # the user from tampering with the session but also allows him to see its contents. + # # removes :person from session + # session[:person] = nil # - # Do not put secret information in session! + # or you can remove the entire session with +reset_session+. + # + # Sessions are stored by default in a browser cookie that's cryptographically signed, but unencrypted. + # This prevents the user from tampering with the session but also allows him to see its contents. + # + # Do not put secret information in cookie-based sessions! # # Other options for session storage are: # - # ActiveRecordStore: sessions are stored in your database, which works better than PStore with multiple app servers and, - # unlike CookieStore, hides your session contents from the user. To use ActiveRecordStore, set + # * ActiveRecordStore - Sessions are stored in your database, which works better than PStore with multiple app servers and, + # unlike CookieStore, hides your session contents from the user. To use ActiveRecordStore, set # - # config.action_controller.session_store = :active_record_store + # config.action_controller.session_store = :active_record_store # - # in your environment.rb and run rake db:sessions:create. + # in your config/environment.rb and run rake db:sessions:create. # - # MemCacheStore: sessions are stored as entries in your memcached cache. Set the session store type in environment.rb: + # * MemCacheStore - Sessions are stored as entries in your memcached cache. + # Set the session store type in config/environment.rb: # - # config.action_controller.session_store = :mem_cache_store + # config.action_controller.session_store = :mem_cache_store # - # This assumes that memcached has been installed and configured properly. See the MemCacheStore docs for more information. + # This assumes that memcached has been installed and configured properly. + # See the MemCacheStore docs for more information. # # == Responses # @@ -255,16 +259,12 @@ module ActionController #:nodoc: DEFAULT_RENDER_STATUS_CODE = "200 OK" include StatusCodes - - # Determines whether the view has access to controller internals @request, @response, @session, and @template. - # By default, it does. - @@view_controller_internals = true - cattr_accessor :view_controller_internals - - # Protected instance variable cache - @@protected_variables_cache = nil - cattr_accessor :protected_variables_cache - + + # Controller specific instance variables which will not be accessible inside views. + @@protected_view_variables = %w(@assigns @performed_redirect @performed_render @variables_added @request_origin @url @parent_controller + @action_name @before_filter_chain_aborted @action_cache_path @_session @_cookies @_headers @_params + @_flash @_response) + # Prepends all the URL-generating helpers from AssetHelper. This makes it possible to easily move javascripts, stylesheets, # and images to a dedicated asset server away from the main web server. Example: # ActionController::Base.asset_host = "http://assets.example.com" @@ -283,9 +283,10 @@ module ActionController #:nodoc: @@debug_routes = true cattr_accessor :debug_routes - # Controls whether the application is thread-safe, so multi-threaded servers like WEBrick know whether to apply a mutex - # around the performance of each action. Action Pack and Active Record are by default thread-safe, but many applications - # may not be. Turned off by default. + # 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 @@ -315,9 +316,10 @@ module ActionController #:nodoc: # A YAML parser is also available and can be turned on with: # # ActionController::Base.param_parsers[Mime::YAML] = :yaml - @@param_parsers = { Mime::MULTIPART_FORM => :multipart_form, + @@param_parsers = { Mime::MULTIPART_FORM => :multipart_form, Mime::URL_ENCODED_FORM => :url_encoded_form, - Mime::XML => :xml_simple } + Mime::XML => :xml_simple, + Mime::JSON => :json } cattr_accessor :param_parsers # Controls the default charset for all renders. @@ -328,17 +330,16 @@ module ActionController #:nodoc: # Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers. cattr_accessor :logger - # Determines which template class should be used by ActionController. - cattr_accessor :template_class - - # Turn on +ignore_missing_templates+ if you want to unit test actions without making the associated templates. - cattr_accessor :ignore_missing_templates - # Controls the resource action separator @@resource_action_separator = "/" cattr_accessor :resource_action_separator - # Sets the token parameter name for RequestForgery. Calling #protect_from_forgery sets it to :authenticity_token by default + # Allow to override path names for default resources' actions + @@resources_path_names = { :new => 'new', :edit => 'edit' } + cattr_accessor :resources_path_names + + # Sets the token parameter name for RequestForgery. Calling +protect_from_forgery+ + # sets it to :authenticity_token by default. cattr_accessor :request_forgery_protection_token # Indicates whether or not optimise the generated named @@ -428,6 +429,7 @@ module ActionController #:nodoc: def view_paths=(value) @view_paths = value + ActionView::TemplateFinder.process_view_paths(value) end # Adds a view_path to the front of the view_paths array. @@ -440,6 +442,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) end # Adds a view_path to the end of the view_paths array. @@ -452,6 +455,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) end # Replace sensitive parameter data from the request log. @@ -534,23 +538,23 @@ module ActionController #:nodoc: # Returns a URL that has been rewritten according to the options hash and the defined Routes. # (For doing a complete redirect, use redirect_to). - #   + # # url_for is used to: - #   - # All keys given to url_for are forwarded to the Route module, save for the following: - # * :anchor -- specifies the anchor name to be appended to the path. For example, + # + # All keys given to +url_for+ are forwarded to the Route module, save for the following: + # * :anchor - Specifies the anchor name to be appended to the path. For example, # url_for :controller => 'posts', :action => 'show', :id => 10, :anchor => 'comments' # will produce "/posts/show/10#comments". - # * :only_path -- if true, returns the relative URL (omitting the protocol, host name, and port) (false by default) - # * :trailing_slash -- if true, adds a trailing slash, as in "/archive/2005/". Note that this + # * :only_path - If true, returns the relative URL (omitting the protocol, host name, and port) (false by default). + # * :trailing_slash - If true, adds a trailing slash, as in "/archive/2005/". Note that this # is currently not recommended since it breaks caching. - # * :host -- overrides the default (current) host if provided. - # * :protocol -- overrides the default (current) protocol if provided. - # * :port -- optionally specify the port to connect to. - # * :user -- Inline HTTP authentication (only plucked out if :password is also present). - # * :password -- Inline HTTP authentication (only plucked out if :user is also present). - # * :skip_relative_url_root -- if true, the url is not constructed using the relative_url_root of the request so the path - # will include the web server relative installation directory. + # * :host - Overrides the default (current) host if provided. + # * :protocol - Overrides the default (current) protocol if provided. + # * :port - Optionally specify the port to connect to. + # * :user - Inline HTTP authentication (only plucked out if :password is also present). + # * :password - Inline HTTP authentication (only plucked out if :user is also present). + # * :skip_relative_url_root - If true, the url is not constructed using the +relative_url_root+ + # of the request so the path will include the web server relative installation directory. # # The URL is generated from the remaining keys in the hash. A URL contains two key parts: the and a query string. # Routes composes a query string as the key/value pairs not included in the . @@ -601,7 +605,7 @@ module ActionController #:nodoc: # url_for :controller => 'posts', :action => nil # # If you explicitly want to create a URL that's almost the same as the current URL, you can do so using the - # :overwrite_params options. Say for your posts you have different views for showing and printing them. + # :overwrite_params options. Say for your posts you have different views for showing and printing them. # Then, in the show view, you get the URL for the print view like this # # url_for :overwrite_params => { :action => 'print' } @@ -642,11 +646,11 @@ module ActionController #:nodoc: # View load paths for controller. def view_paths - (@template || self.class).view_paths + @template.finder.view_paths end def view_paths=(value) - (@template || self.class).view_paths = value + @template.finder.view_paths = value # Mutex needed end # Adds a view_path to the front of the view_paths array. @@ -656,7 +660,7 @@ module ActionController #:nodoc: # self.prepend_view_path(["views/default", "views/custom"]) # def prepend_view_path(path) - (@template || self.class).prepend_view_path(path) + @template.finder.prepend_view_path(path) # Mutex needed end # Adds a view_path to the end of the view_paths array. @@ -666,7 +670,7 @@ module ActionController #:nodoc: # self.append_view_path(["views/default", "views/custom"]) # def append_view_path(path) - (@template || self.class).append_view_path(path) + @template.finder.append_view_path(path) # Mutex needed end protected @@ -772,7 +776,7 @@ module ActionController #:nodoc: # # placed in "app/views/layouts/special.r(html|xml)" # render :text => "Hi there!", :layout => "special" # - # The :text option can also accept a Proc object, which can be used to manually control the page generation. This should + # The :text option can also accept a Proc object, which can be used to manually control the page generation. This should # generally be avoided, as it violates the separation between code and content, and because almost everything that can be # done with this method can also be done more cleanly using one of the other rendering methods, most notably templates. # @@ -826,19 +830,21 @@ module ActionController #:nodoc: # # === Rendering with status and location headers # - # All renders take the :status and :location options and turn them into headers. They can even be used together: + # All renders take the :status and :location options and turn them into headers. They can even be used together: # # render :xml => post.to_xml, :status => :created, :location => post_url(post) - def render(options = nil, &block) #:doc: + def render(options = nil, extra_options = {}, &block) #:doc: raise DoubleRenderError, "Can only render or redirect once per action" if performed? if options.nil? return render_for_file(default_template_name, nil, true) + elsif !extra_options.is_a?(Hash) + raise RenderError, "You called render with invalid options : #{options.inspect}, #{extra_options.inspect}" else if options == :update - options = { :update => true } + options = extra_options.merge({ :update => true }) elsif !options.is_a?(Hash) - raise RenderError, "You called render with invalid options : #{options}" + raise RenderError, "You called render with invalid options : #{options.inspect}" end end @@ -850,8 +856,8 @@ module ActionController #:nodoc: response.headers["Location"] = url_for(location) end - if text = options[:text] - render_for_text(text, options[:status]) + if options.has_key?(:text) + render_for_text(options[:text], options[:status]) else if file = options[:file] @@ -862,7 +868,8 @@ module ActionController #:nodoc: elsif inline = options[:inline] add_variables_to_assigns - render_for_text(@template.render_template(options[:type], inline, nil, options[:locals] || {}), options[:status]) + tmpl = ActionView::InlineTemplate.new(@template, options[:inline], options[:locals], options[:type]) + render_for_text(@template.render_template(tmpl), options[:status]) elsif action_name = options[:action] template = default_template_name(action_name.to_s) @@ -904,7 +911,7 @@ module ActionController #:nodoc: generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(@template, &block) response.content_type = Mime::JS - render_for_text(generator.to_s) + render_for_text(generator.to_s, options[:status]) elsif options[:nothing] # Safari doesn't pass the headers of the return if the response is zero length @@ -997,7 +1004,7 @@ module ActionController #:nodoc: # As you can infer from the example, this is mostly useful for situations where you want to centralize dynamic decisions about the # urls as they stem from the business domain. Please note that any individual url_for call can always override the defaults set # by this method. - def default_url_options(options) #:doc: + def default_url_options(options = nil) end # Redirects the browser to the target specified in +options+. This parameter can take one of three forms: @@ -1029,7 +1036,8 @@ module ActionController #:nodoc: # RedirectBackError will be raised. You may specify some fallback # behavior for this case by rescuing RedirectBackError. def redirect_to(options = {}, response_status = {}) #:doc: - + raise ActionControllerError.new("Cannot redirect to nil!") if options.nil? + if options.is_a?(Hash) && options[:status] status = options.delete(:status) elsif response_status[:status] @@ -1095,7 +1103,6 @@ module ActionController #:nodoc: private def render_for_file(template_path, status = nil, use_full_path = false, locals = {}) #:nodoc: add_variables_to_assigns - assert_existence_of_template_file(template_path) if use_full_path logger.info("Rendering #{template_path}" + (status ? " (#{status})" : '')) if logger render_for_text(@template.render_file(template_path, use_full_path, locals), status) end @@ -1114,11 +1121,7 @@ module ActionController #:nodoc: end def initialize_template_class(response) - unless @@template_class - raise "You must assign a template class through ActionController.template_class= before processing a request" - end - - response.template = ActionView::Base.new(view_paths, {}, self) + response.template = ActionView::Base.new(self.class.view_paths, {}, self) response.template.extend self.class.master_helper_module response.redirected_to = nil @performed_render = @performed_redirect = false @@ -1195,7 +1198,6 @@ module ActionController #:nodoc: def add_variables_to_assigns unless @variables_added add_instance_variables_to_assigns - add_class_variables_to_assigns if view_controller_internals @variables_added = true end end @@ -1209,30 +1211,11 @@ module ActionController #:nodoc: end def add_instance_variables_to_assigns - @@protected_variables_cache ||= Set.new(protected_instance_variables) - instance_variables.each do |var| - next if @@protected_variables_cache.include?(var) + (instance_variable_names - @@protected_view_variables).each do |var| @assigns[var[1..-1]] = instance_variable_get(var) end end - def add_class_variables_to_assigns - %w(view_paths logger template_class ignore_missing_templates).each do |cvar| - @assigns[cvar] = self.send(cvar) - end - end - - def protected_instance_variables - if view_controller_internals - %w(@assigns @performed_redirect @performed_render) - else - %w(@assigns @performed_redirect @performed_render - @_request @request @_response @response @_params @params - @_session @session @_cookies @cookies - @template @request_origin @parent_controller) - end - end - def request_origin # this *needs* to be cached! # otherwise you'd get different results if calling it more than once @@ -1248,7 +1231,7 @@ module ActionController #:nodoc: end def template_exists?(template_name = default_template_name) - @template.file_exists?(template_name) + @template.finder.file_exists?(template_name) end def template_public?(template_name = default_template_name) @@ -1256,20 +1239,11 @@ module ActionController #:nodoc: end def template_exempt_from_layout?(template_name = default_template_name) - extension = @template && @template.pick_template_extension(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 } end - def assert_existence_of_template_file(template_name) - unless template_exists?(template_name) || ignore_missing_templates - full_template_path = template_name.include?('.') ? template_name : "#{template_name}.#{@template.template_format}.erb" - display_paths = view_paths.join(':') - template_type = (template_name =~ /layouts/i) ? 'layout' : 'template' - raise(MissingTemplate, "Missing #{template_type} #{full_template_path} in view path #{display_paths}") - end - end - def default_template_name(action_name = self.action_name) if action_name action_name = action_name.to_s diff --git a/vendor/rails/actionpack/lib/action_controller/benchmarking.rb b/vendor/rails/actionpack/lib/action_controller/benchmarking.rb index 5201d31b..98b0325b 100644 --- a/vendor/rails/actionpack/lib/action_controller/benchmarking.rb +++ b/vendor/rails/actionpack/lib/action_controller/benchmarking.rb @@ -41,14 +41,14 @@ module ActionController #:nodoc: end protected - def render_with_benchmark(options = nil, deprecated_status = nil, &block) + def render_with_benchmark(options = nil, extra_options = {}, &block) unless logger - render_without_benchmark(options, &block) + render_without_benchmark(options, extra_options, &block) else db_runtime = ActiveRecord::Base.connection.reset_runtime if Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected? render_output = nil - @rendering_runtime = Benchmark::measure{ render_output = render_without_benchmark(options, &block) }.real + @rendering_runtime = Benchmark::realtime{ render_output = render_without_benchmark(options, extra_options, &block) } if Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected? @db_rt_before_render = db_runtime diff --git a/vendor/rails/actionpack/lib/action_controller/caching.rb b/vendor/rails/actionpack/lib/action_controller/caching.rb index e3e48f66..c4063dfb 100644 --- a/vendor/rails/actionpack/lib/action_controller/caching.rb +++ b/vendor/rails/actionpack/lib/action_controller/caching.rb @@ -2,6 +2,13 @@ require 'fileutils' require 'uri' require 'set' +require 'action_controller/caching/pages' +require 'action_controller/caching/actions' +require 'action_controller/caching/sql_cache' +require 'action_controller/caching/sweeping' +require 'action_controller/caching/fragments' + + module ActionController #:nodoc: # Caching is a cheap way of speeding up slow applications by keeping the result of calculations, renderings, and database calls # around for subsequent requests. Action Controller affords you three approaches in varying levels of granularity: Page, Action, Fragment. @@ -9,675 +16,57 @@ module ActionController #:nodoc: # You can read more about each approach and the sweeping assistance by clicking the modules below. # # Note: To turn off all caching and sweeping, set Base.perform_caching = false. + # + # + # == Caching stores + # + # All the caching stores from ActiveSupport::Cache is available to be used as backends for Action Controller caching. This setting only + # affects action and fragment caching as page caching is always written to disk. + # + # Configuration examples (MemoryStore is the default): + # + # ActionController::Base.cache_store = :memory_store + # ActionController::Base.cache_store = :file_store, "/path/to/cache/directory" + # ActionController::Base.cache_store = :drb_store, "druby://localhost:9192" + # ActionController::Base.cache_store = :mem_cache_store, "localhost" + # ActionController::Base.cache_store = MyOwnStore.new("parameter") module Caching def self.included(base) #:nodoc: base.class_eval do - include Pages, Actions, Fragments + @@cache_store = nil + cattr_reader :cache_store - if defined? ActiveRecord - include Sweeping, SqlCache + # Defines the storage option for cached fragments + def self.cache_store=(store_option) + @@cache_store = ActiveSupport::Cache.lookup_store(store_option) end + include Pages, Actions, Fragments + include Sweeping, SqlCache if defined?(ActiveRecord) + @@perform_caching = true cattr_accessor :perform_caching + + def self.cache_configured? + perform_caching && cache_store + end end end - # Page caching is an approach to caching where the entire action output of is stored as a HTML file that the web server - # can serve without going through the Action Pack. This can be as much as 100 times faster than going through the process of dynamically - # generating the content. Unfortunately, this incredible speed-up is only available to stateless pages where all visitors - # are treated the same. Content management systems -- including weblogs and wikis -- have many pages that are a great fit - # for this approach, but account-based systems where people log in and manipulate their own data are often less likely candidates. - # - # Specifying which actions to cache is done through the caches class method: - # - # class WeblogController < ActionController::Base - # caches_page :show, :new - # end - # - # This will generate cache files such as weblog/show/5 and weblog/new, which match the URLs used to trigger the dynamic - # generation. This is how the web server is able pick up a cache file when it exists and otherwise let the request pass on to - # the Action Pack to generate it. - # - # Expiration of the cache is handled by deleting the cached file, which results in a lazy regeneration approach where the cache - # is not restored before another hit is made against it. The API for doing so mimics the options from url_for and friends: - # - # class WeblogController < ActionController::Base - # def update - # List.update(params[:list][:id], params[:list]) - # expire_page :action => "show", :id => params[:list][:id] - # redirect_to :action => "show", :id => params[:list][:id] - # end - # end - # - # Additionally, you can expire caches using Sweepers that act on changes in the model to determine when a cache is supposed to be - # expired. - # - # == Setting the cache directory - # - # The cache directory should be the document root for the web server and is set using Base.page_cache_directory = "/document/root". - # For Rails, this directory has already been set to RAILS_ROOT + "/public". - # - # == Setting the cache extension - # - # By default, the cache extension is .html, which makes it easy for the cached files to be picked up by the web server. If you want - # something else, like .php or .shtml, just set Base.page_cache_extension. - module Pages - def self.included(base) #:nodoc: - base.extend(ClassMethods) - base.class_eval do - @@page_cache_directory = defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/public" : "" - cattr_accessor :page_cache_directory - - @@page_cache_extension = '.html' - cattr_accessor :page_cache_extension - end - end - - module ClassMethods - # Expires the page that was cached with the +path+ as a key. Example: - # expire_page "/lists/show" - def expire_page(path) - return unless perform_caching - - benchmark "Expired page: #{page_cache_file(path)}" do - File.delete(page_cache_path(path)) if File.exist?(page_cache_path(path)) - end - end - - # Manually cache the +content+ in the key determined by +path+. Example: - # cache_page "I'm the cached content", "/lists/show" - def cache_page(content, path) - return unless perform_caching - - benchmark "Cached page: #{page_cache_file(path)}" do - FileUtils.makedirs(File.dirname(page_cache_path(path))) - File.open(page_cache_path(path), "wb+") { |f| f.write(content) } - end - end - - # Caches the +actions+ using the page-caching approach that'll store the cache in a path within the page_cache_directory that - # matches the triggering url. - def caches_page(*actions) - return unless perform_caching - actions = actions.map(&:to_s) - after_filter { |c| c.cache_page if actions.include?(c.action_name) } - end - - private - def page_cache_file(path) - name = (path.empty? || path == "/") ? "/index" : URI.unescape(path.chomp('/')) - name << page_cache_extension unless (name.split('/').last || name).include? '.' - return name - end - - def page_cache_path(path) - page_cache_directory + page_cache_file(path) - end - end - - # Expires the page that was cached with the +options+ as a key. Example: - # expire_page :controller => "lists", :action => "show" - def expire_page(options = {}) - return unless perform_caching - - if options.is_a?(Hash) - if options[:action].is_a?(Array) - options[:action].dup.each do |action| - self.class.expire_page(url_for(options.merge(:only_path => true, :skip_relative_url_root => true, :action => action))) - end - else - self.class.expire_page(url_for(options.merge(:only_path => true, :skip_relative_url_root => true))) - end + protected + # Convenience accessor + def cache(key, options = {}, &block) + if cache_configured? + cache_store.fetch(ActiveSupport::Cache.expand_cache_key(key, :controller), options, &block) else - self.class.expire_page(options) - end - end - - # Manually cache the +content+ in the key determined by +options+. If no content is provided, the contents of response.body is used - # If no options are provided, the requested url is used. Example: - # cache_page "I'm the cached content", :controller => "lists", :action => "show" - def cache_page(content = nil, options = nil) - return unless perform_caching && caching_allowed - - path = case options - when Hash - url_for(options.merge(:only_path => true, :skip_relative_url_root => true, :format => params[:format])) - when String - options - else - request.path - end - - self.class.cache_page(content || response.body, path) - end - - private - def caching_allowed - request.get? && response.headers['Status'].to_i == 200 - end - end - - # Action caching is similar to page caching by the fact that the entire output of the response is cached, but unlike page caching, - # every request still goes through the Action Pack. The key benefit of this is that filters are run before the cache is served, which - # allows for authentication and other restrictions on whether someone is allowed to see the cache. Example: - # - # class ListsController < ApplicationController - # before_filter :authenticate, :except => :public - # caches_page :public - # caches_action :show, :feed - # end - # - # In this example, the public action doesn't require authentication, so it's possible to use the faster page caching method. But both the - # show and feed action are to be shielded behind the authenticate filter, so we need to implement those as action caches. - # - # Action caching internally uses the fragment caching and an around filter to do the job. The fragment cache is named according to both - # the current host and the path. So a page that is accessed at http://david.somewhere.com/lists/show/1 will result in a fragment named - # "david.somewhere.com/lists/show/1". This allows the cacher to differentiate between "david.somewhere.com/lists/" and - # "jamis.somewhere.com/lists/" -- which is a helpful way of assisting the subdomain-as-account-key pattern. - # - # Different representations of the same resource, e.g. http://david.somewhere.com/lists and http://david.somewhere.com/lists.xml - # are treated like separate requests and so are cached separately. Keep in mind when expiring an action cache that :action => 'lists' is not the same - # as :action => 'list', :format => :xml. - # - # You can set modify the default action cache path by passing a :cache_path option. This will be passed directly to ActionCachePath.path_for. This is handy - # for actions with multiple possible routes that should be cached differently. If a block is given, it is called with the current controller instance. - # - # class ListsController < ApplicationController - # before_filter :authenticate, :except => :public - # caches_page :public - # caches_action :show, :cache_path => { :project => 1 } - # caches_action :show, :cache_path => Proc.new { |controller| - # controller.params[:user_id] ? - # controller.send(:user_list_url, c.params[:user_id], c.params[:id]) : - # controller.send(:list_url, c.params[:id]) } - # end - module Actions - def self.included(base) #:nodoc: - base.extend(ClassMethods) - base.class_eval do - attr_accessor :rendered_action_cache, :action_cache_path - alias_method_chain :protected_instance_variables, :action_caching - end - end - - module ClassMethods - # Declares that +actions+ should be cached. - # See ActionController::Caching::Actions for details. - def caches_action(*actions) - return unless perform_caching - around_filter(ActionCacheFilter.new(*actions)) - end - end - - def protected_instance_variables_with_action_caching - protected_instance_variables_without_action_caching + %w(@action_cache_path) - end - - def expire_action(options = {}) - return unless perform_caching - if options[:action].is_a?(Array) - options[:action].dup.each do |action| - expire_fragment(ActionCachePath.path_for(self, options.merge({ :action => action }))) - end - else - expire_fragment(ActionCachePath.path_for(self, options)) - end - end - - class ActionCacheFilter #:nodoc: - def initialize(*actions, &block) - @options = actions.extract_options! - @actions = Set.new actions - end - - def before(controller) - return unless @actions.include?(controller.action_name.intern) - cache_path = ActionCachePath.new(controller, path_options_for(controller, @options)) - 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) - false - else - controller.action_cache_path = cache_path - end - end - - def after(controller) - return if !@actions.include?(controller.action_name.intern) || controller.rendered_action_cache || !caching_allowed(controller) - controller.write_fragment(controller.action_cache_path.path, controller.response.body) - end - - private - def set_content_type!(controller, extension) - controller.response.content_type = Mime::Type.lookup_by_extension(extension).to_s if extension - end - - def path_options_for(controller, options) - ((path_options = options[:cache_path]).respond_to?(:call) ? path_options.call(controller) : path_options) || {} - end - - def caching_allowed(controller) - controller.request.get? && controller.response.headers['Status'].to_i == 200 - end - end - - class ActionCachePath - attr_reader :path, :extension - - class << self - def path_for(controller, options) - new(controller, options).path - end - end - - def initialize(controller, options = {}) - @extension = extract_extension(controller.request.path) - path = controller.url_for(options).split('://').last - normalize!(path) - add_extension!(path, @extension) - @path = URI.unescape(path) - end - - private - def normalize!(path) - path << 'index' if path[-1] == ?/ - end - - def add_extension!(path, extension) - path << ".#{extension}" if extension - end - - def extract_extension(file_path) - # Don't want just what comes after the last '.' to accommodate multi part extensions - # such as tar.gz. - file_path[/^[^.]+\.(.+)$/, 1] - end - end - end - - # Fragment caching is used for caching various blocks within templates without caching the entire action as a whole. This is useful when - # certain elements of an action change frequently or depend on complicated state while other parts rarely change or can be shared amongst multiple - # parties. The caching is doing using the cache helper available in the Action View. A template with caching might look something like: - # - # Hello <%= @name %> - # <% cache do %> - # All the topics in the system: - # <%= render :partial => "topic", :collection => Topic.find(:all) %> - # <% end %> - # - # This cache will bind to the name of the action that called it, so if this code was part of the view for the topics/list action, you would - # be able to invalidate it using expire_fragment(:controller => "topics", :action => "list"). - # - # This default behavior is of limited use if you need to cache multiple fragments per action or if the action itself is cached using - # caches_action, so we also have the option to qualify the name of the cached fragment with something like: - # - # <% cache(:action => "list", :action_suffix => "all_topics") do %> - # - # That would result in a name such as "/topics/list/all_topics", avoiding conflicts with the action cache and with any fragments that use a - # different suffix. Note that the URL doesn't have to really exist or be callable - the url_for system is just used to generate unique - # cache names that we can refer to when we need to expire the cache. - # - # The expiration call for this example is: - # - # expire_fragment(:controller => "topics", :action => "list", :action_suffix => "all_topics") - # - # == Fragment stores - # - # By default, cached fragments are stored in memory. The available store options are: - # - # * FileStore: Keeps the fragments on disk in the +cache_path+, which works well for all types of environments and allows all - # processes running from the same application directory to access the cached content. - # * MemoryStore: Keeps the fragments in memory, which is fine for WEBrick and for FCGI (if you don't care that each FCGI process holds its - # own fragment store). It's not suitable for CGI as the process is thrown away at the end of each request. It can potentially also take - # up a lot of memory since each process keeps all the caches in memory. - # * DRbStore: Keeps the fragments in the memory of a separate, shared DRb process. This works for all environments and only keeps one cache - # around for all processes, but requires that you run and manage a separate DRb process. - # * MemCacheStore: Works like DRbStore, but uses Danga's MemCache instead. - # Requires the ruby-memcache library: gem install ruby-memcache. - # - # Configuration examples (MemoryStore is the default): - # - # ActionController::Base.fragment_cache_store = :memory_store - # ActionController::Base.fragment_cache_store = :file_store, "/path/to/cache/directory" - # ActionController::Base.fragment_cache_store = :drb_store, "druby://localhost:9192" - # ActionController::Base.fragment_cache_store = :mem_cache_store, "localhost" - # ActionController::Base.fragment_cache_store = MyOwnStore.new("parameter") - module Fragments - def self.included(base) #:nodoc: - base.class_eval do - @@fragment_cache_store = MemoryStore.new - cattr_reader :fragment_cache_store - - # Defines the storage option for cached fragments - def self.fragment_cache_store=(store_option) - store, *parameters = *([ store_option ].flatten) - @@fragment_cache_store = if store.is_a?(Symbol) - store_class_name = (store == :drb_store ? "DRbStore" : store.to_s.camelize) - store_class = ActionController::Caching::Fragments.const_get(store_class_name) - store_class.new(*parameters) - else - store - end - end - end - end - - # Given a name (as described in expire_fragment), returns a key suitable for use in reading, - # writing, or expiring a cached fragment. If the name is a hash, the generated name is the return - # value of url_for on that hash (without the protocol). - def fragment_cache_key(name) - name.is_a?(Hash) ? url_for(name).split("://").last : name - end - - # Called by CacheHelper#cache - def cache_erb_fragment(block, name = {}, options = nil) - unless perform_caching then block.call; return end - - buffer = eval(ActionView::Base.erb_variable, block.binding) - - if cache = read_fragment(name, options) - buffer.concat(cache) - else - pos = buffer.length - block.call - write_fragment(name, buffer[pos..-1], options) - end - end - - # Writes content to the location signified by name (see expire_fragment for acceptable formats) - def write_fragment(name, content, options = nil) - return unless perform_caching - - key = fragment_cache_key(name) - self.class.benchmark "Cached fragment: #{key}" do - fragment_cache_store.write(key, content, options) - end - content - end - - # Reads a cached fragment from the location signified by name (see expire_fragment for acceptable formats) - def read_fragment(name, options = nil) - return unless perform_caching - - key = fragment_cache_key(name) - self.class.benchmark "Fragment read: #{key}" do - fragment_cache_store.read(key, options) - end - end - - # Name can take one of three forms: - # * String: This would normally take the form of a path like "pages/45/notes" - # * Hash: Is treated as an implicit call to url_for, like { :controller => "pages", :action => "notes", :id => 45 } - # * Regexp: Will destroy all the matched fragments, example: - # %r{pages/\d*/notes} - # Ensure you do not specify start and finish in the regex (^$) because - # the actual filename matched looks like ./cache/filename/path.cache - # Regexp expiration is only supported on caches that can iterate over - # all keys (unlike memcached). - def expire_fragment(name, options = nil) - return unless perform_caching - - key = fragment_cache_key(name) - - if key.is_a?(Regexp) - self.class.benchmark "Expired fragments matching: #{key.source}" do - fragment_cache_store.delete_matched(key, options) - end - else - self.class.benchmark "Expired fragment: #{key}" do - fragment_cache_store.delete(key, options) - end + yield end end - class UnthreadedMemoryStore #:nodoc: - def initialize #:nodoc: - @data = {} - end - - def read(name, options=nil) #:nodoc: - @data[name] - end - - def write(name, value, options=nil) #:nodoc: - @data[name] = value - end - - def delete(name, options=nil) #:nodoc: - @data.delete(name) - end - - def delete_matched(matcher, options=nil) #:nodoc: - @data.delete_if { |k,v| k =~ matcher } - end + private + def cache_configured? + self.class.cache_configured? end - - module ThreadSafety #:nodoc: - def read(name, options=nil) #:nodoc: - @mutex.synchronize { super } - end - - def write(name, value, options=nil) #:nodoc: - @mutex.synchronize { super } - end - - def delete(name, options=nil) #:nodoc: - @mutex.synchronize { super } - end - - def delete_matched(matcher, options=nil) #:nodoc: - @mutex.synchronize { super } - end - end - - class MemoryStore < UnthreadedMemoryStore #:nodoc: - def initialize #:nodoc: - super - if ActionController::Base.allow_concurrency - @mutex = Mutex.new - MemoryStore.module_eval { include ThreadSafety } - end - end - end - - class DRbStore < MemoryStore #:nodoc: - attr_reader :address - - def initialize(address = 'druby://localhost:9192') - super() - @address = address - @data = DRbObject.new(nil, address) - end - end - - begin - require_library_or_gem 'memcache' - class MemCacheStore < MemoryStore #:nodoc: - attr_reader :addresses - - def initialize(*addresses) - super() - addresses = addresses.flatten - addresses = ["localhost"] if addresses.empty? - @addresses = addresses - @data = MemCache.new(*addresses) - end - end - rescue LoadError - # MemCache wasn't available so neither can the store be - end - - class UnthreadedFileStore #:nodoc: - attr_reader :cache_path - - def initialize(cache_path) - @cache_path = cache_path - end - - def write(name, value, options = nil) #:nodoc: - ensure_cache_path(File.dirname(real_file_path(name))) - File.open(real_file_path(name), "wb+") { |f| f.write(value) } - rescue => e - Base.logger.error "Couldn't create cache directory: #{name} (#{e.message})" if Base.logger - end - - def read(name, options = nil) #:nodoc: - File.open(real_file_path(name), 'rb') { |f| f.read } rescue nil - end - - def delete(name, options) #:nodoc: - File.delete(real_file_path(name)) - rescue SystemCallError => e - # If there's no cache, then there's nothing to complain about - end - - def delete_matched(matcher, options) #:nodoc: - search_dir(@cache_path) do |f| - if f =~ matcher - begin - File.delete(f) - rescue SystemCallError => e - # If there's no cache, then there's nothing to complain about - end - end - end - end - - private - def real_file_path(name) - '%s/%s.cache' % [@cache_path, name.gsub('?', '.').gsub(':', '.')] - end - - def ensure_cache_path(path) - FileUtils.makedirs(path) unless File.exist?(path) - end - - def search_dir(dir, &callback) - Dir.foreach(dir) do |d| - next if d == "." || d == ".." - name = File.join(dir, d) - if File.directory?(name) - search_dir(name, &callback) - else - callback.call name - end - end - end - end - - class FileStore < UnthreadedFileStore #:nodoc: - def initialize(cache_path) - super(cache_path) - if ActionController::Base.allow_concurrency - @mutex = Mutex.new - FileStore.module_eval { include ThreadSafety } - end - end - end - end - - # Sweepers are the terminators of the caching world and responsible for expiring caches when model objects change. - # They do this by being half-observers, half-filters and implementing callbacks for both roles. A Sweeper example: - # - # class ListSweeper < ActionController::Caching::Sweeper - # observe List, Item - # - # def after_save(record) - # list = record.is_a?(List) ? record : record.list - # expire_page(:controller => "lists", :action => %w( show public feed ), :id => list.id) - # expire_action(:controller => "lists", :action => "all") - # list.shares.each { |share| expire_page(:controller => "lists", :action => "show", :id => share.url_key) } - # end - # end - # - # The sweeper is assigned in the controllers that wish to have its job performed using the cache_sweeper class method: - # - # class ListsController < ApplicationController - # caches_action :index, :show, :public, :feed - # cache_sweeper :list_sweeper, :only => [ :edit, :destroy, :share ] - # end - # - # In the example above, four actions are cached and three actions are responsible for expiring those caches. - module Sweeping - def self.included(base) #:nodoc: - base.extend(ClassMethods) - end - - module ClassMethods #:nodoc: - def cache_sweeper(*sweepers) - return unless perform_caching - configuration = sweepers.extract_options! - sweepers.each do |sweeper| - ActiveRecord::Base.observers << sweeper if defined?(ActiveRecord) and defined?(ActiveRecord::Base) - sweeper_instance = Object.const_get(Inflector.classify(sweeper)).instance - - if sweeper_instance.is_a?(Sweeper) - around_filter(sweeper_instance, :only => configuration[:only]) - else - after_filter(sweeper_instance, :only => configuration[:only]) - end - end - end - end - end - - if defined?(ActiveRecord) and defined?(ActiveRecord::Observer) - class Sweeper < ActiveRecord::Observer #:nodoc: - attr_accessor :controller - - def before(controller) - self.controller = controller - callback(:before) - end - - def after(controller) - callback(:after) - # Clean up, so that the controller can be collected after this request - self.controller = nil - end - - protected - # gets the action cache path for the given options. - def action_path_for(options) - ActionController::Caching::Actions::ActionCachePath.path_for(controller, options) - end - - # Retrieve instance variables set in the controller. - def assigns(key) - controller.instance_variable_get("@#{key}") - end - - private - def callback(timing) - controller_callback_method_name = "#{timing}_#{controller.controller_name.underscore}" - action_callback_method_name = "#{controller_callback_method_name}_#{controller.action_name}" - - send!(controller_callback_method_name) if respond_to?(controller_callback_method_name, true) - send!(action_callback_method_name) if respond_to?(action_callback_method_name, true) - end - - def method_missing(method, *arguments) - return if @controller.nil? - @controller.send!(method, *arguments) - end - end - end - - module SqlCache - def self.included(base) #:nodoc: - if defined?(ActiveRecord) && ActiveRecord::Base.respond_to?(:cache) - base.alias_method_chain :perform_action, :caching - end - end - - def perform_action_with_caching - ActiveRecord::Base.cache do - perform_action_without_caching - end - end - end end -end +end \ No newline at end of file diff --git a/vendor/rails/actionpack/lib/action_controller/caching/actions.rb b/vendor/rails/actionpack/lib/action_controller/caching/actions.rb new file mode 100644 index 00000000..7b0551c6 --- /dev/null +++ b/vendor/rails/actionpack/lib/action_controller/caching/actions.rb @@ -0,0 +1,143 @@ +require 'set' + +module ActionController #:nodoc: + module Caching + # Action caching is similar to page caching by the fact that the entire output of the response is cached, but unlike page caching, + # every request still goes through the Action Pack. The key benefit of this is that filters are run before the cache is served, which + # allows for authentication and other restrictions on whether someone is allowed to see the cache. Example: + # + # class ListsController < ApplicationController + # before_filter :authenticate, :except => :public + # caches_page :public + # caches_action :show, :feed + # end + # + # In this example, the public action doesn't require authentication, so it's possible to use the faster page caching method. But both the + # show and feed action are to be shielded behind the authenticate filter, so we need to implement those as action caches. + # + # Action caching internally uses the fragment caching and an around filter to do the job. The fragment cache is named according to both + # the current host and the path. So a page that is accessed at http://david.somewhere.com/lists/show/1 will result in a fragment named + # "david.somewhere.com/lists/show/1". This allows the cacher to differentiate between "david.somewhere.com/lists/" and + # "jamis.somewhere.com/lists/" -- which is a helpful way of assisting the subdomain-as-account-key pattern. + # + # Different representations of the same resource, e.g. http://david.somewhere.com/lists and http://david.somewhere.com/lists.xml + # are treated like separate requests and so are cached separately. Keep in mind when expiring an action cache that :action => 'lists' is not the same + # as :action => 'list', :format => :xml. + # + # You can set modify the default action cache path by passing a :cache_path option. This will be passed directly to ActionCachePath.path_for. This is handy + # for actions with multiple possible routes that should be cached differently. If a block is given, it is called with the current controller instance. + # + # class ListsController < ApplicationController + # before_filter :authenticate, :except => :public + # caches_page :public + # caches_action :show, :cache_path => { :project => 1 } + # caches_action :show, :cache_path => Proc.new { |controller| + # controller.params[:user_id] ? + # controller.send(:user_list_url, c.params[:user_id], c.params[:id]) : + # controller.send(:list_url, c.params[:id]) } + # end + module Actions + def self.included(base) #:nodoc: + base.extend(ClassMethods) + base.class_eval do + attr_accessor :rendered_action_cache, :action_cache_path + end + end + + module ClassMethods + # Declares that +actions+ should be cached. + # See ActionController::Caching::Actions for details. + def caches_action(*actions) + return unless cache_configured? + around_filter(ActionCacheFilter.new(*actions)) + end + end + + protected + def expire_action(options = {}) + return unless cache_configured? + + if options[:action].is_a?(Array) + options[:action].dup.each do |action| + expire_fragment(ActionCachePath.path_for(self, options.merge({ :action => action }))) + end + else + expire_fragment(ActionCachePath.path_for(self, options)) + end + end + + class ActionCacheFilter #:nodoc: + def initialize(*actions, &block) + @options = actions.extract_options! + @actions = Set.new(actions) + end + + def before(controller) + return unless @actions.include?(controller.action_name.intern) + + cache_path = ActionCachePath.new(controller, path_options_for(controller, @options)) + + 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) + false + else + controller.action_cache_path = cache_path + end + end + + def after(controller) + return if !@actions.include?(controller.action_name.intern) || controller.rendered_action_cache || !caching_allowed(controller) + controller.write_fragment(controller.action_cache_path.path, controller.response.body) + end + + private + def set_content_type!(controller, extension) + controller.response.content_type = Mime::Type.lookup_by_extension(extension).to_s if extension + end + + def path_options_for(controller, options) + ((path_options = options[:cache_path]).respond_to?(:call) ? path_options.call(controller) : path_options) || {} + end + + def caching_allowed(controller) + controller.request.get? && controller.response.headers['Status'].to_i == 200 + end + end + + class ActionCachePath + attr_reader :path, :extension + + class << self + def path_for(controller, options) + new(controller, options).path + end + end + + def initialize(controller, options = {}) + @extension = extract_extension(controller.request.path) + path = controller.url_for(options).split('://').last + normalize!(path) + add_extension!(path, @extension) + @path = URI.unescape(path) + end + + private + def normalize!(path) + path << 'index' if path[-1] == ?/ + end + + def add_extension!(path, extension) + path << ".#{extension}" if extension + end + + def extract_extension(file_path) + # Don't want just what comes after the last '.' to accommodate multi part extensions + # such as tar.gz. + file_path[/^[^.]+\.(.+)$/, 1] + end + end + end + end +end \ No newline at end of file diff --git a/vendor/rails/actionpack/lib/action_controller/caching/fragments.rb b/vendor/rails/actionpack/lib/action_controller/caching/fragments.rb new file mode 100644 index 00000000..e4d8678a --- /dev/null +++ b/vendor/rails/actionpack/lib/action_controller/caching/fragments.rb @@ -0,0 +1,127 @@ +module ActionController #:nodoc: + module Caching + # Fragment caching is used for caching various blocks within templates without caching the entire action as a whole. This is useful when + # certain elements of an action change frequently or depend on complicated state while other parts rarely change or can be shared amongst multiple + # parties. The caching is doing using the cache helper available in the Action View. A template with caching might look something like: + # + # Hello <%= @name %> + # <% cache do %> + # All the topics in the system: + # <%= render :partial => "topic", :collection => Topic.find(:all) %> + # <% end %> + # + # This cache will bind to the name of the action that called it, so if this code was part of the view for the topics/list action, you would + # be able to invalidate it using expire_fragment(:controller => "topics", :action => "list"). + # + # This default behavior is of limited use if you need to cache multiple fragments per action or if the action itself is cached using + # caches_action, so we also have the option to qualify the name of the cached fragment with something like: + # + # <% cache(:action => "list", :action_suffix => "all_topics") do %> + # + # That would result in a name such as "/topics/list/all_topics", avoiding conflicts with the action cache and with any fragments that use a + # different suffix. Note that the URL doesn't have to really exist or be callable - the url_for system is just used to generate unique + # cache names that we can refer to when we need to expire the cache. + # + # The expiration call for this example is: + # + # expire_fragment(:controller => "topics", :action => "list", :action_suffix => "all_topics") + module Fragments + def self.included(base) #:nodoc: + base.class_eval do + class << self + def fragment_cache_store=(store_option) #:nodoc: + ActiveSupport::Deprecation.warn('The fragment_cache_store= method is now use cache_store=') + self.cache_store = store_option + end + + def fragment_cache_store #:nodoc: + ActiveSupport::Deprecation.warn('The fragment_cache_store method is now use cache_store') + cache_store + end + end + + def fragment_cache_store=(store_option) #:nodoc: + ActiveSupport::Deprecation.warn('The fragment_cache_store= method is now use cache_store=') + self.cache_store = store_option + end + + def fragment_cache_store #:nodoc: + ActiveSupport::Deprecation.warn('The fragment_cache_store method is now use cache_store') + cache_store + end + end + end + + # Given a key (as described in expire_fragment), returns a key suitable for use in reading, + # writing, or expiring a cached fragment. If the key is a hash, the generated key is the return + # value of url_for on that hash (without the protocol). All keys are prefixed with "views/" and uses + # ActiveSupport::Cache.expand_cache_key for the expansion. + def fragment_cache_key(key) + ActiveSupport::Cache.expand_cache_key(key.is_a?(Hash) ? url_for(key).split("://").last : key, :views) + 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) + else + pos = buffer.length + block.call + write_fragment(name, buffer[pos..-1], options) + end + end + + # Writes content to the location signified by key (see expire_fragment for acceptable formats) + def write_fragment(key, content, options = nil) + return unless cache_configured? + + key = fragment_cache_key(key) + + self.class.benchmark "Cached fragment miss: #{key}" do + cache_store.write(key, content, options) + end + + content + end + + # Reads a cached fragment from the location signified by key (see expire_fragment for acceptable formats) + def read_fragment(key, options = nil) + return unless cache_configured? + + key = fragment_cache_key(key) + + self.class.benchmark "Cached fragment hit: #{key}" do + cache_store.read(key, options) + end + end + + # Name can take one of three forms: + # * String: This would normally take the form of a path like "pages/45/notes" + # * Hash: Is treated as an implicit call to url_for, like { :controller => "pages", :action => "notes", :id => 45 } + # * Regexp: Will destroy all the matched fragments, example: + # %r{pages/\d*/notes} + # Ensure you do not specify start and finish in the regex (^$) because + # the actual filename matched looks like ./cache/filename/path.cache + # Regexp expiration is only supported on caches that can iterate over + # all keys (unlike memcached). + def expire_fragment(key, options = nil) + return unless cache_configured? + + key = key.is_a?(Regexp) ? key : fragment_cache_key(key) + + if key.is_a?(Regexp) + self.class.benchmark "Expired fragments matching: #{key.source}" do + cache_store.delete_matched(key, options) + end + else + self.class.benchmark "Expired fragment: #{key}" do + cache_store.delete(key, options) + end + end + end + end + end +end \ No newline at end of file diff --git a/vendor/rails/actionpack/lib/action_controller/caching/pages.rb b/vendor/rails/actionpack/lib/action_controller/caching/pages.rb new file mode 100644 index 00000000..a70ed72f --- /dev/null +++ b/vendor/rails/actionpack/lib/action_controller/caching/pages.rb @@ -0,0 +1,154 @@ +require 'fileutils' +require 'uri' + +module ActionController #:nodoc: + module Caching + # Page caching is an approach to caching where the entire action output of is stored as a HTML file that the web server + # can serve without going through Action Pack. This is the fastest way to cache your content as opposed to going dynamically + # through the process of generating the content. Unfortunately, this incredible speed-up is only available to stateless pages + # where all visitors are treated the same. Content management systems -- including weblogs and wikis -- have many pages that are + # a great fit for this approach, but account-based systems where people log in and manipulate their own data are often less + # likely candidates. + # + # Specifying which actions to cache is done through the caches_page class method: + # + # class WeblogController < ActionController::Base + # caches_page :show, :new + # end + # + # This will generate cache files such as weblog/show/5.html and weblog/new.html, + # which match the URLs used to trigger the dynamic generation. This is how the web server is able + # pick up a cache file when it exists and otherwise let the request pass on to Action Pack to generate it. + # + # Expiration of the cache is handled by deleting the cached file, which results in a lazy regeneration approach where the cache + # is not restored before another hit is made against it. The API for doing so mimics the options from +url_for+ and friends: + # + # class WeblogController < ActionController::Base + # def update + # List.update(params[:list][:id], params[:list]) + # expire_page :action => "show", :id => params[:list][:id] + # redirect_to :action => "show", :id => params[:list][:id] + # end + # end + # + # Additionally, you can expire caches using Sweepers that act on changes in the model to determine when a cache is supposed to be + # expired. + # + # == Setting the cache directory + # + # The cache directory should be the document root for the web server and is set using Base.page_cache_directory = "/document/root". + # For Rails, this directory has already been set to Rails.public_path (which is usually set to RAILS_ROOT + "/public"). Changing + # this setting can be useful to avoid naming conflicts with files in public/, but doing so will likely require configuring your + # web server to look in the new location for cached files. + # + # == Setting the cache extension + # + # Most Rails requests do not have an extension, such as /weblog/new. In these cases, the page caching mechanism will add one in + # order to make it easy for the cached files to be picked up properly by the web server. By default, this cache extension is .html. + # If you want something else, like .php or .shtml, just set Base.page_cache_extension. In cases where a request already has an + # extension, such as .xml or .rss, page caching will not add an extension. This allows it to work well with RESTful apps. + module Pages + def self.included(base) #:nodoc: + base.extend(ClassMethods) + base.class_eval do + @@page_cache_directory = defined?(Rails.public_path) ? Rails.public_path : "" + cattr_accessor :page_cache_directory + + @@page_cache_extension = '.html' + cattr_accessor :page_cache_extension + end + end + + module ClassMethods + # Expires the page that was cached with the +path+ as a key. Example: + # expire_page "/lists/show" + def expire_page(path) + return unless perform_caching + + benchmark "Expired page: #{page_cache_file(path)}" do + File.delete(page_cache_path(path)) if File.exist?(page_cache_path(path)) + end + end + + # Manually cache the +content+ in the key determined by +path+. Example: + # cache_page "I'm the cached content", "/lists/show" + def cache_page(content, path) + return unless perform_caching + + benchmark "Cached page: #{page_cache_file(path)}" do + FileUtils.makedirs(File.dirname(page_cache_path(path))) + File.open(page_cache_path(path), "wb+") { |f| f.write(content) } + end + end + + # Caches the +actions+ using the page-caching approach that'll store the cache in a path within the page_cache_directory that + # matches the triggering url. + # + # Usage: + # + # # cache the index action + # caches_page :index + # + # # cache the index action except for JSON requests + # caches_page :index, :if => Proc.new { |c| !c.request.format.json? } + def caches_page(*actions) + return unless perform_caching + options = actions.extract_options! + after_filter({:only => actions}.merge(options)) { |c| c.cache_page } + end + + private + def page_cache_file(path) + name = (path.empty? || path == "/") ? "/index" : URI.unescape(path.chomp('/')) + name << page_cache_extension unless (name.split('/').last || name).include? '.' + return name + end + + def page_cache_path(path) + page_cache_directory + page_cache_file(path) + end + end + + # Expires the page that was cached with the +options+ as a key. Example: + # expire_page :controller => "lists", :action => "show" + def expire_page(options = {}) + return unless perform_caching + + if options.is_a?(Hash) + if options[:action].is_a?(Array) + options[:action].dup.each do |action| + self.class.expire_page(url_for(options.merge(:only_path => true, :skip_relative_url_root => true, :action => action))) + end + else + self.class.expire_page(url_for(options.merge(:only_path => true, :skip_relative_url_root => true))) + end + else + self.class.expire_page(options) + end + end + + # Manually cache the +content+ in the key determined by +options+. If no content is provided, the contents of response.body is used + # If no options are provided, the requested url is used. Example: + # cache_page "I'm the cached content", :controller => "lists", :action => "show" + def cache_page(content = nil, options = nil) + return unless perform_caching && caching_allowed + + path = case options + when Hash + url_for(options.merge(:only_path => true, :skip_relative_url_root => true, :format => params[:format])) + when String + options + else + request.path + end + + self.class.cache_page(content || response.body, path) + end + + private + def caching_allowed + request.get? && response.headers['Status'].to_i == 200 + end + end + end +end \ No newline at end of file diff --git a/vendor/rails/actionpack/lib/action_controller/caching/sql_cache.rb b/vendor/rails/actionpack/lib/action_controller/caching/sql_cache.rb new file mode 100644 index 00000000..139be610 --- /dev/null +++ b/vendor/rails/actionpack/lib/action_controller/caching/sql_cache.rb @@ -0,0 +1,18 @@ +module ActionController #:nodoc: + module Caching + module SqlCache + def self.included(base) #:nodoc: + if defined?(ActiveRecord) && ActiveRecord::Base.respond_to?(:cache) + base.alias_method_chain :perform_action, :caching + end + end + + protected + def perform_action_with_caching + ActiveRecord::Base.cache do + perform_action_without_caching + end + end + end + end +end \ No newline at end of file diff --git a/vendor/rails/actionpack/lib/action_controller/caching/sweeping.rb b/vendor/rails/actionpack/lib/action_controller/caching/sweeping.rb new file mode 100644 index 00000000..3164e14f --- /dev/null +++ b/vendor/rails/actionpack/lib/action_controller/caching/sweeping.rb @@ -0,0 +1,97 @@ +module ActionController #:nodoc: + module Caching + # Sweepers are the terminators of the caching world and responsible for expiring caches when model objects change. + # They do this by being half-observers, half-filters and implementing callbacks for both roles. A Sweeper example: + # + # class ListSweeper < ActionController::Caching::Sweeper + # observe List, Item + # + # def after_save(record) + # list = record.is_a?(List) ? record : record.list + # expire_page(:controller => "lists", :action => %w( show public feed ), :id => list.id) + # expire_action(:controller => "lists", :action => "all") + # list.shares.each { |share| expire_page(:controller => "lists", :action => "show", :id => share.url_key) } + # end + # end + # + # The sweeper is assigned in the controllers that wish to have its job performed using the cache_sweeper class method: + # + # class ListsController < ApplicationController + # caches_action :index, :show, :public, :feed + # cache_sweeper :list_sweeper, :only => [ :edit, :destroy, :share ] + # end + # + # In the example above, four actions are cached and three actions are responsible for expiring those caches. + # + # You can also name an explicit class in the declaration of a sweeper, which is needed if the sweeper is in a module: + # + # class ListsController < ApplicationController + # caches_action :index, :show, :public, :feed + # cache_sweeper OpenBar::Sweeper, :only => [ :edit, :destroy, :share ] + # end + module Sweeping + def self.included(base) #:nodoc: + base.extend(ClassMethods) + end + + module ClassMethods #:nodoc: + def cache_sweeper(*sweepers) + configuration = sweepers.extract_options! + + sweepers.each do |sweeper| + ActiveRecord::Base.observers << sweeper if defined?(ActiveRecord) and defined?(ActiveRecord::Base) + sweeper_instance = (sweeper.is_a?(Symbol) ? Object.const_get(Inflector.classify(sweeper)) : sweeper).instance + + if sweeper_instance.is_a?(Sweeper) + around_filter(sweeper_instance, :only => configuration[:only]) + else + after_filter(sweeper_instance, :only => configuration[:only]) + end + end + end + end + end + + if defined?(ActiveRecord) and defined?(ActiveRecord::Observer) + class Sweeper < ActiveRecord::Observer #:nodoc: + attr_accessor :controller + + def before(controller) + self.controller = controller + callback(:before) if controller.perform_caching + end + + def after(controller) + callback(:after) if controller.perform_caching + # Clean up, so that the controller can be collected after this request + self.controller = nil + end + + protected + # gets the action cache path for the given options. + def action_path_for(options) + ActionController::Caching::Actions::ActionCachePath.path_for(controller, options) + end + + # Retrieve instance variables set in the controller. + def assigns(key) + controller.instance_variable_get("@#{key}") + end + + private + def callback(timing) + controller_callback_method_name = "#{timing}_#{controller.controller_name.underscore}" + action_callback_method_name = "#{controller_callback_method_name}_#{controller.action_name}" + + send!(controller_callback_method_name) if respond_to?(controller_callback_method_name, true) + send!(action_callback_method_name) if respond_to?(action_callback_method_name, true) + end + + def method_missing(method, *arguments) + return if @controller.nil? + @controller.send!(method, *arguments) + end + end + end + end +end \ No newline at end of file diff --git a/vendor/rails/actionpack/lib/action_controller/cgi_ext/cookie.rb b/vendor/rails/actionpack/lib/action_controller/cgi_ext/cookie.rb index 07d2f08d..3dd374f1 100644 --- a/vendor/rails/actionpack/lib/action_controller/cgi_ext/cookie.rb +++ b/vendor/rails/actionpack/lib/action_controller/cgi_ext/cookie.rb @@ -89,13 +89,12 @@ class CGI #:nodoc: cookies = Hash.new([]) if raw_cookie - raw_cookie.split(/[;,]\s?/).each do |pairs| - name, values = pairs.split('=',2) - next unless name and values + raw_cookie.split(/;\s?/).each do |pairs| + name, value = pairs.split('=',2) + next unless name and value name = CGI::unescape(name) - values = values.split('&').collect!{|v| CGI::unescape(v) } unless cookies.has_key?(name) - cookies[name] = new(name, *values) + cookies[name] = new(name, CGI::unescape(value)) end end end diff --git a/vendor/rails/actionpack/lib/action_controller/cgi_process.rb b/vendor/rails/actionpack/lib/action_controller/cgi_process.rb index 6a802aa8..b529db8a 100644 --- a/vendor/rails/actionpack/lib/action_controller/cgi_process.rb +++ b/vendor/rails/actionpack/lib/action_controller/cgi_process.rb @@ -3,7 +3,7 @@ require 'action_controller/session/cookie_store' module ActionController #:nodoc: class Base - # Process a request extracted from an CGI object and return a response. Pass false as session_options to disable + # Process a request extracted from a CGI object and return a response. Pass false as session_options to disable # sessions (large performance increase if sessions are not needed). The session_options are the same as for CGI::Session: # # * :database_manager - standard options are CGI::Session::FileStore, CGI::Session::MemoryStore, and CGI::Session::PStore @@ -17,7 +17,7 @@ module ActionController #:nodoc: # an ArgumentError is raised. # * :session_expires - the time the current session expires, as a +Time+ object. If not set, the session will continue # indefinitely. - # * :session_domain - the hostname domain for which this session is valid. If not set, defaults to the hostname of the + # * :session_domain - the hostname domain for which this session is valid. If not set, defaults to the hostname of the # server. # * :session_secure - if +true+, this session will only work over HTTPS. # * :session_path - the path for which this session applies. Defaults to the directory of the CGI script. @@ -34,7 +34,8 @@ module ActionController #:nodoc: class CgiRequest < AbstractRequest #:nodoc: attr_accessor :cgi, :session_options - class SessionFixationAttempt < StandardError; end #:nodoc: + class SessionFixationAttempt < StandardError #:nodoc: + end DEFAULT_SESSION_OPTIONS = { :database_manager => CGI::Session::CookieStore, # store data in cookie diff --git a/vendor/rails/actionpack/lib/action_controller/components.rb b/vendor/rails/actionpack/lib/action_controller/components.rb index 7f7ecfff..8275bd38 100644 --- a/vendor/rails/actionpack/lib/action_controller/components.rb +++ b/vendor/rails/actionpack/lib/action_controller/components.rb @@ -39,12 +39,7 @@ module ActionController #:nodoc: base.class_eval do include InstanceMethods extend ClassMethods - - helper do - def render_component(options) - @controller.send!(:render_component_as_string, options) - end - end + helper HelperMethods # If this controller was instantiated to process a component request, # +parent_controller+ points to the instantiator of this controller. @@ -67,6 +62,12 @@ module ActionController #:nodoc: end end + module HelperMethods + def render_component(options) + @controller.send!(:render_component_as_string, options) + end + end + module InstanceMethods # Extracts the action_name from the request parameters and performs that action. def process_with_components(request, response, method = :perform_action, *arguments) #:nodoc: diff --git a/vendor/rails/actionpack/lib/action_controller/cookies.rb b/vendor/rails/actionpack/lib/action_controller/cookies.rb index 19847c69..a4cddbce 100644 --- a/vendor/rails/actionpack/lib/action_controller/cookies.rb +++ b/vendor/rails/actionpack/lib/action_controller/cookies.rb @@ -1,31 +1,38 @@ module ActionController #:nodoc: - # Cookies are read and written through ActionController#cookies. The cookies being read are what were received along with the request, - # the cookies being written are what will be sent out with the response. Cookies are read by value (so you won't get the cookie object - # itself back -- just the value it holds). Examples for writing: + # Cookies are read and written through ActionController#cookies. # - # cookies[:user_name] = "david" # => Will set a simple session cookie + # The cookies being read are the ones received along with the request, the cookies + # being written will be sent out with the response. Reading a cookie does not get + # the cookie object itself back, just the value it holds. + # + # Examples for writing: + # + # # Sets a simple session cookie. + # cookies[:user_name] = "david" + # + # # Sets a cookie that expires in 1 hour. # cookies[:login] = { :value => "XJ-122", :expires => 1.hour.from_now } - # # => Will set a cookie that expires in 1 hour # # Examples for reading: # # cookies[:user_name] # => "david" - # cookies.size # => 2 + # cookies.size # => 2 # # Example for deleting: # # cookies.delete :user_name # - # All the option symbols for setting cookies are: + # The option symbols for setting cookies are: # - # * value - the cookie's value or list of values (as an array). - # * path - the path for which this cookie applies. Defaults to the root of the application. - # * domain - the domain for which this cookie applies. - # * expires - the time at which this cookie expires, as a +Time+ object. - # * secure - whether this cookie is a secure cookie or not (default to false). - # Secure cookies are only transmitted to HTTPS servers. - # * http_only - whether this cookie is accessible via scripting or only HTTP (defaults to false). - + # * :value - The cookie's value or list of values (as an array). + # * :path - The path for which this cookie applies. Defaults to the root + # of the application. + # * :domain - The domain for which this cookie applies. + # * :expires - The time at which this cookie expires, as a Time object. + # * :secure - Whether this cookie is a only transmitted to HTTPS servers. + # Default is +false+. + # * :http_only - Whether this cookie is accessible via scripting or + # only HTTP. Defaults to +false+. module Cookies def self.included(base) base.helper_method :cookies @@ -45,8 +52,7 @@ module ActionController #:nodoc: update(@cookies) end - # Returns the value of the cookie by +name+ -- or nil if no such cookie exists. You set new cookies using cookies[]= - # (for simple name/value cookies without options). + # Returns the value of the cookie by +name+, or +nil+ if no such cookie exists. def [](name) cookie = @cookies[name.to_s] if cookie && cookie.respond_to?(:value) @@ -54,6 +60,8 @@ module ActionController #:nodoc: end end + # Sets the cookie named +name+. The second argument may be the very cookie + # value, or a hash of options as documented above. def []=(name, options) if options.is_a?(Hash) options = options.inject({}) { |options, pair| options[pair.first.to_s] = pair.last; options } @@ -66,14 +74,18 @@ module ActionController #:nodoc: end # Removes the cookie on the client machine by setting the value to an empty string - # and setting its expiration date into the past. Like []=, you can pass in an options - # hash to delete cookies with extra data such as a +path+. + # and setting its expiration date into the past. Like []=, you can pass in + # an options hash to delete cookies with extra data such as a :path. def delete(name, options = {}) options.stringify_keys! set_cookie(options.merge("name" => name.to_s, "value" => "", "expires" => Time.at(0))) end private + # Builds a CGI::Cookie object and adds the cookie to the response headers. + # + # The path of the cookie defaults to "/" if there's none in +options+, and + # everything is passed to the CGI::Cookie constructor. def set_cookie(options) #:doc: options["path"] = "/" unless options["path"] cookie = CGI::Cookie.new(options) diff --git a/vendor/rails/actionpack/lib/action_controller/dispatcher.rb b/vendor/rails/actionpack/lib/action_controller/dispatcher.rb index c8656e4b..6e1e7a26 100644 --- a/vendor/rails/actionpack/lib/action_controller/dispatcher.rb +++ b/vendor/rails/actionpack/lib/action_controller/dispatcher.rb @@ -2,27 +2,39 @@ module ActionController # Dispatches requests to the appropriate controller and takes care of # reloading the app after each request when Dependencies.load? is true. class Dispatcher + @@guard = Mutex.new + class << self + def define_dispatcher_callbacks(cache_classes) + unless cache_classes + # Development mode callbacks + before_dispatch :reload_application + after_dispatch :cleanup_application + end + + # Common callbacks + to_prepare :load_application_controller do + begin + require_dependency 'application' unless defined?(::ApplicationController) + rescue LoadError => error + raise unless error.message =~ /application\.rb/ + end + end + + if defined?(ActiveRecord) + before_dispatch { ActiveRecord::Base.verify_active_connections! } + to_prepare(:activerecord_instantiate_observers) { ActiveRecord::Base.instantiate_observers } + end + + after_dispatch :flush_logger if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER.respond_to?(:flush) + end + # Backward-compatible class method takes CGI-specific args. Deprecated # in favor of Dispatcher.new(output, request, response).dispatch. def dispatch(cgi = nil, session_options = CgiRequest::DEFAULT_SESSION_OPTIONS, output = $stdout) new(output).dispatch_cgi(cgi, session_options) end - # Declare a block to be called before each dispatch. - # Run in the order declared. - def before_dispatch(*method_names, &block) - callbacks[:before].concat method_names - callbacks[:before] << block if block_given? - end - - # Declare a block to be called after each dispatch. - # Run in reverse of the order declared. - def after_dispatch(*method_names, &block) - callbacks[:after].concat method_names - callbacks[:after] << block if block_given? - end - # Add a preparation callback. Preparation callbacks are run before every # request in development mode, and before the first request in production # mode. @@ -32,16 +44,9 @@ module ActionController # existing callback. Passing an identifier is a suggested practice if the # code adding a preparation block may be reloaded. def to_prepare(identifier = nil, &block) - # Already registered: update the existing callback - if identifier - if callback = callbacks[:prepare].assoc(identifier) - callback[1] = block - else - callbacks[:prepare] << [identifier, block] - end - else - callbacks[:prepare] << block - end + @prepare_dispatch_callbacks ||= ActiveSupport::Callbacks::CallbackChain.new + callback = ActiveSupport::Callbacks::Callback.new(:prepare_dispatch, block, :identifier => identifier) + @prepare_dispatch_callbacks | callback end # If the block raises, send status code as a last-ditch response. @@ -86,37 +91,26 @@ module ActionController end cattr_accessor :error_file_path - self.error_file_path = "#{::RAILS_ROOT}/public" if defined? ::RAILS_ROOT + self.error_file_path = Rails.public_path if defined?(Rails.public_path) - cattr_accessor :callbacks - self.callbacks = Hash.new { |h, k| h[k] = [] } - - cattr_accessor :unprepared - self.unprepared = true - - - before_dispatch :reload_application - before_dispatch :prepare_application - after_dispatch :flush_logger - after_dispatch :cleanup_application - - if defined? ActiveRecord - to_prepare :activerecord_instantiate_observers do - ActiveRecord::Base.instantiate_observers - end - end + include ActiveSupport::Callbacks + define_callbacks :prepare_dispatch, :before_dispatch, :after_dispatch def initialize(output, request = nil, response = nil) @output, @request, @response = output, request, response end def dispatch - run_callbacks :before - handle_request - rescue Exception => exception - failsafe_rescue exception - ensure - run_callbacks :after, :reverse_each + @@guard.synchronize do + begin + run_callbacks :before_dispatch + handle_request + rescue Exception => exception + failsafe_rescue exception + ensure + run_callbacks :after_dispatch, :enumerator => :reverse_each + end + end end def dispatch_cgi(cgi, session_options) @@ -130,39 +124,23 @@ module ActionController end def reload_application - if Dependencies.load? - Routing::Routes.reload - self.unprepared = true - end - end + # Run prepare callbacks before every request in development mode + run_callbacks :prepare_dispatch - def prepare_application(force = false) - begin - require_dependency 'application' unless defined?(::ApplicationController) - rescue LoadError => error - raise unless error.message =~ /application\.rb/ - end - - ActiveRecord::Base.verify_active_connections! if defined?(ActiveRecord) - - if unprepared || force - run_callbacks :prepare - self.unprepared = false - end + Routing::Routes.reload + ActionView::TemplateFinder.reload! unless ActionView::Base.cache_template_loading 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(force = false) - if Dependencies.load? || force - ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord) - Dependencies.clear - ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord) - end + def cleanup_application + ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord) + Dependencies.clear + ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord) end def flush_logger - RAILS_DEFAULT_LOGGER.flush if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER.respond_to?(:flush) + RAILS_DEFAULT_LOGGER.flush end protected @@ -171,17 +149,6 @@ module ActionController @controller.process(@request, @response).out(@output) end - def run_callbacks(kind, enumerator = :each) - callbacks[kind].send!(enumerator) do |callback| - case callback - when Proc; callback.call(self) - when String, Symbol; send!(callback) - when Array; callback[1].call(self) - else raise ArgumentError, "Unrecognized callback #{callback.inspect}" - end - end - end - def failsafe_rescue(exception) self.class.failsafe_response(@output, '500 Internal Server Error', exception) do if @controller ||= defined?(::ApplicationController) ? ::ApplicationController : Base diff --git a/vendor/rails/actionpack/lib/action_controller/filters.rb b/vendor/rails/actionpack/lib/action_controller/filters.rb index d7fb2761..6d0c83eb 100644 --- a/vendor/rails/actionpack/lib/action_controller/filters.rb +++ b/vendor/rails/actionpack/lib/action_controller/filters.rb @@ -126,8 +126,8 @@ module ActionController #:nodoc: # end # # To use a filter object with around_filter, pass an object responding - # to :filter or both :before and :after. With a filter method, yield to - # the block as above: + # to :filter or both :before and :after. With a + # filter method, yield to the block as above: # # around_filter BenchmarkingFilter # @@ -191,8 +191,9 @@ module ActionController #:nodoc: # == Filter conditions # # Filters may be limited to specific actions by declaring the actions to - # include or exclude. Both options accept single actions (:only => :index) - # or arrays of actions (:except => [:foo, :bar]). + # include or exclude. Both options accept single actions + # (:only => :index) or arrays of actions + # (:except => [:foo, :bar]). # # class Journal < ActionController::Base # # Require authentication for edit and delete. @@ -244,17 +245,212 @@ module ActionController #:nodoc: # filter and controller action will not be run. If #before renders or redirects, # the second half of #around and will still run but #after and the # action will not. If #around fails to yield, #after will not be run. + + class FilterChain < ActiveSupport::Callbacks::CallbackChain #:nodoc: + def append_filter_to_chain(filters, filter_type, &block) + pos = find_filter_append_position(filters, filter_type) + update_filter_chain(filters, filter_type, pos, &block) + end + + def prepend_filter_to_chain(filters, filter_type, &block) + pos = find_filter_prepend_position(filters, filter_type) + update_filter_chain(filters, filter_type, pos, &block) + end + + def create_filters(filters, filter_type, &block) + filters, conditions = extract_options(filters, &block) + filters.map! { |filter| find_or_create_filter(filter, filter_type, conditions) } + filters + end + + def skip_filter_in_chain(*filters, &test) + filters, conditions = extract_options(filters) + filters.each do |filter| + if callback = find(filter) then delete(callback) end + end if conditions.empty? + update_filter_in_chain(filters, :skip => conditions, &test) + end + + private + def update_filter_chain(filters, filter_type, pos, &block) + new_filters = create_filters(filters, filter_type, &block) + insert(pos, new_filters).flatten! + end + + def find_filter_append_position(filters, filter_type) + # appending an after filter puts it at the end of the call chain + # before and around filters go before the first after filter in the chain + unless filter_type == :after + each_with_index do |f,i| + return i if f.after? + end + end + return -1 + end + + def find_filter_prepend_position(filters, filter_type) + # prepending a before or around filter puts it at the front of the call chain + # after filters go before the first after filter in the chain + if filter_type == :after + each_with_index do |f,i| + return i if f.after? + end + return -1 + end + return 0 + end + + def find_or_create_filter(filter, filter_type, options = {}) + update_filter_in_chain([filter], options) + + if found_filter = find(filter) { |f| f.type == filter_type } + found_filter + else + filter_kind = case + when filter.respond_to?(:before) && filter_type == :before + :before + when filter.respond_to?(:after) && filter_type == :after + :after + else + :filter + end + + case filter_type + when :before + BeforeFilter.new(filter_kind, filter, options) + when :after + AfterFilter.new(filter_kind, filter, options) + else + AroundFilter.new(filter_kind, filter, options) + end + end + end + + def update_filter_in_chain(filters, options, &test) + filters.map! { |f| block_given? ? find(f, &test) : find(f) } + filters.compact! + + map! do |filter| + if filters.include?(filter) + new_filter = filter.dup + new_filter.options.merge!(options) + new_filter + else + filter + end + end + end + end + + class Filter < ActiveSupport::Callbacks::Callback #:nodoc: + def before? + self.class == BeforeFilter + end + + def after? + self.class == AfterFilter + end + + def around? + self.class == AroundFilter + end + + private + def should_not_skip?(controller) + if options[:skip] + !included_in_action?(controller, options[:skip]) + else + true + end + end + + def included_in_action?(controller, options) + if options[:only] + Array(options[:only]).map(&:to_s).include?(controller.action_name) + elsif options[:except] + !Array(options[:except]).map(&:to_s).include?(controller.action_name) + else + true + end + end + + def should_run_callback?(controller) + should_not_skip?(controller) && included_in_action?(controller, options) && super + end + end + + class AroundFilter < Filter #:nodoc: + def type + :around + end + + def call(controller, &block) + if should_run_callback?(controller) + method = filter_responds_to_before_and_after? ? around_proc : self.method + + # For around_filter do |controller, action| + if method.is_a?(Proc) && method.arity == 2 + evaluate_method(method, controller, block) + else + evaluate_method(method, controller, &block) + end + else + block.call + end + end + + private + def filter_responds_to_before_and_after? + method.respond_to?(:before) && method.respond_to?(:after) + end + + def around_proc + Proc.new do |controller, action| + method.before(controller) + + if controller.send!(:performed?) + controller.send!(:halt_filter_chain, method, :rendered_or_redirected) + else + begin + action.call + ensure + method.after(controller) + end + end + end + end + end + + class BeforeFilter < Filter #:nodoc: + def type + :before + end + + def call(controller, &block) + super + if controller.send!(:performed?) + controller.send!(:halt_filter_chain, method, :rendered_or_redirected) + end + end + end + + class AfterFilter < Filter #:nodoc: + def type + :after + end + end + module ClassMethods # The passed filters will be appended to the filter_chain and # will execute before the action on this controller is performed. def append_before_filter(*filters, &block) - append_filter_to_chain(filters, :before, &block) + filter_chain.append_filter_to_chain(filters, :before, &block) end # The passed filters will be prepended to the filter_chain and # will execute before the action on this controller is performed. def prepend_before_filter(*filters, &block) - prepend_filter_to_chain(filters, :before, &block) + filter_chain.prepend_filter_to_chain(filters, :before, &block) end # Shorthand for append_before_filter since it's the most common. @@ -263,19 +459,18 @@ module ActionController #:nodoc: # The passed filters will be appended to the array of filters # that run _after_ actions on this controller are performed. def append_after_filter(*filters, &block) - append_filter_to_chain(filters, :after, &block) + filter_chain.append_filter_to_chain(filters, :after, &block) end # The passed filters will be prepended to the array of filters # that run _after_ actions on this controller are performed. def prepend_after_filter(*filters, &block) - prepend_filter_to_chain(filters, :after, &block) + filter_chain.prepend_filter_to_chain(filters, :after, &block) end # Shorthand for append_after_filter since it's the most common. alias :after_filter :append_after_filter - # If you append_around_filter A.new, B.new, the filter chain looks like # # B#before @@ -287,10 +482,7 @@ module ActionController #:nodoc: # With around filters which yield to the action block, #before and #after # are the code before and after the yield. def append_around_filter(*filters, &block) - filters, conditions = extract_conditions(filters, &block) - filters.map { |f| proxy_before_and_after_filter(f) }.each do |filter| - append_filter_to_chain([filter, conditions]) - end + filter_chain.append_filter_to_chain(filters, :around, &block) end # If you prepend_around_filter A.new, B.new, the filter chain looks like: @@ -304,10 +496,7 @@ module ActionController #:nodoc: # With around filters which yield to the action block, #before and #after # are the code before and after the yield. def prepend_around_filter(*filters, &block) - filters, conditions = extract_conditions(filters, &block) - filters.map { |f| proxy_before_and_after_filter(f) }.each do |filter| - prepend_filter_to_chain([filter, conditions]) - end + filter_chain.prepend_filter_to_chain(filters, :around, &block) end # Shorthand for append_around_filter since it's the most common. @@ -320,7 +509,7 @@ module ActionController #:nodoc: # You can control the actions to skip the filter for with the :only and :except options, # just like when you apply the filters. def skip_before_filter(*filters) - skip_filter_in_chain(*filters, &:before?) + filter_chain.skip_filter_in_chain(*filters, &:before?) end # Removes the specified filters from the +after+ filter chain. Note that this only works for skipping method-reference @@ -330,7 +519,7 @@ module ActionController #:nodoc: # You can control the actions to skip the filter for with the :only and :except options, # just like when you apply the filters. def skip_after_filter(*filters) - skip_filter_in_chain(*filters, &:after?) + filter_chain.skip_filter_in_chain(*filters, &:after?) end # Removes the specified filters from the filter chain. This only works for method reference (symbol) @@ -340,334 +529,30 @@ module ActionController #:nodoc: # You can control the actions to skip the filter for with the :only and :except options, # just like when you apply the filters. def skip_filter(*filters) - skip_filter_in_chain(*filters) + filter_chain.skip_filter_in_chain(*filters) end # Returns an array of Filter objects for this controller. def filter_chain - read_inheritable_attribute("filter_chain") || [] + if chain = read_inheritable_attribute('filter_chain') + return chain + else + write_inheritable_attribute('filter_chain', FilterChain.new) + return filter_chain + end end # Returns all the before filters for this class and all its ancestors. # This method returns the actual filter that was assigned in the controller to maintain existing functionality. def before_filters #:nodoc: - filter_chain.select(&:before?).map(&:filter) + filter_chain.select(&:before?).map(&:method) end # Returns all the after filters for this class and all its ancestors. # This method returns the actual filter that was assigned in the controller to maintain existing functionality. def after_filters #:nodoc: - filter_chain.select(&:after?).map(&:filter) + filter_chain.select(&:after?).map(&:method) end - - # Returns a mapping between filters and the actions that may run them. - def included_actions #:nodoc: - @included_actions ||= read_inheritable_attribute("included_actions") || {} - end - - # Returns a mapping between filters and actions that may not run them. - def excluded_actions #:nodoc: - @excluded_actions ||= read_inheritable_attribute("excluded_actions") || {} - end - - # Find a filter in the filter_chain where the filter method matches the _filter_ param - # and (optionally) the passed block evaluates to true (mostly used for testing before? - # and after? on the filter). Useful for symbol filters. - # - # The object of type Filter is passed to the block when yielded, not the filter itself. - def find_filter(filter, &block) #:nodoc: - filter_chain.select { |f| f.filter == filter && (!block_given? || yield(f)) }.first - end - - # Returns true if the filter is excluded from the given action - def filter_excluded_from_action?(filter,action) #:nodoc: - case - when ia = included_actions[filter] - !ia.include?(action) - when ea = excluded_actions[filter] - ea.include?(action) - end - end - - # Filter class is an abstract base class for all filters. Handles all of the included/excluded actions but - # contains no logic for calling the actual filters. - class Filter #:nodoc: - attr_reader :filter, :included_actions, :excluded_actions - - def initialize(filter) - @filter = filter - end - - def type - :around - end - - def before? - type == :before - end - - def after? - type == :after - end - - def around? - type == :around - end - - def run(controller) - raise ActionControllerError, 'No filter type: Nothing to do here.' - end - - def call(controller, &block) - run(controller) - end - end - - # Abstract base class for filter proxies. FilterProxy objects are meant to mimic the behaviour of the old - # before_filter and after_filter by moving the logic into the filter itself. - class FilterProxy < Filter #:nodoc: - def filter - @filter.filter - end - end - - class BeforeFilterProxy < FilterProxy #:nodoc: - def type - :before - end - - def run(controller) - # only filters returning false are halted. - @filter.call(controller) - if controller.send!(:performed?) - controller.send!(:halt_filter_chain, @filter, :rendered_or_redirected) - end - end - - def call(controller) - yield unless run(controller) - end - end - - class AfterFilterProxy < FilterProxy #:nodoc: - def type - :after - end - - def run(controller) - @filter.call(controller) - end - - def call(controller) - yield - run(controller) - end - end - - class SymbolFilter < Filter #:nodoc: - def call(controller, &block) - controller.send!(@filter, &block) - end - end - - class ProcFilter < Filter #:nodoc: - def call(controller) - @filter.call(controller) - rescue LocalJumpError # a yield from a proc... no no bad dog. - raise(ActionControllerError, 'Cannot yield from a Proc type filter. The Proc must take two arguments and execute #call on the second argument.') - end - end - - class ProcWithCallFilter < Filter #:nodoc: - def call(controller, &block) - @filter.call(controller, block) - rescue LocalJumpError # a yield from a proc... no no bad dog. - raise(ActionControllerError, 'Cannot yield from a Proc type filter. The Proc must take two arguments and execute #call on the second argument.') - end - end - - class MethodFilter < Filter #:nodoc: - def call(controller, &block) - @filter.call(controller, &block) - end - end - - class ClassFilter < Filter #:nodoc: - def call(controller, &block) - @filter.filter(controller, &block) - end - end - - class ClassBeforeFilter < Filter #:nodoc: - def call(controller, &block) - @filter.before(controller) - end - end - - class ClassAfterFilter < Filter #:nodoc: - def call(controller, &block) - @filter.after(controller) - end - end - - protected - def append_filter_to_chain(filters, filter_type = :around, &block) - pos = find_filter_append_position(filters, filter_type) - update_filter_chain(filters, filter_type, pos, &block) - end - - def prepend_filter_to_chain(filters, filter_type = :around, &block) - pos = find_filter_prepend_position(filters, filter_type) - update_filter_chain(filters, filter_type, pos, &block) - end - - def update_filter_chain(filters, filter_type, pos, &block) - new_filters = create_filters(filters, filter_type, &block) - new_chain = filter_chain.insert(pos, new_filters).flatten - write_inheritable_attribute('filter_chain', new_chain) - end - - def find_filter_append_position(filters, filter_type) - # appending an after filter puts it at the end of the call chain - # before and around filters go before the first after filter in the chain - unless filter_type == :after - filter_chain.each_with_index do |f,i| - return i if f.after? - end - end - return -1 - end - - def find_filter_prepend_position(filters, filter_type) - # prepending a before or around filter puts it at the front of the call chain - # after filters go before the first after filter in the chain - if filter_type == :after - filter_chain.each_with_index do |f,i| - return i if f.after? - end - return -1 - end - return 0 - end - - def create_filters(filters, filter_type, &block) #:nodoc: - filters, conditions = extract_conditions(filters, &block) - filters.map! { |filter| find_or_create_filter(filter, filter_type) } - update_conditions(filters, conditions) - filters - end - - def find_or_create_filter(filter, filter_type) - if found_filter = find_filter(filter) { |f| f.type == filter_type } - found_filter - else - f = class_for_filter(filter, filter_type).new(filter) - # apply proxy to filter if necessary - case filter_type - when :before - BeforeFilterProxy.new(f) - when :after - AfterFilterProxy.new(f) - else - f - end - end - end - - # The determination of the filter type was once done at run time. - # This method is here to extract as much logic from the filter run time as possible - def class_for_filter(filter, filter_type) #:nodoc: - case - when filter.is_a?(Symbol) - SymbolFilter - when filter.respond_to?(:call) - if filter.is_a?(Method) - MethodFilter - elsif filter.arity == 1 - ProcFilter - else - ProcWithCallFilter - end - when filter.respond_to?(:filter) - ClassFilter - when filter.respond_to?(:before) && filter_type == :before - ClassBeforeFilter - when filter.respond_to?(:after) && filter_type == :after - ClassAfterFilter - else - raise(ActionControllerError, 'A filter must be a Symbol, Proc, Method, or object responding to filter, after or before.') - end - end - - def extract_conditions(*filters, &block) #:nodoc: - filters.flatten! - conditions = filters.extract_options! - filters << block if block_given? - return filters, conditions - end - - def update_conditions(filters, conditions) - return if conditions.empty? - if conditions[:only] - write_inheritable_hash('included_actions', condition_hash(filters, conditions[:only])) - elsif conditions[:except] - write_inheritable_hash('excluded_actions', condition_hash(filters, conditions[:except])) - end - end - - def condition_hash(filters, *actions) - actions = actions.flatten.map(&:to_s) - filters.inject({}) { |h,f| h.update( f => (actions.blank? ? nil : actions)) } - end - - def skip_filter_in_chain(*filters, &test) #:nodoc: - filters, conditions = extract_conditions(filters) - filters.map! { |f| block_given? ? find_filter(f, &test) : find_filter(f) } - filters.compact! - - if conditions.empty? - delete_filters_in_chain(filters) - else - remove_actions_from_included_actions!(filters,conditions[:only] || []) - conditions[:only], conditions[:except] = conditions[:except], conditions[:only] - update_conditions(filters,conditions) - end - end - - def remove_actions_from_included_actions!(filters,*actions) - actions = actions.flatten.map(&:to_s) - updated_hash = filters.inject(read_inheritable_attribute('included_actions')||{}) do |hash,filter| - ia = (hash[filter] || []) - actions - ia.empty? ? hash.delete(filter) : hash[filter] = ia - hash - end - write_inheritable_attribute('included_actions', updated_hash) - end - - def delete_filters_in_chain(filters) #:nodoc: - write_inheritable_attribute('filter_chain', filter_chain.reject { |f| filters.include?(f) }) - end - - def filter_responds_to_before_and_after(filter) #:nodoc: - filter.respond_to?(:before) && filter.respond_to?(:after) - end - - def proxy_before_and_after_filter(filter) #:nodoc: - return filter unless filter_responds_to_before_and_after(filter) - Proc.new do |controller, action| - filter.before(controller) - - if controller.send!(:performed?) - controller.send!(:halt_filter_chain, filter, :rendered_or_redirected) - else - begin - action.call - ensure - filter.after(controller) - end - end - end - end end module InstanceMethods # :nodoc: @@ -679,89 +564,80 @@ module ActionController #:nodoc: end protected + def process_with_filters(request, response, method = :perform_action, *arguments) #:nodoc: + @before_filter_chain_aborted = false + process_without_filters(request, response, method, *arguments) + end - def process_with_filters(request, response, method = :perform_action, *arguments) #:nodoc: - @before_filter_chain_aborted = false - process_without_filters(request, response, method, *arguments) - end - - def perform_action_with_filters - call_filters(self.class.filter_chain, 0, 0) - end + def perform_action_with_filters + call_filters(self.class.filter_chain, 0, 0) + end private - - def call_filters(chain, index, nesting) - index = run_before_filters(chain, index, nesting) - aborted = @before_filter_chain_aborted - perform_action_without_filters unless performed? || aborted - return index if nesting != 0 || aborted - run_after_filters(chain, index) - end - - def skip_excluded_filters(chain, index) - while (filter = chain[index]) && self.class.filter_excluded_from_action?(filter, action_name) - index = index.next + def call_filters(chain, index, nesting) + index = run_before_filters(chain, index, nesting) + aborted = @before_filter_chain_aborted + perform_action_without_filters unless performed? || aborted + return index if nesting != 0 || aborted + run_after_filters(chain, index) end - [filter, index] - end - def run_before_filters(chain, index, nesting) - while chain[index] - filter, index = skip_excluded_filters(chain, index) - break unless filter # end of call chain reached + def run_before_filters(chain, index, nesting) + while chain[index] + filter, index = chain[index], index + break unless filter # end of call chain reached - case filter.type - when :before - filter.run(self) # invoke before filter - index = index.next - break if @before_filter_chain_aborted - when :around - yielded = false + case filter + when BeforeFilter + filter.call(self) # invoke before filter + index = index.next + break if @before_filter_chain_aborted + when AroundFilter + yielded = false - filter.call(self) do - yielded = true - # all remaining before and around filters will be run in this call - index = call_filters(chain, index.next, nesting.next) + filter.call(self) do + yielded = true + # all remaining before and around filters will be run in this call + index = call_filters(chain, index.next, nesting.next) + end + + halt_filter_chain(filter, :did_not_yield) unless yielded + + break + else + break # no before or around filters left + end + end + + index + end + + def run_after_filters(chain, index) + seen_after_filter = false + + while chain[index] + filter, index = chain[index], index + break unless filter # end of call chain reached + + case filter + when AfterFilter + seen_after_filter = true + filter.call(self) # invoke after filter + else + # implementation error or someone has mucked with the filter chain + raise ActionControllerError, "filter #{filter.inspect} was in the wrong place!" if seen_after_filter end - halt_filter_chain(filter, :did_not_yield) unless yielded - - break - else - break # no before or around filters left - end - end - - index - end - - def run_after_filters(chain, index) - seen_after_filter = false - - while chain[index] - filter, index = skip_excluded_filters(chain, index) - break unless filter # end of call chain reached - - case filter.type - when :after - seen_after_filter = true - filter.run(self) # invoke after filter - else - # implementation error or someone has mucked with the filter chain - raise ActionControllerError, "filter #{filter.inspect} was in the wrong place!" if seen_after_filter + index = index.next end - index = index.next + index.next end - index.next - end - - def halt_filter_chain(filter, reason) - @before_filter_chain_aborted = true - logger.info "Filter chain halted as [#{filter.inspect}] #{reason}." if logger - end + def halt_filter_chain(filter, reason) + @before_filter_chain_aborted = true + logger.info "Filter chain halted as [#{filter.inspect}] #{reason}." if logger + end end end end diff --git a/vendor/rails/actionpack/lib/action_controller/flash.rb b/vendor/rails/actionpack/lib/action_controller/flash.rb index 692168f2..0148fb5c 100644 --- a/vendor/rails/actionpack/lib/action_controller/flash.rb +++ b/vendor/rails/actionpack/lib/action_controller/flash.rb @@ -28,7 +28,6 @@ module ActionController #:nodoc: base.class_eval do include InstanceMethods alias_method_chain :assign_shortcuts, :flash - alias_method_chain :process_cleanup, :flash alias_method_chain :reset_session, :flash end end @@ -166,11 +165,7 @@ module ActionController #:nodoc: def assign_shortcuts_with_flash(request, response) #:nodoc: assign_shortcuts_without_flash(request, response) flash(:refresh) - end - - def process_cleanup_with_flash - flash.sweep if @_session - process_cleanup_without_flash + flash.sweep if @_session && !component_request? end end end diff --git a/vendor/rails/actionpack/lib/action_controller/headers.rb b/vendor/rails/actionpack/lib/action_controller/headers.rb new file mode 100644 index 00000000..7239438c --- /dev/null +++ b/vendor/rails/actionpack/lib/action_controller/headers.rb @@ -0,0 +1,31 @@ +module ActionController + module Http + class Headers < ::Hash + + def initialize(constructor = {}) + if constructor.is_a?(Hash) + super() + update(constructor) + else + super(constructor) + end + end + + def [](header_name) + if include?(header_name) + super + else + super(normalize_header(header_name)) + end + end + + + private + # Takes an HTTP header name and returns it in the + # format + def normalize_header(header_name) + "HTTP_#{header_name.upcase.gsub(/-/, '_')}" + end + end + end +end \ No newline at end of file diff --git a/vendor/rails/actionpack/lib/action_controller/helpers.rb b/vendor/rails/actionpack/lib/action_controller/helpers.rb index 81b8ff97..a8bead4d 100644 --- a/vendor/rails/actionpack/lib/action_controller/helpers.rb +++ b/vendor/rails/actionpack/lib/action_controller/helpers.rb @@ -143,11 +143,19 @@ module ActionController #:nodoc: # Declare a controller method as a helper. For example, the following # makes the +current_user+ controller method available to the view: # class ApplicationController < ActionController::Base - # helper_method :current_user + # helper_method :current_user, :logged_in? + # # def current_user - # @current_user ||= User.find(session[:user]) + # @current_user ||= User.find_by_id(session[:user]) # end + # + # def logged_in? + # current_user != nil + # end # end + # + # In a view: + # <% if logged_in? -%>Welcome, <%= current_user.name %><% end -%> def helper_method(*methods) methods.flatten.each do |method| master_helper_module.module_eval <<-end_eval @@ -167,6 +175,15 @@ module ActionController #:nodoc: attrs.flatten.each { |attr| helper_method(attr, "#{attr}=") } end + # Provides a proxy to access helpers methods from outside the view. + def helpers + unless @helper_proxy + @helper_proxy = ActionView::Base.new + @helper_proxy.extend master_helper_module + else + @helper_proxy + end + end private def default_helper_module! diff --git a/vendor/rails/actionpack/lib/action_controller/http_authentication.rb b/vendor/rails/actionpack/lib/action_controller/http_authentication.rb index 18a503c3..31db012e 100644 --- a/vendor/rails/actionpack/lib/action_controller/http_authentication.rb +++ b/vendor/rails/actionpack/lib/action_controller/http_authentication.rb @@ -1,5 +1,3 @@ -require 'base64' - module ActionController module HttpAuthentication # Makes it dead easy to do HTTP Basic authentication. @@ -72,7 +70,7 @@ module ActionController # # On shared hosts, Apache sometimes doesn't pass authentication headers to # FCGI instances. If your environment matches this description and you cannot - # authenticate, try this rule in public/.htaccess (replace the plain one): + # authenticate, try this rule in your Apache setup: # # RewriteRule ^(.*)$ dispatch.fcgi [E=X-HTTP_AUTHORIZATION:%{HTTP:Authorization},QSA,L] module Basic @@ -110,11 +108,11 @@ module ActionController end def decode_credentials(request) - Base64.decode64(authorization(request).split.last || '') + ActiveSupport::Base64.decode64(authorization(request).split.last || '') end def encode_credentials(user_name, password) - "Basic #{Base64.encode64("#{user_name}:#{password}")}" + "Basic #{ActiveSupport::Base64.encode64("#{user_name}:#{password}")}" end def authentication_request(controller, realm) diff --git a/vendor/rails/actionpack/lib/action_controller/integration.rb b/vendor/rails/actionpack/lib/action_controller/integration.rb index 25fb1b93..a4bbee9c 100644 --- a/vendor/rails/actionpack/lib/action_controller/integration.rb +++ b/vendor/rails/actionpack/lib/action_controller/integration.rb @@ -1,6 +1,7 @@ -require 'dispatcher' require 'stringio' require 'uri' + +require 'action_controller/dispatcher' require 'action_controller/test_process' module ActionController @@ -54,6 +55,9 @@ module ActionController # A running counter of the number of requests processed. attr_accessor :request_count + class MultiPartNeededException < Exception + end + # Create and initialize a new +Session+ instance. def initialize reset! @@ -276,7 +280,7 @@ module ActionController ActionController::Base.clear_last_instantiation! cgi = StubCGI.new(env, data) - Dispatcher.dispatch(cgi, ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, cgi.stdoutput) + ActionController::Dispatcher.dispatch(cgi, ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, cgi.stdoutput) @result = cgi.stdoutput.string @request_count += 1 @@ -293,15 +297,19 @@ module ActionController parse_result return status + rescue MultiPartNeededException + boundary = "----------XnJLe9ZIbbGUYtzPQJ16u1" + status = process(method, path, multipart_body(parameters, boundary), (headers || {}).merge({"CONTENT_TYPE" => "multipart/form-data; boundary=#{boundary}"})) + return status end # Parses the result of the response and extracts the various values, # like cookies, status, headers, etc. def parse_result - headers, result_body = @result.split(/\r\n\r\n/, 2) + response_headers, result_body = @result.split(/\r\n\r\n/, 2) @headers = Hash.new { |h,k| h[k] = [] } - headers.each_line do |line| + response_headers.to_s.each_line do |line| key, value = line.strip.split(/:\s*/, 2) @headers[key.downcase] << value end @@ -311,7 +319,7 @@ module ActionController @cookies[name] = value end - @status, @status_message = @headers["status"].first.split(/ /) + @status, @status_message = @headers["status"].first.to_s.split(/ /) @status = @status.to_i end @@ -341,7 +349,9 @@ module ActionController # Convert the given parameters to a request string. The parameters may # be a string, +nil+, or a Hash. def requestify(parameters, prefix=nil) - if Hash === parameters + if TestUploadedFile === parameters + raise MultiPartNeededException + elsif Hash === parameters return nil if parameters.empty? parameters.map { |k,v| requestify(v, name_with_prefix(prefix, k)) }.join("&") elsif Array === parameters @@ -352,6 +362,45 @@ module ActionController "#{CGI.escape(prefix)}=#{CGI.escape(parameters.to_s)}" end end + + def multipart_requestify(params, first=true) + returning Hash.new do |p| + params.each do |key, value| + k = first ? CGI.escape(key.to_s) : "[#{CGI.escape(key.to_s)}]" + if Hash === value + multipart_requestify(value, false).each do |subkey, subvalue| + p[k + subkey] = subvalue + end + else + p[k] = value + end + end + end + end + + def multipart_body(params, boundary) + multipart_requestify(params).map do |key, value| + if value.respond_to?(:original_filename) + File.open(value.path) do |f| + <<-EOF +--#{boundary}\r +Content-Disposition: form-data; name="#{key}"; filename="#{CGI.escape(value.original_filename)}"\r +Content-Type: #{value.content_type}\r +Content-Length: #{File.stat(value.path).size}\r +\r +#{f.read}\r +EOF + end + else +<<-EOF +--#{boundary}\r +Content-Disposition: form-data; name="#{key}"\r +\r +#{value}\r +EOF + end + end.join("")+"--#{boundary}--\r" + end end # A module used to extend ActionController::Base, so that integration tests diff --git a/vendor/rails/actionpack/lib/action_controller/layout.rb b/vendor/rails/actionpack/lib/action_controller/layout.rb index 63a68c10..b5b59f2d 100644 --- a/vendor/rails/actionpack/lib/action_controller/layout.rb +++ b/vendor/rails/actionpack/lib/action_controller/layout.rb @@ -29,18 +29,20 @@ module ActionController #:nodoc: # # // The header part of this layout # <%= yield %> - # // The footer part of this layout --> + # // The footer part of this layout # # And then you have content pages that look like this: # # hello world # - # Not a word about common structures. At rendering time, the content page is computed and then inserted in the layout, - # like this: + # At rendering time, the content page is computed and then inserted in the layout, like this: # # // The header part of this layout # hello world - # // The footer part of this layout --> + # // The footer part of this layout + # + # NOTE: The old notation for rendering the view from a layout was to expose the magic @content_for_layout instance + # variable. The preferred notation now is to use yield, as documented above. # # == Accessing shared variables # @@ -63,15 +65,15 @@ module ActionController #:nodoc: # == Automatic layout assignment # # If there is a template in app/views/layouts/ with the same name as the current controller then it will be automatically - # set as that controller's layout unless explicitly told otherwise. Say you have a WeblogController, for example. If a template named + # set as that controller's layout unless explicitly told otherwise. Say you have a WeblogController, for example. If a template named # app/views/layouts/weblog.erb or app/views/layouts/weblog.builder exists then it will be automatically set as # the layout for your WeblogController. You can create a layout with the name application.erb or application.builder - # and this will be set as the default controller if there is no layout with the same name as the current controller and there is + # and this will be set as the default controller if there is no layout with the same name as the current controller and there is # no layout explicitly assigned with the +layout+ method. Nested controllers use the same folder structure for automatic layout. # assignment. So an Admin::WeblogController will look for a template named app/views/layouts/admin/weblog.erb. # Setting a layout explicitly will always override the automatic behaviour for the controller where the layout is set. # Explicitly setting the layout in a parent class, though, will not override the child class's layout assignment if the child - # class has a layout with the same name. + # class has a layout with the same name. # # == Inheritance for layouts # @@ -111,7 +113,7 @@ module ActionController #:nodoc: # logged_in? ? "writer_layout" : "reader_layout" # end # - # Now when a new request for the index action is processed, the layout will vary depending on whether the person accessing + # Now when a new request for the index action is processed, the layout will vary depending on whether the person accessing # is logged in or not. # # If you want to use an inline method, such as a proc, do something like this: @@ -124,48 +126,45 @@ module ActionController #:nodoc: # class WeblogController < ActionController::Base # layout "weblog_standard" # - # If no directory is specified for the template name, the template will by default be looked for in +app/views/layouts/+. + # If no directory is specified for the template name, the template will by default be looked for in app/views/layouts/. # Otherwise, it will be looked up relative to the template root. # # == Conditional layouts # # If you have a layout that by default is applied to all the actions of a controller, you still have the option of rendering - # a given action or set of actions without a layout, or restricting a layout to only a single action or a set of actions. The + # a given action or set of actions without a layout, or restricting a layout to only a single action or a set of actions. The # :only and :except options can be passed to the layout call. For example: # # class WeblogController < ActionController::Base # layout "weblog_standard", :except => :rss - # + # # # ... # # end # - # This will assign "weblog_standard" as the WeblogController's layout except for the +rss+ action, which will not wrap a layout + # This will assign "weblog_standard" as the WeblogController's layout except for the +rss+ action, which will not wrap a layout # around the rendered view. # - # Both the :only and :except condition can accept an arbitrary number of method references, so + # Both the :only and :except condition can accept an arbitrary number of method references, so # #:except => [ :rss, :text_only ] is valid, as is :except => :rss. # # == Using a different layout in the action render call - # + # # If most of your actions use the same layout, it makes perfect sense to define a controller-wide layout as described above. - # Some times you'll have exceptions, though, where one action wants to use a different layout than the rest of the controller. - # This is possible using the render method. It's just a bit more manual work as you'll have to supply fully - # qualified template and layout names as this example shows: + # Sometimes you'll have exceptions where one action wants to use a different layout than the rest of the controller. + # You can do this by passing a :layout option to the render call. For example: # # class WeblogController < ActionController::Base + # layout "weblog_standard" + # # def help - # render :action => "help/index", :layout => "help" + # render :action => "help", :layout => "help" # end # end # - # As you can see, you pass the template as the first parameter, the status code as the second ("200" is OK), and the layout - # as the third. - # - # NOTE: The old notation for rendering the view from a layout was to expose the magic @content_for_layout instance - # variable. The preferred notation now is to use yield, as documented above. + # This will render the help action with the "help" layout instead of the controller-wide "weblog_standard" layout. module ClassMethods - # If a layout is specified, all rendered actions will have their result rendered + # If a layout is specified, all rendered actions will have their result rendered # when the layout yields. This layout can itself depend on instance variables assigned during action # performance and have access to them as any normal template would. def layout(template_name, conditions = {}, auto = false) @@ -177,21 +176,19 @@ module ActionController #:nodoc: def layout_conditions #:nodoc: @layout_conditions ||= read_inheritable_attribute("layout_conditions") end - + def default_layout(format) #:nodoc: - layout = read_inheritable_attribute("layout") + layout = read_inheritable_attribute("layout") return layout unless read_inheritable_attribute("auto_layout") @default_layout ||= {} @default_layout[format] ||= default_layout_with_format(format, layout) @default_layout[format] end - + def layout_list #:nodoc: - view_paths.collect do |path| - Dir["#{path}/layouts/**/*"] - end.flatten + Array(view_paths).sum([]) { |path| Dir["#{path}/layouts/**/*"] } end - + private def inherited_with_layout(child) inherited_without_layout(child) @@ -208,13 +205,7 @@ module ActionController #:nodoc: def normalize_conditions(conditions) conditions.inject({}) {|hash, (key, value)| hash.merge(key => [value].flatten.map {|action| action.to_s})} end - - def layout_directory_exists_cache - @@layout_directory_exists_cache ||= Hash.new do |h, dirname| - h[dirname] = File.directory? dirname - end - end - + def default_layout_with_format(format, layout) list = layout_list if list.grep(%r{layouts/#{layout}\.#{format}(\.[a-z][0-9a-z]*)+$}).empty? @@ -236,7 +227,7 @@ module ActionController #:nodoc: when Symbol then send!(layout) when Proc then layout.call(self) end - + # Explicitly passed layout names with slashes are looked up relative to the template root, # but auto-discovered layouts derived from a nested controller will contain a slash, though be relative # to the 'layouts' directory so we have to check the file system to infer which case the layout name came from. @@ -250,16 +241,14 @@ module ActionController #:nodoc: end protected - def render_with_a_layout(options = nil, &block) #:nodoc: + def render_with_a_layout(options = nil, extra_options = {}, &block) #:nodoc: template_with_options = options.is_a?(Hash) - - if apply_layout?(template_with_options, options) && (layout = pick_layout(template_with_options, options)) - assert_existence_of_template_file(layout) + if (layout = pick_layout(template_with_options, options)) && apply_layout?(template_with_options, options) options = options.merge :layout => false if template_with_options logger.info("Rendering template within #{layout}") if logger - content_for_layout = render_with_no_layout(options, &block) + content_for_layout = render_with_no_layout(options, extra_options, &block) erase_render_results add_variables_to_assigns @template.instance_variable_set("@content_for_layout", content_for_layout) @@ -267,7 +256,7 @@ module ActionController #:nodoc: status = template_with_options ? options[:status] : nil render_for_text(@template.render_file(layout, true), status) else - render_with_no_layout(options, &block) + render_with_no_layout(options, extra_options, &block) end end @@ -279,7 +268,7 @@ module ActionController #:nodoc: end def candidate_for_layout?(options) - (options.has_key?(:layout) && options[:layout] != false) || + (options.has_key?(:layout) && options[:layout] != false) || options.values_at(:text, :xml, :json, :file, :inline, :partial, :nothing).compact.empty? && !template_exempt_from_layout?(options[:template] || default_template_name(options[:action])) end @@ -305,7 +294,7 @@ module ActionController #:nodoc: when only = conditions[:only] only.include?(action_name) when except = conditions[:except] - !except.include?(action_name) + !except.include?(action_name) else true end @@ -313,14 +302,9 @@ module ActionController #:nodoc: true end end - - # Does a layout directory for this class exist? - # we cache this info in a class level hash + def layout_directory?(layout_name) - view_paths.find do |path| - next unless template_path = Dir[File.join(path, 'layouts', layout_name) + ".*"].first - self.class.send!(:layout_directory_exists_cache)[File.dirname(template_path)] - end + @template.finder.find_template_extension_from_handler(File.join('layouts', layout_name)) end end end diff --git a/vendor/rails/actionpack/lib/action_controller/mime_responds.rb b/vendor/rails/actionpack/lib/action_controller/mime_responds.rb index 4ba4e626..a17782ca 100644 --- a/vendor/rails/actionpack/lib/action_controller/mime_responds.rb +++ b/vendor/rails/actionpack/lib/action_controller/mime_responds.rb @@ -125,7 +125,7 @@ module ActionController #:nodoc: @order << mime_type - @responses[mime_type] = Proc.new do + @responses[mime_type] ||= Proc.new do @response.template.template_format = mime_type.to_sym @response.content_type = mime_type.to_s block_given? ? block.call : @controller.send(:render, :action => @controller.action_name) @@ -133,7 +133,11 @@ module ActionController #:nodoc: end def any(*args, &block) - args.each { |type| send(type, &block) } + if args.any? + args.each { |type| send(type, &block) } + else + custom(@mime_type_priority.first, &block) + end end def method_missing(symbol, &block) diff --git a/vendor/rails/actionpack/lib/action_controller/mime_type.rb b/vendor/rails/actionpack/lib/action_controller/mime_type.rb index ec9d2eea..8c02f205 100644 --- a/vendor/rails/actionpack/lib/action_controller/mime_type.rb +++ b/vendor/rails/actionpack/lib/action_controller/mime_type.rb @@ -71,8 +71,11 @@ module Mime # keep track of creation order to keep the subsequent sort stable list = [] accept_header.split(/,/).each_with_index do |header, index| - params = header.split(/;\s*q=/) - list << AcceptItem.new(index, *params) unless params.empty? + params, q = header.split(/;\s*q=/) + if params + params.strip! + list << AcceptItem.new(index, params, q) unless params.empty? + end end list.sort! @@ -145,7 +148,10 @@ module Mime end def ==(mime_type) - (@synonyms + [ self ]).any? { |synonym| synonym.to_s == mime_type.to_s } if mime_type + return false if mime_type.blank? + (@synonyms + [ self ]).any? do |synonym| + synonym.to_s == mime_type.to_s || synonym.to_sym == mime_type.to_sym + end end private diff --git a/vendor/rails/actionpack/lib/action_controller/polymorphic_routes.rb b/vendor/rails/actionpack/lib/action_controller/polymorphic_routes.rb index 94aefc9a..e2b7716a 100644 --- a/vendor/rails/actionpack/lib/action_controller/polymorphic_routes.rb +++ b/vendor/rails/actionpack/lib/action_controller/polymorphic_routes.rb @@ -1,8 +1,81 @@ module ActionController + # Polymorphic URL helpers are methods for smart resolution to a named route call when + # given an ActiveRecord model instance. They are to be used in combination with + # ActionController::Resources. + # + # These methods are useful when you want to generate correct URL or path to a RESTful + # resource without having to know the exact type of the record in question. + # + # Nested resources and/or namespaces are also supported, as illustrated in the example: + # + # polymorphic_url([:admin, @article, @comment]) + # #-> results in: + # admin_article_comment_url(@article, @comment) + # + # == Usage within the framework + # + # Polymorphic URL helpers are used in a number of places throughout the Rails framework: + # + # * url_for, so you can use it with a record as the argument, e.g. + # url_for(@article); + # * ActionView::Helpers::FormHelper uses polymorphic_path, so you can write + # form_for(@article) without having to specify :url parameter for the form + # action; + # * redirect_to (which, in fact, uses url_for) so you can write + # redirect_to(post) in your controllers; + # * ActionView::Helpers::AtomFeedHelper, so you don't have to explicitly specify URLs + # for feed entries. + # + # == Prefixed polymorphic helpers + # + # In addition to polymorphic_url and polymorphic_path methods, a + # number of prefixed helpers are available as a shorthand to :action => "..." + # in options. Those are: + # + # * edit_polymorphic_url, edit_polymorphic_path + # * new_polymorphic_url, new_polymorphic_path + # * formatted_polymorphic_url, formatted_polymorphic_path + # + # Example usage: + # + # edit_polymorphic_path(@post) + # #=> /posts/1/edit + # + # formatted_polymorphic_path([@post, :pdf]) + # #=> /posts/1.pdf module PolymorphicRoutes + # Constructs a call to a named RESTful route for the given record and returns the + # resulting URL string. For example: + # + # # calls post_url(post) + # polymorphic_url(post) # => "http://example.com/posts/1" + # + # ==== Options + # + # * :action - Specifies the action prefix for the named route: + # :new, :edit, or :formatted. Default is no prefix. + # * :routing_type - Allowed values are :path or :url. + # Default is :url. + # + # ==== Examples + # + # # an Article record + # polymorphic_url(record) # same as article_url(record) + # + # # a Comment record + # polymorphic_url(record) # same as comment_url(record) + # + # # it recognizes new records and maps to the collection + # record = Comment.new + # polymorphic_url(record) # same as comments_url() + # def polymorphic_url(record_or_hash_or_array, options = {}) - record = extract_record(record_or_hash_or_array) + if record_or_hash_or_array.kind_of?(Array) + record_or_hash_or_array = record_or_hash_or_array.dup + end + record = extract_record(record_or_hash_or_array) + format = extract_format(record_or_hash_or_array, options) namespace = extract_namespace(record_or_hash_or_array) args = case record_or_hash_or_array @@ -11,9 +84,11 @@ module ActionController else [ record_or_hash_or_array ] end + args << format if format + inflection = case - when options[:action] == "new" + when options[:action].to_s == "new" args.pop :singular when record.respond_to?(:new_record?) && record.new_record? @@ -27,8 +102,11 @@ module ActionController send!(named_route, *args) end - def polymorphic_path(record_or_hash_or_array) - polymorphic_url(record_or_hash_or_array, :routing_type => :path) + # Returns the path component of a URL for the given record. It uses + # polymorphic_url with :routing_type => :path. + def polymorphic_path(record_or_hash_or_array, options = {}) + options[:routing_type] = :path + polymorphic_url(record_or_hash_or_array, options) end %w(edit new formatted).each do |action| @@ -43,26 +121,29 @@ module ActionController EOT end - private def action_prefix(options) options[:action] ? "#{options[:action]}_" : "" end def routing_type(options) - "#{options[:routing_type] || "url"}" + options[:routing_type] || :url end def build_named_route_call(records, namespace, inflection, options = {}) - records = Array.new([extract_record(records)]) unless records.is_a?(Array) - base_segment = "#{RecordIdentifier.send!("#{inflection}_class_name", records.pop)}_" - - method_root = records.reverse.inject(base_segment) do |string, name| - segment = "#{RecordIdentifier.send!("singular_class_name", name)}_" - segment << string + unless records.is_a?(Array) + record = extract_record(records) + route = '' + else + record = records.pop + route = records.inject("") do |string, parent| + string << "#{RecordIdentifier.send!("singular_class_name", parent)}_" + end end - action_prefix(options) + namespace + method_root + routing_type(options) + route << "#{RecordIdentifier.send!("#{inflection}_class_name", record)}_" + + action_prefix(options) + namespace + route + routing_type(options).to_s end def extract_record(record_or_hash_or_array) @@ -73,12 +154,22 @@ module ActionController end end + def extract_format(record_or_hash_or_array, options) + if options[:action].to_s == "formatted" && record_or_hash_or_array.is_a?(Array) + record_or_hash_or_array.pop + elsif options[:format] + options[:format] + else + nil + end + end + 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.to_s}_" + namespace << "#{record_or_namespace}_" end end end diff --git a/vendor/rails/actionpack/lib/action_controller/record_identifier.rb b/vendor/rails/actionpack/lib/action_controller/record_identifier.rb index bdf2753a..643ff7e5 100644 --- a/vendor/rails/actionpack/lib/action_controller/record_identifier.rb +++ b/vendor/rails/actionpack/lib/action_controller/record_identifier.rb @@ -33,11 +33,17 @@ module ActionController # Returns plural/singular for a record or class. Example: # - # partial_path(post) # => "posts/post" - # partial_path(Person) # => "people/person" - def partial_path(record_or_class) + # 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) - "#{klass.name.tableize}/#{klass.name.demodulize.underscore}" + + if controller_path && controller_path.include?("/") + "#{File.dirname(controller_path)}/#{klass.name.tableize}/#{klass.name.demodulize.underscore}" + else + "#{klass.name.tableize}/#{klass.name.demodulize.underscore}" + end end # The DOM class convention is to use the singular form of an object or class. Examples: @@ -53,15 +59,15 @@ module ActionController [ prefix, singular_class_name(record_or_class) ].compact * '_' end - # The DOM class convention is to use the singular form of an object or class with the id following an underscore. + # 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_class(Post.new(:id => 45)) # => "post_45" - # dom_class(Post.new) # => "new_post" + # dom_id(Post.new(:id => 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_class(Post.new(:id => 45), :edit) # => "edit_post_45" + # dom_id(Post.new(:id => 45), :edit) # => "edit_post_45" def dom_id(record, prefix = nil) prefix ||= 'new' unless record.id [ prefix, singular_class_name(record), record.id ].compact * '_' diff --git a/vendor/rails/actionpack/lib/action_controller/request.rb b/vendor/rails/actionpack/lib/action_controller/request.rb index 19948da9..d5ecbd9d 100755 --- a/vendor/rails/actionpack/lib/action_controller/request.rb +++ b/vendor/rails/actionpack/lib/action_controller/request.rb @@ -15,7 +15,7 @@ module ActionController # such as { 'RAILS_ENV' => 'production' }. attr_reader :env - # The true HTTP request method as a lowercase symbol, such as :get. + # The true HTTP request method as a lowercase symbol, such as :get. # UnknownHttpMethod is raised for invalid methods not listed in ACCEPTED_HTTP_METHODS. def request_method @request_method ||= begin @@ -28,41 +28,43 @@ module ActionController end end - # The HTTP request method as a lowercase symbol, such as :get. - # Note, HEAD is returned as :get since the two are functionally + # The HTTP request method as a lowercase symbol, such as :get. + # Note, HEAD is returned as :get since the two are functionally # equivalent from the application's perspective. def method request_method == :head ? :get : request_method end - # Is this a GET (or HEAD) request? Equivalent to request.method == :get + # Is this a GET (or HEAD) request? Equivalent to request.method == :get. def get? method == :get end - # Is this a POST request? Equivalent to request.method == :post + # Is this a POST request? Equivalent to request.method == :post. def post? request_method == :post end - # Is this a PUT request? Equivalent to request.method == :put + # Is this a PUT request? Equivalent to request.method == :put. def put? request_method == :put end - # Is this a DELETE request? Equivalent to request.method == :delete + # Is this a DELETE request? Equivalent to request.method == :delete. def delete? request_method == :delete end - # Is this a HEAD request? request.method sees HEAD as :get, so check the - # HTTP method directly. + # Is this a HEAD request? request.method sees HEAD as :get, + # so check the HTTP method directly. def head? request_method == :head end + # Provides acccess to the request's HTTP headers, for example: + # request.headers["Content-Type"] # => "text/plain" def headers - @env + @headers ||= ActionController::Http::Headers.new(@env) end def content_length @@ -111,7 +113,7 @@ module ActionController # end def format=(extension) parameters[:format] = extension.to_s - format + @format = Mime::Type.lookup_by_extension(parameters[:format]) end # Returns true if the request's "X-Requested-With" header contains @@ -122,26 +124,41 @@ module ActionController end alias xhr? :xml_http_request? + # Which IP addresses are "trusted proxies" that can be stripped from + # the right-hand-side of X-Forwarded-For + TRUSTED_PROXIES = /^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i + # Determine originating IP address. REMOTE_ADDR is the standard # but will fail if the user is behind a proxy. HTTP_CLIENT_IP and/or - # HTTP_X_FORWARDED_FOR are set by proxies so check for these before - # falling back to REMOTE_ADDR. HTTP_X_FORWARDED_FOR may be a comma- - # delimited list in the case of multiple chained proxies; the first is - # the originating IP. - # - # Security note: do not use if IP spoofing is a concern for your - # application. Since remote_ip checks HTTP headers for addresses forwarded - # by proxies, the client may send any IP. remote_addr can't be spoofed but - # also doesn't work behind a proxy, since it's always the proxy's IP. + # HTTP_X_FORWARDED_FOR are set by proxies so check for these if + # 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 - return @env['HTTP_CLIENT_IP'] if @env.include? 'HTTP_CLIENT_IP' + if TRUSTED_PROXIES !~ @env['REMOTE_ADDR'] + return @env['REMOTE_ADDR'] + end + + if @env.include? 'HTTP_CLIENT_IP' + if @env.include? 'HTTP_X_FORWARDED_FOR' + # We don't know which came from the proxy, and which from the user + raise ActionControllerError.new(< 1 && TRUSTED_PROXIES =~ remote_ips.last.strip + remote_ips.pop end - return remote_ips.first.strip unless remote_ips.empty? + return remote_ips.last.strip end @env['REMOTE_ADDR'] @@ -385,6 +402,14 @@ module ActionController body.blank? ? {} : Hash.from_xml(body).with_indifferent_access when :yaml YAML.load(body) + when :json + if body.blank? + {} + else + data = ActiveSupport::JSON.decode(body) + data = {:_json => data} unless data.is_a?(Hash) + data.with_indifferent_access + end else {} end @@ -473,7 +498,7 @@ module ActionController when Array value.map { |v| get_typed_value(v) } else - if value.is_a?(UploadedFile) + if value.respond_to? :original_filename # Uploaded file if value.original_filename value @@ -490,7 +515,6 @@ module ActionController end end - MULTIPART_BOUNDARY = %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n EOL = "\015\012" @@ -498,7 +522,7 @@ module ActionController def read_multipart(body, boundary, content_length, env) params = Hash.new([]) boundary = "--" + boundary - quoted_boundary = Regexp.quote(boundary, "n") + quoted_boundary = Regexp.quote(boundary) buf = "" bufsize = 10 * 1024 boundary_end="" @@ -583,17 +607,16 @@ module ActionController else params[name] = [content] end - break if buf.size == 0 break if content_length == -1 end raise EOFError, "bad boundary end of body part" unless boundary_end=~/--/ - begin + begin body.rewind if body.respond_to?(:rewind) - rescue Errno::ESPIPE + rescue Errno::ESPIPE # Handles exceptions raised by input streams that cannot be rewound # such as when using plain CGI under Apache - end + end params end @@ -672,6 +695,7 @@ module ActionController else top << {key => value}.with_indifferent_access push top.last + value = top[key] end else top << value @@ -679,7 +703,8 @@ module ActionController elsif top.is_a? Hash key = CGI.unescape(key) parent << (@top = {}) if top.key?(key) && parent.is_a?(Array) - return top[key] ||= value + top[key] ||= value + return top[key] else raise ArgumentError, "Don't know what to do: top is #{top.inspect}" end @@ -688,7 +713,7 @@ module ActionController end def type_conflict!(klass, value) - raise TypeError, "Conflicting types for parameter containers. Expected an instance of #{klass} but found an instance of #{value.class}. This can be caused by colliding Array and Hash parameters like qs[]=value&qs[key]=value." + raise TypeError, "Conflicting types for parameter containers. Expected an instance of #{klass} but found an instance of #{value.class}. This can be caused by colliding Array and Hash parameters like qs[]=value&qs[key]=value. (The parameters received were #{value.inspect}.)" end end diff --git a/vendor/rails/actionpack/lib/action_controller/request_forgery_protection.rb b/vendor/rails/actionpack/lib/action_controller/request_forgery_protection.rb index 75f9c0b2..139e91ec 100644 --- a/vendor/rails/actionpack/lib/action_controller/request_forgery_protection.rb +++ b/vendor/rails/actionpack/lib/action_controller/request_forgery_protection.rb @@ -13,33 +13,46 @@ module ActionController #:nodoc: base.extend(ClassMethods) end + # Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current web application, not a + # forged link from another site, is done by embedding a token based on the session (which an attacker wouldn't know) in all + # forms and Ajax requests generated by Rails and then verifying the authenticity of that token in the controller. Only + # HTML/JavaScript requests are checked, so this will not protect your XML API (presumably you'll have a different authentication + # scheme there anyway). Also, GET requests are not protected as these should be indempotent anyway. + # + # This is turned on with the protect_from_forgery method, which will check the token and raise an + # ActionController::InvalidAuthenticityToken if it doesn't match what was expected. You can customize the error message in + # production by editing public/422.html. A call to this method in ApplicationController is generated by default in post-Rails 2.0 + # applications. + # + # The token parameter is named authenticity_token by default. If you are generating an HTML form manually (without the + # use of Rails' form_for, form_tag or other helpers), you have to include a hidden field named like that and + # set its value to what is returned by form_authenticity_token. Same applies to manually constructed Ajax requests. To + # make the token available through a global variable to scripts on a certain page, you could add something like this to a view: + # + # <%= javascript_tag "window._token = '#{form_authenticity_token}'" %> + # + # Request forgery protection is disabled by default in test environment. If you are upgrading from Rails 1.x, add this to + # config/environments/test.rb: + # + # # Disable request forgery protection in test environment + # config.action_controller.allow_forgery_protection = false + # + # == Learn more about CSRF (Cross-Site Request Forgery) attacks + # + # Here are some resources: + # * http://isc.sans.org/diary.html?storyid=1750 + # * http://en.wikipedia.org/wiki/Cross-site_request_forgery + # + # Keep in mind, this is NOT a silver-bullet, plug 'n' play, warm security blanket for your rails application. + # There are a few guidelines you should follow: + # + # * Keep your GET requests safe and idempotent. More reading material: + # * http://www.xml.com/pub/a/2002/04/24/deviant.html + # * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1 + # * Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look for "Expires: at end of session" + # module ClassMethods - # Protect a controller's actions from CSRF attacks by ensuring that all forms are coming from the current web application, not - # a forged link from another site. This is done by embedding a token based on the session (which an attacker wouldn't know) in - # all forms and Ajax requests generated by Rails and then verifying the authenticity of that token in the controller. Only - # HTML/JavaScript requests are checked, so this will not protect your XML API (presumably you'll have a different authentication - # scheme there anyway). Also, GET requests are not protected as these should be indempotent anyway. - # - # You turn this on with the #protect_from_forgery method, which will perform the check and raise - # an ActionController::InvalidAuthenticityToken if the token doesn't match what was expected. And it will add - # a _authenticity_token parameter to all forms that are automatically generated by Rails. You can customize the error message - # given through public/422.html. - # - # Learn more about CSRF (Cross-Site Request Forgery) attacks: - # - # * http://isc.sans.org/diary.html?storyid=1750 - # * http://en.wikipedia.org/wiki/Cross-site_request_forgery - # - # Keep in mind, this is NOT a silver-bullet, plug 'n' play, warm security blanket for your rails application. - # There are a few guidelines you should follow: - # - # * Keep your GET requests safe and idempotent. More reading material: - # * http://www.xml.com/pub/a/2002/04/24/deviant.html - # * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1 - # * Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look for "Expires: at end of session" - # - # If you need to construct a request yourself, but still want to take advantage of forgery protection, you can grab the - # authenticity_token using the form_authenticity_token helper method and make it part of the parameters yourself. + # Turn on request forgery protection. Bear in mind that only non-GET, HTML/JavaScript requests are checked. # # Example: # @@ -54,18 +67,12 @@ module ActionController #:nodoc: # skip_before_filter :verify_authenticity_token # end # - # If you are upgrading from Rails 1.x, disable forgery protection to - # simplify your tests. Add this to config/environments/test.rb: - # - # # Disable request forgery protection in test environment - # config.action_controller.allow_forgery_protection = false - # # Valid Options: # - # * :only/:except - passed to the before_filter call. Set which actions are verified. - # * :secret - Custom salt used to generate the form_authenticity_token. + # * :only/:except - Passed to the before_filter call. Set which actions are verified. + # * :secret - Custom salt used to generate the form_authenticity_token. # Leave this off if you are using the cookie session store. - # * :digest - Message digest used for hashing. Defaults to 'SHA1' + # * :digest - Message digest used for hashing. Defaults to 'SHA1'. def protect_from_forgery(options = {}) self.request_forgery_protection_token ||= :authenticity_token before_filter :verify_authenticity_token, :only => options.delete(:only), :except => options.delete(:except) @@ -95,14 +102,15 @@ module ActionController #:nodoc: request.format.html? || request.format.js? end - # Sets the token value for the current session. Pass a :secret option in #protect_from_forgery to add a custom salt to the hash. + # Sets the token value for the current session. Pass a :secret option + # in +protect_from_forgery+ to add a custom salt to the hash. def form_authenticity_token - @form_authenticity_token ||= if request_forgery_protection_options[:secret] + @form_authenticity_token ||= if !session.respond_to?(:session_id) + raise InvalidAuthenticityToken, "Request Forgery Protection requires a valid session. Use #allow_forgery_protection to disable it, or use a valid session." + elsif request_forgery_protection_options[:secret] authenticity_token_from_session_id elsif session.respond_to?(:dbman) && session.dbman.respond_to?(:generate_digest) authenticity_token_from_cookie_session - elsif session.nil? - raise InvalidAuthenticityToken, "Request Forgery Protection requires a valid session. Use #allow_forgery_protection to disable it, or use a valid session." else raise InvalidAuthenticityToken, "No :secret given to the #protect_from_forgery call. Set that or use a session store capable of generating its own keys (Cookie Session Store)." end diff --git a/vendor/rails/actionpack/lib/action_controller/request_profiler.rb b/vendor/rails/actionpack/lib/action_controller/request_profiler.rb index 62f6e665..8a18d194 100755 --- a/vendor/rails/actionpack/lib/action_controller/request_profiler.rb +++ b/vendor/rails/actionpack/lib/action_controller/request_profiler.rb @@ -13,20 +13,21 @@ module ActionController def initialize(script_path) @quiet = false - define_run_method(File.read(script_path)) + define_run_method(script_path) reset! end def benchmark(n) @quiet = true print ' ' + result = Benchmark.realtime do n.times do |i| run - print i % 10 == 0 ? 'x' : '.' - $stdout.flush + print_progress(i) end end + puts result ensure @@ -38,8 +39,26 @@ module ActionController end private - def define_run_method(script) - instance_eval "def run; #{script}; end", __FILE__, __LINE__ + def define_run_method(script_path) + script = File.read(script_path) + + source = <<-end_source + def run + #{script} + old_request_count = request_count + reset! + self.request_count = old_request_count + end + end_source + + instance_eval source, script_path, 1 + end + + def print_progress(i) + print "\n " if i % 60 == 0 + print ' ' if i % 10 == 0 + print '.' + $stdout.flush end end @@ -98,8 +117,9 @@ module ActionController OptionParser.new do |opt| opt.banner = "USAGE: #{$0} [options] [session script path]" - opt.on('-n', '--times [0000]', 'How many requests to process. Defaults to 100.') { |v| options[:n] = v.to_i } + opt.on('-n', '--times [100]', 'How many requests to process. Defaults to 100.') { |v| options[:n] = v.to_i if v } opt.on('-b', '--benchmark', 'Benchmark instead of profiling') { |v| options[:benchmark] = v } + opt.on('-m', '--measure [mode]', 'Which ruby-prof measure mode to use: process_time, wall_time, cpu_time, allocations, or memory. Defaults to process_time.') { |v| options[:measure] = v } opt.on('--open [CMD]', 'Command to open profile results. Defaults to "open %s &"') { |v| options[:open] = v } opt.on('-h', '--help', 'Show this help') { puts opt; exit } @@ -117,7 +137,9 @@ module ActionController def load_ruby_prof begin require 'ruby-prof' - #RubyProf.measure_mode = RubyProf::ALLOCATED_OBJECTS + if mode = options[:measure] + RubyProf.measure_mode = RubyProf.const_get(mode.upcase) + end rescue LoadError abort '`gem install ruby-prof` to use the profiler' end diff --git a/vendor/rails/actionpack/lib/action_controller/rescue.rb b/vendor/rails/actionpack/lib/action_controller/rescue.rb index b91115a9..5022c9a8 100644 --- a/vendor/rails/actionpack/lib/action_controller/rescue.rb +++ b/vendor/rails/actionpack/lib/action_controller/rescue.rb @@ -26,7 +26,7 @@ module ActionController #:nodoc: DEFAULT_RESCUE_TEMPLATE = 'diagnostics' DEFAULT_RESCUE_TEMPLATES = { - 'ActionController::MissingTemplate' => 'missing_template', + 'ActionView::MissingTemplate' => 'missing_template', 'ActionController::RoutingError' => 'routing_error', 'ActionController::UnknownAction' => 'unknown_action', 'ActionView::TemplateError' => 'template_error' @@ -58,33 +58,35 @@ module ActionController #:nodoc: # Rescue exceptions raised in controller actions. # # rescue_from receives a series of exception classes or class - # names, and a trailing :with option with the name of a method or a Proc - # object to be called to handle them. Alternatively a block can be given. + # names, and a trailing :with option with the name of a method + # or a Proc object to be called to handle them. Alternatively a block can + # be given. # # Handlers that take one argument will be called with the exception, so # that the exception can be inspected when dealing with it. # # Handlers are inherited. They are searched from right to left, from # bottom to top, and up the hierarchy. The handler of the first class for - # which exception.is_a?(klass) holds true is the one invoked, if any. + # which exception.is_a?(klass) holds true is the one invoked, if + # any. # - # class ApplicationController < ActionController::Base - # rescue_from User::NotAuthorized, :with => :deny_access # self defined exception - # rescue_from ActiveRecord::RecordInvalid, :with => :show_errors + # class ApplicationController < ActionController::Base + # rescue_from User::NotAuthorized, :with => :deny_access # self defined exception + # rescue_from ActiveRecord::RecordInvalid, :with => :show_errors # - # rescue_from 'MyAppError::Base' do |exception| - # render :xml => exception, :status => 500 + # rescue_from 'MyAppError::Base' do |exception| + # render :xml => exception, :status => 500 + # end + # + # protected + # def deny_access + # ... + # end + # + # def show_errors(exception) + # exception.record.new_record? ? ... + # end # end - # - # protected - # def deny_access - # ... - # end - # - # def show_errors(exception) - # exception.record.new_record? ? ... - # end - # end def rescue_from(*klasses, &block) options = klasses.extract_options! unless options.has_key?(:with) @@ -153,7 +155,7 @@ module ActionController #:nodoc: # If the file doesn't exist, the body of the response will be left empty. def render_optional_error_file(status_code) status = interpret_status(status_code) - path = "#{RAILS_ROOT}/public/#{status[0,3]}.html" + path = "#{Rails.public_path}/#{status[0,3]}.html" if File.exist?(path) render :file => path, :status => status else @@ -165,7 +167,7 @@ module ActionController #:nodoc: # method if you wish to redefine the meaning of a local request to # include remote IP addresses or other criteria. def local_request? #:doc: - request.remote_addr == LOCALHOST and request.remote_ip == LOCALHOST + request.remote_addr == LOCALHOST && request.remote_ip == LOCALHOST end # Render detailed diagnostics for unhandled exceptions rescued from diff --git a/vendor/rails/actionpack/lib/action_controller/resources.rb b/vendor/rails/actionpack/lib/action_controller/resources.rb index 8ec6b84a..26f75780 100644 --- a/vendor/rails/actionpack/lib/action_controller/resources.rb +++ b/vendor/rails/actionpack/lib/action_controller/resources.rb @@ -44,13 +44,14 @@ module ActionController module Resources class Resource #:nodoc: attr_reader :collection_methods, :member_methods, :new_methods - attr_reader :path_prefix, :name_prefix + attr_reader :path_prefix, :name_prefix, :path_segment attr_reader :plural, :singular attr_reader :options def initialize(entities, options) @plural ||= entities @singular ||= options[:singular] || plural.to_s.singularize + @path_segment = options.delete(:as) || @plural @options = options @@ -75,11 +76,13 @@ module ActionController end def path - @path ||= "#{path_prefix}/#{plural}" + @path ||= "#{path_prefix}/#{path_segment}" end def new_path - @new_path ||= "#{path}/new" + new_action = self.options[:path_names][:new] if self.options[:path_names] + new_action ||= Base.resources_path_names[:new] + @new_path ||= "#{path}/#{new_action}" end def member_path @@ -226,17 +229,53 @@ module ActionController # # <% form_for :message, @message, :url => message_path(@message), :html => {:method => :put} do |f| %> # - # The #resources method accepts the following options to customize the resulting routes: - # * :collection - add named routes for other actions that operate on the collection. + # or + # + # <% form_for @message do |f| %> + # + # which takes into account whether @message is a new record or not and generates the + # path and method accordingly. + # + # The +resources+ method accepts the following options to customize the resulting routes: + # * :collection - Add named routes for other actions that operate on the collection. # Takes a hash of #{action} => #{method}, where method is :get/:post/:put/:delete - # or :any if the method does not matter. These routes map to a URL like /messages/rss, with a route of rss_messages_url. - # * :member - same as :collection, but for actions that operate on a specific member. - # * :new - same as :collection, but for actions that operate on the new resource action. - # * :controller - specify the controller name for the routes. - # * :singular - specify the singular name used in the member routes. - # * :requirements - set custom routing parameter requirements. - # * :conditions - specify custom routing recognition conditions. Resources sets the :method value for the method-specific routes. - # * :path_prefix - set a prefix to the routes with required route variables. + # or :any if the method does not matter. These routes map to a URL like /messages/rss, with a route of +rss_messages_url+. + # * :member - Same as :collection, but for actions that operate on a specific member. + # * :new - Same as :collection, but for actions that operate on the new resource action. + # * :controller - Specify the controller name for the routes. + # * :singular - Specify the singular name used in the member routes. + # * :requirements - Set custom routing parameter requirements. + # * :conditions - Specify custom routing recognition conditions. Resources sets the :method value for the method-specific routes. + # * :as - Specify a different resource name to use in the URL path. For example: + # # products_path == '/productos' + # map.resources :products, :as => 'productos' do |product| + # # product_reviews_path(product) == '/productos/1234/comentarios' + # product.resources :product_reviews, :as => 'comentarios' + # end + # + # * :has_one - Specify nested resources, this is a shorthand for mapping singleton resources beneath the current. + # * :has_many - Same has :has_one, but for plural resources. + # + # You may directly specify the routing association with +has_one+ and +has_many+ like: + # + # map.resources :notes, :has_one => :author, :has_many => [:comments, :attachments] + # + # This is the same as: + # + # map.resources :notes do |notes| + # notes.resource :author + # notes.resources :comments + # notes.resources :attachments + # end + # + # * :path_names - Specify different names for the 'new' and 'edit' actions. For example: + # # new_products_path == '/productos/nuevo' + # map.resources :products, :as => 'productos', :path_names => { :new => 'nuevo', :edit => 'editar' } + # + # You can also set default action names from an environment, like this: + # config.action_controller.resources_path_names = { :new => 'nuevo', :edit => 'editar' } + # + # * :path_prefix - Set a prefix to the routes with required route variables. # # Weblog comments usually belong to a post, so you might use resources like: # @@ -249,7 +288,7 @@ module ActionController # article.resources :comments # end # - # The comment resources work the same, but must now include a value for :article_id. + # The comment resources work the same, but must now include a value for :article_id. # # article_comments_url(@article) # article_comment_url(@article, @comment) @@ -257,13 +296,13 @@ module ActionController # article_comments_url(:article_id => @article) # article_comment_url(:article_id => @article, :id => @comment) # - # * :name_prefix - define a prefix for all generated routes, usually ending in an underscore. + # * :name_prefix - Define a prefix for all generated routes, usually ending in an underscore. # Use this if you have named routes that may clash. # # map.resources :tags, :path_prefix => '/books/:book_id', :name_prefix => 'book_' # map.resources :tags, :path_prefix => '/toys/:toy_id', :name_prefix => 'toy_' # - # You may also use :name_prefix to override the generic named routes in a nested resource: + # You may also use :name_prefix to override the generic named routes in a nested resource: # # map.resources :articles do |article| # article.resources :comments, :name_prefix => nil @@ -304,7 +343,7 @@ module ActionController # # --> GET /categories/7/messages/1 # # has named route "category_message" # - # The #resources method sets HTTP method restrictions on the routes it generates. For example, making an + # The +resources+ method sets HTTP method restrictions on the routes it generates. For example, making an # HTTP POST on new_message_url will raise a RoutingError exception. The default route in # config/routes.rb overrides this and allows invalid HTTP methods for resource routes. def resources(*entities, &block) @@ -325,7 +364,7 @@ module ActionController # # See map.resources for general conventions. These are the main differences: # * A singular name is given to map.resource. The default controller name is still taken from the plural name. - # * To specify a custom plural name, use the :plural option. There is no :singular option. + # * To specify a custom plural name, use the :plural option. There is no :singular option. # * No default index route is created for the singleton resource controller. # * When nesting singleton resources, only the singular name is used as the path prefix (example: 'account/messages/1') # @@ -485,8 +524,12 @@ module ActionController resource.member_methods.each do |method, actions| actions.each do |action| action_options = action_options_for(action, resource, method) - map.named_route("#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action}", action_options) - map.named_route("formatted_#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action}.:format",action_options) + + action_path = resource.options[:path_names][action] if resource.options[:path_names].is_a?(Hash) + action_path ||= Base.resources_path_names[action] || action + + map.named_route("#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action_path}", action_options) + map.named_route("formatted_#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action_path}.:format",action_options) end end diff --git a/vendor/rails/actionpack/lib/action_controller/routing.rb b/vendor/rails/actionpack/lib/action_controller/routing.rb index b0c93cca..6aa26651 100644 --- a/vendor/rails/actionpack/lib/action_controller/routing.rb +++ b/vendor/rails/actionpack/lib/action_controller/routing.rb @@ -1,53 +1,13 @@ require 'cgi' require 'uri' require 'action_controller/polymorphic_routes' -require 'action_controller/routing_optimisation' - -class Object - def to_param - to_s - end -end - -class TrueClass - def to_param - self - end -end - -class FalseClass - def to_param - self - end -end - -class NilClass - def to_param - self - end -end - -class Regexp #:nodoc: - def number_of_captures - Regexp.new("|#{source}").match('').captures.length - end - - class << self - def optionalize(pattern) - case unoptionalize(pattern) - when /\A(.|\(.*\))\Z/ then "#{pattern}?" - else "(?:#{pattern})?" - end - end - - def unoptionalize(pattern) - [/\A\(\?:(.*)\)\?\Z/, /\A(.|\(.*\))\?\Z/].each do |regexp| - return $1 if regexp =~ pattern - end - return pattern - end - end -end +require 'action_controller/routing/optimisations' +require 'action_controller/routing/routing_ext' +require 'action_controller/routing/route' +require 'action_controller/routing/segments' +require 'action_controller/routing/builder' +require 'action_controller/routing/route_set' +require 'action_controller/routing/recognition_optimisation' module ActionController # == Routing @@ -55,7 +15,7 @@ module ActionController # The routing module provides URL rewriting in native Ruby. It's a way to # redirect incoming requests to controllers and actions. This replaces # mod_rewrite rules. Best of all, Rails' Routing works with any web server. - # Routes are defined in routes.rb in your RAILS_ROOT/config directory. + # Routes are defined in config/routes.rb. # # Consider the following route, installed by Rails when you generate your # application: @@ -63,7 +23,8 @@ module ActionController # map.connect ':controller/:action/:id' # # This route states that it expects requests to consist of a - # :controller followed by an :action that in turn is fed some :id. + # :controller followed by an :action that in turn is fed + # some :id. # # Suppose you get an incoming request for /blog/edit/22, you'll end up # with: @@ -76,35 +37,35 @@ module ActionController # Think of creating routes as drawing a map for your requests. The map tells # them where to go based on some predefined pattern: # - # ActionController::Routing::Routes.draw do |map| - # Pattern 1 tells some request to go to one place - # Pattern 2 tell them to go to another - # ... - # end + # ActionController::Routing::Routes.draw do |map| + # Pattern 1 tells some request to go to one place + # Pattern 2 tell them to go to another + # ... + # end # # The following symbols are special: # # :controller maps to your controller name # :action maps to an action with your controllers # - # Other names simply map to a parameter as in the case of +:id+. + # Other names simply map to a parameter as in the case of :id. # # == Route priority # # Not all routes are created equally. Routes have priority defined by the - # order of appearance of the routes in the routes.rb file. The priority goes + # order of appearance of the routes in the config/routes.rb file. The priority goes # from top to bottom. The last route in that file is at the lowest priority # and will be applied last. If no route matches, 404 is returned. # # Within blocks, the empty pattern is at the highest priority. # In practice this works out nicely: # - # ActionController::Routing::Routes.draw do |map| - # map.with_options :controller => 'blog' do |blog| - # blog.show '', :action => 'list' - # end - # map.connect ':controller/:action/:view' - # end + # ActionController::Routing::Routes.draw do |map| + # map.with_options :controller => 'blog' do |blog| + # blog.show '', :action => 'list' + # end + # map.connect ':controller/:action/:view' + # end # # In this case, invoking blog controller (with an URL like '/blog/') # without parameters will activate the 'list' action by default. @@ -115,14 +76,15 @@ module ActionController # Hash at the end of your mapping to set any default parameters. # # Example: - # ActionController::Routing:Routes.draw do |map| - # map.connect ':controller/:action/:id', :controller => 'blog' - # end + # + # ActionController::Routing:Routes.draw do |map| + # map.connect ':controller/:action/:id', :controller => 'blog' + # end # # This sets up +blog+ as the default controller if no other is specified. # This means visiting '/' would invoke the blog controller. # - # More formally, you can define defaults in a route with the +:defaults+ key. + # More formally, you can define defaults in a route with the :defaults key. # # map.connect ':controller/:action/:id', :action => 'show', :defaults => { :page => 'Dashboard' } # @@ -133,6 +95,7 @@ module ActionController # for the full URL and +name_of_route_path+ for the URI path. # # Example: + # # # In routes.rb # map.login 'login', :controller => 'accounts', :action => 'login' # @@ -155,6 +118,12 @@ module ActionController # root_url # => 'http://www.example.com/' # root_path # => '' # + # You can also specify an already-defined named route in your map.root call: + # + # # In routes.rb + # map.new_session :controller => 'sessions', :action => 'new' + # map.root :new_session + # # Note: when using +with_options+, the route is simply named after the # method you call on the block parameter rather than map. # @@ -172,33 +141,52 @@ module ActionController # # Routes can generate pretty URLs. For example: # - # map.connect 'articles/:year/:month/:day', - # :controller => 'articles', - # :action => 'find_by_date', - # :year => /\d{4}/, - # :month => /\d{1,2}/, - # :day => /\d{1,2}/ + # map.connect 'articles/:year/:month/:day', + # :controller => 'articles', + # :action => 'find_by_date', + # :year => /\d{4}/, + # :month => /\d{1,2}/, + # :day => /\d{1,2}/ # - # # Using the route above, the url below maps to: - # # params = {:year => '2005', :month => '11', :day => '06'} - # # http://localhost:3000/articles/2005/11/06 + # Using the route above, the URL "http://localhost:3000/articles/2005/11/06" + # maps to + # + # params = {:year => '2005', :month => '11', :day => '06'} # # == Regular Expressions and parameters # You can specify a regular expression to define a format for a parameter. # - # map.geocode 'geocode/:postalcode', :controller => 'geocode', - # :action => 'show', :postalcode => /\d{5}(-\d{4})?/ + # map.geocode 'geocode/:postalcode', :controller => 'geocode', + # :action => 'show', :postalcode => /\d{5}(-\d{4})?/ # # or, more formally: # # map.geocode 'geocode/:postalcode', :controller => 'geocode', # :action => 'show', :requirements => { :postalcode => /\d{5}(-\d{4})?/ } # + # Formats can include the 'ignorecase' and 'extended syntax' regular + # expression modifiers: + # + # map.geocode 'geocode/:postalcode', :controller => 'geocode', + # :action => 'show', :postalcode => /hx\d\d\s\d[a-z]{2}/i + # + # map.geocode 'geocode/:postalcode', :controller => 'geocode', + # :action => 'show',:requirements => { + # :postalcode => /# Postcode format + # \d{5} #Prefix + # (-\d{4})? #Suffix + # /x + # } + # + # Using the multiline match modifier will raise an ArgumentError. + # Encoding regular expression modifiers are silently ignored. The + # match will always use the default encoding or ASCII. + # # == Route globbing # # Specifying *[string] as part of a rule like: # - # map.connect '*path' , :controller => 'blog' , :action => 'unrecognized?' + # map.connect '*path' , :controller => 'blog' , :action => 'unrecognized?' # # will glob all remaining parts of the route that were not recognized earlier. This idiom # must appear at the end of the path. The globbed values are in params[:path] in @@ -226,10 +214,10 @@ module ActionController # # You can reload routes if you feel you must: # - # ActionController::Routing::Routes.reload + # ActionController::Routing::Routes.reload # # This will clear all named routes and reload routes.rb if the file has been modified from - # last load. To absolutely force reloading, use +reload!+. + # last load. To absolutely force reloading, use reload!. # # == Testing Routes # @@ -237,19 +225,19 @@ module ActionController # # === +assert_routing+ # - # def test_movie_route_properly_splits - # opts = {:controller => "plugin", :action => "checkout", :id => "2"} - # assert_routing "plugin/checkout/2", opts - # end + # def test_movie_route_properly_splits + # opts = {:controller => "plugin", :action => "checkout", :id => "2"} + # assert_routing "plugin/checkout/2", opts + # end # # +assert_routing+ lets you test whether or not the route properly resolves into options. # # === +assert_recognizes+ # - # def test_route_has_options - # opts = {:controller => "plugin", :action => "show", :id => "12"} - # assert_recognizes opts, "/plugins/show/12" - # end + # def test_route_has_options + # opts = {:controller => "plugin", :action => "show", :id => "12"} + # assert_recognizes opts, "/plugins/show/12" + # end # # Note the subtle difference between the two: +assert_routing+ tests that # a URL fits options while +assert_recognizes+ tests that a URL @@ -257,16 +245,16 @@ module ActionController # # In tests you can simply pass the URL or named route to +get+ or +post+. # - # def send_to_jail - # get '/jail' - # assert_response :success - # assert_template "jail/front" - # end + # def send_to_jail + # get '/jail' + # assert_response :success + # assert_template "jail/front" + # end # - # def goes_to_login - # get login_url - # #... - # end + # def goes_to_login + # get login_url + # #... + # end # # == View a list of all your routes # @@ -289,6 +277,9 @@ module ActionController end class << self + # Expects an array of controller names as the first argument. + # Executes the passed block with only the named controllers named available. + # This method is used in internal Rails testing. def with_controllers(names) prior_controllers = @possible_controllers use_controllers! names @@ -297,6 +288,10 @@ module ActionController use_controllers! prior_controllers end + # Returns an array of paths, cleaned of double-slashes and relative path references. + # * "\\\" and "//" become "\\" or "/". + # * "/foo/bar/../config" becomes "/foo/config". + # The returned array is sorted by length, descending. def normalize_paths(paths) # do the hokey-pokey of path normalization... paths = paths.collect do |path| @@ -306,8 +301,8 @@ module ActionController gsub(%r{(.)[\\/]$}, '\1') # drop final / or \ if path ends with it # eliminate .. paths where possible - re = %r{\w+[/\\]\.\.[/\\]} - path.gsub!(%r{\w+[/\\]\.\.[/\\]}, "") while path.match(re) + re = %r{[^/\\]+[/\\]\.\.[/\\]} + path.gsub!(re, "") while path.match(re) path end @@ -315,6 +310,7 @@ module ActionController paths = paths.uniq.sort_by { |path| - path.length } end + # Returns the array of controller names currently available to ActionController::Routing. def possible_controllers unless @possible_controllers @possible_controllers = [] @@ -339,10 +335,28 @@ module ActionController @possible_controllers end + # Replaces the internal list of controllers available to ActionController::Routing with the passed argument. + # ActionController::Routing.use_controllers!([ "posts", "comments", "admin/comments" ]) def use_controllers!(controller_names) @possible_controllers = controller_names end + # Returns a controller path for a new +controller+ based on a +previous+ controller path. + # Handles 4 scenarios: + # + # * stay in the previous controller: + # controller_relative_to( nil, "groups/discussion" ) # => "groups/discussion" + # + # * stay in the previous namespace: + # controller_relative_to( "posts", "groups/discussion" ) # => "groups/posts" + # + # * forced move to the root namespace: + # controller_relative_to( "/posts", "groups/discussion" ) # => "posts" + # + # * previous namespace is root: + # controller_relative_to( "posts", "anything_with_no_slashes" ) # =>"posts" + # + def controller_relative_to(controller, previous) if controller.nil? then previous elsif controller[0] == ?/ then controller[1..-1] @@ -351,1143 +365,12 @@ module ActionController end end end - - class Route #:nodoc: - attr_accessor :segments, :requirements, :conditions, :optimise - - def initialize - @segments = [] - @requirements = {} - @conditions = {} - @optimise = true - end - - # Indicates whether the routes should be optimised with the string interpolation - # version of the named routes methods. - def optimise? - @optimise && ActionController::Base::optimise_named_routes - end - - def segment_keys - segments.collect do |segment| - segment.key if segment.respond_to? :key - end.compact - end - - # Write and compile a +generate+ method for this Route. - def write_generation - # Build the main body of the generation - body = "expired = false\n#{generation_extraction}\n#{generation_structure}" - - # If we have conditions that must be tested first, nest the body inside an if - body = "if #{generation_requirements}\n#{body}\nend" if generation_requirements - args = "options, hash, expire_on = {}" - - # Nest the body inside of a def block, and then compile it. - raw_method = method_decl = "def generate_raw(#{args})\npath = begin\n#{body}\nend\n[path, hash]\nend" - instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})" - - # expire_on.keys == recall.keys; in other words, the keys in the expire_on hash - # are the same as the keys that were recalled from the previous request. Thus, - # we can use the expire_on.keys to determine which keys ought to be used to build - # the query string. (Never use keys from the recalled request when building the - # query string.) - - method_decl = "def generate(#{args})\npath, hash = generate_raw(options, hash, expire_on)\nappend_query_string(path, hash, extra_keys(options))\nend" - instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})" - - method_decl = "def generate_extras(#{args})\npath, hash = generate_raw(options, hash, expire_on)\n[path, extra_keys(options)]\nend" - instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})" - raw_method - end - - # Build several lines of code that extract values from the options hash. If any - # of the values are missing or rejected then a return will be executed. - def generation_extraction - segments.collect do |segment| - segment.extraction_code - end.compact * "\n" - end - - # Produce a condition expression that will check the requirements of this route - # upon generation. - def generation_requirements - requirement_conditions = requirements.collect do |key, req| - if req.is_a? Regexp - value_regexp = Regexp.new "\\A#{req.source}\\Z" - "hash[:#{key}] && #{value_regexp.inspect} =~ options[:#{key}]" - else - "hash[:#{key}] == #{req.inspect}" - end - end - requirement_conditions * ' && ' unless requirement_conditions.empty? - end - - def generation_structure - segments.last.string_structure segments[0..-2] - end - - # Write and compile a +recognize+ method for this Route. - def write_recognition - # Create an if structure to extract the params from a match if it occurs. - body = "params = parameter_shell.dup\n#{recognition_extraction * "\n"}\nparams" - body = "if #{recognition_conditions.join(" && ")}\n#{body}\nend" - - # Build the method declaration and compile it - method_decl = "def recognize(path, env={})\n#{body}\nend" - instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})" - method_decl - end - - # Plugins may override this method to add other conditions, like checks on - # host, subdomain, and so forth. Note that changes here only affect route - # recognition, not generation. - def recognition_conditions - result = ["(match = #{Regexp.new(recognition_pattern).inspect}.match(path))"] - result << "conditions[:method] === env[:method]" if conditions[:method] - result - end - - # Build the regular expression pattern that will match this route. - def recognition_pattern(wrap = true) - pattern = '' - segments.reverse_each do |segment| - pattern = segment.build_pattern pattern - end - wrap ? ("\\A" + pattern + "\\Z") : pattern - end - - # Write the code to extract the parameters from a matched route. - def recognition_extraction - next_capture = 1 - extraction = segments.collect do |segment| - x = segment.match_extraction(next_capture) - next_capture += Regexp.new(segment.regexp_chunk).number_of_captures - x - end - extraction.compact - end - - # Write the real generation implementation and then resend the message. - def generate(options, hash, expire_on = {}) - write_generation - generate options, hash, expire_on - end - - def generate_extras(options, hash, expire_on = {}) - write_generation - generate_extras options, hash, expire_on - end - - # Generate the query string with any extra keys in the hash and append - # it to the given path, returning the new path. - def append_query_string(path, hash, query_keys=nil) - return nil unless path - query_keys ||= extra_keys(hash) - "#{path}#{build_query_string(hash, query_keys)}" - end - - # Determine which keys in the given hash are "extra". Extra keys are - # those that were not used to generate a particular route. The extra - # keys also do not include those recalled from the prior request, nor - # do they include any keys that were implied in the route (like a - # :controller that is required, but not explicitly used in the text of - # the route.) - def extra_keys(hash, recall={}) - (hash || {}).keys.map { |k| k.to_sym } - (recall || {}).keys - significant_keys - end - - # Build a query string from the keys of the given hash. If +only_keys+ - # is given (as an array), only the keys indicated will be used to build - # the query string. The query string will correctly build array parameter - # values. - def build_query_string(hash, only_keys = nil) - elements = [] - - (only_keys || hash.keys).each do |key| - if value = hash[key] - elements << value.to_query(key) - end - end - - elements.empty? ? '' : "?#{elements.sort * '&'}" - end - - # Write the real recognition implementation and then resend the message. - def recognize(path, environment={}) - write_recognition - recognize path, environment - end - - # A route's parameter shell contains parameter values that are not in the - # route's path, but should be placed in the recognized hash. - # - # For example, +{:controller => 'pages', :action => 'show'} is the shell for the route: - # - # map.connect '/page/:id', :controller => 'pages', :action => 'show', :id => /\d+/ - # - def parameter_shell - @parameter_shell ||= returning({}) do |shell| - requirements.each do |key, requirement| - shell[key] = requirement unless requirement.is_a? Regexp - end - end - end - - # Return an array containing all the keys that are used in this route. This - # includes keys that appear inside the path, and keys that have requirements - # placed upon them. - def significant_keys - @significant_keys ||= returning [] do |sk| - segments.each { |segment| sk << segment.key if segment.respond_to? :key } - sk.concat requirements.keys - sk.uniq! - end - end - - # Return a hash of key/value pairs representing the keys in the route that - # have defaults, or which are specified by non-regexp requirements. - def defaults - @defaults ||= returning({}) do |hash| - segments.each do |segment| - next unless segment.respond_to? :default - hash[segment.key] = segment.default unless segment.default.nil? - end - requirements.each do |key,req| - next if Regexp === req || req.nil? - hash[key] = req - end - end - end - - def matches_controller_and_action?(controller, action) - unless defined? @matching_prepared - @controller_requirement = requirement_for(:controller) - @action_requirement = requirement_for(:action) - @matching_prepared = true - end - - (@controller_requirement.nil? || @controller_requirement === controller) && - (@action_requirement.nil? || @action_requirement === action) - end - - def to_s - @to_s ||= begin - segs = segments.inject("") { |str,s| str << s.to_s } - "%-6s %-40s %s" % [(conditions[:method] || :any).to_s.upcase, segs, requirements.inspect] - end - end - - protected - def requirement_for(key) - return requirements[key] if requirements.key? key - segments.each do |segment| - return segment.regexp if segment.respond_to?(:key) && segment.key == key - end - nil - end - - end - - class Segment #:nodoc: -# RESERVED_PCHAR = ':@&=+$,;' -# UNSAFE_PCHAR = Regexp.new("[^#{URI::REGEXP::PATTERN::UNRESERVED}#{RESERVED_PCHAR}]", false, 'N').freeze - - attr_accessor :is_optional - alias_method :optional?, :is_optional - - def initialize - self.is_optional = false - end - - def extraction_code - nil - end - - # Continue generating string for the prior segments. - def continue_string_structure(prior_segments) - if prior_segments.empty? - interpolation_statement(prior_segments) - else - new_priors = prior_segments[0..-2] - prior_segments.last.string_structure(new_priors) - end - end - - def interpolation_chunk - CGI.escape(value) - end - - # Return a string interpolation statement for this segment and those before it. - def interpolation_statement(prior_segments) - chunks = prior_segments.collect { |s| s.interpolation_chunk } - chunks << interpolation_chunk - "\"#{chunks * ''}\"#{all_optionals_available_condition(prior_segments)}" - end - - def string_structure(prior_segments) - optional? ? continue_string_structure(prior_segments) : interpolation_statement(prior_segments) - end - - # Return an if condition that is true if all the prior segments can be generated. - # If there are no optional segments before this one, then nil is returned. - def all_optionals_available_condition(prior_segments) - optional_locals = prior_segments.collect { |s| s.local_name if s.optional? && s.respond_to?(:local_name) }.compact - optional_locals.empty? ? nil : " if #{optional_locals * ' && '}" - end - - # Recognition - - def match_extraction(next_capture) - nil - end - - # Warning - - # Returns true if this segment is optional? because of a default. If so, then - # no warning will be emitted regarding this segment. - def optionality_implied? - false - end - end - - class StaticSegment < Segment #:nodoc: - attr_accessor :value, :raw - alias_method :raw?, :raw - - def initialize(value = nil) - super() - self.value = value - end - - def interpolation_chunk - raw? ? value : super - end - - def regexp_chunk - chunk = Regexp.escape(value) - optional? ? Regexp.optionalize(chunk) : chunk - end - - def build_pattern(pattern) - escaped = Regexp.escape(value) - if optional? && ! pattern.empty? - "(?:#{Regexp.optionalize escaped}\\Z|#{escaped}#{Regexp.unoptionalize pattern})" - elsif optional? - Regexp.optionalize escaped - else - escaped + pattern - end - end - - def to_s - value - end - end - - class DividerSegment < StaticSegment #:nodoc: - def initialize(value = nil) - super(value) - self.raw = true - self.is_optional = true - end - - def optionality_implied? - true - end - end - - class DynamicSegment < Segment #:nodoc: - attr_accessor :key, :default, :regexp - - def initialize(key = nil, options = {}) - super() - self.key = key - self.default = options[:default] if options.key? :default - self.is_optional = true if options[:optional] || options.key?(:default) - end - - def to_s - ":#{key}" - end - - # The local variable name that the value of this segment will be extracted to. - def local_name - "#{key}_value" - end - - def extract_value - "#{local_name} = hash[:#{key}] && hash[:#{key}].to_param #{"|| #{default.inspect}" if default}" - end - def value_check - if default # Then we know it won't be nil - "#{value_regexp.inspect} =~ #{local_name}" if regexp - elsif optional? - # If we have a regexp check that the value is not given, or that it matches. - # If we have no regexp, return nil since we do not require a condition. - "#{local_name}.nil? || #{value_regexp.inspect} =~ #{local_name}" if regexp - else # Then it must be present, and if we have a regexp, it must match too. - "#{local_name} #{"&& #{value_regexp.inspect} =~ #{local_name}" if regexp}" - end - end - def expiry_statement - "expired, hash = true, options if !expired && expire_on[:#{key}]" - end - - def extraction_code - s = extract_value - vc = value_check - s << "\nreturn [nil,nil] unless #{vc}" if vc - s << "\n#{expiry_statement}" - end - - def interpolation_chunk(value_code = "#{local_name}") - "\#{CGI.escape(#{value_code}.to_s)}" - end - - def string_structure(prior_segments) - if optional? # We have a conditional to do... - # If we should not appear in the url, just write the code for the prior - # segments. This occurs if our value is the default value, or, if we are - # optional, if we have nil as our value. - "if #{local_name} == #{default.inspect}\n" + - continue_string_structure(prior_segments) + - "\nelse\n" + # Otherwise, write the code up to here - "#{interpolation_statement(prior_segments)}\nend" - else - interpolation_statement(prior_segments) - end - end - - def value_regexp - Regexp.new "\\A#{regexp.source}\\Z" if regexp - end - def regexp_chunk - regexp ? "(#{regexp.source})" : "([^#{Routing::SEPARATORS.join}]+)" - end - - def build_pattern(pattern) - chunk = regexp_chunk - chunk = "(#{chunk})" if Regexp.new(chunk).number_of_captures == 0 - pattern = "#{chunk}#{pattern}" - optional? ? Regexp.optionalize(pattern) : pattern - end - def match_extraction(next_capture) - # All non code-related keys (such as :id, :slug) are URI-unescaped as - # path parameters. - default_value = default ? default.inspect : nil - %[ - value = if (m = match[#{next_capture}]) - CGI.unescape(m) - else - #{default_value} - end - params[:#{key}] = value if value - ] - end - - def optionality_implied? - [:action, :id].include? key - end - - end - - class ControllerSegment < DynamicSegment #:nodoc: - def regexp_chunk - possible_names = Routing.possible_controllers.collect { |name| Regexp.escape name } - "(?i-:(#{(regexp || Regexp.union(*possible_names)).source}))" - end - - # Don't CGI.escape the controller name since it may contain slashes. - def interpolation_chunk(value_code = "#{local_name}") - "\#{#{value_code}.to_s}" - end - - # Make sure controller names like Admin/Content are correctly normalized to - # admin/content - def extract_value - "#{local_name} = (hash[:#{key}] #{"|| #{default.inspect}" if default}).downcase" - end - - def match_extraction(next_capture) - if default - "params[:#{key}] = match[#{next_capture}] ? match[#{next_capture}].downcase : '#{default}'" - else - "params[:#{key}] = match[#{next_capture}].downcase if match[#{next_capture}]" - end - end - end - - class PathSegment < DynamicSegment #:nodoc: -# RESERVED_PCHAR = "#{Segment::RESERVED_PCHAR}/" -# UNSAFE_PCHAR = Regexp.new("[^#{URI::REGEXP::PATTERN::UNRESERVED}#{RESERVED_PCHAR}]", false, 'N').freeze - - def interpolation_chunk(value_code = "#{local_name}") -# "\#{URI.escape(#{value_code}.to_s, ActionController::Routing::PathSegment::UNSAFE_PCHAR)}" - "\#{CGI.escape(#{value_code})}" - end - - def default - '' - end - - def default=(path) - raise RoutingError, "paths cannot have non-empty default values" unless path.blank? - end - - def match_extraction(next_capture) - "params[:#{key}] = PathSegment::Result.new_escaped((match[#{next_capture}]#{" || " + default.inspect if default}).split('/'))#{" if match[" + next_capture + "]" if !default}" - end - - def regexp_chunk - regexp || "(.*)" - end - - def optionality_implied? - true - end - - class Result < ::Array #:nodoc: - def to_s() join '/' end - def self.new_escaped(strings) - new strings.collect {|str| CGI.unescape str} - end - end - end - - class RouteBuilder #:nodoc: - attr_accessor :separators, :optional_separators - - def initialize - self.separators = Routing::SEPARATORS - self.optional_separators = %w( / ) - end - - def separator_pattern(inverted = false) - "[#{'^' if inverted}#{Regexp.escape(separators.join)}]" - end - - def interval_regexp - Regexp.new "(.*?)(#{separators.source}|$)" - end - - # Accepts a "route path" (a string defining a route), and returns the array - # of segments that corresponds to it. Note that the segment array is only - # partially initialized--the defaults and requirements, for instance, need - # to be set separately, via the #assign_route_options method, and the - # #optional? method for each segment will not be reliable until after - # #assign_route_options is called, as well. - def segments_for_route_path(path) - rest, segments = path, [] - - until rest.empty? - segment, rest = segment_for rest - segments << segment - end - segments - end - - # A factory method that returns a new segment instance appropriate for the - # format of the given string. - def segment_for(string) - segment = case string - when /\A:(\w+)/ - key = $1.to_sym - case key - when :controller then ControllerSegment.new(key) - else DynamicSegment.new key - end - when /\A\*(\w+)/ then PathSegment.new($1.to_sym, :optional => true) - when /\A\?(.*?)\?/ - returning segment = StaticSegment.new($1) do - segment.is_optional = true - end - when /\A(#{separator_pattern(:inverted)}+)/ then StaticSegment.new($1) - when Regexp.new(separator_pattern) then - returning segment = DividerSegment.new($&) do - segment.is_optional = (optional_separators.include? $&) - end - end - [segment, $~.post_match] - end - - # Split the given hash of options into requirement and default hashes. The - # segments are passed alongside in order to distinguish between default values - # and requirements. - def divide_route_options(segments, options) - options = options.dup - - if options[:namespace] - options[:controller] = "#{options[:path_prefix]}/#{options[:controller]}" - options.delete(:path_prefix) - options.delete(:name_prefix) - options.delete(:namespace) - end - - requirements = (options.delete(:requirements) || {}).dup - defaults = (options.delete(:defaults) || {}).dup - conditions = (options.delete(:conditions) || {}).dup - - path_keys = segments.collect { |segment| segment.key if segment.respond_to?(:key) }.compact - options.each do |key, value| - hash = (path_keys.include?(key) && ! value.is_a?(Regexp)) ? defaults : requirements - hash[key] = value - end - - [defaults, requirements, conditions] - end - - # Takes a hash of defaults and a hash of requirements, and assigns them to - # the segments. Any unused requirements (which do not correspond to a segment) - # are returned as a hash. - def assign_route_options(segments, defaults, requirements) - route_requirements = {} # Requirements that do not belong to a segment - - segment_named = Proc.new do |key| - segments.detect { |segment| segment.key == key if segment.respond_to?(:key) } - end - - requirements.each do |key, requirement| - segment = segment_named[key] - if segment - raise TypeError, "#{key}: requirements on a path segment must be regular expressions" unless requirement.is_a?(Regexp) - if requirement.source =~ %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z} - raise ArgumentError, "Regexp anchor characters are not allowed in routing requirements: #{requirement.inspect}" - end - segment.regexp = requirement - else - route_requirements[key] = requirement - end - end - - defaults.each do |key, default| - segment = segment_named[key] - raise ArgumentError, "#{key}: No matching segment exists; cannot assign default" unless segment - segment.is_optional = true - segment.default = default.to_param if default - end - - assign_default_route_options(segments) - ensure_required_segments(segments) - route_requirements - end - - # Assign default options, such as 'index' as a default for :action. This - # method must be run *after* user supplied requirements and defaults have - # been applied to the segments. - def assign_default_route_options(segments) - segments.each do |segment| - next unless segment.is_a? DynamicSegment - case segment.key - when :action - if segment.regexp.nil? || segment.regexp.match('index').to_s == 'index' - segment.default ||= 'index' - segment.is_optional = true - end - when :id - if segment.default.nil? && segment.regexp.nil? || segment.regexp =~ '' - segment.is_optional = true - end - end - end - end - - # Makes sure that there are no optional segments that precede a required - # segment. If any are found that precede a required segment, they are - # made required. - def ensure_required_segments(segments) - allow_optional = true - segments.reverse_each do |segment| - allow_optional &&= segment.optional? - if !allow_optional && segment.optional? - unless segment.optionality_implied? - warn "Route segment \"#{segment.to_s}\" cannot be optional because it precedes a required segment. This segment will be required." - end - segment.is_optional = false - elsif allow_optional && segment.respond_to?(:default) && segment.default - # if a segment has a default, then it is optional - segment.is_optional = true - end - end - end - - # Construct and return a route with the given path and options. - def build(path, options) - # Wrap the path with slashes - path = "/#{path}" unless path[0] == ?/ - path = "#{path}/" unless path[-1] == ?/ - - path = "/#{options[:path_prefix].to_s.gsub(/^\//,'')}#{path}" if options[:path_prefix] - - segments = segments_for_route_path(path) - defaults, requirements, conditions = divide_route_options(segments, options) - requirements = assign_route_options(segments, defaults, requirements) - - route = Route.new - - route.segments = segments - route.requirements = requirements - route.conditions = conditions - - if !route.significant_keys.include?(:action) && !route.requirements[:action] - route.requirements[:action] = "index" - route.significant_keys << :action - end - - # Routes cannot use the current string interpolation method - # if there are user-supplied :requirements as the interpolation - # code won't raise RoutingErrors when generating - if options.key?(:requirements) || route.requirements.keys.to_set != Routing::ALLOWED_REQUIREMENTS_FOR_OPTIMISATION - route.optimise = false - end - - if !route.significant_keys.include?(:controller) - raise ArgumentError, "Illegal route: the :controller must be specified!" - end - - route - end - end - - class RouteSet #:nodoc: - # Mapper instances are used to build routes. The object passed to the draw - # block in config/routes.rb is a Mapper instance. - # - # Mapper instances have relatively few instance methods, in order to avoid - # clashes with named routes. - class Mapper #:doc: - def initialize(set) #:nodoc: - @set = set - end - - # Create an unnamed route with the provided +path+ and +options+. See - # ActionController::Routing for an introduction to routes. - def connect(path, options = {}) - @set.add_route(path, options) - end - - # Creates a named route called "root" for matching the root level request. - def root(options = {}) - named_route("root", '', options) - end - - def named_route(name, path, options = {}) #:nodoc: - @set.add_named_route(name, path, options) - end - - # Enables the use of resources in a module by setting the name_prefix, path_prefix, and namespace for the model. - # Example: - # - # map.namespace(:admin) do |admin| - # admin.resources :products, - # :has_many => [ :tags, :images, :variants ] - # end - # - # This will create +admin_products_url+ pointing to "admin/products", which will look for an Admin::ProductsController. - # It'll also create +admin_product_tags_url+ pointing to "admin/products/#{product_id}/tags", which will look for - # Admin::TagsController. - def namespace(name, options = {}, &block) - if options[:namespace] - with_options({:path_prefix => "#{options.delete(:path_prefix)}/#{name}", :name_prefix => "#{options.delete(:name_prefix)}#{name}_", :namespace => "#{options.delete(:namespace)}#{name}/" }.merge(options), &block) - else - with_options({:path_prefix => name, :name_prefix => "#{name}_", :namespace => "#{name}/" }.merge(options), &block) - end - end - - def method_missing(route_name, *args, &proc) #:nodoc: - super unless args.length >= 1 && proc.nil? - @set.add_named_route(route_name, *args) - end - end - - # A NamedRouteCollection instance is a collection of named routes, and also - # maintains an anonymous module that can be used to install helpers for the - # named routes. - class NamedRouteCollection #:nodoc: - include Enumerable - include ActionController::Routing::Optimisation - attr_reader :routes, :helpers - - def initialize - clear! - end - - def clear! - @routes = {} - @helpers = [] - - @module ||= Module.new - @module.instance_methods.each do |selector| - @module.class_eval { remove_method selector } - end - end - - def add(name, route) - routes[name.to_sym] = route - define_named_route_methods(name, route) - end - - def get(name) - routes[name.to_sym] - end - - alias []= add - alias [] get - alias clear clear! - - def each - routes.each { |name, route| yield name, route } - self - end - - def names - routes.keys - end - - def length - routes.length - end - - def reset! - old_routes = routes.dup - clear! - old_routes.each do |name, route| - add(name, route) - end - end - - def install(destinations = [ActionController::Base, ActionView::Base], regenerate = false) - reset! if regenerate - Array(destinations).each do |dest| - dest.send! :include, @module - end - end - - private - def url_helper_name(name, kind = :url) - :"#{name}_#{kind}" - end - - def hash_access_name(name, kind = :url) - :"hash_for_#{name}_#{kind}" - end - - def define_named_route_methods(name, route) - {:url => {:only_path => false}, :path => {:only_path => true}}.each do |kind, opts| - hash = route.defaults.merge(:use_route => name).merge(opts) - define_hash_access route, name, kind, hash - define_url_helper route, name, kind, hash - end - end - - def define_hash_access(route, name, kind, options) - selector = hash_access_name(name, kind) - @module.module_eval <<-end_eval # We use module_eval to avoid leaks - def #{selector}(options = nil) - options ? #{options.inspect}.merge(options) : #{options.inspect} - end - protected :#{selector} - end_eval - helpers << selector - end - - def define_url_helper(route, name, kind, options) - selector = url_helper_name(name, kind) - # The segment keys used for positional paramters - - hash_access_method = hash_access_name(name, kind) - - # allow ordered parameters to be associated with corresponding - # dynamic segments, so you can do - # - # foo_url(bar, baz, bang) - # - # instead of - # - # foo_url(:bar => bar, :baz => baz, :bang => bang) - # - # Also allow options hash, so you can do - # - # foo_url(bar, baz, bang, :sort_by => 'baz') - # - @module.module_eval <<-end_eval # We use module_eval to avoid leaks - def #{selector}(*args) - #{generate_optimisation_block(route, kind)} - - opts = if args.empty? || Hash === args.first - args.first || {} - else - options = args.last.is_a?(Hash) ? args.pop : {} - args = args.zip(#{route.segment_keys.inspect}).inject({}) do |h, (v, k)| - h[k] = v - h - end - options.merge(args) - end - - url_for(#{hash_access_method}(opts)) - end - protected :#{selector} - end_eval - helpers << selector - end - end - - attr_accessor :routes, :named_routes - - def initialize - self.routes = [] - self.named_routes = NamedRouteCollection.new - end - - # Subclasses and plugins may override this method to specify a different - # RouteBuilder instance, so that other route DSL's can be created. - def builder - @builder ||= RouteBuilder.new - end - - def draw - clear! - yield Mapper.new(self) - install_helpers - end - - def clear! - routes.clear - named_routes.clear - @combined_regexp = nil - @routes_by_controller = nil - end - - def install_helpers(destinations = [ActionController::Base, ActionView::Base], regenerate_code = false) - Array(destinations).each { |d| d.module_eval { include Helpers } } - named_routes.install(destinations, regenerate_code) - end - - def empty? - routes.empty? - end - - def load! - Routing.use_controllers! nil # Clear the controller cache so we may discover new ones - clear! - load_routes! - install_helpers - end - - # reload! will always force a reload whereas load checks the timestamp first - alias reload! load! - - def reload - if @routes_last_modified && defined?(RAILS_ROOT) - mtime = File.stat("#{RAILS_ROOT}/config/routes.rb").mtime - # if it hasn't been changed, then just return - return if mtime == @routes_last_modified - # if it has changed then record the new time and fall to the load! below - @routes_last_modified = mtime - end - load! - end - - def load_routes! - if defined?(RAILS_ROOT) && defined?(::ActionController::Routing::Routes) && self == ::ActionController::Routing::Routes - load File.join("#{RAILS_ROOT}/config/routes.rb") - @routes_last_modified = File.stat("#{RAILS_ROOT}/config/routes.rb").mtime - else - add_route ":controller/:action/:id" - end - end - - def add_route(path, options = {}) - route = builder.build(path, options) - routes << route - route - end - - def add_named_route(name, path, options = {}) - # TODO - is options EVER used? - name = options[:name_prefix] + name.to_s if options[:name_prefix] - named_routes[name.to_sym] = add_route(path, options) - end - - def options_as_params(options) - # If an explicit :controller was given, always make :action explicit - # too, so that action expiry works as expected for things like - # - # generate({:controller => 'content'}, {:controller => 'content', :action => 'show'}) - # - # (the above is from the unit tests). In the above case, because the - # controller was explicitly given, but no action, the action is implied to - # be "index", not the recalled action of "show". - # - # great fun, eh? - - options_as_params = options.clone - options_as_params[:action] ||= 'index' if options[:controller] - options_as_params[:action] = options_as_params[:action].to_s if options_as_params[:action] - options_as_params - end - - def build_expiry(options, recall) - recall.inject({}) do |expiry, (key, recalled_value)| - expiry[key] = (options.key?(key) && options[key].to_param != recalled_value.to_param) - expiry - end - end - - # Generate the path indicated by the arguments, and return an array of - # the keys that were not used to generate it. - def extra_keys(options, recall={}) - generate_extras(options, recall).last - end - - def generate_extras(options, recall={}) - generate(options, recall, :generate_extras) - end - - def generate(options, recall = {}, method=:generate) - named_route_name = options.delete(:use_route) - generate_all = options.delete(:generate_all) - if named_route_name - named_route = named_routes[named_route_name] - options = named_route.parameter_shell.merge(options) - end - - options = options_as_params(options) - expire_on = build_expiry(options, recall) - - if options[:controller] - options[:controller] = options[:controller].to_s - end - # if the controller has changed, make sure it changes relative to the - # current controller module, if any. In other words, if we're currently - # on admin/get, and the new controller is 'set', the new controller - # should really be admin/set. - if !named_route && expire_on[:controller] && options[:controller] && options[:controller][0] != ?/ - old_parts = recall[:controller].split('/') - new_parts = options[:controller].split('/') - parts = old_parts[0..-(new_parts.length + 1)] + new_parts - options[:controller] = parts.join('/') - end - - # drop the leading '/' on the controller name - options[:controller] = options[:controller][1..-1] if options[:controller] && options[:controller][0] == ?/ - merged = recall.merge(options) - - if named_route - path = named_route.generate(options, merged, expire_on) - if path.nil? - raise_named_route_error(options, named_route, named_route_name) - else - return path - end - else - merged[:action] ||= 'index' - options[:action] ||= 'index' - - controller = merged[:controller] - action = merged[:action] - - raise RoutingError, "Need controller and action!" unless controller && action - - if generate_all - # Used by caching to expire all paths for a resource - return routes.collect do |route| - route.send!(method, options, merged, expire_on) - end.compact - end - - # don't use the recalled keys when determining which routes to check - routes = routes_by_controller[controller][action][options.keys.sort_by { |x| x.object_id }] - - routes.each do |route| - results = route.send!(method, options, merged, expire_on) - return results if results && (!results.is_a?(Array) || results.first) - end - end - - raise RoutingError, "No route matches #{options.inspect}" - end - - # try to give a helpful error message when named route generation fails - def raise_named_route_error(options, named_route, named_route_name) - diff = named_route.requirements.diff(options) - unless diff.empty? - raise RoutingError, "#{named_route_name}_url failed to generate from #{options.inspect}, expected: #{named_route.requirements.inspect}, diff: #{named_route.requirements.diff(options).inspect}" - else - required_segments = named_route.segments.select {|seg| (!seg.optional?) && (!seg.is_a?(DividerSegment)) } - required_keys_or_values = required_segments.map { |seg| seg.key rescue seg.value } # we want either the key or the value from the segment - raise RoutingError, "#{named_route_name}_url failed to generate from #{options.inspect} - you may have ambiguous routes, or you may need to supply additional parameters for this route. content_url has the following required parameters: #{required_keys_or_values.inspect} - are they all satisfied?" - end - end - - def recognize(request) - params = recognize_path(request.path, extract_request_environment(request)) - request.path_parameters = params.with_indifferent_access - "#{params[:controller].camelize}Controller".constantize - end - - def recognize_path(path, environment={}) - routes.each do |route| - result = route.recognize(path, environment) and return result - end - - allows = HTTP_METHODS.select { |verb| routes.find { |r| r.recognize(path, :method => verb) } } - - if environment[:method] && !HTTP_METHODS.include?(environment[:method]) - raise NotImplemented.new(*allows) - elsif !allows.empty? - raise MethodNotAllowed.new(*allows) - else - raise RoutingError, "No route matches #{path.inspect} with #{environment.inspect}" - end - end - - def routes_by_controller - @routes_by_controller ||= Hash.new do |controller_hash, controller| - controller_hash[controller] = Hash.new do |action_hash, action| - action_hash[action] = Hash.new do |key_hash, keys| - key_hash[keys] = routes_for_controller_and_action_and_keys(controller, action, keys) - end - end - end - end - - def routes_for(options, merged, expire_on) - raise "Need controller and action!" unless controller && action - controller = merged[:controller] - merged = options if expire_on[:controller] - action = merged[:action] || 'index' - - routes_by_controller[controller][action][merged.keys] - end - - def routes_for_controller_and_action(controller, action) - selected = routes.select do |route| - route.matches_controller_and_action? controller, action - end - (selected.length == routes.length) ? routes : selected - end - - def routes_for_controller_and_action_and_keys(controller, action, keys) - selected = routes.select do |route| - route.matches_controller_and_action? controller, action - end - selected.sort_by do |route| - (keys - route.significant_keys).length - end - end - - # Subclasses and plugins may override this method to extract further attributes - # from the request, for use by route conditions and such. - def extract_request_environment(request) - { :method => request.method } - end - end + Routes = RouteSet.new ::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)) { ActionController::Routing::Routes.reload! if block_given? diff --git a/vendor/rails/actionpack/lib/action_controller/routing/builder.rb b/vendor/rails/actionpack/lib/action_controller/routing/builder.rb new file mode 100644 index 00000000..b1a98d1a --- /dev/null +++ b/vendor/rails/actionpack/lib/action_controller/routing/builder.rb @@ -0,0 +1,204 @@ +module ActionController + module Routing + class RouteBuilder #:nodoc: + attr_accessor :separators, :optional_separators + + def initialize + self.separators = Routing::SEPARATORS + self.optional_separators = %w( / ) + end + + def separator_pattern(inverted = false) + "[#{'^' if inverted}#{Regexp.escape(separators.join)}]" + end + + def interval_regexp + Regexp.new "(.*?)(#{separators.source}|$)" + end + + def multiline_regexp?(expression) + expression.options & Regexp::MULTILINE == Regexp::MULTILINE + end + + # Accepts a "route path" (a string defining a route), and returns the array + # of segments that corresponds to it. Note that the segment array is only + # partially initialized--the defaults and requirements, for instance, need + # to be set separately, via the #assign_route_options method, and the + # #optional? method for each segment will not be reliable until after + # #assign_route_options is called, as well. + def segments_for_route_path(path) + rest, segments = path, [] + + until rest.empty? + segment, rest = segment_for rest + segments << segment + end + segments + end + + # A factory method that returns a new segment instance appropriate for the + # format of the given string. + def segment_for(string) + segment = case string + when /\A:(\w+)/ + key = $1.to_sym + case key + when :controller then ControllerSegment.new(key) + else DynamicSegment.new key + end + when /\A\*(\w+)/ then PathSegment.new($1.to_sym, :optional => true) + when /\A\?(.*?)\?/ + returning segment = StaticSegment.new($1) do + segment.is_optional = true + end + when /\A(#{separator_pattern(:inverted)}+)/ then StaticSegment.new($1) + when Regexp.new(separator_pattern) then + returning segment = DividerSegment.new($&) do + segment.is_optional = (optional_separators.include? $&) + end + end + [segment, $~.post_match] + end + + # Split the given hash of options into requirement and default hashes. The + # segments are passed alongside in order to distinguish between default values + # and requirements. + def divide_route_options(segments, options) + options = options.dup + + if options[:namespace] + options[:controller] = "#{options[:path_prefix]}/#{options[:controller]}" + options.delete(:path_prefix) + options.delete(:name_prefix) + options.delete(:namespace) + end + + requirements = (options.delete(:requirements) || {}).dup + defaults = (options.delete(:defaults) || {}).dup + conditions = (options.delete(:conditions) || {}).dup + + path_keys = segments.collect { |segment| segment.key if segment.respond_to?(:key) }.compact + options.each do |key, value| + hash = (path_keys.include?(key) && ! value.is_a?(Regexp)) ? defaults : requirements + hash[key] = value + end + + [defaults, requirements, conditions] + end + + # Takes a hash of defaults and a hash of requirements, and assigns them to + # the segments. Any unused requirements (which do not correspond to a segment) + # are returned as a hash. + def assign_route_options(segments, defaults, requirements) + route_requirements = {} # Requirements that do not belong to a segment + + segment_named = Proc.new do |key| + segments.detect { |segment| segment.key == key if segment.respond_to?(:key) } + end + + requirements.each do |key, requirement| + segment = segment_named[key] + if segment + raise TypeError, "#{key}: requirements on a path segment must be regular expressions" unless requirement.is_a?(Regexp) + if requirement.source =~ %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z} + raise ArgumentError, "Regexp anchor characters are not allowed in routing requirements: #{requirement.inspect}" + end + if multiline_regexp?(requirement) + raise ArgumentError, "Regexp multiline option not allowed in routing requirements: #{requirement.inspect}" + end + segment.regexp = requirement + else + route_requirements[key] = requirement + end + end + + defaults.each do |key, default| + segment = segment_named[key] + raise ArgumentError, "#{key}: No matching segment exists; cannot assign default" unless segment + segment.is_optional = true + segment.default = default.to_param if default + end + + assign_default_route_options(segments) + ensure_required_segments(segments) + route_requirements + end + + # Assign default options, such as 'index' as a default for :action. This + # method must be run *after* user supplied requirements and defaults have + # been applied to the segments. + def assign_default_route_options(segments) + segments.each do |segment| + next unless segment.is_a? DynamicSegment + case segment.key + when :action + if segment.regexp.nil? || segment.regexp.match('index').to_s == 'index' + segment.default ||= 'index' + segment.is_optional = true + end + when :id + if segment.default.nil? && segment.regexp.nil? || segment.regexp =~ '' + segment.is_optional = true + end + end + end + end + + # Makes sure that there are no optional segments that precede a required + # segment. If any are found that precede a required segment, they are + # made required. + def ensure_required_segments(segments) + allow_optional = true + segments.reverse_each do |segment| + allow_optional &&= segment.optional? + if !allow_optional && segment.optional? + unless segment.optionality_implied? + warn "Route segment \"#{segment.to_s}\" cannot be optional because it precedes a required segment. This segment will be required." + end + segment.is_optional = false + elsif allow_optional && segment.respond_to?(:default) && segment.default + # if a segment has a default, then it is optional + segment.is_optional = true + end + end + end + + # Construct and return a route with the given path and options. + def build(path, options) + # Wrap the path with slashes + path = "/#{path}" unless path[0] == ?/ + path = "#{path}/" unless path[-1] == ?/ + + path = "/#{options[:path_prefix].to_s.gsub(/^\//,'')}#{path}" if options[:path_prefix] + + segments = segments_for_route_path(path) + defaults, requirements, conditions = divide_route_options(segments, options) + requirements = assign_route_options(segments, defaults, requirements) + + route = Route.new + + route.segments = segments + route.requirements = requirements + route.conditions = conditions + + if !route.significant_keys.include?(:action) && !route.requirements[:action] + route.requirements[:action] = "index" + route.significant_keys << :action + end + + # Routes cannot use the current string interpolation method + # if there are user-supplied :requirements as the interpolation + # code won't raise RoutingErrors when generating + if options.key?(:requirements) || route.requirements.keys.to_set != Routing::ALLOWED_REQUIREMENTS_FOR_OPTIMISATION + route.optimise = false + end + + if !route.significant_keys.include?(:controller) + raise ArgumentError, "Illegal route: the :controller must be specified!" + end + + route + end + end + end +end diff --git a/vendor/rails/actionpack/lib/action_controller/routing_optimisation.rb b/vendor/rails/actionpack/lib/action_controller/routing/optimisations.rb similarity index 73% rename from vendor/rails/actionpack/lib/action_controller/routing_optimisation.rb rename to vendor/rails/actionpack/lib/action_controller/routing/optimisations.rb index ba4aeb4e..cd4a423e 100644 --- a/vendor/rails/actionpack/lib/action_controller/routing_optimisation.rb +++ b/vendor/rails/actionpack/lib/action_controller/routing/optimisations.rb @@ -1,11 +1,11 @@ module ActionController module Routing # Much of the slow performance from routes comes from the - # complexity of expiry, :requirements matching, defaults providing + # complexity of expiry, :requirements matching, defaults providing # and figuring out which url pattern to use. With named routes # we can avoid the expense of finding the right route. So if # they've provided the right number of arguments, and have no - # :requirements, we can just build up a string and return it. + # :requirements, we can just build up a string and return it. # # To support building optimisations for other common cases, the # generation code is separated into several classes @@ -41,28 +41,29 @@ module ActionController end end - # Temporarily disabled :url optimisation pending proper solution to + # Temporarily disabled :url optimisation pending proper solution to # Issues around request.host etc. def applicable? true end end - # Given a route: - # map.person '/people/:id' + # Given a route # - # If the user calls person_url(@person), we can simply + # map.person '/people/:id' + # + # If the user calls person_url(@person), we can simply # return a string like "/people/#{@person.to_param}" - # rather than triggering the expensive logic in url_for + # rather than triggering the expensive logic in +url_for+. class PositionalArguments < Optimiser def guard_condition number_of_arguments = route.segment_keys.size # if they're using foo_url(:id=>2) it's one # argument, but we don't want to generate /foos/id2 if number_of_arguments == 1 - "defined?(request) && request && args.size == 1 && !args.first.is_a?(Hash)" + "(!defined?(default_url_options) || default_url_options.blank?) && defined?(request) && request && args.size == 1 && !args.first.is_a?(Hash)" else - "defined?(request) && request && args.size == #{number_of_arguments}" + "(!defined?(default_url_options) || default_url_options.blank?) && defined?(request) && request && args.size == #{number_of_arguments}" end end @@ -77,7 +78,7 @@ module ActionController elements << '#{request.relative_url_root if request.relative_url_root}' - # The last entry in route.segments appears to # *always* be a + # The last entry in route.segments appears to *always* be a # 'divider segment' for '/' but we have assertions to ensure that # we don't include the trailing slashes, so skip them. (route.segments.size == 1 ? route.segments : route.segments[0..-2]).each do |segment| @@ -97,7 +98,7 @@ module ActionController # argument class PositionalArgumentsWithAdditionalParams < PositionalArguments def guard_condition - "defined?(request) && request && args.size == #{route.segment_keys.size + 1} && !args.last.has_key?(:anchor) && !args.last.has_key?(:port) && !args.last.has_key?(:host)" + "(!defined?(default_url_options) || default_url_options.blank?) && defined?(request) && request && args.size == #{route.segment_keys.size + 1} && !args.last.has_key?(:anchor) && !args.last.has_key?(:port) && !args.last.has_key?(:host)" end # This case uses almost the same code as positional arguments, @@ -106,7 +107,7 @@ module ActionController super.insert(-2, '?#{args.last.to_query}') end - # To avoid generating http://localhost/?host=foo.example.com we + # To avoid generating "http://localhost/?host=foo.example.com" we # can't use this optimisation on routes without any segments def applicable? super && route.segment_keys.size > 0 diff --git a/vendor/rails/actionpack/lib/action_controller/routing/recognition_optimisation.rb b/vendor/rails/actionpack/lib/action_controller/routing/recognition_optimisation.rb new file mode 100644 index 00000000..cf8f5232 --- /dev/null +++ b/vendor/rails/actionpack/lib/action_controller/routing/recognition_optimisation.rb @@ -0,0 +1,158 @@ +module ActionController + module Routing + # BEFORE: 0.191446860631307 ms/url + # AFTER: 0.029847304022858 ms/url + # Speed up: 6.4 times + # + # Route recognition is slow due to one-by-one iterating over + # a whole routeset (each map.resources generates at least 14 routes) + # and matching weird regexps on each step. + # + # We optimize this by skipping all URI segments that 100% sure can't + # be matched, moving deeper in a tree of routes (where node == segment) + # until first possible match is accured. In such case, we start walking + # a flat list of routes, matching them with accurate matcher. + # So, first step: search a segment tree for the first relevant index. + # Second step: iterate routes starting with that index. + # + # How tree is walked? We can do a recursive tests, but it's smarter: + # We just create a tree of if-s and elsif-s matching segments. + # + # We have segments of 3 flavors: + # 1) nil (no segment, route finished) + # 2) const-dot-dynamic (like "/posts.:xml", "/preview.:size.jpg") + # 3) const (like "/posts", "/comments") + # 4) dynamic ("/:id", "file.:size.:extension") + # + # We split incoming string into segments and iterate over them. + # When segment is nil, we drop immediately, on a current node index. + # When segment is equal to some const, we step into branch. + # If none constants matched, we step into 'dynamic' branch (it's a last). + # If we can't match anything, we drop to last index on a level. + # + # Note: we maintain the original routes order, so we finish building + # steps on a first dynamic segment. + # + # + # Example. Given the routes: + # 0 /posts/ + # 1 /posts/:id + # 2 /posts/:id/comments + # 3 /posts/blah + # 4 /users/ + # 5 /users/:id + # 6 /users/:id/profile + # + # request_uri = /users/123 + # + # There will be only 4 iterations: + # 1) segm test for /posts prefix, skip all /posts/* routes + # 2) segm test for /users/ + # 3) segm test for /users/:id + # (jump to list index = 5) + # 4) full test for /users/:id => here we are! + + class RouteSet + def recognize_path(path, environment={}) + result = recognize_optimized(path, environment) and return result + + # Route was not recognized. Try to find out why (maybe wrong verb). + allows = HTTP_METHODS.select { |verb| routes.find { |r| r.recognize(path, :method => verb) } } + + if environment[:method] && !HTTP_METHODS.include?(environment[:method]) + raise NotImplemented.new(*allows) + elsif !allows.empty? + raise MethodNotAllowed.new(*allows) + else + raise RoutingError, "No route matches #{path.inspect} with #{environment.inspect}" + end + end + + def recognize_optimized(path, env) + write_recognize_optimized + recognize_optimized(path, env) + end + + def write_recognize_optimized + tree = segment_tree(routes) + body = generate_code(tree) + instance_eval %{ + def recognize_optimized(path, env) + segments = to_plain_segments(path) + index = #{body} + return nil unless index + while index < routes.size + result = routes[index].recognize(path, env) and return result + index += 1 + end + nil + end + }, __FILE__, __LINE__ + end + + def segment_tree(routes) + tree = [0] + + i = -1 + routes.each do |route| + i += 1 + # not fast, but runs only once + segments = to_plain_segments(route.segments.inject("") { |str,s| str << s.to_s }) + + node = tree + segments.each do |seg| + seg = :dynamic if seg && seg[0] == ?: + node << [seg, [i]] if node.empty? || node[node.size - 1][0] != seg + node = node[node.size - 1][1] + end + end + tree + end + + def generate_code(list, padding=' ', level = 0) + # a digit + return padding + "#{list[0]}\n" if list.size == 1 && !(Array === list[0]) + + body = padding + "(seg = segments[#{level}]; \n" + + i = 0 + was_nil = false + list.each do |item| + if Array === item + i += 1 + start = (i == 1) + final = (i == list.size) + tag, sub = item + if tag == :dynamic + body += padding + "#{start ? 'if' : 'elsif'} true\n" + body += generate_code(sub, padding + " ", level + 1) + break + elsif tag == nil && !was_nil + was_nil = true + body += padding + "#{start ? 'if' : 'elsif'} seg.nil?\n" + body += generate_code(sub, padding + " ", level + 1) + else + body += padding + "#{start ? 'if' : 'elsif'} seg == '#{tag}'\n" + body += generate_code(sub, padding + " ", level + 1) + end + end + end + body += padding + "else\n" + body += padding + " #{list[0]}\n" + body += padding + "end)\n" + body + end + + # this must be really fast + def to_plain_segments(str) + str = str.dup + str.sub!(/^\/+/,'') + str.sub!(/\/+$/,'') + segments = str.split(/\.[^\/]+\/+|\/+|\.[^\/]+\Z/) # cut off ".format" also + segments << nil + segments + end + + end + end +end diff --git a/vendor/rails/actionpack/lib/action_controller/routing/route.rb b/vendor/rails/actionpack/lib/action_controller/routing/route.rb new file mode 100644 index 00000000..a0d108ba --- /dev/null +++ b/vendor/rails/actionpack/lib/action_controller/routing/route.rb @@ -0,0 +1,240 @@ +module ActionController + module Routing + class Route #:nodoc: + attr_accessor :segments, :requirements, :conditions, :optimise + + def initialize + @segments = [] + @requirements = {} + @conditions = {} + @optimise = true + end + + # Indicates whether the routes should be optimised with the string interpolation + # version of the named routes methods. + def optimise? + @optimise && ActionController::Base::optimise_named_routes + end + + def segment_keys + segments.collect do |segment| + segment.key if segment.respond_to? :key + end.compact + end + + # Write and compile a +generate+ method for this Route. + def write_generation + # Build the main body of the generation + body = "expired = false\n#{generation_extraction}\n#{generation_structure}" + + # If we have conditions that must be tested first, nest the body inside an if + body = "if #{generation_requirements}\n#{body}\nend" if generation_requirements + args = "options, hash, expire_on = {}" + + # Nest the body inside of a def block, and then compile it. + raw_method = method_decl = "def generate_raw(#{args})\npath = begin\n#{body}\nend\n[path, hash]\nend" + instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})" + + # expire_on.keys == recall.keys; in other words, the keys in the expire_on hash + # are the same as the keys that were recalled from the previous request. Thus, + # we can use the expire_on.keys to determine which keys ought to be used to build + # the query string. (Never use keys from the recalled request when building the + # query string.) + + method_decl = "def generate(#{args})\npath, hash = generate_raw(options, hash, expire_on)\nappend_query_string(path, hash, extra_keys(options))\nend" + instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})" + + method_decl = "def generate_extras(#{args})\npath, hash = generate_raw(options, hash, expire_on)\n[path, extra_keys(options)]\nend" + instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})" + raw_method + end + + # Build several lines of code that extract values from the options hash. If any + # of the values are missing or rejected then a return will be executed. + def generation_extraction + segments.collect do |segment| + segment.extraction_code + end.compact * "\n" + end + + # Produce a condition expression that will check the requirements of this route + # upon generation. + def generation_requirements + requirement_conditions = requirements.collect do |key, req| + if req.is_a? Regexp + value_regexp = Regexp.new "\\A#{req.to_s}\\Z" + "hash[:#{key}] && #{value_regexp.inspect} =~ options[:#{key}]" + else + "hash[:#{key}] == #{req.inspect}" + end + end + requirement_conditions * ' && ' unless requirement_conditions.empty? + end + + def generation_structure + segments.last.string_structure segments[0..-2] + end + + # Write and compile a +recognize+ method for this Route. + def write_recognition + # Create an if structure to extract the params from a match if it occurs. + body = "params = parameter_shell.dup\n#{recognition_extraction * "\n"}\nparams" + body = "if #{recognition_conditions.join(" && ")}\n#{body}\nend" + + # Build the method declaration and compile it + method_decl = "def recognize(path, env={})\n#{body}\nend" + instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})" + method_decl + end + + # Plugins may override this method to add other conditions, like checks on + # host, subdomain, and so forth. Note that changes here only affect route + # recognition, not generation. + def recognition_conditions + result = ["(match = #{Regexp.new(recognition_pattern).inspect}.match(path))"] + result << "conditions[:method] === env[:method]" if conditions[:method] + result + end + + # Build the regular expression pattern that will match this route. + def recognition_pattern(wrap = true) + pattern = '' + segments.reverse_each do |segment| + pattern = segment.build_pattern pattern + end + wrap ? ("\\A" + pattern + "\\Z") : pattern + end + + # Write the code to extract the parameters from a matched route. + def recognition_extraction + next_capture = 1 + extraction = segments.collect do |segment| + x = segment.match_extraction(next_capture) + next_capture += Regexp.new(segment.regexp_chunk).number_of_captures + x + end + extraction.compact + end + + # Write the real generation implementation and then resend the message. + def generate(options, hash, expire_on = {}) + write_generation + generate options, hash, expire_on + end + + def generate_extras(options, hash, expire_on = {}) + write_generation + generate_extras options, hash, expire_on + end + + # Generate the query string with any extra keys in the hash and append + # it to the given path, returning the new path. + def append_query_string(path, hash, query_keys=nil) + return nil unless path + query_keys ||= extra_keys(hash) + "#{path}#{build_query_string(hash, query_keys)}" + end + + # Determine which keys in the given hash are "extra". Extra keys are + # those that were not used to generate a particular route. The extra + # keys also do not include those recalled from the prior request, nor + # do they include any keys that were implied in the route (like a + # :controller that is required, but not explicitly used in the + # text of the route.) + def extra_keys(hash, recall={}) + (hash || {}).keys.map { |k| k.to_sym } - (recall || {}).keys - significant_keys + end + + # Build a query string from the keys of the given hash. If +only_keys+ + # is given (as an array), only the keys indicated will be used to build + # the query string. The query string will correctly build array parameter + # values. + def build_query_string(hash, only_keys = nil) + elements = [] + + (only_keys || hash.keys).each do |key| + if value = hash[key] + elements << value.to_query(key) + end + end + + elements.empty? ? '' : "?#{elements.sort * '&'}" + end + + # Write the real recognition implementation and then resend the message. + def recognize(path, environment={}) + write_recognition + recognize path, environment + end + + # A route's parameter shell contains parameter values that are not in the + # route's path, but should be placed in the recognized hash. + # + # For example, +{:controller => 'pages', :action => 'show'} is the shell for the route: + # + # map.connect '/page/:id', :controller => 'pages', :action => 'show', :id => /\d+/ + # + def parameter_shell + @parameter_shell ||= returning({}) do |shell| + requirements.each do |key, requirement| + shell[key] = requirement unless requirement.is_a? Regexp + end + end + end + + # Return an array containing all the keys that are used in this route. This + # includes keys that appear inside the path, and keys that have requirements + # placed upon them. + def significant_keys + @significant_keys ||= returning [] do |sk| + segments.each { |segment| sk << segment.key if segment.respond_to? :key } + sk.concat requirements.keys + sk.uniq! + end + end + + # Return a hash of key/value pairs representing the keys in the route that + # have defaults, or which are specified by non-regexp requirements. + def defaults + @defaults ||= returning({}) do |hash| + segments.each do |segment| + next unless segment.respond_to? :default + hash[segment.key] = segment.default unless segment.default.nil? + end + requirements.each do |key,req| + next if Regexp === req || req.nil? + hash[key] = req + end + end + end + + def matches_controller_and_action?(controller, action) + unless defined? @matching_prepared + @controller_requirement = requirement_for(:controller) + @action_requirement = requirement_for(:action) + @matching_prepared = true + end + + (@controller_requirement.nil? || @controller_requirement === controller) && + (@action_requirement.nil? || @action_requirement === action) + end + + def to_s + @to_s ||= begin + segs = segments.inject("") { |str,s| str << s.to_s } + "%-6s %-40s %s" % [(conditions[:method] || :any).to_s.upcase, segs, requirements.inspect] + end + end + + protected + def requirement_for(key) + return requirements[key] if requirements.key? key + segments.each do |segment| + return segment.regexp if segment.respond_to?(:key) && segment.key == key + end + nil + end + + end + end +end diff --git a/vendor/rails/actionpack/lib/action_controller/routing/route_set.rb b/vendor/rails/actionpack/lib/action_controller/routing/route_set.rb new file mode 100644 index 00000000..5bc13cf2 --- /dev/null +++ b/vendor/rails/actionpack/lib/action_controller/routing/route_set.rb @@ -0,0 +1,435 @@ +module ActionController + module Routing + class RouteSet #:nodoc: + # Mapper instances are used to build routes. The object passed to the draw + # block in config/routes.rb is a Mapper instance. + # + # Mapper instances have relatively few instance methods, in order to avoid + # clashes with named routes. + class Mapper #:doc: + def initialize(set) #:nodoc: + @set = set + end + + # Create an unnamed route with the provided +path+ and +options+. See + # ActionController::Routing for an introduction to routes. + def connect(path, options = {}) + @set.add_route(path, options) + end + + # Creates a named route called "root" for matching the root level request. + def root(options = {}) + if options.is_a?(Symbol) + if source_route = @set.named_routes.routes[options] + options = source_route.defaults.merge({ :conditions => source_route.conditions }) + end + end + named_route("root", '', options) + end + + def named_route(name, path, options = {}) #:nodoc: + @set.add_named_route(name, path, options) + end + + # Enables the use of resources in a module by setting the name_prefix, path_prefix, and namespace for the model. + # Example: + # + # map.namespace(:admin) do |admin| + # admin.resources :products, + # :has_many => [ :tags, :images, :variants ] + # end + # + # This will create +admin_products_url+ pointing to "admin/products", which will look for an Admin::ProductsController. + # It'll also create +admin_product_tags_url+ pointing to "admin/products/#{product_id}/tags", which will look for + # Admin::TagsController. + def namespace(name, options = {}, &block) + if options[:namespace] + with_options({:path_prefix => "#{options.delete(:path_prefix)}/#{name}", :name_prefix => "#{options.delete(:name_prefix)}#{name}_", :namespace => "#{options.delete(:namespace)}#{name}/" }.merge(options), &block) + else + with_options({:path_prefix => name, :name_prefix => "#{name}_", :namespace => "#{name}/" }.merge(options), &block) + end + end + + def method_missing(route_name, *args, &proc) #:nodoc: + super unless args.length >= 1 && proc.nil? + @set.add_named_route(route_name, *args) + end + end + + # A NamedRouteCollection instance is a collection of named routes, and also + # maintains an anonymous module that can be used to install helpers for the + # named routes. + class NamedRouteCollection #:nodoc: + include Enumerable + include ActionController::Routing::Optimisation + attr_reader :routes, :helpers + + def initialize + clear! + end + + def clear! + @routes = {} + @helpers = [] + + @module ||= Module.new + @module.instance_methods.each do |selector| + @module.class_eval { remove_method selector } + end + end + + def add(name, route) + routes[name.to_sym] = route + define_named_route_methods(name, route) + end + + def get(name) + routes[name.to_sym] + end + + alias []= add + alias [] get + alias clear clear! + + def each + routes.each { |name, route| yield name, route } + self + end + + def names + routes.keys + end + + def length + routes.length + end + + def reset! + old_routes = routes.dup + clear! + old_routes.each do |name, route| + add(name, route) + end + end + + def install(destinations = [ActionController::Base, ActionView::Base], regenerate = false) + reset! if regenerate + Array(destinations).each do |dest| + dest.send! :include, @module + end + end + + private + def url_helper_name(name, kind = :url) + :"#{name}_#{kind}" + end + + def hash_access_name(name, kind = :url) + :"hash_for_#{name}_#{kind}" + end + + def define_named_route_methods(name, route) + {:url => {:only_path => false}, :path => {:only_path => true}}.each do |kind, opts| + hash = route.defaults.merge(:use_route => name).merge(opts) + define_hash_access route, name, kind, hash + define_url_helper route, name, kind, hash + end + end + + def define_hash_access(route, name, kind, options) + selector = hash_access_name(name, kind) + @module.module_eval <<-end_eval # We use module_eval to avoid leaks + def #{selector}(options = nil) + options ? #{options.inspect}.merge(options) : #{options.inspect} + end + protected :#{selector} + end_eval + helpers << selector + end + + def define_url_helper(route, name, kind, options) + selector = url_helper_name(name, kind) + # The segment keys used for positional paramters + + hash_access_method = hash_access_name(name, kind) + + # allow ordered parameters to be associated with corresponding + # dynamic segments, so you can do + # + # foo_url(bar, baz, bang) + # + # instead of + # + # foo_url(:bar => bar, :baz => baz, :bang => bang) + # + # Also allow options hash, so you can do + # + # foo_url(bar, baz, bang, :sort_by => 'baz') + # + @module.module_eval <<-end_eval # We use module_eval to avoid leaks + def #{selector}(*args) + #{generate_optimisation_block(route, kind)} + + opts = if args.empty? || Hash === args.first + args.first || {} + else + options = args.extract_options! + args = args.zip(#{route.segment_keys.inspect}).inject({}) do |h, (v, k)| + h[k] = v + h + end + options.merge(args) + end + + url_for(#{hash_access_method}(opts)) + end + protected :#{selector} + end_eval + helpers << selector + end + end + + attr_accessor :routes, :named_routes, :configuration_file + + def initialize + self.routes = [] + self.named_routes = NamedRouteCollection.new + end + + # Subclasses and plugins may override this method to specify a different + # RouteBuilder instance, so that other route DSL's can be created. + def builder + @builder ||= RouteBuilder.new + end + + def draw + clear! + yield Mapper.new(self) + install_helpers + end + + def clear! + routes.clear + named_routes.clear + @combined_regexp = nil + @routes_by_controller = nil + # This will force routing/recognition_optimization.rb + # to refresh optimisations. + @compiled_recognize_optimized = nil + end + + def install_helpers(destinations = [ActionController::Base, ActionView::Base], regenerate_code = false) + Array(destinations).each { |d| d.module_eval { include Helpers } } + named_routes.install(destinations, regenerate_code) + end + + def empty? + routes.empty? + end + + def load! + Routing.use_controllers! nil # Clear the controller cache so we may discover new ones + clear! + load_routes! + install_helpers + end + + # reload! will always force a reload whereas load checks the timestamp first + alias reload! load! + + def reload + if @routes_last_modified && configuration_file + mtime = File.stat(configuration_file).mtime + # if it hasn't been changed, then just return + return if mtime == @routes_last_modified + # if it has changed then record the new time and fall to the load! below + @routes_last_modified = mtime + end + load! + end + + def load_routes! + if configuration_file + load configuration_file + @routes_last_modified = File.stat(configuration_file).mtime + else + add_route ":controller/:action/:id" + end + end + + def add_route(path, options = {}) + route = builder.build(path, options) + routes << route + route + end + + def add_named_route(name, path, options = {}) + # TODO - is options EVER used? + name = options[:name_prefix] + name.to_s if options[:name_prefix] + named_routes[name.to_sym] = add_route(path, options) + end + + def options_as_params(options) + # If an explicit :controller was given, always make :action explicit + # too, so that action expiry works as expected for things like + # + # generate({:controller => 'content'}, {:controller => 'content', :action => 'show'}) + # + # (the above is from the unit tests). In the above case, because the + # controller was explicitly given, but no action, the action is implied to + # be "index", not the recalled action of "show". + # + # great fun, eh? + + options_as_params = options.clone + options_as_params[:action] ||= 'index' if options[:controller] + options_as_params[:action] = options_as_params[:action].to_s if options_as_params[:action] + options_as_params + end + + def build_expiry(options, recall) + recall.inject({}) do |expiry, (key, recalled_value)| + expiry[key] = (options.key?(key) && options[key].to_param != recalled_value.to_param) + expiry + end + end + + # Generate the path indicated by the arguments, and return an array of + # the keys that were not used to generate it. + def extra_keys(options, recall={}) + generate_extras(options, recall).last + end + + def generate_extras(options, recall={}) + generate(options, recall, :generate_extras) + end + + def generate(options, recall = {}, method=:generate) + named_route_name = options.delete(:use_route) + generate_all = options.delete(:generate_all) + if named_route_name + named_route = named_routes[named_route_name] + options = named_route.parameter_shell.merge(options) + end + + options = options_as_params(options) + expire_on = build_expiry(options, recall) + + if options[:controller] + options[:controller] = options[:controller].to_s + end + # if the controller has changed, make sure it changes relative to the + # current controller module, if any. In other words, if we're currently + # on admin/get, and the new controller is 'set', the new controller + # should really be admin/set. + if !named_route && expire_on[:controller] && options[:controller] && options[:controller][0] != ?/ + old_parts = recall[:controller].split('/') + new_parts = options[:controller].split('/') + parts = old_parts[0..-(new_parts.length + 1)] + new_parts + options[:controller] = parts.join('/') + end + + # drop the leading '/' on the controller name + options[:controller] = options[:controller][1..-1] if options[:controller] && options[:controller][0] == ?/ + merged = recall.merge(options) + + if named_route + path = named_route.generate(options, merged, expire_on) + if path.nil? + raise_named_route_error(options, named_route, named_route_name) + else + return path + end + else + merged[:action] ||= 'index' + options[:action] ||= 'index' + + controller = merged[:controller] + action = merged[:action] + + raise RoutingError, "Need controller and action!" unless controller && action + + if generate_all + # Used by caching to expire all paths for a resource + return routes.collect do |route| + route.send!(method, options, merged, expire_on) + end.compact + end + + # don't use the recalled keys when determining which routes to check + routes = routes_by_controller[controller][action][options.keys.sort_by { |x| x.object_id }] + + routes.each do |route| + results = route.send!(method, options, merged, expire_on) + return results if results && (!results.is_a?(Array) || results.first) + end + end + + raise RoutingError, "No route matches #{options.inspect}" + end + + # try to give a helpful error message when named route generation fails + def raise_named_route_error(options, named_route, named_route_name) + diff = named_route.requirements.diff(options) + unless diff.empty? + raise RoutingError, "#{named_route_name}_url failed to generate from #{options.inspect}, expected: #{named_route.requirements.inspect}, diff: #{named_route.requirements.diff(options).inspect}" + else + required_segments = named_route.segments.select {|seg| (!seg.optional?) && (!seg.is_a?(DividerSegment)) } + required_keys_or_values = required_segments.map { |seg| seg.key rescue seg.value } # we want either the key or the value from the segment + raise RoutingError, "#{named_route_name}_url failed to generate from #{options.inspect} - you may have ambiguous routes, or you may need to supply additional parameters for this route. content_url has the following required parameters: #{required_keys_or_values.inspect} - are they all satisfied?" + end + end + + def recognize(request) + params = recognize_path(request.path, extract_request_environment(request)) + request.path_parameters = params.with_indifferent_access + "#{params[:controller].camelize}Controller".constantize + end + + def recognize_path(path, environment={}) + raise "Not optimized! Check that routing/recognition_optimisation overrides RouteSet#recognize_path." + end + + def routes_by_controller + @routes_by_controller ||= Hash.new do |controller_hash, controller| + controller_hash[controller] = Hash.new do |action_hash, action| + action_hash[action] = Hash.new do |key_hash, keys| + key_hash[keys] = routes_for_controller_and_action_and_keys(controller, action, keys) + end + end + end + end + + def routes_for(options, merged, expire_on) + raise "Need controller and action!" unless controller && action + controller = merged[:controller] + merged = options if expire_on[:controller] + action = merged[:action] || 'index' + + routes_by_controller[controller][action][merged.keys] + end + + def routes_for_controller_and_action(controller, action) + selected = routes.select do |route| + route.matches_controller_and_action? controller, action + end + (selected.length == routes.length) ? routes : selected + end + + def routes_for_controller_and_action_and_keys(controller, action, keys) + selected = routes.select do |route| + route.matches_controller_and_action? controller, action + end + selected.sort_by do |route| + (keys - route.significant_keys).length + end + end + + # Subclasses and plugins may override this method to extract further attributes + # from the request, for use by route conditions and such. + def extract_request_environment(request) + { :method => request.method } + end + end + end +end \ No newline at end of file diff --git a/vendor/rails/actionpack/lib/action_controller/routing/routing_ext.rb b/vendor/rails/actionpack/lib/action_controller/routing/routing_ext.rb new file mode 100644 index 00000000..2ad20ee6 --- /dev/null +++ b/vendor/rails/actionpack/lib/action_controller/routing/routing_ext.rb @@ -0,0 +1,46 @@ + +class Object + def to_param + to_s + end +end + +class TrueClass + def to_param + self + end +end + +class FalseClass + def to_param + self + end +end + +class NilClass + def to_param + self + end +end + +class Regexp #:nodoc: + def number_of_captures + Regexp.new("|#{source}").match('').captures.length + end + + class << self + def optionalize(pattern) + case unoptionalize(pattern) + when /\A(.|\(.*\))\Z/ then "#{pattern}?" + else "(?:#{pattern})?" + end + end + + def unoptionalize(pattern) + [/\A\(\?:(.*)\)\?\Z/, /\A(.|\(.*\))\?\Z/].each do |regexp| + return $1 if regexp =~ pattern + end + return pattern + end + end +end diff --git a/vendor/rails/actionpack/lib/action_controller/routing/segments.rb b/vendor/rails/actionpack/lib/action_controller/routing/segments.rb new file mode 100644 index 00000000..aff8afc4 --- /dev/null +++ b/vendor/rails/actionpack/lib/action_controller/routing/segments.rb @@ -0,0 +1,282 @@ +module ActionController + module Routing + class Segment #:nodoc: + RESERVED_PCHAR = ':@&=+$,;' + UNSAFE_PCHAR = Regexp.new("[^#{URI::REGEXP::PATTERN::UNRESERVED}#{RESERVED_PCHAR}]", false, 'N').freeze + + attr_accessor :is_optional + alias_method :optional?, :is_optional + + def initialize + self.is_optional = false + end + + def extraction_code + nil + end + + # Continue generating string for the prior segments. + def continue_string_structure(prior_segments) + if prior_segments.empty? + interpolation_statement(prior_segments) + else + new_priors = prior_segments[0..-2] + prior_segments.last.string_structure(new_priors) + end + end + + def interpolation_chunk + CGI.escape(value) + end + + # Return a string interpolation statement for this segment and those before it. + def interpolation_statement(prior_segments) + chunks = prior_segments.collect { |s| s.interpolation_chunk } + chunks << interpolation_chunk + "\"#{chunks * ''}\"#{all_optionals_available_condition(prior_segments)}" + end + + def string_structure(prior_segments) + optional? ? continue_string_structure(prior_segments) : interpolation_statement(prior_segments) + end + + # Return an if condition that is true if all the prior segments can be generated. + # If there are no optional segments before this one, then nil is returned. + def all_optionals_available_condition(prior_segments) + optional_locals = prior_segments.collect { |s| s.local_name if s.optional? && s.respond_to?(:local_name) }.compact + optional_locals.empty? ? nil : " if #{optional_locals * ' && '}" + end + + # Recognition + + def match_extraction(next_capture) + nil + end + + # Warning + + # Returns true if this segment is optional? because of a default. If so, then + # no warning will be emitted regarding this segment. + def optionality_implied? + false + end + end + + class StaticSegment < Segment #:nodoc: + attr_accessor :value, :raw + alias_method :raw?, :raw + + def initialize(value = nil) + super() + self.value = value + end + + def interpolation_chunk + raw? ? value : super + end + + def regexp_chunk + chunk = Regexp.escape(value) + optional? ? Regexp.optionalize(chunk) : chunk + end + + def build_pattern(pattern) + escaped = Regexp.escape(value) + if optional? && ! pattern.empty? + "(?:#{Regexp.optionalize escaped}\\Z|#{escaped}#{Regexp.unoptionalize pattern})" + elsif optional? + Regexp.optionalize escaped + else + escaped + pattern + end + end + + def to_s + value + end + end + + class DividerSegment < StaticSegment #:nodoc: + def initialize(value = nil) + super(value) + self.raw = true + self.is_optional = true + end + + def optionality_implied? + true + end + end + + class DynamicSegment < Segment #:nodoc: + attr_accessor :key, :default, :regexp + + def initialize(key = nil, options = {}) + super() + self.key = key + self.default = options[:default] if options.key? :default + self.is_optional = true if options[:optional] || options.key?(:default) + end + + def to_s + ":#{key}" + end + + # The local variable name that the value of this segment will be extracted to. + def local_name + "#{key}_value" + end + + def extract_value + "#{local_name} = hash[:#{key}] && hash[:#{key}].to_param #{"|| #{default.inspect}" if default}" + end + def value_check + if default # Then we know it won't be nil + "#{value_regexp.inspect} =~ #{local_name}" if regexp + elsif optional? + # If we have a regexp check that the value is not given, or that it matches. + # If we have no regexp, return nil since we do not require a condition. + "#{local_name}.nil? || #{value_regexp.inspect} =~ #{local_name}" if regexp + else # Then it must be present, and if we have a regexp, it must match too. + "#{local_name} #{"&& #{value_regexp.inspect} =~ #{local_name}" if regexp}" + end + end + def expiry_statement + "expired, hash = true, options if !expired && expire_on[:#{key}]" + end + + def extraction_code + s = extract_value + vc = value_check + s << "\nreturn [nil,nil] unless #{vc}" if vc + s << "\n#{expiry_statement}" + end + + def interpolation_chunk(value_code = "#{local_name}") + "\#{CGI.escape(#{value_code}.to_s)}" + end + + def string_structure(prior_segments) + if optional? # We have a conditional to do... + # If we should not appear in the url, just write the code for the prior + # segments. This occurs if our value is the default value, or, if we are + # optional, if we have nil as our value. + "if #{local_name} == #{default.inspect}\n" + + continue_string_structure(prior_segments) + + "\nelse\n" + # Otherwise, write the code up to here + "#{interpolation_statement(prior_segments)}\nend" + else + interpolation_statement(prior_segments) + end + end + + def value_regexp + Regexp.new "\\A#{regexp.to_s}\\Z" if regexp + end + + def regexp_chunk + if regexp + if regexp_has_modifiers? + "(#{regexp.to_s})" + else + "(#{regexp.source})" + end + else + "([^#{Routing::SEPARATORS.join}]+)" + end + end + + def build_pattern(pattern) + chunk = regexp_chunk + chunk = "(#{chunk})" if Regexp.new(chunk).number_of_captures == 0 + pattern = "#{chunk}#{pattern}" + optional? ? Regexp.optionalize(pattern) : pattern + end + + def match_extraction(next_capture) + # All non code-related keys (such as :id, :slug) are URI-unescaped as + # path parameters. + default_value = default ? default.inspect : nil + %[ + value = if (m = match[#{next_capture}]) + CGI.unescape(m) + else + #{default_value} + end + params[:#{key}] = value if value + ] + end + + def optionality_implied? + [:action, :id].include? key + end + + def regexp_has_modifiers? + regexp.options & (Regexp::IGNORECASE | Regexp::EXTENDED) != 0 + end + + end + + class ControllerSegment < DynamicSegment #:nodoc: + def regexp_chunk + possible_names = Routing.possible_controllers.collect { |name| Regexp.escape name } + "(?i-:(#{(regexp || Regexp.union(*possible_names)).source}))" + end + + # Don't URI.escape the controller name since it may contain slashes. + def interpolation_chunk(value_code = "#{local_name}") + "\#{#{value_code}.to_s}" + end + # Make sure controller names like Admin/Content are correctly normalized to + # admin/content + def extract_value + "#{local_name} = (hash[:#{key}] #{"|| #{default.inspect}" if default}).downcase" + end + + def match_extraction(next_capture) + if default + "params[:#{key}] = match[#{next_capture}] ? match[#{next_capture}].downcase : '#{default}'" + else + "params[:#{key}] = match[#{next_capture}].downcase if match[#{next_capture}]" + end + end + end + + class PathSegment < DynamicSegment #:nodoc: + def interpolation_chunk(value_code = "#{local_name}") + "\#{#{value_code}}" + end + + def extract_value + "#{local_name} = hash[:#{key}] && hash[:#{key}].collect { |path_component| CGI.escape(path_component) }.to_param #{"|| #{default.inspect}" if default}" + end + + def default + '' + end + + def default=(path) + raise RoutingError, "paths cannot have non-empty default values" unless path.blank? + end + + def match_extraction(next_capture) + "params[:#{key}] = PathSegment::Result.new_escaped((match[#{next_capture}]#{" || " + default.inspect if default}).split('/'))#{" if match[" + next_capture + "]" if !default}" + end + + def regexp_chunk + regexp || "(.*)" + end + + def optionality_implied? + true + end + + class Result < ::Array #:nodoc: + def to_s() join '/' end + def self.new_escaped(strings) + new strings.collect {|str| CGI.unescape str} + end + end + end + end +end diff --git a/vendor/rails/actionpack/lib/action_controller/session/active_record_store.rb b/vendor/rails/actionpack/lib/action_controller/session/active_record_store.rb index 14747c50..1e8eb57a 100644 --- a/vendor/rails/actionpack/lib/action_controller/session/active_record_store.rb +++ b/vendor/rails/actionpack/lib/action_controller/session/active_record_store.rb @@ -1,7 +1,6 @@ require 'cgi' require 'cgi/session' require 'digest/md5' -require 'base64' class CGI class Session @@ -14,7 +13,7 @@ class CGI # A session store backed by an Active Record class. A default class is - # provided, but any object duck-typing to an Active Record +Session+ class + # provided, but any object duck-typing to an Active Record Session class # with text +session_id+ and +data+ attributes is sufficient. # # The default assumes a +sessions+ tables with columns: @@ -27,13 +26,13 @@ class CGI # ActionController::SessionOverflowError will be raised. # # You may configure the table name, primary key, and data column. - # For example, at the end of config/environment.rb: + # For example, at the end of config/environment.rb: # CGI::Session::ActiveRecordStore::Session.table_name = 'legacy_session_table' # CGI::Session::ActiveRecordStore::Session.primary_key = 'session_id' # CGI::Session::ActiveRecordStore::Session.data_column_name = 'legacy_session_data' - # Note that setting the primary key to the session_id frees you from - # having a separate id column if you don't want it. However, you must - # set session.model.id = session.session_id by hand! A before_filter + # Note that setting the primary key to the +session_id+ frees you from + # having a separate +id+ column if you don't want it. However, you must + # set session.model.id = session.session_id by hand! A before filter # on ApplicationController is a good place. # # Since the default class is a simple Active Record, you get timestamps @@ -43,7 +42,7 @@ class CGI # You may provide your own session class implementation, whether a # feature-packed Active Record or a bare-metal high-performance SQL # store, by setting - # +CGI::Session::ActiveRecordStore.session_class = MySessionClass+ + # CGI::Session::ActiveRecordStore.session_class = MySessionClass # You must implement these methods: # self.find_by_session_id(session_id) # initialize(hash_of_session_id_and_data) @@ -80,8 +79,8 @@ class CGI find_by_session_id(session_id) end - def marshal(data) Base64.encode64(Marshal.dump(data)) if data end - def unmarshal(data) Marshal.load(Base64.decode64(data)) if data end + def marshal(data) ActiveSupport::Base64.encode64(Marshal.dump(data)) if data end + def unmarshal(data) Marshal.load(ActiveSupport::Base64.decode64(data)) if data end def create_table! connection.execute <<-end_sql @@ -155,8 +154,13 @@ class CGI # The database connection, table name, and session id and data columns # are configurable class attributes. Marshaling and unmarshaling # are implemented as class methods that you may override. By default, - # marshaling data is +Base64.encode64(Marshal.dump(data))+ and - # unmarshaling data is +Marshal.load(Base64.decode64(data))+. + # marshaling data is + # + # ActiveSupport::Base64.encode64(Marshal.dump(data)) + # + # and unmarshaling data is + # + # Marshal.load(ActiveSupport::Base64.decode64(data)) # # This marshaling behavior is intended to store the widest range of # binary session data in a +text+ column. For higher performance, @@ -190,8 +194,8 @@ class CGI end end - def marshal(data) Base64.encode64(Marshal.dump(data)) if data end - def unmarshal(data) Marshal.load(Base64.decode64(data)) if data end + def marshal(data) ActiveSupport::Base64.encode64(Marshal.dump(data)) if data end + def unmarshal(data) Marshal.load(ActiveSupport::Base64.decode64(data)) if data end def create_table! @@connection.execute <<-end_sql @@ -333,4 +337,4 @@ class CGI end end end -end \ No newline at end of file +end diff --git a/vendor/rails/actionpack/lib/action_controller/session/cookie_store.rb b/vendor/rails/actionpack/lib/action_controller/session/cookie_store.rb index 086f5a87..560491f9 100644 --- a/vendor/rails/actionpack/lib/action_controller/session/cookie_store.rb +++ b/vendor/rails/actionpack/lib/action_controller/session/cookie_store.rb @@ -1,6 +1,5 @@ require 'cgi' require 'cgi/session' -require 'base64' # to convert Marshal.dump to ASCII require 'openssl' # to generate the HMAC message digest # This cookie-based session store is the Rails default. Sessions typically @@ -15,27 +14,27 @@ require 'openssl' # to generate the HMAC message digest # TamperedWithCookie is raised if the data integrity check fails. # # A message digest is included with the cookie to ensure data integrity: -# a user cannot alter his user_id without knowing the secret key included in +# a user cannot alter his +user_id+ without knowing the secret key included in # the hash. New apps are generated with a pregenerated secret in # config/environment.rb. Set your own for old apps you're upgrading. # # Session options: -# :secret An application-wide key string or block returning a string -# called per generated digest. The block is called with the -# CGI::Session instance as an argument. It's important that the -# secret is not vulnerable to a dictionary attack. Therefore, -# you should choose a secret consisting of random numbers and -# letters and more than 30 characters. # -# Example: :secret => '449fe2e7daee471bffae2fd8dc02313d' -# :secret => Proc.new { User.current_user.secret_key } +# * :secret: An application-wide key string or block returning a string +# called per generated digest. The block is called with the CGI::Session +# instance as an argument. It's important that the secret is not vulnerable to +# a dictionary attack. Therefore, you should choose a secret consisting of +# random numbers and letters and more than 30 characters. Examples: # -# :digest The message digest algorithm used to verify session integrity -# defaults to 'SHA1' but may be any digest provided by OpenSSL, -# such as 'MD5', 'RIPEMD160', 'SHA256', etc. +# :secret => '449fe2e7daee471bffae2fd8dc02313d' +# :secret => Proc.new { User.current_user.secret_key } +# +# * :digest: The message digest algorithm used to verify session +# integrity defaults to 'SHA1' but may be any digest provided by OpenSSL, +# such as 'MD5', 'RIPEMD160', 'SHA256', etc. # # To generate a secret key for an existing application, run -# `rake secret` and set the key in config/environment.rb +# `rake secret` and set the key in config/environment.rb. # # Note that changing digest or secret invalidates all existing sessions! class CGI::Session::CookieStore @@ -118,7 +117,7 @@ class CGI::Session::CookieStore def delete @data = nil clear_old_cookie_value - write_cookie('value' => '', 'expires' => 1.year.ago) + write_cookie('value' => nil, 'expires' => 1.year.ago) end # Generate the HMAC keyed message digest. Uses SHA1 by default. @@ -130,7 +129,7 @@ class CGI::Session::CookieStore private # Marshal a session hash into safe cookie data. Include an integrity hash. def marshal(session) - data = Base64.encode64(Marshal.dump(session)).chop + data = ActiveSupport::Base64.encode64(Marshal.dump(session)).chop CGI.escape "#{data}--#{generate_digest(data)}" end @@ -142,7 +141,7 @@ class CGI::Session::CookieStore delete raise TamperedWithCookie end - Marshal.load(Base64.decode64(data)) + Marshal.load(ActiveSupport::Base64.decode64(data)) end end diff --git a/vendor/rails/actionpack/lib/action_controller/session_management.rb b/vendor/rails/actionpack/lib/action_controller/session_management.rb index fabb6e7f..80a3ddd2 100644 --- a/vendor/rails/actionpack/lib/action_controller/session_management.rb +++ b/vendor/rails/actionpack/lib/action_controller/session_management.rb @@ -16,9 +16,11 @@ module ActionController #:nodoc: end module ClassMethods - # Set the session store to be used for keeping the session data between requests. By default, sessions are stored - # in browser cookies (:cookie_store), but you can also specify one of the other included stores - # (:active_record_store, :p_store, drb_store, :mem_cache_store, or :memory_store) or your own custom class. + # Set the session store to be used for keeping the session data between requests. + # By default, sessions are stored in browser cookies (:cookie_store), + # but you can also specify one of the other included stores (:active_record_store, + # :p_store, :drb_store, :mem_cache_store, or + # :memory_store) or your own custom class. def session_store=(store) ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:database_manager] = store.is_a?(Symbol) ? CGI::Session.const_get(store == :drb_store ? "DRbStore" : store.to_s.camelize) : store @@ -67,11 +69,16 @@ module ActionController #:nodoc: # session :off, # :if => Proc.new { |req| !(req.format.html? || req.format.js?) } # + # # turn the session back on, useful when it was turned off in the + # # application controller, and you need it on in another controller + # session :on + # # All session options described for ActionController::Base.process_cgi # are valid arguments. def session(*args) options = args.extract_options! + options[:disabled] = false if args.delete(:on) options[:disabled] = true if !args.empty? options[:only] = [*options[:only]].map { |o| o.to_s } if options[:only] options[:except] = [*options[:except]].map { |o| o.to_s } if options[:except] diff --git a/vendor/rails/actionpack/lib/action_controller/streaming.rb b/vendor/rails/actionpack/lib/action_controller/streaming.rb index 42fe4298..186e0e55 100644 --- a/vendor/rails/actionpack/lib/action_controller/streaming.rb +++ b/vendor/rails/actionpack/lib/action_controller/streaming.rb @@ -4,34 +4,37 @@ module ActionController #:nodoc: DEFAULT_SEND_FILE_OPTIONS = { :type => 'application/octet-stream'.freeze, :disposition => 'attachment'.freeze, - :stream => true, - :buffer_size => 4096 + :stream => true, + :buffer_size => 4096, + :x_sendfile => false }.freeze + X_SENDFILE_HEADER = 'X-Sendfile'.freeze + protected # Sends the file by streaming it 4096 bytes at a time. This way the # whole file doesn't need to be read into memory at once. This makes # it feasible to send even large files. # # Be careful to sanitize the path parameter if it coming from a web - # page. send_file(params[:path]) allows a malicious user to + # page. send_file(params[:path]) allows a malicious user to # download any file on your server. # # Options: # * :filename - suggests a filename for the browser to use. - # Defaults to File.basename(path). + # Defaults to File.basename(path). # * :type - specifies an HTTP content type. # Defaults to 'application/octet-stream'. - # * :disposition - specifies whether the file will be shown inline or downloaded. + # * :disposition - specifies whether the file will be shown inline or downloaded. # Valid values are 'inline' and 'attachment' (default). - # * :stream - whether to send the file to the user agent as it is read (true) - # or to read the entire file before sending (false). Defaults to true. + # * :stream - whether to send the file to the user agent as it is read (+true+) + # or to read the entire file before sending (+false+). Defaults to +true+. # * :buffer_size - specifies size (in bytes) of the buffer used to stream the file. # Defaults to 4096. # * :status - specifies the status code to send with the response. Defaults to '200 OK'. - # * :url_based_filename - set to true if you want the browser guess the filename from - # the URL, which is necessary for i18n filenames on certain browsers - # (setting :filename overrides this option). + # * :url_based_filename - set to +true+ if you want the browser guess the filename from + # the URL, which is necessary for i18n filenames on certain browsers + # (setting :filename overrides this option). # # The default Content-Type and Content-Disposition headers are # set to download arbitrary binary files in as many browsers as @@ -39,17 +42,20 @@ module ActionController #:nodoc: # a variety of quirks (especially when downloading over SSL). # # Simple download: + # # send_file '/path/to.zip' # # Show a JPEG in the browser: + # # send_file '/path/to.jpeg', :type => 'image/jpeg', :disposition => 'inline' # # Show a 404 page in the browser: + # # send_file '/path/to/404.html', :type => 'text/html; charset=utf-8', :status => 404 # # Read about the other Content-* HTTP headers if you'd like to - # provide the user with more information (such as Content-Description). - # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11 + # provide the user with more information (such as Content-Description) in + # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11. # # Also be aware that the document may be cached by proxies and browsers. # The Pragma and Cache-Control headers declare how the file may be cached @@ -67,19 +73,24 @@ module ActionController #:nodoc: @performed_render = false - if options[:stream] - render :status => options[:status], :text => Proc.new { |response, output| - logger.info "Streaming file #{path}" unless logger.nil? - len = options[:buffer_size] || 4096 - File.open(path, 'rb') do |file| - while buf = file.read(len) - output.write(buf) - end - end - } + if options[:x_sendfile] + logger.info "Sending #{X_SENDFILE_HEADER} header #{path}" if logger + head options[:status], X_SENDFILE_HEADER => path else - logger.info "Sending file #{path}" unless logger.nil? - File.open(path, 'rb') { |file| render :status => options[:status], :text => file.read } + if options[:stream] + render :status => options[:status], :text => Proc.new { |response, output| + logger.info "Streaming file #{path}" unless logger.nil? + len = options[:buffer_size] || 4096 + File.open(path, 'rb') do |file| + while buf = file.read(len) + output.write(buf) + end + end + } + else + logger.info "Sending file #{path}" unless logger.nil? + File.open(path, 'rb') { |file| render :status => options[:status], :text => file.read } + end end end @@ -87,25 +98,28 @@ module ActionController #:nodoc: # and specify whether to show data inline or download as an attachment. # # Options: - # * :filename - Suggests a filename for the browser to use. + # * :filename - suggests a filename for the browser to use. # * :type - specifies an HTTP content type. # Defaults to 'application/octet-stream'. - # * :disposition - specifies whether the file will be shown inline or downloaded. + # * :disposition - specifies whether the file will be shown inline or downloaded. # Valid values are 'inline' and 'attachment' (default). # * :status - specifies the status code to send with the response. Defaults to '200 OK'. # # Generic data download: + # # send_data buffer # # Download a dynamically-generated tarball: + # # send_data generate_tgz('dir'), :filename => 'dir.tgz' # # Display an image Active Record in the browser: + # # send_data image.data, :type => image.content_type, :disposition => 'inline' # # See +send_file+ for more information on HTTP Content-* headers and caching. def send_data(data, options = {}) #:doc: - logger.info "Sending data #{options[:filename]}" unless logger.nil? + logger.info "Sending data #{options[:filename]}" if logger send_file_headers! options.merge(:length => data.size) @performed_render = false render :status => options[:status], :text => data @@ -130,10 +144,10 @@ module ActionController #:nodoc: ) # Fix a problem with IE 6.0 on opening downloaded files: - # If Cache-Control: no-cache is set (which Rails does by default), - # IE removes the file it just downloaded from its cache immediately - # after it displays the "open/save" dialog, which means that if you - # hit "open" the file isn't there anymore when the application that + # If Cache-Control: no-cache is set (which Rails does by default), + # IE removes the file it just downloaded from its cache immediately + # after it displays the "open/save" dialog, which means that if you + # hit "open" the file isn't there anymore when the application that # is called for handling the download is run, so let's workaround that headers['Cache-Control'] = 'private' if headers['Cache-Control'] == 'no-cache' end diff --git a/vendor/rails/actionpack/lib/action_controller/templates/rescues/_trace.erb b/vendor/rails/actionpack/lib/action_controller/templates/rescues/_trace.erb index b322b0aa..bb2d8375 100644 --- a/vendor/rails/actionpack/lib/action_controller/templates/rescues/_trace.erb +++ b/vendor/rails/actionpack/lib/action_controller/templates/rescues/_trace.erb @@ -10,17 +10,17 @@

RAILS_ROOT: <%= defined?(RAILS_ROOT) ? RAILS_ROOT : "unset" %>

- <% names.each do |name| -%> + <% names.each do |name| %> <% show = "document.getElementById('#{name.gsub /\s/, '-'}').style.display='block';" hide = (names - [name]).collect {|hide_name| "document.getElementById('#{hide_name.gsub /\s/, '-'}').style.display='none';"} %> <%= name %> <%= '|' unless names.last == name %> - <% end -%> + <% end %> - <% traces.each do |name, trace| -%> + <% traces.each do |name, trace| %>
;">
<%= trace.join "\n" %>
- <% end -%> -
\ No newline at end of file + <% end %> + diff --git a/vendor/rails/actionpack/lib/action_controller/test_case.rb b/vendor/rails/actionpack/lib/action_controller/test_case.rb index d81cb5da..757a80ce 100644 --- a/vendor/rails/actionpack/lib/action_controller/test_case.rb +++ b/vendor/rails/actionpack/lib/action_controller/test_case.rb @@ -3,14 +3,43 @@ require 'active_support/test_case' module ActionController class NonInferrableControllerError < ActionControllerError def initialize(name) + @name = name super "Unable to determine the controller to test from #{name}. " + "You'll need to specify it using 'tests YourController' in your " + - "test case definition" + "test case definition. This could mean that #{inferred_controller_name} does not exist " + + "or it contains syntax errors" + end + + def inferred_controller_name + @name.sub(/Test$/, '') end end class TestCase < ActiveSupport::TestCase + # When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline + # (bystepping the regular exception handling from rescue_action). If the request.remote_addr is anything else, the regular + # rescue_action process takes place. This means you can test your rescue_action code by setting remote_addr to something else + # than 0.0.0.0. + # + # The exception is stored in the exception accessor for further inspection. + module RaiseActionExceptions + attr_accessor :exception + + def rescue_action(e) + self.exception = e + + if request.remote_addr == "0.0.0.0" + raise(e) + else + super(e) + end + end + end + + setup :setup_controller_request_and_response + @@controller_class = nil + class << self def tests(controller_class) self.controller_class = controller_class @@ -25,7 +54,7 @@ module ActionController if current_controller_class = read_inheritable_attribute(:controller_class) current_controller_class else - self.controller_class= determine_default_controller_class(name) + self.controller_class = determine_default_controller_class(name) end end @@ -36,18 +65,19 @@ module ActionController end def prepare_controller_class(new_class) - new_class.class_eval do - def rescue_action(e) - raise e - end - end + new_class.send :include, RaiseActionExceptions end end - def setup + def setup_controller_request_and_response @controller = self.class.controller_class.new - @request = TestRequest.new - @response = TestResponse.new + @controller.request = @request = TestRequest.new + @response = TestResponse.new end - end -end \ No newline at end of file + + # Cause the action to be rescued according to the regular rules for rescue_action when the visitor is not local + def rescue_action_in_public! + @request.remote_addr = '208.77.188.166' # example.com + end + end +end diff --git a/vendor/rails/actionpack/lib/action_controller/test_process.rb b/vendor/rails/actionpack/lib/action_controller/test_process.rb index 88533115..dcb6cdf4 100644 --- a/vendor/rails/actionpack/lib/action_controller/test_process.rb +++ b/vendor/rails/actionpack/lib/action_controller/test_process.rb @@ -1,4 +1,5 @@ require 'action_controller/assertions' +require 'action_controller/test_case' module ActionController #:nodoc: class Base @@ -154,12 +155,12 @@ module ActionController #:nodoc: # A refactoring of TestResponse to allow the same behavior to be applied # to the "real" CgiResponse class in integration tests. module TestResponseBehavior #:nodoc: - # the response code of the request + # The response code of the request def response_code headers['Status'][0,3].to_i rescue 0 end - # returns a String to ensure compatibility with Net::HTTPResponse + # Returns a String to ensure compatibility with Net::HTTPResponse def code headers['Status'].to_s.split(' ')[0] end @@ -168,34 +169,34 @@ module ActionController #:nodoc: headers['Status'].to_s.split(' ',2)[1] end - # was the response successful? + # Was the response successful? def success? response_code == 200 end - # was the URL not found? + # Was the URL not found? def missing? response_code == 404 end - # were we redirected? + # Were we redirected? def redirect? (300..399).include?(response_code) end - # was there a server-side error? + # Was there a server-side error? def error? (500..599).include?(response_code) end alias_method :server_error?, :error? - # returns the redirection location or nil + # Returns the redirection location or nil def redirect_url headers['Location'] end - # does the redirect location match this regexp pattern? + # Does the redirect location match this regexp pattern? def redirect_url_match?( pattern ) return false if redirect_url.nil? p = Regexp.new(pattern) if pattern.class == String @@ -204,7 +205,7 @@ module ActionController #:nodoc: p.match(redirect_url) != nil end - # returns the template path of the file which was used to + # Returns the template path of the file which was used to # render this response (or nil) def rendered_file(with_controller=false) unless template.first_render.nil? @@ -216,50 +217,49 @@ module ActionController #:nodoc: end end - # was this template rendered by a file? + # Was this template rendered by a file? def rendered_with_file? !rendered_file.nil? end - # a shortcut to the flash (or an empty hash if no flash.. hey! that rhymes!) + # A shortcut to the flash. Returns an empyt hash if no session flash exists. def flash session['flash'] || {} end - # do we have a flash? + # Do we have a flash? def has_flash? !session['flash'].empty? end - # do we have a flash that has contents? + # Do we have a flash that has contents? def has_flash_with_contents? !flash.empty? end - # does the specified flash object exist? + # Does the specified flash object exist? def has_flash_object?(name=nil) !flash[name].nil? end - # does the specified object exist in the session? + # Does the specified object exist in the session? def has_session_object?(name=nil) !session[name].nil? end - # a shortcut to the template.assigns + # A shortcut to the template.assigns def template_objects template.assigns || {} end - # does the specified template object exist? + # Does the specified template object exist? def has_template_object?(name=nil) !template_objects[name].nil? end # Returns the response cookies, converted to a Hash of (name => CGI::Cookie) pairs - # Example: # - # assert_equal ['AuthorOfNewPage'], r.cookies['author'].value + # assert_equal ['AuthorOfNewPage'], r.cookies['author'].value def cookies headers['cookie'].inject({}) { |hash, cookie| hash[cookie.name] = cookie; hash } end @@ -286,7 +286,7 @@ module ActionController #:nodoc: def initialize(attributes = nil) @session_id = '' - @attributes = attributes + @attributes = attributes.nil? ? nil : attributes.stringify_keys @saved_attributes = nil end @@ -295,11 +295,11 @@ module ActionController #:nodoc: end def [](key) - data[key] + data[key.to_s] end def []=(key, value) - data[key] = value + data[key.to_s] = value end def update @@ -373,7 +373,7 @@ module ActionController #:nodoc: # Sanity check for required instance variables so we can give an # understandable error message. %w(@controller @request @response).each do |iv_name| - if !(instance_variables.include?(iv_name) || instance_variables.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil? + if !(instance_variable_names.include?(iv_name) || instance_variable_names.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil? raise "#{iv_name} is nil: make sure you set it in your test's setup method." end end @@ -464,10 +464,13 @@ module ActionController #:nodoc: return super end - # Shortcut for ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + path, type). Example: + # Shortcut for ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + path, type): + # # post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png') # - # To upload binary files on Windows, pass :binary as the last parameter. This will not affect other platforms. + # To upload binary files on Windows, pass :binary as the last parameter. + # This will not affect other platforms: + # # post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png', :binary) def fixture_file_upload(path, mime_type = nil, binary = false) ActionController::TestUploadedFile.new( @@ -482,17 +485,17 @@ module ActionController #:nodoc: # with a new RouteSet instance. # # The new instance is yielded to the passed block. Typically the block - # will create some routes using map.draw { map.connect ... }: + # will create some routes using map.draw { map.connect ... }: # - # with_routing do |set| - # set.draw do |map| - # map.connect ':controller/:action/:id' - # assert_equal( - # ['/content/10/show', {}], - # map.generate(:controller => 'content', :id => 10, :action => 'show') - # end - # end - # end + # with_routing do |set| + # set.draw do |map| + # map.connect ':controller/:action/:id' + # assert_equal( + # ['/content/10/show', {}], + # map.generate(:controller => 'content', :id => 10, :action => 'show') + # end + # end + # end # def with_routing real_routes = ActionController::Routing::Routes diff --git a/vendor/rails/actionpack/lib/action_controller/url_rewriter.rb b/vendor/rails/actionpack/lib/action_controller/url_rewriter.rb index c650763f..3a38f233 100644 --- a/vendor/rails/actionpack/lib/action_controller/url_rewriter.rb +++ b/vendor/rails/actionpack/lib/action_controller/url_rewriter.rb @@ -1,82 +1,89 @@ -module ActionController +module ActionController # Write URLs from arbitrary places in your codebase, such as your mailers. - # + # # Example: - # + # # class MyMailer # include ActionController::UrlWriter # default_url_options[:host] = 'www.basecamphq.com' - # + # # def signup_url(token) # url_for(:controller => 'signup', action => 'index', :token => token) # end # end - # + # # In addition to providing +url_for+, named routes are also accessible after # including UrlWriter. module UrlWriter - # The default options for urls written by this writer. Typically a :host pair - # is provided. + # The default options for urls written by this writer. Typically a :host + # pair is provided. mattr_accessor :default_url_options self.default_url_options = {} - + def self.included(base) #:nodoc: - ActionController::Routing::Routes.install_helpers base + ActionController::Routing::Routes.install_helpers(base) base.mattr_accessor :default_url_options base.default_url_options ||= default_url_options end - - # Generate a url based on the options provided, default_url_options and the + + # Generate a url based on the options provided, default_url_options and the # routes defined in routes.rb. The following options are supported: - # - # * :only_path If true, the relative url is returned. Defaults to false. - # * :protocol The protocol to connect to. Defaults to 'http'. - # * :host Specifies the host the link should be targetted at. If :only_path is false, this option must be - # provided either explicitly, or via default_url_options. - # * :port Optionally specify the port to connect to. - # * :anchor An anchor name to be appended to the path. - # - # Any other key(:controller, :action, etc...) given to url_for is forwarded to the Routes module. - # + # + # * :only_path - If true, the relative url is returned. Defaults to +false+. + # * :protocol - The protocol to connect to. Defaults to 'http'. + # * :host - Specifies the host the link should be targetted at. + # If :only_path is false, this option must be + # provided either explicitly, or via +default_url_options+. + # * :port - Optionally specify the port to connect to. + # * :anchor - An anchor name to be appended to the path. + # * :skip_relative_url_root - If true, the url is not constructed using the + # +relative_url_root+ set in ActionController::AbstractRequest.relative_url_root. + # * :trailing_slash - If true, adds a trailing slash, as in "/archive/2009/" + # + # Any other key (:controller, :action, etc.) given to + # +url_for+ is forwarded to the Routes module. + # # Examples: - # + # # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :port=>'8080' # => 'http://somehost.org:8080/tasks/testing' # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :anchor => 'ok', :only_path => true # => '/tasks/testing#ok' + # url_for :controller => 'tasks', :action => 'testing', :trailing_slash=>true # => 'http://somehost.org/tasks/testing/' # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :number => '33' # => 'http://somehost.org/tasks/testing?number=33' - # def url_for(options) options = self.class.default_url_options.merge(options) - + url = '' - unless options.delete :only_path + unless options.delete(:only_path) url << (options.delete(:protocol) || 'http') - url << '://' unless url.match("://") #dont add separator if its already been specified in :protocol - + url << '://' unless url.match("://") + raise "Missing host to link to! Please provide :host parameter or set default_url_options[:host]" unless options[:host] url << options.delete(:host) url << ":#{options.delete(:port)}" if options.key?(:port) else - # Delete the unused options to prevent their appearance in the query string - [:protocol, :host, :port].each { |k| options.delete k } + # Delete the unused options to prevent their appearance in the query string. + [:protocol, :host, :port, :skip_relative_url_root].each { |k| options.delete(k) } end - - anchor = "##{CGI.escape options.delete(:anchor).to_param.to_s}" if options.key?(:anchor) - url << Routing::Routes.generate(options, {}) + trailing_slash = options.delete(:trailing_slash) if options.key?(:trailing_slash) + url << ActionController::AbstractRequest.relative_url_root.to_s unless options[:skip_relative_url_root] + anchor = "##{CGI.escape options.delete(:anchor).to_param.to_s}" if options[:anchor] + generated = Routing::Routes.generate(options, {}) + url << (trailing_slash ? generated.sub(/\?|\z/) { "/" + $& } : generated) url << anchor if anchor - return url - end + url + end end - + # Rewrites URLs for Base.redirect_to and Base.url_for in the controller. class UrlRewriter #:nodoc: RESERVED_OPTIONS = [:anchor, :params, :only_path, :host, :protocol, :port, :trailing_slash, :skip_relative_url_root] def initialize(request, parameters) @request, @parameters = request, parameters end - + def rewrite(options = {}) rewrite_url(options) end @@ -123,7 +130,7 @@ module ActionController # Generates the query string, too Routing::Routes.generate(options, @request.symbolized_path_parameters) end - + def rewrite_authentication(options) if options[:user] && options[:password] "#{CGI.escape(options.delete(:user))}:#{CGI.escape(options.delete(:password))}@" diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb b/vendor/rails/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb index 1eb426ae..12c84051 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +++ b/vendor/rails/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb @@ -107,7 +107,7 @@ module HTML # gauntlet if style !~ /^([:,;#%.\sa-zA-Z0-9!]|\w-\w|\'[\s\w]+\'|\"[\s\w]+\"|\([\d,\s]+\))*$/ || - style !~ /^(\s*[-\w]+\s*:\s*[^:;]*(;|$))*$/ + style !~ /^(\s*[-\w]+\s*:\s*[^:;]*(;|$)\s*)*$/ return '' end @@ -170,4 +170,4 @@ module HTML (value =~ /(^[^\/:]*):|(�*58)|(p)|(%|%)3A/ && !allowed_protocols.include?(value.split(protocol_separator).first)) end end -end \ No newline at end of file +end diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/html-scanner/html/tokenizer.rb b/vendor/rails/actionpack/lib/action_controller/vendor/html-scanner/html/tokenizer.rb index b950e846..602411ed 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +++ b/vendor/rails/actionpack/lib/action_controller/vendor/html-scanner/html/tokenizer.rb @@ -54,7 +54,7 @@ module HTML #:nodoc: tag << (@scanner.scan_until(/--\s*>/) || @scanner.scan_until(/\Z/)) elsif @scanner.scan(/!\[CDATA\[/) tag << @scanner.matched - tag << @scanner.scan_until(/\]\]>/) + tag << (@scanner.scan_until(/\]\]>/) || @scanner.scan_until(/\Z/)) elsif @scanner.scan(/!/) # doctype tag << @scanner.matched tag << consume_quoted_regions diff --git a/vendor/rails/actionpack/lib/action_controller/verification.rb b/vendor/rails/actionpack/lib/action_controller/verification.rb index e5045fba..9f606e7b 100644 --- a/vendor/rails/actionpack/lib/action_controller/verification.rb +++ b/vendor/rails/actionpack/lib/action_controller/verification.rb @@ -43,72 +43,88 @@ module ActionController #:nodoc: # the user is redirected to a different action. The +options+ parameter # is a hash consisting of the following key/value pairs: # - # * :params - a single key or an array of keys that must - # be in the params hash in order for the action(s) to be safely - # called. - # * :session - a single key or an array of keys that must - # be in the session in order for the action(s) to be safely called. - # * :flash - a single key or an array of keys that must - # be in the flash in order for the action(s) to be safely called. - # * :method - a single key or an array of keys--any one of which - # must match the current request method in order for the action(s) to - # be safely called. (The key should be a symbol: :get or - # :post, for example.) - # * :xhr - true/false option to ensure that the request is coming - # from an Ajax call or not. - # * :add_flash - a hash of name/value pairs that should be merged - # into the session's flash if the prerequisites cannot be satisfied. - # * :add_headers - a hash of name/value pairs that should be - # merged into the response's headers hash if the prerequisites cannot - # be satisfied. - # * :redirect_to - the redirection parameters to be used when - # redirecting if the prerequisites cannot be satisfied. You can - # redirect either to named route or to the action in some controller. - # * :render - the render parameters to be used when - # the prerequisites cannot be satisfied. - # * :only - only apply this verification to the actions specified - # in the associated array (may also be a single value). - # * :except - do not apply this verification to the actions - # specified in the associated array (may also be a single value). + # :params:: + # a single key or an array of keys that must be in the params + # hash in order for the action(s) to be safely called. + # :session:: + # a single key or an array of keys that must be in the session + # in order for the action(s) to be safely called. + # :flash:: + # a single key or an array of keys that must be in the flash in order + # for the action(s) to be safely called. + # :method:: + # a single key or an array of keys--any one of which must match the + # current request method in order for the action(s) to be safely called. + # (The key should be a symbol: :get or :post, for + # example.) + # :xhr:: + # true/false option to ensure that the request is coming from an Ajax + # call or not. + # :add_flash:: + # a hash of name/value pairs that should be merged into the session's + # flash if the prerequisites cannot be satisfied. + # :add_headers:: + # a hash of name/value pairs that should be merged into the response's + # headers hash if the prerequisites cannot be satisfied. + # :redirect_to:: + # the redirection parameters to be used when redirecting if the + # prerequisites cannot be satisfied. You can redirect either to named + # route or to the action in some controller. + # :render:: + # the render parameters to be used when the prerequisites cannot be satisfied. + # :only:: + # only apply this verification to the actions specified in the associated + # array (may also be a single value). + # :except:: + # do not apply this verification to the actions specified in the associated + # array (may also be a single value). def verify(options={}) - filter_opts = { :only => options[:only], :except => options[:except] } - before_filter(filter_opts) do |c| + before_filter :only => options[:only], :except => options[:except] do |c| c.send! :verify_action, options end end end - def verify_action(options) #:nodoc: - prereqs_invalid = - [*options[:params] ].find { |v| params[v].nil? } || - [*options[:session]].find { |v| session[v].nil? } || - [*options[:flash] ].find { |v| flash[v].nil? } - - if !prereqs_invalid && options[:method] - prereqs_invalid ||= - [*options[:method]].all? { |v| request.method != v.to_sym } - end - - prereqs_invalid ||= (request.xhr? != options[:xhr]) unless options[:xhr].nil? - - if prereqs_invalid - flash.update(options[:add_flash]) if options[:add_flash] - response.headers.update(options[:add_headers]) if options[:add_headers] + private - unless performed? - case - when options[:render] - render(options[:render]) - when options[:redirect_to] - options[:redirect_to] = self.send!(options[:redirect_to]) if options[:redirect_to].is_a?(Symbol) - redirect_to(options[:redirect_to]) - else - head(:bad_request) - end - end + def verify_action(options) #:nodoc: + if prereqs_invalid?(options) + flash.update(options[:add_flash]) if options[:add_flash] + response.headers.update(options[:add_headers]) if options[:add_headers] + apply_remaining_actions(options) unless performed? + end + end + + def prereqs_invalid?(options) # :nodoc: + verify_presence_of_keys_in_hash_flash_or_params(options) || + verify_method(options) || + verify_request_xhr_status(options) + end + + def verify_presence_of_keys_in_hash_flash_or_params(options) # :nodoc: + [*options[:params] ].find { |v| params[v].nil? } || + [*options[:session]].find { |v| session[v].nil? } || + [*options[:flash] ].find { |v| flash[v].nil? } + end + + def verify_method(options) # :nodoc: + [*options[:method]].all? { |v| request.method != v.to_sym } if options[:method] + end + + def verify_request_xhr_status(options) # :nodoc: + request.xhr? != options[:xhr] unless options[:xhr].nil? + end + + def apply_redirect_to(redirect_to_option) # :nodoc: + redirect_to_option.is_a?(Symbol) ? self.send!(redirect_to_option) : redirect_to_option + end + + def apply_remaining_actions(options) # :nodoc: + case + when options[:render] ; render(options[:render]) + when options[:redirect_to] ; redirect_to(apply_redirect_to(options[:redirect_to])) + else head(:bad_request) end end - - private :verify_action end end \ No newline at end of file diff --git a/vendor/rails/actionpack/lib/action_pack.rb b/vendor/rails/actionpack/lib/action_pack.rb index 006c83db..c7fd3092 100644 --- a/vendor/rails/actionpack/lib/action_pack.rb +++ b/vendor/rails/actionpack/lib/action_pack.rb @@ -1,5 +1,5 @@ #-- -# Copyright (c) 2004-2007 David Heinemeier Hansson +# Copyright (c) 2004-2008 David Heinemeier Hansson # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the diff --git a/vendor/rails/actionpack/lib/action_pack/version.rb b/vendor/rails/actionpack/lib/action_pack/version.rb index 7aa6a5db..70fc1ced 100644 --- a/vendor/rails/actionpack/lib/action_pack/version.rb +++ b/vendor/rails/actionpack/lib/action_pack/version.rb @@ -2,7 +2,7 @@ module ActionPack #:nodoc: module VERSION #:nodoc: MAJOR = 2 MINOR = 0 - TINY = 2 + TINY = 991 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/vendor/rails/actionpack/lib/action_view.rb b/vendor/rails/actionpack/lib/action_view.rb index bfcfcab0..5f4126e4 100644 --- a/vendor/rails/actionpack/lib/action_view.rb +++ b/vendor/rails/actionpack/lib/action_view.rb @@ -1,5 +1,5 @@ #-- -# Copyright (c) 2004-2007 David Heinemeier Hansson +# Copyright (c) 2004-2008 David Heinemeier Hansson # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -22,16 +22,24 @@ #++ 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' +require 'action_view/partial_template' +require 'action_view/inline_template' + require 'action_view/base' require 'action_view/partials' require 'action_view/template_error' ActionView::Base.class_eval do include ActionView::Partials -end -ActionView::Base.load_helpers + ActionView::Base.helper_modules.each do |helper_module| + include helper_module + end +end diff --git a/vendor/rails/actionpack/lib/action_view/base.rb b/vendor/rails/actionpack/lib/action_view/base.rb index 0f966add..4840b252 100644 --- a/vendor/rails/actionpack/lib/action_view/base.rb +++ b/vendor/rails/actionpack/lib/action_view/base.rb @@ -1,10 +1,13 @@ 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 +.erb+ (or +.rhtml+) extension then it uses a mixture of ERb - # (included in Ruby) and HTML. If the template file has a +.builder+ (or +.rxml+) extension then Jim Weirich's Builder::XmlMarkup library is used. - # If the template file has a +.rjs+ extension then it will use ActionView::Helpers::PrototypeHelper::JavaScriptGenerator. + # Action View templates can be written in three ways. If the template file has a .erb (or .rhtml) extension then it uses a mixture of ERb + # (included in Ruby) and HTML. If the template file has a .builder (or .rxml) extension then Jim Weirich's Builder::XmlMarkup library is used. + # If the template file has a .rjs extension then it will use ActionView::Helpers::PrototypeHelper::JavaScriptGenerator. # # = ERb # @@ -21,7 +24,7 @@ module ActionView #:nodoc: # # Hi, Mr. <% puts "Frodo" %> # - # If you absolutely must write from within a function, you can use the TextHelper#concat + # If you absolutely must write from within a function, you can use the TextHelper#concat. # # <%- and -%> suppress leading and trailing whitespace, including the trailing newline, and can be used interchangeably with <% and %>. # @@ -43,7 +46,7 @@ module ActionView #:nodoc: # <% @page_title = "A Wonderful Hello" %> # <%= render "shared/header" %> # - # Now the header can pick up on the @page_title variable and use it for outputting a title tag: + # Now the header can pick up on the @page_title variable and use it for outputting a title tag: # # <%= @page_title %> # @@ -53,7 +56,7 @@ module ActionView #:nodoc: # # <%= render "shared/header", { :headline => "Welcome", :person => person } %> # - # These can now be accessed in shared/header with: + # These can now be accessed in shared/header with: # # Headline: <%= headline %> # First name: <%= person.first_name %> @@ -74,13 +77,13 @@ 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 +.builder+ 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 .builder extension. # # Here are some basic examples: # # xml.em("emphasized") # => emphasized - # xml.em { xml.b("emph & bold") } # => emph & bold + # xml.em { xml.b("emph & bold") } # => emph & bold # xml.a("A Link", "href"=>"http://onestepback.org") # => A Link # xml.target("name"=>"compile", "option"=>"fast") # => # # NOTE: order of attributes is not specified. @@ -127,18 +130,18 @@ module ActionView #:nodoc: # # == JavaScriptGenerator # - # JavaScriptGenerator templates end in +.rjs+. Unlike conventional templates which are used to + # JavaScriptGenerator templates end in .rjs. 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. # - # When an .rjs action is called with +link_to_remote+, the generated JavaScript is automatically evaluated. Example: + # When an .rjs action is called with +link_to_remote+, the generated JavaScript is automatically evaluated. Example: # # link_to_remote :url => {:action => 'delete'} # - # The subsequently rendered +delete.rjs+ might look like: + # The subsequently rendered delete.rjs might look like: # # page.replace_html 'sidebar', :partial => 'sidebar' # page.remove "person-#{@person.id}" @@ -150,14 +153,12 @@ module ActionView #:nodoc: class Base include ERB::Util - attr_reader :first_render - attr_accessor :base_path, :assigns, :template_extension - attr_accessor :controller, :view_paths - - attr_reader :logger, :response, :headers - attr_internal :cookies, :flash, :headers, :params, :request, :response, :session + 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. @@ -172,12 +173,6 @@ module ActionView #:nodoc: # Should be +false+ for development environments. Defaults to +true+. @@cache_template_extensions = true cattr_accessor :cache_template_extensions - - # Specify whether local_assigns should be able to use string keys. - # Defaults to +true+. String keys are deprecated and will be removed - # shortly. - @@local_assigns_support_string_keys = true - cattr_accessor :local_assigns_support_string_keys # Specify whether RJS responses should be wrapped in a try/catch block # that alert()s the caught exception (and then re-raises it). @@ -187,89 +182,47 @@ module ActionView #:nodoc: @@erb_variable = '_erbout' cattr_accessor :erb_variable - delegate :request_forgery_protection_token, :to => :controller + attr_internal :request - @@template_handlers = HashWithIndifferentAccess.new + delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers, + :flash, :logger, :action_name, :to => :controller module CompiledTemplates #:nodoc: # holds compiled template code end include CompiledTemplates - # Maps inline templates to their method names + # Maps inline templates to their method names + cattr_accessor :method_names @@method_names = {} - # Map method names to their compile time - @@compile_time = {} # Map method names to the names passed in local assigns so far @@template_args = {} - # Count the number of inline templates - @@inline_template_count = 0 - # Maps template paths without extension to their file extension returned by pick_template_extension. - # If for a given path, path.ext1 and path.ext2 exist on the file system, the order of extensions - # used by pick_template_extension determines whether ext1 or ext2 will be stored. - @@cached_template_extension = {} - # Maps template paths / extensions to - @@cached_base_paths = {} # Cache public asset paths cattr_reader :computed_public_paths @@computed_public_paths = {} - @@template_handlers = {} - @@default_template_handlers = nil - class ObjectWrapper < Struct.new(:value) #:nodoc: end - def self.load_helpers #:nodoc: - Dir.entries("#{File.dirname(__FILE__)}/helpers").sort.each do |file| + def self.helper_modules #:nodoc: + helpers = [] + Dir.entries(File.expand_path("#{File.dirname(__FILE__)}/helpers")).sort.each do |file| next unless file =~ /^([a-z][a-z_]*_helper).rb$/ require "action_view/helpers/#{$1}" helper_module_name = $1.camelize if Helpers.const_defined?(helper_module_name) - include Helpers.const_get(helper_module_name) + helpers << Helpers.const_get(helper_module_name) end end + return helpers end - # Register a class that knows how to handle template files with the given - # extension. This can be used to implement new template types. - # The constructor for the class must take the ActiveView::Base instance - # as a parameter, and the class must implement a #render method that - # takes the contents of the template to render as well as the Hash of - # local assigns available to the template. The #render method ought to - # return the rendered template as a string. - def self.register_template_handler(extension, klass) - @@template_handlers[extension.to_sym] = klass - end - - def self.template_handler_extensions - @@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_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 - - # TODO: Depreciate old template extensions - register_template_handler :rhtml, TemplateHandlers::ERB - register_template_handler :rxml, TemplateHandlers::Builder - def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil)#:nodoc: - @view_paths = view_paths.respond_to?(:find) ? view_paths.dup : [*view_paths].compact @assigns = assigns_for_first_render @assigns_added = nil @controller = controller - @logger = controller && controller.logger + @finder = TemplateFinder.new(self, view_paths) end # Renders the template present at template_path. If use_full_path is set to true, @@ -289,60 +242,28 @@ If you are rendering a subtemplate, you must now use controller-like partial syn END_ERROR end - @first_render ||= template_path - template_path_without_extension, template_extension = path_and_extension(template_path) - if use_full_path - if template_extension - template_file_name = full_template_path(template_path_without_extension, template_extension) - else - template_extension = pick_template_extension(template_path).to_s - unless template_extension - raise ActionViewError, "No template found for #{template_path} in #{view_paths.inspect}" - end - template_file_name = full_template_path(template_path, template_extension) - template_extension = template_extension.gsub(/^.+\./, '') # strip off any formats - end - else - template_file_name = template_path - end - - template_source = nil # Don't read the source until we know that it is required - - if template_file_name.blank? - raise ActionViewError, "Couldn't find template file for #{template_path} in #{view_paths.inspect}" - end - - begin - render_template(template_extension, template_source, template_file_name, local_assigns) - rescue Exception => e - if TemplateError === e - e.sub_template_of(template_file_name) - raise e - else - raise TemplateError.new(find_base_path_for("#{template_path_without_extension}.#{template_extension}") || view_paths.first, template_file_name, @assigns, template_source, e) - end - end + Template.new(self, template_path, use_full_path, local_assigns).render_template end # Renders the template present at template_path (relative to the view_paths array). # The hash in local_assigns is made available as local variables. - def render(options = {}, old_local_assigns = {}, &block) #:nodoc: + def render(options = {}, local_assigns = {}, &block) #:nodoc: if options.is_a?(String) - render_file(options, true, old_local_assigns) + render_file(options, true, local_assigns) elsif options == :update update_page(&block) elsif options.is_a?(Hash) options = options.reverse_merge(:locals => {}, :use_full_path => true) - if options[:layout] - path, partial_name = partial_pieces(options.delete(:layout)) - + if partial_layout = options.delete(:layout) if block_given? - @content_for_layout = capture(&block) - concat(render(options.merge(:partial => "#{path}/#{partial_name}")), block.binding) + wrap_content_for_layout capture(&block) do + concat(render(options.merge(:partial => partial_layout)), block.binding) + end else - @content_for_layout = render(options) - render(options.merge(:partial => "#{path}/#{partial_name}")) + wrap_content_for_layout render(options) do + render(options.merge(:partial => partial_layout)) + end end elsif options[:file] render_file(options[:file], options[:use_full_path], options[:locals]) @@ -351,61 +272,14 @@ If you are rendering a subtemplate, you must now use controller-like partial syn elsif options[:partial] render_partial(options[:partial], ActionView::Base::ObjectWrapper.new(options[:object]), options[:locals]) elsif options[:inline] - render_template(options[:type], options[:inline], nil, options[:locals]) + template = InlineTemplate.new(self, options[:inline], options[:locals], options[:type]) + render_template(template) end end end - # Renders the +template+ which is given as a string as either erb or builder depending on template_extension. - # The hash in local_assigns is made available as local variables. - def render_template(template_extension, template, file_path = nil, local_assigns = {}) #:nodoc: - handler = self.class.handler_for_extension(template_extension) - - if template_handler_is_compilable?(handler) - compile_and_render_template(handler, template, file_path, local_assigns) - else - template ||= read_template_file(file_path, template_extension) # Make sure that a lazyily-read template is loaded. - delegate_render(handler, template, local_assigns) - end - end - - # Gets the full template path with base path for the given template_path and extension. - # - # full_template_path('users/show', 'html.erb') - # # => '~/rails/app/views/users/show.html.erb - # - def full_template_path(template_path, extension) - if @@cache_template_extensions - (@@cached_base_paths[template_path] ||= {})[extension.to_s] ||= find_full_template_path(template_path, extension) - else - find_full_template_path(template_path, extension) - end - 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)#:nodoc: - if @@cache_template_extensions - (@@cached_template_extension[template_path] ||= {})[template_format] ||= find_template_extension_for(template_path) - else - find_template_extension_for(template_path) - end - end - - def file_exists?(template_path)#:nodoc: - 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 + def render_template(template) #:nodoc: + template.render_template end # Returns true is the file may be rendered implicitly. @@ -413,88 +287,38 @@ If you are rendering a subtemplate, you must now use controller-like partial syn template_path.split('/').last[0,1] != '_' end - # symbolized version of the :format parameter of the request, or :html by default. + # Returns a symbolized version of the :format parameter of the request, + # or :html by default. + # + # EXCEPTION: If the :format parameter is not set, the Accept header will be examined for + # whether it contains the JavaScript mime type as its first priority. If that's the case, + # it will be used. This ensures that Ajax applications can use the same URL to support both + # JavaScript and non-JavaScript users. def template_format return @template_format if @template_format - format = controller && controller.respond_to?(:request) && controller.request.parameters[:format] - @template_format = format.blank? ? :html : format.to_sym - end - # Adds a view_path to the front of the view_paths array. - # This change affects the current request only. - # - # @template.prepend_view_path("views/default") - # @template.prepend_view_path(["views/default", "views/custom"]) - # - def prepend_view_path(path) - @view_paths.unshift(*path) - end - - # Adds a view_path to the end of the view_paths array. - # This change affects the current request only. - # - # @template.append_view_path("views/default") - # @template.append_view_path(["views/default", "views/custom"]) - # - def append_view_path(path) - @view_paths.push(*path) + if controller && controller.respond_to?(:request) + parameter_format = controller.request.parameters[:format] + accept_format = controller.request.accepts.first + + case + when parameter_format.blank? && accept_format != :js + @template_format = :html + when parameter_format.blank? && accept_format == :js + @template_format = :js + else + @template_format = parameter_format.to_sym + end + else + @template_format = :html + end end private - def find_full_template_path(template_path, extension) - file_name = "#{template_path}.#{extension}" - base_path = find_base_path_for(file_name) - base_path.blank? ? "" : "#{base_path}/#{file_name}" - end - - # Asserts the existence of a template. - def template_exists?(template_path, extension) - file_path = full_template_path(template_path, extension) - !file_path.blank? && @@method_names.has_key?(file_path) || File.exist?(file_path) - 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 - - # Returns the view path that contains the given relative template path. - def find_base_path_for(template_file_name) - view_paths.find { |p| File.file?(File.join(p, 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 - - # Determines the template's file extension, such as rhtml, rxml, or rjs. - def find_template_extension_for(template_path) - find_template_extension_from_handler(template_path, true) || - find_template_extension_from_handler(template_path) || - find_template_extension_from_first_render() - end - - def find_template_extension_from_handler(template_path, formatted = nil) - checked_template_path = formatted ? "#{template_path}.#{template_format}" : template_path - - self.class.template_handler_extensions.each do |extension| - if template_exists?(checked_template_path, extension) - return formatted ? "#{template_format}.#{extension}" : extension.to_s - end - end - nil - end - - # Determine the template extension from the @first_render filename - def find_template_extension_from_first_render - File.basename(@first_render.to_s)[/^[^.]+\.(.+)$/, 1] - end - - # This method reads a template file. - def read_template_file(template_path, extension) - File.read(template_path) + 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 } end # Evaluate the local assigns and pushes them to the view. @@ -505,138 +329,15 @@ If you are rendering a subtemplate, you must now use controller-like partial syn end end - def delegate_render(handler, template, local_assigns) - handler.new(self).render(template, local_assigns) - end - - def delegate_compile(handler, template) - handler.new(self).compile(template) - end - - def template_handler_is_compilable?(handler) - handler.new(self).respond_to?(:compile) - end - # Assigns instance variables from the controller to the view. def assign_variables_from_controller @assigns.each { |key, value| instance_variable_set("@#{key}", value) } end - - - # Return true if the given template was compiled for a superset of the keys in local_assigns - def supports_local_assigns?(render_symbol, local_assigns) - local_assigns.empty? || - ((args = @@template_args[render_symbol]) && local_assigns.all? { |k,_| args.has_key?(k) }) - end - - # Method to check whether template compilation is necessary. - # The template will be compiled if the inline template or file has not been compiled yet, - # if local_assigns has a new key, which isn't supported by the compiled code yet, - # or if the file has changed on disk and checking file mods hasn't been disabled. - def compile_template?(template, file_name, local_assigns) - method_key = file_name || template - render_symbol = @@method_names[method_key] - - compile_time = @@compile_time[render_symbol] - if compile_time && supports_local_assigns?(render_symbol, local_assigns) - if file_name && !@@cache_template_loading - template_changed_since?(file_name, compile_time) - end - else - true - end - end - - # Method to handle checking a whether a template has changed since last compile; isolated so that templates - # not stored on the file system can hook and extend appropriately. - def template_changed_since?(file_name, compile_time) - lstat = File.lstat(file_name) - compile_time < lstat.mtime || - (lstat.symlink? && compile_time < File.stat(file_name).mtime) - end - - # Method to create the source code for a given template. - def create_template_source(handler, template, render_symbol, locals) - body = delegate_compile(handler, template) - - @@template_args[render_symbol] ||= {} - locals_keys = @@template_args[render_symbol].keys | locals - @@template_args[render_symbol] = locals_keys.inject({}) { |h, k| h[k] = true; h } - - locals_code = "" - locals_keys.each do |key| - locals_code << "#{key} = local_assigns[:#{key}]\n" - end - - "def #{render_symbol}(local_assigns)\n#{locals_code}#{body}\nend" - end - - def assign_method_name(handler, template, file_name) - method_key = file_name || template - @@method_names[method_key] ||= compiled_method_name(handler, template, file_name) - end - - def compiled_method_name(handler, template, file_name) - ['_run', handler.to_s.demodulize.underscore, compiled_method_name_file_path_segment(file_name)].compact.join('_').to_sym - end - - def compiled_method_name_file_path_segment(file_name) - if file_name - s = File.expand_path(file_name) - s.sub!(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}/, '') if defined?(RAILS_ROOT) - s.gsub!(/([^a-zA-Z0-9_])/) { $1.ord } - s - else - (@@inline_template_count += 1).to_s - end - end - - # Compile and evaluate the template's code - def compile_template(handler, template, file_name, local_assigns) - render_symbol = assign_method_name(handler, template, file_name) - render_source = create_template_source(handler, template, render_symbol, local_assigns.keys) - line_offset = @@template_args[render_symbol].size + handler.line_offset - - begin - file_name = 'compiled-template' if file_name.blank? - CompiledTemplates.module_eval(render_source, file_name, -line_offset) - rescue Exception => e # errors from template code - if logger - logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}" - logger.debug "Function body: #{render_source}" - logger.debug "Backtrace: #{e.backtrace.join("\n")}" - end - - raise TemplateError.new(extract_base_path_from(file_name) || view_paths.first, file_name || template, @assigns, template, e) - end - - @@compile_time[render_symbol] = Time.now - # logger.debug "Compiled template #{file_name || template}\n ==> #{render_symbol}" if logger - end - - # Render the provided template with the given local assigns. If the template has not been rendered with the provided - # local assigns yet, or if the template has been updated on disk, then the template will be compiled to a method. - # - # Either, but not both, of template and file_path may be nil. If file_path is given, the template - # will only be read if it has to be compiled. - # - def compile_and_render_template(handler, template = nil, file_path = nil, local_assigns = {}) #:nodoc: - # convert string keys to symbols if requested - local_assigns = local_assigns.symbolize_keys if @@local_assigns_support_string_keys - - # compile the given template, if necessary - if compile_template?(template, file_path, local_assigns) - template ||= read_template_file(file_path, nil) - compile_template(handler, template, file_path, local_assigns) - end - - # Get the method name for this template and run it - method_name = @@method_names[file_path || template] - evaluate_assigns - - send(method_name, local_assigns) do |*name| - instance_variable_get "@content_for_#{name.first || 'layout'}" - end + + def execute(template) + send(template.method, template.locals) do |*names| + instance_variable_get "@content_for_#{names.first || 'layout'}" + end end end end diff --git a/vendor/rails/actionpack/lib/action_view/helpers/active_record_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/active_record_helper.rb index 9b3292a9..f3f204cc 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/active_record_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/active_record_helper.rb @@ -8,47 +8,55 @@ module ActionView end module Helpers - # The Active Record Helper makes it easier to create forms for records kept in instance variables. The most far-reaching is the form + # The Active Record Helper makes it easier to create forms for records kept in instance variables. The most far-reaching is the +form+ # method that creates a complete form for all the basic content types of the record (not associations or aggregations, though). This # is a great way of making the record quickly available for editing, but likely to prove lackluster for a complicated real-world form. - # In that case, it's better to use the input method and the specialized form methods in link:classes/ActionView/Helpers/FormHelper.html + # In that case, it's better to use the +input+ method and the specialized +form+ methods in link:classes/ActionView/Helpers/FormHelper.html module ActiveRecordHelper - # Returns a default input tag for the type of object returned by the method. For example, let's say you have a model - # that has an attribute +title+ of type VARCHAR column, and this instance holds "Hello World": - # input("post", "title") => - # + # Returns a default input tag for the type of object returned by the method. For example, if @post + # has an attribute +title+ mapped to a +VARCHAR+ column that holds "Hello World": + # + # input("post", "title") + # # => def input(record_name, method, options = {}) InstanceTag.new(record_name, method, self).to_tag(options) end - # Returns an entire form with all needed input tags for a specified Active Record object. For example, let's say you - # have a table model Post with attributes named title of type VARCHAR and body of type TEXT: + # Returns an entire form with all needed input tags for a specified Active Record object. For example, if @post + # has attributes named +title+ of type +VARCHAR+ and +body+ of type +TEXT+ then + # # form("post") - # That line would yield a form like the following: - #
- #

- #
- # - #

- #

- #
- # - #

- # - #
+ # + # would yield a form like the following (modulus formatting): + # + #
+ #

+ #
+ # + #

+ #

+ #
+ # + #

+ # + #
# # It's possible to specialize the form builder by using a different action name and by supplying another - # block renderer. For example, let's say you have a model Entry with an attribute message of type VARCHAR: + # block renderer. For example, if @entry has an attribute +message+ of type +VARCHAR+ then # - # form("entry", :action => "sign", :input_block => - # Proc.new { |record, column| "#{column.human_name}: #{input(record, column.name)}
" }) => + # form("entry", + # :action => "sign", + # :input_block => Proc.new { |record, column| + # "#{column.human_name}: #{input(record, column.name)}
" + # }) # - #
- # Message: - #
- # - #
+ # would yield a form like the following (modulus formatting): + # + #
+ # Message: + #
+ # + #
# # It's also possible to add additional content to the form by giving it a block, such as: # @@ -56,6 +64,14 @@ module ActionView # form << content_tag("b", "Department") # form << collection_select("department", "id", @departments, "id", "name") # end + # + # The following options are available: + # + # * :action - The action used when submitting the form (default: +create+ if a new record, otherwise +update+). + # * :input_block - Specialize the output using a different block, see above. + # * :method - The method used when submitting the form (default: +post+). + # * :multipart - Whether to change the enctype of the form to "multipart/form-data", used when uploading a file (default: +false+). + # * :submit_value - The text of the submit button (default: "Create" if a new record, otherwise "Update"). def form(record_name, options = {}) record = instance_variable_get("@#{record_name}") @@ -65,29 +81,27 @@ module ActionView submit_value = options[:submit_value] || options[:action].gsub(/[^\w]/, '').capitalize - contents = '' + contents = form_tag({:action => action}, :method =>(options[:method] || 'post'), :enctype => options[:multipart] ? 'multipart/form-data': nil) contents << hidden_field(record_name, :id) unless record.new_record? contents << all_input_tags(record, record_name, options) yield contents if block_given? contents << submit_tag(submit_value) - - content_tag('form', contents, :action => action, :method => 'post', :enctype => options[:multipart] ? 'multipart/form-data': nil) + contents << '' end # Returns a string containing the error message attached to the +method+ on the +object+ if one exists. # This error message is wrapped in a DIV tag, which can be extended to include a +prepend_text+ and/or +append_text+ # (to properly explain the error), and a +css_class+ to style it accordingly. +object+ should either be the name of an instance variable or - # the actual object. As an example, let's say you have a model - # +post+ that has an error message on the +title+ attribute: + # the actual object. As an example, let's say you have a model @post that has an error message on the +title+ attribute: # - # <%= error_message_on "post", "title" %> => - #
can't be empty
+ # <%= error_message_on "post", "title" %> + # # =>
can't be empty
# - # <%= error_message_on @post, "title" %> => - #
can't be empty
+ # <%= error_message_on @post, "title" %> + # # =>
can't be empty
# - # <%= error_message_on "post", "title", "Title simply ", " (or it won't work).", "inputError" %> => - #
Title simply can't be empty (or it won't work).
+ # <%= error_message_on "post", "title", "Title simply ", " (or it won't work).", "inputError" %> + # # =>
Title simply can't be empty (or it won't work).
def error_message_on(object, method, prepend_text = "", append_text = "", css_class = "formError") if (obj = (object.respond_to?(:errors) ? object : instance_variable_get("@#{object}"))) && (errors = obj.errors.on(method)) @@ -103,30 +117,37 @@ module ActionView # # This DIV can be tailored by the following options: # - # * header_tag - Used for the header of the error div (default: h2) - # * id - The id of the error div (default: errorExplanation) - # * class - The class of the error div (default: errorExplanation) - # * object - The object (or array of objects) for which to display errors, if you need to escape the instance variable convention - # * object_name - The object name to use in the header, or any text that you prefer. If object_name is not set, the name of the first object will be used. - # * header_message - The message in the header of the error div. Pass +nil+ or an empty string to avoid the header message altogether. (default: X errors prohibited this object from being saved) - # * message - The explanation message after the header message and before the error list. Pass +nil+ or an empty string to avoid the explanation message altogether. (default: There were problems with the following fields:) + # * :header_tag - Used for the header of the error div (default: "h2"). + # * :id - The id of the error div (default: "errorExplanation"). + # * :class - The class of the error div (default: "errorExplanation"). + # * :object - The object (or array of objects) for which to display errors, + # if you need to escape the instance variable convention. + # * :object_name - The object name to use in the header, or any text that you prefer. + # If :object_name is not set, the name of the first object will be used. + # * :header_message - The message in the header of the error div. Pass +nil+ + # or an empty string to avoid the header message altogether. (Default: "X errors + # prohibited this object from being saved"). + # * :message - The explanation message after the header message and before + # the error list. Pass +nil+ or an empty string to avoid the explanation message + # altogether. (Default: "There were problems with the following fields:"). # - # To specify the display for one object, you simply provide its name as a parameter. For example, for the +User+ model: + # To specify the display for one object, you simply provide its name as a parameter. + # For example, for the @user model: # # error_messages_for 'user' # - # To specify more than one object, you simply list them; optionally, you can add an extra +object_name+ parameter, which - # will be the name used in the header message. + # To specify more than one object, you simply list them; optionally, you can add an extra :object_name parameter, which + # will be the name used in the header message: # # error_messages_for 'user_common', 'user', :object_name => 'user' # - # If the objects cannot be located as instance variables, you can add an extra +object+ paremeter which gives the actual - # object (or array of objects to use) + # If the objects cannot be located as instance variables, you can add an extra :object paremeter which gives the actual + # object (or array of objects to use): # # error_messages_for 'user', :object => @question.user # # NOTE: This is a pre-packaged presentation of the errors with embedded strings and a certain HTML structure. If what - # you need is significantly different from the default presentation, it makes plenty of sense to access the object.errors + # you need is significantly different from the default presentation, it makes plenty of sense to access the object.errors # instance yourself and set it up. View the source of this method to see how easy it is. def error_messages_for(*params) options = params.extract_options!.symbolize_keys @@ -149,7 +170,7 @@ module ActionView options[:object_name] ||= params.first options[:header_message] = "#{pluralize(count, 'error')} prohibited this #{options[:object_name].to_s.gsub('_', ' ')} from being saved" unless options.include?(:header_message) options[:message] ||= 'There were problems with the following fields:' unless options.include?(:message) - error_messages = objects.map {|object| object.errors.full_messages.map {|msg| content_tag(:li, msg) } } + error_messages = objects.sum {|object| object.errors.full_messages.map {|msg| content_tag(:li, msg) } }.join contents = '' contents << content_tag(options[:header_tag] || :h2, options[:header_message]) unless options[:header_message].blank? @@ -213,29 +234,29 @@ module ActionView end alias_method :to_date_select_tag_without_error_wrapping, :to_date_select_tag - def to_date_select_tag(options = {}) + def to_date_select_tag(options = {}, html_options = {}) if object.respond_to?("errors") && object.errors.respond_to?("on") - error_wrapping(to_date_select_tag_without_error_wrapping(options), object.errors.on(@method_name)) + error_wrapping(to_date_select_tag_without_error_wrapping(options, html_options), object.errors.on(@method_name)) else - to_date_select_tag_without_error_wrapping(options) + to_date_select_tag_without_error_wrapping(options, html_options) end end alias_method :to_datetime_select_tag_without_error_wrapping, :to_datetime_select_tag - def to_datetime_select_tag(options = {}) + def to_datetime_select_tag(options = {}, html_options = {}) if object.respond_to?("errors") && object.errors.respond_to?("on") - error_wrapping(to_datetime_select_tag_without_error_wrapping(options), object.errors.on(@method_name)) + error_wrapping(to_datetime_select_tag_without_error_wrapping(options, html_options), object.errors.on(@method_name)) else - to_datetime_select_tag_without_error_wrapping(options) + to_datetime_select_tag_without_error_wrapping(options, html_options) end end alias_method :to_time_select_tag_without_error_wrapping, :to_time_select_tag - def to_time_select_tag(options = {}) + def to_time_select_tag(options = {}, html_options = {}) if object.respond_to?("errors") && object.errors.respond_to?("on") - error_wrapping(to_time_select_tag_without_error_wrapping(options), object.errors.on(@method_name)) + error_wrapping(to_time_select_tag_without_error_wrapping(options, html_options), object.errors.on(@method_name)) else - to_time_select_tag_without_error_wrapping(options) + to_time_select_tag_without_error_wrapping(options, html_options) end end diff --git a/vendor/rails/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/asset_tag_helper.rb index ba474a8f..dfc7e2b3 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -17,7 +17,7 @@ module ActionView # ActionController::Base.asset_host = "assets.example.com" # image_tag("rails.png") # => Rails - # stylesheet_include_tag("application") + # stylesheet_link_tag("application") # => # # This is useful since browsers typically open at most two connections to a single host, @@ -28,7 +28,7 @@ module ActionView # # image_tag("rails.png") # => Rails - # stylesheet_include_tag("application") + # stylesheet_link_tag("application") # => # # To do this, you can either setup 4 actual hosts, or you can use wildcard DNS to CNAME @@ -47,11 +47,13 @@ module ActionView # ActionController::Base.asset_host = Proc.new { |source| "http://assets#{rand(2) + 1}.example.com" } # image_tag("rails.png") # => Rails - # stylesheet_include_tag("application") + # stylesheet_link_tag("application") # => # - # The proc takes a single source parameter which is the path of the source asset. This can be used to - # generate a particular asset host depending on the asset path. + # The proc takes a source parameter (which is the path of the source asset) and an optional + # request parameter (which is an entire instance of an ActionController::AbstractRequest + # subclass). This can be used to generate a particular asset host depending on the asset path and the particular + # request. # # ActionController::Base.asset_host = Proc.new { |source| # if source.starts_with?('/images') @@ -62,9 +64,22 @@ module ActionView # } # image_tag("rails.png") # => Rails - # stylesheet_include_tag("application") + # stylesheet_link_tag("application") # => # + # The optional request parameter to the proc is useful in particular for serving assets from an + # SSL-protected page. The example proc below disables asset hosting for HTTPS connections, while still sending + # assets for plain HTTP requests from asset hosts. This is useful for avoiding mixed media warnings when serving + # non-HTTP assets from HTTPS web pages when you don't have an SSL certificate for each of the asset hosts. + # + # ActionController::Base.asset_host = Proc.new { |source, request| + # if request.ssl? + # "#{request.protocol}#{request.host_with_port}" + # else + # "#{request.protocol}assets.example.com" + # end + # } + # # === Using asset timestamps # # By default, Rails will append all asset paths with that asset's timestamp. This allows you to set a cache-expiration date for the @@ -86,7 +101,7 @@ module ActionView # something like Live HTTP Headers for Firefox to verify that the cache is indeed working (and that the assets are not being # requested over and over). module AssetTagHelper - ASSETS_DIR = defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/public" : "public" + ASSETS_DIR = defined?(Rails.public_path) ? Rails.public_path : "public" JAVASCRIPTS_DIR = "#{ASSETS_DIR}/javascripts" STYLESHEETS_DIR = "#{ASSETS_DIR}/stylesheets" @@ -140,7 +155,8 @@ module ActionView alias_method :path_to_javascript, :javascript_path # aliased to avoid conflicts with a javascript_path named route JAVASCRIPT_DEFAULT_SOURCES = ['prototype', 'effects', 'dragdrop', 'controls'] unless const_defined?(:JAVASCRIPT_DEFAULT_SOURCES) - @@javascript_default_sources = JAVASCRIPT_DEFAULT_SOURCES.dup + @@javascript_expansions = { :defaults => JAVASCRIPT_DEFAULT_SOURCES.dup } + @@stylesheet_expansions = {} # Returns an html script tag for each of the +sources+ provided. You # can pass in the filename (.js extension is optional) of javascript files @@ -148,7 +164,7 @@ module ActionView # current page or you can pass the full path relative to your document # root. To include the Prototype and Scriptaculous javascript libraries in # your application, pass :defaults as the source. When using - # :defaults, if an application.js file exists in your public + # :defaults, if an application.js file exists in your public # javascripts directory, it will be included as well. You can modify the # html attributes of the script tag by passing a hash as the last argument. # @@ -217,7 +233,7 @@ module ActionView # # # - # javascript_include_tag "prototype", "cart", "checkout", :cache => "shop" # when ActionController::Base.perform_caching is false => + # javascript_include_tag "prototype", "cart", "checkout", :cache => "shop" # when ActionController::Base.perform_caching is true => # def javascript_include_tag(*sources) options = sources.extract_options!.stringify_keys @@ -234,16 +250,46 @@ module ActionView end end + # Register one or more javascript files to be included when symbol + # is passed to javascript_include_tag. This method is typically intended + # to be called from plugin initialization to register javascript files + # that the plugin installed in public/javascripts. + # + # ActionView::Helpers::AssetTagHelper.register_javascript_expansion :monkey => ["head", "body", "tail"] + # + # javascript_include_tag :monkey # => + # + # + # + def self.register_javascript_expansion(expansions) + @@javascript_expansions.merge!(expansions) + end + + # Register one or more stylesheet files to be included when symbol + # is passed to stylesheet_link_tag. This method is typically intended + # to be called from plugin initialization to register stylesheet files + # that the plugin installed in public/stylesheets. + # + # ActionView::Helpers::AssetTagHelper.register_stylesheet_expansion :monkey => ["head", "body", "tail"] + # + # stylesheet_link_tag :monkey # => + # + # + # + def self.register_stylesheet_expansion(expansions) + @@stylesheet_expansions.merge!(expansions) + end + # Register one or more additional JavaScript files to be included when # javascript_include_tag :defaults is called. This method is # typically intended to be called from plugin initialization to register additional # .js files that the plugin installed in public/javascripts. def self.register_javascript_include_default(*sources) - @@javascript_default_sources.concat(sources) + @@javascript_expansions[:defaults].concat(sources) end def self.reset_javascript_include_default #:nodoc: - @@javascript_default_sources = JAVASCRIPT_DEFAULT_SOURCES.dup + @@javascript_expansions[:defaults] = JAVASCRIPT_DEFAULT_SOURCES.dup end # Computes the path to a stylesheet asset in the public stylesheets directory. @@ -286,7 +332,7 @@ module ActionView # # # - # You can also include all styles in the stylesheet directory using :all as the source: + # You can also include all styles in the stylesheet directory using :all as the source: # # stylesheet_link_tag :all # => # @@ -383,7 +429,7 @@ module ActionView options.symbolize_keys! options[:src] = path_to_image(source) - options[:alt] ||= File.basename(options[:src], '.*').split('.').first.capitalize + options[:alt] ||= File.basename(options[:src], '.*').split('.').first.to_s.capitalize if size = options.delete(:size) options[:width], options[:height] = size.split("x") if size =~ %r{^\d+x\d+$} @@ -428,16 +474,18 @@ module ActionView ActionView::Base.computed_public_paths[cache_key] ||= begin - source += ".#{ext}" if File.extname(source).blank? && ext + source += ".#{ext}" if ext && File.extname(source).blank? || File.exist?(File.join(ASSETS_DIR, dir, "#{source}.#{ext}")) if source =~ %r{^[-a-z]+://} source else source = "/#{dir}/#{source}" unless source[0] == ?/ if has_request - source = "#{@controller.request.relative_url_root}#{source}" + unless source =~ %r{^#{@controller.request.relative_url_root}/} + source = "#{@controller.request.relative_url_root}#{source}" + end end - rewrite_asset_path!(source) + source = rewrite_asset_path(source) if include_host host = compute_asset_host(source) @@ -461,9 +509,14 @@ module ActionView def compute_asset_host(source) if host = ActionController::Base.asset_host if host.is_a?(Proc) - host.call(source) + case host.arity + when 2 + host.call(source, @controller.request) + else + host.call(source) + end else - host % (source.hash % 4) + (host =~ /%d/) ? host % (source.hash % 4) : host end end end @@ -484,11 +537,15 @@ module ActionView end end - # Break out the asset path rewrite so you wish to put the asset id + # Break out the asset path rewrite in case plugins wish to put the asset id # someplace other than the query string. - def rewrite_asset_path!(source) + def rewrite_asset_path(source) asset_id = rails_asset_id(source) - source << "?#{asset_id}" if !asset_id.blank? + if asset_id.blank? + source + else + source + "?#{asset_id}" + end end def javascript_src_tag(source, options) @@ -508,28 +565,34 @@ module ActionView end def expand_javascript_sources(sources) - case - when sources.include?(:all) - all_javascript_files = Dir[File.join(JAVASCRIPTS_DIR, '*.js')].collect { |file| File.basename(file).split(".", 0).first }.sort - sources = ((@@javascript_default_sources.dup & all_javascript_files) + all_javascript_files).uniq - - when sources.include?(:defaults) - sources = sources[0..(sources.index(:defaults))] + - @@javascript_default_sources.dup + - sources[(sources.index(:defaults) + 1)..sources.length] - - sources.delete(:defaults) - sources << "application" if file_exist?(File.join(JAVASCRIPTS_DIR, "application.js")) + if sources.include?(:all) + all_javascript_files = Dir[File.join(JAVASCRIPTS_DIR, '*.js')].collect { |file| File.basename(file).gsub(/\.\w+$/, '') }.sort + @@all_javascript_sources ||= ((determine_source(:defaults, @@javascript_expansions).dup & all_javascript_files) + all_javascript_files).uniq + else + expanded_sources = sources.collect do |source| + determine_source(source, @@javascript_expansions) + end.flatten + expanded_sources << "application" if sources.include?(:defaults) && file_exist?(File.join(JAVASCRIPTS_DIR, "application.js")) + expanded_sources end - - sources end def expand_stylesheet_sources(sources) if sources.first == :all - @@all_stylesheet_sources ||= Dir[File.join(STYLESHEETS_DIR, '*.css')].collect { |file| File.basename(file).split(".", 1).first }.sort + @@all_stylesheet_sources ||= Dir[File.join(STYLESHEETS_DIR, '*.css')].collect { |file| File.basename(file).gsub(/\.\w+$/, '') }.sort else - sources + sources.collect do |source| + determine_source(source, @@stylesheet_expansions) + end.flatten + end + end + + def determine_source(source, collection) + case source + when Symbol + collection[source] || raise(ArgumentError, "No expansion found for #{source.inspect}") + else + source end end diff --git a/vendor/rails/actionpack/lib/action_view/helpers/atom_feed_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/atom_feed_helper.rb index c3ceecbf..ebb1cb34 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/atom_feed_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/atom_feed_helper.rb @@ -42,33 +42,65 @@ module ActionView # end # end # - # The options are for atom_feed are: + # The options for atom_feed are: # # * :language: Defaults to "en-US". # * :root_url: The HTML alternative that this feed is doubling for. Defaults to / on the current host. # * :url: The URL for this feed. Defaults to the current URL. + # * :schema_date: The date at which the tag scheme for the feed was first used. A good default is the year you + # created the feed. See http://feedvalidator.org/docs/error/InvalidTAG.html for more information. If not specified, + # 2005 is used (as an "I don't care" value). # - # atom_feed yields a AtomFeedBuilder instance. + # Other namespaces can be added to the root element: + # + # app/views/posts/index.atom.builder: + # atom_feed({'xmlns:app' => 'http://www.w3.org/2007/app', + # 'xmlns:openSearch' => 'http://a9.com/-/spec/opensearch/1.1/'}) do |feed| + # feed.title("My great blog!") + # feed.updated((@posts.first.created_at)) + # feed.tag!(openSearch:totalResults, 10) + # + # for post in @posts + # feed.entry(post) do |entry| + # entry.title(post.title) + # entry.content(post.body, :type => 'html') + # entry.tag!('app:edited', Time.now) + # + # entry.author do |author| + # author.name("DHH") + # end + # end + # end + # end + # + # + # atom_feed yields an AtomFeedBuilder instance. def atom_feed(options = {}, &block) + if options[:schema_date] + options[:schema_date] = options[:schema_date].strftime("%Y-%m-%d") if options[:schema_date].respond_to?(:strftime) + else + options[:schema_date] = "2005" # The Atom spec copyright date + end + xml = options[:xml] || eval("xml", block.binding) xml.instruct! - xml.feed "xml:lang" => options[:language] || "en-US", "xmlns" => 'http://www.w3.org/2005/Atom' do - xml.id("tag:#{request.host}:#{request.request_uri.split(".")[0].gsub("/", "")}") + feed_opts = {"xml:lang" => options[:language] || "en-US", "xmlns" => 'http://www.w3.org/2005/Atom'} + feed_opts.merge!(options).reject!{|k,v| !k.to_s.match(/^xml/)} + + xml.feed(feed_opts) do + xml.id("tag:#{request.host},#{options[:schema_date]}:#{request.request_uri.split(".")[0]}") xml.link(:rel => 'alternate', :type => 'text/html', :href => options[:root_url] || (request.protocol + request.host_with_port)) - - if options[:url] - xml.link(:rel => 'self', :type => 'application/atom+xml', :href => options[:url] || request.url) - end - - yield AtomFeedBuilder.new(xml, self) + xml.link(:rel => 'self', :type => 'application/atom+xml', :href => options[:url] || request.url) + + yield AtomFeedBuilder.new(xml, self, options) end end class AtomFeedBuilder - def initialize(xml, view) - @xml, @view = xml, view + def initialize(xml, view, feed_options = {}) + @xml, @view, @feed_options = xml, view, feed_options end # Accepts a Date or Time object and inserts it in the proper format. If nil is passed, current time in UTC is used. @@ -80,12 +112,12 @@ module ActionView # # Options: # - # * :updated: Time of update. Defaults to the created_at attribute on the record if one such exists. - # * :published: Time first published. Defaults to the updated_at attribute on the record if one such exists. + # * :published: Time first published. Defaults to the created_at attribute on the record if one such exists. + # * :updated: Time of update. Defaults to the updated_at attribute on the record if one such exists. # * :url: The URL for this entry. Defaults to the polymorphic_url for the record. def entry(record, options = {}) @xml.entry do - @xml.id("tag:#{@view.request.host_with_port}:#{record.class}#{record.id}") + @xml.id("tag:#{@view.request.host},#{@feed_options[:schema_date]}:#{record.class}/#{record.id}") if options[:published] || (record.respond_to?(:created_at) && record.created_at) @xml.published((options[:published] || record.created_at).xmlschema) @@ -102,10 +134,10 @@ module ActionView end private - def method_missing(method, *arguments) - @xml.__send__(method, *arguments) + def method_missing(method, *arguments, &block) + @xml.__send__(method, *arguments, &block) end end end end -end \ No newline at end of file +end diff --git a/vendor/rails/actionpack/lib/action_view/helpers/benchmark_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/benchmark_helper.rb index fefa28f4..743d1d40 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/benchmark_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/benchmark_helper.rb @@ -21,11 +21,13 @@ module ActionView # You may give an optional logger level as the second argument # (:debug, :info, :warn, :error); the default value is :info. def benchmark(message = "Benchmarking", level = :info) - if @logger + if controller.logger real = Benchmark.realtime { yield } - @logger.send level, "#{message} (#{'%.5f' % real})" + controller.logger.send(level, "#{message} (#{'%.5f' % real})") + else + yield end end end end -end +end \ No newline at end of file diff --git a/vendor/rails/actionpack/lib/action_view/helpers/cache_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/cache_helper.rb index cf5420a3..930c3977 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/cache_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/cache_helper.rb @@ -31,8 +31,9 @@ module ActionView # <%= render :partial => "topics", :collection => @topic_list %> # Topics listed alphabetically # <% end %> - def cache(name = {}, &block) - @controller.cache_erb_fragment(block, name) + def cache(name = {}, options = nil, &block) + handler = Template.handler_class_for_extension(current_render_extension.to_sym) + handler.new(@controller).cache_fragment(block, name, options) end end end diff --git a/vendor/rails/actionpack/lib/action_view/helpers/capture_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/capture_helper.rb index fc8cd66d..9ea06568 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/capture_helper.rb @@ -118,8 +118,7 @@ module ActionView # for elements that will be fragment cached. # # The deprecated way of accessing a content_for block is to use an instance variable - # named @content_for_#{name_of_the_content_block}. So <%= content_for :footer %> - # would be available as <%= @content_for_footer %>. The preferred usage is now + # named @content_for_#{name_of_the_content_block}. The preferred usage is now # <%= yield :footer %>. def content_for(name, content = nil, &block) existing_content_for = instance_variable_get("@content_for_#{name}").to_s diff --git a/vendor/rails/actionpack/lib/action_view/helpers/date_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/date_helper.rb index c2091dfd..8a9c8044 100755 --- a/vendor/rails/actionpack/lib/action_view/helpers/date_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/date_helper.rb @@ -1,4 +1,5 @@ require "date" +require 'action_view/helpers/tag_helper' module ActionView module Helpers @@ -11,31 +12,32 @@ module ActionView # * :discard_type - set to true if you want to discard the type part of the select name. If set to true, the select_month # method would use simply "date" (which can be overwritten using :prefix) instead of "date[month]". module DateHelper + include ActionView::Helpers::TagHelper DEFAULT_PREFIX = 'date' unless const_defined?('DEFAULT_PREFIX') # Reports the approximate distance in time between two Time or Date objects or integers as seconds. # Set include_seconds to true if you want more detailed approximations when distance < 1 min, 29 secs - # Distances are reported base on the following table: + # Distances are reported based on the following table: # - # 0 <-> 29 secs # => less than a minute - # 30 secs <-> 1 min, 29 secs # => 1 minute - # 1 min, 30 secs <-> 44 mins, 29 secs # => [2..44] minutes - # 44 mins, 30 secs <-> 89 mins, 29 secs # => about 1 hour - # 89 mins, 29 secs <-> 23 hrs, 59 mins, 29 secs # => about [2..24] hours - # 23 hrs, 59 mins, 29 secs <-> 47 hrs, 59 mins, 29 secs # => 1 day - # 47 hrs, 59 mins, 29 secs <-> 29 days, 23 hrs, 59 mins, 29 secs # => [2..29] days - # 29 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs # => about 1 month - # 59 days, 23 hrs, 59 mins, 30 secs <-> 1 yr minus 1 sec # => [2..12] months - # 1 yr <-> 2 yrs minus 1 secs # => about 1 year - # 2 yrs <-> max time or date # => over [2..X] years + # 0 <-> 29 secs # => less than a minute + # 30 secs <-> 1 min, 29 secs # => 1 minute + # 1 min, 30 secs <-> 44 mins, 29 secs # => [2..44] minutes + # 44 mins, 30 secs <-> 89 mins, 29 secs # => about 1 hour + # 89 mins, 29 secs <-> 23 hrs, 59 mins, 29 secs # => about [2..24] hours + # 23 hrs, 59 mins, 29 secs <-> 47 hrs, 59 mins, 29 secs # => 1 day + # 47 hrs, 59 mins, 29 secs <-> 29 days, 23 hrs, 59 mins, 29 secs # => [2..29] days + # 29 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs # => about 1 month + # 59 days, 23 hrs, 59 mins, 30 secs <-> 1 yr minus 1 sec # => [2..12] months + # 1 yr <-> 2 yrs minus 1 secs # => about 1 year + # 2 yrs <-> max time or date # => over [2..X] years # - # With include_seconds = true and the difference < 1 minute 29 seconds - # 0-4 secs # => less than 5 seconds - # 5-9 secs # => less than 10 seconds - # 10-19 secs # => less than 20 seconds - # 20-39 secs # => half a minute - # 40-59 secs # => less than a minute - # 60-89 secs # => 1 minute + # With include_seconds = true and the difference < 1 minute 29 seconds: + # 0-4 secs # => less than 5 seconds + # 5-9 secs # => less than 10 seconds + # 10-19 secs # => less than 20 seconds + # 20-39 secs # => half a minute + # 40-59 secs # => less than a minute + # 60-89 secs # => 1 minute # # ==== Examples # from_time = Time.now @@ -102,15 +104,17 @@ module ActionView # Returns a set of select tags (one for year, month, and day) pre-selected for accessing a specified date-based attribute (identified by # +method+) on an object assigned to the template (identified by +object+). It's possible to tailor the selects through the +options+ hash, - # which accepts all the keys that each of the individual select builders do (like :use_month_numbers for select_month) as well as a range of + # which accepts all the keys that each of the individual select builders do (like :use_month_numbers for select_month) as well as a range of # discard options. The discard options are :discard_year, :discard_month and :discard_day. Set to true, they'll # drop the respective select. Discarding the month select will also automatically discard the day select. It's also possible to explicitly # set the order of the tags using the :order option with an array of symbols :year, :month and :day in # the desired order. Symbols may be omitted and the respective select is not included. # - # Pass the :default option to set the default date. Use a Time object or a Hash of :year, :month, :day, :hour, :minute, and :second. + # Pass the :default option to set the default date. Use a Time object or a Hash of :year, :month, :day, :hour, :minute, and :second. # - # Passing :disabled => true as part of the +options+ will make elements inaccessible for change. + # Passing :disabled => true as part of the +options+ will make elements inaccessible for change. + # + # If anything is passed in the +html_options+ hash it will be applied to every select tag in the set. # # NOTE: Discarded selects will default to 1. So if no month select is available, January will be assumed. # @@ -148,14 +152,16 @@ module ActionView # # Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that all month # choices are valid. - def date_select(object_name, method, options = {}) - InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_date_select_tag(options) + def date_select(object_name, method, options = {}, html_options = {}) + InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_date_select_tag(options, html_options) end # Returns a set of select tags (one for hour, minute and optionally second) pre-selected for accessing a specified # time-based attribute (identified by +method+) on an object assigned to the template (identified by +object+). # You can include the seconds with :include_seconds. # + # If anything is passed in the html_options hash it will be applied to every select tag in the set. + # # ==== Examples # # Creates a time select tag that, when POSTed, will be stored in the post variable in the sunrise attribute # time_select("post", "sunrise") @@ -181,13 +187,15 @@ module ActionView # # Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that all month # choices are valid. - def time_select(object_name, method, options = {}) - InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_time_select_tag(options) + def time_select(object_name, method, options = {}, html_options = {}) + InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_time_select_tag(options, html_options) end # Returns a set of select tags (one for year, month, day, hour, and minute) pre-selected for accessing a specified datetime-based # attribute (identified by +method+) on an object assigned to the template (identified by +object+). Examples: # + # If anything is passed in the html_options hash it will be applied to every select tag in the set. + # # ==== Examples # # Generates a datetime select that, when POSTed, will be stored in the post variable in the written_on attribute # datetime_select("post", "written_on") @@ -205,8 +213,8 @@ module ActionView # datetime_select("post", "written_on", :discard_type => true) # # The selects are prepared for multi-parameter assignment to an Active Record object. - def datetime_select(object_name, method, options = {}) - InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_datetime_select_tag(options) + def datetime_select(object_name, method, options = {}, html_options = {}) + InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_datetime_select_tag(options, html_options) end # Returns a set of html select-tags (one for year, month, day, hour, and minute) pre-selected with the +datetime+. @@ -215,6 +223,8 @@ module ActionView # will be appended onto the :order passed in. You can also add :date_separator and :time_separator # keys to the +options+ to control visual display of the elements. # + # If anything is passed in the html_options hash it will be applied to every select tag in the set. + # # ==== Examples # my_date_time = Time.now + 4.days # @@ -240,9 +250,9 @@ module ActionView # # prefixed with 'payday' rather than 'date' # select_datetime(my_date_time, :prefix => 'payday') # - def select_datetime(datetime = Time.now, options = {}) + def select_datetime(datetime = Time.current, options = {}, html_options = {}) separator = options[:datetime_separator] || '' - select_date(datetime, options) + separator + select_time(datetime, options) + select_date(datetime, options, html_options) + separator + select_time(datetime, options, html_options) end # Returns a set of html select-tags (one for year, month, and day) pre-selected with the +date+. @@ -250,6 +260,8 @@ module ActionView # symbols :year, :month and :day in the desired order. If you do not supply a Symbol, it # will be appended onto the :order passed in. # + # If anything is passed in the html_options hash it will be applied to every select tag in the set. + # # ==== Examples # my_date = Time.today + 6.days # @@ -271,13 +283,13 @@ module ActionView # # prefixed with 'payday' rather than 'date' # select_datetime(my_date_time, :prefix => 'payday') # - def select_date(date = Date.today, options = {}) + def select_date(date = Date.current, options = {}, html_options = {}) options[:order] ||= [] [:year, :month, :day].each { |o| options[:order].push(o) unless options[:order].include?(o) } select_date = '' options[:order].each do |o| - select_date << self.send("select_#{o}", date, options) + select_date << self.send("select_#{o}", date, options, html_options) end select_date end @@ -286,6 +298,8 @@ module ActionView # You can set :time_separator key to format the output, and # the :include_seconds option to include an input for seconds. # + # If anything is passed in the html_options hash it will be applied to every select tag in the set. + # # ==== Examples # my_time = Time.now + 5.days + 7.hours + 3.minutes + 14.seconds # @@ -307,9 +321,9 @@ module ActionView # # separated by ':' and includes an input for seconds # select_time(my_time, :time_separator => ':', :include_seconds => true) # - def select_time(datetime = Time.now, options = {}) + def select_time(datetime = Time.current, options = {}, html_options = {}) separator = options[:time_separator] || '' - select_hour(datetime, options) + separator + select_minute(datetime, options) + (options[:include_seconds] ? separator + select_second(datetime, options) : '') + select_hour(datetime, options, html_options) + separator + select_minute(datetime, options, html_options) + (options[:include_seconds] ? separator + select_second(datetime, options, html_options) : '') end # Returns a select tag with options for each of the seconds 0 through 59 with the current second selected. @@ -329,7 +343,7 @@ module ActionView # # that is named 'interval' rather than 'second' # select_second(my_time, :field_name => 'interval') # - def select_second(datetime, options = {}) + def select_second(datetime, options = {}, html_options = {}) val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.sec) : '' if options[:use_hidden] options[:include_seconds] ? hidden_html(options[:field_name] || 'second', val, options) : '' @@ -337,11 +351,12 @@ module ActionView second_options = [] 0.upto(59) do |second| second_options << ((val == second) ? - %(\n) : - %(\n) + content_tag(:option, leading_zero_on_single_digits(second), :value => leading_zero_on_single_digits(second), :selected => "selected") : + content_tag(:option, leading_zero_on_single_digits(second), :value => leading_zero_on_single_digits(second)) ) + second_options << "\n" end - select_html(options[:field_name] || 'second', second_options, options) + select_html(options[:field_name] || 'second', second_options.join, options, html_options) end end @@ -363,7 +378,7 @@ module ActionView # # that is named 'stride' rather than 'second' # select_minute(my_time, :field_name => 'stride') # - def select_minute(datetime, options = {}) + def select_minute(datetime, options = {}, html_options = {}) val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.min) : '' if options[:use_hidden] hidden_html(options[:field_name] || 'minute', val, options) @@ -371,11 +386,12 @@ module ActionView minute_options = [] 0.step(59, options[:minute_step] || 1) do |minute| minute_options << ((val == minute) ? - %(\n) : - %(\n) + content_tag(:option, leading_zero_on_single_digits(minute), :value => leading_zero_on_single_digits(minute), :selected => "selected") : + content_tag(:option, leading_zero_on_single_digits(minute), :value => leading_zero_on_single_digits(minute)) ) + minute_options << "\n" end - select_html(options[:field_name] || 'minute', minute_options, options) + select_html(options[:field_name] || 'minute', minute_options.join, options, html_options) end end @@ -396,7 +412,7 @@ module ActionView # # that is named 'stride' rather than 'second' # select_minute(my_time, :field_name => 'stride') # - def select_hour(datetime, options = {}) + def select_hour(datetime, options = {}, html_options = {}) val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.hour) : '' if options[:use_hidden] hidden_html(options[:field_name] || 'hour', val, options) @@ -404,11 +420,12 @@ module ActionView hour_options = [] 0.upto(23) do |hour| hour_options << ((val == hour) ? - %(\n) : - %(\n) + content_tag(:option, leading_zero_on_single_digits(hour), :value => leading_zero_on_single_digits(hour), :selected => "selected") : + content_tag(:option, leading_zero_on_single_digits(hour), :value => leading_zero_on_single_digits(hour)) ) + hour_options << "\n" end - select_html(options[:field_name] || 'hour', hour_options, options) + select_html(options[:field_name] || 'hour', hour_options.join, options, html_options) end end @@ -429,7 +446,7 @@ module ActionView # # that is named 'due' rather than 'day' # select_day(my_time, :field_name => 'due') # - def select_day(date, options = {}) + def select_day(date, options = {}, html_options = {}) val = date ? (date.kind_of?(Fixnum) ? date : date.day) : '' if options[:use_hidden] hidden_html(options[:field_name] || 'day', val, options) @@ -437,11 +454,12 @@ module ActionView day_options = [] 1.upto(31) do |day| day_options << ((val == day) ? - %(\n) : - %(\n) + content_tag(:option, day, :value => day, :selected => "selected") : + content_tag(:option, day, :value => day) ) + day_options << "\n" end - select_html(options[:field_name] || 'day', day_options, options) + select_html(options[:field_name] || 'day', day_options.join, options, html_options) end end @@ -479,7 +497,7 @@ module ActionView # # will use keys like "Januar", "Marts." # select_month(Date.today, :use_month_names => %w(Januar Februar Marts ...)) # - def select_month(date, options = {}) + def select_month(date, options = {}, html_options = {}) val = date ? (date.kind_of?(Fixnum) ? date : date.month) : '' if options[:use_hidden] hidden_html(options[:field_name] || 'month', val, options) @@ -497,11 +515,12 @@ module ActionView end month_options << ((val == month_number) ? - %(\n) : - %(\n) + content_tag(:option, month_name, :value => month_number, :selected => "selected") : + content_tag(:option, month_name, :value => month_number) ) + month_options << "\n" end - select_html(options[:field_name] || 'month', month_options, options) + select_html(options[:field_name] || 'month', month_options.join, options, html_options) end end @@ -527,7 +546,7 @@ module ActionView # # has ascending year values # select_year(2006, :start_year => 2000, :end_year => 2010) # - def select_year(date, options = {}) + def select_year(date, options = {}, html_options = {}) val = date ? (date.kind_of?(Fixnum) ? date : date.year) : '' if options[:use_hidden] hidden_html(options[:field_name] || 'year', val, options) @@ -539,29 +558,31 @@ module ActionView step_val = start_year < end_year ? 1 : -1 start_year.step(end_year, step_val) do |year| year_options << ((val == year) ? - %(\n) : - %(\n) + content_tag(:option, year, :value => year, :selected => "selected") : + content_tag(:option, year, :value => year) ) + year_options << "\n" end - select_html(options[:field_name] || 'year', year_options, options) + select_html(options[:field_name] || 'year', year_options.join, options, html_options) end end private - def select_html(type, html_options, options) + def select_html(type, html_options, options, select_tag_options = {}) name_and_id_from_options(options, type) - select_html = %(\n" + content_tag(:select, select_html, select_options) + "\n" end def hidden_html(type, value, options) name_and_id_from_options(options, type) - hidden_html = %(\n) + hidden_html = tag(:input, :type => "hidden", :id => options[:id], :name => options[:name], :value => value) + "\n" end def name_and_id_from_options(options, type) @@ -577,20 +598,20 @@ module ActionView class InstanceTag #:nodoc: include DateHelper - def to_date_select_tag(options = {}) - date_or_time_select(options.merge(:discard_hour => true)) + def to_date_select_tag(options = {}, html_options = {}) + date_or_time_select(options.merge(:discard_hour => true), html_options) end - def to_time_select_tag(options = {}) - date_or_time_select options.merge(:discard_year => true, :discard_month => true) + def to_time_select_tag(options = {}, html_options = {}) + date_or_time_select(options.merge(:discard_year => true, :discard_month => true), html_options) end - def to_datetime_select_tag(options = {}) - date_or_time_select options + def to_datetime_select_tag(options = {}, html_options = {}) + date_or_time_select(options, html_options) end private - def date_or_time_select(options) + def date_or_time_select(options, html_options = {}) defaults = { :discard_type => true } options = defaults.merge(options) datetime = value(object) @@ -627,7 +648,7 @@ module ActionView # This ensures AR can reconstruct valid dates using ParseDate next if discard[param] && date_or_time_select.empty? - date_or_time_select.insert(0, self.send("select_#{param}", datetime, options_with_prefix(position[param], options.merge(:use_hidden => discard[param])))) + date_or_time_select.insert(0, self.send("select_#{param}", datetime, options_with_prefix(position[param], options.merge(:use_hidden => discard[param])), html_options)) date_or_time_select.insert(0, case param when :hour then (discard[:year] && discard[:day] ? "" : " — ") @@ -654,7 +675,7 @@ module ActionView def default_time_from_options(default) case default when nil - Time.now + Time.current when Date, Time default else @@ -662,26 +683,27 @@ module ActionView default[:min] ||= default[:minute] default[:sec] ||= default[:second] + time = Time.current + [:year, :month, :day, :hour, :min, :sec].each do |key| - default[key] ||= Time.now.send(key) + default[key] ||= time.send(key) end - Time.mktime(default[:year], default[:month], default[:day], - default[:hour], default[:min], default[:sec]) + Time.utc(default[:year], default[:month], default[:day], default[:hour], default[:min], default[:sec]) end end end class FormBuilder - def date_select(method, options = {}) + def date_select(method, options = {}, html_options = {}) @template.date_select(@object_name, method, options.merge(:object => @object)) end - def time_select(method, options = {}) + def time_select(method, options = {}, html_options = {}) @template.time_select(@object_name, method, options.merge(:object => @object)) end - def datetime_select(method, options = {}) + def datetime_select(method, options = {}, html_options = {}) @template.datetime_select(@object_name, method, options.merge(:object => @object)) end end diff --git a/vendor/rails/actionpack/lib/action_view/helpers/form_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/form_helper.rb index 2bfb8966..b8600fe4 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/form_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/form_helper.rb @@ -1,6 +1,7 @@ require 'cgi' require 'action_view/helpers/date_helper' require 'action_view/helpers/tag_helper' +require 'action_view/helpers/form_tag_helper' module ActionView module Helpers @@ -32,6 +33,15 @@ module ActionView # # # + # If you are using a partial for your form fields, you can use this shortcut: + # + # <% form_for :person, @person, :url => { :action => "create" } do |f| %> + # <%= render :partial => f %> + # <%= submit_tag 'Create' %> + # <% end %> + # + # This example will render the people/_form partial, setting a local variable called form which references the yielded FormBuilder. + # # The params object created when this form is submitted would look like: # # {"action"=>"create", "controller"=>"persons", "person"=>{"first_name"=>"William", "last_name"=>"Smith"}} @@ -42,7 +52,7 @@ module ActionView # # If the object name contains square brackets the id for the object will be inserted. For example: # - # <%= text_field "person[]", "name" %> + # <%= text_field "person[]", "name" %> # # ...will generate the following ERb. # @@ -57,6 +67,9 @@ module ActionView # # # + # An index option may also be passed to form_for and fields_for. This automatically applies + # the index to all the nested fields. + # # There are also methods for helping to build form tags in link:classes/ActionView/Helpers/FormOptionsHelper.html, # link:classes/ActionView/Helpers/DateHelper.html, and link:classes/ActionView/Helpers/ActiveRecordHelper.html module FormHelper @@ -64,6 +77,7 @@ module ActionView # values for the fields. # # <% form_for :person, @person, :url => { :action => "update" } do |f| %> + # <%= f.error_messages %> # First name: <%= f.text_field :first_name %> # Last name : <%= f.text_field :last_name %> # Biography : <%= f.text_area :biography %> @@ -73,11 +87,12 @@ module ActionView # Worth noting is that the form_for tag is called in a ERb evaluation block, not an ERb output block. So that's <% %>, # not <%= %>. Also worth noting is that form_for yields a form_builder object, in this example as f, which emulates # the API for the stand-alone FormHelper methods, but without the object name. So instead of text_field :person, :name, - # you get away with f.text_field :name. + # you get away with f.text_field :name. Notice that you can even do <%= f.error_messages %> to display the + # error messsages of the model object in question. # # Even further, the form_for method allows you to more easily escape the instance variable convention. So while the stand-alone # approach would require text_field :person, :name, :object => person - # to work with local variables instead of instance ones, the form_for calls remain the same. You simply declare once with + # to work with local variables instead of instance ones, the form_for calls remain the same. You simply declare once with # :person, person and all subsequent field calls save :person and :object => person. # # Also note that form_for doesn't create an exclusive scope. It's still possible to use both the stand-alone FormHelper methods @@ -93,7 +108,7 @@ module ActionView # Note: This also works for the methods in FormOptionHelper and DateHelper that are designed to work with an object as base, # like FormOptionHelper#collection_select and DateHelper#datetime_select. # - # HTML attributes for the form tag can be given as :html => {...}. For example: + # HTML attributes for the form tag can be given as :html => {...}. For example: # # <% form_for :person, @person, :html => {:id => 'person_form'} do |f| %> # ... @@ -135,7 +150,7 @@ module ActionView # ... # <% end %> # - # And for namespaced routes, like admin_post_url: + # And for namespaced routes, like admin_post_url: # # <% form_for([:admin, @post]) do |f| %> # ... @@ -153,10 +168,17 @@ module ActionView # <%= check_box_tag "person[admin]", @person.company.admin? %> # <% end %> # + # In this case, if you use this: + # + # <%= render :partial => f %> + # + # The rendered template is people/_labelling_form and the local variable referencing the form builder is called labelling_form. + # # In many cases you will want to wrap the above in another helper, so you could do something like the following: # - # def labelled_form_for(name, object, options, &proc) - # form_for(name, object, options.merge(:builder => LabellingFormBuiler), &proc) + # def labelled_form_for(record_or_name_or_array, *args, &proc) + # options = args.extract_options! + # form_for(record_or_name_or_array, *(args << options.merge(:builder => LabellingFormBuilder)), &proc) # end # # If you don't need to attach a form to a model instance, then check out FormTagHelper#form_tag. @@ -316,7 +338,7 @@ module ActionView # hash with +options+. These options will be tagged onto the HTML as an HTML element attribute as in the example # shown. # - # ==== Examples + # ==== Examples # hidden_field(:signup, :pass_confirm) # # => # @@ -383,10 +405,10 @@ module ActionView # is set to 0 which is convenient for boolean values. Since HTTP standards say that unchecked checkboxes don't post anything, # we add a hidden value with the same name as the checkbox as a work around. # - # ==== Examples + # ==== Examples # # Let's say that @post.validated? is 1: # check_box("post", "validated") - # # => + # # => # # # # # Let's say that @puppy.gooddog is "no": @@ -394,8 +416,8 @@ module ActionView # # => # # # - # check_box("eula", "accepted", {}, "yes", "no", :class => 'eula_check') - # # => + # check_box("eula", "accepted", { :class => 'eula_check' }, "yes", "no") + # # => # # # def check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0") @@ -411,27 +433,26 @@ module ActionView # # Let's say that @post.category returns "rails": # radio_button("post", "category", "rails") # radio_button("post", "category", "java") - # # => - # # + # # => + # # # # radio_button("user", "receive_newsletter", "yes") # radio_button("user", "receive_newsletter", "no") - # # => - # # + # # => + # # def radio_button(object_name, method, tag_value, options = {}) InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_radio_button_tag(tag_value, options) end end class InstanceTag #:nodoc: - include Helpers::TagHelper + include Helpers::TagHelper, Helpers::FormTagHelper attr_reader :method_name, :object_name DEFAULT_FIELD_OPTIONS = { "size" => 30 }.freeze unless const_defined?(:DEFAULT_FIELD_OPTIONS) DEFAULT_RADIO_OPTIONS = { }.freeze unless const_defined?(:DEFAULT_RADIO_OPTIONS) DEFAULT_TEXT_AREA_OPTIONS = { "cols" => 40, "rows" => 20 }.freeze unless const_defined?(:DEFAULT_TEXT_AREA_OPTIONS) - DEFAULT_DATE_OPTIONS = { :discard_type => true }.freeze unless const_defined?(:DEFAULT_DATE_OPTIONS) def initialize(object_name, method_name, template_object, local_binding = nil, object = nil) @object_name, @method_name = object_name.to_s.dup, method_name.to_s.dup @@ -447,11 +468,13 @@ module ActionView end def to_label_tag(text = nil, options = {}) + options = options.stringify_keys name_and_id = options.dup add_default_name_and_id(name_and_id) - options["for"] = name_and_id["id"] + options.delete("index") + options["for"] ||= name_and_id["id"] content = (text.blank? ? nil : text.to_s) || method_name.humanize - content_tag("label", content, options) + label_tag(name_and_id["id"], content, options) end def to_input_field_tag(field_type, options = {}) @@ -463,6 +486,7 @@ module ActionView end options["type"] = field_type options["value"] ||= value_before_type_cast(object) unless field_type == "file" + options["value"] &&= html_escape(options["value"]) add_default_name_and_id(options) tag("input", options) end @@ -480,8 +504,8 @@ module ActionView options["checked"] = "checked" if checked pretty_tag_value = tag_value.to_s.gsub(/\s/, "_").gsub(/\W/, "").downcase options["id"] ||= defined?(@auto_index) ? - "#{@object_name}_#{@auto_index}_#{@method_name}_#{pretty_tag_value}" : - "#{@object_name}_#{@method_name}_#{pretty_tag_value}" + "#{tag_id_with_index(@auto_index)}_#{pretty_tag_value}" : + "#{tag_id}_#{pretty_tag_value}" add_default_name_and_id(options) tag("input", options) end @@ -512,15 +536,6 @@ module ActionView tag("input", options) << tag("input", "name" => options["name"], "type" => "hidden", "value" => options['disabled'] && checked ? checked_value : unchecked_value) end - def to_date_tag() - defaults = DEFAULT_DATE_OPTIONS.dup - date = value(object) || Date.today - options = Proc.new { |position| defaults.merge(:prefix => "#{@object_name}[#{@method_name}(#{position}i)]") } - html_day_select(date, options.call(3)) + - html_month_select(date, options.call(2)) + - html_year_select(date, options.call(1)) - end - def to_boolean_select_tag(options = {}) options = options.stringify_keys add_default_name_and_id(options) @@ -599,23 +614,27 @@ module ActionView end def tag_name - "#{@object_name}[#{@method_name}]" + "#{@object_name}[#{sanitized_method_name}]" end def tag_name_with_index(index) - "#{@object_name}[#{index}][#{@method_name}]" + "#{@object_name}[#{index}][#{sanitized_method_name}]" end def tag_id - "#{sanitized_object_name}_#{@method_name}" + "#{sanitized_object_name}_#{sanitized_method_name}" end def tag_id_with_index(index) - "#{sanitized_object_name}_#{index}_#{@method_name}" + "#{sanitized_object_name}_#{index}_#{sanitized_method_name}" end def sanitized_object_name - @object_name.gsub(/[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "") + @sanitized_object_name ||= @object_name.gsub(/[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "") + end + + def sanitized_method_name + @sanitized_method_name ||= @method_name.sub(/\?$/,"") end end @@ -628,12 +647,13 @@ module ActionView def initialize(object_name, object, template, options, proc) @object_name, @object, @template, @options, @proc = object_name, object, template, options, proc + @default_options = @options ? @options.slice(:index) : {} end (field_helpers - %w(label check_box radio_button fields_for)).each do |selector| src = <<-end_src def #{selector}(method, options = {}) - @template.send(#{selector.inspect}, @object_name, method, options.merge(:object => @object)) + @template.send(#{selector.inspect}, @object_name, method, objectify_options(options)) end end_src class_eval src, __FILE__, __LINE__ @@ -652,20 +672,20 @@ module ActionView name = "#{object_name}[#{ActionController::RecordIdentifier.singular_class_name(object)}]" args.unshift(object) end - + @template.fields_for(name, *args, &block) end def label(method, text = nil, options = {}) - @template.label(@object_name, method, text, options.merge(:object => @object)) + @template.label(@object_name, method, text, objectify_options(options)) end def check_box(method, options = {}, checked_value = "1", unchecked_value = "0") - @template.check_box(@object_name, method, options.merge(:object => @object), checked_value, unchecked_value) + @template.check_box(@object_name, method, objectify_options(options), checked_value, unchecked_value) end def radio_button(method, tag_value, options = {}) - @template.radio_button(@object_name, method, tag_value, options.merge(:object => @object)) + @template.radio_button(@object_name, method, tag_value, objectify_options(options)) end def error_message_on(method, prepend_text = "", append_text = "", css_class = "formError") @@ -673,12 +693,17 @@ module ActionView end def error_messages(options = {}) - @template.error_messages_for(@object_name, options.merge(:object => @object)) + @template.error_messages_for(@object_name, objectify_options(options)) end def submit(value = "Save changes", options = {}) @template.submit_tag(value, options.reverse_merge(:id => "#{object_name}_submit")) end + + private + def objectify_options(options) + @default_options.merge(options.merge(:object => @object)) + end end end diff --git a/vendor/rails/actionpack/lib/action_view/helpers/form_options_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/form_options_helper.rb index 0f1d2b02..bf65fe55 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -53,6 +53,21 @@ module ActionView # # # + # + # Like the other form helpers, +select+ can accept an :index option to manually set the ID used in the resulting output. Unlike other helpers, +select+ expects this + # option to be in the +html_options+ parameter. + # + # Example: + # + # select("album[]", "genre", %w[rap rock country], {}, { :index => nil }) + # + # becomes: + # + # module FormOptionsHelper include ERB::Util @@ -78,8 +93,8 @@ module ActionView # This allows the user to submit a form page more than once with the expected results of creating multiple records. # In addition, this allows a single partial to be used to generate form inputs for both edit and create forms. # - # By default, post.person_id is the selected option. Specify :selected => value to use a different selection - # or :selected => nil to leave all options unselected. + # By default, post.person_id is the selected option. Specify :selected => value to use a different selection + # or :selected => nil to leave all options unselected. def select(object, method, choices, options = {}, html_options = {}) InstanceTag.new(object, method, self, nil, options.delete(:object)).to_select_tag(choices, options, html_options) end @@ -131,6 +146,17 @@ module ActionView # to TimeZone. This may be used by users to specify a different time # zone model object. (See #time_zone_options_for_select for more # information.) + # Finally, this method supports a :default option, which selects + # a default TimeZone if the object's time zone is nil. + # + # Examples: + # time_zone_select( "user", "time_zone", nil, :include_blank => true) + # + # time_zone_select( "user", "time_zone", nil, :default => "Pacific Time (US & Canada)" ) + # + # time_zone_select( "user", 'time_zone', TimeZone.us_zones, :default => "Pacific Time (US & Canada)") + # + # time_zone_select( "user", "time_zone", TZInfo::Timezone.all.sort, :model => TZInfo::Timezone) def time_zone_select(object, method, priority_zones = nil, options = {}, html_options = {}) InstanceTag.new(object, method, self, nil, options.delete(:object)).to_time_zone_select_tag(priority_zones, options, html_options) end @@ -385,7 +411,7 @@ module ActionView value = value(object) content_tag("select", add_options( - time_zone_options_for_select(value, priority_zones, options[:model] || TimeZone), + time_zone_options_for_select(value || options[:default], priority_zones, options[:model] || TimeZone), options, value ), html_options ) diff --git a/vendor/rails/actionpack/lib/action_view/helpers/form_tag_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/form_tag_helper.rb index 07746508..922a0662 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -114,6 +114,24 @@ module ActionView tag :input, { "type" => "text", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys) end + # Creates a label field + # + # ==== Options + # * Creates standard HTML attributes for the tag. + # + # ==== Examples + # label_tag 'name' + # # => + # + # label_tag 'name', 'Your name' + # # => + # + # label_tag 'name', nil, :class => 'small_label' + # # => + def label_tag(name, text = nil, options = {}) + content_tag :label, text || name.humanize, { "for" => name }.update(options.stringify_keys) + end + # Creates a hidden form input field used to transmit data that would be lost due to HTTP's statelessness or # data that should be hidden from the user. # @@ -298,9 +316,12 @@ module ActionView # Creates a submit button with the text value as the caption. # # ==== Options - # * :disabled - If set to true, the user will not be able to use this input. + # * :confirm => 'question?' - 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. + # * :disabled - If true, the user will not be able to use this input. # * :disable_with - Value of this parameter will be used as the value for a disabled version - # of the submit button when the form is submitted. + # of the submit button when the form is submitted. # * Any other key creates standard HTML options for the tag. # # ==== Examples @@ -320,8 +341,9 @@ module ActionView # submit_tag nil, :class => "form_submit" # # => # - # submit_tag "Edit", :disable_with => "Editing...", :class => 'edit-button' - # # => + # submit_tag "Edit", :disable_with => "Editing...", :class => "edit-button" + # # => def submit_tag(value = "Save changes", options = {}) options.stringify_keys! @@ -333,10 +355,15 @@ module ActionView "#{options["onclick"]}", "result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit())", "if (result == false) { this.value = this.getAttribute('originalValue'); this.disabled = false }", - "return result", + "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 @@ -352,13 +379,13 @@ module ActionView # image_submit_tag("login.png") # # => # - # image_submit_tag("purchase.png"), :disabled => true + # image_submit_tag("purchase.png", :disabled => true) # # => # - # image_submit_tag("search.png"), :class => 'search-button' + # image_submit_tag("search.png", :class => 'search-button') # # => # - # image_submit_tag("agree.png"), :disabled => true, :class => "agree-disagree-button" + # image_submit_tag("agree.png", :disabled => true, :class => "agree-disagree-button") # # => def image_submit_tag(source, options = {}) tag :input, { "type" => "image", "src" => path_to_image(source) }.update(options.stringify_keys) diff --git a/vendor/rails/actionpack/lib/action_view/helpers/javascripts/controls.js b/vendor/rails/actionpack/lib/action_view/helpers/javascripts/controls.js index fbc4418b..5aaf0bb2 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/javascripts/controls.js +++ b/vendor/rails/actionpack/lib/action_view/helpers/javascripts/controls.js @@ -1,4 +1,4 @@ -// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) // (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan) // (c) 2005-2007 Jon Tirsen (http://www.tirsen.com) // Contributors: diff --git a/vendor/rails/actionpack/lib/action_view/helpers/javascripts/dragdrop.js b/vendor/rails/actionpack/lib/action_view/helpers/javascripts/dragdrop.js index ccf4a1e4..bf5cfea6 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/javascripts/dragdrop.js +++ b/vendor/rails/actionpack/lib/action_view/helpers/javascripts/dragdrop.js @@ -1,4 +1,4 @@ -// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) // (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz) // // script.aculo.us is freely distributable under the terms of an MIT-style license. diff --git a/vendor/rails/actionpack/lib/action_view/helpers/javascripts/effects.js b/vendor/rails/actionpack/lib/action_view/helpers/javascripts/effects.js index 65aed239..f030b5db 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/javascripts/effects.js +++ b/vendor/rails/actionpack/lib/action_view/helpers/javascripts/effects.js @@ -1,4 +1,4 @@ -// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) // Contributors: // Justin Palmer (http://encytemedia.com/) // Mark Pilgrim (http://diveintomark.org/) diff --git a/vendor/rails/actionpack/lib/action_view/helpers/number_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/number_helper.rb index eae230ad..120bb4cc 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/number_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/number_helper.rb @@ -54,6 +54,10 @@ module ActionView # * :unit - Sets the denomination of the currency (defaults to "$"). # * :separator - Sets the separator between the units (defaults to "."). # * :delimiter - Sets the thousands delimiter (defaults to ","). + # * :format - Sets the format of the output string (defaults to "%u%n"). The field types are: + # + # %u The currency unit + # %n The number # # ==== Examples # number_to_currency(1234567890.50) # => $1,234,567,890.50 @@ -62,16 +66,19 @@ module ActionView # # number_to_currency(1234567890.50, :unit => "£", :separator => ",", :delimiter => "") # # => £1234567890,50 + # number_to_currency(1234567890.50, :unit => "£", :separator => ",", :delimiter => "", :format => "%n %u") + # # => 1234567890,50 £ def number_to_currency(number, options = {}) options = options.stringify_keys precision = options["precision"] || 2 unit = options["unit"] || "$" separator = precision > 0 ? options["separator"] || "." : "" delimiter = options["delimiter"] || "," + format = options["format"] || "%u%n" begin parts = number_with_precision(number, precision).split('.') - unit + number_with_delimiter(parts[0], delimiter) + separator + parts[1].to_s + format.gsub(/%n/, number_with_delimiter(parts[0], delimiter) + separator + parts[1].to_s).gsub(/%u/, unit) rescue number end @@ -137,11 +144,11 @@ module ActionView # # ==== Examples # number_with_precision(111.2345) # => 111.235 - # number_with_precision(111.2345, 2) # => 111.24 + # number_with_precision(111.2345, 2) # => 111.23 # number_with_precision(13, 5) # => 13.00000 # number_with_precision(389.32314, 0) # => 389 def number_with_precision(number, precision=3) - "%01.#{precision}f" % number + "%01.#{precision}f" % ((Float(number) * (10 ** precision)).round.to_f / 10 ** precision) rescue number end @@ -170,7 +177,7 @@ module ActionView when size < 1.gigabyte; "%.#{precision}f MB" % (size / 1.0.megabyte) when size < 1.terabyte; "%.#{precision}f GB" % (size / 1.0.gigabyte) else "%.#{precision}f TB" % (size / 1.0.terabyte) - end.sub(/([0-9])\.?0+ /, '\1 ' ) + end.sub(/([0-9]\.\d*?)0+ /, '\1 ' ).sub(/\. /,' ') rescue nil end diff --git a/vendor/rails/actionpack/lib/action_view/helpers/prototype_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/prototype_helper.rb index 0435f5c4..1b12aa80 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -255,10 +255,10 @@ module ActionView link_to_function(name, remote_function(options), html_options || options.delete(:html)) end - # Periodically calls the specified url (options[:url]) every + # Periodically calls the specified url (options[:url]) every # options[:frequency] seconds (default is 10). Usually used to - # update a specified div (options[:update]) with the results - # of the remote call. The options for specifying the target with :url + # update a specified div (options[:update]) with the results + # of the remote call. The options for specifying the target with :url # and defining callbacks is the same as link_to_remote. # Examples: # # Call get_averages and put its results in 'avg' every 10 seconds @@ -291,11 +291,11 @@ module ActionView # though it's using JavaScript to serialize the form elements, the form # submission will work just like a regular submission as viewed by the # receiving side (all elements available in params). The options for - # specifying the target with :url and defining callbacks is the same as - # link_to_remote. + # specifying the target with :url and defining callbacks is the same as + # +link_to_remote+. # # A "fall-through" target for browsers that doesn't do JavaScript can be - # specified with the :action/:method options on :html. + # specified with the :action/:method options on :html. # # Example: # # Generates: @@ -304,11 +304,11 @@ module ActionView # form_remote_tag :html => { :action => # url_for(:controller => "some", :action => "place") } # - # The Hash passed to the :html key is equivalent to the options (2nd) + # The Hash passed to the :html key is equivalent to the options (2nd) # argument in the FormTagHelper.form_tag method. # # By default the fall-through action is the same as the one specified in - # the :url (and the default method is :post). + # the :url (and the default method is :post). # # form_remote_tag also takes a block, like form_tag: # # Generates: @@ -422,8 +422,8 @@ module ActionView end # Returns 'eval(request.responseText)' which is the JavaScript function - # that form_remote_tag can call in :complete to evaluate a multiple - # update return document using update_element_function calls. + # that +form_remote_tag+ can call in :complete to evaluate a multiple + # update return document using +update_element_function+ calls. def evaluate_remote_response "eval(request.responseText)" end @@ -631,6 +631,27 @@ module ActionView # render(:update) { |page| page.update_time } # end # + # Calls to JavaScriptGenerator not matching a helper method below + # generate a proxy to the JavaScript Class named by the method called. + # + # Examples: + # + # # Generates: + # # Foo.init(); + # update_page do |page| + # page.foo.init + # end + # + # # Generates: + # # Event.observe('one', 'click', function () { + # # $('two').show(); + # # }); + # update_page do |page| + # page.event.observe('one', 'click') do |p| + # p[:two].show + # end + # end + # # You can also use PrototypeHelper#update_page_tag instead of # PrototypeHelper#update_page to wrap the generated JavaScript in a # " elsif encode == "hex" @@ -403,12 +402,9 @@ module ActionView protocol = 'mailto:' protocol.each_byte { |c| string << sprintf("&#%d;", c) } - for i in 0...email_address.length - if email_address[i,1] =~ /\w/ - string << sprintf("%%%x",email_address[i]) - else - string << email_address[i,1] - end + email_address.each_byte do |c| + char = c.chr + string << (char =~ /\w/ ? sprintf("%%%x", c) : char) end content_tag "a", name || email_address_encoded, html_options.merge({ "href" => "#{string}#{extras}" }) else diff --git a/vendor/rails/actionpack/lib/action_view/inline_template.rb b/vendor/rails/actionpack/lib/action_view/inline_template.rb new file mode 100644 index 00000000..87c012d1 --- /dev/null +++ b/vendor/rails/actionpack/lib/action_view/inline_template.rb @@ -0,0 +1,20 @@ +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/vendor/rails/actionpack/lib/action_view/partial_template.rb b/vendor/rails/actionpack/lib/action_view/partial_template.rb new file mode 100644 index 00000000..1fb3aaee --- /dev/null +++ b/vendor/rails/actionpack/lib/action_view/partial_template.rb @@ -0,0 +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) + 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 + + # Prepare early. This is a performance optimization for partial collections + prepare! + end + + def render + ActionController::Base.benchmark("Rendered #{@path}", 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.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 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 + end + end + + def initialize_counter + @counter_name ||= "#{@variable_name}_counter".to_sym + @locals[@counter_name] = 0 + end + + end +end diff --git a/vendor/rails/actionpack/lib/action_view/partials.rb b/vendor/rails/actionpack/lib/action_view/partials.rb index 0795b8ec..6b294be6 100644 --- a/vendor/rails/actionpack/lib/action_view/partials.rb +++ b/vendor/rails/actionpack/lib/action_view/partials.rb @@ -100,101 +100,59 @@ module ActionView # Title: <%= chief.name %> # # - # As you can see, the :locals hash is shared between both the partial and its layout. + # As you can see, the :locals hash is shared between both the partial and its layout. module Partials private - def render_partial(partial_path, object_assigns = nil, local_assigns = nil) #:nodoc: + def render_partial(partial_path, object_assigns = nil, local_assigns = {}) #:nodoc: case partial_path when String, Symbol, NilClass - path, partial_name = partial_pieces(partial_path) - object = extracting_object(partial_name, object_assigns) - local_assigns = local_assigns ? local_assigns.clone : {} - add_counter_to_local_assigns!(partial_name, local_assigns) - add_object_to_local_assigns!(partial_name, local_assigns, object) - - if logger && logger.debug? - ActionController::Base.benchmark("Rendered #{path}/_#{partial_name}", Logger::DEBUG, false) do - render("#{path}/_#{partial_name}", local_assigns) - end - else - render("#{path}/_#{partial_name}", local_assigns) - end - when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::Associations::HasManyThroughAssociation + # Render the template + ActionView::PartialTemplate.new(self, partial_path, object_assigns, local_assigns).render_template + when ActionView::Helpers::FormBuilder + builder_partial_path = partial_path.class.to_s.demodulize.underscore.sub(/_builder$/, '') + render_partial(builder_partial_path, object_assigns, (local_assigns || {}).merge(builder_partial_path.to_sym => partial_path)) + when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope if partial_path.any? - path = ActionController::RecordIdentifier.partial_path(partial_path.first) collection = partial_path - render_partial_collection(path, collection, nil, object_assigns.value) + render_partial_collection(nil, collection, nil, local_assigns) else "" end else - render_partial( - ActionController::RecordIdentifier.partial_path(partial_path), - object_assigns, local_assigns) + render_partial(ActionController::RecordIdentifier.partial_path(partial_path, controller.class.controller_path), partial_path, local_assigns) end end - def render_partial_collection(partial_name, collection, partial_spacer_template = nil, local_assigns = nil) #:nodoc: - collection_of_partials = Array.new - counter_name = partial_counter_name(partial_name) + def render_partial_collection(partial_path, collection, partial_spacer_template = nil, local_assigns = {}) #:nodoc: + return " " if collection.empty? + local_assigns = local_assigns ? local_assigns.clone : {} - collection.each_with_index do |element, counter| - local_assigns[counter_name] = counter - collection_of_partials.push(render_partial(partial_name, element, local_assigns)) - end + spacer = partial_spacer_template ? render(:partial => partial_spacer_template) : '' - return " " if collection_of_partials.empty? - - if partial_spacer_template - spacer_path, spacer_name = partial_pieces(partial_spacer_template) - collection_of_partials.join(render("#{spacer_path}/_#{spacer_name}")) + if partial_path.nil? + render_partial_collection_with_unknown_partial_path(collection, local_assigns) else - collection_of_partials.join + render_partial_collection_with_known_partial_path(collection, partial_path, local_assigns) + end.join(spacer) + end + + def render_partial_collection_with_known_partial_path(collection, partial_path, local_assigns) + template = ActionView::PartialTemplate.new(self, partial_path, nil, local_assigns) + collection.map do |element| + template.render_member(element) end end - alias_method :render_collection_of_partials, :render_partial_collection - - def partial_pieces(partial_path) - if partial_path.include?('/') - return File.dirname(partial_path), File.basename(partial_path) - else - return controller.class.controller_path, partial_path + def render_partial_collection_with_unknown_partial_path(collection, local_assigns) + templates = Hash.new + i = 0 + collection.map do |element| + partial_path = ActionController::RecordIdentifier.partial_path(element, controller.class.controller_path) + template = templates[partial_path] ||= ActionView::PartialTemplate.new(self, partial_path, nil, local_assigns) + template.counter = i + i += 1 + template.render_member(element) end end - - def partial_counter_name(partial_name) - "#{partial_variable_name(partial_name)}_counter".intern - end - - def partial_variable_name(partial_name) - partial_name.split('/').last.split('.').first.intern - end - - def extracting_object(partial_name, object_assigns) - variable_name = partial_variable_name(partial_name) - if object_assigns.nil? - controller.instance_variable_get("@#{variable_name}") - else - object_assigns - end - end - - def add_counter_to_local_assigns!(partial_name, local_assigns) - counter_name = partial_counter_name(partial_name) - local_assigns[counter_name] = 1 unless local_assigns.has_key?(counter_name) - end - - def add_object_to_local_assigns!(partial_name, local_assigns, object) - variable_name = partial_variable_name(partial_name) - - local_assigns[:object] ||= - local_assigns[variable_name] ||= - if object.is_a?(ActionView::Base::ObjectWrapper) - object.value - else - object - end || controller.instance_variable_get("@#{variable_name}") - end end end diff --git a/vendor/rails/actionpack/lib/action_view/template.rb b/vendor/rails/actionpack/lib/action_view/template.rb new file mode 100644 index 00000000..2cda3d94 --- /dev/null +++ b/vendor/rails/actionpack/lib/action_view/template.rb @@ -0,0 +1,127 @@ +module ActionView #:nodoc: + class Template #:nodoc: + + attr_accessor :locals + attr_reader :handler, :path, :extension, :filename, :path_without_extension, :method + + def initialize(view, path, use_full_path, locals = {}) + @view = view + @finder = @view.finder + + # Clear the forward slash at the beginning if exists + @path = use_full_path ? path.sub(/^\//, '') : path + @view.first_render ||= @path + @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 + + def render_template + render + rescue Exception => e + raise e unless filename + if TemplateError === e + e.sub_template_of(filename) + raise e + else + raise TemplateError.new(self, @view.assigns, e) + end + end + + def render + prepare! + @handler.render(self) + end + + def source + @source ||= File.read(self.filename) + end + + def method_key + @filename + end + + def base_path_for_exception + @finder.find_base_path_for("#{@path_without_extension}.#{@extension}") || @finder.view_paths.first + 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 + end + 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) + 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 + 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 + + # TODO: Depreciate old template extensions + register_template_handler :rhtml, TemplateHandlers::ERB + register_template_handler :rxml, TemplateHandlers::Builder + + end +end diff --git a/vendor/rails/actionpack/lib/action_view/template_error.rb b/vendor/rails/actionpack/lib/action_view/template_error.rb index 01b4b155..65d80362 100644 --- a/vendor/rails/actionpack/lib/action_view/template_error.rb +++ b/vendor/rails/actionpack/lib/action_view/template_error.rb @@ -6,10 +6,11 @@ module ActionView attr_reader :original_exception - def initialize(base_path, file_path, assigns, source, original_exception) - @base_path, @assigns, @source, @original_exception = - base_path, assigns.dup, source, original_exception - @file_path = file_path + def initialize(template, assigns, original_exception) + @base_path = template.base_path_for_exception + @assigns, @source, @original_exception = assigns.dup, template.source, original_exception + @file_path = template.filename + @backtrace = compute_backtrace end def message @@ -40,8 +41,9 @@ module ActionView indent = ' ' * indentation line_counter = start_on_line - - source_code[start_on_line..end_on_line].sum do |line| + return unless source_code = source_code[start_on_line..end_on_line] + + source_code.sum do |line| line_counter += 1 "#{indent}#{line_counter}: #{line}" end @@ -72,14 +74,20 @@ module ActionView "#{source_extract}\n #{clean_backtrace.join("\n ")}\n\n" end + # don't do anything nontrivial here. Any raised exception from here becomes fatal + # (and can't be rescued). def backtrace - [ - "#{source_location.capitalize}\n\n#{source_extract(4)}\n " + - clean_backtrace.join("\n ") - ] + @backtrace end private + def compute_backtrace + [ + "#{source_location.capitalize}\n\n#{source_extract(4)}\n " + + clean_backtrace.join("\n ") + ] + end + def strip_base_path(path) stripped_path = File.expand_path(path).gsub(@base_path, "") stripped_path.gsub!(/^#{Regexp.escape File.expand_path(RAILS_ROOT)}/, '') if defined?(RAILS_ROOT) diff --git a/vendor/rails/actionpack/lib/action_view/template_finder.rb b/vendor/rails/actionpack/lib/action_view/template_finder.rb new file mode 100644 index 00000000..83b7e27c --- /dev/null +++ b/vendor/rails/actionpack/lib/action_view/template_finder.rb @@ -0,0 +1,177 @@ +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 @first_render 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/vendor/rails/actionpack/lib/action_view/template_handler.rb b/vendor/rails/actionpack/lib/action_view/template_handler.rb index b9f4330a..ec407e3f 100644 --- a/vendor/rails/actionpack/lib/action_view/template_handler.rb +++ b/vendor/rails/actionpack/lib/action_view/template_handler.rb @@ -1,17 +1,34 @@ module ActionView class TemplateHandler + def self.line_offset 0 end + def self.compilable? + false + end + def initialize(view) @view = view end - def render(template, local_assigns) + def render(template) end def compile(template) end + + def compilable? + self.class.compilable? + end + + def line_offset + self.class.line_offset + end + + # Called by CacheHelper#cache + def cache_fragment(block, name = {}, options = nil) + end end end diff --git a/vendor/rails/actionpack/lib/action_view/template_handlers/builder.rb b/vendor/rails/actionpack/lib/action_view/template_handlers/builder.rb index 0f49d6ab..f76d8977 100644 --- a/vendor/rails/actionpack/lib/action_view/template_handlers/builder.rb +++ b/vendor/rails/actionpack/lib/action_view/template_handlers/builder.rb @@ -3,6 +3,8 @@ require 'builder' module ActionView module TemplateHandlers class Builder < TemplateHandler + include Compilable + def self.line_offset 2 end @@ -10,10 +12,16 @@ 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 + + "xml = ::Builder::XmlMarkup.new(:indent => 2)\n" + + template.source + "\nxml.target!\n" end + + def cache_fragment(block, name = {}, options = nil) + @view.fragment_for(block, name, options) do + eval('xml.target!', block.binding) + end + end end end end diff --git a/vendor/rails/actionpack/lib/action_view/template_handlers/compilable.rb b/vendor/rails/actionpack/lib/action_view/template_handlers/compilable.rb new file mode 100644 index 00000000..25bd0fea --- /dev/null +++ b/vendor/rails/actionpack/lib/action_view/template_handlers/compilable.rb @@ -0,0 +1,128 @@ +module ActionView + module TemplateHandlers + module Compilable + + def self.included(base) + base.extend ClassMethod + + # Map method names to their compile time + base.cattr_accessor :compile_time + base.compile_time = {} + + # Map method names to the names passed in local assigns so far + base.cattr_accessor :template_args + base.template_args = {} + + # Count the number of inline templates + base.cattr_accessor :inline_template_count + base.inline_template_count = 0 + end + + module ClassMethod + # If a handler is mixin this module, set compilable to true + def compilable? + true + end + end + + def render(template) + @view.send :execute, template + end + + # Compile and evaluate the template's code + def compile_template(template) + return unless compile_template?(template) + + render_symbol = assign_method_name(template) + render_source = create_template_source(template, render_symbol) + line_offset = self.template_args[render_symbol].size + self.line_offset + + begin + file_name = template.filename || 'compiled-template' + ActionView::Base::CompiledTemplates.module_eval(render_source, file_name, -line_offset) + rescue Exception => e # errors from template code + if @view.logger + @view.logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}" + @view.logger.debug "Function body: #{render_source}" + @view.logger.debug "Backtrace: #{e.backtrace.join("\n")}" + end + + raise ActionView::TemplateError.new(template, @view.assigns, e) + end + + self.compile_time[render_symbol] = Time.now + # logger.debug "Compiled template #{file_name || template}\n ==> #{render_symbol}" if logger + end + + private + + # Method to check whether template compilation is necessary. + # The template will be compiled if the inline template or file has not been compiled yet, + # if local_assigns has a new key, which isn't supported by the compiled code yet, + # or if the file has changed on disk and checking file mods hasn't been disabled. + def compile_template?(template) + method_key = template.method_key + render_symbol = @view.method_names[method_key] + + compile_time = self.compile_time[render_symbol] + if compile_time && supports_local_assigns?(render_symbol, template.locals) + if template.filename && !@view.cache_template_loading + template_changed_since?(template.filename, compile_time) + end + else + true + end + end + + def assign_method_name(template) + @view.method_names[template.method_key] ||= compiled_method_name(template) + end + + def compiled_method_name(template) + ['_run', self.class.to_s.demodulize.underscore, compiled_method_name_file_path_segment(template.filename)].compact.join('_').to_sym + end + + def compiled_method_name_file_path_segment(file_name) + if file_name + s = File.expand_path(file_name) + s.sub!(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}/, '') if defined?(RAILS_ROOT) + s.gsub!(/([^a-zA-Z0-9_])/) { $1.ord } + s + else + (self.inline_template_count += 1).to_s + end + end + + # Method to create the source code for a given template. + def create_template_source(template, render_symbol) + body = compile(template) + + self.template_args[render_symbol] ||= {} + locals_keys = self.template_args[render_symbol].keys | template.locals.keys + self.template_args[render_symbol] = locals_keys.inject({}) { |h, k| h[k] = true; h } + + locals_code = "" + locals_keys.each do |key| + locals_code << "#{key} = local_assigns[:#{key}]\n" + end + + "def #{render_symbol}(local_assigns)\n#{locals_code}#{body}\nend" + end + + # Return true if the given template was compiled for a superset of the keys in local_assigns + def supports_local_assigns?(render_symbol, local_assigns) + local_assigns.empty? || + ((args = self.template_args[render_symbol]) && local_assigns.all? { |k,_| args.has_key?(k) }) + end + + # Method to handle checking a whether a template has changed since last compile; isolated so that templates + # not stored on the file system can hook and extend appropriately. + def template_changed_since?(file_name, compile_time) + lstat = File.lstat(file_name) + compile_time < lstat.mtime || + (lstat.symlink? && compile_time < File.stat(file_name).mtime) + end + + end + end +end \ No newline at end of file diff --git a/vendor/rails/actionpack/lib/action_view/template_handlers/erb.rb b/vendor/rails/actionpack/lib/action_view/template_handlers/erb.rb index 022fc362..15a90644 100644 --- a/vendor/rails/actionpack/lib/action_view/template_handlers/erb.rb +++ b/vendor/rails/actionpack/lib/action_view/template_handlers/erb.rb @@ -2,19 +2,54 @@ require 'erb' class ERB module Util - HTML_ESCAPE = { '&' => '&', '"' => '"', '>' => '>', '<' => '<' } + HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"' } + JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003E', '<' => '\u003C' } + # A utility method for escaping HTML tag characters. + # This method is also aliased as h. + # + # In your ERb templates, use this method to escape any unsafe content. For example: + # <%=h @person.name %> + # + # ==== Example: + # puts html_escape("is a > 0 & a < 10?") + # # => is a > 0 & a < 10? def html_escape(s) s.to_s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] } end + + # A utility method for escaping HTML entities in JSON strings. + # This method is also aliased as j. + # + # In your ERb templates, use this method to escape any HTML entities: + # <%=j @person.to_json %> + # + # ==== Example: + # puts json_escape("is a > 0 & a < 10?") + # # => is a \u003E 0 \u0026 a \u003C 10? + def json_escape(s) + s.to_s.gsub(/[&"><]/) { |special| JSON_ESCAPE[special] } + end + + alias j json_escape + module_function :j + module_function :json_escape end end module ActionView module TemplateHandlers class ERB < TemplateHandler + include Compilable + def compile(template) - ::ERB.new(template, nil, @view.erb_trim_mode).src + ::ERB.new(template.source, nil, @view.erb_trim_mode).src + end + + def cache_fragment(block, name = {}, options = nil) #:nodoc: + @view.fragment_for(block, name, options) do + eval(ActionView::Base.erb_variable, block.binding) + end end end end diff --git a/vendor/rails/actionpack/lib/action_view/template_handlers/rjs.rb b/vendor/rails/actionpack/lib/action_view/template_handlers/rjs.rb index 4ca9fc32..5854e33f 100644 --- a/vendor/rails/actionpack/lib/action_view/template_handlers/rjs.rb +++ b/vendor/rails/actionpack/lib/action_view/template_handlers/rjs.rb @@ -1,13 +1,26 @@ module ActionView module TemplateHandlers class RJS < TemplateHandler + include Compilable + def self.line_offset 2 end def compile(template) "controller.response.content_type ||= Mime::JS\n" + - "update_page do |page|\n#{template}\nend" + "update_page do |page|\n#{template.source}\nend" + end + + def cache_fragment(block, name = {}, options = nil) #:nodoc: + @view.fragment_for(block, name, options) do + begin + debug_mode, ActionView::Base.debug_rjs = ActionView::Base.debug_rjs, false + eval('page.to_s', block.binding) + ensure + ActionView::Base.debug_rjs = debug_mode + end + end end end end diff --git a/vendor/rails/actionpack/lib/action_view/test_case.rb b/vendor/rails/actionpack/lib/action_view/test_case.rb new file mode 100644 index 00000000..b2e6589d --- /dev/null +++ b/vendor/rails/actionpack/lib/action_view/test_case.rb @@ -0,0 +1,64 @@ +require 'active_support/test_case' + +module ActionView + class NonInferrableHelperError < ActionViewError + def initialize(name) + super "Unable to determine the helper to test from #{name}. " + + "You'll need to specify it using tests YourHelper in your " + + "test case definition" + end + end + + class TestCase < ActiveSupport::TestCase + class_inheritable_accessor :helper_class + @@helper_class = nil + + class << self + def tests(helper_class) + self.helper_class = helper_class + end + + def helper_class + if current_helper_class = read_inheritable_attribute(:helper_class) + current_helper_class + else + self.helper_class = determine_default_helper_class(name) + end + end + + def determine_default_helper_class(name) + name.sub(/Test$/, '').constantize + rescue NameError + raise NonInferrableHelperError.new(name) + end + end + + ActionView::Base.helper_modules.each do |helper_module| + include helper_module + end + include ActionController::PolymorphicRoutes + include ActionController::RecordIdentifier + + setup :setup_with_helper_class + + def setup_with_helper_class + self.class.send(:include, helper_class) + end + + class TestController < ActionController::Base + attr_accessor :request, :response + + def initialize + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + end + + private + def method_missing(selector, *args) + controller = TestController.new + return controller.send!(selector, *args) if ActionController::Routing::Routes.named_routes.helpers.include?(selector) + super + end + end +end diff --git a/vendor/rails/actionpack/test/abstract_unit.rb b/vendor/rails/actionpack/test/abstract_unit.rb index 700bc1f5..fa1c3293 100644 --- a/vendor/rails/actionpack/test/abstract_unit.rb +++ b/vendor/rails/actionpack/test/abstract_unit.rb @@ -8,6 +8,7 @@ require 'test/unit' require 'action_controller' require 'action_controller/cgi_ext' require 'action_controller/test_process' +require 'action_view/test_case' begin require 'ruby-debug' @@ -19,7 +20,6 @@ end ActiveSupport::Deprecation.debug = true ActionController::Base.logger = nil -ActionController::Base.ignore_missing_templates = false ActionController::Routing::Routes.reload rescue nil diff --git a/vendor/rails/actionpack/test/action_view_test.rb b/vendor/rails/actionpack/test/action_view_test.rb deleted file mode 100644 index a69ff36f..00000000 --- a/vendor/rails/actionpack/test/action_view_test.rb +++ /dev/null @@ -1,44 +0,0 @@ -require File.dirname(__FILE__) + '/abstract_unit' -require 'test/unit' - -class ActionViewTests < Test::Unit::TestCase - def test_find_template_extension_from_first_render - base = ActionView::Base.new - - assert_nil base.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| - base.instance_variable_set('@first_render', input) - assert_equal expectation, base.send(:find_template_extension_from_first_render) - end - end - - def test_should_report_file_exists_correctly - base = ActionView::Base.new - - assert_nil base.send(:find_template_extension_from_first_render) - - assert_equal false, base.send(:file_exists?, 'test.rhtml') - assert_equal false, base.send(:file_exists?, 'test.rb') - - base.instance_variable_set('@first_render', 'foo.rb') - - assert_equal 'rb', base.send(:find_template_extension_from_first_render) - - assert_equal false, base.send(:file_exists?, 'baz') - assert_equal false, base.send(:file_exists?, 'baz.rb') - - end - -end diff --git a/vendor/rails/actionpack/test/active_record_unit.rb b/vendor/rails/actionpack/test/active_record_unit.rb index 5f2745b5..a7d52685 100644 --- a/vendor/rails/actionpack/test/active_record_unit.rb +++ b/vendor/rails/actionpack/test/active_record_unit.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/abstract_unit' +require 'abstract_unit' # Define the essentials class ActiveRecordTestConnector @@ -84,8 +84,7 @@ class ActiveRecordTestConnector end end -# Test case for inheritance -class ActiveRecordTestCase < Test::Unit::TestCase +class ActiveRecordTestCase < ActiveSupport::TestCase # Set our fixture path if ActiveRecordTestConnector.able_to_connect self.fixture_path = "#{File.dirname(__FILE__)}/fixtures/" @@ -100,9 +99,7 @@ class ActiveRecordTestCase < Test::Unit::TestCase super if ActiveRecordTestConnector.connected end - # Default so Test::Unit::TestCase doesn't complain - def test_truth - end + def default_test; end end ActiveRecordTestConnector.setup diff --git a/vendor/rails/actionpack/test/activerecord/active_record_store_test.rb b/vendor/rails/actionpack/test/activerecord/active_record_store_test.rb index 707a0a75..fd7da89a 100644 --- a/vendor/rails/actionpack/test/activerecord/active_record_store_test.rb +++ b/vendor/rails/actionpack/test/activerecord/active_record_store_test.rb @@ -1,9 +1,8 @@ # These tests exercise CGI::Session::ActiveRecordStore, so you're going to # need AR in a sibling directory to AP and have SQLite installed. -require File.dirname(__FILE__) + '/../active_record_unit' +require 'active_record_unit' require 'action_controller/session/active_record_store' - module CommonActiveRecordStoreTests def test_basics s = session_class.new(:session_id => '1234', :data => { 'foo' => 'bar' }) @@ -66,7 +65,7 @@ class ActiveRecordStoreTest < ActiveRecordTestCase def test_save_unloaded_session c = session_class.connection - bogus_class = c.quote(Base64.encode64("\004\010o:\vBlammo\000")) + bogus_class = c.quote(ActiveSupport::Base64.encode64("\004\010o:\vBlammo\000")) c.insert("INSERT INTO #{session_class.table_name} ('#{session_id_column}', 'data') VALUES ('abcdefghijklmnop', #{bogus_class})") sess = session_class.find_by_session_id('abcdefghijklmnop') diff --git a/vendor/rails/actionpack/test/activerecord/render_partial_with_record_identification_test.rb b/vendor/rails/actionpack/test/activerecord/render_partial_with_record_identification_test.rb index ccebbefe..ed10e729 100644 --- a/vendor/rails/actionpack/test/activerecord/render_partial_with_record_identification_test.rb +++ b/vendor/rails/actionpack/test/activerecord/render_partial_with_record_identification_test.rb @@ -1,39 +1,49 @@ -require File.dirname(__FILE__) + '/../active_record_unit' +require 'active_record_unit' + +class RenderPartialWithRecordIdentificationController < ActionController::Base + def render_with_has_many_and_belongs_to_association + @developer = Developer.find(1) + render :partial => @developer.projects + end + + def render_with_has_many_association + @topic = Topic.find(1) + render :partial => @topic.replies + end + + def render_with_named_scope + render :partial => Reply.base + end + + def render_with_has_many_through_association + @developer = Developer.find(:first) + render :partial => @developer.topics + end + + def render_with_has_one_association + @company = Company.find(1) + render :partial => @company.mascot + end + + def render_with_belongs_to_association + @reply = Reply.find(1) + render :partial => @reply.topic + end + + def render_with_record + @developer = Developer.find(:first) + render :partial => @developer + end + + def render_with_record_collection + @developers = Developer.find(:all) + render :partial => @developers + end +end +RenderPartialWithRecordIdentificationController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ] class RenderPartialWithRecordIdentificationTest < ActiveRecordTestCase - fixtures :developers, :projects, :developers_projects, :topics, :replies - - class RenderPartialWithRecordIdentificationController < ActionController::Base - def render_with_has_many_and_belongs_to_association - @developer = Developer.find(1) - render :partial => @developer.projects - end - - def render_with_has_many_association - @topic = Topic.find(1) - render :partial => @topic.replies - end - - def render_with_has_many_through_association - @developer = Developer.find(:first) - render :partial => @developer.topics - end - - def render_with_belongs_to_association - @reply = Reply.find(1) - render :partial => @reply.topic - end - - def render_with_record - @developer = Developer.find(:first) - render :partial => @developer - end - - def render_with_record_collection - @developers = Developer.find(:all) - render :partial => @developers - end - end + fixtures :developers, :projects, :developers_projects, :topics, :replies, :companies, :mascots def setup @controller = RenderPartialWithRecordIdentificationController.new @@ -52,14 +62,9 @@ class RenderPartialWithRecordIdentificationTest < ActiveRecordTestCase assert_template 'replies/_reply' end - def test_rendering_partial_with_has_many_association - get :render_with_has_many_through_association - assert_template 'topics/_topic' - end - - def test_rendering_partial_with_belongs_to_association - get :render_with_belongs_to_association - assert_template 'topics/_topic' + def test_rendering_partial_with_named_scope + get :render_with_named_scope + assert_template 'replies/_reply' end def test_render_with_record @@ -71,4 +76,116 @@ class RenderPartialWithRecordIdentificationTest < ActiveRecordTestCase get :render_with_record_collection assert_template 'developers/_developer' end + + def test_rendering_partial_with_has_one_association + mascot = Company.find(1).mascot + get :render_with_has_one_association + assert_template 'mascots/_mascot' + assert_equal mascot.name, @response.body + end end + +class RenderPartialWithRecordIdentificationController < ActionController::Base + def render_with_has_many_and_belongs_to_association + @developer = Developer.find(1) + render :partial => @developer.projects + end + + def render_with_has_many_association + @topic = Topic.find(1) + render :partial => @topic.replies + end + + def render_with_has_many_through_association + @developer = Developer.find(:first) + render :partial => @developer.topics + end + + def render_with_belongs_to_association + @reply = Reply.find(1) + render :partial => @reply.topic + end + + def render_with_record + @developer = Developer.find(:first) + render :partial => @developer + end + + def render_with_record_collection + @developers = Developer.find(:all) + render :partial => @developers + end +end +RenderPartialWithRecordIdentificationController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ] + +class Game < Struct.new(:name, :id) + def to_param + id.to_s + end +end + +module Fun + class NestedController < ActionController::Base + def render_with_record_in_nested_controller + render :partial => Game.new("Pong") + end + + def render_with_record_collection_in_nested_controller + render :partial => [ Game.new("Pong"), Game.new("Tank") ] + end + end + NestedController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ] + + module Serious + class NestedDeeperController < ActionController::Base + def render_with_record_in_deeper_nested_controller + render :partial => Game.new("Chess") + end + + def render_with_record_collection_in_deeper_nested_controller + render :partial => [ Game.new("Chess"), Game.new("Sudoku"), Game.new("Solitaire") ] + end + end + NestedDeeperController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ] + end +end + +class RenderPartialWithRecordIdentificationAndNestedControllersTest < ActiveRecordTestCase + def setup + @controller = Fun::NestedController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + super + end + + def test_render_with_record_in_nested_controller + get :render_with_record_in_nested_controller + assert_template 'fun/games/_game' + end + + def test_render_with_record_collection_in_nested_controller + get :render_with_record_collection_in_nested_controller + assert_template 'fun/games/_game' + end + +end + +class RenderPartialWithRecordIdentificationAndNestedDeeperControllersTest < ActiveRecordTestCase + def setup + @controller = Fun::Serious::NestedDeeperController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + super + end + + def test_render_with_record_in_deeper_nested_controller + get :render_with_record_in_deeper_nested_controller + assert_template 'fun/serious/games/_game' + end + + def test_render_with_record_collection_in_deeper_nested_controller + get :render_with_record_collection_in_deeper_nested_controller + assert_template 'fun/serious/games/_game' + end + +end \ No newline at end of file diff --git a/vendor/rails/actionpack/test/adv_attr_test.rb b/vendor/rails/actionpack/test/adv_attr_test.rb new file mode 100644 index 00000000..fdda4ad9 --- /dev/null +++ b/vendor/rails/actionpack/test/adv_attr_test.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/abstract_unit' +require 'action_mailer/adv_attr_accessor' + +class AdvAttrTest < Test::Unit::TestCase + class Person + include ActionMailer::AdvAttrAccessor + adv_attr_accessor :name + end + + def test_adv_attr + bob = Person.new + assert_nil bob.name + bob.name 'Bob' + assert_equal 'Bob', bob.name + + assert_raise(ArgumentError) {bob.name 'x', 'y'} + end + + +end \ No newline at end of file diff --git a/vendor/rails/actionpack/test/controller/action_pack_assertions_test.rb b/vendor/rails/actionpack/test/controller/action_pack_assertions_test.rb index 1eb9610d..1db05758 100644 --- a/vendor/rails/actionpack/test/controller/action_pack_assertions_test.rb +++ b/vendor/rails/actionpack/test/controller/action_pack_assertions_test.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../abstract_unit' +require 'abstract_unit' # a controller class to facilitate the tests class ActionPackAssertionsController < ActionController::Base @@ -124,6 +124,15 @@ class ActionPackAssertionsController < ActionController::Base def rescue_action(e) raise; end end +# Used to test that assert_response includes the exception message +# in the failure message when an action raises and assert_response +# is expecting something other than an error. +class AssertResponseWithUnexpectedErrorController < ActionController::Base + def index + raise 'FAIL' + end +end + module Admin class InnerModuleController < ActionController::Base def index @@ -465,6 +474,15 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase rescue Test::Unit::AssertionFailedError => e end end + + def test_assert_response_uses_exception_message + @controller = AssertResponseWithUnexpectedErrorController.new + get :index + assert_response :success + flunk 'Expected non-success response' + rescue Test::Unit::AssertionFailedError => e + assert e.message.include?('FAIL') + end end class ActionPackHeaderTest < Test::Unit::TestCase diff --git a/vendor/rails/actionpack/test/controller/addresses_render_test.rb b/vendor/rails/actionpack/test/controller/addresses_render_test.rb index d1e9122d..a3173420 100644 --- a/vendor/rails/actionpack/test/controller/addresses_render_test.rb +++ b/vendor/rails/actionpack/test/controller/addresses_render_test.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../abstract_unit' +require 'abstract_unit' class Address diff --git a/vendor/rails/actionpack/test/controller/assert_select_test.rb b/vendor/rails/actionpack/test/controller/assert_select_test.rb index b0f3d6ce..5af579f3 100644 --- a/vendor/rails/actionpack/test/controller/assert_select_test.rb +++ b/vendor/rails/actionpack/test/controller/assert_select_test.rb @@ -3,8 +3,8 @@ # Under MIT and/or CC By license. #++ -require "#{File.dirname(__FILE__)}/../abstract_unit" -require "#{File.dirname(__FILE__)}/fake_controllers" +require 'abstract_unit' +require 'controller/fake_controllers' unless defined?(ActionMailer) @@ -345,10 +345,17 @@ class AssertSelectTest < Test::Unit::TestCase page.replace "test", "
\343\203\201\343\202\261\343\203\203\343\203\210
" end assert_select_rjs do - assert_select "#1", :text => "\343\203\201\343\202\261\343\203\203\343\203\210" - assert_select "#1", "\343\203\201\343\202\261\343\203\203\343\203\210" - assert_select "#1", Regexp.new("\343\203\201..\343\203\210",0,'U') - assert_raises(AssertionFailedError) { assert_select "#1", Regexp.new("\343\203\201.\343\203\210",0,'U') } + str = "#1" + assert_select str, :text => "\343\203\201\343\202\261\343\203\203\343\203\210" + assert_select str, "\343\203\201\343\202\261\343\203\203\343\203\210" + if str.respond_to?(:force_encoding) + str.force_encoding(Encoding::UTF_8) + assert_select str, /\343\203\201..\343\203\210/u + assert_raises(AssertionFailedError) { assert_select str, /\343\203\201.\343\203\210/u } + else + assert_select str, Regexp.new("\343\203\201..\343\203\210",0,'U') + assert_raises(AssertionFailedError) { assert_select str, Regexp.new("\343\203\201.\343\203\210",0,'U') } + end end end diff --git a/vendor/rails/actionpack/test/controller/base_test.rb b/vendor/rails/actionpack/test/controller/base_test.rb index 60e61b62..b2871759 100644 --- a/vendor/rails/actionpack/test/controller/base_test.rb +++ b/vendor/rails/actionpack/test/controller/base_test.rb @@ -1,5 +1,4 @@ -require File.dirname(__FILE__) + '/../abstract_unit' -require 'test/unit' +require 'abstract_unit' require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late # Provide some controller to run the tests on. @@ -49,6 +48,15 @@ protected end +class DefaultUrlOptionsController < ActionController::Base + def default_url_options_action + end + + def default_url_options(options = nil) + { :host => 'www.override.com', :action => 'new', :bacon => 'chunky' } + end +end + class ControllerClassTests < Test::Unit::TestCase def test_controller_path assert_equal 'empty', EmptyController.controller_path @@ -87,7 +95,10 @@ class ControllerInstanceTests < Test::Unit::TestCase # Mocha adds some public instance methods to Object that would be # considered actions, so explicitly hide_action them. def hide_mocha_methods_from_controller(controller) - mocha_methods = [:expects, :metaclass, :mocha, :mocha_inspect, :reset_mocha, :stubba_object, :stubba_method, :stubs, :verify, :__metaclass__, :__is_a__] + mocha_methods = [ + :expects, :mocha, :mocha_inspect, :reset_mocha, :stubba_object, + :stubba_method, :stubs, :verify, :__metaclass__, :__is_a__, :to_matcher, + ] controller.class.send!(:hide_action, *mocha_methods) end end @@ -132,3 +143,41 @@ class PerformActionTest < Test::Unit::TestCase assert_response 404 end end + +class DefaultUrlOptionsTest < Test::Unit::TestCase + def setup + @controller = DefaultUrlOptionsController.new + + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + + @request.host = 'www.example.com' + end + + def test_default_url_options_are_used_if_set + ActionController::Routing::Routes.draw do |map| + map.default_url_options 'default_url_options', :controller => 'default_url_options' + map.connect ':controller/:action/:id' + end + + get :default_url_options_action # Make a dummy request so that the controller is initialized properly. + + assert_equal 'http://www.override.com/default_url_options/new?bacon=chunky', @controller.url_for(:controller => 'default_url_options') + assert_equal 'http://www.override.com/default_url_options?bacon=chunky', @controller.send(:default_url_options_url) + ensure + ActionController::Routing::Routes.load! + end +end + +class EnsureNamedRoutesWorksTicket22BugTest < Test::Unit::TestCase + def test_named_routes_still_work + ActionController::Routing::Routes.draw do |map| + map.resources :things + end + EmptyController.send :include, ActionController::UrlWriter + + assert_equal '/things', EmptyController.new.send(:things_path) + ensure + ActionController::Routing::Routes.load! + end +end \ No newline at end of file diff --git a/vendor/rails/actionpack/test/controller/benchmark_test.rb b/vendor/rails/actionpack/test/controller/benchmark_test.rb index f346e575..608ea5f5 100644 --- a/vendor/rails/actionpack/test/controller/benchmark_test.rb +++ b/vendor/rails/actionpack/test/controller/benchmark_test.rb @@ -1,5 +1,4 @@ -require File.dirname(__FILE__) + '/../abstract_unit' -require 'test/unit' +require 'abstract_unit' # Provide some static controllers. class BenchmarkedController < ActionController::Base diff --git a/vendor/rails/actionpack/test/controller/caching_test.rb b/vendor/rails/actionpack/test/controller/caching_test.rb index d6982fbc..ddc1c683 100644 --- a/vendor/rails/actionpack/test/controller/caching_test.rb +++ b/vendor/rails/actionpack/test/controller/caching_test.rb @@ -1,14 +1,15 @@ require 'fileutils' -require File.dirname(__FILE__) + '/../abstract_unit' +require 'abstract_unit' CACHE_DIR = 'test_cache' # Don't change '/../temp/' cavalierly or you might hose something you don't want hosed FILE_STORE_PATH = File.join(File.dirname(__FILE__), '/../temp/', CACHE_DIR) ActionController::Base.page_cache_directory = FILE_STORE_PATH -ActionController::Base.fragment_cache_store = :file_store, FILE_STORE_PATH +ActionController::Base.cache_store = :file_store, FILE_STORE_PATH class PageCachingTestController < ActionController::Base - caches_page :ok, :no_content, :found, :not_found + caches_page :ok, :no_content, :if => Proc.new { |c| !c.request.format.json? } + caches_page :found, :not_found def ok head :ok @@ -25,17 +26,17 @@ class PageCachingTestController < ActionController::Base def not_found head :not_found end - + def custom_path render :text => "Super soaker" cache_page("Super soaker", "/index.html") end - + def expire_custom_path expire_page("/index.html") head :ok end - + def trailing_slash render :text => "Sneak attack" end @@ -95,7 +96,7 @@ class PageCachingTest < Test::Unit::TestCase get :expire_custom_path assert !File.exist?("#{FILE_STORE_PATH}/index.html") end - + def test_should_cache_without_trailing_slash_on_url @controller.class.cache_page 'cached content', '/page_caching_test/trailing_slash' assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/trailing_slash.html") @@ -127,6 +128,12 @@ class PageCachingTest < Test::Unit::TestCase end end end + + def test_page_caching_conditional_options + @request.env['HTTP_ACCEPT'] = 'application/json' + get :ok + assert_page_not_cached :ok + end private def assert_page_cached(action, message = "#{action} should have been cached") @@ -215,7 +222,7 @@ class ActionCacheTest < Test::Unit::TestCase get :index assert_equal cached_time, @response.body end - + def test_action_cache_with_custom_cache_path get :show cached_time = content_to_cache @@ -262,9 +269,9 @@ class ActionCacheTest < Test::Unit::TestCase @request.host = 'jamis.hostname.com' get :index jamis_cache = content_to_cache - + reset! - + @request.host = 'david.hostname.com' get :index david_cache = content_to_cache @@ -308,7 +315,7 @@ class ActionCacheTest < Test::Unit::TestCase assert_equal 'xml', path_object.extension assert_equal 'example.org/posts/index.xml', path_object.path end - + def test_correct_content_type_is_returned_for_cache_hit # run it twice to cache it the first time get :index, :id => 'content-type.xml' @@ -341,9 +348,207 @@ class ActionCacheTest < Test::Unit::TestCase @controller = ActionCachingTestController.new @request.host = 'hostname.com' end - + def assert_cache_exists(path) - full_path = File.join(FILE_STORE_PATH, path + '.cache') + full_path = File.join(FILE_STORE_PATH, "views", path + '.cache') assert File.exist?(full_path), "#{full_path.inspect} does not exist." end end + +class FragmentCachingTestController < ActionController::Base + def some_action; end; +end + +class FragmentCachingTest < Test::Unit::TestCase + def setup + ActionController::Base.perform_caching = true + @store = ActiveSupport::Cache::MemoryStore.new + ActionController::Base.cache_store = @store + @controller = FragmentCachingTestController.new + @params = {:controller => 'posts', :action => 'index'} + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + @controller.params = @params + @controller.request = @request + @controller.response = @response + @controller.send(:initialize_current_url) + end + + def test_fragment_cache_key + assert_equal 'views/what a key', @controller.fragment_cache_key('what a key') + assert_equal( "views/test.host/fragment_caching_test/some_action", + @controller.fragment_cache_key(:controller => 'fragment_caching_test',:action => 'some_action')) + end + + def test_read_fragment__with_caching_enabled + @store.write('views/name', 'value') + assert_equal 'value', @controller.read_fragment('name') + end + + def test_read_fragment__with_caching_disabled + ActionController::Base.perform_caching = false + @store.write('views/name', 'value') + assert_nil @controller.read_fragment('name') + end + + def test_write_fragment__with_caching_enabled + assert_nil @store.read('views/name') + assert_equal 'value', @controller.write_fragment('name', 'value') + assert_equal 'value', @store.read('views/name') + end + + def test_write_fragment__with_caching_disabled + assert_nil @store.read('views/name') + ActionController::Base.perform_caching = false + assert_equal nil, @controller.write_fragment('name', 'value') + assert_nil @store.read('views/name') + end + + def test_expire_fragment__with_simple_key + @store.write('views/name', 'value') + @controller.expire_fragment 'name' + assert_nil @store.read('views/name') + end + + def test_expire_fragment__with__regexp + @store.write('views/name', 'value') + @store.write('views/another_name', 'another_value') + @store.write('views/primalgrasp', 'will not expire ;-)') + + @controller.expire_fragment /name/ + + assert_nil @store.read('views/name') + assert_nil @store.read('views/another_name') + assert_equal 'will not expire ;-)', @store.read('views/primalgrasp') + end + + def test_fragment_for__with_disabled_caching + ActionController::Base.perform_caching = false + + @store.write('views/expensive', 'fragment content') + fragment_computed = false + + buffer = 'generated till now -> ' + @controller.fragment_for(Proc.new { fragment_computed = true }, 'expensive') { buffer } + + assert fragment_computed + assert_equal 'generated till now -> ', buffer + end + + + def test_fragment_for + @store.write('views/expensive', 'fragment content') + fragment_computed = false + + buffer = 'generated till now -> ' + @controller.fragment_for(Proc.new { fragment_computed = true }, 'expensive') { buffer} + + assert !fragment_computed + assert_equal 'generated till now -> fragment content', buffer + end + + def test_cache_erb_fragment + @store.write('views/expensive', 'fragment content') + _erbout = 'generated till now -> ' + + assert_equal( 'generated till now -> fragment content', + ActionView::TemplateHandlers::ERB.new(@controller).cache_fragment(Proc.new{ }, 'expensive')) + end + + def test_cache_rxml_fragment + @store.write('views/expensive', 'fragment content') + xml = 'generated till now -> ' + class << xml; def target!; to_s; end; end + + assert_equal( 'generated till now -> fragment content', + ActionView::TemplateHandlers::Builder.new(@controller).cache_fragment(Proc.new{ }, 'expensive')) + end + + def test_cache_rjs_fragment + @store.write('views/expensive', 'fragment content') + page = 'generated till now -> ' + + assert_equal( 'generated till now -> fragment content', + ActionView::TemplateHandlers::RJS.new(@controller).cache_fragment(Proc.new{ }, 'expensive')) + end + + def test_cache_rjs_fragment_debug_mode_does_not_interfere + @store.write('views/expensive', 'fragment content') + page = 'generated till now -> ' + + begin + debug_mode, ActionView::Base.debug_rjs = ActionView::Base.debug_rjs, true + assert_equal( 'generated till now -> fragment content', + ActionView::TemplateHandlers::RJS.new(@controller).cache_fragment(Proc.new{ }, 'expensive')) + assert ActionView::Base.debug_rjs + ensure + ActionView::Base.debug_rjs = debug_mode + end + end +end + + +class FunctionalCachingController < ActionController::Base + def fragment_cached + end + + def html_fragment_cached_with_partial + respond_to do |format| + format.html + end + end + + def js_fragment_cached_with_partial + respond_to do |format| + format.js + end + end + + + def rescue_action(e) + raise e + end +end + +FunctionalCachingController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ] + +class FunctionalFragmentCachingTest < Test::Unit::TestCase + def setup + ActionController::Base.perform_caching = true + @store = ActiveSupport::Cache::MemoryStore.new + ActionController::Base.cache_store = @store + @controller = FunctionalCachingController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + def test_fragment_caching + get :fragment_cached + assert_response :success + expected_body = <<-CACHED +Hello +This bit's fragment cached +CACHED + assert_equal expected_body, @response.body + + assert_equal "This bit's fragment cached", @store.read('views/test.host/functional_caching/fragment_cached') + end + + def test_fragment_caching_in_partials + get :html_fragment_cached_with_partial + assert_response :success + assert_match /Fragment caching in a partial/, @response.body + assert_match "Fragment caching in a partial", @store.read('views/test.host/functional_caching/html_fragment_cached_with_partial') + end + + def test_fragment_caching_in_rjs_partials + xhr :get, :js_fragment_cached_with_partial + assert_response :success + assert_match /Fragment caching in a partial/, @response.body + assert_match "Fragment caching in a partial", @store.read('views/test.host/functional_caching/js_fragment_cached_with_partial') + end +end + + + + + diff --git a/vendor/rails/actionpack/test/controller/capture_test.rb b/vendor/rails/actionpack/test/controller/capture_test.rb index 7ec5f32a..aaafea39 100644 --- a/vendor/rails/actionpack/test/controller/capture_test.rb +++ b/vendor/rails/actionpack/test/controller/capture_test.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../abstract_unit' +require 'abstract_unit' class CaptureController < ActionController::Base def self.controller_name; "test"; end diff --git a/vendor/rails/actionpack/test/controller/cgi_test.rb b/vendor/rails/actionpack/test/controller/cgi_test.rb index 021781df..87f72fda 100755 --- a/vendor/rails/actionpack/test/controller/cgi_test.rb +++ b/vendor/rails/actionpack/test/controller/cgi_test.rb @@ -1,11 +1,12 @@ -require File.dirname(__FILE__) + '/../abstract_unit' +require 'abstract_unit' require 'action_controller/cgi_process' class BaseCgiTest < Test::Unit::TestCase def setup @request_hash = {"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"} - # cookie as returned by some Nokia phone browsers (no space after semicolon separator) - @alt_cookie_fmt_request_hash = {"HTTP_COOKIE"=>"_session_id=c84ace84796670c052c6ceb2451fb0f2;is_admin=yes"} + # 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"} @fake_cgi = Struct.new(:env_table).new(@request_hash) @request = ActionController::CgiRequest.new(@fake_cgi) end @@ -76,7 +77,7 @@ class CgiRequestTest < BaseCgiTest assert_equal ["yes"], cookies["is_admin"], cookies.inspect alt_cookies = CGI::Cookie::parse(@alt_cookie_fmt_request_hash["HTTP_COOKIE"]); - assert_equal ["c84ace84796670c052c6ceb2451fb0f2"], alt_cookies["_session_id"], alt_cookies.inspect + assert_equal ["c84ace847,96670c052c6ceb2451fb0f2"], alt_cookies["_session_id"], alt_cookies.inspect assert_equal ["yes"], alt_cookies["is_admin"], alt_cookies.inspect end end diff --git a/vendor/rails/actionpack/test/controller/components_test.rb b/vendor/rails/actionpack/test/controller/components_test.rb index debd8a27..82c55483 100644 --- a/vendor/rails/actionpack/test/controller/components_test.rb +++ b/vendor/rails/actionpack/test/controller/components_test.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../abstract_unit' +require 'abstract_unit' class CallerController < ActionController::Base def calling_from_controller diff --git a/vendor/rails/actionpack/test/controller/content_type_test.rb b/vendor/rails/actionpack/test/controller/content_type_test.rb index 1841d37c..d262ce81 100644 --- a/vendor/rails/actionpack/test/controller/content_type_test.rb +++ b/vendor/rails/actionpack/test/controller/content_type_test.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../abstract_unit' +require 'abstract_unit' class ContentTypeController < ActionController::Base def render_content_type_from_body @@ -136,4 +136,4 @@ class ContentTypeTest < Test::Unit::TestCase get :render_default_content_types_for_respond_to assert_equal Mime::XML, @response.content_type end -end \ No newline at end of file +end diff --git a/vendor/rails/actionpack/test/controller/cookie_test.rb b/vendor/rails/actionpack/test/controller/cookie_test.rb index 6a833fee..42f3bd26 100644 --- a/vendor/rails/actionpack/test/controller/cookie_test.rb +++ b/vendor/rails/actionpack/test/controller/cookie_test.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../abstract_unit' +require 'abstract_unit' class CookieTest < Test::Unit::TestCase class TestController < ActionController::Base @@ -37,7 +37,7 @@ class CookieTest < Test::Unit::TestCase end def rescue_action(e) - raise unless ActionController::MissingTemplate # No templates here, and we don't care about the output + raise unless ActionView::MissingTemplate # No templates here, and we don't care about the output end end @@ -132,4 +132,9 @@ class CookieTest < Test::Unit::TestCase assert cookie_str !~ /secure/ assert cookie_str !~ /HttpOnly/ end + + def test_cookies_should_not_be_split_on_ampersand_values + cookies = CGI::Cookie.parse('return_to=http://rubyonrails.org/search?term=api&scope=all&global=true') + assert_equal({"return_to" => ["http://rubyonrails.org/search?term=api&scope=all&global=true"]}, cookies) + end end diff --git a/vendor/rails/actionpack/test/controller/custom_handler_test.rb b/vendor/rails/actionpack/test/controller/custom_handler_test.rb index 2747a0f3..ac484ae1 100644 --- a/vendor/rails/actionpack/test/controller/custom_handler_test.rb +++ b/vendor/rails/actionpack/test/controller/custom_handler_test.rb @@ -1,33 +1,36 @@ -require File.dirname(__FILE__) + '/../abstract_unit' +require 'abstract_unit' -class CustomHandler +class CustomHandler < ActionView::TemplateHandler def initialize( view ) @view = view end - def render( template, local_assigns ) - [ template, - local_assigns, + def render( template ) + [ template.source, + template.locals, @view ] end end class CustomHandlerTest < Test::Unit::TestCase def setup - ActionView::Base.register_template_handler "foo", CustomHandler - ActionView::Base.register_template_handler :foo2, CustomHandler + ActionView::Template.register_template_handler "foo", CustomHandler + ActionView::Template.register_template_handler :foo2, CustomHandler @view = ActionView::Base.new end def test_custom_render - result = @view.render_template( "foo", "hello <%= one %>", nil, :one => "two" ) + template = ActionView::InlineTemplate.new(@view, "hello <%= one %>", { :one => "two" }, "foo") + + result = @view.render_template(template) assert_equal( [ "hello <%= one %>", { :one => "two" }, @view ], result ) end def test_custom_render2 - result = @view.render_template( "foo2", "hello <%= one %>", nil, :one => "two" ) + template = ActionView::InlineTemplate.new(@view, "hello <%= one %>", { :one => "two" }, "foo2") + result = @view.render_template(template) assert_equal( [ "hello <%= one %>", { :one => "two" }, @view ], result ) @@ -35,7 +38,8 @@ class CustomHandlerTest < Test::Unit::TestCase def test_unhandled_extension # uses the ERb handler by default if the extension isn't recognized - result = @view.render_template( "bar", "hello <%= one %>", nil, :one => "two" ) + template = ActionView::InlineTemplate.new(@view, "hello <%= one %>", { :one => "two" }, "bar") + result = @view.render_template(template) assert_equal "hello two", result end end diff --git a/vendor/rails/actionpack/test/controller/deprecation/deprecated_base_methods_test.rb b/vendor/rails/actionpack/test/controller/deprecation/deprecated_base_methods_test.rb index 6d7157e1..8c1a8954 100644 --- a/vendor/rails/actionpack/test/controller/deprecation/deprecated_base_methods_test.rb +++ b/vendor/rails/actionpack/test/controller/deprecation/deprecated_base_methods_test.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../../abstract_unit' +require 'abstract_unit' class DeprecatedBaseMethodsTest < Test::Unit::TestCase class Target < ActionController::Base diff --git a/vendor/rails/actionpack/test/controller/dispatcher_test.rb b/vendor/rails/actionpack/test/controller/dispatcher_test.rb index ec937ebf..eea0813e 100644 --- a/vendor/rails/actionpack/test/controller/dispatcher_test.rb +++ b/vendor/rails/actionpack/test/controller/dispatcher_test.rb @@ -1,4 +1,4 @@ -require "#{File.dirname(__FILE__)}/../abstract_unit" +require 'abstract_unit' uses_mocha 'dispatcher tests' do @@ -11,107 +11,89 @@ class DispatcherTest < Test::Unit::TestCase @output = StringIO.new ENV['REQUEST_METHOD'] = 'GET' - Dispatcher.callbacks[:prepare].clear + # Clear callbacks as they are redefined by Dispatcher#define_dispatcher_callbacks + Dispatcher.instance_variable_set("@prepare_dispatch_callbacks", ActiveSupport::Callbacks::CallbackChain.new) + Dispatcher.instance_variable_set("@before_dispatch_callbacks", ActiveSupport::Callbacks::CallbackChain.new) + Dispatcher.instance_variable_set("@after_dispatch_callbacks", ActiveSupport::Callbacks::CallbackChain.new) + + Dispatcher.stubs(:require_dependency) + @dispatcher = Dispatcher.new(@output) end def teardown - ENV['REQUEST_METHOD'] = nil + ENV.delete 'REQUEST_METHOD' end def test_clears_dependencies_after_dispatch_if_in_loading_mode - Dependencies.stubs(:load?).returns(true) - ActionController::Routing::Routes.expects(:reload).once Dependencies.expects(:clear).once - dispatch + dispatch(@output, false) end def test_leaves_dependencies_after_dispatch_if_not_in_loading_mode - Dependencies.stubs(:load?).returns(false) - ActionController::Routing::Routes.expects(:reload).never Dependencies.expects(:clear).never dispatch end + # Stub out dispatch error logger + class << Dispatcher + def log_failsafe_exception(status, exception); end + end + def test_failsafe_response CGI.expects(:new).raises('some multipart parsing failure') - - ActionController::Routing::Routes.stubs(:reload) - Dispatcher.stubs(:log_failsafe_exception) + Dispatcher.expects(:log_failsafe_exception) assert_nothing_raised { dispatch } assert_equal "Status: 400 Bad Request\r\nContent-Type: text/html\r\n\r\n

400 Bad Request

", @output.string end - def test_reload_application_sets_unprepared_if_loading_dependencies - Dependencies.stubs(:load?).returns(false) - ActionController::Routing::Routes.expects(:reload).never - @dispatcher.unprepared = false - @dispatcher.send!(:reload_application) - assert !@dispatcher.unprepared - - Dependencies.stubs(:load?).returns(true) - ActionController::Routing::Routes.expects(:reload).once - @dispatcher.send!(:reload_application) - assert @dispatcher.unprepared - end - - def test_prepare_application_runs_callbacks_if_unprepared + def test_prepare_callbacks a = b = c = nil - Dispatcher.to_prepare { a = b = c = 1 } - Dispatcher.to_prepare { b = c = 2 } - Dispatcher.to_prepare { c = 3 } + Dispatcher.to_prepare { |*args| a = b = c = 1 } + Dispatcher.to_prepare { |*args| b = c = 2 } + Dispatcher.to_prepare { |*args| c = 3 } - # Skip the callbacks when already prepared. - @dispatcher.unprepared = false - @dispatcher.send! :prepare_application + # Ensure to_prepare callbacks are not run when defined assert_nil a || b || c - # Perform the callbacks when unprepared. - @dispatcher.unprepared = true - @dispatcher.send! :prepare_application + # Run callbacks + @dispatcher.send :run_callbacks, :prepare_dispatch + assert_equal 1, a assert_equal 2, b assert_equal 3, c - # But when not :load, make sure they are only run once + # Make sure they are only run once a = b = c = nil - @dispatcher.send! :prepare_application + @dispatcher.send :dispatch assert_nil a || b || c end def test_to_prepare_with_identifier_replaces a = b = nil - Dispatcher.to_prepare(:unique_id) { a = b = 1 } - Dispatcher.to_prepare(:unique_id) { a = 2 } + Dispatcher.to_prepare(:unique_id) { |*args| a = b = 1 } + Dispatcher.to_prepare(:unique_id) { |*args| a = 2 } - @dispatcher.unprepared = true - @dispatcher.send! :prepare_application + @dispatcher.send :run_callbacks, :prepare_dispatch assert_equal 2, a assert_equal nil, b end - def test_to_prepare_only_runs_once_if_not_loading_dependencies - Dependencies.stubs(:load?).returns(false) - called = 0 - Dispatcher.to_prepare(:unprepared_test) { called += 1 } - 2.times { dispatch } - assert_equal 1, called - end - private - def dispatch(output = @output) + def dispatch(output = @output, cache_classes = true) controller = mock controller.stubs(:process).returns(controller) controller.stubs(:out).with(output).returns('response') ActionController::Routing::Routes.stubs(:recognize).returns(controller) + Dispatcher.define_dispatcher_callbacks(cache_classes) Dispatcher.dispatch(nil, {}, output) end diff --git a/vendor/rails/actionpack/test/controller/fake_controllers.rb b/vendor/rails/actionpack/test/controller/fake_controllers.rb index 5f958b28..75c114c1 100644 --- a/vendor/rails/actionpack/test/controller/fake_controllers.rb +++ b/vendor/rails/actionpack/test/controller/fake_controllers.rb @@ -10,6 +10,23 @@ module Admin class NewsFeedController < Class.new(ActionController::Base); end end +# For speed test +class SpeedController < ActionController::Base; end +class SearchController < SpeedController; end +class VideosController < SpeedController; end +class VideoFileController < SpeedController; end +class VideoSharesController < SpeedController; end +class VideoAbusesController < SpeedController; end +class VideoUploadsController < SpeedController; end +class VideoVisitsController < SpeedController; end +class UsersController < SpeedController; end +class SettingsController < SpeedController; end +class ChannelsController < SpeedController; end +class ChannelVideosController < SpeedController; end +class SessionsController < SpeedController; end +class LostPasswordsController < SpeedController; end +class PagesController < SpeedController; end + ActionController::Routing::Routes.draw do |map| map.route_one 'route_one', :controller => 'elsewhere', :action => 'flash_me' map.connect ':controller/:action/:id' diff --git a/vendor/rails/actionpack/test/controller/fake_models.rb b/vendor/rails/actionpack/test/controller/fake_models.rb index 2761b09f..7420579e 100644 --- a/vendor/rails/actionpack/test/controller/fake_models.rb +++ b/vendor/rails/actionpack/test/controller/fake_models.rb @@ -3,3 +3,9 @@ class Customer < Struct.new(:name, :id) id.to_s end end + +class BadCustomer < Customer +end + +class GoodCustomer < Customer +end diff --git a/vendor/rails/actionpack/test/controller/filter_params_test.rb b/vendor/rails/actionpack/test/controller/filter_params_test.rb index 7b810b16..11adacb5 100644 --- a/vendor/rails/actionpack/test/controller/filter_params_test.rb +++ b/vendor/rails/actionpack/test/controller/filter_params_test.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../abstract_unit' +require 'abstract_unit' class FilterParamController < ActionController::Base end diff --git a/vendor/rails/actionpack/test/controller/filters_test.rb b/vendor/rails/actionpack/test/controller/filters_test.rb index 188e75af..3652c482 100644 --- a/vendor/rails/actionpack/test/controller/filters_test.rb +++ b/vendor/rails/actionpack/test/controller/filters_test.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../abstract_unit' +require 'abstract_unit' # FIXME: crashes Ruby 1.9 class FilterTest < Test::Unit::TestCase @@ -134,6 +134,11 @@ class FilterTest < Test::Unit::TestCase before_filter(ConditionalClassFilter, :ensure_login, Proc.new {|c| c.assigns["ran_proc_filter1"] = true }, :except => :show_without_filter) { |c| c.assigns["ran_proc_filter2"] = true} end + class ConditionalOptionsFilter < ConditionalFilterController + before_filter :ensure_login, :if => Proc.new { |c| true } + before_filter :clean_up_tmp, :if => Proc.new { |c| false } + end + class EmptyFilterChainController < TestController self.filter_chain.clear def show @@ -153,6 +158,30 @@ class FilterTest < Test::Unit::TestCase end end + class SkippingAndLimitedController < TestController + skip_before_filter :ensure_login + before_filter :ensure_login, :only => :index + + def index + render :text => 'ok' + end + + def public + end + end + + class SkippingAndReorderingController < TestController + skip_before_filter :ensure_login + before_filter :find_record + before_filter :ensure_login + + private + def find_record + @ran_filter ||= [] + @ran_filter << "find_record" + end + end + class ConditionalSkippingController < TestController skip_before_filter :ensure_login, :only => [ :login ] skip_after_filter :clean_up, :only => [ :login ] @@ -466,6 +495,11 @@ class FilterTest < Test::Unit::TestCase assert !response.template.assigns["ran_proc_filter2"] end + def test_running_conditional_options + response = test_process(ConditionalOptionsFilter) + assert_equal %w( ensure_login ), response.template.assigns["ran_filter"] + end + def test_running_collection_condition_filters assert_equal %w( ensure_login ), test_process(ConditionalCollectionFilterController).template.assigns["ran_filter"] assert_equal nil, test_process(ConditionalCollectionFilterController, "show_without_filter").template.assigns["ran_filter"] @@ -499,13 +533,6 @@ class FilterTest < Test::Unit::TestCase assert_equal nil, test_process(BeforeAndAfterConditionController, "show_without_filter").template.assigns["ran_filter"] end - def test_bad_filter - bad_filter_controller = Class.new(ActionController::Base) - assert_raises(ActionController::ActionControllerError) do - bad_filter_controller.before_filter 2 - end - end - def test_around_filter controller = test_process(AroundFilterController) assert controller.template.assigns["before_ran"] @@ -562,6 +589,15 @@ class FilterTest < Test::Unit::TestCase response = test_process(PrependingBeforeAndAfterController) assert_equal %w( before_all between_before_all_and_after_all after_all ), response.template.assigns["ran_filter"] end + + def test_skipping_and_limiting_controller + assert_equal %w( ensure_login ), test_process(SkippingAndLimitedController, "index").template.assigns["ran_filter"] + assert_nil test_process(SkippingAndLimitedController, "public").template.assigns["ran_filter"] + end + + def test_skipping_and_reordering_controller + assert_equal %w( find_record ensure_login ), test_process(SkippingAndReorderingController, "index").template.assigns["ran_filter"] + end def test_conditional_skipping_of_filters assert_nil test_process(ConditionalSkippingController, "login").template.assigns["ran_filter"] @@ -696,10 +732,6 @@ class ControllerWithProcFilter < PostsController end end -class ControllerWithWrongFilterType < PostsController - around_filter lambda { yield }, :only => :no_raise -end - class ControllerWithNestedFilters < ControllerWithSymbolAsFilter around_filter :raise_before, :raise_after, :without_exception, :only => :raises_both end @@ -746,17 +778,10 @@ class YieldingAroundFiltersTest < Test::Unit::TestCase assert_equal 1, ControllerWithFilterClass.filter_chain.size assert_equal 1, ControllerWithFilterInstance.filter_chain.size assert_equal 3, ControllerWithSymbolAsFilter.filter_chain.size - assert_equal 1, ControllerWithWrongFilterType.filter_chain.size assert_equal 6, ControllerWithNestedFilters.filter_chain.size assert_equal 4, ControllerWithAllTypesOfFilters.filter_chain.size end - def test_wrong_filter_type - assert_raise(ActionController::ActionControllerError) do - test_process(ControllerWithWrongFilterType,'no_raise') - end - end - def test_base controller = PostsController assert_nothing_raised { test_process(controller,'no_raise') } diff --git a/vendor/rails/actionpack/test/controller/flash_test.rb b/vendor/rails/actionpack/test/controller/flash_test.rb index 4a6f3c9e..e562531b 100644 --- a/vendor/rails/actionpack/test/controller/flash_test.rb +++ b/vendor/rails/actionpack/test/controller/flash_test.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../abstract_unit' +require 'abstract_unit' class FlashTest < Test::Unit::TestCase class TestController < ActionController::Base @@ -52,7 +52,7 @@ class FlashTest < Test::Unit::TestCase end def rescue_action(e) - raise unless ActionController::MissingTemplate === e + raise unless ActionView::MissingTemplate === e end # methods for test_sweep_after_halted_filter_chain diff --git a/vendor/rails/actionpack/test/controller/fragment_store_setting_test.rb b/vendor/rails/actionpack/test/controller/fragment_store_setting_test.rb deleted file mode 100644 index 3df6fd0b..00000000 --- a/vendor/rails/actionpack/test/controller/fragment_store_setting_test.rb +++ /dev/null @@ -1,47 +0,0 @@ -require File.dirname(__FILE__) + '/../abstract_unit' - -MemCache = Struct.new(:MemCache, :address) unless Object.const_defined?(:MemCache) - -class FragmentCacheStoreSettingTest < Test::Unit::TestCase - def teardown - ActionController::Base.fragment_cache_store = ActionController::Caching::Fragments::MemoryStore.new - end - - def test_file_fragment_cache_store - ActionController::Base.fragment_cache_store = :file_store, "/path/to/cache/directory" - assert_kind_of( - ActionController::Caching::Fragments::FileStore, - ActionController::Base.fragment_cache_store - ) - assert_equal "/path/to/cache/directory", ActionController::Base.fragment_cache_store.cache_path - end - - def test_drb_fragment_cache_store - ActionController::Base.fragment_cache_store = :drb_store, "druby://localhost:9192" - assert_kind_of( - ActionController::Caching::Fragments::DRbStore, - ActionController::Base.fragment_cache_store - ) - assert_equal "druby://localhost:9192", ActionController::Base.fragment_cache_store.address - end - - if defined? CGI::Session::MemCacheStore - def test_mem_cache_fragment_cache_store - ActionController::Base.fragment_cache_store = :mem_cache_store, "localhost" - assert_kind_of( - ActionController::Caching::Fragments::MemCacheStore, - ActionController::Base.fragment_cache_store - ) - assert_equal %w(localhost), ActionController::Base.fragment_cache_store.addresses - end - end - - def test_object_assigned_fragment_cache_store - ActionController::Base.fragment_cache_store = ActionController::Caching::Fragments::FileStore.new("/path/to/cache/directory") - assert_kind_of( - ActionController::Caching::Fragments::FileStore, - ActionController::Base.fragment_cache_store - ) - assert_equal "/path/to/cache/directory", ActionController::Base.fragment_cache_store.cache_path - end -end diff --git a/vendor/rails/actionpack/test/controller/header_test.rb b/vendor/rails/actionpack/test/controller/header_test.rb new file mode 100644 index 00000000..33c14a18 --- /dev/null +++ b/vendor/rails/actionpack/test/controller/header_test.rb @@ -0,0 +1,14 @@ +require 'abstract_unit' + +class HeaderTest < Test::Unit::TestCase + def setup + @headers = ActionController::Http::Headers.new("HTTP_CONTENT_TYPE"=>"text/plain") + end + + def test_content_type_works + assert_equal "text/plain", @headers["Content-Type"] + assert_equal "text/plain", @headers["content-type"] + assert_equal "text/plain", @headers["CONTENT_TYPE"] + assert_equal "text/plain", @headers["HTTP_CONTENT_TYPE"] + end +end diff --git a/vendor/rails/actionpack/test/controller/helper_test.rb b/vendor/rails/actionpack/test/controller/helper_test.rb index 117f73b7..6dc77a4a 100644 --- a/vendor/rails/actionpack/test/controller/helper_test.rb +++ b/vendor/rails/actionpack/test/controller/helper_test.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../abstract_unit' +require 'abstract_unit' ActionController::Helpers::HELPERS_DIR.replace File.dirname(__FILE__) + '/../fixtures/helpers' @@ -46,22 +46,10 @@ class HelperTest < Test::Unit::TestCase eval("class #{controller_class_name} < TestController; end") @controller_class = self.class.const_get(controller_class_name) - # Generate new template class and assign to controller. - template_class_name = "Test#{@symbol}View" - eval("class #{template_class_name} < ActionView::Base; end") - @template_class = self.class.const_get(template_class_name) - @controller_class.template_class = @template_class - # Set default test helper. self.test_helper = LocalAbcHelper end - - def teardown - # Reset template class. - #ActionController::Base.template_class = ActionView::Base - end - - + def test_deprecated_helper assert_equal expected_helper_methods, missing_methods assert_nothing_raised { @controller_class.helper TestHelper } @@ -142,6 +130,22 @@ class HelperTest < Test::Unit::TestCase assert methods.include?('foobar') end + def test_helper_proxy + methods = ApplicationController.helpers.methods.map(&:to_s) + + # ActionView + assert methods.include?('pluralize') + + # abc_helper.rb + assert methods.include?('bare_a') + + # fun/games_helper.rb + assert methods.include?('stratego') + + # fun/pdf_helper.rb + assert methods.include?('foobar') + end + private def expected_helper_methods TestHelper.instance_methods.map(&:to_s) diff --git a/vendor/rails/actionpack/test/controller/html-scanner/document_test.rb b/vendor/rails/actionpack/test/controller/html-scanner/document_test.rb index 0719883f..0519533d 100644 --- a/vendor/rails/actionpack/test/controller/html-scanner/document_test.rb +++ b/vendor/rails/actionpack/test/controller/html-scanner/document_test.rb @@ -1,5 +1,4 @@ -require File.dirname(__FILE__) + '/../../abstract_unit' -require 'test/unit' +require 'abstract_unit' class DocumentTest < Test::Unit::TestCase def test_handle_doctype diff --git a/vendor/rails/actionpack/test/controller/html-scanner/node_test.rb b/vendor/rails/actionpack/test/controller/html-scanner/node_test.rb index 1cf0a4bb..240f01ac 100644 --- a/vendor/rails/actionpack/test/controller/html-scanner/node_test.rb +++ b/vendor/rails/actionpack/test/controller/html-scanner/node_test.rb @@ -1,5 +1,4 @@ -require File.dirname(__FILE__) + '/../../abstract_unit' -require 'test/unit' +require 'abstract_unit' class NodeTest < Test::Unit::TestCase diff --git a/vendor/rails/actionpack/test/controller/html-scanner/sanitizer_test.rb b/vendor/rails/actionpack/test/controller/html-scanner/sanitizer_test.rb index 8fe9bbc5..db142f0b 100644 --- a/vendor/rails/actionpack/test/controller/html-scanner/sanitizer_test.rb +++ b/vendor/rails/actionpack/test/controller/html-scanner/sanitizer_test.rb @@ -1,5 +1,4 @@ -require File.dirname(__FILE__) + '/../../abstract_unit' -require 'test/unit' +require 'abstract_unit' class SanitizerTest < Test::Unit::TestCase def setup @@ -203,6 +202,12 @@ class SanitizerTest < Test::Unit::TestCase assert_equal expected, sanitize_css(raw) end + def test_should_sanitize_with_trailing_space + raw = "display:block; " + expected = "display: block;" + assert_equal expected, sanitize_css(raw) + end + def test_should_sanitize_xul_style_attributes raw = %(-moz-binding:url('http://ha.ckers.org/xssmoz.xml#xss')) assert_equal '', sanitize_css(raw) @@ -235,16 +240,20 @@ class SanitizerTest < Test::Unit::TestCase end def test_should_sanitize_img_vbscript - assert_sanitized %(), '' + assert_sanitized %(), '' end protected def assert_sanitized(input, expected = nil) @sanitizer ||= HTML::WhiteListSanitizer.new - assert_equal expected || input, @sanitizer.sanitize(input) + if input + assert_dom_equal expected || input, @sanitizer.sanitize(input) + else + assert_nil @sanitizer.sanitize(input) + end end - + def sanitize_css(input) (@sanitizer ||= HTML::WhiteListSanitizer.new).sanitize_css(input) end -end \ No newline at end of file +end diff --git a/vendor/rails/actionpack/test/controller/html-scanner/tag_node_test.rb b/vendor/rails/actionpack/test/controller/html-scanner/tag_node_test.rb index daeada9b..d1d46673 100644 --- a/vendor/rails/actionpack/test/controller/html-scanner/tag_node_test.rb +++ b/vendor/rails/actionpack/test/controller/html-scanner/tag_node_test.rb @@ -1,5 +1,4 @@ -require File.dirname(__FILE__) + '/../../abstract_unit' -require 'test/unit' +require 'abstract_unit' class TagNodeTest < Test::Unit::TestCase def test_open_without_attributes diff --git a/vendor/rails/actionpack/test/controller/html-scanner/text_node_test.rb b/vendor/rails/actionpack/test/controller/html-scanner/text_node_test.rb index 9853701f..1ab3f445 100644 --- a/vendor/rails/actionpack/test/controller/html-scanner/text_node_test.rb +++ b/vendor/rails/actionpack/test/controller/html-scanner/text_node_test.rb @@ -1,5 +1,4 @@ -require File.dirname(__FILE__) + '/../../abstract_unit' -require 'test/unit' +require 'abstract_unit' class TextNodeTest < Test::Unit::TestCase def setup @@ -48,4 +47,4 @@ class TextNodeTest < Test::Unit::TestCase def test_match_other assert_nil @node.match(:hello) end -end \ No newline at end of file +end diff --git a/vendor/rails/actionpack/test/controller/html-scanner/tokenizer_test.rb b/vendor/rails/actionpack/test/controller/html-scanner/tokenizer_test.rb index 437136b9..a001bcbb 100644 --- a/vendor/rails/actionpack/test/controller/html-scanner/tokenizer_test.rb +++ b/vendor/rails/actionpack/test/controller/html-scanner/tokenizer_test.rb @@ -1,5 +1,4 @@ -require File.dirname(__FILE__) + '/../../abstract_unit' -require 'test/unit' +require 'abstract_unit' class TokenizerTest < Test::Unit::TestCase @@ -79,6 +78,13 @@ class TokenizerTest < Test::Unit::TestCase assert_end end + def test_unterminated_cdata_tag + tokenize %{} + assert_next %{ world} assert_next %{original } diff --git a/vendor/rails/actionpack/test/controller/http_authentication_test.rb b/vendor/rails/actionpack/test/controller/http_authentication_test.rb index 6f7b31a4..c0069e80 100644 --- a/vendor/rails/actionpack/test/controller/http_authentication_test.rb +++ b/vendor/rails/actionpack/test/controller/http_authentication_test.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../abstract_unit' +require 'abstract_unit' class HttpBasicAuthenticationTest < Test::Unit::TestCase include ActionController::HttpAuthentication::Basic diff --git a/vendor/rails/actionpack/test/controller/integration_test.rb b/vendor/rails/actionpack/test/controller/integration_test.rb index 4213bb4a..62c00c5b 100644 --- a/vendor/rails/actionpack/test/controller/integration_test.rb +++ b/vendor/rails/actionpack/test/controller/integration_test.rb @@ -1,27 +1,23 @@ -require File.dirname(__FILE__) + '/../abstract_unit' - -$:.unshift File.dirname(__FILE__) + '/../../../railties/lib' +require 'abstract_unit' require 'action_controller/integration' uses_mocha 'integration' do -# Stub process for testing. -module ActionController - module Integration - class Session - def process(*args) - end - - def generic_url_rewriter - end - end +module IntegrationSessionStubbing + def stub_integration_session(session) + session.stubs(:process) + session.stubs(:generic_url_rewriter) end 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! @@ -212,11 +208,13 @@ class SessionTest < Test::Unit::TestCase end class IntegrationTestTest < Test::Unit::TestCase + include IntegrationSessionStubbing def setup @test = ::ActionController::IntegrationTest.new(:default_test) @test.class.stubs(:fixture_table_names).returns([]) @session = @test.open_session + stub_integration_session(@session) end def test_opens_new_session @@ -235,12 +233,15 @@ end # Tests that integration tests don't call Controller test methods for processing. # Integration tests have their own setup and teardown. class IntegrationTestUsesCorrectClass < ActionController::IntegrationTest + include IntegrationSessionStubbing def self.fixture_table_names [] end def test_integration_methods_called + reset! + stub_integration_session(@integration_session) %w( get post head put delete ).each do |verb| assert_nothing_raised("'#{verb}' should use integration test methods") { send!(verb, '/') } end @@ -248,8 +249,4 @@ class IntegrationTestUsesCorrectClass < ActionController::IntegrationTest end -# TODO -# class MockCGITest < Test::Unit::TestCase -# end - end # uses_mocha diff --git a/vendor/rails/actionpack/test/controller/integration_upload_test.rb b/vendor/rails/actionpack/test/controller/integration_upload_test.rb new file mode 100644 index 00000000..33df1131 --- /dev/null +++ b/vendor/rails/actionpack/test/controller/integration_upload_test.rb @@ -0,0 +1,43 @@ +require 'abstract_unit' +require 'action_controller/integration' +require 'action_controller/routing' + +unless defined? ApplicationController + class ApplicationController < ActionController::Base + end +end + +class UploadTestController < ActionController::Base + session :off + + def update + SessionUploadTest.last_request_type = ActionController::Base.param_parsers[request.content_type] + render :text => "got here" + end +end + +class SessionUploadTest < ActionController::IntegrationTest + FILES_DIR = File.dirname(__FILE__) + '/../fixtures/multipart' + + class << self + attr_accessor :last_request_type + end + + # def setup + # @session = ActionController::Integration::Session.new + # end + def test_post_with_upload + uses_mocha "test_post_with_upload" do + Dependencies.stubs(:load?).returns(false) + with_routing do |set| + set.draw do |map| + map.update 'update', :controller => "upload_test", :action => "update", :method => :post + end + + params = { :uploaded_data => fixture_file_upload(FILES_DIR + "/mona_lisa.jpg", "image/jpg") } + post '/update', params, :location => 'blah' + assert_equal(:multipart_form, SessionUploadTest.last_request_type) + end + end + end +end diff --git a/vendor/rails/actionpack/test/controller/layout_test.rb b/vendor/rails/actionpack/test/controller/layout_test.rb index 85cc3a08..3dc311b7 100644 --- a/vendor/rails/actionpack/test/controller/layout_test.rb +++ b/vendor/rails/actionpack/test/controller/layout_test.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../abstract_unit' +require 'abstract_unit' # The view_paths array must be set on Base and not LayoutTest so that LayoutTest's inherited # method has access to the view_paths array when looking for a layout to automatically assign. @@ -31,16 +31,16 @@ end class MultipleExtensions < LayoutTest end -class MabView +class MabView < ActionView::TemplateHandler def initialize(view) end - def render(text, locals = {}) - text + def render(template) + template.source end end -ActionView::Base::register_template_handler :mab, MabView +ActionView::Template::register_template_handler :mab, MabView class LayoutAutoDiscoveryTest < Test::Unit::TestCase def setup @@ -67,6 +67,7 @@ class LayoutAutoDiscoveryTest < Test::Unit::TestCase get :hello assert_equal 'layouts/third_party_template_library', @controller.active_layout assert_equal 'layouts/third_party_template_library', @response.layout + assert_response :success assert_equal 'Mab', @response.body end @@ -215,7 +216,7 @@ class LayoutExceptionRaised < Test::Unit::TestCase @controller = SetsNonExistentLayoutFile.new get :hello @response.template.class.module_eval { attr_accessor :exception } - assert_equal ActionController::MissingTemplate, @response.template.exception.class + assert_equal ActionView::MissingTemplate, @response.template.exception.class end end @@ -237,3 +238,22 @@ class LayoutStatusIsRenderedTest < Test::Unit::TestCase assert_response 401 end end + +class LayoutSymlinkedTest < LayoutTest + layout "symlinked/symlinked_layout" +end + +class LayoutSymlinkedIsRenderedTest < Test::Unit::TestCase + def setup + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + def test_symlinked_layout_is_rendered + @controller = LayoutSymlinkedTest.new + get :hello + assert_response 200 + assert_equal "layouts/symlinked/symlinked_layout", @response.layout + end +end + \ No newline at end of file diff --git a/vendor/rails/actionpack/test/controller/mime_responds_test.rb b/vendor/rails/actionpack/test/controller/mime_responds_test.rb index f121dd9f..c617cb2e 100644 --- a/vendor/rails/actionpack/test/controller/mime_responds_test.rb +++ b/vendor/rails/actionpack/test/controller/mime_responds_test.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../abstract_unit' +require 'abstract_unit' class RespondToController < ActionController::Base layout :set_layout @@ -107,6 +107,13 @@ class RespondToController < ActionController::Base type.any(:js, :xml) { render :text => "Either JS or XML" } end end + + def handle_any_any + respond_to do |type| + type.html { render :text => 'HTML' } + type.any { render :text => 'Whatever you ask for, I got it' } + end + end def all_types_with_layout respond_to do |type| @@ -335,6 +342,35 @@ class MimeControllerTest < Test::Unit::TestCase assert_equal 'Either JS or XML', @response.body end + def test_handle_any_any + @request.env["HTTP_ACCEPT"] = "*/*" + get :handle_any_any + assert_equal 'HTML', @response.body + end + + def test_handle_any_any_parameter_format + get :handle_any_any, {:format=>'html'} + assert_equal 'HTML', @response.body + end + + def test_handle_any_any_explicit_html + @request.env["HTTP_ACCEPT"] = "text/html" + get :handle_any_any + assert_equal 'HTML', @response.body + end + + def test_handle_any_any_javascript + @request.env["HTTP_ACCEPT"] = "text/javascript" + get :handle_any_any + assert_equal 'Whatever you ask for, I got it', @response.body + end + + def test_handle_any_any_xml + @request.env["HTTP_ACCEPT"] = "text/xml" + get :handle_any_any + assert_equal 'Whatever you ask for, I got it', @response.body + end + def test_rjs_type_skips_layout @request.env["HTTP_ACCEPT"] = "text/javascript" get :all_types_with_layout @@ -432,16 +468,12 @@ class MimeControllerTest < Test::Unit::TestCase assert_equal '
Hello future from Firefox!
', @response.body @request.env["HTTP_ACCEPT"] = "text/iphone" - assert_raises(ActionController::MissingTemplate) { get :iphone_with_html_response_type_without_layout } + assert_raises(ActionView::MissingTemplate) { get :iphone_with_html_response_type_without_layout } end end class AbstractPostController < ActionController::Base - class << self - def view_paths - [ File.dirname(__FILE__) + "/../fixtures/post_test/" ] - end - end + self.view_paths = File.dirname(__FILE__) + "/../fixtures/post_test/" end # For testing layouts which are set automatically diff --git a/vendor/rails/actionpack/test/controller/mime_type_test.rb b/vendor/rails/actionpack/test/controller/mime_type_test.rb index d4aea3c0..03b0f8ba 100644 --- a/vendor/rails/actionpack/test/controller/mime_type_test.rb +++ b/vendor/rails/actionpack/test/controller/mime_type_test.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../abstract_unit' +require 'abstract_unit' class MimeTypeTest < Test::Unit::TestCase Mime::Type.register "image/png", :png @@ -28,6 +28,13 @@ class MimeTypeTest < Test::Unit::TestCase expect = [Mime::HTML, Mime::XML, "image/*", Mime::TEXT, Mime::ALL] assert_equal expect, Mime::Type.parse(accept).collect { |c| c.to_s } end + + # Accept header send with user HTTP_USER_AGENT: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; InfoPath.1) + def test_parse_crappy_broken_acceptlines2 + accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, , pronto/1.00.00, sslvpn/1.00.00.00, */*" + expect = ['image/gif', 'image/x-xbitmap', 'image/jpeg','image/pjpeg', 'application/x-shockwave-flash', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint', 'application/msword', 'pronto/1.00.00', 'sslvpn/1.00.00.00', Mime::ALL ] + assert_equal expect, Mime::Type.parse(accept).collect { |c| c.to_s } + end def test_custom_type Mime::Type.register("image/gif", :gif) @@ -39,6 +46,11 @@ class MimeTypeTest < Test::Unit::TestCase Mime.module_eval { remove_const :GIF if const_defined?(:GIF) } end + def test_type_should_be_equal_to_symbol + assert_equal Mime::HTML, 'application/xhtml+xml' + assert_equal Mime::HTML, :html + end + def test_type_convenience_methods types = [:html, :xml, :png, :pdf, :yaml, :url_encoded_form] types.each do |type| diff --git a/vendor/rails/actionpack/test/controller/new_render_test.rb b/vendor/rails/actionpack/test/controller/new_render_test.rb index 3168daea..6e2c6d90 100644 --- a/vendor/rails/actionpack/test/controller/new_render_test.rb +++ b/vendor/rails/actionpack/test/controller/new_render_test.rb @@ -1,5 +1,5 @@ -require File.dirname(__FILE__) + '/../abstract_unit' -require File.dirname(__FILE__) + '/fake_models' +require 'abstract_unit' +require 'controller/fake_models' class CustomersController < ActionController::Base end @@ -17,6 +17,9 @@ module NewRenderTestHelper end end +class LabellingFormBuilder < ActionView::Helpers::FormBuilder +end + class NewRenderTestController < ActionController::Base layout :determine_layout @@ -75,11 +78,6 @@ class NewRenderTestController < ActionController::Base @secret = 'in the sauce' render :file => 'test/render_file_with_ivar', :use_full_path => true end - - def render_file_not_using_full_path_with_relative_path - @secret = 'in the sauce' - render :file => 'test/../test/render_file_with_ivar', :use_full_path => true - end def render_file_not_using_full_path_with_dot_in_path @secret = 'in the sauce' @@ -136,15 +134,50 @@ class NewRenderTestController < ActionController::Base def partial_with_locals render :partial => "customer", :locals => { :customer => Customer.new("david") } end - + + def partial_with_form_builder + render :partial => ActionView::Helpers::FormBuilder.new(:post, nil, @template, {}, Proc.new {}) + end + + def partial_with_form_builder_subclass + render :partial => LabellingFormBuilder.new(:post, nil, @template, {}, Proc.new {}) + end + def partial_collection render :partial => "customer", :collection => [ Customer.new("david"), Customer.new("mary") ] end + + def partial_collection_with_spacer + render :partial => "customer", :spacer_template => "partial_only", :collection => [ Customer.new("david"), Customer.new("mary") ] + end + + def partial_collection_with_counter + render :partial => "customer_counter", :collection => [ Customer.new("david"), Customer.new("mary") ] + end def partial_collection_with_locals render :partial => "customer_greeting", :collection => [ Customer.new("david"), Customer.new("mary") ], :locals => { :greeting => "Bonjour" } end + def partial_collection_shorthand_with_locals + render :partial => [ Customer.new("david"), Customer.new("mary") ], :locals => { :greeting => "Bonjour" } + end + + def partial_collection_shorthand_with_different_types_of_records + render :partial => [ + BadCustomer.new("mark"), + GoodCustomer.new("craig"), + BadCustomer.new("john"), + GoodCustomer.new("zach"), + GoodCustomer.new("brandon"), + BadCustomer.new("dan") ], + :locals => { :greeting => "Bonjour" } + end + + def partial_collection_shorthand_with_different_types_of_records_with_counter + partial_collection_shorthand_with_different_types_of_records + end + def empty_partial_collection render :partial => "customer", :collection => [] end @@ -206,6 +239,18 @@ class NewRenderTestController < ActionController::Base render :inline => "Hello: <%= params[:name] %>" end + def accessing_request_in_template + render :inline => "Hello: <%= request.host %>" + end + + def accessing_logger_in_template + render :inline => "<%= logger.class %>" + end + + def accessing_action_name_in_template + render :inline => "<%= action_name %>" + end + def accessing_params_in_template_with_layout render :layout => nil, :inline => "Hello: <%= params[:name] %>" end @@ -361,10 +406,18 @@ class NewRenderTestController < ActionController::Base render :action => "calling_partial_with_layout" end + def render_call_to_partial_with_layout_in_main_layout_and_within_content_for_layout + render :action => "calling_partial_with_layout" + end + def render_using_layout_around_block render :action => "using_layout_around_block" end + def render_using_layout_around_block_in_main_layout_and_within_content_for_layout + render :action => "using_layout_around_block" + end + def rescue_action(e) raise end private @@ -387,6 +440,10 @@ class NewRenderTestController < ActionController::Base "layouts/builder" when "action_talk_to_layout", "layout_overriding_layout" "layouts/talk_from_action" + when "render_call_to_partial_with_layout_in_main_layout_and_within_content_for_layout" + "layouts/partial_with_layout" + when "render_using_layout_around_block_in_main_layout_and_within_content_for_layout" + "layouts/block_with_layout" end end end @@ -465,11 +522,6 @@ class NewRenderTest < Test::Unit::TestCase assert_equal "The secret is in the sauce\n", @response.body end - def test_render_file_not_using_full_path_with_relative_path - get :render_file_not_using_full_path_with_relative_path - assert_equal "The secret is in the sauce\n", @response.body - end - def test_render_file_not_using_full_path_with_dot_in_path get :render_file_not_using_full_path_with_dot_in_path assert_equal "The secret is in the sauce\n", @response.body @@ -489,25 +541,18 @@ class NewRenderTest < Test::Unit::TestCase end def test_access_to_request_in_view - view_internals_old_value = ActionController::Base.view_controller_internals + get :accessing_request_in_template + assert_equal "Hello: www.nextangle.com", @response.body + end - ActionController::Base.view_controller_internals = false - ActionController::Base.protected_variables_cache = nil - - get :hello_world - assert !assigns.include?('request'), 'request should not be in assigns' - - ActionController::Base.view_controller_internals = true - ActionController::Base.protected_variables_cache = nil - - get :hello_world - assert !assigns.include?('request'), 'request should not be in assigns' - assert_kind_of ActionController::AbstractRequest, assigns['_request'] - assert_kind_of ActionController::AbstractRequest, @response.template.request - - ensure - ActionController::Base.view_controller_internals = view_internals_old_value - ActionController::Base.protected_variables_cache = nil + def test_access_to_logger_in_view + 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_render_xml @@ -532,6 +577,12 @@ EOS assert_equal "

This is grand!

\n", @response.body end + def test_render_with_default_from_accept_header + @request.env["HTTP_ACCEPT"] = "text/javascript" + get :greeting + assert_equal "$(\"body\").visualEffect(\"highlight\");", @response.body + end + def test_render_rjs_with_default get :delete_with_js assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body @@ -605,7 +656,7 @@ EOS end def test_bad_render_to_string_still_throws_exception - assert_raises(ActionController::MissingTemplate) { get :render_to_string_with_exception } + assert_raises(ActionView::MissingTemplate) { get :render_to_string_with_exception } end def test_render_to_string_that_throws_caught_exception_doesnt_break_assigns @@ -672,15 +723,47 @@ EOS assert_equal "Hello: david", @response.body end + def test_partial_with_form_builder + get :partial_with_form_builder + assert_match(/