From 664552ac021ce4b366092adbb32dbce3a2fbce2a Mon Sep 17 00:00:00 2001 From: Jacques Distler Date: Tue, 4 Aug 2009 10:16:03 -0500 Subject: [PATCH] Rails 2.3.3.1 Update to latest Rails. A little bit of jiggery-pokery is involved, since they neglected to re-include vendored Rack in this release. --- test/functional/admin_controller_test.rb | 21 +- test/functional/wiki_controller_test.rb | 46 +- vendor/rails/actionmailer/CHANGELOG | 4 + vendor/rails/actionmailer/Rakefile | 5 +- .../actionmailer/lib/action_mailer/base.rb | 2 +- .../actionmailer/lib/action_mailer/version.rb | 2 +- .../rails/actionmailer/test/abstract_unit.rb | 3 - vendor/rails/actionpack/CHANGELOG | 5 + vendor/rails/actionpack/Rakefile | 6 +- .../rails/actionpack/lib/action_controller.rb | 5 +- .../assertions/response_assertions.rb | 14 +- .../actionpack/lib/action_controller/base.rb | 9 +- .../lib/action_controller/caching.rb | 2 +- .../lib/action_controller/caching/actions.rb | 10 +- .../lib/action_controller/caching/sweeper.rb | 45 ++ .../lib/action_controller/caching/sweeping.rb | 42 -- .../lib/action_controller/failsafe.rb | 46 +- .../actionpack/lib/action_controller/flash.rb | 14 +- .../action_controller/http_authentication.rb | 7 +- .../lib/action_controller/integration.rb | 15 +- .../lib/action_controller/middlewares.rb | 1 - .../lib/action_controller/reloader.rb | 37 +- .../lib/action_controller/request.rb | 8 +- .../lib/action_controller/response.rb | 4 +- .../lib/action_controller/rewindable_input.rb | 28 -- .../action_controller/routing/route_set.rb | 3 +- .../lib/action_controller/streaming.rb | 2 +- .../lib/action_controller/test_process.rb | 10 +- .../vendor/rack-1.0/rack/reloader.rb | 64 --- .../vendor/{rack-1.0 => rack-1.1.pre}/rack.rb | 7 +- .../rack/adapter/camping.rb | 0 .../rack/auth/abstract/handler.rb | 0 .../rack/auth/abstract/request.rb | 0 .../rack/auth/basic.rb | 0 .../rack/auth/digest/md5.rb | 0 .../rack/auth/digest/nonce.rb | 0 .../rack/auth/digest/params.rb | 0 .../rack/auth/digest/request.rb | 0 .../rack/auth/openid.rb | 0 .../rack/builder.rb | 0 .../rack/cascade.rb | 0 .../rack/chunked.rb | 0 .../rack/commonlogger.rb | 0 .../rack/conditionalget.rb | 2 + .../rack/content_length.rb | 0 .../rack/content_type.rb | 0 .../rack/deflater.rb | 71 +-- .../rack/directory.rb | 0 .../{rack-1.0 => rack-1.1.pre}/rack/file.rb | 0 .../rack/handler.rb | 23 +- .../rack/handler/cgi.rb | 2 +- .../rack/handler/evented_mongrel.rb | 0 .../rack/handler/fastcgi.rb | 47 +- .../rack/handler/lsws.rb | 2 +- .../rack/handler/mongrel.rb | 4 +- .../rack/handler/scgi.rb | 8 +- .../rack/handler/swiftiplied_mongrel.rb | 0 .../rack/handler/thin.rb | 0 .../rack/handler/webrick.rb | 2 +- .../{rack-1.0 => rack-1.1.pre}/rack/head.rb | 0 .../{rack-1.0 => rack-1.1.pre}/rack/lint.rb | 127 ++++- .../rack/lobster.rb | 0 .../{rack-1.0 => rack-1.1.pre}/rack/lock.rb | 0 .../rack/methodoverride.rb | 0 .../{rack-1.0 => rack-1.1.pre}/rack/mime.rb | 0 .../{rack-1.0 => rack-1.1.pre}/rack/mock.rb | 30 +- .../rack/recursive.rb | 0 .../vendor/rack-1.1.pre/rack/reloader.rb | 106 +++++ .../rack/request.rb | 37 +- .../rack/response.rb | 6 +- .../rack-1.1.pre/rack/rewindable_input.rb | 98 ++++ .../rack/session/abstract/id.rb | 0 .../rack/session/cookie.rb | 0 .../rack/session/memcache.rb | 0 .../rack/session/pool.rb | 0 .../rack/showexceptions.rb | 0 .../rack/showstatus.rb | 0 .../{rack-1.0 => rack-1.1.pre}/rack/static.rb | 0 .../{rack-1.0 => rack-1.1.pre}/rack/urlmap.rb | 2 +- .../{rack-1.0 => rack-1.1.pre}/rack/utils.rb | 158 +++++- .../actionpack/lib/action_pack/version.rb | 2 +- .../actionpack/lib/action_view/helpers.rb | 2 +- .../action_view/helpers/asset_tag_helper.rb | 30 +- .../lib/action_view/helpers/form_helper.rb | 37 +- .../helpers/form_options_helper.rb | 2 + .../action_view/helpers/form_tag_helper.rb | 14 +- .../action_view/helpers/prototype_helper.rb | 14 +- .../helpers/scriptaculous_helper.rb | 10 +- .../lib/action_view/helpers/text_helper.rb | 6 +- .../lib/action_view/helpers/url_helper.rb | 2 +- .../rails/actionpack/lib/action_view/paths.rb | 2 +- .../actionpack/lib/action_view/template.rb | 59 +-- vendor/rails/actionpack/test/abstract_unit.rb | 2 +- .../activerecord/active_record_store_test.rb | 6 +- .../controller/action_pack_assertions_test.rb | 27 ++ .../test/controller/caching_test.rb | 39 ++ .../actionpack/test/controller/cookie_test.rb | 10 + .../test/controller/dispatcher_test.rb | 16 +- .../test/controller/failsafe_test.rb | 60 +++ .../test/controller/filter_params_test.rb | 3 +- .../actionpack/test/controller/flash_test.rb | 7 +- .../http_digest_authentication_test.rb | 37 +- .../test/controller/integration_test.rb | 28 ++ .../test/controller/redirect_test.rb | 5 +- .../test/controller/reloader_test.rb | 97 ++++ .../actionpack/test/controller/render_test.rb | 28 +- .../request/multipart_params_parsing_test.rb | 63 +-- .../controller/request/test_request_test.rb | 35 ++ .../url_encoded_params_parsing_test.rb | 38 -- .../test/controller/request_test.rb | 448 +++++++++--------- .../test/controller/resources_test.rb | 8 + .../test/controller/routing_test.rb | 21 + .../test/controller/send_file_test.rb | 2 +- .../controller/session/cookie_store_test.rb | 21 - .../actionpack/test/controller/test_test.rb | 8 + .../test/fixtures/failsafe/500.html | 1 + .../template/active_record_helper_test.rb | 2 +- .../test/template/asset_tag_helper_test.rb | 46 ++ .../test/template/form_helper_test.rb | 123 ++++- .../test/template/form_options_helper_test.rb | 22 + .../test/template/form_tag_helper_test.rb | 29 +- .../test/template/prototype_helper_test.rb | 22 +- .../actionpack/test/template/template_test.rb | 32 ++ vendor/rails/activerecord/CHANGELOG | 11 + vendor/rails/activerecord/Rakefile | 5 +- .../lib/active_record/associations.rb | 97 ++-- .../associations/association_proxy.rb | 4 +- .../associations/belongs_to_association.rb | 26 +- .../belongs_to_polymorphic_association.rb | 6 +- .../has_one_through_association.rb | 16 +- .../lib/active_record/autosave_association.rb | 17 +- .../activerecord/lib/active_record/base.rb | 33 +- .../lib/active_record/calculations.rb | 18 +- .../connection_adapters/postgresql_adapter.rb | 88 +++- .../connection_adapters/sqlite_adapter.rb | 3 + .../lib/active_record/fixtures.rb | 9 +- .../lib/active_record/named_scope.rb | 4 +- .../lib/active_record/schema_dumper.rb | 6 +- .../lib/active_record/serialization.rb | 5 +- .../serializers/json_serializer.rb | 26 +- .../lib/active_record/session_store.rb | 10 +- .../lib/active_record/timestamp.rb | 48 +- .../activerecord/lib/active_record/version.rb | 2 +- .../belongs_to_associations_test.rb | 106 ++++- .../test/cases/associations/eager_test.rb | 12 + .../has_many_associations_test.rb | 6 + .../has_one_through_associations_test.rb | 9 +- .../inner_join_association_test.rb | 5 + .../test/cases/autosave_association_test.rb | 22 + .../activerecord/test/cases/base_test.rb | 4 +- .../test/cases/calculations_test.rb | 22 +- .../test/cases/copy_table_test_sqlite.rb | 10 +- .../activerecord/test/cases/finder_test.rb | 6 + .../activerecord/test/cases/fixtures_test.rb | 5 + .../rails/activerecord/test/cases/helper.rb | 3 +- .../test/cases/json_serialization_test.rb | 114 ++--- .../test/cases/method_scoping_test.rb | 16 +- .../test/cases/reflection_test.rb | 10 +- .../test/cases/schema_dumper_test.rb | 24 +- .../test/cases/schema_test_postgresql.rb | 76 +++ .../activerecord/test/cases/timestamp_test.rb | 75 +++ .../rails/activerecord/test/models/author.rb | 4 + .../rails/activerecord/test/models/company.rb | 14 +- .../activerecord/test/models/developer.rb | 10 + .../rails/activerecord/test/models/essay.rb | 3 + vendor/rails/activerecord/test/models/pet.rb | 2 +- .../rails/activerecord/test/models/project.rb | 2 +- .../rails/activerecord/test/models/reply.rb | 3 +- .../rails/activerecord/test/models/topic.rb | 1 + vendor/rails/activerecord/test/models/toy.rb | 2 + .../rails/activerecord/test/schema/schema.rb | 15 + vendor/rails/activeresource/CHANGELOG | 4 + vendor/rails/activeresource/Rakefile | 5 +- .../lib/active_resource/base.rb | 18 +- .../active_resource/formats/json_format.rb | 4 +- .../lib/active_resource/version.rb | 2 +- .../activeresource/test/abstract_unit.rb | 4 +- vendor/rails/activesupport/CHANGELOG | 7 + .../activesupport/lib/active_support/cache.rb | 15 +- .../active_support/cache/mem_cache_store.rb | 26 +- .../cache/strategy/local_cache.rb | 2 +- .../core_ext/hash/conversions.rb | 17 +- .../core_ext/kernel/debugger.rb | 6 +- .../core_ext/module/attribute_accessors.rb | 2 + .../core_ext/module/delegation.rb | 15 +- .../core_ext/module/model_naming.rb | 14 +- .../active_support/core_ext/numeric/bytes.rb | 24 +- .../active_support/core_ext/string/access.rb | 34 +- .../lib/active_support/duration.rb | 6 +- .../activesupport/lib/active_support/json.rb | 23 +- .../active_support/json/backends/jsongem.rb | 38 ++ .../lib/active_support/json/backends/yaml.rb | 85 ++++ .../lib/active_support/json/decoding.rb | 95 +--- .../lib/active_support/json/encoders/date.rb | 17 +- .../active_support/json/encoders/date_time.rb | 17 +- .../json/encoders/enumerable.rb | 23 +- .../json/encoders/false_class.rb | 6 +- .../lib/active_support/json/encoders/hash.rb | 32 +- .../active_support/json/encoders/nil_class.rb | 6 +- .../active_support/json/encoders/numeric.rb | 16 + .../active_support/json/encoders/object.rb | 8 +- .../active_support/json/encoders/regexp.rb | 4 + .../active_support/json/encoders/string.rb | 37 +- .../active_support/json/encoders/symbol.rb | 4 +- .../lib/active_support/json/encoders/time.rb | 17 +- .../json/encoders/true_class.rb | 6 +- .../lib/active_support/json/encoding.rb | 89 +++- .../lib/active_support/ordered_hash.rb | 28 ++ .../lib/active_support/test_case.rb | 14 +- .../lib/active_support/testing/deprecation.rb | 2 + .../lib/active_support/time_with_zone.rb | 17 +- .../lib/active_support/vendor.rb | 13 +- .../i18n-0.1.3/test/i18n_exceptions_test.rb | 1 - .../vendor/i18n-0.1.3/test/i18n_test.rb | 1 - .../i18n-0.1.3/test/simple_backend_test.rb | 1 - .../memcache.rb | 316 +++++++++--- .../lib/active_support/version.rb | 2 +- .../lib/active_support/xml_mini/jdom.rb | 162 +++++++ .../activesupport/memcached_get_multi.diff | 0 .../rails/activesupport/test/abstract_unit.rb | 3 +- .../rails/activesupport/test/caching_test.rb | 57 ++- .../test/core_ext/duration_test.rb | 9 +- .../test/core_ext/hash_ext_test.rb | 82 +++- .../test/core_ext/module/model_naming_test.rb | 8 + .../test/core_ext/module_test.rb | 2 +- .../test/core_ext/string_ext_test.rb | 2 + .../test/core_ext/time_with_zone_test.rb | 4 +- .../activesupport/test/json/decoding_test.rb | 82 ++-- .../activesupport/test/json/encoding_test.rb | 58 ++- .../activesupport/test/ordered_hash_test.rb | 33 ++ .../test/xml_mini/jdom_engine_test.rb | 153 ++++++ vendor/rails/ci/geminstaller.yml | 4 +- vendor/rails/railties/CHANGELOG | 4 + vendor/rails/railties/Rakefile | 19 +- vendor/rails/railties/configs/routes.rb | 2 +- vendor/rails/railties/guides/rails_guides.rb | 30 +- .../railties/guides/rails_guides/generator.rb | 34 -- .../guides/rails_guides/levenshtein.rb | 112 ----- .../lib/commands/performance/profiler.rb | 2 +- vendor/rails/railties/lib/initializer.rb | 31 +- .../railties/lib/rails/gem_dependency.rb | 41 +- vendor/rails/railties/lib/rails/rack/metal.rb | 2 +- vendor/rails/railties/lib/rails/version.rb | 2 +- vendor/rails/railties/lib/tasks/gems.rake | 25 +- vendor/rails/railties/lib/test_help.rb | 5 +- vendor/rails/railties/test/abstract_unit.rb | 3 - .../railties/test/gem_dependency_test.rb | 74 ++- .../rails/railties/test/initializer_test.rb | 23 +- .../gems/dummy-gem-h-1.0.0/.specification | 29 ++ .../gems/dummy-gem-h-1.0.0/lib/dummy-gem-h.rb | 1 + .../gems/dummy-gem-i-1.0.0/.specification | 41 ++ .../ext/dummy-gem-i/Makefile | 0 .../gems/dummy-gem-i-1.0.0/lib/dummy-gem-i.rb | 1 + .../gems/dummy-gem-j-1.0.0/.specification | 41 ++ .../gems/dummy-gem-j-1.0.0/lib/dummy-gem-j.rb | 1 + .../gems/dummy-gem-k-1.0.0/.specification | 49 ++ .../gems/dummy-gem-k-1.0.0/lib/dummy-gem-k.rb | 1 + 257 files changed, 4346 insertions(+), 1682 deletions(-) create mode 100644 vendor/rails/actionpack/lib/action_controller/caching/sweeper.rb delete mode 100644 vendor/rails/actionpack/lib/action_controller/rewindable_input.rb delete mode 100644 vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/reloader.rb rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack.rb (95%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/adapter/camping.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/auth/abstract/handler.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/auth/abstract/request.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/auth/basic.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/auth/digest/md5.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/auth/digest/nonce.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/auth/digest/params.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/auth/digest/request.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/auth/openid.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/builder.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/cascade.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/chunked.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/commonlogger.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/conditionalget.rb (94%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/content_length.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/content_type.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/deflater.rb (54%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/directory.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/file.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/handler.rb (68%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/handler/cgi.rb (97%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/handler/evented_mongrel.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/handler/fastcgi.rb (72%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/handler/lsws.rb (97%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/handler/mongrel.rb (97%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/handler/scgi.rb (96%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/handler/swiftiplied_mongrel.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/handler/thin.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/handler/webrick.rb (97%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/head.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/lint.rb (77%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/lobster.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/lock.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/methodoverride.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/mime.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/mock.rb (75%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/recursive.rb (100%) create mode 100644 vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/reloader.rb rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/request.rb (88%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/response.rb (97%) create mode 100644 vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/rewindable_input.rb rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/session/abstract/id.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/session/cookie.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/session/memcache.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/session/pool.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/showexceptions.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/showstatus.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/static.rb (100%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/urlmap.rb (95%) rename vendor/rails/actionpack/lib/action_controller/vendor/{rack-1.0 => rack-1.1.pre}/rack/utils.rb (69%) create mode 100644 vendor/rails/actionpack/test/controller/failsafe_test.rb create mode 100644 vendor/rails/actionpack/test/controller/reloader_test.rb create mode 100644 vendor/rails/actionpack/test/controller/request/test_request_test.rb create mode 100644 vendor/rails/actionpack/test/fixtures/failsafe/500.html create mode 100644 vendor/rails/actionpack/test/template/template_test.rb create mode 100644 vendor/rails/activerecord/test/cases/timestamp_test.rb create mode 100644 vendor/rails/activerecord/test/models/essay.rb create mode 100644 vendor/rails/activesupport/lib/active_support/json/backends/jsongem.rb create mode 100644 vendor/rails/activesupport/lib/active_support/json/backends/yaml.rb rename vendor/rails/activesupport/lib/active_support/vendor/{memcache-client-1.6.5 => memcache-client-1.7.4}/memcache.rb (73%) create mode 100644 vendor/rails/activesupport/lib/active_support/xml_mini/jdom.rb create mode 100644 vendor/rails/activesupport/memcached_get_multi.diff create mode 100644 vendor/rails/activesupport/test/xml_mini/jdom_engine_test.rb delete mode 100644 vendor/rails/railties/guides/rails_guides/levenshtein.rb create mode 100644 vendor/rails/railties/test/vendor/gems/dummy-gem-h-1.0.0/.specification create mode 100644 vendor/rails/railties/test/vendor/gems/dummy-gem-h-1.0.0/lib/dummy-gem-h.rb create mode 100644 vendor/rails/railties/test/vendor/gems/dummy-gem-i-1.0.0/.specification create mode 100644 vendor/rails/railties/test/vendor/gems/dummy-gem-i-1.0.0/ext/dummy-gem-i/Makefile create mode 100644 vendor/rails/railties/test/vendor/gems/dummy-gem-i-1.0.0/lib/dummy-gem-i.rb create mode 100644 vendor/rails/railties/test/vendor/gems/dummy-gem-j-1.0.0/.specification create mode 100644 vendor/rails/railties/test/vendor/gems/dummy-gem-j-1.0.0/lib/dummy-gem-j.rb create mode 100644 vendor/rails/railties/test/vendor/gems/dummy-gem-k-1.0.0/.specification create mode 100644 vendor/rails/railties/test/vendor/gems/dummy-gem-k-1.0.0/lib/dummy-gem-k.rb diff --git a/test/functional/admin_controller_test.rb b/test/functional/admin_controller_test.rb index 4ad3c225..11de0795 100644 --- a/test/functional/admin_controller_test.rb +++ b/test/functional/admin_controller_test.rb @@ -58,7 +58,7 @@ class AdminControllerTest < ActionController::TestCase process 'create_system', 'password' => 'a_password', 'web_name' => 'My Wiki', 'web_address' => 'my_wiki' - assert_redirected_to :web => @wiki.webs.keys.first, :action => 'show', :id => 'HomePage' + assert_redirected_to :web => @wiki.webs.keys.first, :controller => 'wiki', :action => 'show', :id => 'HomePage' assert_equal wiki_before, @wiki # and no new web should be created either assert_equal old_size, @wiki.webs.size @@ -68,7 +68,7 @@ class AdminControllerTest < ActionController::TestCase def test_create_system_no_form_and_wiki_already_initialized assert @wiki.setup? process('create_system') - assert_redirected_to :web => @wiki.webs.keys.first, :action => 'show', :id => 'HomePage' + assert_redirected_to :web => @wiki.webs.keys.first, :controller => 'wiki', :action => 'show', :id => 'HomePage' assert(@response.has_flash_object?(:error)) end @@ -78,7 +78,7 @@ class AdminControllerTest < ActionController::TestCase process 'create_web', 'system_password' => 'pswd', 'name' => 'Wiki Two', 'address' => 'wiki2' - assert_redirected_to :web => 'wiki2', :action => 'new', :id => 'HomePage' + assert_redirected_to :web => 'wiki2', :controller => 'wiki', :action => 'new', :id => 'HomePage' wiki2 = @wiki.webs['wiki2'] assert wiki2 assert_equal 'Wiki Two', wiki2.name @@ -90,7 +90,7 @@ class AdminControllerTest < ActionController::TestCase process 'create_web', 'system_password' => 'instiki', 'name' => 'Wiki Two', 'address' => 'wiki2' - assert_redirected_to :web => 'wiki2', :action => 'new', :id => 'HomePage' + assert_redirected_to :web => 'wiki2', :controller => 'wiki', :action => 'new', :id => 'HomePage' end def test_create_web_failed_authentication @@ -98,7 +98,7 @@ class AdminControllerTest < ActionController::TestCase process 'create_web', 'system_password' => 'wrong', 'name' => 'Wiki Two', 'address' => 'wiki2' - assert_redirected_to :web => nil, :action => 'create_web' + assert_redirected_to :controller => 'admin', :action => 'create_web' assert_nil @wiki.webs['wiki2'] end @@ -108,7 +108,6 @@ class AdminControllerTest < ActionController::TestCase assert_response :success end - def test_edit_web_no_form process 'edit_web', 'web' => 'wiki1' # this action simply renders a form @@ -125,7 +124,7 @@ class AdminControllerTest < ActionController::TestCase 'brackets_only' => 'on', 'count_pages' => 'on', 'allow_uploads' => 'on', 'max_upload_size' => '300') - assert_redirected_to :web => 'renamed_wiki1', :action => 'show', :id => 'HomePage' + assert_redirected_to :web => 'renamed_wiki1', :controller => 'wiki', :action => 'show', :id => 'HomePage' @web = Web.find(@web.id) assert_equal 'renamed_wiki1', @web.address assert_equal 'Renamed Wiki1', @web.name @@ -164,7 +163,7 @@ class AdminControllerTest < ActionController::TestCase # safe_mode, published, brackets_only, count_pages, allow_uploads not set # and should become false - assert_redirected_to :web => 'renamed_wiki1', :action => 'show', :id => 'HomePage' + assert_redirected_to :web => 'renamed_wiki1', :controller => 'wiki', :action => 'show', :id => 'HomePage' @web = Web.find(@web.id) assert !@web.safe_mode? assert !@web.published? @@ -237,7 +236,7 @@ class AdminControllerTest < ActionController::TestCase # third pass does not destroy HomePage r = process('remove_orphaned_pages', 'web' => 'wiki1', 'system_password_orphaned' => 'pswd') - assert_redirected_to :action => 'list' + assert_redirected_to :web => 'wiki1', :controller => 'wiki', :action => 'list' @web.pages(true) assert_equal page_order, @web.select.sort, "Pages are not as expected: #{@web.select.sort.map {|p| p.name}.inspect}" @@ -271,14 +270,14 @@ class AdminControllerTest < ActionController::TestCase # third pass does does nothing, since there are no pages in the # 'leaves' category. r = process('remove_orphaned_pages_in_category', 'web' => 'wiki1', 'category' => 'leaves', 'system_password_orphaned_in_category' => 'pswd') - assert_redirected_to :action => 'list' + assert_redirected_to :controller => 'wiki', :web => 'wiki1', :action => 'list' @web.pages(true) assert_equal page_order, @web.select.sort, "Pages are not as expected: #{@web.select.sort.map {|p| p.name}.inspect}" # fourth pass destroys Oak r = process('remove_orphaned_pages_in_category', 'web' => 'wiki1', 'category' => 'trees', 'system_password_orphaned_in_category' => 'pswd') - assert_redirected_to :action => 'list' + assert_redirected_to :controller => 'wiki', :web => 'wiki1', :action => 'list' @web.pages(true) page_order.delete(@oak) assert_equal page_order, @web.select.sort, diff --git a/test/functional/wiki_controller_test.rb b/test/functional/wiki_controller_test.rb index dc226443..dc0a64a1 100755 --- a/test/functional/wiki_controller_test.rb +++ b/test/functional/wiki_controller_test.rb @@ -39,7 +39,7 @@ class WikiControllerTest < ActionController::TestCase set_web_property :password, 'pswd' get :authenticate, :web => 'wiki1', :password => 'pswd' - assert_redirected_to :web => 'wiki1', :action => 'show', :id => 'HomePage' + assert_redirected_to :web => 'wiki1', :controller => 'wiki', :action => 'show', :id => 'HomePage' assert_equal 'pswd', @response.cookies['wiki1'] end @@ -47,7 +47,7 @@ class WikiControllerTest < ActionController::TestCase set_web_property :password, 'pswd' r = process('authenticate', 'web' => 'wiki1', 'password' => 'wrong password') - assert_redirected_to :action => 'login', :web => 'wiki1' + assert_redirected_to :action => 'login', :controller => 'wiki', :web => 'wiki1' assert_nil r.cookies['web_address'] end @@ -72,7 +72,7 @@ class WikiControllerTest < ActionController::TestCase r = process('cancel_edit', 'web' => 'wiki1', 'id' => 'Oak') - assert_redirected_to :action => 'show', :id => 'Oak' + assert_redirected_to :web => 'wiki1', :controller => 'wiki', :action => 'show', :id => 'Oak' assert !Page.find(@oak.id).locked?(Time.now) end @@ -85,7 +85,7 @@ class WikiControllerTest < ActionController::TestCase def test_edit_page_locked_page @home.lock(Time.now, 'Locky') process 'edit', 'web' => 'wiki1', 'id' => 'HomePage' - assert_redirected_to :action => 'locked' + assert_redirected_to :web => 'wiki1', :controller => 'wiki', :action => 'locked', :id => 'HomePage' end def test_edit_page_break_lock @@ -233,19 +233,19 @@ class WikiControllerTest < ActionController::TestCase # delete extra web fixture webs(:instiki).destroy process('index') - assert_redirected_to :web => 'wiki1', :action => 'show', :id => 'HomePage' + assert_redirected_to :web => 'wiki1', :controller => 'wiki', :action => 'show', :id => 'HomePage' end def test_index_multiple_webs @wiki.create_web('Test Wiki 2', 'wiki2') process('index') - assert_redirected_to :action => 'web_list' + assert_redirected_to :controller => 'wiki', :action => 'web_list' end def test_index_multiple_webs_web_explicit @wiki.create_web('Test Wiki 2', 'wiki2') process('index', 'web' => 'wiki2') - assert_redirected_to :web => 'wiki2', :action => 'show', :id => 'HomePage' + assert_redirected_to :web => 'wiki2', :controller => 'wiki', :action => 'show', :id => 'HomePage' end def test_index_wiki_not_initialized @@ -598,7 +598,7 @@ class WikiControllerTest < ActionController::TestCase r = process 'save', 'web' => 'wiki1', 'id' => 'NewPage', 'content' => 'Contents of a new page', 'author' => 'AuthorOfNewPage' - assert_redirected_to :web => 'wiki1', :action => 'show', :id => 'NewPage' + assert_redirected_to :web => 'wiki1', :controller => 'wiki', :action => 'show', :id => 'NewPage' assert_equal 'AuthorOfNewPage', r.cookies['author'] assert_match @eternity, r.headers["Set-Cookie"][0] new_page = @wiki.read_page('wiki1', 'NewPage') @@ -610,7 +610,7 @@ class WikiControllerTest < ActionController::TestCase r = process 'save', 'web' => 'wiki1', 'id' => 'NewPage', 'content' => "Contents of a new page\r\n\000", 'author' => 'AuthorOfNewPage' - assert_redirected_to :web => 'wiki1', :action => 'new', :id => 'NewPage', :content => '' + assert_redirected_to :web => 'wiki1', :controller => 'wiki', :action => 'new', :id => 'NewPage', :content => '' assert_equal 'AuthorOfNewPage', r.cookies['author'] assert_match @eternity, r.headers["Set-Cookie"][0] end @@ -619,7 +619,7 @@ class WikiControllerTest < ActionController::TestCase r = process 'save', 'web' => 'wiki1', 'id' => 'NewPage', 'content' => "Contents of a new page\r\n￾", 'author' => 'AuthorOfNewPage' - assert_redirected_to :web => 'wiki1', :action => 'new', :id => 'NewPage' + assert_redirected_to :web => 'wiki1', :controller => 'wiki', :action => 'new', :id => 'NewPage', :content => '' assert_equal 'AuthorOfNewPage', r.cookies['author'] assert_match @eternity, r.headers["Set-Cookie"][0] end @@ -628,7 +628,7 @@ class WikiControllerTest < ActionController::TestCase r = process 'save', 'web' => 'wiki1', 'id' => 'NewPage', 'content' => "Contents of a new page\r\n￿", 'author' => 'AuthorOfNewPage' - assert_redirected_to :web => 'wiki1', :action => 'new', :id => 'NewPage' + assert_redirected_to :web => 'wiki1', :controller => 'wiki', :action => 'new', :id => 'NewPage', :content => '' assert_equal 'AuthorOfNewPage', r.cookies['author'] assert_match @eternity, r.headers["Set-Cookie"][0] end @@ -640,7 +640,7 @@ class WikiControllerTest < ActionController::TestCase r = process 'save', 'web' => 'wiki1', 'id' => 'HomePage', 'content' => 'Revised HomePage', 'author' => 'Batman' - assert_redirected_to :web => 'wiki1', :action => 'show', :id => 'HomePage' + assert_redirected_to :web => 'wiki1', :controller => 'wiki', :action => 'show', :id => 'HomePage' assert_equal 'Batman', r.cookies['author'] home_page = @wiki.read_page('wiki1', 'HomePage') assert_equal current_revisions+1, home_page.revisions.size @@ -656,7 +656,7 @@ class WikiControllerTest < ActionController::TestCase r = process 'save', 'web' => 'wiki1', 'id' => 'HomePage', 'content' => "Revised HomePage\000", 'author' => 'Batman' - assert_redirected_to :web => 'wiki1', :action => 'edit', :id => 'HomePage', + assert_redirected_to :web => 'wiki1', :controller => 'wiki', :action => 'edit', :id => 'HomePage', :content => 'HisWay would be MyWay $\sin(x)\begin{svg}\end{svg}\includegraphics[width' + '=3em]{foo}$ in kinda ThatWay in HisWay though MyWay \OverThere -- see SmartEng' + 'ine in that SmartEngineGUI' @@ -688,7 +688,10 @@ class WikiControllerTest < ActionController::TestCase r = process 'save', {'web' => 'wiki1', 'id' => 'HomePage', 'content' => @home.revisions.last.content.dup + "\n Try viagra.\n", 'author' => 'SomeOtherAuthor'}, {:return_to => '/wiki1/show/HomePage'} - assert_redirected_to :action => 'edit', :web => 'wiki1', :id => 'HomePage' + assert_redirected_to :action => 'edit', :controller => 'wiki', :web => 'wiki1', :id => 'HomePage', + :content => 'HisWay would be MyWay $\sin(x)\begin{svg}\end{svg}\includegraphics[width=3e'+ + 'm]{foo}$ in kinda ThatWay in HisWay though MyWay \OverThere -- see SmartEngine in'+ + " that SmartEngineGUI\n Try viagra.\n" assert r.flash[:error].to_s == "Your edit was blocked by spam filtering" end @@ -700,7 +703,10 @@ class WikiControllerTest < ActionController::TestCase 'content' => @home.revisions.last.content.dup, 'author' => 'SomeOtherAuthor'}, {:return_to => '/wiki1/show/HomePage'} - assert_redirected_to :action => 'edit', :web => 'wiki1', :id => 'HomePage' + assert_redirected_to :action => 'edit', :controller => 'wiki', :web => 'wiki1', :id => 'HomePage', + :content => 'HisWay would be MyWay $\sin(x)\begin{svg}\end{svg}\includegraphics[width=3e'+ + 'm]{foo}$ in kinda ThatWay in HisWay though MyWay \OverThere -- see SmartEngine in'+ + ' that SmartEngineGUI' assert r.flash[:error].to_s == "You have tried to save page 'HomePage' without changing its content" revisions_after = @home.revisions.size @@ -717,7 +723,7 @@ class WikiControllerTest < ActionController::TestCase 'content' => @liquor.revisions.last.content.dup, 'new_name' => 'booze', 'author' => 'SomeOtherAuthor'}, {:return_to => '/wiki1/show/booze'} - assert_redirected_to :action => 'show', :web => 'wiki1', :id => 'booze' + assert_redirected_to :action => 'show', :controller => 'wiki', :web => 'wiki1', :id => 'booze' revisions_after = @liquor.revisions.size assert_equal revisions_before + 1, revisions_after @@ -741,20 +747,20 @@ class WikiControllerTest < ActionController::TestCase def test_save_invalid_author_name r = process 'save', 'web' => 'wiki1', 'id' => 'NewPage', 'content' => 'Contents of a new page', 'author' => 'foo.bar' - assert_redirected_to :action => 'new', :web => 'wiki1', :id => 'NewPage' + assert_redirected_to :action => 'new', :controller => 'wiki', :web => 'wiki1', :id => 'NewPage' assert r.flash[:error].to_s == 'Your name cannot contain a "."' r = process 'save', 'web' => 'wiki1', 'id' => 'AnotherPage', 'content' => 'Contents of a new page', 'author' => "\000" - assert_redirected_to :action => 'new', :web => 'wiki1', :id => 'AnotherPage' + assert_redirected_to :action => 'new', :controller => 'wiki', :web => 'wiki1', :id => 'AnotherPage' assert r.flash[:error].to_s == "Your name was not valid utf-8" end def test_search r = process 'search', 'web' => 'wiki1', 'query' => '\s[A-Z]ak' - assert_redirected_to :action => 'show', :id => 'Oak' + assert_redirected_to :web => 'wiki1', :action => 'show', :controller => 'wiki', :id => 'Oak' end def test_search_multiple_results @@ -873,7 +879,7 @@ class WikiControllerTest < ActionController::TestCase def test_show_page_nonexistant_page process('show', 'id' => 'UnknownPage', 'web' => 'wiki1') - assert_redirected_to :web => 'wiki1', :action => 'new', :id => 'UnknownPage' + assert_redirected_to :web => 'wiki1', :controller => 'wiki', :action => 'new', :id => 'UnknownPage' end def test_show_no_page diff --git a/vendor/rails/actionmailer/CHANGELOG b/vendor/rails/actionmailer/CHANGELOG index 773e603d..4090dd81 100644 --- a/vendor/rails/actionmailer/CHANGELOG +++ b/vendor/rails/actionmailer/CHANGELOG @@ -1,3 +1,7 @@ +*2.3.3 (July 12, 2009)* + +* No changes, just a version bump. + *2.3.2 [Final] (March 15, 2009)* * Fixed that ActionMailer should send correctly formatted Return-Path in MAIL FROM for SMTP #1842 [Matt Jones] diff --git a/vendor/rails/actionmailer/Rakefile b/vendor/rails/actionmailer/Rakefile index f06f18ff..e6dc2591 100644 --- a/vendor/rails/actionmailer/Rakefile +++ b/vendor/rails/actionmailer/Rakefile @@ -4,7 +4,6 @@ require 'rake/testtask' require 'rake/rdoctask' require 'rake/packagetask' require 'rake/gempackagetask' -require 'rake/contrib/sshpublisher' require File.join(File.dirname(__FILE__), 'lib', 'action_mailer', 'version') PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : '' @@ -55,7 +54,7 @@ spec = Gem::Specification.new do |s| s.rubyforge_project = "actionmailer" s.homepage = "http://www.rubyonrails.org" - s.add_dependency('actionpack', '= 2.3.2' + PKG_BUILD) + s.add_dependency('actionpack', '= 2.3.3' + PKG_BUILD) s.has_rdoc = true s.requirements << 'none' @@ -76,12 +75,14 @@ end desc "Publish the API documentation" task :pgem => [:package] do + require 'rake/contrib/sshpublisher' Rake::SshFilePublisher.new("gems.rubyonrails.org", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload `ssh gems.rubyonrails.org '/u/sites/gems/gemupdate.sh'` end desc "Publish the API documentation" task :pdoc => [:rdoc] do + require 'rake/contrib/sshpublisher' Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/am", "doc").upload end diff --git a/vendor/rails/actionmailer/lib/action_mailer/base.rb b/vendor/rails/actionmailer/lib/action_mailer/base.rb index b77409b6..000c05d1 100644 --- a/vendor/rails/actionmailer/lib/action_mailer/base.rb +++ b/vendor/rails/actionmailer/lib/action_mailer/base.rb @@ -674,7 +674,7 @@ module ActionMailer #:nodoc: def perform_delivery_smtp(mail) destinations = mail.destinations mail.ready_to_send - sender = (mail['return-path'] && mail['return-path'].spec) || mail.from + sender = (mail['return-path'] && mail['return-path'].spec) || mail['from'] smtp = Net::SMTP.new(smtp_settings[:address], smtp_settings[:port]) smtp.enable_starttls_auto if smtp_settings[:enable_starttls_auto] && smtp.respond_to?(:enable_starttls_auto) diff --git a/vendor/rails/actionmailer/lib/action_mailer/version.rb b/vendor/rails/actionmailer/lib/action_mailer/version.rb index 08ff0d2f..db86a297 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 = 3 - TINY = 2 + TINY = 3 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/vendor/rails/actionmailer/test/abstract_unit.rb b/vendor/rails/actionmailer/test/abstract_unit.rb index 3e772557..9728ae5b 100644 --- a/vendor/rails/actionmailer/test/abstract_unit.rb +++ b/vendor/rails/actionmailer/test/abstract_unit.rb @@ -1,9 +1,6 @@ require 'rubygems' require 'test/unit' -gem 'mocha', '>= 0.9.5' -require 'mocha' - $:.unshift "#{File.dirname(__FILE__)}/../lib" $:.unshift "#{File.dirname(__FILE__)}/../../activesupport/lib" $:.unshift "#{File.dirname(__FILE__)}/../../actionpack/lib" diff --git a/vendor/rails/actionpack/CHANGELOG b/vendor/rails/actionpack/CHANGELOG index 8c9486cc..5f6fec67 100644 --- a/vendor/rails/actionpack/CHANGELOG +++ b/vendor/rails/actionpack/CHANGELOG @@ -1,3 +1,8 @@ +*2.3.3 (July 12, 2009)* + +* Fixed that TestResponse.cookies was returning cookies unescaped #1867 [Doug McInnes] + + *2.3.2 [Final] (March 15, 2009)* * Fixed that redirection would just log the options, not the final url (which lead to "Redirected to #") [DHH] diff --git a/vendor/rails/actionpack/Rakefile b/vendor/rails/actionpack/Rakefile index 6cacdf3c..17f6f1ac 100644 --- a/vendor/rails/actionpack/Rakefile +++ b/vendor/rails/actionpack/Rakefile @@ -4,7 +4,6 @@ require 'rake/testtask' require 'rake/rdoctask' require 'rake/packagetask' require 'rake/gempackagetask' -require 'rake/contrib/sshpublisher' require File.join(File.dirname(__FILE__), 'lib', 'action_pack', 'version') PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : '' @@ -80,7 +79,8 @@ spec = Gem::Specification.new do |s| s.has_rdoc = true s.requirements << 'none' - s.add_dependency('activesupport', '= 2.3.2' + PKG_BUILD) + s.add_dependency('activesupport', '= 2.3.3' + PKG_BUILD) + s.add_dependency('rack', '~> 1.0.0') s.require_path = 'lib' s.autorequire = 'action_controller' @@ -136,12 +136,14 @@ task :update_js => [ :update_scriptaculous ] desc "Publish the API documentation" task :pgem => [:package] do + require 'rake/contrib/sshpublisher' Rake::SshFilePublisher.new("gems.rubyonrails.org", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload `ssh gems.rubyonrails.org '/u/sites/gems/gemupdate.sh'` end desc "Publish the API documentation" task :pdoc => [:rdoc] do + require 'rake/contrib/sshpublisher' Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/ap", "doc").upload end diff --git a/vendor/rails/actionpack/lib/action_controller.rb b/vendor/rails/actionpack/lib/action_controller.rb index d03f4cb2..187c958c 100644 --- a/vendor/rails/actionpack/lib/action_controller.rb +++ b/vendor/rails/actionpack/lib/action_controller.rb @@ -32,10 +32,10 @@ rescue LoadError end begin - gem 'rack', '~> 1.0.0' + gem 'rack', '~> 1.1.0' require 'rack' rescue Gem::LoadError - require 'action_controller/vendor/rack-1.0/rack' + require 'action_controller/vendor/rack-1.1.pre/rack' end module ActionController @@ -45,7 +45,6 @@ module ActionController [Base, CGIHandler, CgiRequest, Request, Response, Http::Headers, UrlRewriter, UrlWriter] end - autoload :AbstractRequest, 'action_controller/request' autoload :Base, 'action_controller/base' autoload :Benchmarking, 'action_controller/benchmarking' autoload :Caching, 'action_controller/caching' 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 59760902..989be2db 100644 --- a/vendor/rails/actionpack/lib/action_controller/assertions/response_assertions.rb +++ b/vendor/rails/actionpack/lib/action_controller/assertions/response_assertions.rb @@ -63,7 +63,10 @@ module ActionController # Support partial arguments for hash redirections if options.is_a?(Hash) && @response.redirected_to.is_a?(Hash) - return true if options.all? {|(key, value)| @response.redirected_to[key] == value} + if options.all? {|(key, value)| @response.redirected_to[key] == value} + ::ActiveSupport::Deprecation.warn("Using assert_redirected_to with partial hash arguments is deprecated. Specify the full set arguments instead", caller) + return true + end end redirected_to_after_normalisation = normalize_argument_to_redirection(@response.redirected_to) @@ -82,6 +85,9 @@ module ActionController # # assert that the "new" view template was rendered # assert_template "new" # + # # assert that the "new" view template was rendered with Symbol + # assert_template :new + # # # assert that the "_customer" partial was rendered twice # assert_template :partial => '_customer', :count => 2 # @@ -91,7 +97,7 @@ module ActionController def assert_template(options = {}, message = nil) clean_backtrace do case options - when NilClass, String + when NilClass, String, Symbol rendered = @response.rendered[:template].to_s msg = build_message(message, "expecting but rendering with ", @@ -100,7 +106,7 @@ module ActionController if options.nil? @response.rendered[:template].blank? else - rendered.to_s.match(options) + rendered.to_s.match(options.to_s) end end when Hash @@ -123,6 +129,8 @@ module ActionController assert @response.rendered[:partials].empty?, "Expected no partials to be rendered" end + else + raise ArgumentError end end end diff --git a/vendor/rails/actionpack/lib/action_controller/base.rb b/vendor/rails/actionpack/lib/action_controller/base.rb index 0facf706..3c89fc8b 100644 --- a/vendor/rails/actionpack/lib/action_controller/base.rb +++ b/vendor/rails/actionpack/lib/action_controller/base.rb @@ -491,6 +491,10 @@ module ActionController #:nodoc: filtered_parameters[key] = '[FILTERED]' elsif value.is_a?(Hash) filtered_parameters[key] = filter_parameters(value) + elsif value.is_a?(Array) + filtered_parameters[key] = value.collect do |item| + filter_parameters(item) + end elsif block_given? key = key.dup value = value.dup if value @@ -950,8 +954,9 @@ module ActionController #:nodoc: response.content_type ||= Mime::JS render_for_text(js, options[:status]) - elsif json = options[:json] - json = json.to_json unless json.is_a?(String) + elsif options.include?(:json) + json = options[:json] + json = ActiveSupport::JSON.encode(json) unless json.is_a?(String) json = "#{options[:callback]}(#{json})" unless options[:callback].blank? response.content_type ||= Mime::JSON render_for_text(json, options[:status]) diff --git a/vendor/rails/actionpack/lib/action_controller/caching.rb b/vendor/rails/actionpack/lib/action_controller/caching.rb index 80d13e25..f6862230 100644 --- a/vendor/rails/actionpack/lib/action_controller/caching.rb +++ b/vendor/rails/actionpack/lib/action_controller/caching.rb @@ -27,7 +27,7 @@ module ActionController #:nodoc: autoload :Actions, 'action_controller/caching/actions' autoload :Fragments, 'action_controller/caching/fragments' autoload :Pages, 'action_controller/caching/pages' - autoload :Sweeper, 'action_controller/caching/sweeping' + autoload :Sweeper, 'action_controller/caching/sweeper' autoload :Sweeping, 'action_controller/caching/sweeping' def self.included(base) #:nodoc: diff --git a/vendor/rails/actionpack/lib/action_controller/caching/actions.rb b/vendor/rails/actionpack/lib/action_controller/caching/actions.rb index 87b5029e..21ee9bd3 100644 --- a/vendor/rails/actionpack/lib/action_controller/caching/actions.rb +++ b/vendor/rails/actionpack/lib/action_controller/caching/actions.rb @@ -61,7 +61,9 @@ module ActionController #:nodoc: filter_options = { :only => actions, :if => options.delete(:if), :unless => options.delete(:unless) } cache_filter = ActionCacheFilter.new(:layout => options.delete(:layout), :cache_path => options.delete(:cache_path), :store_options => options) - around_filter(cache_filter, filter_options) + around_filter(filter_options) do |controller, action| + cache_filter.filter(controller, action) + end end end @@ -83,6 +85,12 @@ module ActionController #:nodoc: @options = options end + def filter(controller, action) + should_continue = before(controller) + action.call if should_continue + after(controller) + end + def before(controller) cache_path = ActionCachePath.new(controller, path_options_for(controller, @options.slice(:cache_path))) if cache = controller.read_fragment(cache_path.path, @options[:store_options]) diff --git a/vendor/rails/actionpack/lib/action_controller/caching/sweeper.rb b/vendor/rails/actionpack/lib/action_controller/caching/sweeper.rb new file mode 100644 index 00000000..4885d8b2 --- /dev/null +++ b/vendor/rails/actionpack/lib/action_controller/caching/sweeper.rb @@ -0,0 +1,45 @@ +require 'active_record' + +module ActionController #:nodoc: + module Caching + 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, &block) + return if @controller.nil? + @controller.__send__(method, *arguments, &block) + end + end + end +end diff --git a/vendor/rails/actionpack/lib/action_controller/caching/sweeping.rb b/vendor/rails/actionpack/lib/action_controller/caching/sweeping.rb index c1be264f..9b320021 100644 --- a/vendor/rails/actionpack/lib/action_controller/caching/sweeping.rb +++ b/vendor/rails/actionpack/lib/action_controller/caching/sweeping.rb @@ -51,47 +51,5 @@ module ActionController #:nodoc: 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, &block) - return if @controller.nil? - @controller.__send__(method, *arguments, &block) - end - end - end end end diff --git a/vendor/rails/actionpack/lib/action_controller/failsafe.rb b/vendor/rails/actionpack/lib/action_controller/failsafe.rb index 56758114..7f8aee82 100644 --- a/vendor/rails/actionpack/lib/action_controller/failsafe.rb +++ b/vendor/rails/actionpack/lib/action_controller/failsafe.rb @@ -1,4 +1,19 @@ +require 'erb' + module ActionController + # The Failsafe middleware is usually the top-most middleware in the Rack + # middleware chain. It returns the underlying middleware's response, but if + # the underlying middle raises an exception then Failsafe will log the + # exception into the Rails log file, and will attempt to return an error + # message response. + # + # Failsafe is a last resort for logging errors and for telling the HTTP + # client that something went wrong. Do not confuse this with the + # ActionController::Rescue module, which is responsible for catching + # exceptions at deeper levels. Unlike Failsafe, which is as simple as + # possible, Rescue provides features that allow developers to hook into + # the error handling logic, and can customize the error message response + # based on the HTTP client's IP. class Failsafe cattr_accessor :error_file_path self.error_file_path = Rails.public_path if defined?(Rails.public_path) @@ -11,7 +26,7 @@ module ActionController @app.call(env) rescue Exception => exception # Reraise exception in test environment - if env["rack.test"] + if defined?(Rails) && Rails.env.test? raise exception else failsafe_response(exception) @@ -21,18 +36,37 @@ module ActionController private def failsafe_response(exception) log_failsafe_exception(exception) - [500, {'Content-Type' => 'text/html'}, failsafe_response_body] + [500, {'Content-Type' => 'text/html'}, [failsafe_response_body]] rescue Exception => failsafe_error # Logger or IO errors $stderr.puts "Error during failsafe response: #{failsafe_error}" end def failsafe_response_body - error_path = "#{self.class.error_file_path}/500.html" - if File.exist?(error_path) - File.read(error_path) + error_template_path = "#{self.class.error_file_path}/500.html" + if File.exist?(error_template_path) + begin + result = render_template(error_template_path) + rescue Exception + result = nil + end else - "

500 Internal Server Error

" + result = nil end + if result.nil? + result = "

500 Internal Server Error

" << + "If you are the administrator of this website, then please read this web " << + "application's log file to find out what went wrong." + end + result + end + + # The default 500.html uses the h() method. + def h(text) # :nodoc: + ERB::Util.h(text) + end + + def render_template(filename) + ERB.new(File.read(filename)).result(binding) end def log_failsafe_exception(exception) diff --git a/vendor/rails/actionpack/lib/action_controller/flash.rb b/vendor/rails/actionpack/lib/action_controller/flash.rb index 56ee9c67..93912073 100644 --- a/vendor/rails/actionpack/lib/action_controller/flash.rb +++ b/vendor/rails/actionpack/lib/action_controller/flash.rb @@ -120,6 +120,11 @@ module ActionController #:nodoc: (@used.keys - keys).each{ |k| @used.delete(k) } end + def store(session, key = "flash") + return if self.empty? + session[key] = self + end + private # Used internally by the keep and discard methods # use() # marks the entire flash as used @@ -139,7 +144,10 @@ module ActionController #:nodoc: protected def perform_action_with_flash perform_action_without_flash - remove_instance_variable(:@_flash) if defined? @_flash + if defined? @_flash + @_flash.store(session) + remove_instance_variable(:@_flash) + end end def reset_session_with_flash @@ -151,8 +159,8 @@ module ActionController #:nodoc: # read a notice you put there or flash["notice"] = "hello" # to put a new one. def flash #:doc: - unless defined? @_flash - @_flash = session["flash"] ||= FlashHash.new + if !defined?(@_flash) + @_flash = session["flash"] || FlashHash.new @_flash.sweep end diff --git a/vendor/rails/actionpack/lib/action_controller/http_authentication.rb b/vendor/rails/actionpack/lib/action_controller/http_authentication.rb index b6b5267c..88c289bc 100644 --- a/vendor/rails/actionpack/lib/action_controller/http_authentication.rb +++ b/vendor/rails/actionpack/lib/action_controller/http_authentication.rb @@ -183,7 +183,7 @@ module ActionController request.env['REDIRECT_X_HTTP_AUTHORIZATION'] end - # Raises error unless the request credentials response value matches the expected value. + # Returns false unless the request credentials response value matches the expected value. # First try the password as a ha1 digest password. If this fails, then try it as a plain # text password. def validate_digest_response(request, realm, &password_procedure) @@ -192,9 +192,12 @@ module ActionController if valid_nonce && realm == credentials[:realm] && opaque == credentials[:opaque] password = password_procedure.call(credentials[:username]) + return false unless password + + method = request.env['rack.methodoverride.original_method'] || request.env['REQUEST_METHOD'] [true, false].any? do |password_is_ha1| - expected = expected_response(request.env['REQUEST_METHOD'], request.env['REQUEST_URI'], credentials, password, password_is_ha1) + expected = expected_response(method, request.env['REQUEST_URI'], credentials, password, password_is_ha1) expected == credentials[:response] end end diff --git a/vendor/rails/actionpack/lib/action_controller/integration.rb b/vendor/rails/actionpack/lib/action_controller/integration.rb index 26b69557..58b64762 100644 --- a/vendor/rails/actionpack/lib/action_controller/integration.rb +++ b/vendor/rails/actionpack/lib/action_controller/integration.rb @@ -292,9 +292,7 @@ module ActionController "rack.errors" => StringIO.new, "rack.multithread" => true, "rack.multiprocess" => true, - "rack.run_once" => false, - - "rack.test" => true + "rack.run_once" => false ) (headers || {}).each do |key, value| @@ -311,12 +309,7 @@ module ActionController ActionController::Base.clear_last_instantiation! - app = @application - # Rack::Lint doesn't accept String headers or bodies in Ruby 1.9 - unless RUBY_VERSION >= '1.9.0' && Rack.release <= '0.9.0' - app = Rack::Lint.new(app) - end - + app = Rack::Lint.new(@application) status, headers, body = app.call(env) @request_count += 1 @@ -333,7 +326,7 @@ module ActionController end @body = "" - if body.is_a?(String) + if body.respond_to?(:to_str) @body << body else body.each { |part| @body << part } @@ -416,7 +409,7 @@ module ActionController 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)}]" + k = first ? key.to_s : "[#{key.to_s}]" if Hash === value multipart_requestify(value, false).each do |subkey, subvalue| p[k + subkey] = subvalue diff --git a/vendor/rails/actionpack/lib/action_controller/middlewares.rb b/vendor/rails/actionpack/lib/action_controller/middlewares.rb index 371cf6d8..dda25fc2 100644 --- a/vendor/rails/actionpack/lib/action_controller/middlewares.rb +++ b/vendor/rails/actionpack/lib/action_controller/middlewares.rb @@ -7,7 +7,6 @@ use "ActionController::Failsafe" use lambda { ActionController::Base.session_store }, lambda { ActionController::Base.session_options } -use "ActionController::RewindableInput" use "ActionController::ParamsParser" use "Rack::MethodOverride" use "Rack::Head" diff --git a/vendor/rails/actionpack/lib/action_controller/reloader.rb b/vendor/rails/actionpack/lib/action_controller/reloader.rb index 46789309..459dece1 100644 --- a/vendor/rails/actionpack/lib/action_controller/reloader.rb +++ b/vendor/rails/actionpack/lib/action_controller/reloader.rb @@ -1,14 +1,45 @@ module ActionController class Reloader + class BodyWrapper + def initialize(body) + @body = body + end + + def close + @body.close if @body.respond_to?(:close) + ensure + Dispatcher.cleanup_application + end + + def method_missing(*args, &block) + @body.send(*args, &block) + end + + def respond_to?(symbol, include_private = false) + symbol == :close || @body.respond_to?(symbol, include_private) + end + end + def initialize(app) @app = app end def call(env) Dispatcher.reload_application - @app.call(env) - ensure - Dispatcher.cleanup_application + status, headers, body = @app.call(env) + # We do not want to call 'cleanup_application' in an ensure block + # because the returned Rack response body may lazily generate its data. This + # is for example the case if one calls + # + # render :text => lambda { ... code here which refers to application models ... } + # + # in an ActionController. + # + # Instead, we will want to cleanup the application code after the request is + # completely finished. So we wrap the body in a BodyWrapper class so that + # when the Rack handler calls #close during the end of the request, we get to + # run our cleanup code. + [status, headers, BodyWrapper.new(body)] end end end diff --git a/vendor/rails/actionpack/lib/action_controller/request.rb b/vendor/rails/actionpack/lib/action_controller/request.rb index ef223f15..1c3c1c83 100755 --- a/vendor/rails/actionpack/lib/action_controller/request.rb +++ b/vendor/rails/actionpack/lib/action_controller/request.rb @@ -95,6 +95,10 @@ module ActionController end end + def media_type + content_type.to_s + end + # Returns the accepted MIME type for the request. def accepts @accepts ||= begin @@ -383,7 +387,7 @@ EOM alias_method :params, :parameters def path_parameters=(parameters) #:nodoc: - @env["rack.routing_args"] = parameters + @env["action_controller.request.path_parameters"] = parameters @symbolized_path_parameters = @parameters = nil end @@ -399,7 +403,7 @@ EOM # # See symbolized_path_parameters for symbolized keys. def path_parameters - @env["rack.routing_args"] ||= {} + @env["action_controller.request.path_parameters"] ||= {} end # The request body is an IO input stream. If the RAW_POST_DATA environment diff --git a/vendor/rails/actionpack/lib/action_controller/response.rb b/vendor/rails/actionpack/lib/action_controller/response.rb index ccff473d..def03fac 100644 --- a/vendor/rails/actionpack/lib/action_controller/response.rb +++ b/vendor/rails/actionpack/lib/action_controller/response.rb @@ -151,8 +151,8 @@ module ActionController # :nodoc: if @body.respond_to?(:call) @writer = lambda { |x| callback.call(x) } @body.call(self, self) - elsif @body.is_a?(String) - @body.each_line(&callback) + elsif @body.respond_to?(:to_str) + yield @body else @body.each(&callback) end diff --git a/vendor/rails/actionpack/lib/action_controller/rewindable_input.rb b/vendor/rails/actionpack/lib/action_controller/rewindable_input.rb deleted file mode 100644 index cedfb7fd..00000000 --- a/vendor/rails/actionpack/lib/action_controller/rewindable_input.rb +++ /dev/null @@ -1,28 +0,0 @@ -module ActionController - class RewindableInput - class RewindableIO < ActiveSupport::BasicObject - def initialize(io) - @io = io - @rewindable = io.is_a?(::StringIO) - end - - def method_missing(method, *args, &block) - unless @rewindable - @io = ::StringIO.new(@io.read) - @rewindable = true - end - - @io.__send__(method, *args, &block) - end - end - - def initialize(app) - @app = app - end - - def call(env) - env['rack.input'] = RewindableIO.new(env['rack.input']) - @app.call(env) - 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 index 044ace7d..a983d376 100644 --- a/vendor/rails/actionpack/lib/action_controller/routing/route_set.rb +++ b/vendor/rails/actionpack/lib/action_controller/routing/route_set.rb @@ -305,6 +305,7 @@ module ActionController end def add_route(path, options = {}) + options.each { |k, v| options[k] = v.to_s if [:controller, :action].include?(k) && v.is_a?(Symbol) } route = builder.build(path, options) routes << route route @@ -436,7 +437,7 @@ module ActionController def recognize(request) params = recognize_path(request.path, extract_request_environment(request)) request.path_parameters = params.with_indifferent_access - "#{params[:controller].camelize}Controller".constantize + "#{params[:controller].to_s.camelize}Controller".constantize end def recognize_path(path, environment={}) diff --git a/vendor/rails/actionpack/lib/action_controller/streaming.rb b/vendor/rails/actionpack/lib/action_controller/streaming.rb index 9f80f48c..8a9fbfc1 100644 --- a/vendor/rails/actionpack/lib/action_controller/streaming.rb +++ b/vendor/rails/actionpack/lib/action_controller/streaming.rb @@ -161,7 +161,7 @@ module ActionController #:nodoc: content_type = content_type.to_s.strip # fixes a problem with extra '\r' with some browsers headers.merge!( - 'Content-Length' => options[:length], + 'Content-Length' => options[:length].to_s, 'Content-Type' => content_type, 'Content-Disposition' => disposition, 'Content-Transfer-Encoding' => 'binary' diff --git a/vendor/rails/actionpack/lib/action_controller/test_process.rb b/vendor/rails/actionpack/lib/action_controller/test_process.rb index dbaec00b..9de3faba 100644 --- a/vendor/rails/actionpack/lib/action_controller/test_process.rb +++ b/vendor/rails/actionpack/lib/action_controller/test_process.rb @@ -1,3 +1,4 @@ +require 'rack/session/abstract/id' module ActionController #:nodoc: class TestRequest < Request #:nodoc: attr_accessor :cookies, :session_options @@ -13,6 +14,8 @@ module ActionController #:nodoc: @query_parameters = {} @session = TestSession.new + default_rack_options = Rack::Session::Abstract::ID::DEFAULT_OPTIONS + @session_options ||= {:id => generate_sid(default_rack_options[:sidbits])}.merge(default_rack_options) initialize_default_values initialize_containers @@ -110,6 +113,7 @@ module ActionController #:nodoc: end def recycle! + @env["action_controller.request.request_parameters"] = {} self.query_parameters = {} self.path_parameters = {} @headers, @request_method, @accepts, @content_type = nil, nil, nil, nil @@ -120,6 +124,10 @@ module ActionController #:nodoc: end private + def generate_sid(sidbits) + "%0#{sidbits / 4}x" % rand(2**sidbits - 1) + end + def initialize_containers @cookies = {} end @@ -250,7 +258,7 @@ module ActionController #:nodoc: def cookies cookies = {} Array(headers['Set-Cookie']).each do |cookie| - key, value = cookie.split(";").first.split("=") + key, value = cookie.split(";").first.split("=").map {|val| Rack::Utils.unescape(val)} cookies[key] = value end cookies diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/reloader.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/reloader.rb deleted file mode 100644 index b17d8c09..00000000 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/reloader.rb +++ /dev/null @@ -1,64 +0,0 @@ -require 'thread' - -module Rack - # Rack::Reloader checks on every request, but at most every +secs+ - # seconds, if a file loaded changed, and reloads it, logging to - # rack.errors. - # - # It is recommended you use ShowExceptions to catch SyntaxErrors etc. - - class Reloader - def initialize(app, secs=10) - @app = app - @secs = secs # reload every @secs seconds max - @last = Time.now - end - - def call(env) - if Time.now > @last + @secs - Thread.exclusive { - reload!(env['rack.errors']) - @last = Time.now - } - end - - @app.call(env) - end - - def reload!(stderr=$stderr) - need_reload = $LOADED_FEATURES.find_all { |loaded| - begin - if loaded =~ /\A[.\/]/ # absolute filename or 1.9 - abs = loaded - else - abs = $LOAD_PATH.map { |path| ::File.join(path, loaded) }. - find { |file| ::File.exist? file } - end - - if abs - ::File.mtime(abs) > @last - @secs rescue false - else - false - end - end - } - - need_reload.each { |l| - $LOADED_FEATURES.delete l - } - - need_reload.each { |to_load| - begin - if require to_load - stderr.puts "#{self.class}: reloaded `#{to_load}'" - end - rescue LoadError, SyntaxError => e - raise e # Possibly ShowExceptions - end - } - - stderr.flush - need_reload - end - end -end diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack.rb similarity index 95% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack.rb index 6349b950..371d0156 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack.rb +++ b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack.rb @@ -3,7 +3,8 @@ # Rack is freely distributable under the terms of an MIT-style license. # See COPYING or http://www.opensource.org/licenses/mit-license.php. -$:.unshift(File.expand_path(File.dirname(__FILE__))) +path = File.expand_path(File.dirname(__FILE__)) +$:.unshift(path) unless $:.include?(path) # The Rack main module, serving as a namespace for all core Rack @@ -14,7 +15,7 @@ $:.unshift(File.expand_path(File.dirname(__FILE__))) module Rack # The Rack protocol version number implemented. - VERSION = [0,1] + VERSION = [1,0] # Return the Rack protocol version as a dotted string. def self.version @@ -23,7 +24,7 @@ module Rack # Return the Rack release as a dotted string. def self.release - "1.0 bundled" + "1.0" end autoload :Builder, "rack/builder" diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/adapter/camping.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/adapter/camping.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/adapter/camping.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/adapter/camping.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/handler.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/abstract/handler.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/handler.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/abstract/handler.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/request.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/abstract/request.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/request.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/abstract/request.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/basic.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/basic.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/basic.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/basic.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/digest/md5.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/digest/md5.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/digest/md5.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/digest/md5.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/digest/nonce.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/digest/nonce.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/digest/nonce.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/digest/nonce.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/digest/params.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/digest/params.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/digest/params.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/digest/params.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/digest/request.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/digest/request.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/digest/request.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/digest/request.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/openid.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/openid.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/openid.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/openid.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/builder.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/builder.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/builder.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/builder.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/cascade.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/cascade.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/cascade.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/cascade.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/chunked.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/chunked.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/chunked.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/chunked.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/commonlogger.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/commonlogger.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/commonlogger.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/commonlogger.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/conditionalget.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/conditionalget.rb similarity index 94% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/conditionalget.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/conditionalget.rb index 7bec8241..046ebdb0 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/conditionalget.rb +++ b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/conditionalget.rb @@ -26,6 +26,8 @@ module Rack headers = Utils::HeaderHash.new(headers) if etag_matches?(env, headers) || modified_since?(env, headers) status = 304 + headers.delete('Content-Type') + headers.delete('Content-Length') body = [] end [status, headers, body] diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/content_length.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/content_length.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/content_length.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/content_length.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/content_type.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/content_type.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/content_type.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/content_type.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/deflater.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/deflater.rb similarity index 54% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/deflater.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/deflater.rb index a42b7477..14137a94 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/deflater.rb +++ b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/deflater.rb @@ -33,17 +33,15 @@ module Rack case encoding when "gzip" + headers['Content-Encoding'] = "gzip" + headers.delete('Content-Length') mtime = headers.key?("Last-Modified") ? Time.httpdate(headers["Last-Modified"]) : Time.now - body = self.class.gzip(body, mtime) - size = Rack::Utils.bytesize(body) - headers = headers.merge("Content-Encoding" => "gzip", "Content-Length" => size.to_s) - [status, headers, [body]] + [status, headers, GzipStream.new(body, mtime)] when "deflate" - body = self.class.deflate(body) - size = Rack::Utils.bytesize(body) - headers = headers.merge("Content-Encoding" => "deflate", "Content-Length" => size.to_s) - [status, headers, [body]] + headers['Content-Encoding'] = "deflate" + headers.delete('Content-Length') + [status, headers, DeflateStream.new(body)] when "identity" [status, headers, body] when nil @@ -52,34 +50,47 @@ module Rack end end - def self.gzip(body, mtime) - io = StringIO.new - gzip = Zlib::GzipWriter.new(io) - gzip.mtime = mtime + class GzipStream + def initialize(body, mtime) + @body = body + @mtime = mtime + end - # TODO: Add streaming - body.each { |part| gzip << part } + def each(&block) + @writer = block + gzip =::Zlib::GzipWriter.new(self) + gzip.mtime = @mtime + @body.each { |part| gzip << part } + @body.close if @body.respond_to?(:close) + gzip.close + @writer = nil + end - gzip.close - return io.string + def write(data) + @writer.call(data) + end end - DEFLATE_ARGS = [ - Zlib::DEFAULT_COMPRESSION, - # drop the zlib header which causes both Safari and IE to choke - -Zlib::MAX_WBITS, - Zlib::DEF_MEM_LEVEL, - Zlib::DEFAULT_STRATEGY - ] + class DeflateStream + DEFLATE_ARGS = [ + Zlib::DEFAULT_COMPRESSION, + # drop the zlib header which causes both Safari and IE to choke + -Zlib::MAX_WBITS, + Zlib::DEF_MEM_LEVEL, + Zlib::DEFAULT_STRATEGY + ] - # Loosely based on Mongrel's Deflate handler - def self.deflate(body) - deflater = Zlib::Deflate.new(*DEFLATE_ARGS) + def initialize(body) + @body = body + end - # TODO: Add streaming - body.each { |part| deflater << part } - - return deflater.finish + def each + deflater = ::Zlib::Deflate.new(*DEFLATE_ARGS) + @body.each { |part| yield deflater.deflate(part) } + @body.close if @body.respond_to?(:close) + yield deflater.finish + nil + end end end end diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/directory.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/directory.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/directory.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/directory.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/file.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/file.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/file.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/file.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler.rb similarity index 68% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler.rb index 1018af64..5624a1e7 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler.rb +++ b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler.rb @@ -10,16 +10,37 @@ module Rack module Handler def self.get(server) return unless server + server = server.to_s if klass = @handlers[server] obj = Object klass.split("::").each { |x| obj = obj.const_get(x) } obj else - Rack::Handler.const_get(server.capitalize) + try_require('rack/handler', server) + const_get(server) end end + # Transforms server-name constants to their canonical form as filenames, + # then tries to require them but silences the LoadError if not found + # + # Naming convention: + # + # Foo # => 'foo' + # FooBar # => 'foo_bar.rb' + # FooBAR # => 'foobar.rb' + # FOObar # => 'foobar.rb' + # FOOBAR # => 'foobar.rb' + # FooBarBaz # => 'foo_bar_baz.rb' + def self.try_require(prefix, const_name) + file = const_name.gsub(/^[A-Z]+/) { |pre| pre.downcase }. + gsub(/[A-Z]+[^A-Z]/, '_\&').downcase + + require(::File.join(prefix, file)) + rescue LoadError + end + def self.register(server, klass) @handlers ||= {} @handlers[server] = klass diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/cgi.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/cgi.rb similarity index 97% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/cgi.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/cgi.rb index e38156c7..f45f3d73 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/cgi.rb +++ b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/cgi.rb @@ -15,7 +15,7 @@ module Rack env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" - env.update({"rack.version" => [0,1], + env.update({"rack.version" => [1,0], "rack.input" => $stdin, "rack.errors" => $stderr, diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/evented_mongrel.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/evented_mongrel.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/evented_mongrel.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/evented_mongrel.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/fastcgi.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/fastcgi.rb similarity index 72% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/fastcgi.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/fastcgi.rb index 6324c7d2..2cbb5025 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/fastcgi.rb +++ b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/fastcgi.rb @@ -1,6 +1,17 @@ require 'fcgi' require 'socket' require 'rack/content_length' +require 'rack/rewindable_input' + +class FCGI::Stream + alias _rack_read_without_buffer read + + def read(n, buffer=nil) + buf = _rack_read_without_buffer n + buffer.replace(buf.to_s) if buffer + buf + end +end module Rack module Handler @@ -13,34 +24,18 @@ module Rack } end - module ProperStream # :nodoc: - def each # This is missing by default. - while line = gets - yield line - end - end - - def read(*args) - if args.empty? - super || "" # Empty string on EOF. - else - super - end - end - end - def self.serve(request, app) app = Rack::ContentLength.new(app) env = request.env env.delete "HTTP_CONTENT_LENGTH" - request.in.extend ProperStream - env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" - env.update({"rack.version" => [0,1], - "rack.input" => request.in, + rack_input = RewindableInput.new(request.in) + + env.update({"rack.version" => [1,0], + "rack.input" => rack_input, "rack.errors" => request.err, "rack.multithread" => false, @@ -57,12 +52,16 @@ module Rack env.delete "CONTENT_TYPE" if env["CONTENT_TYPE"] == "" env.delete "CONTENT_LENGTH" if env["CONTENT_LENGTH"] == "" - status, headers, body = app.call(env) begin - send_headers request.out, status, headers - send_body request.out, body + status, headers, body = app.call(env) + begin + send_headers request.out, status, headers + send_body request.out, body + ensure + body.close if body.respond_to? :close + end ensure - body.close if body.respond_to? :close + rack_input.close request.finish end end diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/lsws.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/lsws.rb similarity index 97% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/lsws.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/lsws.rb index c65ba3ec..7231336d 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/lsws.rb +++ b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/lsws.rb @@ -15,7 +15,7 @@ module Rack env = ENV.to_hash env.delete "HTTP_CONTENT_LENGTH" env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" - env.update({"rack.version" => [0,1], + env.update({"rack.version" => [1,0], "rack.input" => StringIO.new($stdin.read.to_s), "rack.errors" => $stderr, "rack.multithread" => false, diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/mongrel.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/mongrel.rb similarity index 97% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/mongrel.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/mongrel.rb index f0c0d583..a6b4fa93 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/mongrel.rb +++ b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/mongrel.rb @@ -10,7 +10,7 @@ module Rack server = ::Mongrel::HttpServer.new(options[:Host] || '0.0.0.0', options[:Port] || 8080) # Acts like Rack::URLMap, utilizing Mongrel's own path finding methods. - # Use is similar to #run, replacing the app argument with a hash of + # Use is similar to #run, replacing the app argument with a hash of # { path=>app, ... } or an instance of Rack::URLMap. if options[:map] if app.is_a? Hash @@ -45,7 +45,7 @@ module Rack env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" - env.update({"rack.version" => [0,1], + env.update({"rack.version" => [1,0], "rack.input" => request.body || StringIO.new(""), "rack.errors" => $stderr, diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/scgi.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/scgi.rb similarity index 96% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/scgi.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/scgi.rb index 9495c663..df0e764d 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/scgi.rb +++ b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/scgi.rb @@ -7,14 +7,14 @@ module Rack module Handler class SCGI < ::SCGI::Processor attr_accessor :app - + def self.run(app, options=nil) new(options.merge(:app=>app, :host=>options[:Host], :port=>options[:Port], :socket=>options[:Socket])).listen end - + def initialize(settings = {}) @app = Rack::Chunked.new(Rack::ContentLength.new(settings[:app])) @log = Object.new @@ -22,7 +22,7 @@ module Rack def @log.error(*args); end super(settings) end - + def process_request(request, input_body, socket) env = {}.replace(request) env.delete "HTTP_CONTENT_TYPE" @@ -32,7 +32,7 @@ module Rack env["PATH_INFO"] = env["REQUEST_PATH"] env["QUERY_STRING"] ||= "" env["SCRIPT_NAME"] = "" - env.update({"rack.version" => [0,1], + env.update({"rack.version" => [1,0], "rack.input" => StringIO.new(input_body), "rack.errors" => $stderr, diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/swiftiplied_mongrel.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/swiftiplied_mongrel.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/thin.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/thin.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/thin.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/thin.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/webrick.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/webrick.rb similarity index 97% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/webrick.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/webrick.rb index 22ae14b3..619632a9 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/webrick.rb +++ b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/webrick.rb @@ -23,7 +23,7 @@ module Rack env = req.meta_vars env.delete_if { |k, v| v.nil? } - env.update({"rack.version" => [0,1], + env.update({"rack.version" => [1,0], "rack.input" => StringIO.new(req.body.to_s), "rack.errors" => $stderr, diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/head.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/head.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/head.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/head.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/lint.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/lint.rb similarity index 77% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/lint.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/lint.rb index 44a33ce3..bb0693d3 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/lint.rb +++ b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/lint.rb @@ -88,9 +88,9 @@ module Rack ## within the application. This may be an ## empty string, if the request URL targets ## the application root and does not have a - ## trailing slash. This information should be - ## decoded by the server if it comes from a - ## URL. + ## trailing slash. This value may be + ## percent-encoded when I originating from + ## a URL. ## QUERY_STRING:: The portion of the request URL that ## follows the ?, if any. May be @@ -111,19 +111,48 @@ module Rack ## In addition to this, the Rack environment must include these ## Rack-specific variables: - ## rack.version:: The Array [0,1], representing this version of Rack. + ## rack.version:: The Array [1,0], representing this version of Rack. ## rack.url_scheme:: +http+ or +https+, depending on the request URL. ## rack.input:: See below, the input stream. ## rack.errors:: See below, the error stream. ## rack.multithread:: true if the application object may be simultaneously invoked by another thread in the same process, false otherwise. ## rack.multiprocess:: true if an equivalent application object may be simultaneously invoked by another process, false otherwise. ## rack.run_once:: true if the server expects (but does not guarantee!) that the application will only be invoked this one time during the life of its containing process. Normally, this will only be true for a server based on CGI (or something similar). + ## + + ## Additional environment specifications have approved to + ## standardized middleware APIs. None of these are required to + ## be implemented by the server. + + ## rack.session:: A hash like interface for storing request session data. + ## The store must implement: + if session = env['rack.session'] + ## store(key, value) (aliased as []=); + assert("session #{session.inspect} must respond to store and []=") { + session.respond_to?(:store) && session.respond_to?(:[]=) + } + + ## fetch(key, default = nil) (aliased as []); + assert("session #{session.inspect} must respond to fetch and []") { + session.respond_to?(:fetch) && session.respond_to?(:[]) + } + + ## delete(key); + assert("session #{session.inspect} must respond to delete") { + session.respond_to?(:delete) + } + + ## clear; + assert("session #{session.inspect} must respond to clear") { + session.respond_to?(:clear) + } + end ## The server or the application can store their own data in the ## environment, too. The keys must contain at least one dot, ## and should be prefixed uniquely. The prefix rack. - ## is reserved for use with the Rack core distribution and must - ## not be used otherwise. + ## is reserved for use with the Rack core distribution and other + ## accepted specifications and must not be used otherwise. ## %w[REQUEST_METHOD SERVER_NAME SERVER_PORT @@ -202,9 +231,12 @@ module Rack end ## === The Input Stream + ## + ## The input stream is an IO-like object which contains the raw HTTP + ## POST data. If it is a file then it must be opened in binary mode. def check_input(input) - ## The input stream must respond to +gets+, +each+ and +read+. - [:gets, :each, :read].each { |method| + ## The input stream must respond to +gets+, +each+, +read+ and +rewind+. + [:gets, :each, :read, :rewind].each { |method| assert("rack.input #{input} does not respond to ##{method}") { input.respond_to? method } @@ -222,10 +254,6 @@ module Rack @input.size end - def rewind - @input.rewind - end - ## * +gets+ must be called without arguments and return a string, ## or +nil+ on EOF. def gets(*args) @@ -237,21 +265,44 @@ module Rack v end - ## * +read+ must be called without or with one integer argument - ## and return a string, or +nil+ on EOF. + ## * +read+ behaves like IO#read. Its signature is read([length, [buffer]]). + ## If given, +length+ must be an non-negative Integer (>= 0) or +nil+, and +buffer+ must + ## be a String and may not be nil. If +length+ is given and not nil, then this method + ## reads at most +length+ bytes from the input stream. If +length+ is not given or nil, + ## then this method reads all data until EOF. + ## When EOF is reached, this method returns nil if +length+ is given and not nil, or "" + ## if +length+ is not given or is nil. + ## If +buffer+ is given, then the read data will be placed into +buffer+ instead of a + ## newly created String object. def read(*args) assert("rack.input#read called with too many arguments") { - args.size <= 1 + args.size <= 2 } - if args.size == 1 - assert("rack.input#read called with non-integer argument") { - args.first.kind_of? Integer + if args.size >= 1 + assert("rack.input#read called with non-integer and non-nil length") { + args.first.kind_of?(Integer) || args.first.nil? + } + assert("rack.input#read called with a negative length") { + args.first.nil? || args.first >= 0 } end + if args.size >= 2 + assert("rack.input#read called with non-String buffer") { + args[1].kind_of?(String) + } + end + v = @input.read(*args) - assert("rack.input#read didn't return a String") { + + assert("rack.input#read didn't return nil or a String") { v.nil? or v.instance_of? String } + if args[0].nil? + assert("rack.input#read(nil) returned nil on EOF") { + !v.nil? + } + end + v end @@ -266,6 +317,23 @@ module Rack } end + ## * +rewind+ must be called without arguments. It rewinds the input + ## stream back to the beginning. It must not raise Errno::ESPIPE: + ## that is, it may not be a pipe or a socket. Therefore, handler + ## developers must buffer the input data into some rewindable object + ## if the underlying input stream is not rewindable. + def rewind(*args) + assert("rack.input#rewind called with arguments") { args.size == 0 } + assert("rack.input#rewind raised Errno::ESPIPE") { + begin + @input.rewind + true + rescue Errno::ESPIPE + false + end + } + end + ## * +close+ must never be called on the input stream. def close(*args) assert("rack.input#close must not be called") { false } @@ -316,13 +384,14 @@ module Rack ## === The Status def check_status(status) - ## The status, if parsed as integer (+to_i+), must be greater than or equal to 100. + ## This is an HTTP status. When parsed as integer (+to_i+), it must be + ## greater than or equal to 100. assert("Status must be >=100 seen as integer") { status.to_i >= 100 } end ## === The Headers def check_headers(header) - ## The header must respond to each, and yield values of key and value. + ## The header must respond to +each+, and yield values of key and value. assert("headers object should respond to #each, but doesn't (got #{header.class} as headers)") { header.respond_to? :each } @@ -344,7 +413,8 @@ module Rack ## The values of the header must be Strings, assert("a header value must be a String, but the value of " + "'#{key}' is a #{value.class}") { value.kind_of? String } - ## consisting of lines (for multiple header values) seperated by "\n". + ## consisting of lines (for multiple header values, e.g. multiple + ## Set-Cookie values) seperated by "\n". value.split("\n").each { |item| ## The lines must not contain characters below 037. assert("invalid header value #{key}: #{item.inspect}") { @@ -416,7 +486,7 @@ module Rack ## === The Body def each @closed = false - ## The Body must respond to #each + ## The Body must respond to +each+ @body.each { |part| ## and must only yield String values. assert("Body yielded non-string value #{part.inspect}") { @@ -425,14 +495,19 @@ module Rack yield part } ## - ## If the Body responds to #close, it will be called after iteration. + ## The Body itself should not be an instance of String, as this will + ## break in Ruby 1.9. + ## + ## If the Body responds to +close+, it will be called after iteration. # XXX howto: assert("Body has not been closed") { @closed } ## - ## If the Body responds to #to_path, it must return a String + ## If the Body responds to +to_path+, it must return a String ## identifying the location of a file whose contents are identical - ## to that produced by calling #each. + ## to that produced by calling +each+; this may be used by the + ## server as an alternative, possibly more efficient way to + ## transport the response. if @body.respond_to?(:to_path) assert("The file identified by body.to_path does not exist") { diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/lobster.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/lobster.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/lobster.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/lobster.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/lock.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/lock.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/lock.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/lock.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/methodoverride.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/methodoverride.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/methodoverride.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/methodoverride.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/mime.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/mime.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/mime.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/mime.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/mock.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/mock.rb similarity index 75% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/mock.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/mock.rb index 70852da3..fdefb034 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/mock.rb +++ b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/mock.rb @@ -40,7 +40,7 @@ module Rack end DEFAULT_ENV = { - "rack.version" => [0,1], + "rack.version" => [1,0], "rack.input" => StringIO.new, "rack.errors" => StringIO.new, "rack.multithread" => true, @@ -73,14 +73,17 @@ module Rack # Return the Rack environment used for a request to +uri+. def self.env_for(uri="", opts={}) uri = URI(uri) + uri.path = "/#{uri.path}" unless uri.path[0] == ?/ + env = DEFAULT_ENV.dup - env["REQUEST_METHOD"] = opts[:method] || "GET" + env["REQUEST_METHOD"] = opts[:method] ? opts[:method].to_s.upcase : "GET" env["SERVER_NAME"] = uri.host || "example.org" env["SERVER_PORT"] = uri.port ? uri.port.to_s : "80" env["QUERY_STRING"] = uri.query.to_s env["PATH_INFO"] = (!uri.path || uri.path.empty?) ? "/" : uri.path env["rack.url_scheme"] = uri.scheme || "http" + env["HTTPS"] = env["rack.url_scheme"] == "https" ? "on" : "off" env["SCRIPT_NAME"] = opts[:script_name] || "" @@ -90,6 +93,27 @@ module Rack env["rack.errors"] = StringIO.new end + if params = opts[:params] + if env["REQUEST_METHOD"] == "GET" + params = Utils.parse_nested_query(params) if params.is_a?(String) + params.update(Utils.parse_nested_query(env["QUERY_STRING"])) + env["QUERY_STRING"] = Utils.build_nested_query(params) + elsif !opts.has_key?(:input) + opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded" + if params.is_a?(Hash) + if data = Utils::Multipart.build_multipart(params) + opts[:input] = data + opts["CONTENT_LENGTH"] ||= data.length.to_s + opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Utils::Multipart::MULTIPART_BOUNDARY}" + else + opts[:input] = Utils.build_nested_query(params) + end + else + opts[:input] = params + end + end + end + opts[:input] ||= "" if String === opts[:input] env["rack.input"] = StringIO.new(opts[:input]) @@ -125,7 +149,7 @@ module Rack @body = "" body.each { |part| @body << part } - @errors = errors.string + @errors = errors.string if errors.respond_to?(:string) end # Status diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/recursive.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/recursive.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/recursive.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/recursive.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/reloader.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/reloader.rb new file mode 100644 index 00000000..aa2f060b --- /dev/null +++ b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/reloader.rb @@ -0,0 +1,106 @@ +# Copyright (c) 2009 Michael Fellinger m.fellinger@gmail.com +# All files in this distribution are subject to the terms of the Ruby license. + +require 'pathname' + +module Rack + + # High performant source reloader + # + # This class acts as Rack middleware. + # + # What makes it especially suited for use in a production environment is that + # any file will only be checked once and there will only be made one system + # call stat(2). + # + # Please note that this will not reload files in the background, it does so + # only when actively called. + # + # It is performing a check/reload cycle at the start of every request, but + # also respects a cool down time, during which nothing will be done. + class Reloader + def initialize(app, cooldown = 10, backend = Stat) + @app = app + @cooldown = cooldown + @last = (Time.now - cooldown) + @cache = {} + @mtimes = {} + + extend backend + end + + def call(env) + if @cooldown and Time.now > @last + @cooldown + if Thread.list.size > 1 + Thread.exclusive{ reload! } + else + reload! + end + + @last = Time.now + end + + @app.call(env) + end + + def reload!(stderr = $stderr) + rotation do |file, mtime| + previous_mtime = @mtimes[file] ||= mtime + safe_load(file, mtime, stderr) if mtime > previous_mtime + end + end + + # A safe Kernel::load, issuing the hooks depending on the results + def safe_load(file, mtime, stderr = $stderr) + load(file) + stderr.puts "#{self.class}: reloaded `#{file}'" + file + rescue LoadError, SyntaxError => ex + stderr.puts ex + ensure + @mtimes[file] = mtime + end + + module Stat + def rotation + files = [$0, *$LOADED_FEATURES].uniq + paths = ['./', *$LOAD_PATH].uniq + + files.map{|file| + next if file =~ /\.(so|bundle)$/ # cannot reload compiled files + + found, stat = figure_path(file, paths) + next unless found and stat and mtime = stat.mtime + + @cache[file] = found + + yield(found, mtime) + }.compact + end + + # Takes a relative or absolute +file+ name, a couple possible +paths+ that + # the +file+ might reside in. Returns the full path and File::Stat for the + # path. + def figure_path(file, paths) + found = @cache[file] + found = file if !found and Pathname.new(file).absolute? + found, stat = safe_stat(found) + return found, stat if found + + paths.each do |possible_path| + path = ::File.join(possible_path, file) + found, stat = safe_stat(path) + return ::File.expand_path(found), stat if found + end + end + + def safe_stat(file) + return unless file + stat = ::File.stat(file) + return file, stat if stat.file? + rescue Errno::ENOENT, Errno::ENOTDIR + @cache.delete(file) and false + end + end + end +end diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/request.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/request.rb similarity index 88% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/request.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/request.rb index d77fa265..04cdde00 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/request.rb +++ b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/request.rb @@ -17,7 +17,7 @@ module Rack # The environment of the request. attr_reader :env - def self.new(env) + def self.new(env, *args) if self == Rack::Request env["rack.request"] ||= super else @@ -38,6 +38,8 @@ module Rack def query_string; @env["QUERY_STRING"].to_s end def content_length; @env['CONTENT_LENGTH'] end def content_type; @env['CONTENT_TYPE'] end + def session; @env['rack.session'] ||= {} end + def session_options; @env['rack.session.options'] ||= {} end # The media type (type/subtype) portion of the CONTENT_TYPE header # without any media type parameters. e.g., when CONTENT_TYPE is @@ -46,7 +48,7 @@ module Rack # For more information on the use of media types in HTTP, see: # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7 def media_type - content_type && content_type.split(/\s*[;,]\s*/, 2)[0].downcase + content_type && content_type.split(/\s*[;,]\s*/, 2).first.downcase end # The media type parameters provided in CONTENT_TYPE as a Hash, or @@ -92,6 +94,14 @@ module Rack 'multipart/form-data' ] + # The set of media-types. Requests that do not indicate + # one of the media types presents in this list will not be eligible + # for param parsing like soap attachments or generic multiparts + PARSEABLE_DATA_MEDIA_TYPES = [ + 'multipart/related', + 'multipart/mixed' + ] + # Determine whether the request body contains form-data by checking # the request media_type against registered form-data media-types: # "application/x-www-form-urlencoded" and "multipart/form-data". The @@ -101,6 +111,12 @@ module Rack FORM_DATA_MEDIA_TYPES.include?(media_type) end + # Determine whether the request body contains data by checking + # the request media_type against registered parse-data media-types + def parseable_data? + PARSEABLE_DATA_MEDIA_TYPES.include?(media_type) + end + # Returns the data recieved in the query string. def GET if @env["rack.request.query_string"] == query_string @@ -119,7 +135,7 @@ module Rack def POST if @env["rack.request.form_input"].eql? @env["rack.input"] @env["rack.request.form_hash"] - elsif form_data? + elsif form_data? || parseable_data? @env["rack.request.form_input"] = @env["rack.input"] unless @env["rack.request.form_hash"] = Utils::Multipart.parse_multipart(env) @@ -131,12 +147,7 @@ module Rack @env["rack.request.form_vars"] = form_vars @env["rack.request.form_hash"] = Utils.parse_nested_query(form_vars) - begin - @env["rack.input"].rewind if @env["rack.input"].respond_to?(:rewind) - rescue Errno::ESPIPE - # Handles exceptions raised by input streams that cannot be rewound - # such as when using plain CGI under Apache - end + @env["rack.input"].rewind end @env["rack.request.form_hash"] else @@ -212,10 +223,12 @@ module Rack url end + def path + script_name + path_info + end + def fullpath - path = script_name + path_info - path << "?" << query_string unless query_string.empty? - path + query_string.empty? ? path : "#{path}?#{query_string}" end def accept_encoding diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/response.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/response.rb similarity index 97% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/response.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/response.rb index caf60d5b..28b4d830 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/response.rb +++ b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/response.rb @@ -95,6 +95,10 @@ module Rack :expires => Time.at(0) }.merge(value)) end + def redirect(target, status=302) + self.status = status + self["Location"] = target + end def finish(&block) @block = block @@ -120,7 +124,7 @@ module Rack # def write(str) s = str.to_s - @length += s.size + @length += Rack::Utils.bytesize(s) @writer.call s header["Content-Length"] = @length.to_s diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/rewindable_input.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/rewindable_input.rb new file mode 100644 index 00000000..2347dc35 --- /dev/null +++ b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/rewindable_input.rb @@ -0,0 +1,98 @@ +require 'tempfile' + +module Rack + # Class which can make any IO object rewindable, including non-rewindable ones. It does + # this by buffering the data into a tempfile, which is rewindable. + # + # rack.input is required to be rewindable, so if your input stream IO is non-rewindable + # by nature (e.g. a pipe or a socket) then you can wrap it in an object of this class + # to easily make it rewindable. + # + # Don't forget to call #close when you're done. This frees up temporary resources that + # RewindableInput uses, though it does *not* close the original IO object. + class RewindableInput + def initialize(io) + @io = io + @rewindable_io = nil + @unlinked = false + end + + def gets + make_rewindable unless @rewindable_io + @rewindable_io.gets + end + + def read(*args) + make_rewindable unless @rewindable_io + @rewindable_io.read(*args) + end + + def each(&block) + make_rewindable unless @rewindable_io + @rewindable_io.each(&block) + end + + def rewind + make_rewindable unless @rewindable_io + @rewindable_io.rewind + end + + # Closes this RewindableInput object without closing the originally + # wrapped IO oject. Cleans up any temporary resources that this RewindableInput + # has created. + # + # This method may be called multiple times. It does nothing on subsequent calls. + def close + if @rewindable_io + if @unlinked + @rewindable_io.close + else + @rewindable_io.close! + end + @rewindable_io = nil + end + end + + private + + # Ruby's Tempfile class has a bug. Subclass it and fix it. + class Tempfile < ::Tempfile + def _close + @tmpfile.close if @tmpfile + @data[1] = nil if @data + @tmpfile = nil + end + end + + def make_rewindable + # Buffer all data into a tempfile. Since this tempfile is private to this + # RewindableInput object, we chmod it so that nobody else can read or write + # it. On POSIX filesystems we also unlink the file so that it doesn't + # even have a file entry on the filesystem anymore, though we can still + # access it because we have the file handle open. + @rewindable_io = Tempfile.new('RackRewindableInput') + @rewindable_io.chmod(0000) + if filesystem_has_posix_semantics? + @rewindable_io.unlink + @unlinked = true + end + + buffer = "" + while @io.read(1024 * 4, buffer) + entire_buffer_written_out = false + while !entire_buffer_written_out + written = @rewindable_io.write(buffer) + entire_buffer_written_out = written == buffer.size + if !entire_buffer_written_out + buffer.slice!(0 .. written - 1) + end + end + end + @rewindable_io.rewind + end + + def filesystem_has_posix_semantics? + RUBY_PLATFORM !~ /(mswin|mingw|cygwin|java)/ + end + end +end diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/session/abstract/id.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/session/abstract/id.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/session/abstract/id.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/session/abstract/id.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/session/cookie.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/session/cookie.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/session/cookie.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/session/cookie.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/session/memcache.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/session/memcache.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/session/memcache.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/session/memcache.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/session/pool.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/session/pool.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/session/pool.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/session/pool.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/showexceptions.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/showexceptions.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/showexceptions.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/showexceptions.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/showstatus.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/showstatus.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/showstatus.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/showstatus.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/static.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/static.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/static.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/static.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/urlmap.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/urlmap.rb similarity index 95% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/urlmap.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/urlmap.rb index 0ff32df1..fcf6616c 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/urlmap.rb +++ b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/urlmap.rb @@ -30,7 +30,7 @@ module Rack location = location.chomp('/') [host, location, app] - }.sort_by { |(h, l, a)| [-l.size, h.to_s.size] } # Longest path first + }.sort_by { |(h, l, a)| [h ? -h.size : (-1.0 / 0.0), -l.size] } # Longest path first end def call(env) diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/utils.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/utils.rb similarity index 69% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/utils.rb rename to vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/utils.rb index 0a61bce7..42e2e698 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/utils.rb +++ b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/utils.rb @@ -1,3 +1,5 @@ +# -*- encoding: binary -*- + require 'set' require 'tempfile' @@ -63,7 +65,7 @@ module Rack module_function :parse_nested_query def normalize_params(params, name, v = nil) - name =~ %r([\[\]]*([^\[\]]+)\]*) + name =~ %r(\A[\[\]]*([^\[\]]+)\]*) k = $1 || '' after = $' || '' @@ -73,12 +75,12 @@ module Rack params[k] = v elsif after == "[]" params[k] ||= [] - raise TypeError unless params[k].is_a?(Array) + raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) params[k] << v elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$) child_key = $1 params[k] ||= [] - raise TypeError unless params[k].is_a?(Array) + raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) if params[k].last.is_a?(Hash) && !params[k].last.key?(child_key) normalize_params(params[k].last, child_key, v) else @@ -86,6 +88,7 @@ module Rack end else params[k] ||= {} + raise TypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Hash) params[k] = normalize_params(params[k], after, v) end @@ -104,6 +107,25 @@ module Rack end module_function :build_query + def build_nested_query(value, prefix = nil) + case value + when Array + value.map { |v| + build_nested_query(v, "#{prefix}[]") + }.join("&") + when Hash + value.map { |k, v| + build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k)) + }.join("&") + when String + raise ArgumentError, "value must be a Hash" if prefix.nil? + "#{prefix}=#{escape(value)}" + else + prefix + end + end + module_function :build_nested_query + # Escape ampersands, brackets and quotes to their HTML/XML entities. def escape_html(string) string.to_s.gsub("&", "&"). @@ -288,11 +310,39 @@ module Rack # Usually, Rack::Request#POST takes care of calling this. module Multipart + class UploadedFile + # The filename, *not* including the path, of the "uploaded" file + attr_reader :original_filename + + # The content type of the "uploaded" file + attr_accessor :content_type + + def initialize(path, content_type = "text/plain", binary = false) + raise "#{path} file does not exist" unless ::File.exist?(path) + @content_type = content_type + @original_filename = ::File.basename(path) + @tempfile = Tempfile.new(@original_filename) + @tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding) + @tempfile.binmode if binary + FileUtils.copy_file(path, @tempfile.path) + end + + def path + @tempfile.path + end + alias_method :local_path, :path + + def method_missing(method_name, *args, &block) #:nodoc: + @tempfile.__send__(method_name, *args, &block) + end + end + EOL = "\r\n" + MULTIPART_BOUNDARY = "AaB03x" def self.parse_multipart(env) unless env['CONTENT_TYPE'] =~ - %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n + %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n nil else boundary = "--#{$1}" @@ -301,13 +351,16 @@ module Rack buf = "" content_length = env['CONTENT_LENGTH'].to_i input = env['rack.input'] + input.rewind - boundary_size = boundary.size + EOL.size + boundary_size = Utils.bytesize(boundary) + EOL.size bufsize = 16384 content_length -= boundary_size - status = input.read(boundary_size) + read_buffer = '' + + status = input.read(boundary_size, read_buffer) raise EOFError, "bad content body" unless status == boundary + EOL rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/n @@ -318,15 +371,15 @@ module Rack filename = content_type = name = nil until head && buf =~ rx - if !head && i = buf.index("\r\n\r\n") + if !head && i = buf.index(EOL+EOL) head = buf.slice!(0, i+2) # First \r\n buf.slice!(0, 2) # Second \r\n filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1] - content_type = head[/Content-Type: (.*)\r\n/ni, 1] - name = head[/Content-Disposition:.* name="?([^\";]*)"?/ni, 1] + content_type = head[/Content-Type: (.*)#{EOL}/ni, 1] + name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1] - if filename + if content_type || filename body = Tempfile.new("RackMultipart") body.binmode if body.respond_to?(:binmode) end @@ -339,7 +392,7 @@ module Rack body << buf.slice!(0, buf.size - (boundary_size+4)) end - c = input.read(bufsize < content_length ? bufsize : content_length) + c = input.read(bufsize < content_length ? bufsize : content_length, read_buffer) raise EOFError, "bad content body" if c.nil? || c.empty? buf << c content_length -= c.size @@ -368,6 +421,12 @@ module Rack data = {:filename => filename, :type => content_type, :name => name, :tempfile => body, :head => head} + elsif !filename && content_type + body.rewind + + # Generic multipart cases, not coming from a form + data = {:type => content_type, + :name => name, :tempfile => body, :head => head} else data = body end @@ -377,16 +436,81 @@ module Rack break if buf.empty? || content_length == -1 } - begin - input.rewind if input.respond_to?(:rewind) - rescue Errno::ESPIPE - # Handles exceptions raised by input streams that cannot be rewound - # such as when using plain CGI under Apache - end + input.rewind params end end + + def self.build_multipart(params, first = true) + if first + unless params.is_a?(Hash) + raise ArgumentError, "value must be a Hash" + end + + multipart = false + query = lambda { |value| + case value + when Array + value.each(&query) + when Hash + value.values.each(&query) + when UploadedFile + multipart = true + end + } + params.values.each(&query) + return nil unless multipart + end + + flattened_params = Hash.new + + params.each do |key, value| + k = first ? key.to_s : "[#{key}]" + + case value + when Array + value.map { |v| + build_multipart(v, false).each { |subkey, subvalue| + flattened_params["#{k}[]#{subkey}"] = subvalue + } + } + when Hash + build_multipart(value, false).each { |subkey, subvalue| + flattened_params[k + subkey] = subvalue + } + else + flattened_params[k] = value + end + end + + if first + flattened_params.map { |name, file| + if file.respond_to?(:original_filename) + ::File.open(file.path, "rb") do |f| + f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding) +<<-EOF +--#{MULTIPART_BOUNDARY}\r +Content-Disposition: form-data; name="#{name}"; filename="#{Utils.escape(file.original_filename)}"\r +Content-Type: #{file.content_type}\r +Content-Length: #{::File.stat(file.path).size}\r +\r +#{f.read}\r +EOF + end + else +<<-EOF +--#{MULTIPART_BOUNDARY}\r +Content-Disposition: form-data; name="#{name}"\r +\r +#{file}\r +EOF + end + }.join + "--#{MULTIPART_BOUNDARY}--\r" + else + flattened_params + end + end end end end diff --git a/vendor/rails/actionpack/lib/action_pack/version.rb b/vendor/rails/actionpack/lib/action_pack/version.rb index e0aa2a5f..66fca7df 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 = 3 - TINY = 2 + TINY = 3 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/vendor/rails/actionpack/lib/action_view/helpers.rb b/vendor/rails/actionpack/lib/action_view/helpers.rb index 693ab7c2..97fa2d80 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers.rb @@ -11,7 +11,7 @@ module ActionView #:nodoc: autoload :FormHelper, 'action_view/helpers/form_helper' autoload :FormOptionsHelper, 'action_view/helpers/form_options_helper' autoload :FormTagHelper, 'action_view/helpers/form_tag_helper' - autoload :JavascriptHelper, 'action_view/helpers/javascript_helper' + autoload :JavaScriptHelper, 'action_view/helpers/javascript_helper' autoload :NumberHelper, 'action_view/helpers/number_helper' autoload :PrototypeHelper, 'action_view/helpers/prototype_helper' autoload :RecordIdentificationHelper, 'action_view/helpers/record_identification_helper' 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 a32beb61..babb9db3 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 @@ -272,14 +272,17 @@ module ActionView # javascript_include_tag :all, :cache => true, :recursive => true def javascript_include_tag(*sources) options = sources.extract_options!.stringify_keys - cache = options.delete("cache") + concat = options.delete("concat") + cache = concat || options.delete("cache") recursive = options.delete("recursive") - if ActionController::Base.perform_caching && cache + if concat || (ActionController::Base.perform_caching && cache) joined_javascript_name = (cache == true ? "all" : cache) + ".js" - joined_javascript_path = File.join(JAVASCRIPTS_DIR, joined_javascript_name) + joined_javascript_path = File.join(joined_javascript_name[/^#{File::SEPARATOR}/] ? ASSETS_DIR : JAVASCRIPTS_DIR, joined_javascript_name) - write_asset_file_contents(joined_javascript_path, compute_javascript_paths(sources, recursive)) unless File.exists?(joined_javascript_path) + unless ActionController::Base.perform_caching && File.exists?(joined_javascript_path) + write_asset_file_contents(joined_javascript_path, compute_javascript_paths(sources, recursive)) + end javascript_src_tag(joined_javascript_name, options) else expand_javascript_sources(sources, recursive).collect { |source| javascript_src_tag(source, options) }.join("\n") @@ -410,16 +413,25 @@ module ActionView # The :recursive option is also available for caching: # # stylesheet_link_tag :all, :cache => true, :recursive => true + # + # To force concatenation (even in development mode) set :concat to true. This is useful if + # you have too many stylesheets for IE to load. + # + # stylesheet_link_tag :all, :concat => true + # def stylesheet_link_tag(*sources) options = sources.extract_options!.stringify_keys - cache = options.delete("cache") + concat = options.delete("concat") + cache = concat || options.delete("cache") recursive = options.delete("recursive") - if ActionController::Base.perform_caching && cache + if concat || (ActionController::Base.perform_caching && cache) joined_stylesheet_name = (cache == true ? "all" : cache) + ".css" - joined_stylesheet_path = File.join(STYLESHEETS_DIR, joined_stylesheet_name) + joined_stylesheet_path = File.join(joined_stylesheet_name[/^#{File::SEPARATOR}/] ? ASSETS_DIR : STYLESHEETS_DIR, joined_stylesheet_name) - write_asset_file_contents(joined_stylesheet_path, compute_stylesheet_paths(sources, recursive)) unless File.exists?(joined_stylesheet_path) + unless ActionController::Base.perform_caching && File.exists?(joined_stylesheet_path) + write_asset_file_contents(joined_stylesheet_path, compute_stylesheet_paths(sources, recursive)) + end stylesheet_tag(joined_stylesheet_name, options) else expand_stylesheet_sources(sources, recursive).collect { |source| stylesheet_tag(source, options) }.join("\n") @@ -679,4 +691,4 @@ module ActionView end end end -end \ No newline at end of file +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 a589bcba..2ac407c7 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/form_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/form_helper.rb @@ -493,7 +493,8 @@ module ActionView # Returns a label tag tailored for labelling an input field for a specified attribute (identified by +method+) on an object # assigned to the template (identified by +object+). The text of label will default to the attribute name unless you specify # it explicitly. Additional options on the label tag can be passed as a hash with +options+. These options will be tagged - # onto the HTML as an HTML element attribute as in the example shown. + # onto the HTML as an HTML element attribute as in the example shown, except for the :value option, which is designed to + # target labels for radio_button tags (where the value is used in the ID of the input tag). # # ==== Examples # label(:post, :title) @@ -505,6 +506,9 @@ module ActionView # label(:post, :title, "A short title", :class => "title_label") # # => # + # label(:post, :privacy, "Public Post", :value => "public") + # # => + # def label(object_name, method, text = nil, options = {}) InstanceTag.new(object_name, method, self, options.delete(:object)).to_label_tag(text, options) end @@ -720,8 +724,9 @@ module ActionView def to_label_tag(text = nil, options = {}) options = options.stringify_keys + tag_value = options.delete("value") name_and_id = options.dup - add_default_name_and_id(name_and_id) + add_default_name_and_id_for_value(tag_value, name_and_id) options.delete("index") options["for"] ||= name_and_id["id"] content = (text.blank? ? nil : text.to_s) || method_name.humanize @@ -753,11 +758,7 @@ module ActionView checked = self.class.radio_button_checked?(value(object), tag_value) end options["checked"] = "checked" if checked - pretty_tag_value = tag_value.to_s.gsub(/\s/, "_").gsub(/\W/, "").downcase - options["id"] ||= defined?(@auto_index) ? - "#{tag_id_with_index(@auto_index)}_#{pretty_tag_value}" : - "#{tag_id}_#{pretty_tag_value}" - add_default_name_and_id(options) + add_default_name_and_id_for_value(tag_value, options) tag("input", options) end @@ -858,6 +859,17 @@ module ActionView end private + def add_default_name_and_id_for_value(tag_value, options) + if tag_value + pretty_tag_value = tag_value.to_s.gsub(/\s/, "_").gsub(/\W/, "").downcase + specified_id = options["id"] + add_default_name_and_id(options) + options["id"] += "_#{pretty_tag_value}" unless specified_id + else + add_default_name_and_id(options) + end + end + def add_default_name_and_id(options) if options.has_key?("index") options["name"] ||= tag_name_with_index(options["index"]) @@ -905,6 +917,7 @@ module ActionView attr_accessor :object_name, :object, :options def initialize(object_name, object, template, options, proc) + @nested_child_index = {} @object_name, @object, @template, @options, @proc = object_name, object, template, options, proc @default_options = @options ? @options.slice(:index) : {} if @object_name.to_s.match(/\[\]$/) @@ -1007,7 +1020,7 @@ module ActionView explicit_child_index = args.last[:child_index] if args.last.is_a?(Hash) children.map do |child| - fields_for_nested_model("#{name}[#{explicit_child_index || nested_child_index}]", child, args, block) + fields_for_nested_model("#{name}[#{explicit_child_index || nested_child_index(name)}]", child, args, block) end.join else fields_for_nested_model(name, explicit_object || association, args, block) @@ -1025,9 +1038,9 @@ module ActionView end end - def nested_child_index - @nested_child_index ||= -1 - @nested_child_index += 1 + def nested_child_index(name) + @nested_child_index[name] ||= -1 + @nested_child_index[name] += 1 end end end @@ -1036,4 +1049,4 @@ module ActionView cattr_accessor :default_form_builder self.default_form_builder = ::ActionView::Helpers::FormBuilder end -end \ No newline at end of file +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 6b385ef7..6adbab17 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 @@ -230,6 +230,8 @@ module ActionView # # NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag. def options_for_select(container, selected = nil) + return container if String === container + container = container.to_a if Hash === container selected, disabled = extract_selected_and_disabled(selected) 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 6d39a53a..c2171916 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 @@ -230,6 +230,8 @@ module ActionView # * :rows - Specify the number of rows in the textarea # * :cols - Specify the number of columns in the textarea # * :disabled - If set to true, the user will not be able to use this input. + # * :escape - By default, the contents of the text input are HTML escaped. + # If you need unescaped contents, set this to false. # * Any other key creates standard HTML attributes for the tag. # # ==== Examples @@ -257,7 +259,10 @@ module ActionView options["cols"], options["rows"] = size.split("x") if size.respond_to?(:split) end - content_tag :textarea, content, { "name" => name, "id" => name }.update(options.stringify_keys) + escape = options.key?("escape") ? options.delete("escape") : true + content = html_escape(content) if escape + + content_tag :textarea, content, { "name" => name, "id" => sanitize_to_id(name) }.update(options.stringify_keys) end # Creates a check box form input tag. @@ -353,7 +358,8 @@ module ActionView disable_with << ";#{options.delete('onclick')}" if options['onclick'] options["onclick"] = "if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }" - options["onclick"] << "else { hiddenCommit = this.cloneNode(false);hiddenCommit.setAttribute('type', 'hidden');this.form.appendChild(hiddenCommit); }" + options["onclick"] << "else { hiddenCommit = document.createElement('input');hiddenCommit.type = 'hidden';" + options["onclick"] << "hiddenCommit.value = this.value;hiddenCommit.name = this.name;this.form.appendChild(hiddenCommit); }" options["onclick"] << "this.setAttribute('originalValue', this.value);this.disabled = true;#{disable_with};" options["onclick"] << "result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());" options["onclick"] << "if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;" @@ -444,10 +450,10 @@ module ActionView '' when /^post$/i, "", nil html_options["method"] = "post" - protect_against_forgery? ? content_tag(:div, token_tag, :style => 'margin:0;padding:0') : '' + protect_against_forgery? ? content_tag(:div, token_tag, :style => 'margin:0;padding:0;display:inline') : '' else html_options["method"] = "post" - content_tag(:div, tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag, :style => 'margin:0;padding:0') + content_tag(:div, tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag, :style => 'margin:0;padding:0;display:inline') end 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 91ef72e5..448d6f5f 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -686,7 +686,7 @@ module ActionView # Returns an object whose to_json evaluates to +code+. Use this to pass a literal JavaScript # expression as an argument to another JavaScriptGenerator method. def literal(code) - ActiveSupport::JSON::Variable.new(code.to_s) + ::ActiveSupport::JSON::Variable.new(code.to_s) end # Returns a collection reference by finding it through a CSS +pattern+ in the DOM. This collection can then be @@ -973,7 +973,7 @@ module ActionView def loop_on_multiple_args(method, ids) record(ids.size>1 ? "#{javascript_object_for(ids)}.each(#{method})" : - "#{method}(#{ids.first.to_json})") + "#{method}(#{::ActiveSupport::JSON.encode(ids.first)})") end def page @@ -997,7 +997,7 @@ module ActionView end def javascript_object_for(object) - object.respond_to?(:to_json) ? object.to_json : object.inspect + ::ActiveSupport::JSON.encode(object) end def arguments_for_call(arguments, block = nil) @@ -1139,7 +1139,7 @@ module ActionView class JavaScriptElementProxy < JavaScriptProxy #:nodoc: def initialize(generator, id) @id = id - super(generator, "$(#{id.to_json})") + super(generator, "$(#{::ActiveSupport::JSON.encode(id)})") end # Allows access of element attributes through +attribute+. Examples: @@ -1211,7 +1211,7 @@ module ActionView enumerate :eachSlice, :variable => variable, :method_args => [number], :yield_args => %w(value index), :return => true, &block else add_variable_assignment!(variable) - append_enumerable_function!("eachSlice(#{number.to_json});") + append_enumerable_function!("eachSlice(#{::ActiveSupport::JSON.encode(number)});") end end @@ -1232,7 +1232,7 @@ module ActionView def pluck(variable, property) add_variable_assignment!(variable) - append_enumerable_function!("pluck(#{property.to_json});") + append_enumerable_function!("pluck(#{::ActiveSupport::JSON.encode(property)});") end def zip(variable, *arguments, &block) @@ -1296,7 +1296,7 @@ module ActionView class JavaScriptElementCollectionProxy < JavaScriptCollectionProxy #:nodoc:\ def initialize(generator, pattern) - super(generator, "$$(#{pattern.to_json})") + super(generator, "$$(#{::ActiveSupport::JSON.encode(pattern)})") end end end diff --git a/vendor/rails/actionpack/lib/action_view/helpers/scriptaculous_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/scriptaculous_helper.rb index e16935ea..04af2781 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/scriptaculous_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/scriptaculous_helper.rb @@ -43,7 +43,7 @@ module ActionView # You can change the behaviour with various options, see # http://script.aculo.us for more documentation. def visual_effect(name, element_id = false, js_options = {}) - element = element_id ? element_id.to_json : "element" + element = element_id ? ActiveSupport::JSON.encode(element_id) : "element" js_options[:queue] = if js_options[:queue].is_a?(Hash) '{' + js_options[:queue].map {|k, v| k == :limit ? "#{k}:#{v}" : "#{k}:'#{v}'" }.join(',') + '}' @@ -138,7 +138,7 @@ module ActionView end def sortable_element_js(element_id, options = {}) #:nodoc: - options[:with] ||= "Sortable.serialize(#{element_id.to_json})" + options[:with] ||= "Sortable.serialize(#{ActiveSupport::JSON.encode(element_id)})" options[:onUpdate] ||= "function(){" + remote_function(options) + "}" options.delete_if { |key, value| PrototypeHelper::AJAX_OPTIONS.include?(key) } @@ -149,7 +149,7 @@ module ActionView options[:containment] = array_or_string_for_javascript(options[:containment]) if options[:containment] options[:only] = array_or_string_for_javascript(options[:only]) if options[:only] - %(Sortable.create(#{element_id.to_json}, #{options_for_javascript(options)});) + %(Sortable.create(#{ActiveSupport::JSON.encode(element_id)}, #{options_for_javascript(options)});) end # Makes the element with the DOM ID specified by +element_id+ draggable. @@ -164,7 +164,7 @@ module ActionView end def draggable_element_js(element_id, options = {}) #:nodoc: - %(new Draggable(#{element_id.to_json}, #{options_for_javascript(options)});) + %(new Draggable(#{ActiveSupport::JSON.encode(element_id)}, #{options_for_javascript(options)});) end # Makes the element with the DOM ID specified by +element_id+ receive @@ -219,7 +219,7 @@ module ActionView # Confirmation happens during the onDrop callback, so it can be removed from the options options.delete(:confirm) if options[:confirm] - %(Droppables.add(#{element_id.to_json}, #{options_for_javascript(options)});) + %(Droppables.add(#{ActiveSupport::JSON.encode(element_id)}, #{options_for_javascript(options)});) end end end diff --git a/vendor/rails/actionpack/lib/action_view/helpers/text_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/text_helper.rb index 48bf4717..8463af97 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/text_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/text_helper.rb @@ -271,8 +271,8 @@ module ActionView end # Returns the text with all the Markdown codes turned into HTML tags. - # This method requires BlueCloth[http://www.deveiate.org/projects/BlueCloth] - # to be available. + # This method requires BlueCloth[http://www.deveiate.org/projects/BlueCloth] or another + # Markdown library to be installed.. # # ==== Examples # markdown("We are using __Markdown__ now!") @@ -288,7 +288,7 @@ module ActionView # markdown('![The ROR logo](http://rubyonrails.com/images/rails.png "Ruby on Rails")') # # => '

The ROR logo

' def markdown(text) - text.blank? ? "" : BlueCloth.new(text).to_html + text.blank? ? "" : Markdown.new(text).to_html end # Returns +text+ transformed into HTML using simple formatting rules. diff --git a/vendor/rails/actionpack/lib/action_view/helpers/url_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/url_helper.rb index 36e0a78e..92708861 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/url_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/url_helper.rb @@ -1,4 +1,4 @@ -require 'action_view/helpers/javascript_helper' +#require 'action_view/helpers/javascript_helper' module ActionView module Helpers #:nodoc: diff --git a/vendor/rails/actionpack/lib/action_view/paths.rb b/vendor/rails/actionpack/lib/action_view/paths.rb index 8cc3fe29..a0a2f968 100644 --- a/vendor/rails/actionpack/lib/action_view/paths.rb +++ b/vendor/rails/actionpack/lib/action_view/paths.rb @@ -61,7 +61,7 @@ module ActionView #:nodoc: end end - return Template.new(original_template_path, original_template_path.to_s =~ /\A\// ? "" : ".") if File.file?(original_template_path) + return Template.new(original_template_path) if File.file?(original_template_path) raise MissingTemplate.new(self, original_template_path, format) end diff --git a/vendor/rails/actionpack/lib/action_view/template.rb b/vendor/rails/actionpack/lib/action_view/template.rb index c339c8a5..a974f265 100644 --- a/vendor/rails/actionpack/lib/action_view/template.rb +++ b/vendor/rails/actionpack/lib/action_view/template.rb @@ -107,9 +107,8 @@ module ActionView #:nodoc: attr_accessor :locale, :name, :format, :extension delegate :to_s, :to => :path - def initialize(template_path, load_path) - @template_path = template_path.dup - @load_path, @filename = load_path, File.join(load_path, template_path) + def initialize(template_path, load_path = nil) + @template_path, @load_path = template_path.dup, load_path @base_path, @name, @locale, @format, @extension = split(template_path) @base_path.to_s.gsub!(/\/$/, '') # Push to split method @@ -180,6 +179,12 @@ module ActionView #:nodoc: @@exempt_from_layout.any? { |exempted| path =~ exempted } end + def filename + # no load_path means this is an "absolute pathed" template + load_path ? File.join(load_path, template_path) : template_path + end + memoize :filename + def source File.read(filename) end @@ -212,46 +217,30 @@ module ActionView #:nodoc: end def valid_locale?(locale) - I18n.available_locales.include?(locale.to_sym) + locale && I18n.available_locales.include?(locale.to_sym) end # Returns file split into an array # [base_path, name, locale, format, extension] def split(file) if m = file.to_s.match(/^(.*\/)?([^\.]+)\.(.*)$/) - base_path = m[1] - name = m[2] - extensions = m[3] - else - return + [m[1], m[2], *parse_extensions(m[3])] + end + end + + # returns parsed extensions as an array + # [locale, format, extension] + def parse_extensions(extensions) + exts = extensions.split(".") + + if extension = valid_extension?(exts.last) && exts.pop || nil + locale = valid_locale?(exts.first) && exts.shift || nil + format = exts.join('.') if exts.any? # join('.') is needed for multipart templates + else # no extension, just format + format = exts.last end - locale = nil - format = nil - extension = nil - - if m = extensions.split(".") - if valid_locale?(m[0]) && m[1] && valid_extension?(m[2]) # All three - locale = m[0] - format = m[1] - extension = m[2] - elsif m[0] && m[1] && valid_extension?(m[2]) # Multipart formats - format = "#{m[0]}.#{m[1]}" - extension = m[2] - elsif valid_locale?(m[0]) && valid_extension?(m[1]) # locale and extension - locale = m[0] - extension = m[1] - elsif valid_extension?(m[1]) # format and extension - format = m[0] - extension = m[1] - elsif valid_extension?(m[0]) # Just extension - extension = m[0] - else # No extension - format = m[0] - end - end - - [base_path, name, locale, format, extension] + [locale, format, extension] end end end diff --git a/vendor/rails/actionpack/test/abstract_unit.rb b/vendor/rails/actionpack/test/abstract_unit.rb index cdeee934..0b67e56d 100644 --- a/vendor/rails/actionpack/test/abstract_unit.rb +++ b/vendor/rails/actionpack/test/abstract_unit.rb @@ -8,7 +8,7 @@ require 'yaml' require 'stringio' require 'test/unit' -gem 'mocha', '>= 0.9.5' +gem 'mocha', '>= 0.9.7' require 'mocha' begin 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 c98892ed..bde36eb9 100644 --- a/vendor/rails/actionpack/test/activerecord/active_record_store_test.rb +++ b/vendor/rails/actionpack/test/activerecord/active_record_store_test.rb @@ -27,9 +27,9 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest end def call_reset_session - session[:bar] + session[:foo] reset_session - session[:bar] = "baz" + session[:foo] = "baz" head :ok end @@ -86,7 +86,7 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest get '/get_session_value' assert_response :success - assert_equal 'foo: nil', response.body + assert_equal 'foo: "baz"', response.body get '/get_session_id' assert_response :success 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 cb7922ef..6e92eff0 100644 --- a/vendor/rails/actionpack/test/controller/action_pack_assertions_test.rb +++ b/vendor/rails/actionpack/test/controller/action_pack_assertions_test.rb @@ -11,6 +11,9 @@ class ActionPackAssertionsController < ActionController::Base # a standard template def hello_xml_world() render :template => "test/hello_xml_world"; end + + # a standard partial + def partial() render :partial => 'test/partial'; end # a redirect to an internal location def redirect_internal() redirect_to "/nothing"; end @@ -332,6 +335,30 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase assert @response.rendered[:template] assert 'hello_world', @response.rendered[:template].to_s end + + def test_assert_template_with_partial + get :partial + assert_template :partial => '_partial' + end + + def test_assert_template_with_nil + get :nothing + assert_template nil + end + + def test_assert_template_with_string + get :hello_world + assert_template 'hello_world' + end + + def test_assert_template_with_symbol + get :hello_world + assert_template :hello_world + end + + def test_assert_template_with_bad_argument + assert_raise(ArgumentError) { assert_template 1 } + end # check the redirection location def test_redirection_location diff --git a/vendor/rails/actionpack/test/controller/caching_test.rb b/vendor/rails/actionpack/test/controller/caching_test.rb index 86dafd92..6dcb67e5 100644 --- a/vendor/rails/actionpack/test/controller/caching_test.rb +++ b/vendor/rails/actionpack/test/controller/caching_test.rb @@ -1,5 +1,6 @@ require 'fileutils' require 'abstract_unit' +require 'active_record_unit' CACHE_DIR = 'test_cache' # Don't change '/../temp/' cavalierly or you might hose something you don't want hosed @@ -7,6 +8,10 @@ FILE_STORE_PATH = File.join(File.dirname(__FILE__), '/../temp/', CACHE_DIR) ActionController::Base.page_cache_directory = FILE_STORE_PATH ActionController::Base.cache_store = :file_store, FILE_STORE_PATH +# Force sweeper classes to load +ActionController::Caching::Sweeper +ActionController::Caching::Sweeping + class PageCachingTestController < ActionController::Base caches_page :ok, :no_content, :if => Proc.new { |c| !c.request.format.json? } caches_page :found, :not_found @@ -152,6 +157,7 @@ class ActionCachingTestController < ActionController::Base caches_action :edit, :cache_path => Proc.new { |c| c.params[:id] ? "http://test.host/#{c.params[:id]};edit" : "http://test.host/edit" } caches_action :with_layout caches_action :layout_false, :layout => false + caches_action :record_not_found, :four_oh_four, :simple_runtime_error layout 'talk_from_action.erb' @@ -174,6 +180,18 @@ class ActionCachingTestController < ActionController::Base render :text => @cache_this, :layout => true end + def record_not_found + raise ActiveRecord::RecordNotFound, "oops!" + end + + def four_oh_four + render :text => "404'd!", :status => 404 + end + + def simple_runtime_error + raise "oops!" + end + alias_method :show, :index alias_method :edit, :index alias_method :destroy, :index @@ -456,6 +474,27 @@ class ActionCacheTest < ActionController::TestCase assert_response :success end + def test_record_not_found_returns_404_for_multiple_requests + get :record_not_found + assert_response 404 + get :record_not_found + assert_response 404 + end + + def test_four_oh_four_returns_404_for_multiple_requests + get :four_oh_four + assert_response 404 + get :four_oh_four + assert_response 404 + end + + def test_simple_runtime_error_returns_500_for_multiple_requests + get :simple_runtime_error + assert_response 500 + get :simple_runtime_error + assert_response 500 + end + private def content_to_cache assigns(:cache_this) diff --git a/vendor/rails/actionpack/test/controller/cookie_test.rb b/vendor/rails/actionpack/test/controller/cookie_test.rb index 657be3c4..f7d97e16 100644 --- a/vendor/rails/actionpack/test/controller/cookie_test.rb +++ b/vendor/rails/actionpack/test/controller/cookie_test.rb @@ -6,6 +6,10 @@ class CookieTest < ActionController::TestCase cookies["user_name"] = "david" end + def set_with_with_escapable_characters + cookies["that & guy"] = "foo & bar => baz" + end + def authenticate_for_fourteen_days cookies["user_name"] = { "value" => "david", "expires" => Time.utc(2005, 10, 10,5) } end @@ -53,6 +57,12 @@ class CookieTest < ActionController::TestCase assert_equal({"user_name" => "david"}, @response.cookies) end + def test_setting_with_escapable_characters + get :set_with_with_escapable_characters + assert_equal ["that+%26+guy=foo+%26+bar+%3D%3E+baz; path=/"], @response.headers["Set-Cookie"] + assert_equal({"that & guy" => "foo & bar => baz"}, @response.cookies) + end + def test_setting_cookie_for_fourteen_days get :authenticate_for_fourteen_days assert_equal ["user_name=david; path=/; expires=Mon, 10-Oct-2005 05:00:00 GMT"], @response.headers["Set-Cookie"] diff --git a/vendor/rails/actionpack/test/controller/dispatcher_test.rb b/vendor/rails/actionpack/test/controller/dispatcher_test.rb index 7887b711..3aa5bf98 100644 --- a/vendor/rails/actionpack/test/controller/dispatcher_test.rb +++ b/vendor/rails/actionpack/test/controller/dispatcher_test.rb @@ -25,7 +25,8 @@ class DispatcherTest < Test::Unit::TestCase def test_clears_dependencies_after_dispatch_if_in_loading_mode ActiveSupport::Dependencies.expects(:clear).once - dispatch(false) + # Close the response so dependencies kicks in + dispatch(false).last.close end def test_reloads_routes_before_dispatch_if_in_loading_mode @@ -49,13 +50,14 @@ class DispatcherTest < Test::Unit::TestCase Dispatcher.any_instance.expects(:dispatch).raises('b00m') ActionController::Failsafe.any_instance.expects(:log_failsafe_exception) + response = nil assert_nothing_raised do - assert_equal [ - 500, - {"Content-Type" => "text/html"}, - "

500 Internal Server Error

" - ], dispatch + response = dispatch end + assert_equal 3, response.size + assert_equal 500, response[0] + assert_equal({"Content-Type" => "text/html"}, response[1]) + assert_match /500 Internal Server Error/, response[2].join end def test_prepare_callbacks @@ -94,7 +96,7 @@ class DispatcherTest < Test::Unit::TestCase def dispatch(cache_classes = true) ActionController::Routing::RouteSet.any_instance.stubs(:call).returns([200, {}, 'response']) Dispatcher.define_dispatcher_callbacks(cache_classes) - Dispatcher.new.call({}) + Dispatcher.new.call({'rack.input' => StringIO.new('')}) end def assert_subclasses(howmany, klass, message = klass.subclasses.inspect) diff --git a/vendor/rails/actionpack/test/controller/failsafe_test.rb b/vendor/rails/actionpack/test/controller/failsafe_test.rb new file mode 100644 index 00000000..9008f645 --- /dev/null +++ b/vendor/rails/actionpack/test/controller/failsafe_test.rb @@ -0,0 +1,60 @@ +require 'abstract_unit' +require 'stringio' +require 'logger' + +class FailsafeTest < ActionController::TestCase + FIXTURE_PUBLIC = "#{File.dirname(__FILE__)}/../fixtures/failsafe".freeze + + def setup + @old_error_file_path = ActionController::Failsafe.error_file_path + ActionController::Failsafe.error_file_path = FIXTURE_PUBLIC + @app = mock + @log_io = StringIO.new + @logger = Logger.new(@log_io) + @failsafe = ActionController::Failsafe.new(@app) + @failsafe.stubs(:failsafe_logger).returns(@logger) + end + + def teardown + ActionController::Failsafe.error_file_path = @old_error_file_path + end + + def app_will_raise_error! + @app.expects(:call).then.raises(RuntimeError.new("Printer on fire")) + end + + def test_calls_app_and_returns_its_return_value + @app.expects(:call).returns([200, { "Content-Type" => "text/html" }, "ok"]) + assert_equal [200, { "Content-Type" => "text/html" }, "ok"], @failsafe.call({}) + end + + def test_writes_to_log_file_on_exception + app_will_raise_error! + @failsafe.call({}) + assert_match /Printer on fire/, @log_io.string # Logs exception message. + assert_match /failsafe_test\.rb/, @log_io.string # Logs backtrace. + end + + def test_returns_500_internal_server_error_on_exception + app_will_raise_error! + response = @failsafe.call({}) + assert_equal 3, response.size # It is a valid Rack response. + assert_equal 500, response[0] # Status is 500. + end + + def test_renders_error_page_file_with_erb + app_will_raise_error! + response = @failsafe.call({}) + assert_equal 500, response[0] + assert_equal "hello my world", response[2].join + end + + def test_returns_a_default_message_if_erb_rendering_failed + app_will_raise_error! + @failsafe.expects(:render_template).raises(RuntimeError.new("Harddisk is crashing")) + response = @failsafe.call({}) + assert_equal 500, response[0] + assert_match /500 Internal Server Error/, response[2].join + assert_match %r(please read this web application's log file), response[2].join + end +end diff --git a/vendor/rails/actionpack/test/controller/filter_params_test.rb b/vendor/rails/actionpack/test/controller/filter_params_test.rb index 0b259a79..0f480881 100644 --- a/vendor/rails/actionpack/test/controller/filter_params_test.rb +++ b/vendor/rails/actionpack/test/controller/filter_params_test.rb @@ -23,7 +23,8 @@ class FilterParamTest < Test::Unit::TestCase [{'foo'=>'bar', 'bar'=>'foo'},{'foo'=>'[FILTERED]', 'bar'=>'foo'},%w'foo baz'], [{'foo'=>'bar', 'baz'=>'foo'},{'foo'=>'[FILTERED]', 'baz'=>'[FILTERED]'},%w'foo baz'], [{'bar'=>{'foo'=>'bar','bar'=>'foo'}},{'bar'=>{'foo'=>'[FILTERED]','bar'=>'foo'}},%w'fo'], - [{'foo'=>{'foo'=>'bar','bar'=>'foo'}},{'foo'=>'[FILTERED]'},%w'f banana']] + [{'foo'=>{'foo'=>'bar','bar'=>'foo'}},{'foo'=>'[FILTERED]'},%w'f banana'], + [{'baz'=>[{'foo'=>'baz'}]}, {'baz'=>[{'foo'=>'[FILTERED]'}]}, %w(foo)]] test_hashes.each do |before_filter, after_filter, filter_words| FilterParamController.filter_parameter_logging(*filter_words) diff --git a/vendor/rails/actionpack/test/controller/flash_test.rb b/vendor/rails/actionpack/test/controller/flash_test.rb index d8a89281..81c724a5 100644 --- a/vendor/rails/actionpack/test/controller/flash_test.rb +++ b/vendor/rails/actionpack/test/controller/flash_test.rb @@ -121,7 +121,7 @@ class FlashTest < ActionController::TestCase assert_nil @response.template.assigns["flash_copy"]["that"], "On second flash" assert_equal "hello again", @response.template.assigns["flash_copy"]["this"], "On second flash" end - + def test_flash_after_reset_session get :use_flash_after_reset_session assert_equal "hello", @response.template.assigns["flashy_that"] @@ -139,4 +139,9 @@ class FlashTest < ActionController::TestCase get :std_action assert_nil @response.template.assigns["flash_copy"]["foo"] end + + def test_does_not_set_the_session_if_the_flash_is_empty + get :std_action + assert_nil session["flash"] + end end diff --git a/vendor/rails/actionpack/test/controller/http_digest_authentication_test.rb b/vendor/rails/actionpack/test/controller/http_digest_authentication_test.rb index 00789eea..5cc47ee7 100644 --- a/vendor/rails/actionpack/test/controller/http_digest_authentication_test.rb +++ b/vendor/rails/actionpack/test/controller/http_digest_authentication_test.rb @@ -67,6 +67,15 @@ class HttpDigestAuthenticationTest < ActionController::TestCase assert_equal 'SuperSecret', credentials[:realm] end + test "authentication request with nil credentials" do + @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => nil, :password => nil) + get :index + + assert_response :unauthorized + assert_equal "HTTP Digest: Access denied.\n", @response.body, "Authentication didn't fail for request" + assert_not_equal 'Hello Secret', @response.body, "Authentication didn't fail for request" + end + test "authentication request with invalid password" do @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'foo') get :display @@ -151,6 +160,21 @@ class HttpDigestAuthenticationTest < ActionController::TestCase assert_equal 'Definitely Maybe', @response.body end + test "authentication request with _method" do + @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please', :method => :post) + @request.env['rack.methodoverride.original_method'] = 'POST' + put :display + + assert_response :success + assert assigns(:logged_in) + assert_equal 'Definitely Maybe', @response.body + end + + test "validate_digest_response should fail with nil returning password_procedure" do + @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => nil, :password => nil) + assert !ActionController::HttpAuthentication::Digest.validate_digest_response(@request, "SuperSecret"){nil} + end + private def encode_credentials(options) @@ -161,15 +185,22 @@ class HttpDigestAuthenticationTest < ActionController::TestCase # to prevent tampering of timestamp ActionController::Base.session_options[:secret] = "session_options_secret" - # Perform unauthenticated GET to retrieve digest parameters to use on subsequent request - get :index + # Perform unauthenticated request to retrieve digest parameters to use on subsequent request + method = options.delete(:method) || 'GET' + + case method.to_s.upcase + when 'GET' + get :index + when 'POST' + post :index + end assert_response :unauthorized credentials = decode_credentials(@response.headers['WWW-Authenticate']) credentials.merge!(options) credentials.reverse_merge!(:uri => "#{@request.env['REQUEST_URI']}") - ActionController::HttpAuthentication::Digest.encode_credentials("GET", credentials, password, options[:password_is_ha1]) + ActionController::HttpAuthentication::Digest.encode_credentials(method, credentials, password, options[:password_is_ha1]) end def decode_credentials(header) diff --git a/vendor/rails/actionpack/test/controller/integration_test.rb b/vendor/rails/actionpack/test/controller/integration_test.rb index e39a934c..b8281b54 100644 --- a/vendor/rails/actionpack/test/controller/integration_test.rb +++ b/vendor/rails/actionpack/test/controller/integration_test.rb @@ -240,6 +240,14 @@ class IntegrationProcessTest < ActionController::IntegrationTest render :text => "foo: #{params[:foo]}", :status => 200 end + def post_with_multiparameter_params + render :text => "foo(1i): #{params[:"foo(1i)"]}, foo(2i): #{params[:"foo(2i)"]}", :status => 200 + end + + def multipart_post_with_multiparameter_params + render :text => "foo(1i): #{params[:"foo(1i)"]}, foo(2i): #{params[:"foo(2i)"]}, filesize: #{params[:file].size}", :status => 200 + end + def post render :text => "Created", :status => 201 end @@ -255,6 +263,8 @@ class IntegrationProcessTest < ActionController::IntegrationTest end end + FILES_DIR = File.dirname(__FILE__) + '/../fixtures/multipart' + def test_get with_test_route_set do get '/get' @@ -360,6 +370,24 @@ class IntegrationProcessTest < ActionController::IntegrationTest end end + def test_post_with_multiparameter_attribute_parameters + with_test_route_set do + post '/post_with_multiparameter_params', :"foo(1i)" => "bar", :"foo(2i)" => "baz" + + assert_equal 200, status + assert_equal "foo(1i): bar, foo(2i): baz", response.body + end + end + + def test_multipart_post_with_multiparameter_attribute_parameters + with_test_route_set do + post '/multipart_post_with_multiparameter_params', :"foo(1i)" => "bar", :"foo(2i)" => "baz", :file => fixture_file_upload(FILES_DIR + "/mona_lisa.jpg", "image/jpg") + + assert_equal 200, status + assert_equal "foo(1i): bar, foo(2i): baz, filesize: 159528", response.body + end + end + def test_head with_test_route_set do head '/get' diff --git a/vendor/rails/actionpack/test/controller/redirect_test.rb b/vendor/rails/actionpack/test/controller/redirect_test.rb index 91e21db8..c4574869 100644 --- a/vendor/rails/actionpack/test/controller/redirect_test.rb +++ b/vendor/rails/actionpack/test/controller/redirect_test.rb @@ -235,7 +235,10 @@ class RedirectTest < ActionController::TestCase def test_redirect_with_partial_params get :module_redirect - assert_redirected_to :action => 'hello_world' + + assert_deprecated do + assert_redirected_to :action => 'hello_world' + end end def test_redirect_to_nil diff --git a/vendor/rails/actionpack/test/controller/reloader_test.rb b/vendor/rails/actionpack/test/controller/reloader_test.rb new file mode 100644 index 00000000..6f1f3c85 --- /dev/null +++ b/vendor/rails/actionpack/test/controller/reloader_test.rb @@ -0,0 +1,97 @@ +require 'abstract_unit' + +class ReloaderTests < ActiveSupport::TestCase + Reloader = ActionController::Reloader + Dispatcher = ActionController::Dispatcher + + class MyBody < Array + def initialize(&block) + @on_close = block + end + + def foo + "foo" + end + + def bar + "bar" + end + + def close + @on_close.call if @on_close + end + end + + def setup_and_return_body(app = lambda { }) + Dispatcher.expects(:reload_application) + reloader = Reloader.new(app) + headers, status, body = reloader.call({ }) + body + end + + def test_it_reloads_the_application_before_the_request + Dispatcher.expects(:reload_application) + reloader = Reloader.new(lambda { + [200, { "Content-Type" => "text/html" }, [""]] + }) + reloader.call({ }) + end + + def test_returned_body_object_always_responds_to_close + body = setup_and_return_body(lambda { + [200, { "Content-Type" => "text/html" }, [""]] + }) + assert body.respond_to?(:close) + end + + def test_returned_body_object_behaves_like_underlying_object + body = setup_and_return_body(lambda { + b = MyBody.new + b << "hello" + b << "world" + [200, { "Content-Type" => "text/html" }, b] + }) + assert_equal 2, body.size + assert_equal "hello", body[0] + assert_equal "world", body[1] + assert_equal "foo", body.foo + assert_equal "bar", body.bar + end + + def test_it_calls_close_on_underlying_object_when_close_is_called_on_body + close_called = false + body = setup_and_return_body(lambda { + b = MyBody.new do + close_called = true + end + [200, { "Content-Type" => "text/html" }, b] + }) + body.close + assert close_called + end + + def test_returned_body_object_responds_to_all_methods_supported_by_underlying_object + body = setup_and_return_body(lambda { + [200, { "Content-Type" => "text/html" }, MyBody.new] + }) + assert body.respond_to?(:size) + assert body.respond_to?(:each) + assert body.respond_to?(:foo) + assert body.respond_to?(:bar) + end + + def test_it_doesnt_clean_up_the_application_after_call + Dispatcher.expects(:cleanup_application).never + body = setup_and_return_body(lambda { + [200, { "Content-Type" => "text/html" }, MyBody.new] + }) + end + + def test_it_cleans_up_the_application_when_close_is_called_on_body + Dispatcher.expects(:cleanup_application) + body = setup_and_return_body(lambda { + [200, { "Content-Type" => "text/html" }, MyBody.new] + }) + body.close + end +end diff --git a/vendor/rails/actionpack/test/controller/render_test.rb b/vendor/rails/actionpack/test/controller/render_test.rb index a5293156..112e9efc 100644 --- a/vendor/rails/actionpack/test/controller/render_test.rb +++ b/vendor/rails/actionpack/test/controller/render_test.rb @@ -193,20 +193,24 @@ class TestController < ActionController::Base render :inline => "<%= controller_name %>" end + def render_json_nil + render :json => nil + end + def render_json_hello_world - render :json => {:hello => 'world'}.to_json + render :json => ActiveSupport::JSON.encode(:hello => 'world') end def render_json_hello_world_with_callback - render :json => {:hello => 'world'}.to_json, :callback => 'alert' + render :json => ActiveSupport::JSON.encode(:hello => 'world'), :callback => 'alert' end def render_json_with_custom_content_type - render :json => {:hello => 'world'}.to_json, :content_type => 'text/javascript' + render :json => ActiveSupport::JSON.encode(:hello => 'world'), :content_type => 'text/javascript' end def render_symbol_json - render :json => {:hello => 'world'}.to_json + render :json => ActiveSupport::JSON.encode(:hello => 'world') end def render_json_with_render_to_string @@ -886,33 +890,39 @@ class RenderTest < ActionController::TestCase assert_equal "The secret is in the sauce\n", @response.body end + def test_render_json_nil + get :render_json_nil + assert_equal 'null', @response.body + assert_equal 'application/json', @response.content_type + end + def test_render_json get :render_json_hello_world - assert_equal '{"hello": "world"}', @response.body + assert_equal '{"hello":"world"}', @response.body assert_equal 'application/json', @response.content_type end def test_render_json_with_callback get :render_json_hello_world_with_callback - assert_equal 'alert({"hello": "world"})', @response.body + assert_equal 'alert({"hello":"world"})', @response.body assert_equal 'application/json', @response.content_type end def test_render_json_with_custom_content_type get :render_json_with_custom_content_type - assert_equal '{"hello": "world"}', @response.body + assert_equal '{"hello":"world"}', @response.body assert_equal 'text/javascript', @response.content_type end def test_render_symbol_json get :render_symbol_json - assert_equal '{"hello": "world"}', @response.body + assert_equal '{"hello":"world"}', @response.body assert_equal 'application/json', @response.content_type end def test_render_json_with_render_to_string get :render_json_with_render_to_string - assert_equal '{"hello": "partial html"}', @response.body + assert_equal '{"hello":"partial html"}', @response.body assert_equal 'application/json', @response.content_type end diff --git a/vendor/rails/actionpack/test/controller/request/multipart_params_parsing_test.rb b/vendor/rails/actionpack/test/controller/request/multipart_params_parsing_test.rb index b812072e..cc81a87c 100644 --- a/vendor/rails/actionpack/test/controller/request/multipart_params_parsing_test.rb +++ b/vendor/rails/actionpack/test/controller/request/multipart_params_parsing_test.rb @@ -96,7 +96,7 @@ class MultipartParamsParsingTest < ActionController::IntegrationTest # Ruby CGI doesn't handle multipart/mixed for us. files = params['files'] - assert_kind_of String, files + assert_kind_of Tempfile, files files.force_encoding('ASCII-8BIT') if files.respond_to?(:force_encoding) assert_equal 19756, files.size end @@ -133,46 +133,6 @@ class MultipartParamsParsingTest < ActionController::IntegrationTest end end - # The lint wrapper is used in integration tests - # instead of a normal StringIO class - InputWrapper = Rack::Lint::InputWrapper - - test "parses unwindable stream" do - InputWrapper.any_instance.stubs(:rewind).raises(Errno::ESPIPE) - params = parse_multipart('large_text_file') - assert_equal %w(file foo), params.keys.sort - assert_equal 'bar', params['foo'] - end - - test "uploads and reads file with unwindable input" do - InputWrapper.any_instance.stubs(:rewind).raises(Errno::ESPIPE) - - with_test_routing do - post '/read', :uploaded_data => fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain") - assert_equal "File: Hello", response.body - end - end - - test "passes through rack middleware and uploads file" do - with_muck_middleware do - with_test_routing do - post '/read', :uploaded_data => fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain") - assert_equal "File: Hello", response.body - end - end - end - - test "passes through rack middleware and uploads file with unwindable input" do - InputWrapper.any_instance.stubs(:rewind).raises(Errno::ESPIPE) - - with_muck_middleware do - with_test_routing do - post '/read', :uploaded_data => fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain") - assert_equal "File: Hello", response.body - end - end - end - private def fixture(name) File.open(File.join(FIXTURE_PATH, name), 'rb') do |file| @@ -199,25 +159,4 @@ class MultipartParamsParsingTest < ActionController::IntegrationTest yield end end - - class MuckMiddleware - def initialize(app) - @app = app - end - - def call(env) - req = Rack::Request.new(env) - req.params # Parse params - @app.call(env) - end - end - - def with_muck_middleware - original_middleware = ActionController::Dispatcher.middleware - middleware = original_middleware.dup - middleware.insert_after ActionController::RewindableInput, MuckMiddleware - ActionController::Dispatcher.middleware = middleware - yield - ActionController::Dispatcher.middleware = original_middleware - end end diff --git a/vendor/rails/actionpack/test/controller/request/test_request_test.rb b/vendor/rails/actionpack/test/controller/request/test_request_test.rb new file mode 100644 index 00000000..81551b4b --- /dev/null +++ b/vendor/rails/actionpack/test/controller/request/test_request_test.rb @@ -0,0 +1,35 @@ +require 'abstract_unit' +require 'stringio' + +class ActionController::TestRequestTest < ActiveSupport::TestCase + + def setup + @request = ActionController::TestRequest.new + end + + def test_test_request_has_session_options_initialized + assert @request.session_options + end + + Rack::Session::Abstract::ID::DEFAULT_OPTIONS.each_key do |option| + test "test_rack_default_session_options_#{option}_exists_in_session_options_and_is_default" do + assert_equal(Rack::Session::Abstract::ID::DEFAULT_OPTIONS[option], + @request.session_options[option], + "Missing rack session default option #{option} in request.session_options") + end + test "test_rack_default_session_options_#{option}_exists_in_session_options" do + assert(@request.session_options.has_key?(option), + "Missing rack session option #{option} in request.session_options") + end + end + + def test_session_id_exists_by_default + assert_not_nil(@request.session_options[:id]) + end + + def test_session_id_different_on_each_call + prev_id = + assert_not_equal(@request.session_options[:id], ActionController::TestRequest.new.session_options[:id]) + end + +end \ No newline at end of file diff --git a/vendor/rails/actionpack/test/controller/request/url_encoded_params_parsing_test.rb b/vendor/rails/actionpack/test/controller/request/url_encoded_params_parsing_test.rb index 7e6099a0..7167cdaf 100644 --- a/vendor/rails/actionpack/test/controller/request/url_encoded_params_parsing_test.rb +++ b/vendor/rails/actionpack/test/controller/request/url_encoded_params_parsing_test.rb @@ -126,45 +126,7 @@ class UrlEncodedParamsParsingTest < ActionController::IntegrationTest assert_parses expected, query end - test "passes through rack middleware and parses params" do - with_muck_middleware do - assert_parses({ "a" => { "b" => "c" } }, "a[b]=c") - end - end - - # The lint wrapper is used in integration tests - # instead of a normal StringIO class - InputWrapper = Rack::Lint::InputWrapper - - test "passes through rack middleware and parses params with unwindable input" do - InputWrapper.any_instance.stubs(:rewind).raises(Errno::ESPIPE) - with_muck_middleware do - assert_parses({ "a" => { "b" => "c" } }, "a[b]=c") - end - end - private - class MuckMiddleware - def initialize(app) - @app = app - end - - def call(env) - req = Rack::Request.new(env) - req.params # Parse params - @app.call(env) - end - end - - def with_muck_middleware - original_middleware = ActionController::Dispatcher.middleware - middleware = original_middleware.dup - middleware.insert_after ActionController::RewindableInput, MuckMiddleware - ActionController::Dispatcher.middleware = middleware - yield - ActionController::Dispatcher.middleware = original_middleware - end - def with_test_routing with_routing do |set| set.draw do |map| diff --git a/vendor/rails/actionpack/test/controller/request_test.rb b/vendor/rails/actionpack/test/controller/request_test.rb index c72f885a..c4cc63e6 100644 --- a/vendor/rails/actionpack/test/controller/request_test.rb +++ b/vendor/rails/actionpack/test/controller/request_test.rb @@ -3,7 +3,6 @@ require 'abstract_unit' class RequestTest < ActiveSupport::TestCase def setup ActionController::Base.relative_url_root = nil - @request = ActionController::TestRequest.new end def teardown @@ -11,60 +10,52 @@ class RequestTest < ActiveSupport::TestCase end def test_remote_ip - assert_equal '0.0.0.0', @request.remote_ip + request = stub_request 'REMOTE_ADDR' => '1.2.3.4' + assert_equal '1.2.3.4', request.remote_ip - @request.remote_addr = '1.2.3.4' - assert_equal '1.2.3.4', @request.remote_ip + request = stub_request 'REMOTE_ADDR' => '1.2.3.4,3.4.5.6' + assert_equal '1.2.3.4', request.remote_ip - @request.remote_addr = '1.2.3.4,3.4.5.6' - assert_equal '1.2.3.4', @request.remote_ip + request = stub_request 'REMOTE_ADDR' => '1.2.3.4', + 'HTTP_X_FORWARDED_FOR' => '3.4.5.6' + assert_equal '1.2.3.4', request.remote_ip - @request.env['HTTP_CLIENT_IP'] = '2.3.4.5' - assert_equal '1.2.3.4', @request.remote_ip + request = stub_request 'REMOTE_ADDR' => '127.0.0.1', + 'HTTP_X_FORWARDED_FOR' => '3.4.5.6' + assert_equal '3.4.5.6', request.remote_ip - @request.remote_addr = '192.168.0.1' - assert_equal '2.3.4.5', @request.remote_ip - @request.env.delete 'HTTP_CLIENT_IP' + request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,3.4.5.6' + assert_equal '3.4.5.6', request.remote_ip - @request.remote_addr = '1.2.3.4' - @request.env['HTTP_X_FORWARDED_FOR'] = '3.4.5.6' - assert_equal '1.2.3.4', @request.remote_ip + request = stub_request 'HTTP_X_FORWARDED_FOR' => '172.16.0.1,3.4.5.6' + assert_equal '3.4.5.6', request.remote_ip - @request.remote_addr = '127.0.0.1' - @request.env['HTTP_X_FORWARDED_FOR'] = '3.4.5.6' - assert_equal '3.4.5.6', @request.remote_ip + request = stub_request 'HTTP_X_FORWARDED_FOR' => '192.168.0.1,3.4.5.6' + assert_equal '3.4.5.6', request.remote_ip - @request.env['HTTP_X_FORWARDED_FOR'] = 'unknown,3.4.5.6' - assert_equal '3.4.5.6', @request.remote_ip + request = stub_request 'HTTP_X_FORWARDED_FOR' => '10.0.0.1,3.4.5.6' + assert_equal '3.4.5.6', request.remote_ip - @request.env['HTTP_X_FORWARDED_FOR'] = '172.16.0.1,3.4.5.6' - assert_equal '3.4.5.6', @request.remote_ip + request = stub_request 'HTTP_X_FORWARDED_FOR' => '10.0.0.1, 10.0.0.1, 3.4.5.6' + assert_equal '3.4.5.6', request.remote_ip - @request.env['HTTP_X_FORWARDED_FOR'] = '192.168.0.1,3.4.5.6' - assert_equal '3.4.5.6', @request.remote_ip + request = stub_request 'HTTP_X_FORWARDED_FOR' => '127.0.0.1,3.4.5.6' + assert_equal '3.4.5.6', request.remote_ip - @request.env['HTTP_X_FORWARDED_FOR'] = '10.0.0.1,3.4.5.6' - assert_equal '3.4.5.6', @request.remote_ip + request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,192.168.0.1' + assert_equal 'unknown', request.remote_ip - @request.env['HTTP_X_FORWARDED_FOR'] = '10.0.0.1, 10.0.0.1, 3.4.5.6' - assert_equal '3.4.5.6', @request.remote_ip + request = stub_request 'HTTP_X_FORWARDED_FOR' => '9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4' + assert_equal '3.4.5.6', request.remote_ip - @request.env['HTTP_X_FORWARDED_FOR'] = '127.0.0.1,3.4.5.6' - assert_equal '3.4.5.6', @request.remote_ip - - @request.env['HTTP_X_FORWARDED_FOR'] = 'unknown,192.168.0.1' - assert_equal 'unknown', @request.remote_ip - - @request.env['HTTP_X_FORWARDED_FOR'] = '9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4' - assert_equal '3.4.5.6', @request.remote_ip - - @request.env['HTTP_CLIENT_IP'] = '8.8.8.8' + request = stub_request 'HTTP_X_FORWARDED_FOR' => '1.1.1.1', + 'HTTP_CLIENT_IP' => '2.2.2.2' e = assert_raise(ActionController::ActionControllerError) { - @request.remote_ip + request.remote_ip } assert_match /IP spoofing attack/, e.message - assert_match /HTTP_X_FORWARDED_FOR="9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4"/, e.message - assert_match /HTTP_CLIENT_IP="8.8.8.8"/, e.message + assert_match /HTTP_X_FORWARDED_FOR="1.1.1.1"/, e.message + assert_match /HTTP_CLIENT_IP="2.2.2.2"/, e.message # turn IP Spoofing detection off. # This is useful for sites that are aimed at non-IP clients. The typical @@ -72,336 +63,333 @@ class RequestTest < ActiveSupport::TestCase # leap of faith to assume that their proxies are ever going to set the # HTTP_CLIENT_IP/HTTP_X_FORWARDED_FOR headers properly. ActionController::Base.ip_spoofing_check = false - assert_equal('8.8.8.8', @request.remote_ip) + request = stub_request 'HTTP_X_FORWARDED_FOR' => '1.1.1.1', + 'HTTP_CLIENT_IP' => '2.2.2.2' + assert_equal '2.2.2.2', request.remote_ip ActionController::Base.ip_spoofing_check = true - @request.env['HTTP_X_FORWARDED_FOR'] = '8.8.8.8, 9.9.9.9' - assert_equal '8.8.8.8', @request.remote_ip - - @request.env.delete 'HTTP_CLIENT_IP' - @request.env.delete 'HTTP_X_FORWARDED_FOR' + request = stub_request 'HTTP_X_FORWARDED_FOR' => '8.8.8.8, 9.9.9.9' + assert_equal '9.9.9.9', request.remote_ip end def test_domains - @request.host = "www.rubyonrails.org" - assert_equal "rubyonrails.org", @request.domain + request = stub_request 'HTTP_HOST' => 'www.rubyonrails.org' + assert_equal "rubyonrails.org", request.domain - @request.host = "www.rubyonrails.co.uk" - assert_equal "rubyonrails.co.uk", @request.domain(2) + request = stub_request 'HTTP_HOST' => "www.rubyonrails.co.uk" + assert_equal "rubyonrails.co.uk", request.domain(2) - @request.host = "192.168.1.200" - assert_nil @request.domain + request = stub_request 'HTTP_HOST' => "192.168.1.200" + assert_nil request.domain - @request.host = "foo.192.168.1.200" - assert_nil @request.domain + request = stub_request 'HTTP_HOST' => "foo.192.168.1.200" + assert_nil request.domain - @request.host = "192.168.1.200.com" - assert_equal "200.com", @request.domain - - @request.host = nil - assert_nil @request.domain + request = stub_request 'HTTP_HOST' => "192.168.1.200.com" + assert_equal "200.com", request.domain end def test_subdomains - @request.host = "www.rubyonrails.org" - assert_equal %w( www ), @request.subdomains + request = stub_request 'HTTP_HOST' => "www.rubyonrails.org" + assert_equal %w( www ), request.subdomains - @request.host = "www.rubyonrails.co.uk" - assert_equal %w( www ), @request.subdomains(2) + request = stub_request 'HTTP_HOST' => "www.rubyonrails.co.uk" + assert_equal %w( www ), request.subdomains(2) - @request.host = "dev.www.rubyonrails.co.uk" - assert_equal %w( dev www ), @request.subdomains(2) + request = stub_request 'HTTP_HOST' => "dev.www.rubyonrails.co.uk" + assert_equal %w( dev www ), request.subdomains(2) - @request.host = "foobar.foobar.com" - assert_equal %w( foobar ), @request.subdomains + request = stub_request 'HTTP_HOST' => "foobar.foobar.com" + assert_equal %w( foobar ), request.subdomains - @request.host = "192.168.1.200" - assert_equal [], @request.subdomains + request = stub_request 'HTTP_HOST' => "192.168.1.200" + assert_equal [], request.subdomains - @request.host = "foo.192.168.1.200" - assert_equal [], @request.subdomains + request = stub_request 'HTTP_HOST' => "foo.192.168.1.200" + assert_equal [], request.subdomains - @request.host = "192.168.1.200.com" - assert_equal %w( 192 168 1 ), @request.subdomains + request = stub_request 'HTTP_HOST' => "192.168.1.200.com" + assert_equal %w( 192 168 1 ), request.subdomains - @request.host = nil - assert_equal [], @request.subdomains + request = stub_request 'HTTP_HOST' => nil + assert_equal [], request.subdomains end def test_port_string - @request.port = 80 - assert_equal "", @request.port_string + request = stub_request 'HTTP_HOST' => 'www.example.org:80' + assert_equal "", request.port_string - @request.port = 8080 - assert_equal ":8080", @request.port_string + request = stub_request 'HTTP_HOST' => 'www.example.org:8080' + assert_equal ":8080", request.port_string end def test_request_uri - @request.env['SERVER_SOFTWARE'] = 'Apache 42.342.3432' + request = stub_request 'REQUEST_URI' => "http://www.rubyonrails.org/path/of/some/uri?mapped=1" + assert_equal "/path/of/some/uri?mapped=1", request.request_uri + assert_equal "/path/of/some/uri", request.path - @request.set_REQUEST_URI "http://www.rubyonrails.org/path/of/some/uri?mapped=1" - assert_equal "/path/of/some/uri?mapped=1", @request.request_uri - assert_equal "/path/of/some/uri", @request.path + request = stub_request 'REQUEST_URI' => "http://www.rubyonrails.org/path/of/some/uri" + assert_equal "/path/of/some/uri", request.request_uri + assert_equal "/path/of/some/uri", request.path - @request.set_REQUEST_URI "http://www.rubyonrails.org/path/of/some/uri" - assert_equal "/path/of/some/uri", @request.request_uri - assert_equal "/path/of/some/uri", @request.path + request = stub_request 'REQUEST_URI' => "/path/of/some/uri" + assert_equal "/path/of/some/uri", request.request_uri + assert_equal "/path/of/some/uri", request.path - @request.set_REQUEST_URI "/path/of/some/uri" - assert_equal "/path/of/some/uri", @request.request_uri - assert_equal "/path/of/some/uri", @request.path + request = stub_request 'REQUEST_URI' => "/" + assert_equal "/", request.request_uri + assert_equal "/", request.path - @request.set_REQUEST_URI "/" - assert_equal "/", @request.request_uri - assert_equal "/", @request.path + request = stub_request 'REQUEST_URI' => "/?m=b" + assert_equal "/?m=b", request.request_uri + assert_equal "/", request.path - @request.set_REQUEST_URI "/?m=b" - assert_equal "/?m=b", @request.request_uri - assert_equal "/", @request.path - - @request.set_REQUEST_URI "/" - @request.env['SCRIPT_NAME'] = "/dispatch.cgi" - assert_equal "/", @request.request_uri - assert_equal "/", @request.path + request = stub_request 'REQUEST_URI' => "/", 'SCRIPT_NAME' => '/dispatch.cgi' + assert_equal "/", request.request_uri + assert_equal "/", request.path ActionController::Base.relative_url_root = "/hieraki" - @request.set_REQUEST_URI "/hieraki/" - @request.env['SCRIPT_NAME'] = "/hieraki/dispatch.cgi" - assert_equal "/hieraki/", @request.request_uri - assert_equal "/", @request.path + request = stub_request 'REQUEST_URI' => "/hieraki/", 'SCRIPT_NAME' => "/hieraki/dispatch.cgi" + assert_equal "/hieraki/", request.request_uri + assert_equal "/", request.path ActionController::Base.relative_url_root = nil ActionController::Base.relative_url_root = "/collaboration/hieraki" - @request.set_REQUEST_URI "/collaboration/hieraki/books/edit/2" - @request.env['SCRIPT_NAME'] = "/collaboration/hieraki/dispatch.cgi" - assert_equal "/collaboration/hieraki/books/edit/2", @request.request_uri - assert_equal "/books/edit/2", @request.path + request = stub_request 'REQUEST_URI' => "/collaboration/hieraki/books/edit/2", + 'SCRIPT_NAME' => "/collaboration/hieraki/dispatch.cgi" + assert_equal "/collaboration/hieraki/books/edit/2", request.request_uri + assert_equal "/books/edit/2", request.path ActionController::Base.relative_url_root = nil # The following tests are for when REQUEST_URI is not supplied (as in IIS) - @request.env['PATH_INFO'] = "/path/of/some/uri?mapped=1" - @request.env['SCRIPT_NAME'] = nil #"/path/dispatch.rb" - @request.set_REQUEST_URI nil - assert_equal "/path/of/some/uri?mapped=1", @request.request_uri - assert_equal "/path/of/some/uri", @request.path + request = stub_request 'PATH_INFO' => "/path/of/some/uri?mapped=1", + 'SCRIPT_NAME' => nil, + 'REQUEST_URI' => nil + assert_equal "/path/of/some/uri?mapped=1", request.request_uri + assert_equal "/path/of/some/uri", request.path ActionController::Base.relative_url_root = '/path' - @request.env['PATH_INFO'] = "/path/of/some/uri?mapped=1" - @request.env['SCRIPT_NAME'] = "/path/dispatch.rb" - @request.set_REQUEST_URI nil - assert_equal "/path/of/some/uri?mapped=1", @request.request_uri - assert_equal "/of/some/uri", @request.path + request = stub_request 'PATH_INFO' => "/path/of/some/uri?mapped=1", + 'SCRIPT_NAME' => "/path/dispatch.rb", + 'REQUEST_URI' => nil + assert_equal "/path/of/some/uri?mapped=1", request.request_uri + assert_equal "/of/some/uri", request.path ActionController::Base.relative_url_root = nil - @request.env['PATH_INFO'] = "/path/of/some/uri" - @request.env['SCRIPT_NAME'] = nil - @request.set_REQUEST_URI nil - assert_equal "/path/of/some/uri", @request.request_uri - assert_equal "/path/of/some/uri", @request.path + request = stub_request 'PATH_INFO' => "/path/of/some/uri", + 'SCRIPT_NAME' => nil, + 'REQUEST_URI' => nil + assert_equal "/path/of/some/uri", request.request_uri + assert_equal "/path/of/some/uri", request.path - @request.env['PATH_INFO'] = "/" - @request.set_REQUEST_URI nil - assert_equal "/", @request.request_uri - assert_equal "/", @request.path + request = stub_request 'PATH_INFO' => '/', 'REQUEST_URI' => nil + assert_equal "/", request.request_uri + assert_equal "/", request.path - @request.env['PATH_INFO'] = "/?m=b" - @request.set_REQUEST_URI nil - assert_equal "/?m=b", @request.request_uri - assert_equal "/", @request.path + request = stub_request 'PATH_INFO' => '/?m=b', 'REQUEST_URI' => nil + assert_equal "/?m=b", request.request_uri + assert_equal "/", request.path - @request.env['PATH_INFO'] = "/" - @request.env['SCRIPT_NAME'] = "/dispatch.cgi" - @request.set_REQUEST_URI nil - assert_equal "/", @request.request_uri - assert_equal "/", @request.path + request = stub_request 'PATH_INFO' => "/", + 'SCRIPT_NAME' => "/dispatch.cgi", + 'REQUEST_URI' => nil + assert_equal "/", request.request_uri + assert_equal "/", request.path ActionController::Base.relative_url_root = '/hieraki' - @request.env['PATH_INFO'] = "/hieraki/" - @request.env['SCRIPT_NAME'] = "/hieraki/dispatch.cgi" - @request.set_REQUEST_URI nil - assert_equal "/hieraki/", @request.request_uri - assert_equal "/", @request.path + request = stub_request 'PATH_INFO' => "/hieraki/", + 'SCRIPT_NAME' => "/hieraki/dispatch.cgi", + 'REQUEST_URI' => nil + assert_equal "/hieraki/", request.request_uri + assert_equal "/", request.path ActionController::Base.relative_url_root = nil - @request.set_REQUEST_URI '/hieraki/dispatch.cgi' + request = stub_request 'REQUEST_URI' => '/hieraki/dispatch.cgi' ActionController::Base.relative_url_root = '/hieraki' - assert_equal "/dispatch.cgi", @request.path + assert_equal "/dispatch.cgi", request.path ActionController::Base.relative_url_root = nil - @request.set_REQUEST_URI '/hieraki/dispatch.cgi' + request = stub_request 'REQUEST_URI' => '/hieraki/dispatch.cgi' ActionController::Base.relative_url_root = '/foo' - assert_equal "/hieraki/dispatch.cgi", @request.path + assert_equal "/hieraki/dispatch.cgi", request.path ActionController::Base.relative_url_root = nil # This test ensures that Rails uses REQUEST_URI over PATH_INFO ActionController::Base.relative_url_root = nil - @request.env['REQUEST_URI'] = "/some/path" - @request.env['PATH_INFO'] = "/another/path" - @request.env['SCRIPT_NAME'] = "/dispatch.cgi" - assert_equal "/some/path", @request.request_uri - assert_equal "/some/path", @request.path + request = stub_request 'REQUEST_URI' => "/some/path", + 'PATH_INFO' => "/another/path", + 'SCRIPT_NAME' => "/dispatch.cgi" + assert_equal "/some/path", request.request_uri + assert_equal "/some/path", request.path end def test_host_with_default_port - @request.host = "rubyonrails.org" - @request.port = 80 - assert_equal "rubyonrails.org", @request.host_with_port + request = stub_request 'HTTP_HOST' => 'rubyonrails.org:80' + assert_equal "rubyonrails.org", request.host_with_port end def test_host_with_non_default_port - @request.host = "rubyonrails.org" - @request.port = 81 - assert_equal "rubyonrails.org:81", @request.host_with_port + request = stub_request 'HTTP_HOST' => 'rubyonrails.org:81' + assert_equal "rubyonrails.org:81", request.host_with_port end def test_server_software - assert_equal nil, @request.server_software + request = stub_request + assert_equal nil, request.server_software - @request.env['SERVER_SOFTWARE'] = 'Apache3.422' - assert_equal 'apache', @request.server_software + request = stub_request 'SERVER_SOFTWARE' => 'Apache3.422' + assert_equal 'apache', request.server_software - @request.env['SERVER_SOFTWARE'] = 'lighttpd(1.1.4)' - assert_equal 'lighttpd', @request.server_software + request = stub_request 'SERVER_SOFTWARE' => 'lighttpd(1.1.4)' + assert_equal 'lighttpd', request.server_software end def test_xml_http_request - assert !@request.xml_http_request? - assert !@request.xhr? + request = stub_request - @request.env['HTTP_X_REQUESTED_WITH'] = "DefinitelyNotAjax1.0" - assert !@request.xml_http_request? - assert !@request.xhr? + assert !request.xml_http_request? + assert !request.xhr? - @request.env['HTTP_X_REQUESTED_WITH'] = "XMLHttpRequest" - assert @request.xml_http_request? - assert @request.xhr? + request = stub_request 'HTTP_X_REQUESTED_WITH' => 'DefinitelyNotAjax1.0' + assert !request.xml_http_request? + assert !request.xhr? + + request = stub_request 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest' + assert request.xml_http_request? + assert request.xhr? end def test_reports_ssl - assert !@request.ssl? - @request.env['HTTPS'] = 'on' - assert @request.ssl? + request = stub_request + assert !request.ssl? + + request = stub_request 'HTTPS' => 'on' + assert request.ssl? end def test_reports_ssl_when_proxied_via_lighttpd - assert !@request.ssl? - @request.env['HTTP_X_FORWARDED_PROTO'] = 'https' - assert @request.ssl? + request = stub_request + assert !request.ssl? + + request = stub_request 'HTTP_X_FORWARDED_PROTO' => 'https' + assert request.ssl? end def test_symbolized_request_methods [:get, :post, :put, :delete].each do |method| - self.request_method = method - assert_equal method, @request.method + request = stub_request 'REQUEST_METHOD' => method.to_s.upcase + assert_equal method, request.method end end def test_invalid_http_method_raises_exception assert_raise(ActionController::UnknownHttpMethod) do - self.request_method = :random_method - @request.request_method + request = stub_request 'REQUEST_METHOD' => 'RANDOM_METHOD' + request.request_method end end def test_allow_method_hacking_on_post [:get, :head, :options, :put, :post, :delete].each do |method| - self.request_method = method - assert_equal(method == :head ? :get : method, @request.method) - end - end - - def test_invalid_method_hacking_on_post_raises_exception - assert_raise(ActionController::UnknownHttpMethod) do - self.request_method = :_random_method - @request.request_method + request = stub_request 'REQUEST_METHOD' => method.to_s.upcase + assert_equal(method == :head ? :get : method, request.method) end end def test_restrict_method_hacking - @request.instance_eval { @parameters = { :_method => 'put' } } [:get, :put, :delete].each do |method| - self.request_method = method - assert_equal method, @request.method + request = stub_request 'REQUEST_METHOD' => method.to_s.upcase, + 'action_controller.request.request_parameters' => { :_method => 'put' } + assert_equal method, request.method end end def test_head_masquerading_as_get - self.request_method = :head - assert_equal :get, @request.method - assert @request.get? - assert @request.head? + request = stub_request 'REQUEST_METHOD' => 'HEAD' + assert_equal :get, request.method + assert request.get? + assert request.head? end def test_xml_format - @request.instance_eval { @parameters = { :format => 'xml' } } - assert_equal Mime::XML, @request.format + request = stub_request + request.expects(:parameters).at_least_once.returns({ :format => 'xml' }) + assert_equal Mime::XML, request.format end def test_xhtml_format - @request.instance_eval { @parameters = { :format => 'xhtml' } } - assert_equal Mime::HTML, @request.format + request = stub_request + request.expects(:parameters).at_least_once.returns({ :format => 'xhtml' }) + assert_equal Mime::HTML, request.format end def test_txt_format - @request.instance_eval { @parameters = { :format => 'txt' } } - assert_equal Mime::TEXT, @request.format + request = stub_request + request.expects(:parameters).at_least_once.returns({ :format => 'txt' }) + assert_equal Mime::TEXT, request.format end - def test_nil_format + def test_xml_http_request ActionController::Base.use_accept_header, old = false, ActionController::Base.use_accept_header - @request.instance_eval { @parameters = {} } - @request.env["HTTP_X_REQUESTED_WITH"] = "XMLHttpRequest" - assert @request.xhr? - assert_equal Mime::JS, @request.format - + request = stub_request 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest' + request.expects(:parameters).at_least_once.returns({}) + assert request.xhr? + assert_equal Mime::JS, request.format ensure ActionController::Base.use_accept_header = old end def test_content_type - @request.env["CONTENT_TYPE"] = "text/html" - assert_equal Mime::HTML, @request.content_type + request = stub_request 'CONTENT_TYPE' => 'text/html' + assert_equal Mime::HTML, request.content_type end - def test_format_assignment_should_set_format - @request.instance_eval { self.format = :txt } - assert !@request.format.xml? - @request.instance_eval { self.format = :xml } - assert @request.format.xml? + def test_can_override_format_with_parameter + request = stub_request + request.expects(:parameters).at_least_once.returns({ :format => :txt }) + assert !request.format.xml? + + request = stub_request + request.expects(:parameters).at_least_once.returns({ :format => :xml }) + assert request.format.xml? end def test_content_no_type - assert_equal nil, @request.content_type + request = stub_request + assert_equal nil, request.content_type end def test_content_type_xml - @request.env["CONTENT_TYPE"] = "application/xml" - assert_equal Mime::XML, @request.content_type + request = stub_request 'CONTENT_TYPE' => 'application/xml' + assert_equal Mime::XML, request.content_type end def test_content_type_with_charset - @request.env["CONTENT_TYPE"] = "application/xml; charset=UTF-8" - assert_equal Mime::XML, @request.content_type + request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8' + assert_equal Mime::XML, request.content_type end def test_user_agent - assert_not_nil @request.user_agent + request = stub_request 'HTTP_USER_AGENT' => 'TestAgent' + assert_equal 'TestAgent', request.user_agent end def test_parameters - @request.stubs(:request_parameters).returns({ "foo" => 1 }) - @request.stubs(:query_parameters).returns({ "bar" => 2 }) + request = stub_request + request.stubs(:request_parameters).returns({ "foo" => 1 }) + request.stubs(:query_parameters).returns({ "bar" => 2 }) - assert_equal({"foo" => 1, "bar" => 2}, @request.parameters) - assert_equal({"foo" => 1}, @request.request_parameters) - assert_equal({"bar" => 2}, @request.query_parameters) + assert_equal({"foo" => 1, "bar" => 2}, request.parameters) + assert_equal({"foo" => 1}, request.request_parameters) + assert_equal({"bar" => 2}, request.query_parameters) + end + +protected + + def stub_request(env={}) + ActionController::Request.new(env) end - protected - def request_method=(method) - @request.env['REQUEST_METHOD'] = method.to_s.upcase - @request.request_method = nil # Reset the ivar cache - end end diff --git a/vendor/rails/actionpack/test/controller/resources_test.rb b/vendor/rails/actionpack/test/controller/resources_test.rb index c807e71c..30ab110e 100644 --- a/vendor/rails/actionpack/test/controller/resources_test.rb +++ b/vendor/rails/actionpack/test/controller/resources_test.rb @@ -120,6 +120,14 @@ class ResourcesTest < ActionController::TestCase end end + def test_irregular_id_requirements_should_get_passed_to_member_actions + expected_options = {:controller => 'messages', :action => 'custom', :id => '1.1.1'} + + with_restful_routing(:messages, :member => {:custom => :get}, :requirements => {:id => /[0-9]\.[0-9]\.[0-9]/}) do + assert_recognizes(expected_options, :path => 'messages/1.1.1/custom', :method => :get) + end + end + def test_with_path_prefix with_restful_routing :messages, :path_prefix => '/thread/:thread_id' do assert_simply_restful_for :messages, :path_prefix => 'thread/5/', :options => { :thread_id => '5' } diff --git a/vendor/rails/actionpack/test/controller/routing_test.rb b/vendor/rails/actionpack/test/controller/routing_test.rb index ef561197..93759425 100644 --- a/vendor/rails/actionpack/test/controller/routing_test.rb +++ b/vendor/rails/actionpack/test/controller/routing_test.rb @@ -1662,6 +1662,17 @@ class RouteSetTest < Test::Unit::TestCase assert_equal 1, set.routes.size end + def test_draw_symbol_controller_name + assert_equal 0, set.routes.size + set.draw do |map| + map.connect '/users/index', :controller => :users, :action => :index + end + @request = ActionController::TestRequest.new + @request.request_uri = '/users/index' + assert_nothing_raised { set.recognize(@request) } + assert_equal 1, set.routes.size + end + def test_named_draw assert_equal 0, set.routes.size set.draw do |map| @@ -2476,6 +2487,16 @@ class RouteSetTest < Test::Unit::TestCase end assert_equal({:controller => 'pages', :action => 'show', :name => 'JAMIS'}, set.recognize_path('/page/JAMIS')) end + + def test_routes_with_symbols + set.draw do |map| + map.connect 'unnamed', :controller => :pages, :action => :show, :name => :as_symbol + map.named 'named', :controller => :pages, :action => :show, :name => :as_symbol + end + assert_equal({:controller => 'pages', :action => 'show', :name => :as_symbol}, set.recognize_path('/unnamed')) + assert_equal({:controller => 'pages', :action => 'show', :name => :as_symbol}, set.recognize_path('/named')) + end + end class RouteLoadingTest < Test::Unit::TestCase diff --git a/vendor/rails/actionpack/test/controller/send_file_test.rb b/vendor/rails/actionpack/test/controller/send_file_test.rb index a27e9519..26c7f9bd 100644 --- a/vendor/rails/actionpack/test/controller/send_file_test.rb +++ b/vendor/rails/actionpack/test/controller/send_file_test.rb @@ -108,7 +108,7 @@ class SendFileTest < ActionController::TestCase @controller.send(:send_file_headers!, options) h = @controller.headers - assert_equal 1, h['Content-Length'] + assert_equal '1', h['Content-Length'] assert_equal 'image/png', h['Content-Type'] assert_equal 'disposition; filename="filename"', h['Content-Disposition'] assert_equal 'binary', h['Content-Transfer-Encoding'] diff --git a/vendor/rails/actionpack/test/controller/session/cookie_store_test.rb b/vendor/rails/actionpack/test/controller/session/cookie_store_test.rb index 48a961ca..40fcd568 100644 --- a/vendor/rails/actionpack/test/controller/session/cookie_store_test.rb +++ b/vendor/rails/actionpack/test/controller/session/cookie_store_test.rb @@ -193,27 +193,6 @@ class CookieStoreTest < ActionController::IntegrationTest end end - def test_session_store_with_expire_after - app = ActionController::Session::CookieStore.new(DispatcherApp, :key => SessionKey, :secret => SessionSecret, :expire_after => 5.hours) - @integration_session = open_session(app) - - with_test_route_set do - # First request accesses the session - cookies[SessionKey] = SignedBar - - get '/set_session_value' - assert_response :success - cookie = headers['Set-Cookie'] - - # Second request does not access the session so the - # expires header should not be changed - get '/no_session_access' - assert_response :success - assert_equal cookie, headers['Set-Cookie'], - "#{unmarshal_session(cookie).inspect} expected but was #{unmarshal_session(headers['Set-Cookie']).inspect}" - end - end - private def with_test_route_set with_routing do |set| diff --git a/vendor/rails/actionpack/test/controller/test_test.rb b/vendor/rails/actionpack/test/controller/test_test.rb index 65c894c2..3924b282 100644 --- a/vendor/rails/actionpack/test/controller/test_test.rb +++ b/vendor/rails/actionpack/test/controller/test_test.rb @@ -515,6 +515,14 @@ XML assert_nil @request.instance_variable_get("@request_method") end + def test_params_reset_after_post_request + post :no_op, :foo => "bar" + assert_equal "bar", @request.params[:foo] + @request.recycle! + post :no_op + assert @request.params[:foo].blank? + end + %w(controller response request).each do |variable| %w(get post put delete head process).each do |method| define_method("test_#{variable}_missing_for_#{method}_raises_error") do diff --git a/vendor/rails/actionpack/test/fixtures/failsafe/500.html b/vendor/rails/actionpack/test/fixtures/failsafe/500.html new file mode 100644 index 00000000..f3af84d6 --- /dev/null +++ b/vendor/rails/actionpack/test/fixtures/failsafe/500.html @@ -0,0 +1 @@ +hello <%= "my" %> world \ No newline at end of file diff --git a/vendor/rails/actionpack/test/template/active_record_helper_test.rb b/vendor/rails/actionpack/test/template/active_record_helper_test.rb index 83c028b5..11812e78 100644 --- a/vendor/rails/actionpack/test/template/active_record_helper_test.rb +++ b/vendor/rails/actionpack/test/template/active_record_helper_test.rb @@ -170,7 +170,7 @@ class ActiveRecordHelperTest < ActionView::TestCase @request_forgery_protection_token = 'authenticity_token' @form_authenticity_token = '123' assert_dom_equal( - %(


\n


), + %(


\n


), form("post") ) end diff --git a/vendor/rails/actionpack/test/template/asset_tag_helper_test.rb b/vendor/rails/actionpack/test/template/asset_tag_helper_test.rb index 32ad87c1..7ffabfff 100644 --- a/vendor/rails/actionpack/test/template/asset_tag_helper_test.rb +++ b/vendor/rails/actionpack/test/template/asset_tag_helper_test.rb @@ -316,9 +316,17 @@ class AssetTagHelperTest < ActionView::TestCase assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'money.js')) + assert_dom_equal( + %(), + javascript_include_tag(:all, :cache => "/absolute/test") + ) + + assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::ASSETS_DIR, 'absolute', 'test.js')) + ensure FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'all.js')) FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'money.js')) + FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::ASSETS_DIR, 'absolute')) end def test_caching_javascript_include_tag_when_caching_on_with_proc_asset_host @@ -546,9 +554,47 @@ class AssetTagHelperTest < ActionView::TestCase ) assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) + + assert_dom_equal( + %(), + stylesheet_link_tag(:all, :cache => "/absolute/test") + ) + + assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::ASSETS_DIR, 'absolute', 'test.css')) ensure FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) + FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::ASSETS_DIR, 'absolute')) + end + + def test_concat_stylesheet_link_tag_when_caching_off + ENV["RAILS_ASSET_ID"] = "" + + assert_dom_equal( + %(), + stylesheet_link_tag(:all, :concat => true) + ) + + expected = Dir["#{ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR}/*.css"].map { |p| File.mtime(p) }.max + assert_equal expected, File.mtime(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) + + assert_dom_equal( + %(), + stylesheet_link_tag(:all, :concat => "money") + ) + + assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) + + assert_dom_equal( + %(), + stylesheet_link_tag(:all, :concat => "/absolute/test") + ) + + assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::ASSETS_DIR, 'absolute', 'test.css')) + ensure + FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) + FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) + FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::ASSETS_DIR, 'absolute')) end def test_caching_stylesheet_link_tag_when_caching_on_with_proc_asset_host diff --git a/vendor/rails/actionpack/test/template/form_helper_test.rb b/vendor/rails/actionpack/test/template/form_helper_test.rb index 654eee40..e92f62d8 100644 --- a/vendor/rails/actionpack/test/template/form_helper_test.rb +++ b/vendor/rails/actionpack/test/template/form_helper_test.rb @@ -21,6 +21,9 @@ silence_warnings do attr_accessor :comments def comments_attributes=(attributes); end + + attr_accessor :tags + def tags_attributes=(attributes); end end class Comment @@ -33,6 +36,50 @@ silence_warnings do def name @id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}" end + + attr_accessor :relevances + def relevances_attributes=(attributes); end + + end + + class Tag + attr_reader :id + attr_reader :post_id + def initialize(id = nil, post_id = nil); @id, @post_id = id, post_id end + def save; @id = 1; @post_id = 1 end + def new_record?; @id.nil? end + def to_param; @id; end + def value + @id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}" + end + + attr_accessor :relevances + def relevances_attributes=(attributes); end + + end + + class CommentRelevance + attr_reader :id + attr_reader :comment_id + def initialize(id = nil, comment_id = nil); @id, @comment_id = id, comment_id end + def save; @id = 1; @comment_id = 1 end + def new_record?; @id.nil? end + def to_param; @id; end + def value + @id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}" + end + end + + class TagRelevance + attr_reader :id + attr_reader :tag_id + def initialize(id = nil, tag_id = nil); @id, @tag_id = id, tag_id end + def save; @id = 1; @tag_id = 1 end + def new_record?; @id.nil? end + def to_param; @id; end + def value + @id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}" + end end class Author < Comment @@ -98,6 +145,11 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal('', label(:post, :title, nil, "for" => "my_for")) end + def test_label_for_radio_buttons_with_value + assert_dom_equal('', label("post", "title", "The title goes here", :value => "great_title")) + assert_dom_equal('', label("post", "title", "The title goes here", :value => "great title")) + end + def test_text_field assert_dom_equal( '', text_field("post", "title") @@ -377,7 +429,7 @@ class FormHelperTest < ActionView::TestCase expected = "
" + - "
" + + "
" + "" + "" + "" + @@ -531,6 +583,20 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal expected, output_buffer end + def test_nested_fields_for_with_index_radio_button + form_for(:post, @post) do |f| + f.fields_for(:comment, @post, :index => 5) do |c| + concat c.radio_button(:title, "hello") + end + end + + expected = "" + + "" + + "
" + + assert_dom_equal expected, output_buffer + end + def test_nested_fields_for_with_auto_index_on_both form_for("post[]", @post) do |f| f.fields_for("comment[]", @post) do |c| @@ -720,6 +786,51 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal expected, output_buffer end + def test_nested_fields_uses_unique_indices_for_different_collection_associations + @post.comments = [Comment.new(321)] + @post.tags = [Tag.new(123), Tag.new(456)] + @post.comments[0].relevances = [] + @post.tags[0].relevances = [] + @post.tags[1].relevances = [] + form_for(:post, @post) do |f| + f.fields_for(:comments, @post.comments[0]) do |cf| + concat cf.text_field(:name) + cf.fields_for(:relevances, CommentRelevance.new(314)) do |crf| + concat crf.text_field(:value) + end + end + f.fields_for(:tags, @post.tags[0]) do |tf| + concat tf.text_field(:value) + tf.fields_for(:relevances, TagRelevance.new(3141)) do |trf| + concat trf.text_field(:value) + end + end + f.fields_for('tags', @post.tags[1]) do |tf| + concat tf.text_field(:value) + tf.fields_for(:relevances, TagRelevance.new(31415)) do |trf| + concat trf.text_field(:value) + end + end + end + + expected = '
' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
' + + assert_dom_equal expected, output_buffer + end + def test_fields_for fields_for(:post, @post) do |f| concat f.text_field(:title) @@ -1072,7 +1183,7 @@ class FormHelperTest < ActionView::TestCase def test_form_for_with_existing_object form_for(@post) do |f| end - expected = "
" + expected = "
" assert_equal expected, output_buffer end @@ -1093,7 +1204,7 @@ class FormHelperTest < ActionView::TestCase form_for([@post, @comment]) {} - expected = %(
) + expected = %(
) assert_dom_equal expected, output_buffer end @@ -1112,7 +1223,7 @@ class FormHelperTest < ActionView::TestCase form_for([:admin, @post, @comment]) {} - expected = %(
) + expected = %(
) assert_dom_equal expected, output_buffer end @@ -1128,7 +1239,7 @@ class FormHelperTest < ActionView::TestCase def test_form_for_with_existing_object_and_custom_url form_for(@post, :url => "/super_posts") do |f| end - expected = "
" + expected = "
" assert_equal expected, output_buffer end @@ -1173,4 +1284,4 @@ class FormHelperTest < ActionView::TestCase def protect_against_forgery? false end -end \ No newline at end of file +end diff --git a/vendor/rails/actionpack/test/template/form_options_helper_test.rb b/vendor/rails/actionpack/test/template/form_options_helper_test.rb index 78db8797..73624406 100644 --- a/vendor/rails/actionpack/test/template/form_options_helper_test.rb +++ b/vendor/rails/actionpack/test/template/form_options_helper_test.rb @@ -80,6 +80,14 @@ class FormOptionsHelperTest < ActionView::TestCase ) end + def test_string_options_for_select + options = "" + assert_dom_equal( + options, + options_for_select(options) + ) + end + def test_array_options_for_select assert_dom_equal( "\n\n", @@ -324,6 +332,20 @@ class FormOptionsHelperTest < ActionView::TestCase ) end + def test_select_under_fields_for_with_string_and_given_prompt + @post = Post.new + options = "" + + fields_for :post, @post do |f| + concat f.select(:category, options, :prompt => 'The prompt') + end + + assert_dom_equal( + "", + output_buffer + ) + end + def test_select_with_blank @post = Post.new @post.category = "" diff --git a/vendor/rails/actionpack/test/template/form_tag_helper_test.rb b/vendor/rails/actionpack/test/template/form_tag_helper_test.rb index c713b8da..09a0c646 100644 --- a/vendor/rails/actionpack/test/template/form_tag_helper_test.rb +++ b/vendor/rails/actionpack/test/template/form_tag_helper_test.rb @@ -39,13 +39,13 @@ class FormTagHelperTest < ActionView::TestCase def test_form_tag_with_method_put actual = form_tag({}, { :method => :put }) - expected = %(
) + expected = %(
) assert_dom_equal expected, actual end def test_form_tag_with_method_delete actual = form_tag({}, { :method => :delete }) - expected = %(
) + expected = %(
) assert_dom_equal expected, actual end @@ -61,7 +61,7 @@ class FormTagHelperTest < ActionView::TestCase __in_erb_template = '' form_tag("http://example.com", :method => :put) { concat "Hello world!" } - expected = %(
Hello world!
) + expected = %(
Hello world!
) assert_dom_equal expected, output_buffer end @@ -153,6 +153,23 @@ class FormTagHelperTest < ActionView::TestCase assert_dom_equal expected, actual end + def test_text_area_tag_id_sanitized + input_elem = root_elem(text_area_tag("item[][description]")) + assert_match VALID_HTML_ID, input_elem['id'] + end + + def test_text_area_tag_escape_content + actual = text_area_tag "body", "hello world", :size => "20x40" + expected = %() + assert_dom_equal expected, actual + end + + def test_text_area_tag_unescaped_content + actual = text_area_tag "body", "hello world", :size => "20x40", :escape => false + expected = %() + assert_dom_equal expected, actual + end + def test_text_field_tag actual = text_field_tag "title", "Hello!" expected = %() @@ -252,14 +269,14 @@ class FormTagHelperTest < ActionView::TestCase def test_submit_tag assert_dom_equal( - %(), + %(), submit_tag("Save", :disable_with => "Saving...", :onclick => "alert('hello!')") ) end def test_submit_tag_with_no_onclick_options assert_dom_equal( - %(), + %(), submit_tag("Save", :disable_with => "Saving...") ) end @@ -273,7 +290,7 @@ class FormTagHelperTest < ActionView::TestCase def test_submit_tag_with_confirmation_and_with_disable_with assert_dom_equal( - %(), + %(), submit_tag("Save", :disable_with => "Saving...", :confirm => "Are you sure?") ) end diff --git a/vendor/rails/actionpack/test/template/prototype_helper_test.rb b/vendor/rails/actionpack/test/template/prototype_helper_test.rb index d6b86a39..3bcf5327 100644 --- a/vendor/rails/actionpack/test/template/prototype_helper_test.rb +++ b/vendor/rails/actionpack/test/template/prototype_helper_test.rb @@ -130,7 +130,7 @@ class PrototypeHelperTest < PrototypeHelperBaseTest end def test_form_remote_tag_with_method - assert_dom_equal %(
), + assert_dom_equal %(
), form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :html => { :method => :put }) end @@ -158,7 +158,7 @@ class PrototypeHelperTest < PrototypeHelperBaseTest @record.save remote_form_for(@record) {} - expected = %(
) + expected = %(
) assert_dom_equal expected, output_buffer end @@ -174,7 +174,7 @@ class PrototypeHelperTest < PrototypeHelperBaseTest @article.save remote_form_for([@author, @article]) {} - expected = %(
) + expected = %(
) assert_dom_equal expected, output_buffer end @@ -327,28 +327,28 @@ class JavaScriptGeneratorTest < PrototypeHelperBaseTest def test_remove assert_equal 'Element.remove("foo");', @generator.remove('foo') - assert_equal '["foo", "bar", "baz"].each(Element.remove);', + assert_equal '["foo","bar","baz"].each(Element.remove);', @generator.remove('foo', 'bar', 'baz') end def test_show assert_equal 'Element.show("foo");', @generator.show('foo') - assert_equal '["foo", "bar", "baz"].each(Element.show);', + assert_equal '["foo","bar","baz"].each(Element.show);', @generator.show('foo', 'bar', 'baz') end def test_hide assert_equal 'Element.hide("foo");', @generator.hide('foo') - assert_equal '["foo", "bar", "baz"].each(Element.hide);', + assert_equal '["foo","bar","baz"].each(Element.hide);', @generator.hide('foo', 'bar', 'baz') end def test_toggle assert_equal 'Element.toggle("foo");', @generator.toggle('foo') - assert_equal '["foo", "bar", "baz"].each(Element.toggle);', + assert_equal '["foo","bar","baz"].each(Element.toggle);', @generator.toggle('foo', 'bar', 'baz') end @@ -385,7 +385,7 @@ class JavaScriptGeneratorTest < PrototypeHelperBaseTest assert_equal <<-EOS.chomp, @generator.to_s Element.insert("element", { top: "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E" }); Element.insert("element", { bottom: "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E" }); -["foo", "bar"].each(Element.remove); +["foo","bar"].each(Element.remove); Element.update("baz", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E"); EOS end @@ -554,8 +554,8 @@ return (value.className == "welcome"); end assert_equal <<-EOS.strip, @generator.to_s -var a = [1, 2, 3].zip([4, 5, 6], [7, 8, 9]); -var b = [1, 2, 3].zip([4, 5, 6], [7, 8, 9], function(array) { +var a = [1, 2, 3].zip([4,5,6], [7,8,9]); +var b = [1, 2, 3].zip([4,5,6], [7,8,9], function(array) { return array.reverse(); }); EOS @@ -606,7 +606,7 @@ return value.reverse(); def test_literal literal = @generator.literal("function() {}") - assert_equal "function() {}", literal.to_json + assert_equal "function() {}", ActiveSupport::JSON.encode(literal) assert_equal "", @generator.to_s end diff --git a/vendor/rails/actionpack/test/template/template_test.rb b/vendor/rails/actionpack/test/template/template_test.rb new file mode 100644 index 00000000..7caec7ad --- /dev/null +++ b/vendor/rails/actionpack/test/template/template_test.rb @@ -0,0 +1,32 @@ +require 'abstract_unit' + +class TemplateTest < Test::Unit::TestCase + def test_template_path_parsing + with_options :base_path => nil, :name => 'abc', :locale => nil, :format => 'html', :extension => 'erb' do |t| + t.assert_parses_template_path 'abc.en.html.erb', :locale => 'en' + t.assert_parses_template_path 'abc.en.plain.html.erb', :locale => 'en', :format => 'plain.html' + t.assert_parses_template_path 'abc.html.erb' + t.assert_parses_template_path 'abc.plain.html.erb', :format => 'plain.html' + t.assert_parses_template_path 'abc.erb', :format => nil + t.assert_parses_template_path 'abc.html', :extension => nil + + t.assert_parses_template_path '_abc.html.erb', :name => '_abc' + + t.assert_parses_template_path 'test/abc.html.erb', :base_path => 'test' + t.assert_parses_template_path './test/abc.html.erb', :base_path => './test' + t.assert_parses_template_path '../test/abc.html.erb', :base_path => '../test' + + t.assert_parses_template_path 'abc', :extension => nil, :format => nil, :name => nil + t.assert_parses_template_path 'abc.xxx', :extension => nil, :format => 'xxx', :name => 'abc' + t.assert_parses_template_path 'abc.html.xxx', :extension => nil, :format => 'xxx', :name => 'abc' + end + end + + private + def assert_parses_template_path(path, parse_results) + template = ActionView::Template.new(path, '') + parse_results.each_pair do |k, v| + assert_block(%Q{Expected template to parse #{k.inspect} from "#{path}" as #{v.inspect}, but got #{template.send(k).inspect}}) { v == template.send(k) } + end + end +end diff --git a/vendor/rails/activerecord/CHANGELOG b/vendor/rails/activerecord/CHANGELOG index c73ac464..5593a22e 100644 --- a/vendor/rails/activerecord/CHANGELOG +++ b/vendor/rails/activerecord/CHANGELOG @@ -1,3 +1,14 @@ +*2.3.3 (July 12, 2009)* + +* Added :primary_key option to belongs_to associations. #765 [Szymon Nowak, Philip Hallstrom, Noel Rocha] + # employees.company_name references companies.name + Employee.belongs_to :company, :primary_key => 'name', :foreign_key => 'company_name' + +* Added :touch option to belongs_to associations that will touch the parent record when the current record is saved or destroyed [DHH] + +* Added ActiveRecord::Base#touch to update the updated_at/on attributes (or another specified timestamp) with the current time [DHH] + + *2.3.2 [Final] (March 15, 2009)* * Added ActiveRecord::Base.find_each and ActiveRecord::Base.find_in_batches for batch processing [DHH/Jamis Buck] diff --git a/vendor/rails/activerecord/Rakefile b/vendor/rails/activerecord/Rakefile index b50008c9..78550536 100644 --- a/vendor/rails/activerecord/Rakefile +++ b/vendor/rails/activerecord/Rakefile @@ -4,7 +4,6 @@ require 'rake/testtask' require 'rake/rdoctask' require 'rake/packagetask' require 'rake/gempackagetask' -require 'rake/contrib/sshpublisher' require File.join(File.dirname(__FILE__), 'lib', 'active_record', 'version') require File.expand_path(File.dirname(__FILE__)) + "/test/config" @@ -177,7 +176,7 @@ spec = Gem::Specification.new do |s| s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) } end - s.add_dependency('activesupport', '= 2.3.2' + PKG_BUILD) + s.add_dependency('activesupport', '= 2.3.3' + PKG_BUILD) s.files.delete FIXTURES_ROOT + "/fixture_database.sqlite" s.files.delete FIXTURES_ROOT + "/fixture_database_2.sqlite" @@ -231,12 +230,14 @@ end desc "Publish the beta gem" task :pgem => [:package] do + require 'rake/contrib/sshpublisher' Rake::SshFilePublisher.new("gems.rubyonrails.org", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload `ssh gems.rubyonrails.org '/u/sites/gems/gemupdate.sh'` end desc "Publish the API documentation" task :pdoc => [:rdoc] do + require 'rake/contrib/sshpublisher' Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/ar", "doc").upload end diff --git a/vendor/rails/activerecord/lib/active_record/associations.rb b/vendor/rails/activerecord/lib/active_record/associations.rb index 6d25b36a..66db63ac 100755 --- a/vendor/rails/activerecord/lib/active_record/associations.rb +++ b/vendor/rails/activerecord/lib/active_record/associations.rb @@ -957,6 +957,8 @@ module ActiveRecord # of the association with an "_id" suffix. So a class that defines a belongs_to :person association will use # "person_id" as the default :foreign_key. Similarly, belongs_to :favorite_person, :class_name => "Person" # will use a foreign key of "favorite_person_id". + # [:primary_key] + # Specify the method that returns the primary key of associated object used for the association. By default this is id. # [:dependent] # If set to :destroy, the associated object is destroyed when this object is. If set to # :delete, the associated object is deleted *without* calling its destroy method. This option should not be specified when @@ -981,15 +983,21 @@ module ActiveRecord # If false, don't validate the associated objects when saving the parent object. +false+ by default. # [:autosave] # If true, always save the associated object or destroy it if marked for destruction, when saving the parent object. Off by default. + # [:touch] + # If true, the associated object will be touched (the updated_at/on attributes set to now) when this record is either saved or + # destroyed. If you specify a symbol, that attribute will be updated with the current time instead of the updated_at/on attribute. # # Option examples: # belongs_to :firm, :foreign_key => "client_of" + # belongs_to :person, :primary_key => "name", :foreign_key => "person_name" # belongs_to :author, :class_name => "Person", :foreign_key => "author_id" # belongs_to :valid_coupon, :class_name => "Coupon", :foreign_key => "coupon_id", # :conditions => 'discounts > #{payments_count}' # belongs_to :attachable, :polymorphic => true # belongs_to :project, :readonly => true # belongs_to :post, :counter_cache => true + # belongs_to :company, :touch => true + # belongs_to :company, :touch => :employees_last_updated_at def belongs_to(association_id, options = {}) reflection = create_belongs_to_reflection(association_id, options) @@ -1001,28 +1009,8 @@ module ActiveRecord association_constructor_method(:create, reflection, BelongsToAssociation) end - # Create the callbacks to update counter cache - if options[:counter_cache] - cache_column = reflection.counter_cache_column - - method_name = "belongs_to_counter_cache_after_create_for_#{reflection.name}".to_sym - define_method(method_name) do - association = send(reflection.name) - association.class.increment_counter(cache_column, send(reflection.primary_key_name)) unless association.nil? - end - after_create method_name - - method_name = "belongs_to_counter_cache_before_destroy_for_#{reflection.name}".to_sym - define_method(method_name) do - association = send(reflection.name) - association.class.decrement_counter(cache_column, send(reflection.primary_key_name)) unless association.nil? - end - before_destroy method_name - - module_eval( - "#{reflection.class_name}.send(:attr_readonly,\"#{cache_column}\".intern) if defined?(#{reflection.class_name}) && #{reflection.class_name}.respond_to?(:attr_readonly)" - ) - end + add_counter_cache_callbacks(reflection) if options[:counter_cache] + add_touch_callbacks(reflection, options[:touch]) if options[:touch] configure_dependency_for_belongs_to(reflection) end @@ -1329,6 +1317,43 @@ module ActiveRecord end end + def add_counter_cache_callbacks(reflection) + cache_column = reflection.counter_cache_column + + method_name = "belongs_to_counter_cache_after_create_for_#{reflection.name}".to_sym + define_method(method_name) do + association = send(reflection.name) + association.class.increment_counter(cache_column, association.id) unless association.nil? + end + after_create(method_name) + + method_name = "belongs_to_counter_cache_before_destroy_for_#{reflection.name}".to_sym + define_method(method_name) do + association = send(reflection.name) + association.class.decrement_counter(cache_column, association.id) unless association.nil? + end + before_destroy(method_name) + + module_eval( + "#{reflection.class_name}.send(:attr_readonly,\"#{cache_column}\".intern) if defined?(#{reflection.class_name}) && #{reflection.class_name}.respond_to?(:attr_readonly)" + ) + end + + def add_touch_callbacks(reflection, touch_attribute) + method_name = "belongs_to_touch_after_save_or_destroy_for_#{reflection.name}".to_sym + define_method(method_name) do + association = send(reflection.name) + + if touch_attribute == true + association.touch unless association.nil? + else + association.touch(touch_attribute) unless association.nil? + end + end + after_save(method_name) + after_destroy(method_name) + end + def find_with_associations(options = {}) catch :invalid_query do join_dependency = JoinDependency.new(self, merge_includes(scope(:find, :include), options[:include]), options[:joins]) @@ -1353,7 +1378,7 @@ module ActiveRecord dependent_conditions = [] dependent_conditions << "#{reflection.primary_key_name} = \#{record.quoted_id}" dependent_conditions << "#{reflection.options[:as]}_type = '#{base_class.name}'" if reflection.options[:as] - dependent_conditions << sanitize_sql(reflection.options[:conditions]) if reflection.options[:conditions] + dependent_conditions << sanitize_sql(reflection.options[:conditions], reflection.quoted_table_name) if reflection.options[:conditions] dependent_conditions << extra_conditions if extra_conditions dependent_conditions = dependent_conditions.collect {|where| "(#{where})" }.join(" AND ") dependent_conditions = dependent_conditions.gsub('@', '\@') @@ -1497,9 +1522,9 @@ module ActiveRecord mattr_accessor :valid_keys_for_belongs_to_association @@valid_keys_for_belongs_to_association = [ - :class_name, :foreign_key, :foreign_type, :remote, :select, :conditions, + :class_name, :primary_key, :foreign_key, :foreign_type, :remote, :select, :conditions, :include, :dependent, :counter_cache, :extend, :polymorphic, :readonly, - :validate + :validate, :touch ] def create_belongs_to_reflection(association_id, options) @@ -1643,17 +1668,29 @@ module ActiveRecord string.scan(/([\.a-zA-Z_]+).?\./).flatten end + def tables_in_hash(hash) + return [] if hash.blank? + tables = hash.map do |key, value| + if value.is_a?(Hash) + key.to_s + else + tables_in_string(key) if key.is_a?(String) + end + end + tables.flatten.compact + end + def conditions_tables(options) # look in both sets of conditions conditions = [scope(:find, :conditions), options[:conditions]].inject([]) do |all, cond| case cond when nil then all - when Array then all << cond.first - when Hash then all << cond.keys - else all << cond + when Array then all << tables_in_string(cond.first) + when Hash then all << tables_in_hash(cond) + else all << tables_in_string(cond) end end - tables_in_string(conditions.join(' ')) + conditions.flatten end def order_tables(options) @@ -2101,7 +2138,7 @@ module ActiveRecord klass.send(:type_condition, aliased_table_name)] unless klass.descends_from_active_record? [through_reflection, reflection].each do |ref| - join << "AND #{interpolate_sql(sanitize_sql(ref.options[:conditions]))} " if ref && ref.options[:conditions] + join << "AND #{interpolate_sql(sanitize_sql(ref.options[:conditions], aliased_table_name))} " if ref && ref.options[:conditions] end join diff --git a/vendor/rails/activerecord/lib/active_record/associations/association_proxy.rb b/vendor/rails/activerecord/lib/active_record/associations/association_proxy.rb index 676c4ace..241b9bfe 100644 --- a/vendor/rails/activerecord/lib/active_record/associations/association_proxy.rb +++ b/vendor/rails/activerecord/lib/active_record/associations/association_proxy.rb @@ -169,8 +169,8 @@ module ActiveRecord end # Forwards the call to the reflection class. - def sanitize_sql(sql) - @reflection.klass.send(:sanitize_sql, sql) + def sanitize_sql(sql, table_name = @reflection.klass.quoted_table_name) + @reflection.klass.send(:sanitize_sql, sql, table_name) end # Assigns the ID of the owner to the corresponding foreign key in +record+. diff --git a/vendor/rails/activerecord/lib/active_record/associations/belongs_to_association.rb b/vendor/rails/activerecord/lib/active_record/associations/belongs_to_association.rb index f05c6be0..05f8f4fe 100644 --- a/vendor/rails/activerecord/lib/active_record/associations/belongs_to_association.rb +++ b/vendor/rails/activerecord/lib/active_record/associations/belongs_to_association.rb @@ -14,7 +14,7 @@ module ActiveRecord if record.nil? if counter_cache_name && !@owner.new_record? - @reflection.klass.decrement_counter(counter_cache_name, @owner[@reflection.primary_key_name]) if @owner[@reflection.primary_key_name] + @reflection.klass.decrement_counter(counter_cache_name, previous_record_id) if @owner[@reflection.primary_key_name] end @target = @owner[@reflection.primary_key_name] = nil @@ -27,7 +27,7 @@ module ActiveRecord end @target = (AssociationProxy === record ? record.target : record) - @owner[@reflection.primary_key_name] = record.id unless record.new_record? + @owner[@reflection.primary_key_name] = record_id(record) unless record.new_record? @updated = true end @@ -41,18 +41,36 @@ module ActiveRecord private def find_target - @reflection.klass.find( + find_method = if @reflection.options[:primary_key] + "find_by_#{@reflection.options[:primary_key]}" + else + "find" + end + @reflection.klass.send(find_method, @owner[@reflection.primary_key_name], :select => @reflection.options[:select], :conditions => conditions, :include => @reflection.options[:include], :readonly => @reflection.options[:readonly] - ) + ) if @owner[@reflection.primary_key_name] end def foreign_key_present !@owner[@reflection.primary_key_name].nil? end + + def record_id(record) + record.send(@reflection.options[:primary_key] || :id) + end + + def previous_record_id + @previous_record_id ||= if @reflection.options[:primary_key] + previous_record = @owner.send(@reflection.name) + previous_record.nil? ? nil : previous_record.id + else + @owner[@reflection.primary_key_name] + end + end end end end diff --git a/vendor/rails/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb b/vendor/rails/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb index d8146daa..67e18d69 100644 --- a/vendor/rails/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb +++ b/vendor/rails/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb @@ -7,7 +7,7 @@ module ActiveRecord else @target = (AssociationProxy === record ? record.target : record) - @owner[@reflection.primary_key_name] = record.id + @owner[@reflection.primary_key_name] = record_id(record) @owner[@reflection.options[:foreign_type]] = record.class.base_class.name.to_s @updated = true @@ -41,6 +41,10 @@ module ActiveRecord !@owner[@reflection.primary_key_name].nil? end + def record_id(record) + record.send(@reflection.options[:primary_key] || :id) + end + def association_class @owner[@reflection.options[:foreign_type]] ? @owner[@reflection.options[:foreign_type]].constantize : nil end diff --git a/vendor/rails/activerecord/lib/active_record/associations/has_one_through_association.rb b/vendor/rails/activerecord/lib/active_record/associations/has_one_through_association.rb index 8073ebaf..d93c8e78 100644 --- a/vendor/rails/activerecord/lib/active_record/associations/has_one_through_association.rb +++ b/vendor/rails/activerecord/lib/active_record/associations/has_one_through_association.rb @@ -1,31 +1,31 @@ module ActiveRecord module Associations class HasOneThroughAssociation < HasManyThroughAssociation - + def create_through_record(new_value) #nodoc: klass = @reflection.through_reflection.klass current_object = @owner.send(@reflection.through_reflection.name) - + if current_object - current_object.update_attributes(construct_join_attributes(new_value)) + new_value ? current_object.update_attributes(construct_join_attributes(new_value)) : current_object.destroy else - @owner.send(@reflection.through_reflection.name, klass.send(:create, construct_join_attributes(new_value))) + @owner.send(@reflection.through_reflection.name, klass.send(:create, construct_join_attributes(new_value))) if new_value end end - + private def find(*args) super(args.merge(:limit => 1)) end - + def find_target super.first end def reset_target! @target = nil - end - end + end + end end end diff --git a/vendor/rails/activerecord/lib/active_record/autosave_association.rb b/vendor/rails/activerecord/lib/active_record/autosave_association.rb index 741aa2ac..4f63b52c 100644 --- a/vendor/rails/activerecord/lib/active_record/autosave_association.rb +++ b/vendor/rails/activerecord/lib/active_record/autosave_association.rb @@ -311,11 +311,13 @@ module ActiveRecord # ActiveRecord::Base after the AutosaveAssociation module, which it does by default. def save_has_one_association(reflection) if (association = association_instance_get(reflection.name)) && !association.target.nil? - if reflection.options[:autosave] && association.marked_for_destruction? + autosave = reflection.options[:autosave] + + if autosave && association.marked_for_destruction? association.destroy - elsif new_record? || association.new_record? || association[reflection.primary_key_name] != id || reflection.options[:autosave] + elsif new_record? || association.new_record? || association[reflection.primary_key_name] != id || autosave association[reflection.primary_key_name] = id - association.save(false) + association.save(!autosave) end end end @@ -330,13 +332,16 @@ module ActiveRecord # ActiveRecord::Base after the AutosaveAssociation module, which it does by default. def save_belongs_to_association(reflection) if association = association_instance_get(reflection.name) - if reflection.options[:autosave] && association.marked_for_destruction? + autosave = reflection.options[:autosave] + + if autosave && association.marked_for_destruction? association.destroy else - association.save(false) if association.new_record? || reflection.options[:autosave] + association.save(!autosave) if association.new_record? || autosave if association.updated? - self[reflection.primary_key_name] = association.id + association_id = association.send(reflection.options[:primary_key] || :id) + self[reflection.primary_key_name] = association_id # TODO: Removing this code doesn't seem to matter… if reflection.options[:polymorphic] self[reflection.options[:foreign_type]] = association.class.base_class.name.to_s diff --git a/vendor/rails/activerecord/lib/active_record/base.rb b/vendor/rails/activerecord/lib/active_record/base.rb index 2a538511..d155837d 100755 --- a/vendor/rails/activerecord/lib/active_record/base.rb +++ b/vendor/rails/activerecord/lib/active_record/base.rb @@ -687,14 +687,9 @@ module ActiveRecord #:nodoc: # Person.exists?(['name LIKE ?', "%#{query}%"]) # Person.exists? def exists?(id_or_conditions = {}) - connection.select_all( - construct_finder_sql( - :select => "#{quoted_table_name}.#{primary_key}", - :conditions => expand_id_conditions(id_or_conditions), - :limit => 1 - ), - "#{name} Exists" - ).size > 0 + find_initial( + :select => "#{quoted_table_name}.#{primary_key}", + :conditions => expand_id_conditions(id_or_conditions)) ? true : false end # Creates an object (or multiple objects) and saves it to the database, if validations pass. @@ -2168,7 +2163,7 @@ module ActiveRecord #:nodoc: # default_scope :order => 'last_name, first_name' # end def default_scope(options = {}) - self.default_scoping << { :find => options, :create => (options.is_a?(Hash) && options.has_key?(:conditions)) ? options[:conditions] : {} } + self.default_scoping << { :find => options, :create => options[:conditions].is_a?(Hash) ? options[:conditions] : {} } end # Test whether the given method and optional key are scoped. @@ -2228,12 +2223,12 @@ module ActiveRecord #:nodoc: # ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'" # { :name => "foo'bar", :group_id => 4 } returns "name='foo''bar' and group_id='4'" # "name='foo''bar' and group_id='4'" returns "name='foo''bar' and group_id='4'" - def sanitize_sql_for_conditions(condition) + def sanitize_sql_for_conditions(condition, table_name = quoted_table_name) return nil if condition.blank? case condition when Array; sanitize_sql_array(condition) - when Hash; sanitize_sql_hash_for_conditions(condition) + when Hash; sanitize_sql_hash_for_conditions(condition, table_name) else condition end end @@ -3034,11 +3029,11 @@ module ActiveRecord #:nodoc: def execute_callstack_for_multiparameter_attributes(callstack) errors = [] callstack.each do |name, values| - klass = (self.class.reflect_on_aggregation(name.to_sym) || column_for_attribute(name)).klass - if values.empty? - send(name + "=", nil) - else - begin + begin + klass = (self.class.reflect_on_aggregation(name.to_sym) || column_for_attribute(name)).klass + if values.empty? + send(name + "=", nil) + else value = if Time == klass instantiate_time_object(name, values) elsif Date == klass @@ -3052,9 +3047,9 @@ module ActiveRecord #:nodoc: end send(name + "=", value) - rescue => ex - errors << AttributeAssignmentError.new("error on assignment #{values.inspect} to #{name}", ex, name) end + rescue => ex + errors << AttributeAssignmentError.new("error on assignment #{values.inspect} to #{name}", ex, name) end end unless errors.empty? @@ -3080,7 +3075,7 @@ module ActiveRecord #:nodoc: end def type_cast_attribute_value(multiparameter_name, value) - multiparameter_name =~ /\([0-9]*([a-z])\)/ ? value.send("to_" + $1) : value + multiparameter_name =~ /\([0-9]*([if])\)/ ? value.send("to_" + $1) : value end def find_parameter_position(multiparameter_name) diff --git a/vendor/rails/activerecord/lib/active_record/calculations.rb b/vendor/rails/activerecord/lib/active_record/calculations.rb index f077818d..7af97d72 100644 --- a/vendor/rails/activerecord/lib/active_record/calculations.rb +++ b/vendor/rails/activerecord/lib/active_record/calculations.rb @@ -141,30 +141,22 @@ module ActiveRecord def construct_count_options_from_args(*args) options = {} column_name = :all - + # We need to handle # count() # count(:column_name=:all) # count(options={}) # count(column_name=:all, options={}) - # selects specified by scopes case args.size - when 0 - column_name = scope(:find)[:select] if scope(:find) when 1 - if args[0].is_a?(Hash) - column_name = scope(:find)[:select] if scope(:find) - options = args[0] - else - column_name = args[0] - end + args[0].is_a?(Hash) ? options = args[0] : column_name = args[0] when 2 column_name, options = args else raise ArgumentError, "Unexpected parameters passed to count(): #{args.inspect}" - end - - [column_name || :all, options] + end if args.size > 0 + + [column_name, options] end def construct_calculation_sql(operation, column_name, options) #:nodoc: diff --git a/vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 913bb521..8440223d 100644 --- a/vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -287,7 +287,13 @@ module ActiveRecord # Escapes binary strings for bytea input to the database. def escape_bytea(value) - if PGconn.respond_to?(:escape_bytea) + if @connection.respond_to?(:escape_bytea) + self.class.instance_eval do + define_method(:escape_bytea) do |value| + @connection.escape_bytea(value) if value + end + end + elsif PGconn.respond_to?(:escape_bytea) self.class.instance_eval do define_method(:escape_bytea) do |value| PGconn.escape_bytea(value) if value @@ -376,7 +382,13 @@ module ActiveRecord # Quotes strings for use in SQL input in the postgres driver for better performance. def quote_string(s) #:nodoc: - if PGconn.respond_to?(:escape) + if @connection.respond_to?(:escape) + self.class.instance_eval do + define_method(:quote_string) do |s| + @connection.escape(s) + end + end + elsif PGconn.respond_to?(:escape) self.class.instance_eval do define_method(:quote_string) do |s| PGconn.escape(s) @@ -392,9 +404,28 @@ module ActiveRecord quote_string(s) end + # Checks the following cases: + # + # - table_name + # - "table.name" + # - schema_name.table_name + # - schema_name."table.name" + # - "schema.name".table_name + # - "schema.name"."table.name" + def quote_table_name(name) + schema, name_part = extract_pg_identifier_from_name(name.to_s) + + unless name_part + quote_column_name(schema) + else + table_name, name_part = extract_pg_identifier_from_name(name_part) + "#{quote_column_name(schema)}.#{quote_column_name(table_name)}" + end + end + # Quotes column names for use in SQL queries. def quote_column_name(name) #:nodoc: - %("#{name}") + PGconn.quote_ident(name.to_s) end # Quote date/time values for use in SQL input. Includes microseconds @@ -621,33 +652,36 @@ module ActiveRecord def indexes(table_name, name = nil) schemas = schema_search_path.split(/,/).map { |p| quote(p) }.join(',') result = query(<<-SQL, name) - SELECT distinct i.relname, d.indisunique, a.attname - FROM pg_class t, pg_class i, pg_index d, pg_attribute a + SELECT distinct i.relname, d.indisunique, d.indkey, t.oid + FROM pg_class t, pg_class i, pg_index d WHERE i.relkind = 'i' AND d.indexrelid = i.oid AND d.indisprimary = 'f' AND t.oid = d.indrelid AND t.relname = '#{table_name}' AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname IN (#{schemas}) ) - AND a.attrelid = t.oid - AND ( d.indkey[0]=a.attnum OR d.indkey[1]=a.attnum - OR d.indkey[2]=a.attnum OR d.indkey[3]=a.attnum - OR d.indkey[4]=a.attnum OR d.indkey[5]=a.attnum - OR d.indkey[6]=a.attnum OR d.indkey[7]=a.attnum - OR d.indkey[8]=a.attnum OR d.indkey[9]=a.attnum ) ORDER BY i.relname SQL - current_index = nil + indexes = [] - result.each do |row| - if current_index != row[0] - indexes << IndexDefinition.new(table_name, row[0], row[1] == "t", []) - current_index = row[0] - end + indexes = result.map do |row| + index_name = row[0] + unique = row[1] == 't' + indkey = row[2].split(" ") + oid = row[3] + + columns = query(<<-SQL, "Columns for index #{row[0]} on #{table_name}").inject({}) {|attlist, r| attlist[r[1]] = r[0]; attlist} + SELECT a.attname, a.attnum + FROM pg_attribute a + WHERE a.attrelid = #{oid} + AND a.attnum IN (#{indkey.join(",")}) + SQL + + column_names = indkey.map {|attnum| columns[attnum] } + IndexDefinition.new(table_name, index_name, unique, column_names) - indexes.last.columns << row[2] end indexes @@ -745,7 +779,7 @@ module ActiveRecord AND attr.attrelid = cons.conrelid AND attr.attnum = cons.conkey[1] AND cons.contype = 'p' - AND dep.refobjid = '#{table}'::regclass + AND dep.refobjid = '#{quote_table_name(table)}'::regclass end_sql if result.nil? or result.empty? @@ -764,7 +798,7 @@ module ActiveRecord JOIN pg_attribute attr ON (t.oid = attrelid) JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum) JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1]) - WHERE t.oid = '#{table}'::regclass + WHERE t.oid = '#{quote_table_name(table)}'::regclass AND cons.contype = 'p' AND def.adsrc ~* 'nextval' end_sql @@ -839,7 +873,7 @@ module ActiveRecord # Drops an index from a table. def remove_index(table_name, options = {}) - execute "DROP INDEX #{index_name(table_name, options)}" + execute "DROP INDEX #{quote_table_name(index_name(table_name, options))}" end # Maps logical Rails types to PostgreSQL-specific data types. @@ -1040,11 +1074,21 @@ module ActiveRecord SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull FROM pg_attribute a LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum - WHERE a.attrelid = '#{table_name}'::regclass + WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum end_sql end + + def extract_pg_identifier_from_name(name) + match_data = name[0,1] == '"' ? name.match(/\"([^\"]+)\"/) : name.match(/([^\.]+)/) + + if match_data + rest = name[match_data[0].length..-1] + rest = rest[1..-1] if rest[0,1] == "." + [match_data[1], (rest.length > 0 ? rest : nil)] + end + end end end end diff --git a/vendor/rails/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/vendor/rails/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index afd6472d..69f79755 100644 --- a/vendor/rails/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/vendor/rails/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -1,3 +1,4 @@ +# encoding: binary require 'active_record/connection_adapters/abstract_adapter' module ActiveRecord @@ -46,6 +47,7 @@ module ActiveRecord class SQLiteColumn < Column #:nodoc: class << self def string_to_binary(value) + value = value.dup.force_encoding(Encoding::BINARY) if value.respond_to?(:force_encoding) value.gsub(/\0|\%/n) do |b| case b when "\0" then "%00" @@ -55,6 +57,7 @@ module ActiveRecord end def binary_to_string(value) + value = value.dup.force_encoding(Encoding::BINARY) if value.respond_to?(:force_encoding) value.gsub(/%00|%25/n) do |b| case b when "%00" then "\0" diff --git a/vendor/rails/activerecord/lib/active_record/fixtures.rb b/vendor/rails/activerecord/lib/active_record/fixtures.rb index c6501113..77f0931e 100644 --- a/vendor/rails/activerecord/lib/active_record/fixtures.rb +++ b/vendor/rails/activerecord/lib/active_record/fixtures.rb @@ -1,6 +1,7 @@ require 'erb' require 'yaml' require 'csv' +require 'zlib' require 'active_support/dependencies' require 'active_support/test_case' @@ -433,6 +434,7 @@ end # Any fixture labeled "DEFAULTS" is safely ignored. class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash) + MAX_ID = 2 ** 31 - 1 DEFAULT_FILTER_RE = /\.ya?ml$/ @@all_cached_fixtures = {} @@ -524,11 +526,10 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash) cached_fixtures(connection, table_names) end - # Returns a consistent identifier for +label+. This will always - # be a positive integer, and will always be the same for a given - # label, assuming the same OS, platform, and version of Ruby. + # Returns a consistent, platform-independent identifier for +label+. + # Identifiers are positive integers less than 2^32. def self.identify(label) - label.to_s.hash.abs + Zlib.crc32(label.to_s) % MAX_ID end attr_reader :table_name, :name diff --git a/vendor/rails/activerecord/lib/active_record/named_scope.rb b/vendor/rails/activerecord/lib/active_record/named_scope.rb index 1f3ef300..3df70890 100644 --- a/vendor/rails/activerecord/lib/active_record/named_scope.rb +++ b/vendor/rails/activerecord/lib/active_record/named_scope.rb @@ -114,7 +114,7 @@ module ActiveRecord end end - delegate :scopes, :with_scope, :to => :proxy_scope + delegate :scopes, :with_scope, :scoped_methods, :to => :proxy_scope def initialize(proxy_scope, options, &block) options ||= {} @@ -178,7 +178,7 @@ module ActiveRecord else with_scope({:find => proxy_options, :create => proxy_options[:conditions].is_a?(Hash) ? proxy_options[:conditions] : {}}, :reverse_merge) do method = :new if method == :build - if current_scoped_methods_when_defined + if current_scoped_methods_when_defined && !scoped_methods.include?(current_scoped_methods_when_defined) with_scope current_scoped_methods_when_defined do proxy_scope.send(method, *args, &block) end diff --git a/vendor/rails/activerecord/lib/active_record/schema_dumper.rb b/vendor/rails/activerecord/lib/active_record/schema_dumper.rb index 557a5549..651cd361 100644 --- a/vendor/rails/activerecord/lib/active_record/schema_dumper.rb +++ b/vendor/rails/activerecord/lib/active_record/schema_dumper.rb @@ -78,11 +78,14 @@ HEADER begin tbl = StringIO.new + # first dump primary key column if @connection.respond_to?(:pk_and_sequence_for) pk, pk_seq = @connection.pk_and_sequence_for(table) + elsif @connection.respond_to?(:primary_key) + pk = @connection.primary_key(table) end pk ||= 'id' - + tbl.print " create_table #{table.inspect}" if columns.detect { |c| c.name == pk } if pk != 'id' @@ -94,6 +97,7 @@ HEADER tbl.print ", :force => true" tbl.puts " do |t|" + # then dump all non-primary key columns column_specs = columns.map do |column| raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" if @types[column.type].nil? next if column.name == pk diff --git a/vendor/rails/activerecord/lib/active_record/serialization.rb b/vendor/rails/activerecord/lib/active_record/serialization.rb index 870b4b2d..629ce9a1 100644 --- a/vendor/rails/activerecord/lib/active_record/serialization.rb +++ b/vendor/rails/activerecord/lib/active_record/serialization.rb @@ -5,8 +5,9 @@ module ActiveRecord #:nodoc: class Serializer #:nodoc: attr_reader :options - def initialize(record, options = {}) - @record, @options = record, options.dup + def initialize(record, options = nil) + @record = record + @options = options ? options.dup : {} end # To replicate the behavior in ActiveRecord#attributes, diff --git a/vendor/rails/activerecord/lib/active_record/serializers/json_serializer.rb b/vendor/rails/activerecord/lib/active_record/serializers/json_serializer.rb index 1fd65ed0..085d4f17 100644 --- a/vendor/rails/activerecord/lib/active_record/serializers/json_serializer.rb +++ b/vendor/rails/activerecord/lib/active_record/serializers/json_serializer.rb @@ -1,8 +1,10 @@ +require 'active_support/json' +require 'active_support/core_ext/module/model_naming' + module ActiveRecord #:nodoc: module Serialization def self.included(base) base.cattr_accessor :include_root_in_json, :instance_writer => false - base.extend ClassMethods end # Returns a JSON string representing the model. Some configuration is @@ -72,28 +74,16 @@ module ActiveRecord #:nodoc: # {"comments": [{"body": "Don't think too hard"}], # "title": "So I was thinking"}]} def to_json(options = {}) - if include_root_in_json - "{#{self.class.json_class_name}: #{JsonSerializer.new(self, options).to_s}}" - else - JsonSerializer.new(self, options).to_s - end + hash = Serializer.new(self, options).serializable_record + hash = { self.class.model_name.element => hash } if include_root_in_json + ActiveSupport::JSON.encode(hash) end + def as_json(options = nil) self end #:nodoc: + def from_json(json) self.attributes = ActiveSupport::JSON.decode(json) self end - - class JsonSerializer < ActiveRecord::Serialization::Serializer #:nodoc: - def serialize - serializable_record.to_json - end - end - - module ClassMethods - def json_class_name - @json_class_name ||= name.demodulize.underscore.inspect - end - end end end diff --git a/vendor/rails/activerecord/lib/active_record/session_store.rb b/vendor/rails/activerecord/lib/active_record/session_store.rb index 3cc4640f..c91b9433 100644 --- a/vendor/rails/activerecord/lib/active_record/session_store.rb +++ b/vendor/rails/activerecord/lib/active_record/session_store.rb @@ -295,7 +295,7 @@ module ActiveRecord def set_session(env, sid, session_data) Base.silence do - record = env[SESSION_RECORD_KEY] ||= find_session(sid) + record = get_session_model(env, sid) record.data = session_data return false unless record.save @@ -309,6 +309,14 @@ module ActiveRecord return true end + + def get_session_model(env, sid) + if env[ENV_SESSION_OPTIONS_KEY][:id].nil? + env[SESSION_RECORD_KEY] = find_session(sid) + else + env[SESSION_RECORD_KEY] ||= find_session(sid) + end + end def find_session(id) @@session_class.find_by_session_id(id) || diff --git a/vendor/rails/activerecord/lib/active_record/timestamp.rb b/vendor/rails/activerecord/lib/active_record/timestamp.rb index 8dbe80a0..d9e1ef35 100644 --- a/vendor/rails/activerecord/lib/active_record/timestamp.rb +++ b/vendor/rails/activerecord/lib/active_record/timestamp.rb @@ -15,27 +15,57 @@ module ActiveRecord base.class_inheritable_accessor :record_timestamps, :instance_writer => false base.record_timestamps = true end + + # Saves the record with the updated_at/on attributes set to the current time. + # If the save fails because of validation errors, an ActiveRecord::RecordInvalid exception is raised. + # If an attribute name is passed, that attribute is used for the touch instead of the updated_at/on attributes. + # + # Examples: + # + # product.touch # updates updated_at + # product.touch(:designed_at) # updates the designed_at attribute + def touch(attribute = nil) + current_time = current_time_from_proper_timezone + + if attribute + write_attribute(attribute, current_time) + else + write_attribute('updated_at', current_time) if respond_to?(:updated_at) + write_attribute('updated_on', current_time) if respond_to?(:updated_on) + end + + save! + end + private def create_with_timestamps #:nodoc: if record_timestamps - t = self.class.default_timezone == :utc ? Time.now.utc : Time.now - write_attribute('created_at', t) if respond_to?(:created_at) && created_at.nil? - write_attribute('created_on', t) if respond_to?(:created_on) && created_on.nil? + current_time = current_time_from_proper_timezone - write_attribute('updated_at', t) if respond_to?(:updated_at) && updated_at.nil? - write_attribute('updated_on', t) if respond_to?(:updated_on) && updated_on.nil? + write_attribute('created_at', current_time) if respond_to?(:created_at) && created_at.nil? + write_attribute('created_on', current_time) if respond_to?(:created_on) && created_on.nil? + + write_attribute('updated_at', current_time) if respond_to?(:updated_at) && updated_at.nil? + write_attribute('updated_on', current_time) if respond_to?(:updated_on) && updated_on.nil? end + create_without_timestamps end def update_with_timestamps(*args) #:nodoc: if record_timestamps && (!partial_updates? || changed?) - t = self.class.default_timezone == :utc ? Time.now.utc : Time.now - write_attribute('updated_at', t) if respond_to?(:updated_at) - write_attribute('updated_on', t) if respond_to?(:updated_on) + current_time = current_time_from_proper_timezone + + write_attribute('updated_at', current_time) if respond_to?(:updated_at) + write_attribute('updated_on', current_time) if respond_to?(:updated_on) end + update_without_timestamps(*args) end + + def current_time_from_proper_timezone + self.class.default_timezone == :utc ? Time.now.utc : Time.now + end end -end +end \ No newline at end of file diff --git a/vendor/rails/activerecord/lib/active_record/version.rb b/vendor/rails/activerecord/lib/active_record/version.rb index 852807b4..cbd6958a 100644 --- a/vendor/rails/activerecord/lib/active_record/version.rb +++ b/vendor/rails/activerecord/lib/active_record/version.rb @@ -2,7 +2,7 @@ module ActiveRecord module VERSION #:nodoc: MAJOR = 2 MINOR = 3 - TINY = 2 + TINY = 3 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/vendor/rails/activerecord/test/cases/associations/belongs_to_associations_test.rb b/vendor/rails/activerecord/test/cases/associations/belongs_to_associations_test.rb index 13a78a18..970601cd 100644 --- a/vendor/rails/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/vendor/rails/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -14,6 +14,7 @@ require 'models/tagging' require 'models/comment' require 'models/sponsor' require 'models/member' +require 'models/essay' class BelongsToAssociationsTest < ActiveRecord::TestCase fixtures :accounts, :companies, :developers, :projects, :topics, @@ -25,6 +26,11 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert !Client.find(3).firm.nil?, "Microsoft should have a firm" end + def test_belongs_to_with_primary_key + client = Client.create(:name => "Primary key client", :firm_name => companies(:first_firm).name) + assert_equal companies(:first_firm).name, client.firm_with_primary_key.name + end + def test_proxy_assignment account = Account.find(1) assert_nothing_raised { account.firm = account.firm } @@ -47,6 +53,13 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal apple.id, citibank.firm_id end + def test_natural_assignment_with_primary_key + apple = Firm.create("name" => "Apple") + citibank = Client.create("name" => "Primary key client") + citibank.firm_with_primary_key = apple + assert_equal apple.name, citibank.firm_name + end + def test_no_unexpected_aliasing first_firm = companies(:first_firm) another_firm = companies(:another_firm) @@ -69,6 +82,15 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal apple, citibank.firm end + def test_creating_the_belonging_object_with_primary_key + client = Client.create(:name => "Primary key client") + apple = client.create_firm_with_primary_key("name" => "Apple") + assert_equal apple, client.firm_with_primary_key + client.save + client.reload + assert_equal apple, client.firm_with_primary_key + end + def test_building_the_belonging_object citibank = Account.create("credit_limit" => 10) apple = citibank.build_firm("name" => "Apple") @@ -76,6 +98,13 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal apple.id, citibank.firm_id end + def test_building_the_belonging_object_with_primary_key + client = Client.create(:name => "Primary key client") + apple = client.build_firm_with_primary_key("name" => "Apple") + client.save + assert_equal apple.name, client.firm_name + end + def test_natural_assignment_to_nil client = Client.find(3) client.firm = nil @@ -84,6 +113,14 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_nil client.client_of end + def test_natural_assignment_to_nil_with_primary_key + client = Client.create(:name => "Primary key client", :firm_name => companies(:first_firm).name) + client.firm_with_primary_key = nil + client.save + assert_nil client.firm_with_primary_key(true) + assert_nil client.client_of + end + def test_with_different_class_name assert_equal Company.find(1).name, Company.find(3).firm_with_other_name.name assert_not_nil Company.find(3).firm_with_other_name, "Microsoft should have a firm" @@ -110,6 +147,17 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal 0, Topic.find(debate.id).send(:read_attribute, "replies_count"), "First reply deleted" end + def test_belongs_to_with_primary_key_counter + debate = Topic.create("title" => "debate") + assert_equal 0, debate.send(:read_attribute, "replies_count"), "No replies yet" + + trash = debate.replies_with_primary_key.create("title" => "blah!", "content" => "world around!") + assert_equal 1, Topic.find(debate.id).send(:read_attribute, "replies_count"), "First reply created" + + trash.destroy + assert_equal 0, Topic.find(debate.id).send(:read_attribute, "replies_count"), "First reply deleted" + end + def test_belongs_to_counter_with_assigning_nil p = Post.find(1) c = Comment.find(1) @@ -122,6 +170,18 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal 1, Post.find(p.id).comments.size end + def test_belongs_to_with_primary_key_counter_with_assigning_nil + debate = Topic.create("title" => "debate") + reply = Reply.create("title" => "blah!", "content" => "world around!", "parent_title" => "debate") + + assert_equal debate.title, reply.parent_title + assert_equal 1, Topic.find(debate.id).send(:read_attribute, "replies_count") + + reply.topic_with_primary_key = nil + + assert_equal 0, Topic.find(debate.id).send(:read_attribute, "replies_count") + end + def test_belongs_to_counter_with_reassigning t1 = Topic.create("title" => "t1") t2 = Topic.create("title" => "t2") @@ -219,6 +279,18 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal firm, final_cut.firm(true) end + def test_assignment_before_child_saved_with_primary_key + final_cut = Client.new("name" => "Final Cut") + firm = Firm.find(1) + final_cut.firm_with_primary_key = firm + assert final_cut.new_record? + assert final_cut.save + assert !final_cut.new_record? + assert !firm.new_record? + assert_equal firm, final_cut.firm_with_primary_key + assert_equal firm, final_cut.firm_with_primary_key(true) + end + def test_new_record_with_foreign_key_but_no_object c = Client.new("firm_id" => 1) assert_equal Firm.find(:first), c.firm_with_basic_id @@ -297,26 +369,52 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase member = Member.create sponsor.sponsorable = member assert_equal "Member", sponsor.sponsorable_type - + # should update when assigning a new record sponsor = Sponsor.new member = Member.new sponsor.sponsorable = member assert_equal "Member", sponsor.sponsorable_type end - + + def test_polymorphic_assignment_with_primary_key_foreign_type_field_updating + # should update when assigning a saved record + essay = Essay.new + writer = Author.create(:name => "David") + essay.writer = writer + assert_equal "Author", essay.writer_type + + # should update when assigning a new record + essay = Essay.new + writer = Author.new + essay.writer = writer + assert_equal "Author", essay.writer_type + end + def test_polymorphic_assignment_updates_foreign_id_field_for_new_and_saved_records sponsor = Sponsor.new saved_member = Member.create new_member = Member.new - + sponsor.sponsorable = saved_member assert_equal saved_member.id, sponsor.sponsorable_id - + sponsor.sponsorable = new_member assert_equal nil, sponsor.sponsorable_id end + def test_polymorphic_assignment_with_primary_key_updates_foreign_id_field_for_new_and_saved_records + essay = Essay.new + saved_writer = Author.create(:name => "David") + new_writer = Author.new + + essay.writer = saved_writer + assert_equal saved_writer.name, essay.writer_id + + essay.writer = new_writer + assert_equal nil, essay.writer_id + end + def test_belongs_to_proxy_should_not_respond_to_private_methods assert_raise(NoMethodError) { companies(:first_firm).private_method } assert_raise(NoMethodError) { companies(:second_client).firm.private_method } diff --git a/vendor/rails/activerecord/test/cases/associations/eager_test.rb b/vendor/rails/activerecord/test/cases/associations/eager_test.rb index 40723814..d23f86b7 100644 --- a/vendor/rails/activerecord/test/cases/associations/eager_test.rb +++ b/vendor/rails/activerecord/test/cases/associations/eager_test.rb @@ -223,6 +223,18 @@ class EagerAssociationTest < ActiveRecord::TestCase end end + def test_eager_association_loading_with_belongs_to_and_conditions_hash + comments = [] + assert_nothing_raised do + comments = Comment.find(:all, :include => :post, :conditions => {:posts => {:id => 4}}, :limit => 3, :order => 'comments.id') + end + assert_equal 3, comments.length + assert_equal [5,6,7], comments.collect { |c| c.id } + assert_no_queries do + comments.first.post + end + end + def test_eager_association_loading_with_belongs_to_and_conditions_string_with_quoted_table_name quoted_posts_id= Comment.connection.quote_table_name('posts') + '.' + Comment.connection.quote_column_name('id') assert_nothing_raised do diff --git a/vendor/rails/activerecord/test/cases/associations/has_many_associations_test.rb b/vendor/rails/activerecord/test/cases/associations/has_many_associations_test.rb index 30edf79a..5df74fcd 100644 --- a/vendor/rails/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/vendor/rails/activerecord/test/cases/associations/has_many_associations_test.rb @@ -719,6 +719,12 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert Client.find(:all, :conditions => "firm_id=#{firm.id}").empty? end + def test_dependence_for_associations_with_hash_condition + david = authors(:david) + post = posts(:thinking).id + assert_difference('Post.count', -1) { assert david.destroy } + end + def test_destroy_dependent_when_deleted_from_association firm = Firm.find(:first) assert_equal 2, firm.clients.size diff --git a/vendor/rails/activerecord/test/cases/associations/has_one_through_associations_test.rb b/vendor/rails/activerecord/test/cases/associations/has_one_through_associations_test.rb index 12c59875..ab6e6d20 100644 --- a/vendor/rails/activerecord/test/cases/associations/has_one_through_associations_test.rb +++ b/vendor/rails/activerecord/test/cases/associations/has_one_through_associations_test.rb @@ -43,7 +43,14 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase @member.reload end end - + + def test_set_record_to_nil_should_delete_association + @member.club = nil + @member.reload + assert_equal nil, @member.current_membership + assert_nil @member.club + end + def test_has_one_through_polymorphic assert_equal clubs(:moustache_club), @member.sponsor_club end diff --git a/vendor/rails/activerecord/test/cases/associations/inner_join_association_test.rb b/vendor/rails/activerecord/test/cases/associations/inner_join_association_test.rb index f87c9141..71415317 100644 --- a/vendor/rails/activerecord/test/cases/associations/inner_join_association_test.rb +++ b/vendor/rails/activerecord/test/cases/associations/inner_join_association_test.rb @@ -29,6 +29,11 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase assert_match /INNER JOIN .?categories.? ON.*AND.*.?General.?.*TERMINATING_MARKER/, sql end + def test_construct_finder_sql_applies_aliases_tables_on_association_conditions + result = Author.find(:all, :joins => [:thinking_posts, :welcome_posts]) + assert_equal authors(:david), result.first + end + def test_construct_finder_sql_unpacks_nested_joins sql = Author.send(:construct_finder_sql, :joins => {:posts => [[:comments]]}) assert_no_match /inner join.*inner join.*inner join/i, sql, "only two join clauses should be present" diff --git a/vendor/rails/activerecord/test/cases/autosave_association_test.rb b/vendor/rails/activerecord/test/cases/autosave_association_test.rb index 436f50d3..919b6f85 100644 --- a/vendor/rails/activerecord/test/cases/autosave_association_test.rb +++ b/vendor/rails/activerecord/test/cases/autosave_association_test.rb @@ -38,6 +38,17 @@ class TestAutosaveAssociationsInGeneral < ActiveRecord::TestCase end class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase + def test_should_save_parent_but_not_invalid_child + firm = Firm.new(:name => 'GlobalMegaCorp') + assert firm.valid? + + firm.build_account_using_primary_key + assert !firm.build_account_using_primary_key.valid? + + assert firm.save + assert firm.account_using_primary_key.new_record? + end + def test_save_fails_for_invalid_has_one firm = Firm.find(:first) assert firm.valid? @@ -126,6 +137,17 @@ class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCas end class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::TestCase + def test_should_save_parent_but_not_invalid_child + client = Client.new(:name => 'Joe (the Plumber)') + assert client.valid? + + client.build_firm + assert !client.firm.valid? + + assert client.save + assert client.firm.new_record? + end + def test_save_fails_for_invalid_belongs_to assert log = AuditLog.create(:developer_id => 0, :message => "") diff --git a/vendor/rails/activerecord/test/cases/base_test.rb b/vendor/rails/activerecord/test/cases/base_test.rb index 99d77961..604271e8 100755 --- a/vendor/rails/activerecord/test/cases/base_test.rb +++ b/vendor/rails/activerecord/test/cases/base_test.rb @@ -1756,7 +1756,7 @@ class BasicsTest < ActiveRecord::TestCase end def test_scoped_find_with_group_and_having - developers = Developer.with_scope(:find => { :group => 'salary', :having => "SUM(salary) > 10000", :select => "SUM(salary) as salary" }) do + developers = Developer.with_scope(:find => { :group => 'developers.salary', :having => "SUM(salary) > 10000", :select => "SUM(salary) as salary" }) do Developer.find(:all) end assert_equal 3, developers.size @@ -2014,7 +2014,7 @@ class BasicsTest < ActiveRecord::TestCase def test_inspect_instance topic = topics(:first) - assert_equal %(#), topic.inspect + assert_equal %(#), topic.inspect end def test_inspect_new_instance diff --git a/vendor/rails/activerecord/test/cases/calculations_test.rb b/vendor/rails/activerecord/test/cases/calculations_test.rb index 56dcdea1..b4f76cbc 100644 --- a/vendor/rails/activerecord/test/cases/calculations_test.rb +++ b/vendor/rails/activerecord/test/cases/calculations_test.rb @@ -2,6 +2,9 @@ require "cases/helper" require 'models/company' require 'models/topic' require 'models/edge' +require 'models/owner' +require 'models/pet' +require 'models/toy' Company.has_many :accounts @@ -10,7 +13,7 @@ class NumericData < ActiveRecord::Base end class CalculationsTest < ActiveRecord::TestCase - fixtures :companies, :accounts, :topics + fixtures :companies, :accounts, :topics, :owners, :pets, :toys def test_should_sum_field assert_equal 318, Account.sum(:credit_limit) @@ -264,19 +267,6 @@ class CalculationsTest < ActiveRecord::TestCase assert_equal 4, Account.count(:distinct => true, :include => :firm, :select => :credit_limit) end - def test_should_count_scoped_select - Account.update_all("credit_limit = NULL") - assert_equal 0, Account.scoped(:select => "credit_limit").count - end - - def test_should_count_scoped_select_with_options - Account.update_all("credit_limit = NULL") - Account.last.update_attribute('credit_limit', 49) - Account.first.update_attribute('credit_limit', 51) - - assert_equal 1, Account.scoped(:select => "credit_limit").count(:conditions => ['credit_limit >= 50']) - end - def test_should_count_manual_select_with_include assert_equal 6, Account.count(:select => "DISTINCT accounts.id", :include => :firm) end @@ -297,6 +287,10 @@ class CalculationsTest < ActiveRecord::TestCase assert_raise(ArgumentError) { Account.count(1, 2, 3) } end + def test_count_with_scoped_has_many_through_association + assert_equal 1, owners(:blackbeard).toys.with_name('Bone').count + end + def test_should_sum_expression assert_equal '636', Account.sum("2 * credit_limit") end diff --git a/vendor/rails/activerecord/test/cases/copy_table_test_sqlite.rb b/vendor/rails/activerecord/test/cases/copy_table_test_sqlite.rb index 72bd7e2d..de8af309 100644 --- a/vendor/rails/activerecord/test/cases/copy_table_test_sqlite.rb +++ b/vendor/rails/activerecord/test/cases/copy_table_test_sqlite.rb @@ -10,7 +10,7 @@ class CopyTableTest < ActiveRecord::TestCase end end - def test_copy_table(from = 'companies', to = 'companies2', options = {}) + def test_copy_table(from = 'customers', to = 'customers2', options = {}) assert_nothing_raised {copy_table(from, to, options)} assert_equal row_count(from), row_count(to) @@ -24,11 +24,11 @@ class CopyTableTest < ActiveRecord::TestCase end def test_copy_table_renaming_column - test_copy_table('companies', 'companies2', - :rename => {'client_of' => 'fan_of'}) do |from, to, options| - expected = column_values(from, 'client_of') + test_copy_table('customers', 'customers2', + :rename => {'name' => 'person_name'}) do |from, to, options| + expected = column_values(from, 'name') assert expected.any?, 'only nils in resultset; real values are needed' - assert_equal expected, column_values(to, 'fan_of') + assert_equal expected, column_values(to, 'person_name') end end diff --git a/vendor/rails/activerecord/test/cases/finder_test.rb b/vendor/rails/activerecord/test/cases/finder_test.rb index d8778957..25e339f5 100644 --- a/vendor/rails/activerecord/test/cases/finder_test.rb +++ b/vendor/rails/activerecord/test/cases/finder_test.rb @@ -119,6 +119,12 @@ class FinderTest < ActiveRecord::TestCase Address.new(existing_address.street + "1", existing_address.city, existing_address.country)) end + def test_exists_with_scoped_include + Developer.with_scope(:find => { :include => :projects, :order => "projects.name" }) do + assert Developer.exists? + end + end + def test_find_by_array_of_one_id assert_kind_of(Array, Topic.find([ 1 ])) assert_equal(1, Topic.find([ 1 ]).length) diff --git a/vendor/rails/activerecord/test/cases/fixtures_test.rb b/vendor/rails/activerecord/test/cases/fixtures_test.rb index 252bf4ff..b07d4f35 100644 --- a/vendor/rails/activerecord/test/cases/fixtures_test.rb +++ b/vendor/rails/activerecord/test/cases/fixtures_test.rb @@ -518,6 +518,11 @@ class FoxyFixturesTest < ActiveRecord::TestCase assert_equal(Fixtures.identify(:foo), Fixtures.identify(:foo)) end + def test_identifies_consistently + assert_equal 1281023246, Fixtures.identify(:ruby) + assert_equal 2140105598, Fixtures.identify(:sapphire_2) + end + TIMESTAMP_COLUMNS = %w(created_at created_on updated_at updated_on) def test_populates_timestamp_columns diff --git a/vendor/rails/activerecord/test/cases/helper.rb b/vendor/rails/activerecord/test/cases/helper.rb index 1ec52ac2..1ef38c99 100644 --- a/vendor/rails/activerecord/test/cases/helper.rb +++ b/vendor/rails/activerecord/test/cases/helper.rb @@ -5,8 +5,7 @@ require 'config' require 'rubygems' require 'test/unit' -gem 'mocha', '>= 0.9.5' -require 'mocha' +require 'stringio' require 'active_record' require 'active_record/test_case' diff --git a/vendor/rails/activerecord/test/cases/json_serialization_test.rb b/vendor/rails/activerecord/test/cases/json_serialization_test.rb index 975acde0..54bc8e23 100644 --- a/vendor/rails/activerecord/test/cases/json_serialization_test.rb +++ b/vendor/rails/activerecord/test/cases/json_serialization_test.rb @@ -26,19 +26,19 @@ class JsonSerializationTest < ActiveRecord::TestCase NamespacedContact.include_root_in_json = true @contact = NamespacedContact.new :name => 'whatever' json = @contact.to_json - assert_match %r{^\{"namespaced_contact": \{}, json + assert_match %r{^\{"namespaced_contact":\{}, json end def test_should_include_root_in_json Contact.include_root_in_json = true json = @contact.to_json - assert_match %r{^\{"contact": \{}, json - assert_match %r{"name": "Konata Izumi"}, json - assert_match %r{"age": 16}, json - assert json.include?(%("created_at": #{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) - assert_match %r{"awesome": true}, json - assert_match %r{"preferences": \{"shows": "anime"\}}, json + assert_match %r{^\{"contact":\{}, json + assert_match %r{"name":"Konata Izumi"}, json + assert_match %r{"age":16}, json + assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_match %r{"awesome":true}, json + assert_match %r{"preferences":\{"shows":"anime"\}}, json ensure Contact.include_root_in_json = false end @@ -46,31 +46,31 @@ class JsonSerializationTest < ActiveRecord::TestCase def test_should_encode_all_encodable_attributes json = @contact.to_json - assert_match %r{"name": "Konata Izumi"}, json - assert_match %r{"age": 16}, json - assert json.include?(%("created_at": #{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) - assert_match %r{"awesome": true}, json - assert_match %r{"preferences": \{"shows": "anime"\}}, json + assert_match %r{"name":"Konata Izumi"}, json + assert_match %r{"age":16}, json + assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_match %r{"awesome":true}, json + assert_match %r{"preferences":\{"shows":"anime"\}}, json end def test_should_allow_attribute_filtering_with_only json = @contact.to_json(:only => [:name, :age]) - assert_match %r{"name": "Konata Izumi"}, json - assert_match %r{"age": 16}, json - assert_no_match %r{"awesome": true}, json - assert !json.include?(%("created_at": #{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) - assert_no_match %r{"preferences": \{"shows": "anime"\}}, json + assert_match %r{"name":"Konata Izumi"}, json + assert_match %r{"age":16}, json + assert_no_match %r{"awesome":true}, json + assert !json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_no_match %r{"preferences":\{"shows":"anime"\}}, json end def test_should_allow_attribute_filtering_with_except json = @contact.to_json(:except => [:name, :age]) - assert_no_match %r{"name": "Konata Izumi"}, json - assert_no_match %r{"age": 16}, json - assert_match %r{"awesome": true}, json - assert json.include?(%("created_at": #{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) - assert_match %r{"preferences": \{"shows": "anime"\}}, json + assert_no_match %r{"name":"Konata Izumi"}, json + assert_no_match %r{"age":16}, json + assert_match %r{"awesome":true}, json + assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_match %r{"preferences":\{"shows":"anime"\}}, json end def test_methods_are_called_on_object @@ -79,12 +79,12 @@ class JsonSerializationTest < ActiveRecord::TestCase def @contact.favorite_quote; "Constraints are liberating"; end # Single method. - assert_match %r{"label": "Has cheezburger"}, @contact.to_json(:only => :name, :methods => :label) + assert_match %r{"label":"Has cheezburger"}, @contact.to_json(:only => :name, :methods => :label) # Both methods. methods_json = @contact.to_json(:only => :name, :methods => [:label, :favorite_quote]) - assert_match %r{"label": "Has cheezburger"}, methods_json - assert_match %r{"favorite_quote": "Constraints are liberating"}, methods_json + assert_match %r{"label":"Has cheezburger"}, methods_json + assert_match %r{"favorite_quote":"Constraints are liberating"}, methods_json end end @@ -99,42 +99,42 @@ class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase def test_includes_uses_association_name json = @david.to_json(:include => :posts) - assert_match %r{"posts": \[}, json + assert_match %r{"posts":\[}, json - assert_match %r{"id": 1}, json - assert_match %r{"name": "David"}, json + assert_match %r{"id":1}, json + assert_match %r{"name":"David"}, json - assert_match %r{"author_id": 1}, json - assert_match %r{"title": "Welcome to the weblog"}, json - assert_match %r{"body": "Such a lovely day"}, json + assert_match %r{"author_id":1}, json + assert_match %r{"title":"Welcome to the weblog"}, json + assert_match %r{"body":"Such a lovely day"}, json - assert_match %r{"title": "So I was thinking"}, json - assert_match %r{"body": "Like I hopefully always am"}, json + assert_match %r{"title":"So I was thinking"}, json + assert_match %r{"body":"Like I hopefully always am"}, json end def test_includes_uses_association_name_and_applies_attribute_filters json = @david.to_json(:include => { :posts => { :only => :title } }) - assert_match %r{"name": "David"}, json - assert_match %r{"posts": \[}, json + assert_match %r{"name":"David"}, json + assert_match %r{"posts":\[}, json - assert_match %r{"title": "Welcome to the weblog"}, json - assert_no_match %r{"body": "Such a lovely day"}, json + assert_match %r{"title":"Welcome to the weblog"}, json + assert_no_match %r{"body":"Such a lovely day"}, json - assert_match %r{"title": "So I was thinking"}, json - assert_no_match %r{"body": "Like I hopefully always am"}, json + assert_match %r{"title":"So I was thinking"}, json + assert_no_match %r{"body":"Like I hopefully always am"}, json end def test_includes_fetches_second_level_associations json = @david.to_json(:include => { :posts => { :include => { :comments => { :only => :body } } } }) - assert_match %r{"name": "David"}, json - assert_match %r{"posts": \[}, json + assert_match %r{"name":"David"}, json + assert_match %r{"posts":\[}, json - assert_match %r{"comments": \[}, json - assert_match %r{\{"body": "Thank you again for the welcome"\}}, json - assert_match %r{\{"body": "Don't think too hard"\}}, json - assert_no_match %r{"post_id": }, json + assert_match %r{"comments":\[}, json + assert_match %r{\{"body":"Thank you again for the welcome"\}}, json + assert_match %r{\{"body":"Don't think too hard"\}}, json + assert_no_match %r{"post_id":}, json end def test_includes_fetches_nth_level_associations @@ -151,11 +151,11 @@ class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase } }) - assert_match %r{"name": "David"}, json - assert_match %r{"posts": \[}, json + assert_match %r{"name":"David"}, json + assert_match %r{"posts":\[}, json - assert_match %r{"taggings": \[}, json - assert_match %r{"tag": \{"name": "General"\}}, json + assert_match %r{"taggings":\[}, json + assert_match %r{"tag":\{"name":"General"\}}, json end def test_should_not_call_methods_on_associations_that_dont_respond @@ -163,33 +163,33 @@ class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase json = @david.to_json(:include => :posts, :methods => :favorite_quote) assert !@david.posts.first.respond_to?(:favorite_quote) - assert_match %r{"favorite_quote": "Constraints are liberating"}, json - assert_equal %r{"favorite_quote": }.match(json).size, 1 + assert_match %r{"favorite_quote":"Constraints are liberating"}, json + assert_equal %r{"favorite_quote":}.match(json).size, 1 end def test_should_allow_only_option_for_list_of_authors authors = [@david, @mary] - assert_equal %([{"name": "David"}, {"name": "Mary"}]), authors.to_json(:only => :name) + assert_equal %([{"name":"David"},{"name":"Mary"}]), ActiveSupport::JSON.encode(authors, :only => :name) end def test_should_allow_except_option_for_list_of_authors authors = [@david, @mary] - assert_equal %([{"id": 1}, {"id": 2}]), authors.to_json(:except => [:name, :author_address_id, :author_address_extra_id]) + assert_equal %([{"id":1},{"id":2}]), ActiveSupport::JSON.encode(authors, :except => [:name, :author_address_id, :author_address_extra_id]) end def test_should_allow_includes_for_list_of_authors authors = [@david, @mary] - json = authors.to_json( + json = ActiveSupport::JSON.encode(authors, :only => :name, :include => { :posts => { :only => :id } } ) - ['"name": "David"', '"posts": [', '{"id": 1}', '{"id": 2}', '{"id": 4}', - '{"id": 5}', '{"id": 6}', '"name": "Mary"', '"posts": [{"id": 7}]'].each do |fragment| + ['"name":"David"', '"posts":[', '{"id":1}', '{"id":2}', '{"id":4}', + '{"id":5}', '{"id":6}', '"name":"Mary"', '"posts":[{"id":7}]'].each do |fragment| assert json.include?(fragment), json end end @@ -200,6 +200,6 @@ class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase 2 => @mary } - assert_equal %({"1": {"name": "David"}}), authors_hash.to_json(:only => [1, :name]) + assert_equal %({"1":{"name":"David"}}), ActiveSupport::JSON.encode(authors_hash, :only => [1, :name]) end end diff --git a/vendor/rails/activerecord/test/cases/method_scoping_test.rb b/vendor/rails/activerecord/test/cases/method_scoping_test.rb index 3c34cdea..2f660a3e 100644 --- a/vendor/rails/activerecord/test/cases/method_scoping_test.rb +++ b/vendor/rails/activerecord/test/cases/method_scoping_test.rb @@ -591,6 +591,16 @@ class DefaultScopingTest < ActiveRecord::TestCase assert_equal expected, received end + def test_default_scope_with_conditions_string + assert_equal Developer.find_all_by_name('David').map(&:id).sort, DeveloperCalledDavid.all.map(&:id).sort + assert_equal nil, DeveloperCalledDavid.create!.name + end + + def test_default_scope_with_conditions_hash + assert_equal Developer.find_all_by_name('Jamis').map(&:id).sort, DeveloperCalledJamis.all.map(&:id).sort + assert_equal 'Jamis', DeveloperCalledJamis.create!.name + end + def test_default_scoping_with_threads scope = [{ :create => {}, :find => { :order => 'salary DESC' } }] @@ -628,9 +638,9 @@ class DefaultScopingTest < ActiveRecord::TestCase assert_equal expected, received end - def test_named_scope - expected = Developer.find(:all, :order => 'salary DESC, name DESC').collect { |dev| dev.salary } - received = DeveloperOrderedBySalary.by_name.find(:all).collect { |dev| dev.salary } + def test_named_scope_overwrites_default + expected = Developer.find(:all, :order => 'name DESC').collect { |dev| dev.name } + received = DeveloperOrderedBySalary.by_name.find(:all).collect { |dev| dev.name } assert_equal expected, received end diff --git a/vendor/rails/activerecord/test/cases/reflection_test.rb b/vendor/rails/activerecord/test/cases/reflection_test.rb index db64bbb8..30ec157d 100644 --- a/vendor/rails/activerecord/test/cases/reflection_test.rb +++ b/vendor/rails/activerecord/test/cases/reflection_test.rb @@ -21,25 +21,25 @@ class ReflectionTest < ActiveRecord::TestCase def test_read_attribute_names assert_equal( - %w( id title author_name author_email_address bonus_time written_on last_read content approved replies_count parent_id type ).sort, + %w( id title author_name author_email_address bonus_time written_on last_read content approved replies_count parent_id parent_title type ).sort, @first.attribute_names ) end def test_columns - assert_equal 12, Topic.columns.length + assert_equal 13, Topic.columns.length end def test_columns_are_returned_in_the_order_they_were_declared column_names = Topic.columns.map { |column| column.name } - assert_equal %w(id title author_name author_email_address written_on bonus_time last_read content approved replies_count parent_id type), column_names + assert_equal %w(id title author_name author_email_address written_on bonus_time last_read content approved replies_count parent_id parent_title type), column_names end def test_content_columns content_columns = Topic.content_columns content_column_names = content_columns.map {|column| column.name} - assert_equal 8, content_columns.length - assert_equal %w(title author_name author_email_address written_on bonus_time last_read content approved).sort, content_column_names.sort + assert_equal 9, content_columns.length + assert_equal %w(title author_name author_email_address written_on bonus_time last_read content approved parent_title).sort, content_column_names.sort end def test_column_string_type_and_limit diff --git a/vendor/rails/activerecord/test/cases/schema_dumper_test.rb b/vendor/rails/activerecord/test/cases/schema_dumper_test.rb index 17e4c755..972700df 100644 --- a/vendor/rails/activerecord/test/cases/schema_dumper_test.rb +++ b/vendor/rails/activerecord/test/cases/schema_dumper_test.rb @@ -22,6 +22,11 @@ class SchemaDumperTest < ActiveRecord::TestCase assert_no_match %r{create_table "sqlite_sequence"}, output end + def test_schema_dump_includes_camelcase_table_name + output = standard_dump + assert_match %r{create_table "CamelCase"}, output + end + def assert_line_up(lines, pattern, required = false) return assert(true) if lines.empty? matches = lines.map { |line| line.match(pattern) } @@ -147,19 +152,24 @@ class SchemaDumperTest < ActiveRecord::TestCase end end + def test_schema_dumps_index_columns_in_right_order + index_definition = standard_dump.split(/\n/).grep(/add_index.*companies/).first.strip + assert_equal 'add_index "companies", ["firm_id", "type", "rating", "ruby_type"], :name => "company_index"', index_definition + end + + def test_schema_dump_should_honor_nonstandard_primary_keys + output = standard_dump + match = output.match(%r{create_table "movies"(.*)do}) + assert_not_nil(match, "nonstandardpk table not found") + assert_match %r(:primary_key => "movieid"), match[1], "non-standard primary key not preserved" + end + if current_adapter?(:MysqlAdapter) def test_schema_dump_should_not_add_default_value_for_mysql_text_field output = standard_dump assert_match %r{t.text\s+"body",\s+:null => false$}, output end - def test_mysql_schema_dump_should_honor_nonstandard_primary_keys - output = standard_dump - match = output.match(%r{create_table "movies"(.*)do}) - assert_not_nil(match, "nonstandardpk table not found") - assert_match %r(:primary_key => "movieid"), match[1], "non-standard primary key not preserved" - end - def test_schema_dump_includes_length_for_mysql_blob_and_text_fields output = standard_dump assert_match %r{t.binary\s+"tiny_blob",\s+:limit => 255$}, output diff --git a/vendor/rails/activerecord/test/cases/schema_test_postgresql.rb b/vendor/rails/activerecord/test/cases/schema_test_postgresql.rb index 336a3876..a294848f 100644 --- a/vendor/rails/activerecord/test/cases/schema_test_postgresql.rb +++ b/vendor/rails/activerecord/test/cases/schema_test_postgresql.rb @@ -6,6 +6,7 @@ class SchemaTest < ActiveRecord::TestCase SCHEMA_NAME = 'test_schema' SCHEMA2_NAME = 'test_schema2' TABLE_NAME = 'things' + CAPITALIZED_TABLE_NAME = 'Things' INDEX_A_NAME = 'a_index_things_on_name' INDEX_B_NAME = 'b_index_things_on_different_columns_in_each_schema' INDEX_A_COLUMN = 'name' @@ -18,9 +19,27 @@ class SchemaTest < ActiveRecord::TestCase 'moment timestamp without time zone default now()' ] + class Thing1 < ActiveRecord::Base + set_table_name "test_schema.things" + end + + class Thing2 < ActiveRecord::Base + set_table_name "test_schema2.things" + end + + class Thing3 < ActiveRecord::Base + set_table_name 'test_schema."things.table"' + end + + class Thing4 < ActiveRecord::Base + set_table_name 'test_schema."Things"' + end + def setup @connection = ActiveRecord::Base.connection @connection.execute "CREATE SCHEMA #{SCHEMA_NAME} CREATE TABLE #{TABLE_NAME} (#{COLUMNS.join(',')})" + @connection.execute "CREATE TABLE #{SCHEMA_NAME}.\"#{TABLE_NAME}.table\" (#{COLUMNS.join(',')})" + @connection.execute "CREATE TABLE #{SCHEMA_NAME}.\"#{CAPITALIZED_TABLE_NAME}\" (#{COLUMNS.join(',')})" @connection.execute "CREATE SCHEMA #{SCHEMA2_NAME} CREATE TABLE #{TABLE_NAME} (#{COLUMNS.join(',')})" @connection.execute "CREATE INDEX #{INDEX_A_NAME} ON #{SCHEMA_NAME}.#{TABLE_NAME} USING btree (#{INDEX_A_COLUMN});" @connection.execute "CREATE INDEX #{INDEX_A_NAME} ON #{SCHEMA2_NAME}.#{TABLE_NAME} USING btree (#{INDEX_A_COLUMN});" @@ -39,6 +58,12 @@ class SchemaTest < ActiveRecord::TestCase end end + def test_with_schema_prefixed_capitalized_table_name + assert_nothing_raised do + assert_equal COLUMNS, columns("#{SCHEMA_NAME}.#{CAPITALIZED_TABLE_NAME}") + end + end + def test_with_schema_search_path assert_nothing_raised do with_schema_search_path(SCHEMA_NAME) do @@ -47,6 +72,47 @@ class SchemaTest < ActiveRecord::TestCase end end + + def test_proper_encoding_of_table_name + assert_equal '"table_name"', @connection.quote_table_name('table_name') + assert_equal '"table.name"', @connection.quote_table_name('"table.name"') + assert_equal '"schema_name"."table_name"', @connection.quote_table_name('schema_name.table_name') + assert_equal '"schema_name"."table.name"', @connection.quote_table_name('schema_name."table.name"') + assert_equal '"schema.name"."table_name"', @connection.quote_table_name('"schema.name".table_name') + assert_equal '"schema.name"."table.name"', @connection.quote_table_name('"schema.name"."table.name"') + end + + def test_classes_with_qualified_schema_name + assert_equal 0, Thing1.count + assert_equal 0, Thing2.count + assert_equal 0, Thing3.count + assert_equal 0, Thing4.count + + Thing1.create(:id => 1, :name => "thing1", :email => "thing1@localhost", :moment => Time.now) + assert_equal 1, Thing1.count + assert_equal 0, Thing2.count + assert_equal 0, Thing3.count + assert_equal 0, Thing4.count + + Thing2.create(:id => 1, :name => "thing1", :email => "thing1@localhost", :moment => Time.now) + assert_equal 1, Thing1.count + assert_equal 1, Thing2.count + assert_equal 0, Thing3.count + assert_equal 0, Thing4.count + + Thing3.create(:id => 1, :name => "thing1", :email => "thing1@localhost", :moment => Time.now) + assert_equal 1, Thing1.count + assert_equal 1, Thing2.count + assert_equal 1, Thing3.count + assert_equal 0, Thing4.count + + Thing4.create(:id => 1, :name => "thing1", :email => "thing1@localhost", :moment => Time.now) + assert_equal 1, Thing1.count + assert_equal 1, Thing2.count + assert_equal 1, Thing3.count + assert_equal 1, Thing4.count + end + def test_raise_on_unquoted_schema_name assert_raise(ActiveRecord::StatementInvalid) do with_schema_search_path '$user,public' @@ -69,6 +135,16 @@ class SchemaTest < ActiveRecord::TestCase do_dump_index_tests_for_schema(SCHEMA2_NAME, INDEX_A_COLUMN, INDEX_B_COLUMN_S2) end + def test_with_uppercase_index_name + ActiveRecord::Base.connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)" + assert_nothing_raised { ActiveRecord::Base.connection.remove_index :things, :name => "#{SCHEMA_NAME}.things_Index"} + + ActiveRecord::Base.connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)" + ActiveRecord::Base.connection.schema_search_path = SCHEMA_NAME + assert_nothing_raised { ActiveRecord::Base.connection.remove_index :things, :name => "things_Index"} + ActiveRecord::Base.connection.schema_search_path = "public" + end + private def columns(table_name) @connection.send(:column_definitions, table_name).map do |name, type, default| diff --git a/vendor/rails/activerecord/test/cases/timestamp_test.rb b/vendor/rails/activerecord/test/cases/timestamp_test.rb new file mode 100644 index 00000000..24b237a7 --- /dev/null +++ b/vendor/rails/activerecord/test/cases/timestamp_test.rb @@ -0,0 +1,75 @@ +require 'cases/helper' +require 'models/developer' +require 'models/owner' +require 'models/pet' + +class TimestampTest < ActiveRecord::TestCase + fixtures :developers, :owners, :pets + + def setup + @developer = Developer.first + @previously_updated_at = @developer.updated_at + end + + def test_saving_a_changed_record_updates_its_timestamp + @developer.name = "Jack Bauer" + @developer.save! + + assert @previously_updated_at != @developer.updated_at + end + + def test_saving_a_unchanged_record_doesnt_update_its_timestamp + @developer.save! + + assert @previously_updated_at == @developer.updated_at + end + + def test_touching_a_record_updates_its_timestamp + @developer.touch + + assert @previously_updated_at != @developer.updated_at + end + + def test_touching_a_different_attribute + previously_created_at = @developer.created_at + @developer.touch(:created_at) + + assert previously_created_at != @developer.created_at + end + + def test_saving_a_record_with_a_belongs_to_that_specifies_touching_the_parent_should_update_the_parent_updated_at + pet = Pet.first + owner = pet.owner + previously_owner_updated_at = owner.updated_at + + pet.name = "Fluffy the Third" + pet.save + + assert previously_owner_updated_at != pet.owner.updated_at + end + + def test_destroying_a_record_with_a_belongs_to_that_specifies_touching_the_parent_should_update_the_parent_updated_at + pet = Pet.first + owner = pet.owner + previously_owner_updated_at = owner.updated_at + + pet.destroy + + assert previously_owner_updated_at != pet.owner.updated_at + end + + def test_saving_a_record_with_a_belongs_to_that_specifies_touching_a_specific_attribute_the_parent_should_update_that_attribute + Pet.belongs_to :owner, :touch => :happy_at + + pet = Pet.first + owner = pet.owner + previously_owner_happy_at = owner.happy_at + + pet.name = "Fluffy the Third" + pet.save + + assert previously_owner_happy_at != pet.owner.happy_at + ensure + Pet.belongs_to :owner, :touch => true + end +end \ No newline at end of file diff --git a/vendor/rails/activerecord/test/models/author.rb b/vendor/rails/activerecord/test/models/author.rb index 4ffac4fe..b844c7cc 100644 --- a/vendor/rails/activerecord/test/models/author.rb +++ b/vendor/rails/activerecord/test/models/author.rb @@ -25,6 +25,8 @@ class Author < ActiveRecord::Base has_many :comments_with_order_and_conditions, :through => :posts, :source => :comments, :order => 'comments.body', :conditions => "comments.body like 'Thank%'" has_many :comments_with_include, :through => :posts, :source => :comments, :include => :post + has_many :thinking_posts, :class_name => 'Post', :conditions => { :title => 'So I was thinking' }, :dependent => :delete_all + has_many :welcome_posts, :class_name => 'Post', :conditions => { :title => 'Welcome to the weblog' } has_many :comments_desc, :through => :posts, :source => :comments, :order => 'comments.id DESC' has_many :limited_comments, :through => :posts, :source => :comments, :limit => 1 @@ -85,6 +87,8 @@ class Author < ActiveRecord::Base has_many :tags, :through => :posts # through has_many :through has_many :post_categories, :through => :posts, :source => :categories + has_one :essay, :primary_key => :name, :as => :writer + belongs_to :author_address, :dependent => :destroy belongs_to :author_address_extra, :dependent => :delete, :class_name => "AuthorAddress" diff --git a/vendor/rails/activerecord/test/models/company.rb b/vendor/rails/activerecord/test/models/company.rb index 02a775f9..2a65b034 100644 --- a/vendor/rails/activerecord/test/models/company.rb +++ b/vendor/rails/activerecord/test/models/company.rb @@ -78,19 +78,13 @@ class DependentFirm < Company has_many :companies, :foreign_key => 'client_of', :order => "id", :dependent => :nullify end -class ExclusivelyDependentFirm < Company - has_one :account, :foreign_key => "firm_id", :dependent => :delete - has_many :dependent_sanitized_conditional_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id", :dependent => :delete_all, :conditions => "name = 'BigShot Inc.'" - has_many :dependent_conditional_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id", :dependent => :delete_all, :conditions => ["name = ?", 'BigShot Inc.'] - has_many :dependent_hash_conditional_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id", :dependent => :delete_all, :conditions => {:name => 'BigShot Inc.'} -end - class Client < Company belongs_to :firm, :foreign_key => "client_of" belongs_to :firm_with_basic_id, :class_name => "Firm", :foreign_key => "firm_id" belongs_to :firm_with_select, :class_name => "Firm", :foreign_key => "firm_id", :select => "id" belongs_to :firm_with_other_name, :class_name => "Firm", :foreign_key => "client_of" belongs_to :firm_with_condition, :class_name => "Firm", :foreign_key => "client_of", :conditions => ["1 = ?", 1] + belongs_to :firm_with_primary_key, :class_name => "Firm", :primary_key => "name", :foreign_key => "firm_name" belongs_to :readonly_firm, :class_name => "Firm", :foreign_key => "firm_id", :readonly => true # Record destruction so we can test whether firm.clients.clear has @@ -125,6 +119,12 @@ class Client < Company end end +class ExclusivelyDependentFirm < Company + has_one :account, :foreign_key => "firm_id", :dependent => :delete + has_many :dependent_sanitized_conditional_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id", :dependent => :delete_all, :conditions => "name = 'BigShot Inc.'" + has_many :dependent_conditional_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id", :dependent => :delete_all, :conditions => ["name = ?", 'BigShot Inc.'] + has_many :dependent_hash_conditional_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id", :dependent => :delete_all, :conditions => {:name => 'BigShot Inc.'} +end class SpecialClient < Client end diff --git a/vendor/rails/activerecord/test/models/developer.rb b/vendor/rails/activerecord/test/models/developer.rb index 92039a4f..05897033 100644 --- a/vendor/rails/activerecord/test/models/developer.rb +++ b/vendor/rails/activerecord/test/models/developer.rb @@ -89,3 +89,13 @@ class DeveloperOrderedBySalary < ActiveRecord::Base end end end + +class DeveloperCalledDavid < ActiveRecord::Base + self.table_name = 'developers' + default_scope :conditions => "name = 'David'" +end + +class DeveloperCalledJamis < ActiveRecord::Base + self.table_name = 'developers' + default_scope :conditions => { :name => 'Jamis' } +end diff --git a/vendor/rails/activerecord/test/models/essay.rb b/vendor/rails/activerecord/test/models/essay.rb new file mode 100644 index 00000000..6c28f5e4 --- /dev/null +++ b/vendor/rails/activerecord/test/models/essay.rb @@ -0,0 +1,3 @@ +class Essay < ActiveRecord::Base + belongs_to :writer, :primary_key => :name, :polymorphic => true +end diff --git a/vendor/rails/activerecord/test/models/pet.rb b/vendor/rails/activerecord/test/models/pet.rb index dc1a3c5e..a8bf94dd 100644 --- a/vendor/rails/activerecord/test/models/pet.rb +++ b/vendor/rails/activerecord/test/models/pet.rb @@ -1,5 +1,5 @@ class Pet < ActiveRecord::Base set_primary_key :pet_id - belongs_to :owner + belongs_to :owner, :touch => true has_many :toys end diff --git a/vendor/rails/activerecord/test/models/project.rb b/vendor/rails/activerecord/test/models/project.rb index 550d4ae2..f25b2ddf 100644 --- a/vendor/rails/activerecord/test/models/project.rb +++ b/vendor/rails/activerecord/test/models/project.rb @@ -13,7 +13,7 @@ class Project < ActiveRecord::Base :after_add => Proc.new {|o, r| o.developers_log << "after_adding#{r.id || ''}"}, :before_remove => Proc.new {|o, r| o.developers_log << "before_removing#{r.id}"}, :after_remove => Proc.new {|o, r| o.developers_log << "after_removing#{r.id}"} - has_and_belongs_to_many :well_payed_salary_groups, :class_name => "Developer", :group => "salary", :having => "SUM(salary) > 10000", :select => "SUM(salary) as salary" + has_and_belongs_to_many :well_payed_salary_groups, :class_name => "Developer", :group => "developers.salary", :having => "SUM(salary) > 10000", :select => "SUM(salary) as salary" attr_accessor :developers_log diff --git a/vendor/rails/activerecord/test/models/reply.rb b/vendor/rails/activerecord/test/models/reply.rb index 1c990aca..4063785f 100644 --- a/vendor/rails/activerecord/test/models/reply.rb +++ b/vendor/rails/activerecord/test/models/reply.rb @@ -4,12 +4,13 @@ class Reply < Topic named_scope :base belongs_to :topic, :foreign_key => "parent_id", :counter_cache => true + belongs_to :topic_with_primary_key, :class_name => "Topic", :primary_key => "title", :foreign_key => "parent_title", :counter_cache => "replies_count" has_many :replies, :class_name => "SillyReply", :dependent => :destroy, :foreign_key => "parent_id" validate :errors_on_empty_content validate_on_create :title_is_wrong_create - attr_accessible :title, :author_name, :author_email_address, :written_on, :content, :last_read + attr_accessible :title, :author_name, :author_email_address, :written_on, :content, :last_read, :parent_title def validate errors.add("title", "Empty") unless attribute_present? "title" diff --git a/vendor/rails/activerecord/test/models/topic.rb b/vendor/rails/activerecord/test/models/topic.rb index 51012d22..201d96dc 100644 --- a/vendor/rails/activerecord/test/models/topic.rb +++ b/vendor/rails/activerecord/test/models/topic.rb @@ -39,6 +39,7 @@ class Topic < ActiveRecord::Base named_scope :by_rejected_ids, lambda {{ :conditions => { :id => all(:conditions => {:approved => false}).map(&:id) } }} has_many :replies, :dependent => :destroy, :foreign_key => "parent_id" + has_many :replies_with_primary_key, :class_name => "Reply", :dependent => :destroy, :primary_key => "title", :foreign_key => "parent_title" serialize :content before_create :default_written_on diff --git a/vendor/rails/activerecord/test/models/toy.rb b/vendor/rails/activerecord/test/models/toy.rb index 79a88db0..0e68ba57 100644 --- a/vendor/rails/activerecord/test/models/toy.rb +++ b/vendor/rails/activerecord/test/models/toy.rb @@ -1,4 +1,6 @@ class Toy < ActiveRecord::Base set_primary_key :toy_id belongs_to :pet + + named_scope :with_name, lambda { |name| {:conditions => {:name => name}} } end diff --git a/vendor/rails/activerecord/test/schema/schema.rb b/vendor/rails/activerecord/test/schema/schema.rb index ea848a29..d080140e 100644 --- a/vendor/rails/activerecord/test/schema/schema.rb +++ b/vendor/rails/activerecord/test/schema/schema.rb @@ -68,6 +68,10 @@ ActiveRecord::Schema.define do t.boolean :value end + create_table "CamelCase", :force => true do |t| + t.string :name + end + create_table :categories, :force => true do |t| t.string :name, :null => false t.string :type @@ -114,6 +118,8 @@ ActiveRecord::Schema.define do t.integer :rating, :default => 1 end + add_index :companies, [:firm_id, :type, :rating, :ruby_type], :name => "company_index" + create_table :computers, :force => true do |t| t.integer :developer, :null => false t.integer :extendedWarranty, :null => false @@ -155,6 +161,12 @@ ActiveRecord::Schema.define do t.integer :course_id, :null => false end + create_table :essays, :force => true do |t| + t.string :name + t.string :writer_id + t.string :writer_type + end + create_table :events, :force => true do |t| t.string :title, :limit => 5 end @@ -281,6 +293,8 @@ ActiveRecord::Schema.define do create_table :owners, :primary_key => :owner_id ,:force => true do |t| t.string :name + t.column :updated_at, :datetime + t.column :happy_at, :datetime end @@ -410,6 +424,7 @@ ActiveRecord::Schema.define do t.boolean :approved, :default => true t.integer :replies_count, :default => 0 t.integer :parent_id + t.string :parent_title t.string :type end diff --git a/vendor/rails/activeresource/CHANGELOG b/vendor/rails/activeresource/CHANGELOG index 65729348..11424163 100644 --- a/vendor/rails/activeresource/CHANGELOG +++ b/vendor/rails/activeresource/CHANGELOG @@ -1,3 +1,7 @@ +*2.3.3 (July 12, 2009)* + +* No changes, just a version bump. + *2.3.2 [Final] (March 15, 2009)* * Nothing new, just included in 2.3.2 diff --git a/vendor/rails/activeresource/Rakefile b/vendor/rails/activeresource/Rakefile index bf7bbb02..c6591ccd 100644 --- a/vendor/rails/activeresource/Rakefile +++ b/vendor/rails/activeresource/Rakefile @@ -4,7 +4,6 @@ require 'rake/testtask' require 'rake/rdoctask' require 'rake/packagetask' require 'rake/gempackagetask' -require 'rake/contrib/sshpublisher' require File.join(File.dirname(__FILE__), 'lib', 'active_resource', 'version') @@ -67,7 +66,7 @@ spec = Gem::Specification.new do |s| s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) } end - s.add_dependency('activesupport', '= 2.3.2' + PKG_BUILD) + s.add_dependency('activesupport', '= 2.3.3' + PKG_BUILD) s.require_path = 'lib' s.autorequire = 'active_resource' @@ -117,12 +116,14 @@ end desc "Publish the beta gem" task :pgem => [:package] do + require 'rake/contrib/sshpublisher' Rake::SshFilePublisher.new("gems.rubyonrails.org", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload `ssh gems.rubyonrails.org '/u/sites/gems/gemupdate.sh'` end desc "Publish the API documentation" task :pdoc => [:rdoc] do + require 'rake/contrib/sshpublisher' Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/ar", "doc").upload end diff --git a/vendor/rails/activeresource/lib/active_resource/base.rb b/vendor/rails/activeresource/lib/active_resource/base.rb index a8c0da31..4a4ee9f4 100644 --- a/vendor/rails/activeresource/lib/active_resource/base.rb +++ b/vendor/rails/activeresource/lib/active_resource/base.rb @@ -832,7 +832,7 @@ module ActiveResource !new? && self.class.exists?(to_param, :params => prefix_options) end - # A method to convert the the resource to an XML string. + # Converts the resource to an XML string representation. # # ==== Options # The +options+ parameter is handed off to the +to_xml+ method on each @@ -841,7 +841,14 @@ module ActiveResource # # * :indent - Set the indent level for the XML output (default is +2+). # * :dasherize - Boolean option to determine whether or not element names should - # replace underscores with dashes (default is false). + # replace underscores with dashes. Default is true. The default can be set to false + # by setting the module attribute ActiveSupport.dasherize_xml = false in an initializer. Because save + # uses this method, and there are no options on save, then you will have to set the default if you don't + # want underscores in element names to become dashes when the resource is saved. This is important when + # integrating with non-Rails applications. + # * :camelize - Boolean option to determine whether or not element names should be converted + # to camel case, e.g some_name to SomeName. Default is false. Like :dasherize you can + # change the default by setting the module attribute ActiveSupport.camelise_xml = true in an initializer. # * :skip_instruct - Toggle skipping the +instruct!+ call on the XML builder # that generates the XML declaration (default is false). # @@ -861,8 +868,7 @@ module ActiveResource attributes.to_xml({:root => self.class.element_name}.merge(options)) end - # Returns a JSON string representing the model. Some configuration is - # available through +options+. + # Coerces to a hash for JSON encoding. # # ==== Options # The +options+ are passed to the +to_json+ method on each @@ -886,8 +892,8 @@ module ActiveResource # # person.to_json(:except => ["first_name"]) # # => {"last_name": "Smith"} - def to_json(options={}) - attributes.to_json(options) + def as_json(options = nil) + attributes.as_json(options) end # Returns the serialized string representation of the resource in the configured diff --git a/vendor/rails/activeresource/lib/active_resource/formats/json_format.rb b/vendor/rails/activeresource/lib/active_resource/formats/json_format.rb index 1d88fc5f..127e8288 100644 --- a/vendor/rails/activeresource/lib/active_resource/formats/json_format.rb +++ b/vendor/rails/activeresource/lib/active_resource/formats/json_format.rb @@ -11,8 +11,8 @@ module ActiveResource "application/json" end - def encode(hash, options={}) - hash.to_json(options) + def encode(hash, options = nil) + ActiveSupport::JSON.encode(hash, options) end def decode(json) diff --git a/vendor/rails/activeresource/lib/active_resource/version.rb b/vendor/rails/activeresource/lib/active_resource/version.rb index 3df2555d..8c68de74 100644 --- a/vendor/rails/activeresource/lib/active_resource/version.rb +++ b/vendor/rails/activeresource/lib/active_resource/version.rb @@ -2,7 +2,7 @@ module ActiveResource module VERSION #:nodoc: MAJOR = 2 MINOR = 3 - TINY = 2 + TINY = 3 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/vendor/rails/activeresource/test/abstract_unit.rb b/vendor/rails/activeresource/test/abstract_unit.rb index 0f11ea48..07d201a7 100644 --- a/vendor/rails/activeresource/test/abstract_unit.rb +++ b/vendor/rails/activeresource/test/abstract_unit.rb @@ -1,8 +1,6 @@ require 'rubygems' require 'test/unit' - -gem 'mocha', '>= 0.9.5' -require 'mocha' +require 'active_support/test_case' $:.unshift "#{File.dirname(__FILE__)}/../lib" $:.unshift "#{File.dirname(__FILE__)}/../../activesupport/lib" diff --git a/vendor/rails/activesupport/CHANGELOG b/vendor/rails/activesupport/CHANGELOG index ab40e1a1..cb57790d 100644 --- a/vendor/rails/activesupport/CHANGELOG +++ b/vendor/rails/activesupport/CHANGELOG @@ -1,3 +1,10 @@ +*2.3.3 (July 12, 2009)* + +* JSON: +Object#to_json+ calls +as_json+ to coerce itself into something natively encodable like +Hash+, +Integer+, or +String+. Override +as_json+ instead of +to_json+ so you're JSON-library-agnostic. [Jeremy Kemper] + +* Allow MemCacheStore to be initialized with a MemCache-like object instead of addresses and options [Bryan Helmkamp] + + *2.3.2 [Final] (March 15, 2009)* * XmlMini supports LibXML and Nokogiri backends. #2084, #2190 [Bart ten Brinke, Aaron Patterson] diff --git a/vendor/rails/activesupport/lib/active_support/cache.rb b/vendor/rails/activesupport/lib/active_support/cache.rb index 83174d3a..3f311852 100644 --- a/vendor/rails/activesupport/lib/active_support/cache.rb +++ b/vendor/rails/activesupport/lib/active_support/cache.rb @@ -91,11 +91,16 @@ module ActiveSupport class Store cattr_accessor :logger + attr_reader :silence, :logger_off + def silence! @silence = true self end + alias silence? silence + alias logger_off? logger_off + # Fetches data from the cache, using the given key. If there is data in # the cache with the given key, then that data is returned. # @@ -220,8 +225,16 @@ module ActiveSupport end private + def expires_in(options) + expires_in = options && options[:expires_in] + + raise ":expires_in must be a number" if expires_in && !expires_in.is_a?(Numeric) + + expires_in || 0 + end + def log(operation, key, options) - logger.debug("Cache #{operation}: #{key}#{options ? " (#{options.inspect})" : ""}") if logger && !@silence && !@logger_off + logger.debug("Cache #{operation}: #{key}#{options ? " (#{options.inspect})" : ""}") if logger && !silence? && !logger_off? end end end diff --git a/vendor/rails/activesupport/lib/active_support/cache/mem_cache_store.rb b/vendor/rails/activesupport/lib/active_support/cache/mem_cache_store.rb index 4d8e1fdd..954d0f54 100644 --- a/vendor/rails/activesupport/lib/active_support/cache/mem_cache_store.rb +++ b/vendor/rails/activesupport/lib/active_support/cache/mem_cache_store.rb @@ -23,7 +23,12 @@ module ActiveSupport DELETED = "DELETED\r\n" end - attr_reader :addresses + def self.build_mem_cache(*addresses) + addresses = addresses.flatten + options = addresses.extract_options! + addresses = ["localhost"] if addresses.empty? + MemCache.new(addresses, options) + end # Creates a new MemCacheStore object, with the given memcached server # addresses. Each address is either a host name, or a host-with-port string @@ -34,15 +39,20 @@ module ActiveSupport # If no addresses are specified, then MemCacheStore will connect to # localhost port 11211 (the default memcached port). def initialize(*addresses) - addresses = addresses.flatten - options = addresses.extract_options! - addresses = ["localhost"] if addresses.empty? - @addresses = addresses - @data = MemCache.new(addresses, options) + if addresses.first.respond_to?(:get) + @data = addresses.first + else + @data = self.class.build_mem_cache(*addresses) + end extend Strategy::LocalCache end + # Reads multiple keys from the cache. + def read_multi(*keys) + @data.get_multi keys + end + def read(key, options = nil) # :nodoc: super @data.get(key, raw?(options)) @@ -120,10 +130,6 @@ module ActiveSupport end private - def expires_in(options) - (options && options[:expires_in]) || 0 - end - def raw?(options) options && options[:raw] end diff --git a/vendor/rails/activesupport/lib/active_support/cache/strategy/local_cache.rb b/vendor/rails/activesupport/lib/active_support/cache/strategy/local_cache.rb index d83e259a..ea59375c 100644 --- a/vendor/rails/activesupport/lib/active_support/cache/strategy/local_cache.rb +++ b/vendor/rails/activesupport/lib/active_support/cache/strategy/local_cache.rb @@ -38,7 +38,7 @@ module ActiveSupport elsif value.nil? value = super local_cache.write(key, value || NULL) if local_cache - value + value.duplicable? ? value.dup : value else # forcing the value to be immutable value.duplicable? ? value.dup : value diff --git a/vendor/rails/activesupport/lib/active_support/core_ext/hash/conversions.rb b/vendor/rails/activesupport/lib/active_support/core_ext/hash/conversions.rb index 10435975..5ae43c0c 100644 --- a/vendor/rails/activesupport/lib/active_support/core_ext/hash/conversions.rb +++ b/vendor/rails/activesupport/lib/active_support/core_ext/hash/conversions.rb @@ -1,6 +1,14 @@ require 'date' +require 'active_support/core_ext/module/attribute_accessors' module ActiveSupport #:nodoc: + # these accessors are here because people using ActiveResource and REST to integrate with other systems + # have to be able to control the default behavior of rename_key. dasherize_xml is set to true to emulate + # existing behavior. In a future version it should be set to false by default. + mattr_accessor :dasherize_xml + mattr_accessor :camelize_xml + self.dasherize_xml = true + self.camelize_xml = false module CoreExtensions #:nodoc: module Hash #:nodoc: module Conversions @@ -143,10 +151,11 @@ module ActiveSupport #:nodoc: end def rename_key(key, options = {}) - camelize = options.has_key?(:camelize) && options[:camelize] - dasherize = !options.has_key?(:dasherize) || options[:dasherize] + camelize = options.has_key?(:camelize) ? options[:camelize] : ActiveSupport.camelize_xml + dasherize = options.has_key?(:dasherize) ? options[:dasherize] : ActiveSupport.dasherize_xml key = key.camelize if camelize - dasherize ? key.dasherize : key + key = key.dasherize if dasherize + key end module ClassMethods @@ -221,7 +230,7 @@ module ActiveSupport #:nodoc: case params.class.to_s when "Hash" params.inject({}) do |h,(k,v)| - h[k.to_s.underscore.tr("-", "_")] = unrename_keys(v) + h[k.to_s.tr("-", "_")] = unrename_keys(v) h end when "Array" diff --git a/vendor/rails/activesupport/lib/active_support/core_ext/kernel/debugger.rb b/vendor/rails/activesupport/lib/active_support/core_ext/kernel/debugger.rb index 4007a647..0813a513 100644 --- a/vendor/rails/activesupport/lib/active_support/core_ext/kernel/debugger.rb +++ b/vendor/rails/activesupport/lib/active_support/core_ext/kernel/debugger.rb @@ -2,12 +2,14 @@ module Kernel unless respond_to?(:debugger) # Starts a debugging session if ruby-debug has been loaded (call script/server --debugger to do load it). def debugger - Rails.logger.info "\n***** Debugger requested, but was not available: Start server with --debugger to enable *****\n" + message = "\n***** Debugger requested, but was not available: Start server with --debugger to enable *****\n" + defined?(Rails) ? Rails.logger.info(message) : $stderr.puts(message) end end def breakpoint - Rails.logger.info "\n***** The 'breakpoint' command has been renamed 'debugger' -- please change *****\n" + message = "\n***** The 'breakpoint' command has been renamed 'debugger' -- please change *****\n" + defined?(Rails) ? Rails.logger.info(message) : $stderr.puts(message) debugger end end diff --git a/vendor/rails/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb b/vendor/rails/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb index 9402cb85..9359b22b 100644 --- a/vendor/rails/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb +++ b/vendor/rails/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb @@ -1,3 +1,5 @@ +require "active_support/core_ext/array" + # Extends the module object with module and instance accessors for class attributes, # just like the native attr* accessors for instance attributes. # diff --git a/vendor/rails/activesupport/lib/active_support/core_ext/module/delegation.rb b/vendor/rails/activesupport/lib/active_support/core_ext/module/delegation.rb index fb4b5f0f..9377bff2 100644 --- a/vendor/rails/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/vendor/rails/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -108,12 +108,21 @@ class Module prefix = options[:prefix] && "#{options[:prefix] == true ? to : options[:prefix]}_" - allow_nil = options[:allow_nil] && "#{to} && " + file, line = caller.first.split(':', 2) + line = line.to_i methods.each do |method| - module_eval(<<-EOS, "(__DELEGATION__)", 1) + on_nil = + if options[:allow_nil] + 'return' + else + %(raise "#{prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}") + end + + module_eval(<<-EOS, file, line) def #{prefix}#{method}(*args, &block) # def customer_name(*args, &block) - #{allow_nil}#{to}.__send__(#{method.inspect}, *args, &block) # client && client.__send__(:name, *args, &block) + #{on_nil} if #{to}.nil? + #{to}.__send__(#{method.inspect}, *args, &block) # client && client.__send__(:name, *args, &block) end # end EOS end diff --git a/vendor/rails/activesupport/lib/active_support/core_ext/module/model_naming.rb b/vendor/rails/activesupport/lib/active_support/core_ext/module/model_naming.rb index 3ec4f3ba..9686be01 100644 --- a/vendor/rails/activesupport/lib/active_support/core_ext/module/model_naming.rb +++ b/vendor/rails/activesupport/lib/active_support/core_ext/module/model_naming.rb @@ -1,13 +1,15 @@ module ActiveSupport class ModelName < String - attr_reader :singular, :plural, :cache_key, :partial_path + attr_reader :singular, :plural, :element, :collection, :partial_path + alias_method :cache_key, :collection def initialize(name) super - @singular = underscore.tr('/', '_').freeze - @plural = @singular.pluralize.freeze - @cache_key = tableize.freeze - @partial_path = "#{@cache_key}/#{demodulize.underscore}".freeze + @singular = ActiveSupport::Inflector.underscore(self).tr('/', '_').freeze + @plural = ActiveSupport::Inflector.pluralize(@singular).freeze + @element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self)).freeze + @collection = ActiveSupport::Inflector.tableize(self).freeze + @partial_path = "#{@collection}/#{@element}".freeze end end @@ -16,7 +18,7 @@ module ActiveSupport # Returns an ActiveSupport::ModelName object for module. It can be # used to retrieve all kinds of naming-related information. def model_name - @model_name ||= ModelName.new(name) + @model_name ||= ::ActiveSupport::ModelName.new(name) end end end diff --git a/vendor/rails/activesupport/lib/active_support/core_ext/numeric/bytes.rb b/vendor/rails/activesupport/lib/active_support/core_ext/numeric/bytes.rb index 56477673..d3ff615e 100644 --- a/vendor/rails/activesupport/lib/active_support/core_ext/numeric/bytes.rb +++ b/vendor/rails/activesupport/lib/active_support/core_ext/numeric/bytes.rb @@ -3,41 +3,47 @@ module ActiveSupport #:nodoc: module Numeric #:nodoc: # Enables the use of byte calculations and declarations, like 45.bytes + 2.6.megabytes module Bytes + KILOBYTE = 1024 + MEGABYTE = KILOBYTE * 1024 + GIGABYTE = MEGABYTE * 1024 + TERABYTE = GIGABYTE * 1024 + PETABYTE = TERABYTE * 1024 + EXABYTE = PETABYTE * 1024 + def bytes self end alias :byte :bytes def kilobytes - self * 1024 + self * KILOBYTE end alias :kilobyte :kilobytes def megabytes - self * 1024.kilobytes + self * MEGABYTE end alias :megabyte :megabytes def gigabytes - self * 1024.megabytes + self * GIGABYTE end alias :gigabyte :gigabytes def terabytes - self * 1024.gigabytes + self * TERABYTE end alias :terabyte :terabytes - + def petabytes - self * 1024.terabytes + self * PETABYTE end alias :petabyte :petabytes - + def exabytes - self * 1024.petabytes + self * EXABYTE end alias :exabyte :exabytes - end end end diff --git a/vendor/rails/activesupport/lib/active_support/core_ext/string/access.rb b/vendor/rails/activesupport/lib/active_support/core_ext/string/access.rb index 7fb21fa4..e806b321 100644 --- a/vendor/rails/activesupport/lib/active_support/core_ext/string/access.rb +++ b/vendor/rails/activesupport/lib/active_support/core_ext/string/access.rb @@ -41,9 +41,15 @@ module ActiveSupport #:nodoc: # "hello".first(2) # => "he" # "hello".first(10) # => "hello" def first(limit = 1) - mb_chars[0..(limit - 1)].to_s + if limit == 0 + '' + elsif limit >= size + self + else + mb_chars[0...limit].to_s + end end - + # Returns the last character of the string or the last +limit+ characters. # # Examples: @@ -51,7 +57,13 @@ module ActiveSupport #:nodoc: # "hello".last(2) # => "lo" # "hello".last(10) # => "hello" def last(limit = 1) - (mb_chars[(-limit)..-1] || self).to_s + if limit == 0 + '' + elsif limit >= size + self + else + mb_chars[(-limit)..-1].to_s + end end end else @@ -69,11 +81,23 @@ module ActiveSupport #:nodoc: end def first(limit = 1) - self[0..(limit - 1)] + if limit == 0 + '' + elsif limit >= size + self + else + to(limit - 1) + end end def last(limit = 1) - from(-limit) || self + if limit == 0 + '' + elsif limit >= size + self + else + from(-limit) + end end end end diff --git a/vendor/rails/activesupport/lib/active_support/duration.rb b/vendor/rails/activesupport/lib/active_support/duration.rb index f64661c5..aa6d1aa3 100644 --- a/vendor/rails/activesupport/lib/active_support/duration.rb +++ b/vendor/rails/activesupport/lib/active_support/duration.rb @@ -67,10 +67,12 @@ module ActiveSupport def inspect #:nodoc: consolidated = parts.inject(::Hash.new(0)) { |h,part| h[part.first] += part.last; h } - [:years, :months, :days, :minutes, :seconds].map do |length| + parts = [:years, :months, :days, :minutes, :seconds].map do |length| n = consolidated[length] "#{n} #{n == 1 ? length.to_s.singularize : length.to_s}" if n.nonzero? - end.compact.to_sentence(:locale => :en) + end.compact + parts = ["0 seconds"] if parts.empty? + parts.to_sentence(:locale => :en) end protected diff --git a/vendor/rails/activesupport/lib/active_support/json.rb b/vendor/rails/activesupport/lib/active_support/json.rb index 2bdb4a7b..3e1d9b1d 100644 --- a/vendor/rails/activesupport/lib/active_support/json.rb +++ b/vendor/rails/activesupport/lib/active_support/json.rb @@ -1,23 +1,2 @@ -module ActiveSupport - # If true, use ISO 8601 format for dates and times. Otherwise, fall back to the Active Support legacy format. - mattr_accessor :use_standard_json_time_format - - class << self - def escape_html_entities_in_json - @escape_html_entities_in_json - end - - def escape_html_entities_in_json=(value) - ActiveSupport::JSON::Encoding.escape_regex = \ - if value - /[\010\f\n\r\t"\\><&]/ - else - /[\010\f\n\r\t"\\]/ - end - @escape_html_entities_in_json = value - end - end -end - -require 'active_support/json/encoding' require 'active_support/json/decoding' +require 'active_support/json/encoding' diff --git a/vendor/rails/activesupport/lib/active_support/json/backends/jsongem.rb b/vendor/rails/activesupport/lib/active_support/json/backends/jsongem.rb new file mode 100644 index 00000000..a6da27d5 --- /dev/null +++ b/vendor/rails/activesupport/lib/active_support/json/backends/jsongem.rb @@ -0,0 +1,38 @@ +require 'json' unless defined?(JSON) + +module ActiveSupport + module JSON + ParseError = ::JSON::ParserError unless const_defined?(:ParseError) + + module Backends + module JSONGem + extend self + + # Converts a JSON string into a Ruby object. + def decode(json) + data = ::JSON.parse(json) + if ActiveSupport.parse_json_times + convert_dates_from(data) + else + data + end + end + + private + def convert_dates_from(data) + case data + when DATE_REGEX + DateTime.parse(data) + when Array + data.map! { |d| convert_dates_from(d) } + when Hash + data.each do |key, value| + data[key] = convert_dates_from(value) + end + else data + end + end + end + end + end +end \ No newline at end of file diff --git a/vendor/rails/activesupport/lib/active_support/json/backends/yaml.rb b/vendor/rails/activesupport/lib/active_support/json/backends/yaml.rb new file mode 100644 index 00000000..a2797ccd --- /dev/null +++ b/vendor/rails/activesupport/lib/active_support/json/backends/yaml.rb @@ -0,0 +1,85 @@ +require 'active_support/core_ext/string/starts_ends_with' + +module ActiveSupport + module JSON + unless const_defined?(:ParseError) + class ParseError < StandardError + end + end + + module Backends + module Yaml + extend self + + # Converts a JSON string into a Ruby object. + def decode(json) + YAML.load(convert_json_to_yaml(json)) + rescue ArgumentError => e + raise ParseError, "Invalid JSON string" + end + + protected + # Ensure that ":" and "," are always followed by a space + def convert_json_to_yaml(json) #:nodoc: + require 'strscan' unless defined? ::StringScanner + scanner, quoting, marks, pos, times = ::StringScanner.new(json), false, [], nil, [] + while scanner.scan_until(/(\\['"]|['":,\\]|\\.)/) + case char = scanner[1] + when '"', "'" + if !quoting + quoting = char + pos = scanner.pos + elsif quoting == char + if json[pos..scanner.pos-2] =~ DATE_REGEX + # found a date, track the exact positions of the quotes so we can remove them later. + # oh, and increment them for each current mark, each one is an extra padded space that bumps + # the position in the final YAML output + total_marks = marks.size + times << pos+total_marks << scanner.pos+total_marks + end + quoting = false + end + when ":","," + marks << scanner.pos - 1 unless quoting + end + end + + if marks.empty? + json.gsub(/\\([\\\/]|u[[:xdigit:]]{4})/) do + ustr = $1 + if ustr.start_with?('u') + [ustr[1..-1].to_i(16)].pack("U") + elsif ustr == '\\' + '\\\\' + else + ustr + end + end + else + left_pos = [-1].push(*marks) + right_pos = marks << scanner.pos + scanner.rest_size + output = [] + left_pos.each_with_index do |left, i| + scanner.pos = left.succ + output << scanner.peek(right_pos[i] - scanner.pos + 1).gsub(/\\([\\\/]|u[[:xdigit:]]{4})/) do + ustr = $1 + if ustr.start_with?('u') + [ustr[1..-1].to_i(16)].pack("U") + elsif ustr == '\\' + '\\\\' + else + ustr + end + end + end + output = output * " " + + times.each { |i| output[i-1] = ' ' } + output.gsub!(/\\\//, '/') + output + end + end + end + end + end +end \ No newline at end of file diff --git a/vendor/rails/activesupport/lib/active_support/json/decoding.rb b/vendor/rails/activesupport/lib/active_support/json/decoding.rb index 0e079341..b4e41777 100644 --- a/vendor/rails/activesupport/lib/active_support/json/decoding.rb +++ b/vendor/rails/activesupport/lib/active_support/json/decoding.rb @@ -1,82 +1,33 @@ -require 'yaml' -require 'strscan' +require 'active_support/core_ext/module/attribute_accessors' module ActiveSupport + # Look for and parse json strings that look like ISO 8601 times. + mattr_accessor :parse_json_times + module JSON - class ParseError < StandardError - end - class << self - # Converts a JSON string into a Ruby object. - def decode(json) - YAML.load(convert_json_to_yaml(json)) - rescue ArgumentError => e - raise ParseError, "Invalid JSON string" + delegate :decode, :to => :backend + + def backend + self.backend = "Yaml" unless defined?(@backend) + @backend end - - protected - # matches YAML-formatted dates - DATE_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[ \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?)?)$/ - # Ensure that ":" and "," are always followed by a space - def convert_json_to_yaml(json) #:nodoc: - scanner, quoting, marks, pos, times = StringScanner.new(json), false, [], nil, [] - while scanner.scan_until(/(\\['"]|['":,\\]|\\.)/) - case char = scanner[1] - when '"', "'" - if !quoting - quoting = char - pos = scanner.pos - elsif quoting == char - if json[pos..scanner.pos-2] =~ DATE_REGEX - # found a date, track the exact positions of the quotes so we can remove them later. - # oh, and increment them for each current mark, each one is an extra padded space that bumps - # the position in the final YAML output - total_marks = marks.size - times << pos+total_marks << scanner.pos+total_marks - end - quoting = false - end - when ":","," - marks << scanner.pos - 1 unless quoting - end - end - - if marks.empty? - json.gsub(/\\([\\\/]|u[[:xdigit:]]{4})/) do - ustr = $1 - if ustr.starts_with?('u') - [ustr[1..-1].to_i(16)].pack("U") - elsif ustr == '\\' - '\\\\' - else - ustr - end - end - else - left_pos = [-1].push(*marks) - right_pos = marks << scanner.pos + scanner.rest_size - output = [] - left_pos.each_with_index do |left, i| - scanner.pos = left.succ - output << scanner.peek(right_pos[i] - scanner.pos + 1).gsub(/\\([\\\/]|u[[:xdigit:]]{4})/) do - ustr = $1 - if ustr.starts_with?('u') - [ustr[1..-1].to_i(16)].pack("U") - elsif ustr == '\\' - '\\\\' - else - ustr - end - end - end - output = output * " " - - times.each { |i| output[i-1] = ' ' } - output.gsub!(/\\\//, '/') - output - end + def backend=(name) + if name.is_a?(Module) + @backend = name + else + require "active_support/json/backends/#{name.to_s.downcase}.rb" + @backend = ActiveSupport::JSON::Backends::const_get(name) end + end + + def with_backend(name) + old_backend, self.backend = backend, name + yield + ensure + self.backend = old_backend + end end end end diff --git a/vendor/rails/activesupport/lib/active_support/json/encoders/date.rb b/vendor/rails/activesupport/lib/active_support/json/encoders/date.rb index cc84de13..0df1b8ed 100644 --- a/vendor/rails/activesupport/lib/active_support/json/encoders/date.rb +++ b/vendor/rails/activesupport/lib/active_support/json/encoders/date.rb @@ -1,21 +1,22 @@ class Date - # Returns a JSON string representing the date. If ActiveSupport.use_standard_json_time_format is set to true, the - # ISO 8601 format is used. + # Coerces the date to a string for JSON encoding. + # + # ISO 8601 format is used if ActiveSupport::JSON::Encoding.use_standard_json_time_format is set. # # ==== Examples # - # # With ActiveSupport.use_standard_json_time_format = true + # # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = true # Date.new(2005,2,1).to_json # # => "2005-02-01" # - # # With ActiveSupport.use_standard_json_time_format = false + # # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = false # Date.new(2005,2,1).to_json # # => "2005/02/01" - def to_json(options = nil) - if ActiveSupport.use_standard_json_time_format - %("#{strftime("%Y-%m-%d")}") + def as_json(options = nil) + if ActiveSupport::JSON::Encoding.use_standard_json_time_format + strftime("%Y-%m-%d") else - %("#{strftime("%Y/%m/%d")}") + strftime("%Y/%m/%d") end end end diff --git a/vendor/rails/activesupport/lib/active_support/json/encoders/date_time.rb b/vendor/rails/activesupport/lib/active_support/json/encoders/date_time.rb index 6c858241..20c12a76 100644 --- a/vendor/rails/activesupport/lib/active_support/json/encoders/date_time.rb +++ b/vendor/rails/activesupport/lib/active_support/json/encoders/date_time.rb @@ -1,21 +1,22 @@ class DateTime - # Returns a JSON string representing the datetime. If ActiveSupport.use_standard_json_time_format is set to true, the - # ISO 8601 format is used. + # Coerces the datetime to a string for JSON encoding. + # + # ISO 8601 format is used if ActiveSupport::JSON::Encoding.use_standard_json_time_format is set. # # ==== Examples # - # # With ActiveSupport.use_standard_json_time_format = true + # # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = true # DateTime.civil(2005,2,1,15,15,10).to_json # # => "2005-02-01T15:15:10+00:00" # - # # With ActiveSupport.use_standard_json_time_format = false + # # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = false # DateTime.civil(2005,2,1,15,15,10).to_json # # => "2005/02/01 15:15:10 +0000" - def to_json(options = nil) - if ActiveSupport.use_standard_json_time_format - xmlschema.inspect + def as_json(options = nil) + if ActiveSupport::JSON::Encoding.use_standard_json_time_format + xmlschema else - strftime('"%Y/%m/%d %H:%M:%S %z"') + strftime('%Y/%m/%d %H:%M:%S %z') end end end diff --git a/vendor/rails/activesupport/lib/active_support/json/encoders/enumerable.rb b/vendor/rails/activesupport/lib/active_support/json/encoders/enumerable.rb index 881b1d62..65924e38 100644 --- a/vendor/rails/activesupport/lib/active_support/json/encoders/enumerable.rb +++ b/vendor/rails/activesupport/lib/active_support/json/encoders/enumerable.rb @@ -1,12 +1,17 @@ module Enumerable - # Returns a JSON string representing the enumerable. Any +options+ - # given will be passed on to its elements. For example: - # - # users = User.find(:all) - # # => users.to_json(:only => :name) - # - # will pass the :only => :name option to each user. - def to_json(options = {}) #:nodoc: - "[#{map { |value| ActiveSupport::JSON.encode(value, options) } * ', '}]" + # Coerces the enumerable to an array for JSON encoding. + def as_json(options = nil) #:nodoc: + to_a + end +end + +class Array + # Returns a JSON string representing the Array. +options+ are passed to each element. + def to_json(options = nil) #:nodoc: + "[#{map { |value| ActiveSupport::JSON.encode(value, options) } * ','}]" + end + + def as_json(options = nil) #:nodoc: + self end end diff --git a/vendor/rails/activesupport/lib/active_support/json/encoders/false_class.rb b/vendor/rails/activesupport/lib/active_support/json/encoders/false_class.rb index bf084433..c2bb1ee2 100644 --- a/vendor/rails/activesupport/lib/active_support/json/encoders/false_class.rb +++ b/vendor/rails/activesupport/lib/active_support/json/encoders/false_class.rb @@ -1,5 +1,7 @@ class FalseClass - def to_json(options = nil) #:nodoc: - 'false' + AS_JSON = ActiveSupport::JSON::Variable.new('false').freeze + + def as_json(options = nil) #:nodoc: + AS_JSON end end diff --git a/vendor/rails/activesupport/lib/active_support/json/encoders/hash.rb b/vendor/rails/activesupport/lib/active_support/json/encoders/hash.rb index e38b4f3e..cfe21e4a 100644 --- a/vendor/rails/activesupport/lib/active_support/json/encoders/hash.rb +++ b/vendor/rails/activesupport/lib/active_support/json/encoders/hash.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/array/wrapper' + class Hash # Returns a JSON string representing the hash. # @@ -28,19 +30,27 @@ class Hash # would pass the :include => :posts option to users, # allowing the posts association in the User model to be converted to JSON # as well. - def to_json(options = {}) #:nodoc: - hash_keys = self.keys - - if except = options[:except] - hash_keys = hash_keys - Array.wrap(except) - elsif only = options[:only] - hash_keys = hash_keys & Array.wrap(only) - end + def to_json(options = nil) #:nodoc: + hash = as_json(options) result = '{' - result << hash_keys.map do |key| - "#{ActiveSupport::JSON.encode(key.to_s)}: #{ActiveSupport::JSON.encode(self[key], options)}" - end * ', ' + result << hash.map do |key, value| + "#{ActiveSupport::JSON.encode(key.to_s)}:#{ActiveSupport::JSON.encode(value, options)}" + end * ',' result << '}' end + + def as_json(options = nil) #:nodoc: + if options + if attrs = options[:except] + except(*Array.wrap(attrs)) + elsif attrs = options[:only] + slice(*Array.wrap(attrs)) + else + self + end + else + self + end + end end diff --git a/vendor/rails/activesupport/lib/active_support/json/encoders/nil_class.rb b/vendor/rails/activesupport/lib/active_support/json/encoders/nil_class.rb index 4763471a..041c1a26 100644 --- a/vendor/rails/activesupport/lib/active_support/json/encoders/nil_class.rb +++ b/vendor/rails/activesupport/lib/active_support/json/encoders/nil_class.rb @@ -1,5 +1,7 @@ class NilClass - def to_json(options = nil) #:nodoc: - 'null' + AS_JSON = ActiveSupport::JSON::Variable.new('null').freeze + + def as_json(options = nil) #:nodoc: + AS_JSON end end diff --git a/vendor/rails/activesupport/lib/active_support/json/encoders/numeric.rb b/vendor/rails/activesupport/lib/active_support/json/encoders/numeric.rb index 38713fb3..6493bd67 100644 --- a/vendor/rails/activesupport/lib/active_support/json/encoders/numeric.rb +++ b/vendor/rails/activesupport/lib/active_support/json/encoders/numeric.rb @@ -2,4 +2,20 @@ class Numeric def to_json(options = nil) #:nodoc: to_s end + + def as_json(options = nil) #:nodoc: + self + end +end + +class Float + def to_json(options = nil) #:nodoc: + to_s + end +end + +class Integer + def to_json(options = nil) #:nodoc: + to_s + end end diff --git a/vendor/rails/activesupport/lib/active_support/json/encoders/object.rb b/vendor/rails/activesupport/lib/active_support/json/encoders/object.rb index ca215d49..09941005 100644 --- a/vendor/rails/activesupport/lib/active_support/json/encoders/object.rb +++ b/vendor/rails/activesupport/lib/active_support/json/encoders/object.rb @@ -1,6 +1,10 @@ class Object # Dumps object in JSON (JavaScript Object Notation). See www.json.org for more info. - def to_json(options = {}) - ActiveSupport::JSON.encode(instance_values, options) + def to_json(options = nil) + ActiveSupport::JSON.encode(as_json(options)) + end + + def as_json(options = nil) + instance_values end end diff --git a/vendor/rails/activesupport/lib/active_support/json/encoders/regexp.rb b/vendor/rails/activesupport/lib/active_support/json/encoders/regexp.rb index b6116b70..14fdbf24 100644 --- a/vendor/rails/activesupport/lib/active_support/json/encoders/regexp.rb +++ b/vendor/rails/activesupport/lib/active_support/json/encoders/regexp.rb @@ -2,4 +2,8 @@ class Regexp def to_json(options = nil) #:nodoc: inspect end + + def as_json(options = nil) #:nodoc: + self + end end diff --git a/vendor/rails/activesupport/lib/active_support/json/encoders/string.rb b/vendor/rails/activesupport/lib/active_support/json/encoders/string.rb index 5ef79795..697658ec 100644 --- a/vendor/rails/activesupport/lib/active_support/json/encoders/string.rb +++ b/vendor/rails/activesupport/lib/active_support/json/encoders/string.rb @@ -1,36 +1,9 @@ -module ActiveSupport - module JSON - module Encoding - mattr_accessor :escape_regex - - ESCAPED_CHARS = { - "\010" => '\b', - "\f" => '\f', - "\n" => '\n', - "\r" => '\r', - "\t" => '\t', - '"' => '\"', - '\\' => '\\\\', - '>' => '\u003E', - '<' => '\u003C', - '&' => '\u0026' - } - end - end -end - -ActiveSupport.escape_html_entities_in_json = true - class String def to_json(options = nil) #:nodoc: - json = '"' + gsub(ActiveSupport::JSON::Encoding.escape_regex) { |s| - ActiveSupport::JSON::Encoding::ESCAPED_CHARS[s] - } - json.force_encoding('ascii-8bit') if respond_to?(:force_encoding) - json.gsub(/([\xC0-\xDF][\x80-\xBF]| - [\xE0-\xEF][\x80-\xBF]{2}| - [\xF0-\xF7][\x80-\xBF]{3})+/nx) { |s| - s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/, '\\\\u\&') - } + '"' + ActiveSupport::JSON::Encoding.escape(self) + end + + def as_json(options = nil) #:nodoc: + self end end diff --git a/vendor/rails/activesupport/lib/active_support/json/encoders/symbol.rb b/vendor/rails/activesupport/lib/active_support/json/encoders/symbol.rb index 485112f9..f7dcd491 100644 --- a/vendor/rails/activesupport/lib/active_support/json/encoders/symbol.rb +++ b/vendor/rails/activesupport/lib/active_support/json/encoders/symbol.rb @@ -1,5 +1,5 @@ class Symbol - def to_json(options = {}) #:nodoc: - ActiveSupport::JSON.encode(to_s, options) + def as_json(options = nil) #:nodoc: + to_s end end diff --git a/vendor/rails/activesupport/lib/active_support/json/encoders/time.rb b/vendor/rails/activesupport/lib/active_support/json/encoders/time.rb index f45a0059..fa54e9e3 100644 --- a/vendor/rails/activesupport/lib/active_support/json/encoders/time.rb +++ b/vendor/rails/activesupport/lib/active_support/json/encoders/time.rb @@ -1,21 +1,22 @@ class Time - # Returns a JSON string representing the time. If ActiveSupport.use_standard_json_time_format is set to true, the - # ISO 8601 format is used. + # Coerces the time to a string for JSON encoding. + # + # ISO 8601 format is used if ActiveSupport::JSON::Encoding.use_standard_json_time_format is set. # # ==== Examples # - # # With ActiveSupport.use_standard_json_time_format = true + # # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = true # Time.utc(2005,2,1,15,15,10).to_json # # => "2005-02-01T15:15:10Z" # - # # With ActiveSupport.use_standard_json_time_format = false + # # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = false # Time.utc(2005,2,1,15,15,10).to_json # # => "2005/02/01 15:15:10 +0000" - def to_json(options = nil) - if ActiveSupport.use_standard_json_time_format - xmlschema.inspect + def as_json(options = nil) + if ActiveSupport::JSON::Encoding.use_standard_json_time_format + xmlschema else - %("#{strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)}") + %(#{strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)}) end end end diff --git a/vendor/rails/activesupport/lib/active_support/json/encoders/true_class.rb b/vendor/rails/activesupport/lib/active_support/json/encoders/true_class.rb index 037d812b..4b65dee3 100644 --- a/vendor/rails/activesupport/lib/active_support/json/encoders/true_class.rb +++ b/vendor/rails/activesupport/lib/active_support/json/encoders/true_class.rb @@ -1,5 +1,7 @@ class TrueClass - def to_json(options = nil) #:nodoc: - 'true' + AS_JSON = ActiveSupport::JSON::Variable.new('true').freeze + + def as_json(options = nil) #:nodoc: + AS_JSON end end diff --git a/vendor/rails/activesupport/lib/active_support/json/encoding.rb b/vendor/rails/activesupport/lib/active_support/json/encoding.rb index aaaa3cdf..ffd20500 100644 --- a/vendor/rails/activesupport/lib/active_support/json/encoding.rb +++ b/vendor/rails/activesupport/lib/active_support/json/encoding.rb @@ -1,20 +1,91 @@ +# encoding: utf-8 +require 'active_support/core_ext/module/delegation' +require 'active_support/deprecation' + module ActiveSupport + class << self + delegate :use_standard_json_time_format, :use_standard_json_time_format=, + :escape_html_entities_in_json, :escape_html_entities_in_json=, + :to => :'ActiveSupport::JSON::Encoding' + end + module JSON - class CircularReferenceError < StandardError + # matches YAML-formatted dates + DATE_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[ \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?))$/ + + class << self + delegate :encode, :to => :'ActiveSupport::JSON::Encoding' end - # Converts a Ruby object into a JSON string. - def self.encode(value, options = {}) - seen = (options[:seen] ||= []) - raise CircularReferenceError, 'object references itself' if seen.include?(value) - seen << value - value.send(:to_json, options) - ensure - seen.pop + module Encoding #:nodoc: + class CircularReferenceError < StandardError + end + + ESCAPED_CHARS = { + "\010" => '\b', + "\f" => '\f', + "\n" => '\n', + "\r" => '\r', + "\t" => '\t', + '"' => '\"', + '\\' => '\\\\', + '>' => '\u003E', + '<' => '\u003C', + '&' => '\u0026' } + + class << self + # If true, use ISO 8601 format for dates and times. Otherwise, fall back to the Active Support legacy format. + attr_accessor :use_standard_json_time_format + + attr_accessor :escape_regex + attr_reader :escape_html_entities_in_json + + def escape_html_entities_in_json=(value) + self.escape_regex = \ + if @escape_html_entities_in_json = value + /[\010\f\n\r\t"\\><&]/ + else + /[\010\f\n\r\t"\\]/ + end + end + + def escape(string) + string = string.dup.force_encoding(::Encoding::BINARY) if string.respond_to?(:force_encoding) + json = string. + gsub(escape_regex) { |s| ESCAPED_CHARS[s] }. + gsub(/([\xC0-\xDF][\x80-\xBF]| + [\xE0-\xEF][\x80-\xBF]{2}| + [\xF0-\xF7][\x80-\xBF]{3})+/nx) { |s| + s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/n, '\\\\u\&') + } + %("#{json}") + end + + # Converts a Ruby object into a JSON string. + def encode(value, options = nil) + options = {} unless Hash === options + seen = (options[:seen] ||= []) + raise CircularReferenceError, 'object references itself' if seen.include?(value) + seen << value + value.to_json(options) + ensure + seen.pop + end + end + + self.escape_html_entities_in_json = true end + + CircularReferenceError = Deprecation::DeprecatedConstantProxy.new('ActiveSupport::JSON::CircularReferenceError', Encoding::CircularReferenceError) end end +# Hack to load json gem first so we can overwrite its to_json. +begin + require 'json' +rescue LoadError +end + require 'active_support/json/variable' require 'active_support/json/encoders/date' require 'active_support/json/encoders/date_time' diff --git a/vendor/rails/activesupport/lib/active_support/ordered_hash.rb b/vendor/rails/activesupport/lib/active_support/ordered_hash.rb index fed8094a..4324e40c 100644 --- a/vendor/rails/activesupport/lib/active_support/ordered_hash.rb +++ b/vendor/rails/activesupport/lib/active_support/ordered_hash.rb @@ -10,6 +10,30 @@ module ActiveSupport @keys = [] end + def self.[](*args) + ordered_hash = new + + if (args.length == 1 && args.first.is_a?(Array)) + args.first.each do |key_value_pair| + next unless (key_value_pair.is_a?(Array)) + ordered_hash[key_value_pair[0]] = key_value_pair[1] + end + + return ordered_hash + end + + unless (args.size % 2 == 0) + raise ArgumentError.new("odd number of arguments for Hash") + end + + args.each_with_index do |val, ind| + next if (ind % 2 != 0) + ordered_hash[val] = args[ind + 1] + end + + ordered_hash + end + def initialize_copy(other) super # make a deep copy of keys @@ -57,6 +81,10 @@ module ActiveSupport self end + def to_a + @keys.map { |key| [ key, self[key] ] } + end + def each_key @keys.each { |key| yield key } end diff --git a/vendor/rails/activesupport/lib/active_support/test_case.rb b/vendor/rails/activesupport/lib/active_support/test_case.rb index f05d4098..62fe7f5f 100644 --- a/vendor/rails/activesupport/lib/active_support/test_case.rb +++ b/vendor/rails/activesupport/lib/active_support/test_case.rb @@ -1,5 +1,11 @@ +require 'test/unit/testcase' +require 'active_support/testing/setup_and_teardown' +require 'active_support/testing/assertions' +require 'active_support/testing/deprecation' +require 'active_support/testing/declarative' + begin - gem 'mocha', '>= 0.9.3' + gem 'mocha', ">= 0.9.7" require 'mocha' rescue LoadError # Fake Mocha::ExpectationError so we can rescue it in #run. Bleh. @@ -7,12 +13,6 @@ rescue LoadError Mocha.const_set :ExpectationError, Class.new(StandardError) end -require 'test/unit/testcase' -require 'active_support/testing/setup_and_teardown' -require 'active_support/testing/assertions' -require 'active_support/testing/deprecation' -require 'active_support/testing/declarative' - module ActiveSupport class TestCase < ::Test::Unit::TestCase if defined? MiniTest diff --git a/vendor/rails/activesupport/lib/active_support/testing/deprecation.rb b/vendor/rails/activesupport/lib/active_support/testing/deprecation.rb index e9220605..2271caf8 100644 --- a/vendor/rails/activesupport/lib/active_support/testing/deprecation.rb +++ b/vendor/rails/activesupport/lib/active_support/testing/deprecation.rb @@ -1,3 +1,5 @@ +require "active_support/core_ext/module" + module ActiveSupport module Testing module Deprecation #:nodoc: diff --git a/vendor/rails/activesupport/lib/active_support/time_with_zone.rb b/vendor/rails/activesupport/lib/active_support/time_with_zone.rb index 518ca774..2e5a2332 100644 --- a/vendor/rails/activesupport/lib/active_support/time_with_zone.rb +++ b/vendor/rails/activesupport/lib/active_support/time_with_zone.rb @@ -108,23 +108,24 @@ module ActiveSupport end alias_method :iso8601, :xmlschema - # Returns a JSON string representing the TimeWithZone. If ActiveSupport.use_standard_json_time_format is set to - # true, the ISO 8601 format is used. + # Coerces the date to a string for JSON encoding. + # + # ISO 8601 format is used if ActiveSupport::JSON::Encoding.use_standard_json_time_format is set. # # ==== Examples # - # # With ActiveSupport.use_standard_json_time_format = true + # # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = true # Time.utc(2005,2,1,15,15,10).in_time_zone.to_json # # => "2005-02-01T15:15:10Z" # - # # With ActiveSupport.use_standard_json_time_format = false + # # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = false # Time.utc(2005,2,1,15,15,10).in_time_zone.to_json # # => "2005/02/01 15:15:10 +0000" - def to_json(options = nil) - if ActiveSupport.use_standard_json_time_format - xmlschema.inspect + def as_json(options = nil) + if ActiveSupport::JSON::Encoding.use_standard_json_time_format + xmlschema else - %("#{time.strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)}") + %(#{time.strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)}) end end diff --git a/vendor/rails/activesupport/lib/active_support/vendor.rb b/vendor/rails/activesupport/lib/active_support/vendor.rb index 28852e65..5b51af0a 100644 --- a/vendor/rails/activesupport/lib/active_support/vendor.rb +++ b/vendor/rails/activesupport/lib/active_support/vendor.rb @@ -9,9 +9,9 @@ end require 'builder' begin - gem 'memcache-client', '>= 1.6.5' + gem 'memcache-client', '>= 1.7.4' rescue Gem::LoadError - $:.unshift "#{File.dirname(__FILE__)}/vendor/memcache-client-1.6.5" + $:.unshift "#{File.dirname(__FILE__)}/vendor/memcache-client-1.7.4" end begin @@ -20,10 +20,9 @@ rescue Gem::LoadError $:.unshift "#{File.dirname(__FILE__)}/vendor/tzinfo-0.3.12" end -# TODO I18n gem has not been released yet -# begin -# gem 'i18n', '~> 0.1.3' -# rescue Gem::LoadError +begin + gem 'i18n', '~> 0.1.3' +rescue Gem::LoadError $:.unshift "#{File.dirname(__FILE__)}/vendor/i18n-0.1.3/lib" require 'i18n' -# end +end diff --git a/vendor/rails/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_exceptions_test.rb b/vendor/rails/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_exceptions_test.rb index dfcba690..4e78e71b 100644 --- a/vendor/rails/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_exceptions_test.rb +++ b/vendor/rails/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_exceptions_test.rb @@ -2,7 +2,6 @@ $:.unshift "lib" require 'rubygems' require 'test/unit' -require 'mocha' require 'i18n' require 'active_support' diff --git a/vendor/rails/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_test.rb b/vendor/rails/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_test.rb index 50d6832c..2835ec4e 100644 --- a/vendor/rails/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_test.rb +++ b/vendor/rails/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_test.rb @@ -2,7 +2,6 @@ $:.unshift "lib" require 'rubygems' require 'test/unit' -require 'mocha' require 'i18n' require 'active_support' diff --git a/vendor/rails/activesupport/lib/active_support/vendor/i18n-0.1.3/test/simple_backend_test.rb b/vendor/rails/activesupport/lib/active_support/vendor/i18n-0.1.3/test/simple_backend_test.rb index 65f3ac11..a1696c77 100644 --- a/vendor/rails/activesupport/lib/active_support/vendor/i18n-0.1.3/test/simple_backend_test.rb +++ b/vendor/rails/activesupport/lib/active_support/vendor/i18n-0.1.3/test/simple_backend_test.rb @@ -3,7 +3,6 @@ $:.unshift "lib" require 'rubygems' require 'test/unit' -require 'mocha' require 'i18n' require 'time' require 'yaml' diff --git a/vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.6.5/memcache.rb b/vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb similarity index 73% rename from vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.6.5/memcache.rb rename to vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb index 4d594c20..f249da79 100644 --- a/vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.6.5/memcache.rb +++ b/vendor/rails/activesupport/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb @@ -2,9 +2,9 @@ $TESTING = defined?($TESTING) && $TESTING require 'socket' require 'thread' -require 'timeout' require 'zlib' require 'digest/sha1' +require 'net/protocol' ## # A Ruby client library for memcached. @@ -15,7 +15,7 @@ class MemCache ## # The version of MemCache you are using. - VERSION = '1.6.4.99' + VERSION = '1.7.4' ## # Default options for the cache object. @@ -27,6 +27,7 @@ class MemCache :failover => true, :timeout => 0.5, :logger => nil, + :no_reply => false, } ## @@ -71,6 +72,12 @@ class MemCache attr_reader :logger + ## + # Don't send or look for a reply from the memcached server for write operations. + # Please note this feature only works in memcached 1.2.5 and later. Earlier + # versions will reply with "ERROR". + attr_reader :no_reply + ## # Accepts a list of +servers+ and a list of +opts+. +servers+ may be # omitted. See +servers=+ for acceptable server list arguments. @@ -79,12 +86,17 @@ class MemCache # # [:namespace] Prepends this value to all keys added or retrieved. # [:readonly] Raises an exception on cache writes when true. - # [:multithread] Wraps cache access in a Mutex for thread safety. + # [:multithread] Wraps cache access in a Mutex for thread safety. Defaults to true. # [:failover] Should the client try to failover to another server if the # first server is down? Defaults to true. # [:timeout] Time to use as the socket read timeout. Defaults to 0.5 sec, - # set to nil to disable timeouts (this is a major performance penalty in Ruby 1.8). + # set to nil to disable timeouts (this is a major performance penalty in Ruby 1.8, + # "gem install SystemTimer' to remove most of the penalty). # [:logger] Logger to use for info/debug output, defaults to nil + # [:no_reply] Don't bother looking for a reply for write operations (i.e. they + # become 'fire and forget'), memcached 1.2.5 and later only, speeds up + # set/add/delete/incr/decr significantly. + # # Other options are ignored. def initialize(*args) @@ -114,6 +126,7 @@ class MemCache @timeout = opts[:timeout] @failover = opts[:failover] @logger = opts[:logger] + @no_reply = opts[:no_reply] @mutex = Mutex.new if @multithread logger.info { "memcache-client #{VERSION} #{Array(servers).inspect}" } if logger @@ -192,8 +205,8 @@ class MemCache def get(key, raw = false) with_server(key) do |server, cache_key| + logger.debug { "get #{key} from #{server.inspect}" } if logger value = cache_get server, cache_key - logger.debug { "GET #{key} from #{server.inspect}: #{value ? value.to_s.size : 'nil'}" } if logger return nil if value.nil? value = Marshal.load value unless raw return value @@ -202,6 +215,25 @@ class MemCache handle_error nil, err end + ## + # Performs a +get+ with the given +key+. If + # the value does not exist and a block was given, + # the block will be called and the result saved via +add+. + # + # If you do not provide a block, using this + # method is the same as using +get+. + # + def fetch(key, expiry = 0, raw = false) + value = get(key, raw) + + if value.nil? && block_given? + value = yield + add(key, value, expiry, raw) + end + + value + end + ## # Retrieves multiple values from memcached in parallel, if possible. # @@ -283,15 +315,60 @@ class MemCache with_server(key) do |server, cache_key| value = Marshal.dump value unless raw - logger.debug { "SET #{key} to #{server.inspect}: #{value ? value.to_s.size : 'nil'}" } if logger + logger.debug { "set #{key} to #{server.inspect}: #{value.to_s.size}" } if logger - data = value.to_s - raise MemCacheError, "Value too large, memcached can only store 1MB of data per key" if data.size > ONE_MB + raise MemCacheError, "Value too large, memcached can only store 1MB of data per key" if value.to_s.size > ONE_MB - command = "set #{cache_key} 0 #{expiry} #{data.size}\r\n#{data}\r\n" + command = "set #{cache_key} 0 #{expiry} #{value.to_s.size}#{noreply}\r\n#{value}\r\n" with_socket_management(server) do |socket| socket.write command + break nil if @no_reply + result = socket.gets + raise_on_error_response! result + + if result.nil? + server.close + raise MemCacheError, "lost connection to #{server.host}:#{server.port}" + end + + result + end + end + end + + ## + # "cas" is a check and set operation which means "store this data but + # only if no one else has updated since I last fetched it." This can + # be used as a form of optimistic locking. + # + # Works in block form like so: + # cache.cas('some-key') do |value| + # value + 1 + # end + # + # Returns: + # +nil+ if the value was not found on the memcached server. + # +STORED+ if the value was updated successfully + # +EXISTS+ if the value was updated by someone else since last fetch + + def cas(key, expiry=0, raw=false) + raise MemCacheError, "Update of readonly cache" if @readonly + raise MemCacheError, "A block is required" unless block_given? + + (value, token) = gets(key, raw) + return nil unless value + updated = yield value + + with_server(key) do |server, cache_key| + + value = Marshal.dump updated unless raw + logger.debug { "cas #{key} to #{server.inspect}: #{value.to_s.size}" } if logger + command = "cas #{cache_key} 0 #{expiry} #{value.to_s.size} #{token}#{noreply}\r\n#{value}\r\n" + + with_socket_management(server) do |socket| + socket.write command + break nil if @no_reply result = socket.gets raise_on_error_response! result @@ -311,17 +388,79 @@ class MemCache # If +raw+ is true, +value+ will not be Marshalled. # # Readers should call this method in the event of a cache miss, not - # MemCache#set or MemCache#[]=. + # MemCache#set. def add(key, value, expiry = 0, raw = false) raise MemCacheError, "Update of readonly cache" if @readonly with_server(key) do |server, cache_key| value = Marshal.dump value unless raw - logger.debug { "ADD #{key} to #{server}: #{value ? value.to_s.size : 'nil'}" } if logger - command = "add #{cache_key} 0 #{expiry} #{value.to_s.size}\r\n#{value}\r\n" + logger.debug { "add #{key} to #{server}: #{value ? value.to_s.size : 'nil'}" } if logger + command = "add #{cache_key} 0 #{expiry} #{value.to_s.size}#{noreply}\r\n#{value}\r\n" with_socket_management(server) do |socket| socket.write command + break nil if @no_reply + result = socket.gets + raise_on_error_response! result + result + end + end + end + + ## + # Add +key+ to the cache with value +value+ that expires in +expiry+ + # seconds, but only if +key+ already exists in the cache. + # If +raw+ is true, +value+ will not be Marshalled. + def replace(key, value, expiry = 0, raw = false) + raise MemCacheError, "Update of readonly cache" if @readonly + with_server(key) do |server, cache_key| + value = Marshal.dump value unless raw + logger.debug { "replace #{key} to #{server}: #{value ? value.to_s.size : 'nil'}" } if logger + command = "replace #{cache_key} 0 #{expiry} #{value.to_s.size}#{noreply}\r\n#{value}\r\n" + + with_socket_management(server) do |socket| + socket.write command + break nil if @no_reply + result = socket.gets + raise_on_error_response! result + result + end + end + end + + ## + # Append - 'add this data to an existing key after existing data' + # Please note the value is always passed to memcached as raw since it + # doesn't make a lot of sense to concatenate marshalled data together. + def append(key, value) + raise MemCacheError, "Update of readonly cache" if @readonly + with_server(key) do |server, cache_key| + logger.debug { "append #{key} to #{server}: #{value ? value.to_s.size : 'nil'}" } if logger + command = "append #{cache_key} 0 0 #{value.to_s.size}#{noreply}\r\n#{value}\r\n" + + with_socket_management(server) do |socket| + socket.write command + break nil if @no_reply + result = socket.gets + raise_on_error_response! result + result + end + end + end + + ## + # Prepend - 'add this data to an existing key before existing data' + # Please note the value is always passed to memcached as raw since it + # doesn't make a lot of sense to concatenate marshalled data together. + def prepend(key, value) + raise MemCacheError, "Update of readonly cache" if @readonly + with_server(key) do |server, cache_key| + logger.debug { "prepend #{key} to #{server}: #{value ? value.to_s.size : 'nil'}" } if logger + command = "prepend #{cache_key} 0 0 #{value.to_s.size}#{noreply}\r\n#{value}\r\n" + + with_socket_management(server) do |socket| + socket.write command + break nil if @no_reply result = socket.gets raise_on_error_response! result result @@ -336,7 +475,9 @@ class MemCache raise MemCacheError, "Update of readonly cache" if @readonly with_server(key) do |server, cache_key| with_socket_management(server) do |socket| - socket.write "delete #{cache_key} #{expiry}\r\n" + logger.debug { "delete #{cache_key} on #{server}" } if logger + socket.write "delete #{cache_key} #{expiry}#{noreply}\r\n" + break nil if @no_reply result = socket.gets raise_on_error_response! result result @@ -346,19 +487,33 @@ class MemCache ## # Flush the cache from all memcache servers. + # A non-zero value for +delay+ will ensure that the flush + # is propogated slowly through your memcached server farm. + # The Nth server will be flushed N*delay seconds from now, + # asynchronously so this method returns quickly. + # This prevents a huge database spike due to a total + # flush all at once. - def flush_all + def flush_all(delay=0) raise MemCacheError, 'No active servers' unless active? raise MemCacheError, "Update of readonly cache" if @readonly begin + delay_time = 0 @servers.each do |server| with_socket_management(server) do |socket| - socket.write "flush_all\r\n" + logger.debug { "flush_all #{delay_time} on #{server}" } if logger + if delay == 0 # older versions of memcached will fail silently otherwise + socket.write "flush_all#{noreply}\r\n" + else + socket.write "flush_all #{delay_time}#{noreply}\r\n" + end + break nil if @no_reply result = socket.gets raise_on_error_response! result result end + delay_time += delay end rescue IndexError => err handle_error nil, err @@ -500,7 +655,7 @@ class MemCache break unless failover hkey = hash_for "#{try}#{key}" end - + raise MemCacheError, "No servers available" end @@ -510,7 +665,8 @@ class MemCache def cache_decr(server, cache_key, amount) with_socket_management(server) do |socket| - socket.write "decr #{cache_key} #{amount}\r\n" + socket.write "decr #{cache_key} #{amount}#{noreply}\r\n" + break nil if @no_reply text = socket.gets raise_on_error_response! text return nil if text == "NOT_FOUND\r\n" @@ -546,6 +702,38 @@ class MemCache end end + def gets(key, raw = false) + with_server(key) do |server, cache_key| + logger.debug { "gets #{key} from #{server.inspect}" } if logger + result = with_socket_management(server) do |socket| + socket.write "gets #{cache_key}\r\n" + keyline = socket.gets # "VALUE \r\n" + + if keyline.nil? then + server.close + raise MemCacheError, "lost connection to #{server.host}:#{server.port}" + end + + raise_on_error_response! keyline + return nil if keyline == "END\r\n" + + unless keyline =~ /(\d+) (\w+)\r/ then + server.close + raise MemCacheError, "unexpected response #{keyline.inspect}" + end + value = socket.read $1.to_i + socket.read 2 # "\r\n" + socket.gets # "END\r\n" + [value, $2] + end + result[0] = Marshal.load result[0] unless raw + result + end + rescue TypeError => err + handle_error nil, err + end + + ## # Fetches +cache_keys+ from +server+ using a multi-get. @@ -579,7 +767,8 @@ class MemCache def cache_incr(server, cache_key, amount) with_socket_management(server) do |socket| - socket.write "incr #{cache_key} #{amount}\r\n" + socket.write "incr #{cache_key} #{amount}#{noreply}\r\n" + break nil if @no_reply text = socket.gets raise_on_error_response! text return nil if text == "NOT_FOUND\r\n" @@ -617,7 +806,7 @@ class MemCache block.call(socket) - rescue SocketError => err + rescue SocketError, Errno::EAGAIN, Timeout::Error => err logger.warn { "Socket failure: #{err.message}" } if logger server.mark_dead(err) handle_error(server, err) @@ -659,6 +848,10 @@ class MemCache raise new_error end + def noreply + @no_reply ? ' noreply' : '' + end + ## # Performs setup for making a request with +key+ from memcached. Returns # the server to fetch the key from and the complete key to use. @@ -712,13 +905,6 @@ class MemCache class Server - ## - # The amount of time to wait to establish a connection with a memcached - # server. If a connection cannot be established within this time limit, - # the server will be marked as down. - - CONNECT_TIMEOUT = 0.25 - ## # The amount of time to wait before attempting to re-establish a # connection with a server that is marked dead. @@ -802,14 +988,11 @@ class MemCache # Attempt to connect if not already connected. begin - @sock = @timeout ? TCPTimeoutSocket.new(@host, @port, @timeout) : TCPSocket.new(@host, @port) - - if Socket.constants.include? 'TCP_NODELAY' then - @sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 - end + @sock = connect_to(@host, @port, @timeout) + @sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 @retry = nil @status = 'CONNECTED' - rescue SocketError, SystemCallError, IOError, Timeout::Error => err + rescue SocketError, SystemCallError, IOError => err logger.warn { "Unable to open socket: #{err.class.name}, #{err.message}" } if logger mark_dead err end @@ -817,6 +1000,12 @@ class MemCache return @sock end + def connect_to(host, port, timeout=nil) + io = MemCache::BufferedIO.new(TCPSocket.new(host, port)) + io.read_timeout = timeout + io + end + ## # Close the connection to the memcached server targeted by this # object. The server is not considered dead. @@ -848,51 +1037,33 @@ class MemCache class MemCacheError < RuntimeError; end -end + class BufferedIO < Net::BufferedIO # :nodoc: + BUFSIZE = 1024 * 16 -# TCPSocket facade class which implements timeouts. -class TCPTimeoutSocket + # An implementation similar to this is in *trunk* for 1.9. When it + # gets released, this method can be removed when using 1.9 + def rbuf_fill + begin + @rbuf << @io.read_nonblock(BUFSIZE) + rescue Errno::EWOULDBLOCK + retry unless @read_timeout + if IO.select([@io], nil, nil, @read_timeout) + retry + else + raise Timeout::Error, 'IO timeout' + end + end + end - def initialize(host, port, timeout) - Timeout::timeout(MemCache::Server::CONNECT_TIMEOUT, SocketError) do - @sock = TCPSocket.new(host, port) - @len = timeout + def setsockopt *args + @io.setsockopt *args + end + + def gets + readuntil("\n") end end - def write(*args) - Timeout::timeout(@len, SocketError) do - @sock.write(*args) - end - end - - def gets(*args) - Timeout::timeout(@len, SocketError) do - @sock.gets(*args) - end - end - - def read(*args) - Timeout::timeout(@len, SocketError) do - @sock.read(*args) - end - end - - def _socket - @sock - end - - def method_missing(meth, *args) - @sock.__send__(meth, *args) - end - - def closed? - @sock.closed? - end - - def close - @sock.close - end end module Continuum @@ -932,4 +1103,5 @@ module Continuum "<#{value}, #{server.host}:#{server.port}>" end end + end diff --git a/vendor/rails/activesupport/lib/active_support/version.rb b/vendor/rails/activesupport/lib/active_support/version.rb index 30f598a8..24ce690c 100644 --- a/vendor/rails/activesupport/lib/active_support/version.rb +++ b/vendor/rails/activesupport/lib/active_support/version.rb @@ -2,7 +2,7 @@ module ActiveSupport module VERSION #:nodoc: MAJOR = 2 MINOR = 3 - TINY = 2 + TINY = 3 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/vendor/rails/activesupport/lib/active_support/xml_mini/jdom.rb b/vendor/rails/activesupport/lib/active_support/xml_mini/jdom.rb new file mode 100644 index 00000000..d795d556 --- /dev/null +++ b/vendor/rails/activesupport/lib/active_support/xml_mini/jdom.rb @@ -0,0 +1,162 @@ +raise "JRuby is required to use the JDOM backend for XmlMini" unless RUBY_PLATFORM =~ /java/ + +require 'jruby' +include Java + +import javax.xml.parsers.DocumentBuilder unless defined? DocumentBuilder +import javax.xml.parsers.DocumentBuilderFactory unless defined? DocumentBuilderFactory +import java.io.StringReader unless defined? StringReader +import org.xml.sax.InputSource unless defined? InputSource +import org.xml.sax.Attributes unless defined? Attributes +import org.w3c.dom.Node unless defined? Node + +# = XmlMini JRuby JDOM implementation +module ActiveSupport + module XmlMini_JDOM #:nodoc: + extend self + + CONTENT_KEY = '__content__'.freeze + + NODE_TYPE_NAMES = %w{ATTRIBUTE_NODE CDATA_SECTION_NODE COMMENT_NODE DOCUMENT_FRAGMENT_NODE + DOCUMENT_NODE DOCUMENT_TYPE_NODE ELEMENT_NODE ENTITY_NODE ENTITY_REFERENCE_NODE NOTATION_NODE + PROCESSING_INSTRUCTION_NODE TEXT_NODE} + + node_type_map = {} + NODE_TYPE_NAMES.each { |type| node_type_map[Node.send(type)] = type } + + # Parse an XML Document string into a simple hash using Java's jdom. + # string:: + # XML Document string to parse + def parse(string) + if string.blank? + {} + else + @dbf = DocumentBuilderFactory.new_instance + xml_string_reader = StringReader.new(string) + xml_input_source = InputSource.new(xml_string_reader) + doc = @dbf.new_document_builder.parse(xml_input_source) + merge_element!({}, doc.document_element) + end + end + + private + + # Convert an XML element and merge into the hash + # + # hash:: + # Hash to merge the converted element into. + # element:: + # XML element to merge into hash + def merge_element!(hash, element) + merge!(hash, element.tag_name, collapse(element)) + end + + # Actually converts an XML document element into a data structure. + # + # element:: + # The document element to be collapsed. + def collapse(element) + hash = get_attributes(element) + + child_nodes = element.child_nodes + if child_nodes.length > 0 + for i in 0...child_nodes.length + child = child_nodes.item(i) + merge_element!(hash, child) unless child.node_type == Node.TEXT_NODE + end + merge_texts!(hash, element) unless empty_content?(element) + hash + else + merge_texts!(hash, element) + end + end + + # Merge all the texts of an element into the hash + # + # hash:: + # Hash to add the converted emement to. + # element:: + # XML element whose texts are to me merged into the hash + def merge_texts!(hash, element) + text_children = texts(element) + if text_children.join.empty? + hash + else + # must use value to prevent double-escaping + merge!(hash, CONTENT_KEY, text_children.join) + end + end + + # Adds a new key/value pair to an existing Hash. If the key to be added + # already exists and the existing value associated with key is not + # an Array, it will be wrapped in an Array. Then the new value is + # appended to that Array. + # + # hash:: + # Hash to add key/value pair to. + # key:: + # Key to be added. + # value:: + # Value to be associated with key. + def merge!(hash, key, value) + if hash.has_key?(key) + if hash[key].instance_of?(Array) + hash[key] << value + else + hash[key] = [hash[key], value] + end + elsif value.instance_of?(Array) + hash[key] = [value] + else + hash[key] = value + end + hash + end + + # Converts the attributes array of an XML element into a hash. + # Returns an empty Hash if node has no attributes. + # + # element:: + # XML element to extract attributes from. + def get_attributes(element) + attribute_hash = {} + attributes = element.attributes + for i in 0...attributes.length + attribute_hash[attributes.item(i).name] = attributes.item(i).value + end + attribute_hash + end + + # Determines if a document element has text content + # + # element:: + # XML element to be checked. + def texts(element) + texts = [] + child_nodes = element.child_nodes + for i in 0...child_nodes.length + item = child_nodes.item(i) + if item.node_type == Node.TEXT_NODE + texts << item.get_data + end + end + texts + end + + # Determines if a document element has text content + # + # element:: + # XML element to be checked. + def empty_content?(element) + text = '' + child_nodes = element.child_nodes + for i in 0...child_nodes.length + item = child_nodes.item(i) + if item.node_type == Node.TEXT_NODE + text << item.get_data.strip + end + end + text.strip.length == 0 + end + end +end diff --git a/vendor/rails/activesupport/memcached_get_multi.diff b/vendor/rails/activesupport/memcached_get_multi.diff new file mode 100644 index 00000000..e69de29b diff --git a/vendor/rails/activesupport/test/abstract_unit.rb b/vendor/rails/activesupport/test/abstract_unit.rb index a0c0c59e..9ded5f83 100644 --- a/vendor/rails/activesupport/test/abstract_unit.rb +++ b/vendor/rails/activesupport/test/abstract_unit.rb @@ -1,8 +1,7 @@ require 'rubygems' require 'test/unit' -gem 'mocha', '>= 0.9.5' -require 'mocha' +ENV['NO_RELOAD'] = '1' $:.unshift "#{File.dirname(__FILE__)}/../lib" require 'active_support' diff --git a/vendor/rails/activesupport/test/caching_test.rb b/vendor/rails/activesupport/test/caching_test.rb index 4e212f16..94c130de 100644 --- a/vendor/rails/activesupport/test/caching_test.rb +++ b/vendor/rails/activesupport/test/caching_test.rb @@ -1,3 +1,4 @@ +require 'logger' require 'abstract_unit' class CacheKeyTest < ActiveSupport::TestCase @@ -20,22 +21,34 @@ class CacheStoreSettingTest < ActiveSupport::TestCase end def test_mem_cache_fragment_cache_store + MemCache.expects(:new).with(%w[localhost], {}) store = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost" assert_kind_of(ActiveSupport::Cache::MemCacheStore, store) - assert_equal %w(localhost), store.addresses + end + + def test_mem_cache_fragment_cache_store_with_given_mem_cache + mem_cache = MemCache.new + MemCache.expects(:new).never + store = ActiveSupport::Cache.lookup_store :mem_cache_store, mem_cache + assert_kind_of(ActiveSupport::Cache::MemCacheStore, store) + end + + def test_mem_cache_fragment_cache_store_with_given_mem_cache_like_object + MemCache.expects(:new).never + store = ActiveSupport::Cache.lookup_store :mem_cache_store, stub("memcache", :get => true) + assert_kind_of(ActiveSupport::Cache::MemCacheStore, store) end def test_mem_cache_fragment_cache_store_with_multiple_servers + MemCache.expects(:new).with(%w[localhost 192.168.1.1], {}) store = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost", '192.168.1.1' assert_kind_of(ActiveSupport::Cache::MemCacheStore, store) - assert_equal %w(localhost 192.168.1.1), store.addresses end def test_mem_cache_fragment_cache_store_with_options + MemCache.expects(:new).with(%w[localhost 192.168.1.1], { :namespace => "foo" }) store = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost", '192.168.1.1', :namespace => 'foo' assert_kind_of(ActiveSupport::Cache::MemCacheStore, store) - assert_equal %w(localhost 192.168.1.1), store.addresses - assert_equal 'foo', store.instance_variable_get('@data').instance_variable_get('@namespace') end def test_object_assigned_fragment_cache_store @@ -161,6 +174,8 @@ uses_memcached 'memcached backed store' do @cache = ActiveSupport::Cache.lookup_store(:mem_cache_store) @data = @cache.instance_variable_get(:@data) @cache.clear + @cache.silence! + @cache.logger = Logger.new("/dev/null") end include CacheStoreBehavior @@ -173,6 +188,15 @@ uses_memcached 'memcached backed store' do end end + def test_stored_objects_should_not_be_frozen + @cache.with_local_cache do + @cache.write('foo', 'bar') + end + @cache.with_local_cache do + assert !@cache.read('foo').frozen? + end + end + def test_write_should_return_true_on_success @cache.with_local_cache do result = @cache.write('foo', 'bar') @@ -256,6 +280,15 @@ uses_memcached 'memcached backed store' do end end + def test_multi_get + @cache.with_local_cache do + @cache.write('foo', 1) + @cache.write('goo', 2) + result = @cache.read_multi('foo', 'goo') + assert_equal({'foo' => 1, 'goo' => 2}, result) + end + end + def test_middleware app = lambda { |env| result = @cache.write('foo', 'bar') @@ -265,6 +298,22 @@ uses_memcached 'memcached backed store' do app = @cache.middleware.new(app) app.call({}) end + + def test_expires_in + result = @cache.write('foo', 'bar', :expires_in => 1) + assert_equal 'bar', @cache.read('foo') + sleep 2 + assert_equal nil, @cache.read('foo') + end + + def test_expires_in_with_invalid_value + @cache.write('baz', 'bat') + assert_raise(RuntimeError) do + @cache.write('foo', 'bar', :expires_in => 'Mon Jun 29 13:10:40 -0700 2150') + end + assert_equal 'bat', @cache.read('baz') + assert_equal nil, @cache.read('foo') + end end class CompressedMemCacheStore < ActiveSupport::TestCase diff --git a/vendor/rails/activesupport/test/core_ext/duration_test.rb b/vendor/rails/activesupport/test/core_ext/duration_test.rb index ab5a8666..e33eeb72 100644 --- a/vendor/rails/activesupport/test/core_ext/duration_test.rb +++ b/vendor/rails/activesupport/test/core_ext/duration_test.rb @@ -2,6 +2,7 @@ require 'abstract_unit' class DurationTest < ActiveSupport::TestCase def test_inspect + assert_equal '0 seconds', 0.seconds.inspect assert_equal '1 month', 1.month.inspect assert_equal '1 month and 1 day', (1.month + 1.day).inspect assert_equal '6 months and -2 days', (6.months - 2.days).inspect @@ -44,20 +45,20 @@ class DurationTest < ActiveSupport::TestCase Time.stubs(:now).returns Time.local(2000) # since assert_equal 36.hours.since, 1.5.days.since - assert_equal((24 * 1.7).hours.since, 1.7.days.since) + assert_in_delta((24 * 1.7).hours.since, 1.7.days.since, 0.01) # ago assert_equal 36.hours.ago, 1.5.days.ago - assert_equal((24 * 1.7).hours.ago, 1.7.days.ago) + assert_in_delta((24 * 1.7).hours.ago, 1.7.days.ago, 0.01) end def test_since_and_ago_with_fractional_weeks Time.stubs(:now).returns Time.local(2000) # since assert_equal((7 * 36).hours.since, 1.5.weeks.since) - assert_equal((7 * 24 * 1.7).hours.since, 1.7.weeks.since) + assert_in_delta((7 * 24 * 1.7).hours.since, 1.7.weeks.since, 0.01) # ago assert_equal((7 * 36).hours.ago, 1.5.weeks.ago) - assert_equal((7 * 24 * 1.7).hours.ago, 1.7.weeks.ago) + assert_in_delta((7 * 24 * 1.7).hours.ago, 1.7.weeks.ago, 0.01) end def test_deprecated_fractional_years diff --git a/vendor/rails/activesupport/test/core_ext/hash_ext_test.rb b/vendor/rails/activesupport/test/core_ext/hash_ext_test.rb index 0edac72f..c58c0acb 100644 --- a/vendor/rails/activesupport/test/core_ext/hash_ext_test.rb +++ b/vendor/rails/activesupport/test/core_ext/hash_ext_test.rb @@ -403,29 +403,87 @@ class HashToXmlTest < Test::Unit::TestCase @xml_options = { :root => :person, :skip_instruct => true, :indent => 0 } end + def test_default_values_for_rename_keys + assert_equal true,ActiveSupport.dasherize_xml + assert_equal false,ActiveSupport.camelize_xml + end + def test_one_level xml = { :name => "David", :street => "Paulina" }.to_xml(@xml_options) assert_equal "", xml.first(8) assert xml.include?(%(Paulina)) assert xml.include?(%(David)) end - + # we add :camelize => false because otherwise we'd be accidentally testing the default value for :camelize def test_one_level_dasherize_false - xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:dasherize => false)) + xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:dasherize => false,:camelize=>false)) assert_equal "", xml.first(8) assert xml.include?(%(Paulina)) assert xml.include?(%(David)) end def test_one_level_dasherize_true - xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:dasherize => true)) + xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:dasherize => true,:camelize=>false)) assert_equal "", xml.first(8) assert xml.include?(%(Paulina)) assert xml.include?(%(David)) end + def test_one_level_dasherize_default_false + current_default = ActiveSupport.dasherize_xml + ActiveSupport.dasherize_xml = false + xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:camelize=>false)) + assert_equal "", xml.first(8) + assert xml.include?(%(Paulina)) + assert xml.include?(%(David)) + ensure + ActiveSupport.dasherize_xml = current_default + end + + def test_one_level_dasherize_default_true + current_default = ActiveSupport.dasherize_xml + ActiveSupport.dasherize_xml = true + xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:camelize=>false)) + assert_equal "", xml.first(8) + assert xml.include?(%(Paulina)) + assert xml.include?(%(David)) + ensure + ActiveSupport.dasherize_xml = current_default + end + def test_one_level_camelize_true - xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:camelize => true)) + xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:camelize => true,:dasherize => false)) + assert_equal "", xml.first(8) + assert xml.include?(%(Paulina)) + assert xml.include?(%(David)) + end + + #camelize=>false is already tested above + + def test_one_level_camelize_default_false + current_default = ActiveSupport.camelize_xml + ActiveSupport.camelize_xml = false + xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:dasherize => false)) + assert_equal "", xml.first(8) + assert xml.include?(%(Paulina)) + assert xml.include?(%(David)) + ensure + ActiveSupport.camelize_xml = current_default + end + + def test_one_level_camelize_default_true + current_default = ActiveSupport.camelize_xml + ActiveSupport.camelize_xml = true + xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:dasherize => false)) + assert_equal "", xml.first(8) + assert xml.include?(%(Paulina)) + assert xml.include?(%(David)) + ensure + ActiveSupport.camelize_xml = current_default + end + + def test_one_level_camelize_true_dasherize_true + xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:dasherize => true,:camelize=>true)) assert_equal "", xml.first(8) assert xml.include?(%(Paulina)) assert xml.include?(%(David)) @@ -654,6 +712,22 @@ class HashToXmlTest < Test::Unit::TestCase assert_equal expected_blog_hash, Hash.from_xml(blog_xml) end + def test_all_caps_key_from_xml + test_xml = <<-EOT + + Lorem Ipsum + + EOT + + expected_hash = { + "ABC3XYZ" => { + "TEST" => "Lorem Ipsum" + } + } + + assert_equal expected_hash, Hash.from_xml(test_xml) + end + def test_empty_array_with_whitespace_from_xml blog_xml = <<-XML diff --git a/vendor/rails/activesupport/test/core_ext/module/model_naming_test.rb b/vendor/rails/activesupport/test/core_ext/module/model_naming_test.rb index d08349dd..b0e46c4d 100644 --- a/vendor/rails/activesupport/test/core_ext/module/model_naming_test.rb +++ b/vendor/rails/activesupport/test/core_ext/module/model_naming_test.rb @@ -13,6 +13,14 @@ class ModelNamingTest < Test::Unit::TestCase assert_equal 'post_track_backs', @model_name.plural end + def test_element + assert_equal 'track_back', @model_name.element + end + + def test_collection + assert_equal 'post/track_backs', @model_name.collection + end + def test_partial_path assert_equal 'post/track_backs/track_back', @model_name.partial_path end diff --git a/vendor/rails/activesupport/test/core_ext/module_test.rb b/vendor/rails/activesupport/test/core_ext/module_test.rb index 0d3d10f3..7fb6e14d 100644 --- a/vendor/rails/activesupport/test/core_ext/module_test.rb +++ b/vendor/rails/activesupport/test/core_ext/module_test.rb @@ -141,7 +141,7 @@ class ModuleTest < Test::Unit::TestCase def test_delegation_without_allow_nil_and_nil_value david = Someone.new("David") - assert_raise(NoMethodError) { david.street } + assert_raise(RuntimeError) { david.street } end def test_parent diff --git a/vendor/rails/activesupport/test/core_ext/string_ext_test.rb b/vendor/rails/activesupport/test/core_ext/string_ext_test.rb index 6c9b7e72..7d51e81f 100644 --- a/vendor/rails/activesupport/test/core_ext/string_ext_test.rb +++ b/vendor/rails/activesupport/test/core_ext/string_ext_test.rb @@ -132,10 +132,12 @@ class StringInflectionsTest < Test::Unit::TestCase assert_equal "h", s.first assert_equal "he", s.first(2) + assert_equal "", s.first(0) assert_equal "o", s.last assert_equal "llo", s.last(3) assert_equal "hello", s.last(10) + assert_equal "", s.last(0) assert_equal 'x', 'x'.first assert_equal 'x', 'x'.first(4) diff --git a/vendor/rails/activesupport/test/core_ext/time_with_zone_test.rb b/vendor/rails/activesupport/test/core_ext/time_with_zone_test.rb index accfe51e..03ed783c 100644 --- a/vendor/rails/activesupport/test/core_ext/time_with_zone_test.rb +++ b/vendor/rails/activesupport/test/core_ext/time_with_zone_test.rb @@ -55,12 +55,12 @@ class TimeWithZoneTest < Test::Unit::TestCase end def test_to_json - assert_equal "\"1999/12/31 19:00:00 -0500\"", @twz.to_json + assert_equal "\"1999/12/31 19:00:00 -0500\"", ActiveSupport::JSON.encode(@twz) end def test_to_json_with_use_standard_json_time_format_config_set_to_true old, ActiveSupport.use_standard_json_time_format = ActiveSupport.use_standard_json_time_format, true - assert_equal "\"1999-12-31T19:00:00-05:00\"", @twz.to_json + assert_equal "\"1999-12-31T19:00:00-05:00\"", ActiveSupport::JSON.encode(@twz) ensure ActiveSupport.use_standard_json_time_format = old end diff --git a/vendor/rails/activesupport/test/json/decoding_test.rb b/vendor/rails/activesupport/test/json/decoding_test.rb index 8fe40557..86053c9f 100644 --- a/vendor/rails/activesupport/test/json/decoding_test.rb +++ b/vendor/rails/activesupport/test/json/decoding_test.rb @@ -1,49 +1,77 @@ # encoding: UTF-8 require 'abstract_unit' -class TestJSONDecoding < Test::Unit::TestCase +class TestJSONDecoding < ActiveSupport::TestCase TESTS = { %q({"returnTo":{"\/categories":"\/"}}) => {"returnTo" => {"/categories" => "/"}}, - %q({returnTo:{"\/categories":"\/"}}) => {"returnTo" => {"/categories" => "/"}}, %q({"return\\"To\\":":{"\/categories":"\/"}}) => {"return\"To\":" => {"/categories" => "/"}}, %q({"returnTo":{"\/categories":1}}) => {"returnTo" => {"/categories" => 1}}, %({"returnTo":[1,"a"]}) => {"returnTo" => [1, "a"]}, %({"returnTo":[1,"\\"a\\",", "b"]}) => {"returnTo" => [1, "\"a\",", "b"]}, - %({a: "'", "b": "5,000"}) => {"a" => "'", "b" => "5,000"}, - %({a: "a's, b's and c's", "b": "5,000"}) => {"a" => "a's, b's and c's", "b" => "5,000"}, + %({"a": "'", "b": "5,000"}) => {"a" => "'", "b" => "5,000"}, + %({"a": "a's, b's and c's", "b": "5,000"}) => {"a" => "a's, b's and c's", "b" => "5,000"}, # multibyte %({"matzue": "松江", "asakusa": "浅草"}) => {"matzue" => "松江", "asakusa" => "浅草"}, - %({a: "2007-01-01"}) => {'a' => Date.new(2007, 1, 1)}, - %({a: "2007-01-01 01:12:34 Z"}) => {'a' => Time.utc(2007, 1, 1, 1, 12, 34)}, + %({"a": "2007-01-01"}) => {'a' => Date.new(2007, 1, 1)}, + %({"a": "2007-01-01 01:12:34 Z"}) => {'a' => Time.utc(2007, 1, 1, 1, 12, 34)}, # no time zone - %({a: "2007-01-01 01:12:34"}) => {'a' => "2007-01-01 01:12:34"}, + %({"a": "2007-01-01 01:12:34"}) => {'a' => "2007-01-01 01:12:34"}, # needs to be *exact* - %({a: " 2007-01-01 01:12:34 Z "}) => {'a' => " 2007-01-01 01:12:34 Z "}, - %({a: "2007-01-01 : it's your birthday"}) => {'a' => "2007-01-01 : it's your birthday"}, + %({"a": " 2007-01-01 01:12:34 Z "}) => {'a' => " 2007-01-01 01:12:34 Z "}, + %({"a": "2007-01-01 : it's your birthday"}) => {'a' => "2007-01-01 : it's your birthday"}, %([]) => [], %({}) => {}, - %(1) => 1, - %("") => "", - %("\\"") => "\"", - %(null) => nil, - %(true) => true, - %(false) => false, - %q("http:\/\/test.host\/posts\/1") => "http://test.host/posts/1", - %q("\u003cunicode\u0020escape\u003e") => "", - %q("\\\\u0020skip double backslashes") => "\\u0020skip double backslashes", - %q({a: "\u003cbr /\u003e"}) => {'a' => "
"}, - %q({b:["\u003ci\u003e","\u003cb\u003e","\u003cu\u003e"]}) => {'b' => ["","",""]} + %({"a":1}) => {"a" => 1}, + %({"a": ""}) => {"a" => ""}, + %({"a":"\\""}) => {"a" => "\""}, + %({"a": null}) => {"a" => nil}, + %({"a": true}) => {"a" => true}, + %({"a": false}) => {"a" => false}, + %q({"a": "http:\/\/test.host\/posts\/1"}) => {"a" => "http://test.host/posts/1"}, + %q({"a": "\u003cunicode\u0020escape\u003e"}) => {"a" => ""}, + %q({"a": "\\\\u0020skip double backslashes"}) => {"a" => "\\u0020skip double backslashes"}, + %q({"a": "\u003cbr /\u003e"}) => {'a' => "
"}, + %q({"b":["\u003ci\u003e","\u003cb\u003e","\u003cu\u003e"]}) => {'b' => ["","",""]} } - - TESTS.each do |json, expected| - define_method :"test_json_decoding_#{json}" do - assert_nothing_raised do - assert_equal expected, ActiveSupport::JSON.decode(json) + + # load the default JSON backend + ActiveSupport::JSON.backend + + backends = %w(Yaml) + begin + gem 'json', '>= 1.1' + require 'json' + backends << "JSONGem" + rescue Gem::LoadError + # Skip JSON gem tests + end + + backends.each do |backend| + TESTS.each do |json, expected| + test "json decodes #{json} with the #{backend} backend" do + ActiveSupport.parse_json_times = true + silence_warnings do + ActiveSupport::JSON.with_backend backend do + assert_nothing_raised do + assert_equal expected, ActiveSupport::JSON.decode(json) + end + end + end end end end - + + if backends.include?("JSONGem") + test "json decodes time json with time parsing disabled" do + ActiveSupport.parse_json_times = false + expected = {"a" => "2007-01-01 01:12:34 Z"} + ActiveSupport::JSON.with_backend "JSONGem" do + assert_equal expected, ActiveSupport::JSON.decode(%({"a": "2007-01-01 01:12:34 Z"})) + end + end + end + def test_failed_json_decoding assert_raise(ActiveSupport::JSON::ParseError) { ActiveSupport::JSON.decode(%({: 1})) } end -end +end \ No newline at end of file diff --git a/vendor/rails/activesupport/test/json/encoding_test.rb b/vendor/rails/activesupport/test/json/encoding_test.rb index 7d2eedad..ab8e4e80 100644 --- a/vendor/rails/activesupport/test/json/encoding_test.rb +++ b/vendor/rails/activesupport/test/json/encoding_test.rb @@ -8,6 +8,12 @@ class TestJSONEncoding < Test::Unit::TestCase end end + class Custom + def to_json(options) + '"custom"' + end + end + TrueTests = [[ true, %(true) ]] FalseTests = [[ false, %(false) ]] NilTests = [[ nil, %(null) ]] @@ -18,14 +24,15 @@ class TestJSONEncoding < Test::Unit::TestCase [ 'a "string" with quotes & an ampersand', %("a \\"string\\" with quotes \\u0026 an ampersand") ], [ 'http://test.host/posts/1', %("http://test.host/posts/1")]] - ArrayTests = [[ ['a', 'b', 'c'], %([\"a\", \"b\", \"c\"]) ], - [ [1, 'a', :b, nil, false], %([1, \"a\", \"b\", null, false]) ]] + ArrayTests = [[ ['a', 'b', 'c'], %([\"a\",\"b\",\"c\"]) ], + [ [1, 'a', :b, nil, false], %([1,\"a\",\"b\",null,false]) ]] SymbolTests = [[ :a, %("a") ], [ :this, %("this") ], [ :"a b", %("a b") ]] - ObjectTests = [[ Foo.new(1, 2), %({\"a\": 1, \"b\": 2}) ]] + ObjectTests = [[ Foo.new(1, 2), %({\"a\":1,\"b\":2}) ]] + CustomTests = [[ Custom.new, '"custom"' ]] VariableTests = [[ ActiveSupport::JSON::Variable.new('foo'), 'foo'], [ ActiveSupport::JSON::Variable.new('alert("foo")'), 'alert("foo")']] @@ -46,7 +53,7 @@ class TestJSONEncoding < Test::Unit::TestCase ActiveSupport.escape_html_entities_in_json = class_tests !~ /^Standard/ ActiveSupport.use_standard_json_time_format = class_tests =~ /^Standard/ self.class.const_get(class_tests).each do |pair| - assert_equal pair.last, pair.first.to_json + assert_equal pair.last, ActiveSupport::JSON.encode(pair.first) end ensure ActiveSupport.escape_html_entities_in_json = false @@ -56,45 +63,50 @@ class TestJSONEncoding < Test::Unit::TestCase end def test_hash_encoding - assert_equal %({\"a\": \"b\"}), { :a => :b }.to_json - assert_equal %({\"a\": 1}), { 'a' => 1 }.to_json - assert_equal %({\"a\": [1, 2]}), { 'a' => [1,2] }.to_json - assert_equal %({"1": 2}), { 1 => 2 }.to_json + assert_equal %({\"a\":\"b\"}), ActiveSupport::JSON.encode(:a => :b) + assert_equal %({\"a\":1}), ActiveSupport::JSON.encode('a' => 1) + assert_equal %({\"a\":[1,2]}), ActiveSupport::JSON.encode('a' => [1,2]) + assert_equal %({"1":2}), ActiveSupport::JSON.encode(1 => 2) - sorted_json = '{' + {:a => :b, :c => :d}.to_json[1..-2].split(', ').sort.join(', ') + '}' - assert_equal %({\"a\": \"b\", \"c\": \"d\"}), sorted_json + sorted_json = '{' + ActiveSupport::JSON.encode(:a => :b, :c => :d)[1..-2].split(',').sort.join(',') + '}' + assert_equal %({\"a\":\"b\",\"c\":\"d\"}), sorted_json end def test_utf8_string_encoded_properly_when_kcode_is_utf8 with_kcode 'UTF8' do - assert_equal '"\\u20ac2.99"', '€2.99'.to_json - assert_equal '"\\u270e\\u263a"', '✎☺'.to_json + result = ActiveSupport::JSON.encode('€2.99') + assert_equal '"\\u20ac2.99"', result + assert_equal(Encoding::UTF_8, result.encoding) if result.respond_to?(:encoding) + + result = ActiveSupport::JSON.encode('✎☺') + assert_equal '"\\u270e\\u263a"', result + assert_equal(Encoding::UTF_8, result.encoding) if result.respond_to?(:encoding) end end def test_exception_raised_when_encoding_circular_reference a = [1] a << a - assert_raise(ActiveSupport::JSON::CircularReferenceError) { a.to_json } + assert_raise(ActiveSupport::JSON::Encoding::CircularReferenceError) { ActiveSupport::JSON.encode(a) } end def test_hash_key_identifiers_are_always_quoted values = {0 => 0, 1 => 1, :_ => :_, "$" => "$", "a" => "a", :A => :A, :A0 => :A0, "A0B" => "A0B"} - assert_equal %w( "$" "A" "A0" "A0B" "_" "a" "0" "1" ).sort, object_keys(values.to_json) + assert_equal %w( "$" "A" "A0" "A0B" "_" "a" "0" "1" ).sort, object_keys(ActiveSupport::JSON.encode(values)) end def test_hash_should_allow_key_filtering_with_only - assert_equal %({"a": 1}), { 'a' => 1, :b => 2, :c => 3 }.to_json(:only => 'a') + assert_equal %({"a":1}), ActiveSupport::JSON.encode({'a' => 1, :b => 2, :c => 3}, :only => 'a') end def test_hash_should_allow_key_filtering_with_except - assert_equal %({"b": 2}), { 'foo' => 'bar', :b => 2, :c => 3 }.to_json(:except => ['foo', :c]) + assert_equal %({"b":2}), ActiveSupport::JSON.encode({'foo' => 'bar', :b => 2, :c => 3}, :except => ['foo', :c]) end def test_time_to_json_includes_local_offset ActiveSupport.use_standard_json_time_format = true with_env_tz 'US/Eastern' do - assert_equal %("2005-02-01T15:15:10-05:00"), Time.local(2005,2,1,15,15,10).to_json + assert_equal %("2005-02-01T15:15:10-05:00"), ActiveSupport::JSON.encode(Time.local(2005,2,1,15,15,10)) end ensure ActiveSupport.use_standard_json_time_format = false @@ -108,7 +120,7 @@ class TestJSONEncoding < Test::Unit::TestCase :latitude => 123.234 } } - result = hash.to_json + result = ActiveSupport::JSON.encode(hash) end end @@ -127,6 +139,16 @@ class TestJSONEncoding < Test::Unit::TestCase end class JsonOptionsTests < Test::Unit::TestCase + # The json extension passes internal state to to_json + def test_non_hash_options_should_be_tolerated + faux_internal_state_object = Object.new + + value = Object.new + def value.to_json(options) options end + + assert_kind_of Hash, ActiveSupport::JSON.encode(value, faux_internal_state_object) + end + def test_enumerable_should_passthrough_options_to_elements json_options = { :include => :posts } ActiveSupport::JSON.expects(:encode).with(1, json_options) diff --git a/vendor/rails/activesupport/test/ordered_hash_test.rb b/vendor/rails/activesupport/test/ordered_hash_test.rb index 7cd8c8a8..15bd5718 100644 --- a/vendor/rails/activesupport/test/ordered_hash_test.rb +++ b/vendor/rails/activesupport/test/ordered_hash_test.rb @@ -51,6 +51,10 @@ class OrderedHashTest < Test::Unit::TestCase assert_same @ordered_hash, @ordered_hash.to_hash end + def test_to_a + assert_equal @keys.zip(@values), @ordered_hash.to_a + end + def test_has_key assert_equal true, @ordered_hash.has_key?('blue') assert_equal true, @ordered_hash.key?('blue') @@ -158,4 +162,33 @@ class OrderedHashTest < Test::Unit::TestCase def test_inspect assert @ordered_hash.inspect.include?(@hash.inspect) end + + def test_alternate_initialization_with_splat + alternate = ActiveSupport::OrderedHash[1,2,3,4] + assert_kind_of ActiveSupport::OrderedHash, alternate + assert_equal [1, 3], alternate.keys + end + + def test_alternate_initialization_with_array + alternate = ActiveSupport::OrderedHash[ [ + [1, 2], + [3, 4], + "bad key value pair", + [ 'missing value' ] + ]] + + assert_kind_of ActiveSupport::OrderedHash, alternate + assert_equal [1, 3, 'missing value'], alternate.keys + assert_equal [2, 4, nil ], alternate.values + end + + def test_alternate_initialization_raises_exception_on_odd_length_args + begin + alternate = ActiveSupport::OrderedHash[1,2,3,4,5] + flunk "Hash::[] should have raised an exception on initialization " + + "with an odd number of parameters" + rescue + assert_equal "odd number of arguments for Hash", $!.message + end + end end diff --git a/vendor/rails/activesupport/test/xml_mini/jdom_engine_test.rb b/vendor/rails/activesupport/test/xml_mini/jdom_engine_test.rb new file mode 100644 index 00000000..b7452289 --- /dev/null +++ b/vendor/rails/activesupport/test/xml_mini/jdom_engine_test.rb @@ -0,0 +1,153 @@ +require 'abstract_unit' +require 'active_support/xml_mini' + +if RUBY_PLATFORM =~ /java/ + +class JDOMEngineTest < Test::Unit::TestCase + include ActiveSupport + + def setup + @default_backend = XmlMini.backend + XmlMini.backend = 'JDOM' + end + + def teardown + XmlMini.backend = @default_backend + end + + # def test_file_from_xml + # hash = Hash.from_xml(<<-eoxml) + # + # + # + # + # eoxml + # assert hash.has_key?('blog') + # assert hash['blog'].has_key?('logo') + # + # file = hash['blog']['logo'] + # assert_equal 'logo.png', file.original_filename + # assert_equal 'image/png', file.content_type + # end + + def test_exception_thrown_on_expansion_attack + assert_raise NativeException do + attack_xml = <<-EOT + + + + + + + + + ]> + + &a; + + EOT + Hash.from_xml(attack_xml) + end + end + + def test_setting_JDOM_as_backend + XmlMini.backend = 'JDOM' + assert_equal XmlMini_JDOM, XmlMini.backend + end + + def test_blank_returns_empty_hash + assert_equal({}, XmlMini.parse(nil)) + assert_equal({}, XmlMini.parse('')) + end + + def test_array_type_makes_an_array + assert_equal_rexml(<<-eoxml) + + + a post + another post + + + eoxml + end + + def test_one_node_document_as_hash + assert_equal_rexml(<<-eoxml) + + eoxml + end + + def test_one_node_with_attributes_document_as_hash + assert_equal_rexml(<<-eoxml) + + eoxml + end + + def test_products_node_with_book_node_as_hash + assert_equal_rexml(<<-eoxml) + + + + eoxml + end + + def test_products_node_with_two_book_nodes_as_hash + assert_equal_rexml(<<-eoxml) + + + + + eoxml + end + + def test_single_node_with_content_as_hash + assert_equal_rexml(<<-eoxml) + + hello world + + eoxml + end + + def test_children_with_children + assert_equal_rexml(<<-eoxml) + + + + + + eoxml + end + + def test_children_with_text + assert_equal_rexml(<<-eoxml) + + + hello everyone + + + eoxml + end + + def test_children_with_non_adjacent_text + assert_equal_rexml(<<-eoxml) + + good + + hello everyone + + morning + + eoxml + end + + private + def assert_equal_rexml(xml) + hash = XmlMini.with_backend('REXML') { XmlMini.parse(xml) } + assert_equal(hash, XmlMini.parse(xml)) + end +end + +else + # don't run these test because we aren't running in JRuby +end diff --git a/vendor/rails/ci/geminstaller.yml b/vendor/rails/ci/geminstaller.yml index 33f1e811..a04bf944 100644 --- a/vendor/rails/ci/geminstaller.yml +++ b/vendor/rails/ci/geminstaller.yml @@ -7,14 +7,14 @@ gems: - name: memcache-client version: >= 1.5.0 - name: mocha - version: >= 0.9.5 + version: >= 0.9.7 - name: mysql #version: >= 2.7 version: = 2.7 - name: pg version: >= 0.7.9.2008.10.13 - name: rack - version: '~> 0.9.0' + version: '~> 1.0.0' - name: rake version: >= 0.8.1 - name: sqlite-ruby diff --git a/vendor/rails/railties/CHANGELOG b/vendor/rails/railties/CHANGELOG index e8e8434a..b095fab8 100644 --- a/vendor/rails/railties/CHANGELOG +++ b/vendor/rails/railties/CHANGELOG @@ -1,3 +1,7 @@ +*2.3.3 (July 12 2009) + +* Version bump + *2.3.2 [Final] (March 15, 2009)* * Allow metal to live in plugins #2045 [Matthew Rudy] diff --git a/vendor/rails/railties/Rakefile b/vendor/rails/railties/Rakefile index 6c0fc226..9bdb3372 100644 --- a/vendor/rails/railties/Rakefile +++ b/vendor/rails/railties/Rakefile @@ -2,7 +2,6 @@ require 'rake' require 'rake/testtask' require 'rake/rdoctask' require 'rake/gempackagetask' -require 'rake/contrib/rubyforgepublisher' require 'date' require 'rbconfig' @@ -246,7 +245,7 @@ def copy_with_rewritten_ruby_path(src_file, dest_file) end desc 'Generate guides (for authors), use ONLY=foo to process just "foo.textile"' -task :guides do +task :generate_guides do ruby "guides/rails_guides.rb" end @@ -294,6 +293,7 @@ PKG_FILES = FileList[ 'doc/**/*', 'dispatches/**/*', 'environments/**/*', + 'guides/**/*', 'helpers/**/*', 'generators/**/*', 'html/**/*', @@ -311,16 +311,16 @@ spec = Gem::Specification.new do |s| EOF s.add_dependency('rake', '>= 0.8.3') - s.add_dependency('activesupport', '= 2.3.2' + PKG_BUILD) - s.add_dependency('activerecord', '= 2.3.2' + PKG_BUILD) - s.add_dependency('actionpack', '= 2.3.2' + PKG_BUILD) - s.add_dependency('actionmailer', '= 2.3.2' + PKG_BUILD) - s.add_dependency('activeresource', '= 2.3.2' + PKG_BUILD) + s.add_dependency('activesupport', '= 2.3.3' + PKG_BUILD) + s.add_dependency('activerecord', '= 2.3.3' + PKG_BUILD) + s.add_dependency('actionpack', '= 2.3.3' + PKG_BUILD) + s.add_dependency('actionmailer', '= 2.3.3' + PKG_BUILD) + s.add_dependency('activeresource', '= 2.3.3' + PKG_BUILD) s.rdoc_options << '--exclude' << '.' s.has_rdoc = false - s.files = PKG_FILES.to_a.delete_if {|f| f.include?('.svn')} + s.files = PKG_FILES.to_a.delete_if {|f| f =~ %r{\.svn|guides/output}} s.require_path = 'lib' s.bindir = "bin" # Use these for applications. s.executables = ["rails"] @@ -345,7 +345,7 @@ task :pgem => [:gem] do end desc "Publish the guides" -task :pguides => :guides do +task :pguides => :generate_guides do mkdir_p 'pkg' `tar -czf pkg/guides.gz guides/output` Rake::SshFilePublisher.new("web.rubyonrails.org", "/u/sites/guides.rubyonrails.org/public", "pkg", "guides.gz").upload @@ -354,6 +354,7 @@ end desc "Publish the release files to RubyForge." task :release => [ :package ] do + require 'rake/contrib/rubyforgepublisher' require 'rubyforge' packages = %w( gem ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" } diff --git a/vendor/rails/railties/configs/routes.rb b/vendor/rails/railties/configs/routes.rb index 4f3d9d22..ea14ce1b 100644 --- a/vendor/rails/railties/configs/routes.rb +++ b/vendor/rails/railties/configs/routes.rb @@ -37,7 +37,7 @@ ActionController::Routing::Routes.draw do |map| # Install the default routes as the lowest priority. # Note: These default routes make all actions in every controller accessible via GET requests. You should - # consider removing the them or commenting them out if you're using named routes and resources. + # consider removing or commenting them out if you're using named routes and resources. map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format' end diff --git a/vendor/rails/railties/guides/rails_guides.rb b/vendor/rails/railties/guides/rails_guides.rb index 725f4cd8..b73e10e4 100644 --- a/vendor/rails/railties/guides/rails_guides.rb +++ b/vendor/rails/railties/guides/rails_guides.rb @@ -1,17 +1,28 @@ pwd = File.dirname(__FILE__) $: << pwd -$: << File.join(pwd, "../../activesupport/lib") -$: << File.join(pwd, "../../actionpack/lib") -require "action_controller" -require "action_view" - -# Require rubygems after loading Action View -require 'rubygems' begin - gem 'RedCloth', '>= 4.1.1'# Need exactly 4.1.1 + as_lib = File.join(pwd, "../../activesupport/lib") + ap_lib = File.join(pwd, "../../actionpack/lib") + + $: << as_lib if File.directory?(as_lib) + $: << ap_lib if File.directory?(ap_lib) + + require "action_controller" + require "action_view" +rescue LoadError + require 'rubygems' + gem "actionpack", '>= 2.3' + + require "action_controller" + require "action_view" +end + +begin + require 'rubygems' + gem 'RedCloth', '>= 4.1.1' rescue Gem::LoadError - $stderr.puts %(Missing the RedCloth 4.1.1 gem.\nPlease `gem install -v=4.1.1 RedCloth` to generate the guides.) + $stderr.puts %(Generating Guides requires RedCloth 4.1.1+) exit 1 end @@ -22,7 +33,6 @@ module RailsGuides autoload :Indexer, "rails_guides/indexer" autoload :Helpers, "rails_guides/helpers" autoload :TextileExtensions, "rails_guides/textile_extensions" - autoload :Levenshtein, "rails_guides/levenshtein" end RedCloth.send(:include, RailsGuides::TextileExtensions) diff --git a/vendor/rails/railties/guides/rails_guides/generator.rb b/vendor/rails/railties/guides/rails_guides/generator.rb index 8e69af5b..6c0d9f3c 100644 --- a/vendor/rails/railties/guides/rails_guides/generator.rb +++ b/vendor/rails/railties/guides/rails_guides/generator.rb @@ -57,7 +57,6 @@ module RailsGuides result = view.render(:layout => 'layout', :text => textile(body)) f.write result - warn_about_broken_links(result) end end end @@ -135,38 +134,5 @@ module RailsGuides code_blocks[$1.to_i] end end - - def warn_about_broken_links(html) - anchors = extract_anchors(html) - check_fragment_identifiers(html, anchors) - end - - def extract_anchors(html) - # Textile generates headers with IDs computed from titles. - anchors = Set.new - html.scan(/ Levenshtein.distance(fragment_identifier, b) - } - puts "*** BROKEN LINK: ##{fragment_identifier}, perhaps you meant ##{guess}." - end - end - end end end diff --git a/vendor/rails/railties/guides/rails_guides/levenshtein.rb b/vendor/rails/railties/guides/rails_guides/levenshtein.rb deleted file mode 100644 index 02e35f60..00000000 --- a/vendor/rails/railties/guides/rails_guides/levenshtein.rb +++ /dev/null @@ -1,112 +0,0 @@ -# -# Levenshtein distance algorithm implementation for Ruby, with UTF-8 support -# -# Author:: Paul BATTLEY (pbattley @ gmail.com) -# Version:: 1.3 -# Date:: 2005-04-19 -# -# == About -# -# The Levenshtein distance is a measure of how similar two strings s and t are, -# calculated as the number of deletions/insertions/substitutions needed to -# transform s into t. The greater the distance, the more the strings differ. -# -# The Levenshtein distance is also sometimes referred to as the -# easier-to-pronounce-and-spell 'edit distance'. -# -# == Revision history -# -# * 2005-05-19 1.3 Repairing an oversight, distance can now be called via -# Levenshtein.distance(s, t) -# * 2005-05-04 1.2 Now uses just one 1-dimensional array. I think this is as -# far as optimisation can go. -# * 2005-05-04 1.1 Now storing only the current and previous rows of the matrix -# instead of the whole lot. -# -# == Licence -# -# Copyright (c) 2005 Paul Battley -# -# Usage of the works is permitted provided that this instrument is retained -# with the works, so that any entity that uses the works is notified of this -# instrument. -# -# DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. -# - -module Levenshtein - - # - # Calculate the Levenshtein distance between two strings +str1+ and +str2+. - # +str1+ and +str2+ should be ASCII or UTF-8. - # - def distance(str1, str2) - s = str1.unpack('U*') - t = str2.unpack('U*') - n = s.length - m = t.length - return m if (0 == n) - return n if (0 == m) - - d = (0..m).to_a - x = nil - - (0...n).each do |i| - e = i+1 - (0...m).each do |j| - cost = (s[i] == t[j]) ? 0 : 1 - x = [ - d[j+1] + 1, # insertion - e + 1, # deletion - d[j] + cost # substitution - ].min - d[j] = e - e = x - end - d[m] = x - end - - return x - end - - extend self -end - -if (__FILE__ == $0) - require 'test/unit' - - class LevenshteinTest < Test::Unit::TestCase - include Levenshtein - - EXPECTED = [ - # Easy ones - ['test', 'test', 0], - ['test', 'tent', 1], - ['gumbo', 'gambol', 2], - ['kitten', 'sitting', 3], - # Empty strings - ['foo', '', 3], - ['', '', 0], - ['a', '', 1], - # UTF-8 - ["f\303\266o", 'foo', 1], - ["fran\303\247ais", 'francais', 1], - ["fran\303\247ais", "fran\303\246ais", 1], - ["\347\247\201\343\201\256\345\220\215\345\211\215\343\201\257"<< - "\343\203\235\343\203\274\343\203\253\343\201\247\343\201\231", - "\343\201\274\343\201\217\343\201\256\345\220\215\345\211\215\343\201"<< - "\257\343\203\235\343\203\274\343\203\253\343\201\247\343\201\231", - 2], # Japanese - # Edge cases - ['a', 'a', 0], - ['0123456789', 'abcdefghijklmnopqrstuvwxyz', 26] - ] - - def test_known_distances - EXPECTED.each do |a,b,x| - assert_equal(x, distance(a, b)) - assert_equal(x, distance(b, a)) - end - end - end -end diff --git a/vendor/rails/railties/lib/commands/performance/profiler.rb b/vendor/rails/railties/lib/commands/performance/profiler.rb index fd111bae..7df840f1 100644 --- a/vendor/rails/railties/lib/commands/performance/profiler.rb +++ b/vendor/rails/railties/lib/commands/performance/profiler.rb @@ -29,7 +29,7 @@ begin printer_class = RubyProf::FlatPrinter end printer = printer_class.new(results) - printer.print($stderr, 0) + printer.print($stderr) rescue LoadError require "prof" $stderr.puts 'Using the old ruby-prof extension.' diff --git a/vendor/rails/railties/lib/initializer.rb b/vendor/rails/railties/lib/initializer.rb index a04405a7..5f5e557d 100644 --- a/vendor/rails/railties/lib/initializer.rb +++ b/vendor/rails/railties/lib/initializer.rb @@ -159,6 +159,8 @@ module Rails add_support_load_paths + check_for_unbuilt_gems + load_gems load_plugins @@ -301,11 +303,30 @@ module Rails end def load_gems - unless $gems_build_rake_task + unless $gems_rake_task @configuration.gems.each { |gem| gem.load } end end + def check_for_unbuilt_gems + unbuilt_gems = @configuration.gems.select(&:frozen?).reject(&:built?) + if unbuilt_gems.size > 0 + # don't print if the gems:build rake tasks are being run + unless $gems_build_rake_task + abort <<-end_error +The following gems have native components that need to be built + #{unbuilt_gems.map { |gem| "#{gem.name} #{gem.requirement}" } * "\n "} + +You're running: + ruby #{Gem.ruby_version} at #{Gem.ruby} + rubygems #{Gem::RubyGemsVersion} at #{Gem.path * ', '} + +Run `rake gems:build` to build the unbuilt gems. + end_error + end + end + end + def check_gem_dependencies unloaded_gems = @configuration.gems.reject { |g| g.loaded? } if unloaded_gems.size > 0 @@ -420,7 +441,8 @@ Run `rake gems:install` to install the missing gems. def initialize_database_middleware if configuration.frameworks.include?(:active_record) - if ActionController::Base.session_store == ActiveRecord::SessionStore + if configuration.frameworks.include?(:action_controller) && + ActionController::Base.session_store == ActiveRecord::SessionStore configuration.middleware.insert_before :"ActiveRecord::SessionStore", ActiveRecord::ConnectionAdapters::ConnectionManagement configuration.middleware.insert_before :"ActiveRecord::SessionStore", ActiveRecord::QueryCache else @@ -565,7 +587,7 @@ Run `rake gems:install` to install the missing gems. Rails::Rack::Metal.metal_paths += plugin_loader.engine_metal_paths configuration.middleware.insert_before( - :"ActionController::RewindableInput", + :"ActionController::ParamsParser", Rails::Rack::Metal, :if => Rails::Rack::Metal.metals.any?) end @@ -862,7 +884,7 @@ Run `rake gems:install` to install the missing gems. # Enable threaded mode. Allows concurrent requests to controller actions and # multiple database connections. Also disables automatic dependency loading - # after boot, and disables reloading code on every request, as these are + # after boot, and disables reloading code on every request, as these are # fundamentally incompatible with thread safety. def threadsafe! self.preload_frameworks = true @@ -1103,3 +1125,4 @@ class Rails::OrderedOptions < Array #:nodoc: return false end end + diff --git a/vendor/rails/railties/lib/rails/gem_dependency.rb b/vendor/rails/railties/lib/rails/gem_dependency.rb index 3062a771..06d830ba 100644 --- a/vendor/rails/railties/lib/rails/gem_dependency.rb +++ b/vendor/rails/railties/lib/rails/gem_dependency.rb @@ -29,6 +29,22 @@ module Rails end end + def self.from_directory_name(directory_name, load_spec=true) + directory_name_parts = File.basename(directory_name).split('-') + name = directory_name_parts[0..-2].join('-') + version = directory_name_parts.last + result = self.new(name, :version => version) + spec_filename = File.join(directory_name, '.specification') + if load_spec + raise "Missing specification file in #{File.dirname(spec_filename)}. Perhaps you need to do a 'rake gems:refresh_specs'?" unless File.exists?(spec_filename) + spec = YAML::load_file(spec_filename) + result.specification = spec + end + result + rescue ArgumentError => e + raise "Unable to determine gem name and version from '#{directory_name}'" + end + def initialize(name, options = {}) require 'rubygems' unless Object.const_defined?(:Gem) @@ -95,14 +111,26 @@ module Rails end end + def specification=(s) + @spec = s + end + def requirement r = version_requirements (r == Gem::Requirement.default) ? nil : r end def built? - # TODO: If Rubygems ever gives us a way to detect this, we should use it - false + return false unless frozen? + + if vendor_gem? + specification.extensions.each do |ext| + makefile = File.join(unpacked_gem_directory, File.dirname(ext), 'Makefile') + return false unless File.exists?(makefile) + end + end + + true end def framework_gem? @@ -155,15 +183,16 @@ module Rails specification && File.exists?(unpacked_gem_directory) end - def build + def build(options={}) require 'rails/gem_builder' - unless built? + return if specification.nil? + if options[:force] || !built? return unless File.exists?(unpacked_specification_filename) spec = YAML::load_file(unpacked_specification_filename) Rails::GemBuilder.new(spec, unpacked_gem_directory).build_extensions puts "Built gem: '#{unpacked_gem_directory}'" end - dependencies.each { |dep| dep.build } + dependencies.each { |dep| dep.build(options) } end def install @@ -223,7 +252,7 @@ module Rails real_spec = Gem::Specification.load(specification.loaded_from) write_specification(real_spec) end - dependencies.each { |dep| dep.unpack } if options[:recursive] + dependencies.each { |dep| dep.unpack(options) } if options[:recursive] end def write_specification(spec) diff --git a/vendor/rails/railties/lib/rails/rack/metal.rb b/vendor/rails/railties/lib/rails/rack/metal.rb index adc43da8..8719a5c5 100644 --- a/vendor/rails/railties/lib/rails/rack/metal.rb +++ b/vendor/rails/railties/lib/rails/rack/metal.rb @@ -26,7 +26,7 @@ module Rails load_list.map do |requested_metal| if metal = all_metals[requested_metal] - require metal + require_dependency metal requested_metal.constantize end end.compact diff --git a/vendor/rails/railties/lib/rails/version.rb b/vendor/rails/railties/lib/rails/version.rb index 99c7516a..d3f81d88 100644 --- a/vendor/rails/railties/lib/rails/version.rb +++ b/vendor/rails/railties/lib/rails/version.rb @@ -2,7 +2,7 @@ module Rails module VERSION #:nodoc: MAJOR = 2 MINOR = 3 - TINY = 2 + TINY = 3 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/vendor/rails/railties/lib/tasks/gems.rake b/vendor/rails/railties/lib/tasks/gems.rake index ed07bf20..f1c34c7c 100644 --- a/vendor/rails/railties/lib/tasks/gems.rake +++ b/vendor/rails/railties/lib/tasks/gems.rake @@ -20,18 +20,25 @@ namespace :gems do desc "Build any native extensions for unpacked gems" task :build do $gems_build_rake_task = true - Rake::Task['gems:unpack'].invoke - current_gems.each &:build + frozen_gems.each { |gem| gem.build } + end + + namespace :build do + desc "Force the build of all gems" + task :force do + $gems_build_rake_task = true + frozen_gems.each { |gem| gem.build(:force => true) } + end end desc "Installs all required gems." task :install => :base do - current_gems.each &:install + current_gems.each { |gem| gem.install } end desc "Unpacks all required gems into vendor/gems." task :unpack => :install do - current_gems.each &:unpack + current_gems.each { |gem| gem.unpack } end namespace :unpack do @@ -42,8 +49,8 @@ namespace :gems do end desc "Regenerate gem specifications in correct format." - task :refresh_specs => :base do - current_gems.each &:refresh + task :refresh_specs do + frozen_gems(false).each { |gem| gem.refresh } end end @@ -53,6 +60,12 @@ def current_gems gems end +def frozen_gems(load_specs=true) + Dir[File.join(RAILS_ROOT, 'vendor', 'gems', '*-*')].map do |gem_dir| + Rails::GemDependency.from_directory_name(gem_dir, load_specs) + end +end + def print_gem_status(gem, indent=1) code = case when gem.framework_gem? then 'R' diff --git a/vendor/rails/railties/lib/test_help.rb b/vendor/rails/railties/lib/test_help.rb index ee24ea3a..f8608925 100644 --- a/vendor/rails/railties/lib/test_help.rb +++ b/vendor/rails/railties/lib/test_help.rb @@ -29,7 +29,10 @@ end begin require_library_or_gem 'ruby-debug' Debugger.start - Debugger.settings[:autoeval] = true if Debugger.respond_to?(:settings) + if Debugger.respond_to?(:settings) + Debugger.settings[:autoeval] = true + Debugger.settings[:autolist] = 1 + end rescue LoadError # ruby-debug wasn't available so neither can the debugging be end diff --git a/vendor/rails/railties/test/abstract_unit.rb b/vendor/rails/railties/test/abstract_unit.rb index 0addcb8b..85f680da 100644 --- a/vendor/rails/railties/test/abstract_unit.rb +++ b/vendor/rails/railties/test/abstract_unit.rb @@ -9,9 +9,6 @@ require 'stringio' require 'rubygems' require 'test/unit' -gem 'mocha', '>= 0.9.5' -require 'mocha' - require 'active_support' require 'active_support/test_case' diff --git a/vendor/rails/railties/test/gem_dependency_test.rb b/vendor/rails/railties/test/gem_dependency_test.rb index 189ad02b..a4cf6f76 100644 --- a/vendor/rails/railties/test/gem_dependency_test.rb +++ b/vendor/rails/railties/test/gem_dependency_test.rb @@ -18,7 +18,7 @@ class GemDependencyTest < Test::Unit::TestCase def test_configuration_adds_gem_dependency config = Rails::Configuration.new config.gem "xaws-s3x", :lib => "aws/s3", :version => "0.4.0" - assert_equal [["install", "xaws-s3x", "--version", '"= 0.4.0"']], config.gems.collect(&:install_command) + assert_equal [["install", "xaws-s3x", "--version", '"= 0.4.0"']], config.gems.collect { |g| g.install_command } end def test_gem_creates_install_command @@ -144,4 +144,76 @@ class GemDependencyTest < Test::Unit::TestCase end end + def test_gem_ignores_development_dependencies + dummy_gem = Rails::GemDependency.new "dummy-gem-k" + dummy_gem.add_load_paths + dummy_gem.load + assert_equal 1, dummy_gem.dependencies.size + end + + def test_gem_guards_against_duplicate_unpacks + dummy_gem = Rails::GemDependency.new "dummy-gem-a" + dummy_gem.stubs(:frozen?).returns(true) + dummy_gem.expects(:unpack_base).never + dummy_gem.unpack + end + + def test_gem_does_not_unpack_framework_gems + dummy_gem = Rails::GemDependency.new "dummy-gem-a" + dummy_gem.stubs(:framework_gem?).returns(true) + dummy_gem.expects(:unpack_base).never + dummy_gem.unpack + end + + def test_gem_from_directory_name_attempts_to_load_specification + assert_raises RuntimeError do + dummy_gem = Rails::GemDependency.from_directory_name('dummy-gem-1.1') + end + end + + def test_gem_from_directory_name + dummy_gem = Rails::GemDependency.from_directory_name('dummy-gem-1.1', false) + assert_equal 'dummy-gem', dummy_gem.name + assert_equal '= 1.1', dummy_gem.version_requirements.to_s + end + + def test_gem_from_directory_name_loads_specification_successfully + assert_nothing_raised do + dummy_gem = Rails::GemDependency.from_directory_name(File.join(Rails::GemDependency.unpacked_path, 'dummy-gem-g-1.0.0')) + assert_not_nil dummy_gem.specification + end + end + + def test_gem_from_invalid_directory_name + assert_raises RuntimeError do + dummy_gem = Rails::GemDependency.from_directory_name('dummy-gem') + end + assert_raises RuntimeError do + dummy_gem = Rails::GemDependency.from_directory_name('dummy') + end + end + + def test_gem_determines_build_status + assert_equal true, Rails::GemDependency.new("dummy-gem-a").built? + assert_equal true, Rails::GemDependency.new("dummy-gem-i").built? + assert_equal false, Rails::GemDependency.new("dummy-gem-j").built? + end + + def test_gem_determines_build_status_only_on_vendor_gems + framework_gem = Rails::GemDependency.new('dummy-framework-gem') + framework_gem.stubs(:framework_gem?).returns(true) # already loaded + framework_gem.stubs(:vendor_rails?).returns(false) # but not in vendor/rails + framework_gem.stubs(:vendor_gem?).returns(false) # and not in vendor/gems + framework_gem.add_load_paths # freeze framework gem early + assert framework_gem.built? + end + + def test_gem_build_passes_options_to_dependencies + start_gem = Rails::GemDependency.new("dummy-gem-g") + dep_gem = Rails::GemDependency.new("dummy-gem-f") + start_gem.stubs(:dependencies).returns([dep_gem]) + dep_gem.expects(:build).with({ :force => true }).once + start_gem.build(:force => true) + end + end diff --git a/vendor/rails/railties/test/initializer_test.rb b/vendor/rails/railties/test/initializer_test.rb index 561f7b8b..ace0ccaf 100644 --- a/vendor/rails/railties/test/initializer_test.rb +++ b/vendor/rails/railties/test/initializer_test.rb @@ -309,7 +309,7 @@ class InitializerSetupI18nTests < Test::Unit::TestCase config.i18n.load_path << "my/other/locale.yml" Rails::Initializer.run(:initialize_i18n, config) - assert_equal [ + assert_equal [ File.expand_path(File.dirname(__FILE__) + "/../../activesupport/lib/active_support/locale/en.yml"), File.expand_path(File.dirname(__FILE__) + "/../../actionpack/lib/action_view/locale/en.yml"), File.expand_path(File.dirname(__FILE__) + "/../../activerecord/lib/active_record/locale/en.yml"), @@ -363,17 +363,31 @@ class InitializerDatabaseMiddlewareTest < Test::Unit::TestCase ensure ActionController::Base.session_store = store end + + def test_ensure_database_middleware_doesnt_use_action_controller_on_initializing + @config.frameworks -= [:action_controller] + store = ActionController::Base.session_store + ActionController::Base.session_store = ActiveRecord::SessionStore + + @config.middleware.expects(:use).with(ActiveRecord::ConnectionAdapters::ConnectionManagement) + @config.middleware.expects(:use).with(ActiveRecord::QueryCache) + + Rails::Initializer.run(:initialize_database_middleware, @config) + ensure + ActionController::Base.session_store = store + @config.frameworks += [:action_controller] + end end class InitializerViewPathsTest < Test::Unit::TestCase def setup @config = Rails::Configuration.new @config.frameworks = [:action_view, :action_controller, :action_mailer] - + ActionController::Base.stubs(:view_paths).returns(stub) ActionMailer::Base.stubs(:view_paths).returns(stub) end - + def test_load_view_paths_doesnt_perform_anything_when_action_view_not_in_frameworks @config.frameworks -= [:action_view] ActionController::Base.view_paths.expects(:load!).never @@ -396,4 +410,5 @@ class RailsRootTest < Test::Unit::TestCase def test_rails_dot_root_should_be_a_pathname assert_equal File.join(RAILS_ROOT, 'app', 'controllers'), Rails.root.join('app', 'controllers').to_s end -end \ No newline at end of file +end + diff --git a/vendor/rails/railties/test/vendor/gems/dummy-gem-h-1.0.0/.specification b/vendor/rails/railties/test/vendor/gems/dummy-gem-h-1.0.0/.specification new file mode 100644 index 00000000..b3f79309 --- /dev/null +++ b/vendor/rails/railties/test/vendor/gems/dummy-gem-h-1.0.0/.specification @@ -0,0 +1,29 @@ +--- !ruby/object:Gem::Specification +name: dummy-gem-h +version: !ruby/object:Gem::Version + version: 1.3.0 +platform: ruby +authors: +- "Nobody" +date: 2008-10-03 00:00:00 -04:00 +dependencies: +files: +- lib +- lib/dummy-gem-h.rb +require_paths: +- lib +required_ruby_version: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: "0" + version: +required_rubygems_version: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: "0" + version: +requirements: [] +specification_version: 2 +summary: Dummy Gem H diff --git a/vendor/rails/railties/test/vendor/gems/dummy-gem-h-1.0.0/lib/dummy-gem-h.rb b/vendor/rails/railties/test/vendor/gems/dummy-gem-h-1.0.0/lib/dummy-gem-h.rb new file mode 100644 index 00000000..0f912349 --- /dev/null +++ b/vendor/rails/railties/test/vendor/gems/dummy-gem-h-1.0.0/lib/dummy-gem-h.rb @@ -0,0 +1 @@ +DUMMY_GEM_H_VERSION="1.0.0" diff --git a/vendor/rails/railties/test/vendor/gems/dummy-gem-i-1.0.0/.specification b/vendor/rails/railties/test/vendor/gems/dummy-gem-i-1.0.0/.specification new file mode 100644 index 00000000..50b4969d --- /dev/null +++ b/vendor/rails/railties/test/vendor/gems/dummy-gem-i-1.0.0/.specification @@ -0,0 +1,41 @@ +--- !ruby/object:Gem::Specification +name: dummy-gem-i +version: !ruby/object:Gem::Version + version: 1.3.0 +platform: ruby +authors: +- "Nobody" +date: 2008-10-03 00:00:00 -04:00 +dependencies: +- !ruby/object:Gem::Dependency + name: dummy-gem-i + type: :runtime + version_requirement: + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: 1.0.0 + version: +extensions: +- ext/dummy-gem-i/extconf.rb +files: +- lib +- lib/dummy-gem-i.rb +require_paths: +- lib +required_ruby_version: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: "0" + version: +required_rubygems_version: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: "0" + version: +requirements: [] +specification_version: 2 +summary: Dummy Gem G diff --git a/vendor/rails/railties/test/vendor/gems/dummy-gem-i-1.0.0/ext/dummy-gem-i/Makefile b/vendor/rails/railties/test/vendor/gems/dummy-gem-i-1.0.0/ext/dummy-gem-i/Makefile new file mode 100644 index 00000000..e69de29b diff --git a/vendor/rails/railties/test/vendor/gems/dummy-gem-i-1.0.0/lib/dummy-gem-i.rb b/vendor/rails/railties/test/vendor/gems/dummy-gem-i-1.0.0/lib/dummy-gem-i.rb new file mode 100644 index 00000000..2f9a376c --- /dev/null +++ b/vendor/rails/railties/test/vendor/gems/dummy-gem-i-1.0.0/lib/dummy-gem-i.rb @@ -0,0 +1 @@ +DUMMY_GEM_I_VERSION="1.0.0" diff --git a/vendor/rails/railties/test/vendor/gems/dummy-gem-j-1.0.0/.specification b/vendor/rails/railties/test/vendor/gems/dummy-gem-j-1.0.0/.specification new file mode 100644 index 00000000..2c456546 --- /dev/null +++ b/vendor/rails/railties/test/vendor/gems/dummy-gem-j-1.0.0/.specification @@ -0,0 +1,41 @@ +--- !ruby/object:Gem::Specification +name: dummy-gem-j +version: !ruby/object:Gem::Version + version: 1.3.0 +platform: ruby +authors: +- "Nobody" +date: 2008-10-03 00:00:00 -04:00 +dependencies: +- !ruby/object:Gem::Dependency + name: dummy-gem-j + type: :runtime + version_requirement: + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: 1.0.0 + version: +extensions: +- ext/dummy-gem-j/extconf.rb +files: +- lib +- lib/dummy-gem-j.rb +require_paths: +- lib +required_ruby_version: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: "0" + version: +required_rubygems_version: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: "0" + version: +requirements: [] +specification_version: 2 +summary: Dummy Gem G diff --git a/vendor/rails/railties/test/vendor/gems/dummy-gem-j-1.0.0/lib/dummy-gem-j.rb b/vendor/rails/railties/test/vendor/gems/dummy-gem-j-1.0.0/lib/dummy-gem-j.rb new file mode 100644 index 00000000..8ecd363f --- /dev/null +++ b/vendor/rails/railties/test/vendor/gems/dummy-gem-j-1.0.0/lib/dummy-gem-j.rb @@ -0,0 +1 @@ +DUMMY_GEM_J_VERSION="1.0.0" diff --git a/vendor/rails/railties/test/vendor/gems/dummy-gem-k-1.0.0/.specification b/vendor/rails/railties/test/vendor/gems/dummy-gem-k-1.0.0/.specification new file mode 100644 index 00000000..20edd0f8 --- /dev/null +++ b/vendor/rails/railties/test/vendor/gems/dummy-gem-k-1.0.0/.specification @@ -0,0 +1,49 @@ +--- !ruby/object:Gem::Specification +name: dummy-gem-k +version: !ruby/object:Gem::Version + version: 1.3.0 +platform: ruby +authors: +- "Nobody" +date: 2008-10-03 00:00:00 -04:00 +dependencies: +- !ruby/object:Gem::Dependency + name: dummy-gem-k + type: :runtime + version_requirement: + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: 1.0.0 + version: +- !ruby/object:Gem::Dependency + name: dummy-gem-h + type: :development + version_requirement: + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: 1.0.0 + version: +files: +- lib +- lib/dummy-gem-k.rb +require_paths: +- lib +required_ruby_version: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: "0" + version: +required_rubygems_version: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: "0" + version: +requirements: [] +specification_version: 2 +summary: Dummy Gem I diff --git a/vendor/rails/railties/test/vendor/gems/dummy-gem-k-1.0.0/lib/dummy-gem-k.rb b/vendor/rails/railties/test/vendor/gems/dummy-gem-k-1.0.0/lib/dummy-gem-k.rb new file mode 100644 index 00000000..97fb1d69 --- /dev/null +++ b/vendor/rails/railties/test/vendor/gems/dummy-gem-k-1.0.0/lib/dummy-gem-k.rb @@ -0,0 +1 @@ +DUMMY_GEM_K_VERSION="1.0.0"