From 207fb1f7f204b72fa1d1fded1fc7dc00d98df7a5 Mon Sep 17 00:00:00 2001 From: Jacques Distler Date: Mon, 15 Oct 2007 12:16:54 -0500 Subject: [PATCH] New Version Sync with Latest Instiki Trunk. Migrate to Rails 1.2.5. Bump version number. --- CHANGELOG | 28 +- README | 127 +++-- app/controllers/application.rb | 2 +- app/models/page.rb | 2 +- instiki.bat | 2 + lib/page_renderer.rb | 6 +- .../plugins/action_cache/lib/action_cache.rb | 1 + vendor/rails/actionmailer/CHANGELOG | 10 + vendor/rails/actionmailer/Rakefile | 2 +- .../actionmailer/lib/action_mailer/version.rb | 2 +- vendor/rails/actionpack/CHANGELOG | 53 ++- vendor/rails/actionpack/Rakefile | 2 +- .../assertions/dom_assertions.rb | 4 +- .../assertions/model_assertions.rb | 2 +- .../assertions/response_assertions.rb | 3 + .../assertions/routing_assertions.rb | 1 + .../assertions/selector_assertions.rb | 2 + .../actionpack/lib/action_controller/base.rb | 17 +- .../lib/action_controller/caching.rb | 78 ++-- .../cgi_ext/pstore_performance_fix.rb | 30 ++ .../cgi_ext/raw_post_data_fix.rb | 2 +- .../lib/action_controller/cgi_process.rb | 17 +- .../lib/action_controller/cookies.rb | 8 +- .../lib/action_controller/filters.rb | 267 +++++++---- .../lib/action_controller/integration.rb | 52 ++- .../macros/in_place_editing.rb | 2 +- .../lib/action_controller/pagination.rb | 8 +- .../lib/action_controller/request.rb | 4 - .../lib/action_controller/resources.rb | 149 ++++-- .../lib/action_controller/routing.rb | 79 +++- .../lib/action_controller/test_process.rb | 7 +- .../lib/action_controller/url_rewriter.rb | 5 +- .../lib/action_controller/verification.rb | 1 + .../actionpack/lib/action_pack/version.rb | 2 +- .../rails/actionpack/lib/action_view/base.rb | 44 +- .../lib/action_view/compiled_templates.rb | 4 +- .../helpers/active_record_helper.rb | 36 +- .../lib/action_view/helpers/debug_helper.rb | 10 + .../action_view/helpers/deprecated_helper.rb | 3 + .../action_view/helpers/prototype_helper.rb | 50 +- .../test/activerecord/pagination_test.rb | 9 + .../controller/action_pack_assertions_test.rb | 13 + .../test/controller/addresses_render_test.rb | 5 +- .../actionpack/test/controller/base_test.rb | 2 +- .../test/controller/caching_test.rb | 5 +- .../actionpack/test/controller/cookie_test.rb | 11 + .../deprecated_base_methods_test.rb | 18 + .../test/controller/filter_params_test.rb | 1 + .../test/controller/filters_test.rb | 175 +++++-- .../test/controller/integration_test.rb | 101 +++- .../actionpack/test/controller/render_test.rb | 46 -- .../test/controller/resources_test.rb | 249 ++++++++-- .../test/controller/routing_test.rb | 4 +- .../actionpack/test/controller/test_test.rb | 16 + .../test/controller/url_rewriter_test.rb | 76 ++- .../test/controller/verification_test.rb | 15 + .../test/fixtures/test/hello_world.rxml | 3 +- .../test/template/asset_tag_helper_test.rb | 5 + .../test/template/compiled_templates_test.rb | 46 +- .../test/template/javascript_helper_test.rb | 8 +- .../test/template/number_helper_test.rb | 2 +- .../test/template/prototype_helper_test.rb | 26 +- vendor/rails/actionwebservice/CHANGELOG | 14 + vendor/rails/actionwebservice/Rakefile | 4 +- .../lib/action_web_service/version.rb | 2 +- vendor/rails/activerecord/CHANGELOG | 34 ++ vendor/rails/activerecord/Rakefile | 2 +- .../lib/active_record/acts/list.rb | 16 +- .../lib/active_record/acts/tree.rb | 7 + .../lib/active_record/associations.rb | 43 +- .../associations/association_collection.rb | 6 +- .../associations/has_many_association.rb | 4 +- .../has_many_through_association.rb | 10 + .../activerecord/lib/active_record/base.rb | 15 +- .../lib/active_record/calculations.rb | 4 +- .../connection_adapters/abstract/quoting.rb | 2 +- .../connection_adapters/oracle_adapter.rb | 1 + .../connection_adapters/sqlite_adapter.rb | 4 +- .../lib/active_record/deprecated_finders.rb | 6 +- .../lib/active_record/fixtures.rb | 2 +- .../lib/active_record/timestamp.rb | 9 - .../activerecord/lib/active_record/version.rb | 2 +- .../test/associations/eager_test.rb | 13 + .../test/associations/join_model_test.rb | 11 +- .../activerecord/test/associations_test.rb | 39 +- vendor/rails/activerecord/test/base_test.rb | 21 +- .../activerecord/test/fixtures/author.rb | 1 + .../activerecord/test/fixtures/binaries.yml | 437 ++++++++++++++++++ .../test/fixtures/db_definitions/schema.rb | 5 + .../activerecord/test/fixtures/developer.rb | 10 + .../rails/activerecord/test/fixtures_test.rb | 14 +- .../rails/activerecord/test/migration_test.rb | 19 +- vendor/rails/activerecord/test/mixin_test.rb | 47 ++ .../activerecord/test/validations_test.rb | 4 +- vendor/rails/activesupport/CHANGELOG | 16 + .../lib/active_support/core_ext/blank.rb | 12 +- .../core_ext/hash/conversions.rb | 51 +- .../core_ext/module/introspection.rb | 14 + .../lib/active_support/dependencies.rb | 6 +- .../lib/active_support/json/encoders/core.rb | 8 +- .../lib/active_support/multibyte/chars.rb | 12 +- .../lib/active_support/version.rb | 2 +- .../test/core_ext/hash_ext_test.rb | 37 ++ .../test/core_ext/module_test.rb | 8 + .../activesupport/test/dependencies_test.rb | 11 + vendor/rails/activesupport/test/json_test.rb | 97 ++++ vendor/rails/railties/CHANGELOG | 26 +- vendor/rails/railties/README | 35 +- vendor/rails/railties/Rakefile | 10 +- vendor/rails/railties/environments/boot.rb | 30 +- .../railties/environments/environment.rb | 30 +- vendor/rails/railties/lib/dispatcher.rb | 3 +- vendor/rails/railties/lib/initializer.rb | 42 +- vendor/rails/railties/lib/rails/version.rb | 2 +- .../components/scaffold/scaffold_generator.rb | 2 +- .../scaffold_resource_generator.rb | 1 + vendor/rails/railties/lib/railties_path.rb | 2 +- .../rails/railties/lib/tasks/framework.rake | 8 +- vendor/rails/railties/lib/tasks/routes.rake | 17 + vendor/rails/release.rb | 4 +- 120 files changed, 2592 insertions(+), 662 deletions(-) create mode 100755 instiki.bat create mode 100644 vendor/rails/actionpack/lib/action_controller/cgi_ext/pstore_performance_fix.rb create mode 100644 vendor/rails/activerecord/test/fixtures/binaries.yml create mode 100644 vendor/rails/activesupport/test/json_test.rb create mode 100644 vendor/rails/railties/lib/tasks/routes.rake diff --git a/CHANGELOG b/CHANGELOG index f4f13a24..22f9d832 100755 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,9 +1,30 @@ - * TRUNK: +------------------------------------------------------------------------------ + * 0.12.0: + + 0.12 is mainly a bugfix release. We recommend all instiki Users to upgrade. + In this version, some security holes where fixed + - An XSS vulnerability in categories + - An XSS vulnerability in + - fixes that Instiki allows "dangerous" operations as HTTP GETs + + as well as some other small improvements. + - fixes for instiki running on mongrel + - fixes for instiki running on mongrel_cluster + + We added a lot of tests, synced with Jacques Distler's version and fixed + small bugs as well. A note to Mac OSX users: use the Ruby One-Click-Installer + for OSX ( http://rubyosx.com ) or make sure you are not running into problems + with sqlite (see http://instiki.5uper.net/instiki/show/SQLite+issues+on+OSX) + +------------------------------------------------------------------------------ + * 0.11.pl1 - ANTISPAM: - updated and included spam_patterns.txt - included dnsbl_check - DNS Blackhole Lists check [thanks to joost from http://www.spacebabies.nl ] + - included the form-spam-protection rails plugin + http://form-spam-protection.googlecode.com/svn/form_spam_protection/ - BUGFIXES: - fix PDF output not to contain garbage chars [Jesse Newland] @@ -16,10 +37,9 @@ - lots of small bugfixes and changes - UPDATES: - - Rails 1.2 tested and packaged with instiki + - Rails 1.2.1 tested and packaged with instiki - updated RubyZip to 0.9.1 - - updated RedCloth to 3.0.4 - - updated packaged sqlite3-ruby to 1.2.0 + - updated packaged sqlite3-ruby - FEATURES: - fix: being logged in on more Webs at once works now [Jaques Distler] diff --git a/README b/README index ffcab202..a65cd0fc 100755 --- a/README +++ b/README @@ -1,39 +1,61 @@ -===What is Instiki? -Admitted, it's YetAnotherWikiClone[http://c2.com/cgi/wiki?WikiWikiClones], but with a strong focus -on simplicity of installation and running: += Instiki -Step 1. Download -Step 2. Run "instiki" +Instiki is a wiki clone so pretty and easy to set up, you'll wonder if it’s really a wiki. Runs on Rails and focuses on portability and stability. Supports file uploads, PDF export, RSS, multiple users and password protection. Some use Instiki as a CMS (Content Management System) because of it's ability to export static pages. -If you are on Windows: -"Step 3. Chuckle... "There's no step three!" (TM)" +Instiki lowers the barriers of interest for when you might consider using a wiki. It's so simple to get running that you'll find yourself using it for anything -- taking notes, brainstorming, organizing a gathering. -You're now running a perfectly suitable wiki on port 2500 -that'll present you with one-step setup, followed by a textarea for the home page -on http://localhost:2500 -Instiki lowers the barriers of interest for when you might consider -using a wiki. It's so simple to get running that you'll find yourself -using it for anything -- taking notes, brainstorming, organizing a -gathering. +== Supported Platforms -Having said all that, if you are not on Windows, in this version of Instiki it is a somewhat different story. -Since the author has no Linux or Mac at hand, and Instiki is moving to a SQL-based backend, this is what it takes -to install (until somebody sends a patch to properly package Instiki for all those other platforms): +Instiki only relies on Ruby - the sole external dependency (it includes all other dependencies). Any OS that can run Ruby can run Instiki - that includes Windows, Linux, Mac OS X and most known Unix flavors. -3. Kill "instiki" -4. Install SQLite 3 database engine from http://www.sqlite.org/ -5. Install SQLite 3 driver for Ruby from http://sqlite-ruby.rubyforge.org/ -6. Install Rake from http://rake.rubyforge.org/ -7. Execute rm -f db/*.db -8. Execute 'rake environment RAILS_ENV=production migrate' -9. Make an embarrassed sigh (as I do while writing this) -10. Run 'instiki' again -11. Pat yourself on the shoulder for being such a talented geek -12. At least, there is no step twelve! (TM) +Instiki on BeOS, Amiga OS, OS2, Zeta OS and support for various exotic Platforms is planned. Mostly it already works, if Ruby runs there (download the linux version in this case). Please contact parasew if you want to help out for your OS that is not listed. Please also get in touch if you are able to create an instiki package for your favorite unix or linux distribution. + + +== 3 easy Steps to get the Instiki experience + + Step 1. Get Ruby, Download Instiki + Step 2. Run "instiki" + Step 3. Chuckle... "There's no step three!" (TM) + + +== Details + +You need at least Ruby Version 1.8.4 installed on your System. The second dependency is a Database System, but don't worry, maybe you are already served. + + +=== If you are on Windows + +- Get the *Ruby One-Click Installer - Windows* http://rubyforge.org/projects/rubyinstaller +- double-click instiki.bat or instiki.cmd and there you go! + +if you are running Windows 95, 98 or ME and cannot get instiki to run, try Version 0.11.pl1 which is the last instiki Version to support that old-style OS's. Please update to some Unix-OS or complain to the Ruby on Rails List at http://www.ruby-forum.com/forum/3 (Rails does not support your old Windows.) + + +=== If you are on Mac OSX + +Since the Apple guys really screwed it up, having an old Ruby Version (1.8.2) and a broken Readline Library with MacOSX Tiger, you have to + +- use the Ruby One-Click-Installer for OSX ( http://rubyosx.com ) if you don't already have macports' Ruby +- make sure you read http://instiki.5uper.net/instiki/show/SQLite+issues+on+OSX +- run "ruby instiki.rb" via command-line in the directory + + +=== If you are on Linux + + +=== Any other System + +- get Ruby for your System, compile if nessesary: http://ruby-lang.org +- get SQLite or compile from http://sqlite.org (you can also use mysql or any other supported database system if you want) +- run instiki + +You're now running a perfectly suitable wiki on port 2500 that'll present you with one-step setup, followed by a textarea for the home page on http://localhost:2500 + + +== Features -===Features: * Regular expression search: Find deep stuff really fast * Revisions: Follow the changes on every page from birth. Rollback to an earlier rev * Export to HTML or markup in a zip: Take the entire wiki with you home or for reference @@ -42,24 +64,27 @@ to install (until somebody sends a patch to properly package Instiki for all tho * Password-protected webs: Keep it private * Authors: Each revision is associated with an author, so you can see who changed what * Reference tracker: Which other pages are pointing to the current? -* Speed: Using Madelein[http://madeleine.sourceforge.net] for persistence (all pages are in memory) -* Three markup choices: Textile[http://www.textism.com/tools/textile] - (default / RedCloth[http://www.whytheluckystiff.net/ruby/redcloth]), +* Three markup choices: Textile http://www.textism.com/tools/textile + (default / RedCloth http://www.whytheluckystiff.net/ruby/redcloth ), Markdown (BlueCloth[http://bluecloth.rubyforge.org]), and RDoc[http://rdoc.sourceforge.net/doc] -* Embedded webserver: Through WEBrick[http://www.webrick.org] +* Embedded webserver: Through WEBrick[http://www.webrick.org], also runs on Mongel if you want to. * Internationalization: Wiki words in any latin, greek, cyrillian, or armenian characters * Color diffs: Track changes through revisions -* Definitely can run on SQLite and MySQL -* May be able to run on Postgres, Oracle, DB2 and SqlServer. If you try this, and it works - (or, it doesn't, but you make it work) please write about it on Instiki.org. +* Runs on SQLite per default, can be configured to run on PostgreSQL, MySQL, DB2, Firebird, Openbase, Oracle, SQL Server or Sybase + + +== Command-line options: -===Command-line options: * Run "ruby instiki --help" -===History: + +== History: + * See CHANGELOG -===Migrating Instiki 0.10.2 storage to Instiki 0.11.0 database + +== Migrating Instiki 0.10.2 storage to Instiki 0.11.0 database + 1. Install Instiki 0.11 and check that it works (you should be able to create a web, edit and save a HomePage) 2. Execute ruby script\import_storage \ @@ -81,7 +106,9 @@ to install (until somebody sends a patch to properly package Instiki for all tho The most common migration problem is this: if you open All Pages and see a lot of orphaned pages, you forgot to run ruby script\reset_references after importing the data. + ===Upgrading from Instiki-AR Beta 1 + In Beta 2, we switch to ActiveRecord:Migrations. Therefore: 1. Back up your production database. 2. Open command-line session to your database and execute: @@ -93,21 +120,33 @@ Step 2 creates a table that tells to ActiveRecord:Migrations that the current ve of this database is 1 (corresponding to Beta 1), and step 3 makes it up-to-date with the current version of Instiki. -===Download the latest release from: + +== Download the latest release from: + * http://rubyforge.org/project/showfiles.php?group_id=186 -===Visit the "official" Instiki wiki: + +== Visit the "official" Instiki wiki: + * http://instiki.org -===License: + +== License: + * same as Ruby's + --- + Authors:: Versions 0.0 to 0.9.1:: David Heinemeier Hansson -Email:: david@loudthinking.com -Weblog:: http://www.loudthinking.com +Email:: david[AT]loudthinking.com +Weblog:: http://www.loudthinking.com[http://www.loudthinking.com] From 0.9.2 onwards:: Alexey Verkhovsky -Email:: alex@verk.info +Email:: alex[AT]verk.info + +From 0.11 onwards:: Matthias Tarasiewicz and 5uper.net +Email:: parasew[AT]gmail.com +Website:: http://5uper.net[http://5uper.net] diff --git a/app/controllers/application.rb b/app/controllers/application.rb index 236c0df6..02a1aac2 100644 --- a/app/controllers/application.rb +++ b/app/controllers/application.rb @@ -219,7 +219,7 @@ end module Instiki module VERSION #:nodoc: MAJOR = 0 - MINOR = 12 + MINOR = 13 TINY = 0 SUFFIX = '(MML+)' PRERELEASE = 'pre' # false diff --git a/app/models/page.rb b/app/models/page.rb index c5f48d43..9861c6e9 100644 --- a/app/models/page.rb +++ b/app/models/page.rb @@ -25,7 +25,7 @@ class Page < ActiveRecord::Base if (revisions_size > 0) && continous_revision?(time, author) current_revision.update_attributes(:content => content, :revised_at => time) else - revisions.create(:content => content, :author => author, :revised_at => time) + revisions.build(:content => content, :author => author, :revised_at => time) end save self diff --git a/instiki.bat b/instiki.bat new file mode 100755 index 00000000..00461495 --- /dev/null +++ b/instiki.bat @@ -0,0 +1,2 @@ +set PATH=.\lib\native\win32;%PATH% +ruby.exe script\server -e production \ No newline at end of file diff --git a/lib/page_renderer.rb b/lib/page_renderer.rb index 2291c818..936327dc 100644 --- a/lib/page_renderer.rb +++ b/lib/page_renderer.rb @@ -143,19 +143,19 @@ class PageRenderer else link_type = WikiReference.link_type(@revision.page.web, referenced_name) end - references.create :referenced_name => referenced_name, :link_type => link_type + references.build :referenced_name => referenced_name, :link_type => link_type end include_chunks = rendering_result.find_chunks(Include) includes = include_chunks.map { |c| ( c.escaped? ? nil : c.page_name ) }.compact.uniq includes.each do |included_page_name| - references.create :referenced_name => included_page_name, + references.build :referenced_name => included_page_name, :link_type => WikiReference::INCLUDED_PAGE end categories = rendering_result.find_chunks(Category).map { |cat| cat.list }.flatten categories.each do |category| - references.create :referenced_name => category, :link_type => WikiReference::CATEGORY + references.build :referenced_name => category, :link_type => WikiReference::CATEGORY end end end diff --git a/vendor/plugins/action_cache/lib/action_cache.rb b/vendor/plugins/action_cache/lib/action_cache.rb index 79544126..1fd552cb 100644 --- a/vendor/plugins/action_cache/lib/action_cache.rb +++ b/vendor/plugins/action_cache/lib/action_cache.rb @@ -1,5 +1,6 @@ require 'yaml' require 'time' +require 'md5' module ActionController class AbstractResponse #:nodoc: diff --git a/vendor/rails/actionmailer/CHANGELOG b/vendor/rails/actionmailer/CHANGELOG index 968f621a..aab72a91 100644 --- a/vendor/rails/actionmailer/CHANGELOG +++ b/vendor/rails/actionmailer/CHANGELOG @@ -1,3 +1,13 @@ +*1.3.5* (October 12th, 2007) + +* Depend on Action Pack 1.13.5 + + +*1.3.4* (October 4th, 2007) + +* Depend on Action Pack 1.13.4 + + *1.3.3* (March 12th, 2007) * Depend on Action Pack 1.13.3 diff --git a/vendor/rails/actionmailer/Rakefile b/vendor/rails/actionmailer/Rakefile index aac65b21..5bb9f1d0 100755 --- a/vendor/rails/actionmailer/Rakefile +++ b/vendor/rails/actionmailer/Rakefile @@ -54,7 +54,7 @@ spec = Gem::Specification.new do |s| s.rubyforge_project = "actionmailer" s.homepage = "http://www.rubyonrails.org" - s.add_dependency('actionpack', '= 1.13.3' + PKG_BUILD) + s.add_dependency('actionpack', '= 1.13.5' + PKG_BUILD) s.has_rdoc = true s.requirements << 'none' diff --git a/vendor/rails/actionmailer/lib/action_mailer/version.rb b/vendor/rails/actionmailer/lib/action_mailer/version.rb index 03f075fb..498af239 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 = 1 MINOR = 3 - TINY = 3 + TINY = 5 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/vendor/rails/actionpack/CHANGELOG b/vendor/rails/actionpack/CHANGELOG index c298ff56..082d6bae 100644 --- a/vendor/rails/actionpack/CHANGELOG +++ b/vendor/rails/actionpack/CHANGELOG @@ -1,6 +1,55 @@ +*1.13.5* (October 12th, 2007) + +* Backport: allow array and hash query parameters. Array route parameters are converted/to/a/path as before. #6765, #7047, #7462 [bgipsy, Jeremy McAnally, Dan Kubb, brendan, Diego Algorta Casamayou] + +* Fix in place editor's setter action with non-string fields. #7418 [Andreas] + + +*1.13.4* (October 4th, 2007) + +* Only accept session ids from cookies, prevents session fixation attacks. [bradediger] + +* Change the resource seperator from ; to / change the generated routes to use the new-style named routes. e.g. new_group_user_path(@group) instead of group_new_user_path(@group). [pixeltrix] + +* Integration tests: introduce methods for other HTTP methods. #6353 [caboose] + +* Improve performance of action caching. Closes #8231 [skaes] + +* Fix errors with around_filters which do not yield, restore 1.1 behaviour with after filters. Closes #8891 [skaes] + + After filters will *no longer* be run if an around_filter fails to yield, users relying on + this behaviour are advised to put the code in question after a yield statement in an around filter. + +* Allow you to delete cookies with options. Closes #3685 [josh, Chris Wanstrath] + +* Deprecate pagination. Install the classic_pagination plugin for forward compatibility, or move to the superior will_paginate plugin. #8157 [Mislav Marohnic] + +* Fix filtered parameter logging with nil parameter values. #8422 [choonkeat] + +* Integration tests: alias xhr to xml_http_request and add a request_method argument instead of always using POST. #7124 [Nik Wakelin, Francois Beausoleil, Wizard] + +* Document caches_action. #5419 [Jarkko Laine] + +* observe_form always sends the serialized form. #5271 [manfred, normelton@gmail.com] + +* Update UrlWriter to accept :anchor parameter. Closes #6771. [octopod] + +* Replace the current block/continuation filter chain handling by an implementation based on a simple loop. Closes #8226 [Stefan Kaes] + +* Return the string representation from an Xml Builder when rendering a partial. #5044 [tpope] + +* Cleaned up, corrected, and mildly expanded ActionPack documentation. Closes #7190 [jeremymcanally] + +* Small collection of ActionController documentation cleanups. Closes #7319 [jeremymcanally] + +* Performance: patch cgi/session/pstore to require digest/md5 once rather than per #initialize. #7583 [Stefan Kaes] + +* Deprecation: verification with :redirect_to => :named_route shouldn't be deprecated. #7525 [Justin French] + + *1.13.3* (March 12th, 2007) -* Apply [5709] to stable. +* Fix a bug in Routing where a parameter taken from the path of the current request could not be used as a query parameter for the next. #6752 [Nicholas Seckar] * session_enabled? works with session :off. #6680 [Catfish] @@ -440,7 +489,7 @@ * Avoid naming collision among compiled view methods. [Jeremy Kemper] -* Fix CGI extensions when they expect string but get nil in Windows. Closes #5276 [mislav@nippur.irb.hr] +* Fix CGI extensions when they expect string but get nil in Windows. Closes #5276 [Mislav Marohnic] * Determine the correct template_root for deeply nested components. #2841 [s.brink@web.de] diff --git a/vendor/rails/actionpack/Rakefile b/vendor/rails/actionpack/Rakefile index 4bca6b6d..1b2af373 100755 --- a/vendor/rails/actionpack/Rakefile +++ b/vendor/rails/actionpack/Rakefile @@ -75,7 +75,7 @@ spec = Gem::Specification.new do |s| s.has_rdoc = true s.requirements << 'none' - s.add_dependency('activesupport', '= 1.4.2' + PKG_BUILD) + s.add_dependency('activesupport', '= 1.4.4' + PKG_BUILD) s.require_path = 'lib' s.autorequire = 'action_controller' diff --git a/vendor/rails/actionpack/lib/action_controller/assertions/dom_assertions.rb b/vendor/rails/actionpack/lib/action_controller/assertions/dom_assertions.rb index d1eea59e..355080fe 100644 --- a/vendor/rails/actionpack/lib/action_controller/assertions/dom_assertions.rb +++ b/vendor/rails/actionpack/lib/action_controller/assertions/dom_assertions.rb @@ -1,7 +1,7 @@ module ActionController module Assertions module DomAssertions - # test 2 html strings to be equivalent, i.e. identical up to reordering of attributes + # Test two HTML strings for equivalency (e.g., identical up to reordering of attributes) def assert_dom_equal(expected, actual, message="") clean_backtrace do expected_dom = HTML::Document.new(expected).root @@ -11,7 +11,7 @@ module ActionController end end - # negated form of +assert_dom_equivalent+ + # The negated form of +assert_dom_equivalent+. def assert_dom_not_equal(expected, actual, message="") clean_backtrace do expected_dom = HTML::Document.new(expected).root diff --git a/vendor/rails/actionpack/lib/action_controller/assertions/model_assertions.rb b/vendor/rails/actionpack/lib/action_controller/assertions/model_assertions.rb index a9bcd7db..5fc5c81c 100644 --- a/vendor/rails/actionpack/lib/action_controller/assertions/model_assertions.rb +++ b/vendor/rails/actionpack/lib/action_controller/assertions/model_assertions.rb @@ -1,7 +1,7 @@ module ActionController module Assertions module ModelAssertions - # ensures that the passed record is valid by active record standards. returns the error messages if not + # Ensures that the passed record is valid by ActiveRecord standards and returns any error messages if it is not. def assert_valid(record) clean_backtrace do assert record.valid?, record.errors.full_messages.join("\n") 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 bcb07e67..1d68fd86 100644 --- a/vendor/rails/actionpack/lib/action_controller/assertions/response_assertions.rb +++ b/vendor/rails/actionpack/lib/action_controller/assertions/response_assertions.rb @@ -69,6 +69,7 @@ module ActionController end if value.respond_to?(:[]) && value['controller'] + value['controller'] = value['controller'].to_s if key == :actual && value['controller'].first != '/' && !value['controller'].include?('/') new_controller_path = ActionController::Routing.controller_relative_to(value['controller'], @controller.class.controller_path) value['controller'] = new_controller_path if value['controller'] != new_controller_path && ActionController::Routing.possible_controllers.include?(new_controller_path) @@ -120,6 +121,7 @@ module ActionController end private + # Recognizes the route for a given path. def recognized_request_for(path, request_method = nil) path = "/#{path}" unless path.first == '/' @@ -132,6 +134,7 @@ module ActionController request end + # Proxy to to_param if the object will respond to it. def parameterize(value) value.respond_to?(:to_param) ? value.to_param : value end diff --git a/vendor/rails/actionpack/lib/action_controller/assertions/routing_assertions.rb b/vendor/rails/actionpack/lib/action_controller/assertions/routing_assertions.rb index 11a649c4..6cd4d48b 100644 --- a/vendor/rails/actionpack/lib/action_controller/assertions/routing_assertions.rb +++ b/vendor/rails/actionpack/lib/action_controller/assertions/routing_assertions.rb @@ -82,6 +82,7 @@ module ActionController end private + # Recognizes the route for a given path. def recognized_request_for(path, request_method = nil) path = "/#{path}" unless path.first == '/' diff --git a/vendor/rails/actionpack/lib/action_controller/assertions/selector_assertions.rb b/vendor/rails/actionpack/lib/action_controller/assertions/selector_assertions.rb index a5267e20..54d4f8d5 100644 --- a/vendor/rails/actionpack/lib/action_controller/assertions/selector_assertions.rb +++ b/vendor/rails/actionpack/lib/action_controller/assertions/selector_assertions.rb @@ -561,6 +561,8 @@ module ActionController # RJS encodes double quotes and line breaks. unescaped= rjs_string.gsub('\"', '"') unescaped.gsub!('\n', "\n") + unescaped.gsub!('\076', '>') + unescaped.gsub!('\074', '<') # RJS encodes non-ascii characters. unescaped.gsub!(RJS_PATTERN_UNICODE_ESCAPED_CHAR) {|u| [$1.hex].pack('U*')} unescaped diff --git a/vendor/rails/actionpack/lib/action_controller/base.rb b/vendor/rails/actionpack/lib/action_controller/base.rb index 3c21c868..4450b089 100755 --- a/vendor/rails/actionpack/lib/action_controller/base.rb +++ b/vendor/rails/actionpack/lib/action_controller/base.rb @@ -7,7 +7,6 @@ require 'action_controller/url_rewriter' require 'action_controller/status_codes' require 'drb' require 'set' -require 'md5' module ActionController #:nodoc: class ActionControllerError < StandardError #:nodoc: @@ -293,6 +292,10 @@ module ActionController #:nodoc: # Turn on +ignore_missing_templates+ if you want to unit test actions without making the associated templates. cattr_accessor :ignore_missing_templates + # Controls the resource action separator + @@resource_action_separator = "/" + cattr_accessor :resource_action_separator + # Holds the request object that's primarily used to get environment variables through access like # request.env["REQUEST_URI"]. attr_internal :request @@ -394,7 +397,8 @@ module ActionController #:nodoc: elsif value.is_a?(Hash) filtered_parameters[key] = filter_parameters(value) elsif block_given? - key, value = key.dup, value.dup + key = key.dup + value = value.dup if value yield key, value filtered_parameters[key] = value else @@ -539,6 +543,7 @@ module ActionController #:nodoc: self.class.controller_path end + # Test whether the session is enabled for this request. def session_enabled? request.session_options && request.session_options[:disabled] != false end @@ -600,12 +605,6 @@ module ActionController #:nodoc: # _Deprecation_ _notice_: This used to have the signatures # render_partial(partial_path = default_template_name, object = nil, local_assigns = {}) and # render_partial_collection(partial_name, collection, partial_spacer_template = nil, local_assigns = {}). - # == Automatic etagging - # - # Rendering will automatically insert the etag header on 200 OK responses. The etag is calculated using MD5 of the - # response body. If a request comes in that has a matching etag, the response will be changed to a 304 Not Modified - # and the response body will be set to an empty string. - # # # === Rendering a template # @@ -829,8 +828,6 @@ module ActionController #:nodoc: else response.body = text end - - response.body end def render_javascript(javascript, status = nil, append_response = true) #:nodoc: diff --git a/vendor/rails/actionpack/lib/action_controller/caching.rb b/vendor/rails/actionpack/lib/action_controller/caching.rb index 768f139a..94e44c9c 100644 --- a/vendor/rails/actionpack/lib/action_controller/caching.rb +++ b/vendor/rails/actionpack/lib/action_controller/caching.rb @@ -1,5 +1,6 @@ require 'fileutils' require 'uri' +require 'set' module ActionController #:nodoc: # Caching is a cheap way of speeding up slow applications by keeping the result of calculations, renderings, and database calls @@ -163,13 +164,24 @@ module ActionController #:nodoc: module Actions def self.included(base) #:nodoc: base.extend(ClassMethods) - base.send(:attr_accessor, :rendered_action_cache) + base.class_eval do + attr_accessor :rendered_action_cache, :action_cache_path + alias_method_chain :protected_instance_variables, :action_caching + end end - module ClassMethods #:nodoc: + def protected_instance_variables_with_action_caching + protected_instance_variables_without_action_caching + %w(@action_cache_path) + end + + module ClassMethods + # Declares that +actions+ should be cached. + # See ActionController::Caching::Actions for details. def caches_action(*actions) return unless perform_caching - around_filter(ActionCacheFilter.new(*actions)) + action_cache_filter = ActionCacheFilter.new(*actions) + before_filter action_cache_filter + after_filter action_cache_filter end end @@ -185,70 +197,59 @@ module ActionController #:nodoc: end class ActionCacheFilter #:nodoc: - def initialize(*actions, &block) - @actions = actions + def initialize(*actions) + @actions = Set.new actions end def before(controller) - return unless @actions.include?(controller.action_name.intern) - action_cache_path = ActionCachePath.new(controller) - if cache = controller.read_fragment(action_cache_path.path) + return unless @actions.include?(controller.action_name.to_sym) + cache_path = ActionCachePath.new(controller, {}) + if cache = controller.read_fragment(cache_path.path) controller.rendered_action_cache = true - set_content_type!(action_cache_path) + set_content_type!(controller, cache_path.extension) controller.send(:render_text, cache) false + else + controller.action_cache_path = cache_path end end def after(controller) - return if !@actions.include?(controller.action_name.intern) || controller.rendered_action_cache - controller.write_fragment(ActionCachePath.path_for(controller), controller.response.body) + return if !@actions.include?(controller.action_name.to_sym) || controller.rendered_action_cache + controller.write_fragment(controller.action_cache_path.path, controller.response.body) end private - - def set_content_type!(action_cache_path) - if extention = action_cache_path.extension - content_type = Mime::EXTENSION_LOOKUP[extention] - action_cache_path.controller.response.content_type = content_type.to_s - end + def set_content_type!(controller, extension) + controller.response.content_type = Mime::EXTENSION_LOOKUP[extension].to_s if extension end end class ActionCachePath - attr_reader :controller, :options + attr_reader :path, :extension class << self - def path_for(*args, &block) - new(*args).path + def path_for(controller, options) + new(controller, options).path end end def initialize(controller, options = {}) - @controller = controller - @options = options - end - - def path - return @path if @path - @path = controller.url_for(options).split('://').last - normalize! - add_extension! - URI.unescape(@path) - end - - def extension - @extension ||= extract_extension(controller.request.path) + @extension = extract_extension(controller.request.path) + path = controller.url_for(options).split('://').last + normalize!(path) + add_extension!(path, @extension) + @path = URI.unescape(path) end private - def normalize! - @path << 'index' if @path.last == '/' + def normalize!(path) + path << 'index' if path[-1] == ?/ end - def add_extension! - @path << ".#{extension}" if extension + def add_extension!(path, extension) + path << ".#{extension}" if extension end def extract_extension(file_path) @@ -472,7 +473,6 @@ module ActionController #:nodoc: end def write(name, value, options = nil) #:nodoc: - File.umask(0006) ensure_cache_path(File.dirname(real_file_path(name))) File.open(real_file_path(name), "wb+") { |f| f.write(value) } rescue => e diff --git a/vendor/rails/actionpack/lib/action_controller/cgi_ext/pstore_performance_fix.rb b/vendor/rails/actionpack/lib/action_controller/cgi_ext/pstore_performance_fix.rb new file mode 100644 index 00000000..79e427a3 --- /dev/null +++ b/vendor/rails/actionpack/lib/action_controller/cgi_ext/pstore_performance_fix.rb @@ -0,0 +1,30 @@ +# CGI::Session::PStore.initialize requires 'digest/md5' on every call. +# This makes sense when spawning processes per request, but is +# unnecessarily expensive when serving requests from a long-lived +# process. +require 'cgi/session' +require 'cgi/session/pstore' +require 'digest/md5' + +class CGI::Session::PStore #:nodoc: + def initialize(session, option={}) + dir = option['tmpdir'] || Dir::tmpdir + prefix = option['prefix'] || '' + id = session.session_id + md5 = Digest::MD5.hexdigest(id)[0,16] + path = dir+"/"+prefix+md5 + path.untaint + if File::exist?(path) + @hash = nil + else + unless session.new_session + raise CGI::Session::NoSession, "uninitialized session" + end + @hash = {} + end + @p = ::PStore.new(path) + @p.transaction do |p| + File.chmod(0600, p.path) + end + end +end diff --git a/vendor/rails/actionpack/lib/action_controller/cgi_ext/raw_post_data_fix.rb b/vendor/rails/actionpack/lib/action_controller/cgi_ext/raw_post_data_fix.rb index 4c124cb2..4f6fbce6 100644 --- a/vendor/rails/actionpack/lib/action_controller/cgi_ext/raw_post_data_fix.rb +++ b/vendor/rails/actionpack/lib/action_controller/cgi_ext/raw_post_data_fix.rb @@ -65,7 +65,7 @@ class CGI #:nodoc: if env_qs.blank? && !(uri = env_table['REQUEST_URI']).blank? uri.split('?', 2)[1] || '' else - env_qs + env_qs || '' end end end diff --git a/vendor/rails/actionpack/lib/action_controller/cgi_process.rb b/vendor/rails/actionpack/lib/action_controller/cgi_process.rb index efb2c615..efbe558f 100644 --- a/vendor/rails/actionpack/lib/action_controller/cgi_process.rb +++ b/vendor/rails/actionpack/lib/action_controller/cgi_process.rb @@ -2,6 +2,7 @@ require 'action_controller/cgi_ext/cgi_ext' require 'action_controller/cgi_ext/cookie_performance_fix' require 'action_controller/cgi_ext/raw_post_data_fix' require 'action_controller/cgi_ext/session_performance_fix' +require 'action_controller/cgi_ext/pstore_performance_fix' module ActionController #:nodoc: class Base @@ -12,8 +13,8 @@ module ActionController #:nodoc: # (default). Additionally, there is CGI::Session::DRbStore and CGI::Session::ActiveRecordStore. Read more about these in # lib/action_controller/session. # * :session_key - the parameter name used for the session id. Defaults to '_session_id'. - # * :session_id - the session id to use. If not provided, then it is retrieved from the +session_key+ parameter - # of the request, or automatically generated for a new session. + # * :session_id - the session id to use. If not provided, then it is retrieved from the +session_key+ cookie, or + # automatically generated for a new session. # * :new_session - if true, force creation of a new session. If not set, a new session is only created if none currently # exists. If false, a new session is never created, and if none currently exists and the +session_id+ option is not set, # an ArgumentError is raised. @@ -23,6 +24,8 @@ module ActionController #:nodoc: # server. # * :session_secure - if +true+, this session will only work over HTTPS. # * :session_path - the path for which this session applies. Defaults to the directory of the CGI script. + # * :cookie_only - if +true+ (the default), session IDs will only be accepted from cookies and not from + # the query string or POST parameters. This protects against session fixation attacks. def self.process_cgi(cgi = CGI.new, session_options = {}) new.process_cgi(cgi, session_options) end @@ -33,18 +36,21 @@ module ActionController #:nodoc: end class CgiRequest < AbstractRequest #:nodoc: - attr_accessor :cgi, :session_options + attr_accessor :cgi, :session_options, :cookie_only + class SessionFixationAttempt < StandardError; end #:nodoc: DEFAULT_SESSION_OPTIONS = { :database_manager => CGI::Session::PStore, :prefix => "ruby_sess.", - :session_path => "/" + :session_path => "/", + :cookie_only => true } unless const_defined?(:DEFAULT_SESSION_OPTIONS) def initialize(cgi, session_options = {}) @cgi = cgi @session_options = session_options @env = @cgi.send(:env_table) + @cookie_only = session_options.delete :cookie_only super() end @@ -108,6 +114,9 @@ module ActionController #:nodoc: @session = Hash.new else stale_session_check! do + if @cookie_only && request_parameters[session_options_with_string_keys['session_key']] + raise SessionFixationAttempt + end case value = session_options_with_string_keys['new_session'] when true @session = new_session diff --git a/vendor/rails/actionpack/lib/action_controller/cookies.rb b/vendor/rails/actionpack/lib/action_controller/cookies.rb index 52423aa6..d337491e 100644 --- a/vendor/rails/actionpack/lib/action_controller/cookies.rb +++ b/vendor/rails/actionpack/lib/action_controller/cookies.rb @@ -62,9 +62,11 @@ module ActionController #:nodoc: end # Removes the cookie on the client machine by setting the value to an empty string - # and setting its expiration date into the past - def delete(name) - set_cookie("name" => name.to_s, "value" => "", "expires" => Time.at(0)) + # and setting its expiration date into the past. Like []=, you can pass in an options + # hash to delete cookies with extra data such as a +path+. + def delete(name, options = {}) + options.stringify_keys! + set_cookie(options.merge("name" => name.to_s, "value" => "", "expires" => Time.at(0))) end private diff --git a/vendor/rails/actionpack/lib/action_controller/filters.rb b/vendor/rails/actionpack/lib/action_controller/filters.rb index 3290deff..11d23742 100644 --- a/vendor/rails/actionpack/lib/action_controller/filters.rb +++ b/vendor/rails/actionpack/lib/action_controller/filters.rb @@ -214,9 +214,10 @@ module ActionController #:nodoc: # == Filter Chain Halting # # before_filter and around_filter may halt the request - # before controller action is run. This is useful, for example, to deny + # before a controller action is run. This is useful, for example, to deny # access to unauthenticated users or to redirect from http to https. # Simply return false from the filter or call render or redirect. + # After filters will not be executed if the filter chain is halted. # # Around filters halt the request unless the action block is called. # Given these filters @@ -238,12 +239,12 @@ module ActionController #:nodoc: # . . / # . #around (code after yield) # . / - # #after (actual filter code is run) + # #after (actual filter code is run, unless the around filter does not yield) # - # If #around returns before yielding, only #after will be run. The #before - # filter and controller action will not be run. If #before returns false, - # the second half of #around and all of #after will still run but the - # action will not. + # If #around returns before yielding, #after will still not be run. The #before + # filter and controller action will not be run. If #before returns false, + # the second half of #around and will still run but #after and the + # action will not. If #around does not yield, #after will not be run. module ClassMethods # The passed filters will be appended to the filter_chain and # will execute before the action on this controller is performed. @@ -263,13 +264,13 @@ module ActionController #:nodoc: # The passed filters will be appended to the array of filters # that run _after_ actions on this controller are performed. def append_after_filter(*filters, &block) - prepend_filter_to_chain(filters, :after, &block) + append_filter_to_chain(filters, :after, &block) end # The passed filters will be prepended to the array of filters # that run _after_ actions on this controller are performed. def prepend_after_filter(*filters, &block) - append_filter_to_chain(filters, :after, &block) + prepend_filter_to_chain(filters, :after, &block) end # Shorthand for append_after_filter since it's the most common. @@ -362,12 +363,12 @@ module ActionController #:nodoc: # Returns a mapping between filters and the actions that may run them. def included_actions #:nodoc: - read_inheritable_attribute("included_actions") || {} + @included_actions ||= read_inheritable_attribute("included_actions") || {} end # Returns a mapping between filters and actions that may not run them. def excluded_actions #:nodoc: - read_inheritable_attribute("excluded_actions") || {} + @excluded_actions ||= read_inheritable_attribute("excluded_actions") || {} end # Find a filter in the filter_chain where the filter method matches the _filter_ param @@ -381,10 +382,11 @@ module ActionController #:nodoc: # Returns true if the filter is excluded from the given action def filter_excluded_from_action?(filter,action) #:nodoc: - if (ia = included_actions[filter]) && !ia.empty? + case + when ia = included_actions[filter] !ia.include?(action) - else - (excluded_actions[filter] || []).include?(action) + when ea = excluded_actions[filter] + ea.include?(action) end end @@ -397,20 +399,28 @@ module ActionController #:nodoc: @filter = filter end + def type + :around + end + def before? - false + type == :before end def after? - false + type == :after end def around? - true + type == :around + end + + def run(controller) + raise ActionControllerError, 'No filter type: Nothing to do here.' end def call(controller, &block) - raise(ActionControllerError, 'No filter type: Nothing to do here.') + run(controller) end end @@ -420,35 +430,38 @@ module ActionController #:nodoc: def filter @filter.filter end - - def around? - false - end end class BeforeFilterProxy < FilterProxy #:nodoc: - def before? - true + def type + :before end - def call(controller, &block) - if false == @filter.call(controller) # must only stop if equal to false. only filters returning false are halted. - controller.halt_filter_chain(@filter, :returned_false) - else - yield + def run(controller) + # only filters returning false are halted. + if false == @filter.call(controller) + controller.send :halt_filter_chain, @filter, :returned_false end end + + def call(controller) + yield unless run(controller) + end end class AfterFilterProxy < FilterProxy #:nodoc: - def after? - true + def type + :after end - def call(controller, &block) - yield + def run(controller) @filter.call(controller) end + + def call(controller) + yield + run(controller) + end end class SymbolFilter < Filter #:nodoc: @@ -485,29 +498,72 @@ module ActionController #:nodoc: end end + class ClassBeforeFilter < Filter #:nodoc: + def call(controller, &block) + @filter.before(controller) + end + end + + class ClassAfterFilter < Filter #:nodoc: + def call(controller, &block) + @filter.after(controller) + end + end + protected - def append_filter_to_chain(filters, position = :around, &block) - write_inheritable_array('filter_chain', create_filters(filters, position, &block) ) + def append_filter_to_chain(filters, filter_type = :around, &block) + pos = find_filter_append_position(filters, filter_type) + update_filter_chain(filters, filter_type, pos, &block) end - def prepend_filter_to_chain(filters, position = :around, &block) - write_inheritable_attribute('filter_chain', create_filters(filters, position, &block) + filter_chain) + def prepend_filter_to_chain(filters, filter_type = :around, &block) + pos = find_filter_prepend_position(filters, filter_type) + update_filter_chain(filters, filter_type, pos, &block) end - def create_filters(filters, position, &block) #:nodoc: + def update_filter_chain(filters, filter_type, pos, &block) + new_filters = create_filters(filters, filter_type, &block) + new_chain = filter_chain.insert(pos, new_filters).flatten + write_inheritable_attribute('filter_chain', new_chain) + end + + def find_filter_append_position(filters, filter_type) + # appending an after filter puts it at the end of the call chain + # before and around filters go before the first after filter in the chain + unless filter_type == :after + filter_chain.each_with_index do |f,i| + return i if f.after? + end + end + return -1 + end + + def find_filter_prepend_position(filters, filter_type) + # prepending a before or around filter puts it at the front of the call chain + # after filters go before the first after filter in the chain + if filter_type == :after + filter_chain.each_with_index do |f,i| + return i if f.after? + end + return -1 + end + return 0 + end + + def create_filters(filters, filter_type, &block) #:nodoc: filters, conditions = extract_conditions(filters, &block) - filters.map! { |filter| find_or_create_filter(filter,position) } + filters.map! { |filter| find_or_create_filter(filter, filter_type) } update_conditions(filters, conditions) filters end - def find_or_create_filter(filter,position) - if found_filter = find_filter(filter) { |f| f.send("#{position}?") } + def find_or_create_filter(filter, filter_type) + if found_filter = find_filter(filter) { |f| f.type == filter_type } found_filter else - f = class_for_filter(filter).new(filter) + f = class_for_filter(filter, filter_type).new(filter) # apply proxy to filter if necessary - case position + case filter_type when :before BeforeFilterProxy.new(f) when :after @@ -520,7 +576,7 @@ module ActionController #:nodoc: # The determination of the filter type was once done at run time. # This method is here to extract as much logic from the filter run time as possible - def class_for_filter(filter) #:nodoc: + def class_for_filter(filter, filter_type) #:nodoc: case when filter.is_a?(Symbol) SymbolFilter @@ -534,8 +590,12 @@ module ActionController #:nodoc: end when filter.respond_to?(:filter) ClassFilter + when filter.respond_to?(:before) && filter_type == :before + ClassBeforeFilter + when filter.respond_to?(:after) && filter_type == :after + ClassAfterFilter else - raise(ActionControllerError, 'A filters must be a Symbol, Proc, Method, or object responding to filter.') + raise(ActionControllerError, 'A filter must be a Symbol, Proc, Method, or object responding to filter, after or before.') end end @@ -550,8 +610,8 @@ module ActionController #:nodoc: return if conditions.empty? if conditions[:only] write_inheritable_hash('included_actions', condition_hash(filters, conditions[:only])) - else - write_inheritable_hash('excluded_actions', condition_hash(filters, conditions[:except])) if conditions[:except] + elsif conditions[:except] + write_inheritable_hash('excluded_actions', condition_hash(filters, conditions[:except])) end end @@ -576,9 +636,9 @@ module ActionController #:nodoc: def remove_actions_from_included_actions!(filters,*actions) actions = actions.flatten.map(&:to_s) - updated_hash = filters.inject(included_actions) do |hash,filter| + updated_hash = filters.inject(read_inheritable_attribute('included_actions')||{}) do |hash,filter| ia = (hash[filter] || []) - actions - ia.blank? ? hash.delete(filter) : hash[filter] = ia + ia.empty? ? hash.delete(filter) : hash[filter] = ia hash end write_inheritable_attribute('included_actions', updated_hash) @@ -595,7 +655,9 @@ module ActionController #:nodoc: def proxy_before_and_after_filter(filter) #:nodoc: return filter unless filter_responds_to_before_and_after(filter) Proc.new do |controller, action| - unless filter.before(controller) == false + if filter.before(controller) == false + controller.send :halt_filter_chain, filter, :returned_false + else begin action.call ensure @@ -615,53 +677,90 @@ module ActionController #:nodoc: end end - def perform_action_with_filters - call_filter(self.class.filter_chain, 0) - end + protected def process_with_filters(request, response, method = :perform_action, *arguments) #:nodoc: @before_filter_chain_aborted = false process_without_filters(request, response, method, *arguments) end - def filter_chain - self.class.filter_chain - end - - def call_filter(chain, index) - return (performed? || perform_action_without_filters) if index >= chain.size - filter = chain[index] - return call_filter(chain, index.next) if self.class.filter_excluded_from_action?(filter,action_name) - - halted = false - filter.call(self) do - halted = call_filter(chain, index.next) - end - halt_filter_chain(filter.filter, :no_yield) if halted == false unless @before_filter_chain_aborted - halted - end - - def halt_filter_chain(filter, reason) - if logger - case reason - when :no_yield - logger.info "Filter chain halted as [#{filter.inspect}] did not yield." - when :returned_false - logger.info "Filter chain halted as [#{filter.inspect}] returned false." - end - end - @before_filter_chain_aborted = true - return false + def perform_action_with_filters + call_filters(self.class.filter_chain, 0, 0) end private - def process_cleanup_with_filters - if @before_filter_chain_aborted - close_session + + def call_filters(chain, index, nesting) + index = run_before_filters(chain, index, nesting) + aborted = @before_filter_chain_aborted + perform_action_without_filters unless performed? || aborted + return index if nesting != 0 || aborted + run_after_filters(chain, index) + end + + def skip_excluded_filters(chain, index) + while (filter = chain[index]) && self.class.filter_excluded_from_action?(filter, action_name) + index = index.next + end + [filter, index] + end + + def run_before_filters(chain, index, nesting) + while chain[index] + filter, index = skip_excluded_filters(chain, index) + break unless filter # end of call chain reached + case filter.type + when :before + filter.run(self) # invoke before filter + index = index.next + break if @before_filter_chain_aborted + when :around + yielded = false + filter.call(self) do + yielded = true + # all remaining before and around filters will be run in this call + index = call_filters(chain, index.next, nesting.next) + end + halt_filter_chain(filter, :did_not_yield) unless yielded + break else - process_cleanup_without_filters + break # no before or around filters left end end + index + end + + def run_after_filters(chain, index) + seen_after_filter = false + while chain[index] + filter, index = skip_excluded_filters(chain, index) + break unless filter # end of call chain reached + case filter.type + when :after + seen_after_filter = true + filter.run(self) # invoke after filter + else + # implementation error or someone has mucked with the filter chain + raise ActionControllerError, "filter #{filter.inspect} was in the wrong place!" if seen_after_filter + end + index = index.next + end + index.next + end + + def halt_filter_chain(filter, reason) + @before_filter_chain_aborted = true + logger.info "Filter chain halted as [#{filter.inspect}] #{reason}." if logger + false + end + + def process_cleanup_with_filters + if @before_filter_chain_aborted + close_session + else + process_cleanup_without_filters + end + end end end end diff --git a/vendor/rails/actionpack/lib/action_controller/integration.rb b/vendor/rails/actionpack/lib/action_controller/integration.rb index d77540a2..a0c74093 100644 --- a/vendor/rails/actionpack/lib/action_controller/integration.rb +++ b/vendor/rails/actionpack/lib/action_controller/integration.rb @@ -67,7 +67,7 @@ module ActionController @https = false @cookies = {} @controller = @request = @response = nil - + self.host = "www.example.com" self.remote_addr = "127.0.0.1" self.accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5" @@ -89,7 +89,7 @@ module ActionController # session.https! # session.https!(false) def https!(flag=true) - @https = flag + @https = flag end # Return +true+ if the session is mimicing a secure HTTPS request. @@ -143,10 +143,10 @@ module ActionController # Performs a GET request with the given parameters. The parameters may # be +nil+, a Hash, or a string that is appropriately encoded # (application/x-www-form-urlencoded or multipart/form-data). The headers - # should be a hash. The keys will automatically be upcased, with the + # should be a hash. The keys will automatically be upcased, with the # prefix 'HTTP_' added if needed. # - # You can also perform POST, PUT, DELETE, and HEAD requests with #post, + # You can also perform POST, PUT, DELETE, and HEAD requests with #post, # #put, #delete, and #head. def get(path, parameters=nil, headers=nil) process :get, path, parameters, headers @@ -161,31 +161,41 @@ module ActionController def put(path, parameters=nil, headers=nil) process :put, path, parameters, headers end - + # Performs a DELETE request with the given parameters. See get() for more details. def delete(path, parameters=nil, headers=nil) process :delete, path, parameters, headers end - + # Performs a HEAD request with the given parameters. See get() for more details. def head(path, parameters=nil, headers=nil) process :head, path, parameters, headers end - # Performs an XMLHttpRequest request with the given parameters, mimicing - # the request environment created by the Prototype library. The parameters - # may be +nil+, a Hash, or a string that is appropriately encoded - # (application/x-www-form-urlencoded or multipart/form-data). The headers - # should be a hash. The keys will automatically be upcased, with the - # prefix 'HTTP_' added if needed. - def xml_http_request(path, parameters=nil, headers=nil) - headers = (headers || {}).merge( - "X-Requested-With" => "XMLHttpRequest", - "Accept" => "text/javascript, text/html, application/xml, text/xml, */*" - ) + # Performs an XMLHttpRequest request with the given parameters, mirroring + # a request from the Prototype library. + # + # The request_method is :get, :post, :put, :delete or :head; the + # parameters are +nil+, a hash, or a url-encoded or multipart string; + # the headers are a hash. Keys are automatically upcased and prefixed + # with 'HTTP_' if not already. + # + # This method used to omit the request_method parameter, assuming it + # was :post. This was deprecated in Rails 1.2.4. Always pass the request + # method as the first argument. + def xml_http_request(request_method, path, parameters = nil, headers = nil) + unless request_method.is_a?(Symbol) + ActiveSupport::Deprecation.warn 'xml_http_request now takes the request_method (:get, :post, etc.) as the first argument. It used to assume :post, so add the :post argument to your existing method calls to silence this warning.' + request_method, path, parameters, headers = :post, request_method, path, parameters + end - post(path, parameters, headers) + headers ||= {} + headers['X-Requested-With'] = 'XMLHttpRequest' + headers['Accept'] = 'text/javascript, text/html, application/xml, text/xml, */*' + + process(request_method, path, parameters, headers) end + alias xhr :xml_http_request # Returns the URL for the given options, according to the rules specified # in the application's routes. @@ -292,7 +302,7 @@ module ActionController @status = @status.to_i end - # Encode the cookies hash in a format suitable for passing to a + # Encode the cookies hash in a format suitable for passing to a # request. def encode_cookies cookies.inject("") do |string, (name, value)| @@ -450,7 +460,7 @@ module ActionController # without any test methods. def run(*args) #:nodoc: return if @method_name == "default_test" - super + super end # Because of how use_instantiated_fixtures and use_transactional_fixtures @@ -490,7 +500,7 @@ module ActionController @integration_session = open_session end - %w(get post cookies assigns xml_http_request).each do |method| + %w(get post put head delete cookies assigns xml_http_request).each do |method| define_method(method) do |*args| reset! unless @integration_session # reset the html_document variable, but only for new get/post calls diff --git a/vendor/rails/actionpack/lib/action_controller/macros/in_place_editing.rb b/vendor/rails/actionpack/lib/action_controller/macros/in_place_editing.rb index d04f1ce1..2d973f5b 100644 --- a/vendor/rails/actionpack/lib/action_controller/macros/in_place_editing.rb +++ b/vendor/rails/actionpack/lib/action_controller/macros/in_place_editing.rb @@ -24,7 +24,7 @@ module ActionController define_method("set_#{object}_#{attribute}") do @item = object.to_s.camelize.constantize.find(params[:id]) @item.update_attribute(attribute, params[:value]) - render :text => @item.send(attribute) + render :text => @item.send(attribute).to_s end end end diff --git a/vendor/rails/actionpack/lib/action_controller/pagination.rb b/vendor/rails/actionpack/lib/action_controller/pagination.rb index 595a08c7..415e7207 100644 --- a/vendor/rails/actionpack/lib/action_controller/pagination.rb +++ b/vendor/rails/actionpack/lib/action_controller/pagination.rb @@ -1,7 +1,9 @@ module ActionController # === Action Pack pagination for Active Record collections # - # DEPRECATION WARNING: Pagination will be separated into its own plugin with Rails 2.0. + # DEPRECATION WARNING: Pagination will be moved to a plugin in Rails 2.0. + # Install the classic_pagination plugin for forward compatibility: + # script/plugin install svn://errtheblog.com/svn/plugins/classic_pagination # # The Pagination module aids in the process of paging large collections of # Active Record objects. It offers macro-style automatic fetching of your @@ -130,6 +132,8 @@ module ActionController paginator_and_collection_for(collection_id, options) end + deprecate :paginate => 'Pagination is moving to a plugin in Rails 2.0: script/plugin install svn://errtheblog.com/svn/plugins/classic_pagination' + # These methods become class methods on any controller module ClassMethods # Creates a +before_filter+ which automatically paginates an Active @@ -148,6 +152,8 @@ module ActionController OPTIONS[self][collection_id] = options end end + + deprecate :paginate => 'Pagination is moving to a plugin in Rails 2.0: script/plugin install svn://errtheblog.com/svn/plugins/classic_pagination' end def create_paginators_and_retrieve_collections #:nodoc: diff --git a/vendor/rails/actionpack/lib/action_controller/request.rb b/vendor/rails/actionpack/lib/action_controller/request.rb index 348cac8c..b1cb1252 100755 --- a/vendor/rails/actionpack/lib/action_controller/request.rb +++ b/vendor/rails/actionpack/lib/action_controller/request.rb @@ -48,10 +48,6 @@ module ActionController # REQUEST_METHOD header directly. Thus, for head, both get? and head? will return true. def head? @env['REQUEST_METHOD'].downcase.to_sym == :head - end - - def headers - @env end # Determine whether the body of a HTTP call is URL-encoded (default) diff --git a/vendor/rails/actionpack/lib/action_controller/resources.rb b/vendor/rails/actionpack/lib/action_controller/resources.rb index d55e7f02..204916d3 100644 --- a/vendor/rails/actionpack/lib/action_controller/resources.rb +++ b/vendor/rails/actionpack/lib/action_controller/resources.rb @@ -2,48 +2,68 @@ module ActionController module Resources class Resource #:nodoc: attr_reader :collection_methods, :member_methods, :new_methods - attr_reader :path_prefix, :name_prefix + attr_reader :path_prefix, :new_name_prefix attr_reader :plural, :singular attr_reader :options def initialize(entities, options) @plural = entities @singular = options[:singular] || plural.to_s.singularize - + @options = options arrange_actions add_default_actions set_prefixes end - + def controller @controller ||= (options[:controller] || plural).to_s end - + def path @path ||= "#{path_prefix}/#{plural}" end - + def new_path @new_path ||= "#{path}/new" end - + def member_path @member_path ||= "#{path}/:id" end - + def nesting_path_prefix @nesting_path_prefix ||= "#{path}/:#{singular}_id" end - + + def deprecate_name_prefix? + @name_prefix.blank? && !@new_name_prefix.blank? + end + + def name_prefix + deprecate_name_prefix? ? @new_name_prefix : @name_prefix + end + + def old_name_prefix + @name_prefix + end + + def nesting_name_prefix + "#{new_name_prefix}#{singular}_" + end + + def action_separator + @action_separator ||= Base.resource_action_separator + end + protected def arrange_actions @collection_methods = arrange_actions_by_methods(options.delete(:collection)) @member_methods = arrange_actions_by_methods(options.delete(:member)) @new_methods = arrange_actions_by_methods(options.delete(:new)) end - + def add_default_actions add_default_action(member_methods, :get, :edit) add_default_action(new_methods, :get, :new) @@ -52,6 +72,7 @@ module ActionController def set_prefixes @path_prefix = options.delete(:path_prefix) @name_prefix = options.delete(:name_prefix) + @new_name_prefix = options.delete(:new_name_prefix) end def arrange_actions_by_methods(actions) @@ -60,7 +81,7 @@ module ActionController flipped_hash end end - + def add_default_action(collection, method, action) (collection[method] ||= []).unshift(action) end @@ -178,11 +199,11 @@ module ActionController # # The comment resources work the same, but must now include a value for :article_id. # - # comments_url(@article) - # comment_url(@article, @comment) + # article_comments_url(@article) + # article_comment_url(@article, @comment) # - # comments_url(:article_id => @article) - # comment_url(:article_id => @article, :id => @comment) + # article_comments_url(:article_id => @article) + # article_comment_url(:article_id => @article, :id => @comment) # # * :name_prefix -- define a prefix for all generated routes, usually ending in an underscore. # Use this if you have named routes that may clash. @@ -192,7 +213,7 @@ module ActionController # # * :collection -- add named routes for other actions that operate on the collection. # Takes a hash of #{action} => #{method}, where method is :get/:post/:put/:delete - # or :any if the method does not matter. These routes map to a URL like /messages;rss, with a route of rss_messages_url. + # or :any if the method does not matter. These routes map to a URL like /messages/rss, with a route of rss_messages_url. # * :member -- same as :collection, but for actions that operate on a specific member. # * :new -- same as :collection, but for actions that operate on the new resource action. # @@ -204,19 +225,19 @@ module ActionController # # --> GET /thread/7/messages/1 # # map.resources :messages, :collection => { :rss => :get } - # # --> GET /messages;rss (maps to the #rss action) + # # --> GET /messages/rss (maps to the #rss action) # # also adds a named route called "rss_messages" # # map.resources :messages, :member => { :mark => :post } - # # --> POST /messages/1;mark (maps to the #mark action) + # # --> POST /messages/1/mark (maps to the #mark action) # # also adds a named route called "mark_message" # # map.resources :messages, :new => { :preview => :post } - # # --> POST /messages/new;preview (maps to the #preview action) + # # --> POST /messages/new/preview (maps to the #preview action) # # also adds a named route called "preview_new_message" # # map.resources :messages, :new => { :new => :any, :preview => :post } - # # --> POST /messages/new;preview (maps to the #preview action) + # # --> POST /messages/new/preview (maps to the #preview action) # # also adds a named route called "preview_new_message" # # --> /messages/new can be invoked via any request method # @@ -235,9 +256,10 @@ module ActionController # /account profile. # # See map.resources for general conventions. These are the main differences: - # - a singular name is given to map.resource. The default controller name is taken from the singular name. - # - To specify a custom plural name, use the :plural option. There is no :singular option - # - No default index, new, or create routes are created for the singleton resource controller. + # - A singular name is given to map.resource. The default controller name is taken from the singular name. + # - There is no :collection option as there is only the singleton resource. + # - There is no :singular option as the singular name is passed to map.resource. + # - No default index route is created for the singleton resource controller. # - When nesting singleton resources, only the singular name is used as the path prefix (example: 'account/messages/1') # # Example: @@ -300,7 +322,7 @@ module ActionController map_member_actions(map, resource) if block_given? - with_options(:path_prefix => resource.nesting_path_prefix, &block) + with_options(:path_prefix => resource.nesting_path_prefix, :new_name_prefix => resource.nesting_name_prefix, &block) end end end @@ -315,7 +337,7 @@ module ActionController map_member_actions(map, resource) if block_given? - with_options(:path_prefix => resource.nesting_path_prefix, &block) + with_options(:path_prefix => resource.nesting_path_prefix, :new_name_prefix => resource.nesting_name_prefix, &block) end end end @@ -324,8 +346,21 @@ module ActionController resource.collection_methods.each do |method, actions| actions.each do |action| action_options = action_options_for(action, resource, method) - map.named_route("#{resource.name_prefix}#{action}_#{resource.plural}", "#{resource.path};#{action}", action_options) - map.named_route("formatted_#{resource.name_prefix}#{action}_#{resource.plural}", "#{resource.path}.:format;#{action}", action_options) + + unless resource.old_name_prefix.blank? + map.deprecated_named_route("#{action}_#{resource.name_prefix}#{resource.plural}", "#{resource.old_name_prefix}#{action}_#{resource.plural}") + map.deprecated_named_route("formatted_#{action}_#{resource.name_prefix}#{resource.plural}", "formatted_#{resource.old_name_prefix}#{action}_#{resource.plural}") + end + + if resource.deprecate_name_prefix? + map.deprecated_named_route("#{action}_#{resource.name_prefix}#{resource.plural}", "#{action}_#{resource.plural}") + map.deprecated_named_route("formatted_#{action}_#{resource.name_prefix}#{resource.plural}", "formatted_#{action}_#{resource.plural}") + end + + map.named_route("#{action}_#{resource.name_prefix}#{resource.plural}", "#{resource.path}#{resource.action_separator}#{action}", action_options) + map.connect("#{resource.path};#{action}", action_options) + map.connect("#{resource.path}.:format;#{action}", action_options) + map.named_route("formatted_#{action}_#{resource.name_prefix}#{resource.plural}", "#{resource.path}#{resource.action_separator}#{action}.:format", action_options) end end end @@ -335,6 +370,11 @@ module ActionController map.named_route("#{resource.name_prefix}#{resource.plural}", resource.path, index_action_options) map.named_route("formatted_#{resource.name_prefix}#{resource.plural}", "#{resource.path}.:format", index_action_options) + if resource.deprecate_name_prefix? + map.deprecated_named_route("#{resource.name_prefix}#{resource.plural}", "#{resource.plural}") + map.deprecated_named_route("formatted_#{resource.name_prefix}#{resource.plural}", "formatted_#{resource.plural}") + end + create_action_options = action_options_for("create", resource) map.connect(resource.path, create_action_options) map.connect("#{resource.path}.:format", create_action_options) @@ -351,11 +391,37 @@ module ActionController actions.each do |action| action_options = action_options_for(action, resource, method) if action == :new - map.named_route("#{resource.name_prefix}new_#{resource.singular}", resource.new_path, action_options) - map.named_route("formatted_#{resource.name_prefix}new_#{resource.singular}", "#{resource.new_path}.:format", action_options) + + unless resource.old_name_prefix.blank? + map.deprecated_named_route("new_#{resource.name_prefix}#{resource.singular}", "#{resource.old_name_prefix}new_#{resource.singular}") + map.deprecated_named_route("formatted_new_#{resource.name_prefix}#{resource.singular}", "formatted_#{resource.old_name_prefix}new_#{resource.singular}") + end + + if resource.deprecate_name_prefix? + map.deprecated_named_route("new_#{resource.name_prefix}#{resource.singular}", "new_#{resource.singular}") + map.deprecated_named_route("formatted_new_#{resource.name_prefix}#{resource.singular}", "formatted_new_#{resource.singular}") + end + + map.named_route("new_#{resource.name_prefix}#{resource.singular}", resource.new_path, action_options) + map.named_route("formatted_new_#{resource.name_prefix}#{resource.singular}", "#{resource.new_path}.:format", action_options) + else - map.named_route("#{resource.name_prefix}#{action}_new_#{resource.singular}", "#{resource.new_path};#{action}", action_options) - map.named_route("formatted_#{resource.name_prefix}#{action}_new_#{resource.singular}", "#{resource.new_path}.:format;#{action}", action_options) + + unless resource.old_name_prefix.blank? + map.deprecated_named_route("#{action}_new_#{resource.name_prefix}#{resource.singular}", "#{resource.old_name_prefix}#{action}_new_#{resource.singular}") + map.deprecated_named_route("formatted_#{action}_new_#{resource.name_prefix}#{resource.singular}", "formatted_#{resource.old_name_prefix}#{action}_new_#{resource.singular}") + end + + if resource.deprecate_name_prefix? + map.deprecated_named_route("#{action}_new_#{resource.name_prefix}#{resource.singular}", "#{action}_new_#{resource.singular}") + map.deprecated_named_route("formatted_#{action}_new_#{resource.name_prefix}#{resource.singular}", "formatted_#{action}_new_#{resource.singular}") + end + + map.named_route("#{action}_new_#{resource.name_prefix}#{resource.singular}", "#{resource.new_path}#{resource.action_separator}#{action}", action_options) + map.connect("#{resource.new_path};#{action}", action_options) + map.connect("#{resource.new_path}.:format;#{action}", action_options) + map.named_route("formatted_#{action}_new_#{resource.name_prefix}#{resource.singular}", "#{resource.new_path}#{resource.action_separator}#{action}.:format", action_options) + end end end @@ -365,8 +431,22 @@ module ActionController resource.member_methods.each do |method, actions| actions.each do |action| action_options = action_options_for(action, resource, method) - map.named_route("#{resource.name_prefix}#{action}_#{resource.singular}", "#{resource.member_path};#{action}", action_options) - map.named_route("formatted_#{resource.name_prefix}#{action}_#{resource.singular}", "#{resource.member_path}.:format;#{action}",action_options) + + unless resource.old_name_prefix.blank? + map.deprecated_named_route("#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.old_name_prefix}#{action}_#{resource.singular}") + map.deprecated_named_route("formatted_#{action}_#{resource.name_prefix}#{resource.singular}", "formatted_#{resource.old_name_prefix}#{action}_#{resource.singular}") + end + + if resource.deprecate_name_prefix? + map.deprecated_named_route("#{action}_#{resource.name_prefix}#{resource.singular}", "#{action}_#{resource.singular}") + map.deprecated_named_route("formatted_#{action}_#{resource.name_prefix}#{resource.singular}", "formatted_#{action}_#{resource.singular}") + end + + map.named_route("#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action}", action_options) + map.connect("#{resource.member_path};#{action}", action_options) + map.connect("#{resource.member_path}.:format;#{action}", action_options) + map.named_route("formatted_#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action}.:format", action_options) + end end @@ -374,6 +454,11 @@ module ActionController map.named_route("#{resource.name_prefix}#{resource.singular}", resource.member_path, show_action_options) map.named_route("formatted_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}.:format", show_action_options) + if resource.deprecate_name_prefix? + map.deprecated_named_route("#{resource.name_prefix}#{resource.singular}", "#{resource.singular}") + map.deprecated_named_route("formatted_#{resource.name_prefix}#{resource.singular}", "formatted_#{resource.singular}") + end + update_action_options = action_options_for("update", resource) map.connect(resource.member_path, update_action_options) map.connect("#{resource.member_path}.:format", update_action_options) diff --git a/vendor/rails/actionpack/lib/action_controller/routing.rb b/vendor/rails/actionpack/lib/action_controller/routing.rb index b132a80c..4568a3fb 100644 --- a/vendor/rails/actionpack/lib/action_controller/routing.rb +++ b/vendor/rails/actionpack/lib/action_controller/routing.rb @@ -451,26 +451,17 @@ module ActionController # is given (as an array), only the keys indicated will be used to build # the query string. The query string will correctly build array parameter # values. - def build_query_string(hash, only_keys=nil) + def build_query_string(hash, only_keys = nil) elements = [] - - only_keys ||= hash.keys - only_keys.each do |key| - value = hash[key] or next - key = CGI.escape key.to_s - if value.class == Array - key << '[]' - else - value = [ value ] - end - value.each { |val| elements << "#{key}=#{CGI.escape(val.to_param.to_s)}" } - end - - query_string = "?#{elements.join("&")}" unless elements.empty? - query_string || "" + (only_keys || hash.keys).each do |key| + if value = hash[key] + elements << value.to_query(key) + end + end + elements.empty? ? '' : "?#{elements.sort * '&'}" end - + # Write the real recognition implementation and then resend the message. def recognize(path, environment={}) write_recognition @@ -668,7 +659,7 @@ module ActionController end def extract_value - "#{local_name} = hash[:#{key}] #{"|| #{default.inspect}" if default}" + "#{local_name} = hash[:#{key}] && hash[:#{key}].to_param #{"|| #{default.inspect}" if default}" end def value_check if default # Then we know it won't be nil @@ -989,6 +980,10 @@ module ActionController def named_route(name, path, options = {}) @set.add_named_route(name, path, options) end + + def deprecated_named_route(name, deprecated_name, options = {}) + @set.add_deprecated_named_route(name, deprecated_name) + end # Added deprecation notice for anyone who already added a named route called "root". # It'll be used as a shortcut for map.connect '' in Rails 2.0. @@ -1019,7 +1014,7 @@ module ActionController def clear! @routes = {} @helpers = [] - + @module ||= Module.new @module.instance_methods.each do |selector| @module.send :remove_method, selector @@ -1055,6 +1050,38 @@ module ActionController def install(destinations = [ActionController::Base, ActionView::Base]) Array(destinations).each { |dest| dest.send :include, @module } end + + def define_deprecated_named_route_methods(name, deprecated_name) + + [:url, :path].each do |kind| + @module.send :module_eval, <<-end_eval # We use module_eval to avoid leaks + + def #{url_helper_name(deprecated_name, kind)}(*args) + + ActiveSupport::Deprecation.warn( + 'The named route "#{url_helper_name(deprecated_name, kind)}" uses a format that has been deprecated. ' + + 'You should use "#{url_helper_name(name, kind)}" instead.', caller + ) + + send :#{url_helper_name(name, kind)}, *args + + end + + def #{hash_access_name(deprecated_name, kind)}(*args) + + ActiveSupport::Deprecation.warn( + 'The named route "#{hash_access_name(deprecated_name, kind)}" uses a format that has been deprecated. ' + + 'You should use "#{hash_access_name(name, kind)}" instead.', caller + ) + + send :#{hash_access_name(name, kind)}, *args + + end + + end_eval + end + + end private def url_helper_name(name, kind = :url) @@ -1177,6 +1204,10 @@ module ActionController def add_named_route(name, path, options = {}) named_routes[name] = add_route(path, options) end + + def add_deprecated_named_route(name, deprecated_name) + named_routes.define_deprecated_named_route_methods(name, deprecated_name) + end def options_as_params(options) # If an explicit :controller was given, always make :action explicit @@ -1190,10 +1221,9 @@ module ActionController # # great fun, eh? - options_as_params = options[:controller] ? { :action => "index" } : {} - options.each do |k, value| - options_as_params[k] = value.to_param - end + options_as_params = options.clone + options_as_params[:action] ||= 'index' if options[:controller] + options_as_params[:action] = options_as_params[:action].to_s if options_as_params[:action] options_as_params end @@ -1224,6 +1254,9 @@ module ActionController options = options_as_params(options) expire_on = build_expiry(options, recall) + if options[:controller] + options[:controller] = options[:controller].to_s + end # if the controller has changed, make sure it changes relative to the # current controller module, if any. In other words, if we're currently # on admin/get, and the new controller is 'set', the new controller diff --git a/vendor/rails/actionpack/lib/action_controller/test_process.rb b/vendor/rails/actionpack/lib/action_controller/test_process.rb index 4011e6cf..79eb0e10 100644 --- a/vendor/rails/actionpack/lib/action_controller/test_process.rb +++ b/vendor/rails/actionpack/lib/action_controller/test_process.rb @@ -24,6 +24,7 @@ module ActionController #:nodoc: attr_accessor :cookies, :session_options attr_accessor :query_parameters, :request_parameters, :path, :session, :env attr_accessor :host + attr_reader :request_uri_overridden def initialize(query_parameters = nil, request_parameters = nil, session = nil) @query_parameters = query_parameters || {} @@ -67,12 +68,14 @@ module ActionController #:nodoc: # Used to check AbstractRequest's request_uri functionality. # Disables the use of @path and @request_uri so superclass can handle those. def set_REQUEST_URI(value) + @request_uri_overridden = true @env["REQUEST_URI"] = value @request_uri = nil @path = nil end def request_uri=(uri) + @env["REQUEST_URI"] = uri @request_uri = uri @path = uri.split("?").first end @@ -426,12 +429,12 @@ module ActionController #:nodoc: end def build_request_uri(action, parameters) - unless @request.env['REQUEST_URI'] + unless @request.request_uri_overridden options = @controller.send(:rewrite_options, parameters) options.update(:only_path => true, :action => action) url = ActionController::UrlRewriter.new(@request, parameters) - @request.set_REQUEST_URI(url.rewrite(options)) + @request.request_uri = url.rewrite(options) end end diff --git a/vendor/rails/actionpack/lib/action_controller/url_rewriter.rb b/vendor/rails/actionpack/lib/action_controller/url_rewriter.rb index 0a5aab14..029f5eae 100644 --- a/vendor/rails/actionpack/lib/action_controller/url_rewriter.rb +++ b/vendor/rails/actionpack/lib/action_controller/url_rewriter.rb @@ -52,8 +52,9 @@ module ActionController # Delete the unused options to prevent their appearance in the query string [:protocol, :host, :port].each { |k| options.delete k } end + anchor = "##{options.delete(:anchor)}" if options.key?(:anchor) url << Routing::Routes.generate(options, {}) - return url + return "#{url}#{anchor}" end end @@ -76,6 +77,7 @@ module ActionController alias_method :to_s, :to_str private + # Given a path and options, returns a rewritten URL string def rewrite_url(path, options) rewritten_url = "" unless options[:only_path] @@ -91,6 +93,7 @@ module ActionController rewritten_url end + # Given a Hash of options, generates a route def rewrite_path(options) options = options.symbolize_keys options.update(options[:params].symbolize_keys) if options[:params] diff --git a/vendor/rails/actionpack/lib/action_controller/verification.rb b/vendor/rails/actionpack/lib/action_controller/verification.rb index 7cdf6584..131131a1 100644 --- a/vendor/rails/actionpack/lib/action_controller/verification.rb +++ b/vendor/rails/actionpack/lib/action_controller/verification.rb @@ -95,6 +95,7 @@ module ActionController #:nodoc: response.headers.update(options[:add_headers]) if options[:add_headers] unless performed? render(options[:render]) if options[:render] + options[:redirect_to] = self.send(options[:redirect_to]) if options[:redirect_to].is_a? Symbol redirect_to(options[:redirect_to]) if options[:redirect_to] end return false diff --git a/vendor/rails/actionpack/lib/action_pack/version.rb b/vendor/rails/actionpack/lib/action_pack/version.rb index 09eaef6e..e64cc7f2 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 = 1 MINOR = 13 - TINY = 3 + TINY = 5 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/vendor/rails/actionpack/lib/action_view/base.rb b/vendor/rails/actionpack/lib/action_view/base.rb index e0bd5915..1e4fd629 100644 --- a/vendor/rails/actionpack/lib/action_view/base.rb +++ b/vendor/rails/actionpack/lib/action_view/base.rb @@ -148,7 +148,7 @@ module ActionView #:nodoc: # # This refreshes the sidebar, removes a person element and highlights the user list. # - # See the ActionView::Helpers::PrototypeHelper::JavaScriptGenerator documentation for more details. + # See the ActionView::Helpers::PrototypeHelper::GeneratorMethods documentation for more details. class Base include ERB::Util @@ -160,7 +160,7 @@ module ActionView #:nodoc: attr_internal *ActionController::Base::DEPRECATED_INSTANCE_VARIABLES # Specify trim mode for the ERB compiler. Defaults to '-'. - # See ERB documentation for suitable values. + # See ERb documentation for suitable values. @@erb_trim_mode = '-' cattr_accessor :erb_trim_mode @@ -191,17 +191,17 @@ module ActionView #:nodoc: end include CompiledTemplates - # maps inline templates to their method names + # Maps inline templates to their method names @@method_names = {} - # map method names to their compile time + # Map method names to their compile time @@compile_time = {} - # map method names to the names passed in local assigns so far + # Map method names to the names passed in local assigns so far @@template_args = {} - # count the number of inline templates + # Count the number of inline templates @@inline_template_count = 0 - # maps template paths without extension to their file extension returned by pick_template_extension. - # if for a given path, path.ext1 and path.ext2 exist on the file system, the order of extensions - # used by pick_template_extension determines whether ext1 or ext2 will be stored + # Maps template paths without extension to their file extension returned by pick_template_extension. + # If for a given path, path.ext1 and path.ext2 exist on the file system, the order of extensions + # used by pick_template_extension determines whether ext1 or ext2 will be stored. @@cached_template_extension = {} class ObjectWrapper < Struct.new(:value) #:nodoc: @@ -305,7 +305,6 @@ module ActionView #:nodoc: # Render the provided template with the given local assigns. If the template has not been rendered with the provided # local assigns yet, or if the template has been updated on disk, then the template will be compiled to a method. # - # Either, but not both, of template and file_path may be nil. If file_path is given, the template # will only be read if it has to be compiled. # @@ -371,10 +370,12 @@ module ActionView #:nodoc: end private + # Builds a string holding the full path of the template including extension def full_template_path(template_path, extension) "#{@base_path}/#{template_path}.#{extension}" end + # Asserts the existence of a template. def template_exists?(template_path, extension) file_path = full_template_path(template_path, extension) @@method_names.has_key?(file_path) || FileTest.exists?(file_path) @@ -389,6 +390,7 @@ module ActionView #:nodoc: @@cache_template_extensions && @@cached_template_extension[template_path] end + # Determines the template's file extension, such as rhtml, rxml, or rjs. def find_template_extension_for(template_path) if match = delegate_template_exists?(template_path) match.first.to_sym @@ -405,6 +407,7 @@ module ActionView #:nodoc: File.read(template_path) end + # Evaluate the local assigns and pushes them to the view. def evaluate_assigns unless @assigns_added assign_variables_from_controller @@ -416,6 +419,7 @@ module ActionView #:nodoc: handler.new(self).render(template, local_assigns) end + # Assigns instance variables from the controller to the view. def assign_variables_from_controller @assigns.each { |key, value| instance_variable_set("@#{key}", value) } end @@ -427,10 +431,10 @@ module ActionView #:nodoc: ((args = @@template_args[render_symbol]) && local_assigns.all? { |k,_| args.has_key?(k) }) end - # Check whether compilation is necessary. - # Compile if the inline template or file has not been compiled yet. - # Or if local_assigns has a new key, which isn't supported by the compiled code yet. - # Or if the file has changed on disk and checking file mods hasn't been disabled. + # Method to check whether template compilation is necessary. + # The template will be compiled if the inline template or file has not been compiled yet, + # if local_assigns has a new key, which isn't supported by the compiled code yet, + # or if the file has changed on disk and checking file mods hasn't been disabled. def compile_template?(template, file_name, local_assigns) method_key = file_name || template render_symbol = @@method_names[method_key] @@ -445,14 +449,15 @@ module ActionView #:nodoc: end end - # Create source code for given template + # Method to create the source code for a given template. def create_template_source(extension, template, render_symbol, locals) if template_requires_setup?(extension) body = case extension.to_sym when :rxml "controller.response.content_type ||= 'application/xml'\n" + - "xml = Builder::XmlMarkup.new(:indent => 2)\n" + - template + "xml ||= Builder::XmlMarkup.new(:indent => 2)\n" + + template + + "\nxml.target!\n" when :rjs "controller.response.content_type ||= 'text/javascript'\n" + "update_page do |page|\n#{template}\nend" @@ -473,11 +478,11 @@ module ActionView #:nodoc: "def #{render_symbol}(local_assigns)\n#{locals_code}#{body}\nend" end - def template_requires_setup?(extension) + def template_requires_setup?(extension) #:nodoc: templates_requiring_setup.include? extension.to_s end - def templates_requiring_setup + def templates_requiring_setup #:nodoc: %w(rxml rjs) end @@ -501,6 +506,7 @@ module ActionView #:nodoc: end end + # Compile and evaluate the template's code def compile_template(extension, template, file_name, local_assigns) render_symbol = assign_method_name(extension, template, file_name) render_source = create_template_source(extension, template, render_symbol, local_assigns.keys) diff --git a/vendor/rails/actionpack/lib/action_view/compiled_templates.rb b/vendor/rails/actionpack/lib/action_view/compiled_templates.rb index deb730f4..73cce12e 100644 --- a/vendor/rails/actionpack/lib/action_view/compiled_templates.rb +++ b/vendor/rails/actionpack/lib/action_view/compiled_templates.rb @@ -3,14 +3,14 @@ module ActionView # CompiledTemplates modules hold methods that have been compiled. # Templates are compiled into these methods so that they do not need to be - # re-read and re-parsed each request. + # read and parsed for each request. # # Each template may be compiled into one or more methods. Each method accepts a given # set of parameters which is used to implement local assigns passing. # # To use a compiled template module, create a new instance and include it into the class # in which you want the template to be rendered. - class CompiledTemplates < Module #:nodoc: + class CompiledTemplates < Module attr_reader :method_names def initialize diff --git a/vendor/rails/actionpack/lib/action_view/helpers/active_record_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/active_record_helper.rb index 33eaa138..a19ee51f 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/active_record_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/active_record_helper.rb @@ -13,17 +13,18 @@ module ActionView # is a great of making the record quickly available for editing, but likely to prove lackluster for a complicated real-world form. # In that case, it's better to use the input method and the specialized form methods in link:classes/ActionView/Helpers/FormHelper.html module ActiveRecordHelper - # Returns a default input tag for the type of object returned by the method. Example - # (title is a VARCHAR column and holds "Hello World"): + # Returns a default input tag for the type of object returned by the method. For example, let's say you have a model + # that has an attribute +title+ of type VARCHAR column, and this instance holds "Hello World": # input("post", "title") => # def input(record_name, method, options = {}) InstanceTag.new(record_name, method, self).to_tag(options) end - # Returns an entire form with input tags and everything for a specified Active Record object. Example - # (post is a new record that has a title using VARCHAR and a body using TEXT): - # form("post") => + # Returns an entire form with all needed input tags for a specified Active Record object. For example, let's say you + # have a table model Post with attributes named title of type VARCHAR and body of type TEXT: + # form("post") + # That line would yield a form like the following: #
#

#
@@ -32,14 +33,13 @@ module ActionView #

#
# #

# #
# # It's possible to specialize the form builder by using a different action name and by supplying another - # block renderer. Example (entry is a new record that has a message attribute using VARCHAR): + # block renderer. For example, let's say you have a model Entry with an attribute message of type VARCHAR: # # form("entry", :action => "sign", :input_block => # Proc.new { |record, column| "#{column.human_name}: #{input(record, column.name)}
" }) => @@ -74,16 +74,16 @@ module ActionView content_tag('form', contents, :action => action, :method => 'post', :enctype => options[:multipart] ? 'multipart/form-data': nil) end - # Returns a string containing the error message attached to the +method+ on the +object+, if one exists. - # This error message is wrapped in a DIV tag, which can be specialized to include both a +prepend_text+ and +append_text+ - # to properly introduce the error and a +css_class+ to style it accordingly. Examples (post has an error message - # "can't be empty" on the title attribute): + # Returns a string containing the error message attached to the +method+ on the +object+ if one exists. + # This error message is wrapped in a DIV tag, which can be extended to include a +prepend_text+ and/or +append_text+ + # (to properly explain the error), and a +css_class+ to style it accordingly. As an example, let's say you have a model + # +post+ that has an error message on the +title+ attribute: # # <%= error_message_on "post", "title" %> => #
can't be empty
# - # <%= error_message_on "post", "title", "Title simply ", " (or it won't work)", "inputError" %> => - #
Title simply can't be empty (or it won't work)
+ # <%= error_message_on "post", "title", "Title simply ", " (or it won't work).", "inputError" %> => + #
Title simply can't be empty (or it won't work).
def error_message_on(object, method, prepend_text = "", append_text = "", css_class = "formError") if (obj = instance_variable_get("@#{object}")) && (errors = obj.errors.on(method)) content_tag("div", "#{prepend_text}#{errors.is_a?(Array) ? errors.first : errors}#{append_text}", :class => css_class) @@ -92,11 +92,11 @@ module ActionView end end - # Returns a string with a div containing all of the error messages for the objects located as instance variables by the names + # Returns a string with a DIV containing all of the error messages for the objects located as instance variables by the names # given. If more than one object is specified, the errors for the objects are displayed in the order that the object names are # provided. # - # This div can be tailored by the following options: + # This DIV can be tailored by the following options: # # * header_tag - Used for the header of the error div (default: h2) # * id - The id of the error div (default: errorExplanation) @@ -105,12 +105,12 @@ module ActionView # any text that you prefer. If object_name is not set, the name of # the first object will be used. # - # Specifying one object: + # To specify the display for one object, you simply provide its name as a parameter. For example, for the +User+ model: # # error_messages_for 'user' # - # Specifying more than one object (and using the name 'user' in the - # header as the object_name instead of 'user_common'): + # To specify more than one object, you simply list them; optionally, you can add an extra +object_name+ parameter, which + # be the name in the header. # # error_messages_for 'user_common', 'user', :object_name => 'user' # diff --git a/vendor/rails/actionpack/lib/action_view/helpers/debug_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/debug_helper.rb index 9e92813a..ef089c1b 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/debug_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/debug_helper.rb @@ -3,6 +3,16 @@ module ActionView # Provides a set of methods for making it easier to locate problems. module DebugHelper # Returns a
-tag set with the +object+ dumped by YAML. Very readable way to inspect an object.
+      #  my_hash = {'first' => 1, 'second' => 'two', 'third' => [1,2,3]}
+      #  debug(my_hash)
+      #  => 
--- 
+      #  first: 1
+      #  second: two
+      #  third: 
+      #  - 1
+      #  - 2
+      #  - 3
+      #  
def debug(object) begin Marshal::dump(object) diff --git a/vendor/rails/actionpack/lib/action_view/helpers/deprecated_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/deprecated_helper.rb index 04392f5b..81f26dfe 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/deprecated_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/deprecated_helper.rb @@ -2,6 +2,9 @@ module ActionView module Helpers module PrototypeHelper + # Method to execute an element update using Prototype. + # DEPRECATION WARNING: This helper has been depercated; use RJS instead. + # See ActionView::Helpers::PrototypeHelper::JavaScriptGenerator::GeneratorMethods for more information. def update_element_function(element_id, options = {}, &block) content = escape_javascript(options[:content] || '') content = escape_javascript(capture(&block)) if block 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 71fe29db..988d2460 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -250,8 +250,10 @@ module ActionView return function end - # Observes the field with the DOM ID specified by +field_id+ and makes - # an Ajax call when its contents have changed. + # Observes the field with the DOM ID specified by +field_id+ and calls a + # callback when its contents have changed. The default callback is an + # Ajax call. By default the value of the observed field is sent as a + # parameter with the Ajax call. # # Required +options+ are either of: # :url:: +url_for+-style options for the action to call @@ -268,14 +270,24 @@ module ActionView # :update:: Specifies the DOM ID of the element whose # innerHTML should be updated with the # XMLHttpRequest response text. - # :with:: A JavaScript expression specifying the - # parameters for the XMLHttpRequest. This defaults - # to 'value', which in the evaluated context - # refers to the new field value. If you specify a - # string without a "=", it'll be extended to mean - # the form key that the value should be assigned to. - # So :with => "term" gives "'term'=value". If a "=" is - # present, no extension will happen. + # :with:: A JavaScript expression specifying the parameters + # for the XMLHttpRequest. The default is to send the + # key and value of the observed field. Any custom + # expressions should return a valid URL query string. + # The value of the field is stored in the JavaScript + # variable +value+. + # + # Examples + # + # :with => "'my_custom_key=' + value" + # :with => "'person[name]=' + prompt('New name')" + # :with => "Form.Element.serialize('other-field')" + # + # Finally + # :with => 'name' + # is shorthand for + # :with => "'name=' + value" + # This essentially just changes the key of the parameter. # :on:: Specifies which event handler to observe. By default, # it's set to "changed" for text fields and areas and # "click" for radio buttons and checkboxes. With this, @@ -291,11 +303,15 @@ module ActionView build_observer('Form.Element.EventObserver', field_id, options) end end - - # Like +observe_field+, but operates on an entire form identified by the - # DOM ID +form_id+. +options+ are the same as +observe_field+, except - # the default value of the :with option evaluates to the - # serialized (request string) value of the form. + + # Observes the form with the DOM ID specified by +form_id+ and calls a + # callback when its contents have changed. The default callback is an + # Ajax call. By default all fields of the observed field are sent as + # parameters with the Ajax call. + # + # The +options+ for +observe_form+ are the same as the options for + # +observe_field+. The JavaScript variable +value+ available to the + # :with option is set to the serialized form by default. def observe_form(form_id, options = {}) if options[:frequency] build_observer('Form.Observer', form_id, options) @@ -660,10 +676,10 @@ module ActionView end def build_observer(klass, name, options = {}) - if options[:with] && !options[:with].include?("=") + if options[:with] && (options[:with] !~ /[=(.]/) options[:with] = "'#{options[:with]}=' + value" else - options[:with] ||= 'value' if options[:update] + options[:with] ||= 'value' unless options[:function] end callback = options[:function] || remote_function(options) diff --git a/vendor/rails/actionpack/test/activerecord/pagination_test.rb b/vendor/rails/actionpack/test/activerecord/pagination_test.rb index ddd2cec8..5e2fb8e7 100644 --- a/vendor/rails/actionpack/test/activerecord/pagination_test.rb +++ b/vendor/rails/actionpack/test/activerecord/pagination_test.rb @@ -5,6 +5,8 @@ class PaginationTest < ActiveRecordTestCase class PaginationController < ActionController::Base self.template_root = "#{File.dirname(__FILE__)}/../fixtures/" + + around_filter :silence_deprecation_warnings def simple_paginate @topic_pages, @topics = paginate(:topics) @@ -67,6 +69,13 @@ class PaginationTest < ActiveRecordTestCase :count => "d.id") render :nothing => true end + + + def silence_deprecation_warnings + ActiveSupport::Deprecation.silence do + yield + end + end def rescue_errors(e) raise e end 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 5489f522..e7c229df 100644 --- a/vendor/rails/actionpack/test/controller/action_pack_assertions_test.rb +++ b/vendor/rails/actionpack/test/controller/action_pack_assertions_test.rb @@ -19,6 +19,8 @@ class ActionPackAssertionsController < ActionController::Base def redirect_to_controller() redirect_to :controller => "elsewhere", :action => "flash_me"; end + def redirect_to_controller_with_symbol() redirect_to :controller => :elsewhere, :action => :flash_me; end + def redirect_to_path() redirect_to '/some/path' end def redirect_to_named_route() redirect_to route_one_url end @@ -555,6 +557,17 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase assert_redirected_to 'http://test.host/some/path' end + def test_assert_redirection_with_symbol + process :redirect_to_controller_with_symbol + assert_nothing_raised { + assert_redirected_to :controller => "elsewhere", :action => "flash_me" + } + process :redirect_to_controller_with_symbol + assert_nothing_raised { + assert_redirected_to :controller => :elsewhere, :action => :flash_me + } + end + def test_redirected_to_with_nested_controller @controller = Admin::InnerModuleController.new get :redirect_to_absolute_controller diff --git a/vendor/rails/actionpack/test/controller/addresses_render_test.rb b/vendor/rails/actionpack/test/controller/addresses_render_test.rb index 4de1c805..f329b2df 100644 --- a/vendor/rails/actionpack/test/controller/addresses_render_test.rb +++ b/vendor/rails/actionpack/test/controller/addresses_render_test.rb @@ -39,7 +39,10 @@ class AddressesTest < Test::Unit::TestCase end def test_list - get :list + # because pagination is deprecated + ActiveSupport::Deprecation.silence do + get :list + end assert_equal "We only need to get this far!", @response.body.chomp end end diff --git a/vendor/rails/actionpack/test/controller/base_test.rb b/vendor/rails/actionpack/test/controller/base_test.rb index bcc47326..1d04b8bd 100644 --- a/vendor/rails/actionpack/test/controller/base_test.rb +++ b/vendor/rails/actionpack/test/controller/base_test.rb @@ -88,7 +88,7 @@ class ControllerInstanceTests < Test::Unit::TestCase # Mocha adds methods to Object which are then included in the public_instance_methods # This method hides those from the controller so the above tests won't know the difference def hide_mocha_methods_from_controller(controller) - mocha_methods = [:expects, :metaclass, :mocha, :mocha_inspect, :reset_mocha, :stubba_object, :stubba_method, :stubs, :verify] + mocha_methods = [:expects, :metaclass, :mocha, :mocha_inspect, :reset_mocha, :stubba_object, :stubba_method, :stubs, :verify, :__is_a__, :__metaclass__] controller.class.send(:hide_action, *mocha_methods) end diff --git a/vendor/rails/actionpack/test/controller/caching_test.rb b/vendor/rails/actionpack/test/controller/caching_test.rb index 07e16896..9cc6d0c1 100644 --- a/vendor/rails/actionpack/test/controller/caching_test.rb +++ b/vendor/rails/actionpack/test/controller/caching_test.rb @@ -97,6 +97,7 @@ class ActionCachingTestController < ActionController::Base caches_action :index def index + sleep 0.01 @cache_this = Time.now.to_f.to_s render :text => @cache_this end @@ -195,7 +196,7 @@ class ActionCacheTest < Test::Unit::TestCase def test_xml_version_of_resource_is_treated_as_different_cache @mock_controller.mock_url_for = 'http://example.org/posts/' @mock_controller.mock_path = '/posts/index.xml' - path_object = @path_class.new(@mock_controller) + path_object = @path_class.new(@mock_controller, {}) assert_equal 'xml', path_object.extension assert_equal 'example.org/posts/index.xml', path_object.path end @@ -204,7 +205,7 @@ class ActionCacheTest < Test::Unit::TestCase @mock_controller.mock_url_for = 'http://example.org/' @mock_controller.mock_path = '/' - assert_equal 'example.org/index', @path_class.path_for(@mock_controller) + assert_equal 'example.org/index', @path_class.path_for(@mock_controller, {}) end def test_file_extensions diff --git a/vendor/rails/actionpack/test/controller/cookie_test.rb b/vendor/rails/actionpack/test/controller/cookie_test.rb index 5bab99fd..44023b07 100644 --- a/vendor/rails/actionpack/test/controller/cookie_test.rb +++ b/vendor/rails/actionpack/test/controller/cookie_test.rb @@ -31,6 +31,11 @@ class CookieTest < Test::Unit::TestCase cookies.delete("user_name") end + def delete_cookie_with_path + cookies.delete("user_name", :path => '/beaten') + render_text "hello world" + end + def rescue_action(e) raise unless ActionController::MissingTemplate # No templates here, and we don't care about the output end @@ -85,4 +90,10 @@ class CookieTest < Test::Unit::TestCase assert_equal "david", jar["user_name"] assert_equal nil, jar["something_else"] end + + def test_delete_cookie_with_path + get :delete_cookie_with_path + assert_equal "/beaten", @response.headers["cookie"].first.path + assert_not_equal "/", @response.headers["cookie"].first.path + end end diff --git a/vendor/rails/actionpack/test/controller/deprecation/deprecated_base_methods_test.rb b/vendor/rails/actionpack/test/controller/deprecation/deprecated_base_methods_test.rb index d8da676f..3b210742 100644 --- a/vendor/rails/actionpack/test/controller/deprecation/deprecated_base_methods_test.rb +++ b/vendor/rails/actionpack/test/controller/deprecation/deprecated_base_methods_test.rb @@ -1,6 +1,12 @@ require File.dirname(__FILE__) + '/../../abstract_unit' class DeprecatedBaseMethodsTest < Test::Unit::TestCase + # ActiveRecord model mock to test pagination deprecation + class DummyModel + def self.find(*args) [] end + def self.count(*args) 0 end + end + class Target < ActionController::Base def deprecated_symbol_parameter_to_url_for redirect_to(url_for(:home_url, "superstars")) @@ -18,6 +24,11 @@ class DeprecatedBaseMethodsTest < Test::Unit::TestCase this_method_doesnt_exist end + def pagination + paginate :dummy_models, :class_name => 'DeprecatedBaseMethodsTest::DummyModel' + render :nothing => true + end + def rescue_action(e) raise e end end @@ -27,6 +38,7 @@ class DeprecatedBaseMethodsTest < Test::Unit::TestCase @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new @controller = Target.new + @controller.logger = Logger.new(nil) unless @controller.logger end def test_deprecated_symbol_parameter_to_url_for @@ -57,4 +69,10 @@ class DeprecatedBaseMethodsTest < Test::Unit::TestCase error = Test::Unit::Error.new('testing ur doodz', e) assert_not_deprecated { error.message } end + + def test_pagination_deprecation + assert_deprecated('svn://errtheblog.com/svn/plugins/classic_pagination') do + get :pagination + end + 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 5ad0d7f8..7b810b16 100644 --- a/vendor/rails/actionpack/test/controller/filter_params_test.rb +++ b/vendor/rails/actionpack/test/controller/filter_params_test.rb @@ -16,6 +16,7 @@ class FilterParamTest < Test::Unit::TestCase assert @controller.respond_to?(:filter_parameters) test_hashes = [[{},{},[]], + [{'foo'=>nil},{'foo'=>nil},[]], [{'foo'=>'bar'},{'foo'=>'bar'},[]], [{'foo'=>'bar'},{'foo'=>'bar'},%w'food'], [{'foo'=>'bar'},{'foo'=>'[FILTERED]'},%w'foo'], diff --git a/vendor/rails/actionpack/test/controller/filters_test.rb b/vendor/rails/actionpack/test/controller/filters_test.rb index 3a74eba0..31330960 100644 --- a/vendor/rails/actionpack/test/controller/filters_test.rb +++ b/vendor/rails/actionpack/test/controller/filters_test.rb @@ -14,7 +14,7 @@ class FilterTest < Test::Unit::TestCase @ran_filter ||= [] @ran_filter << "ensure_login" end - + def clean_up @ran_after_filter ||= [] @ran_after_filter << "clean_up" @@ -62,7 +62,7 @@ class FilterTest < Test::Unit::TestCase render :inline => "something else" end end - + class ConditionalFilterController < ActionController::Base def show render :inline => "ran action" @@ -86,7 +86,7 @@ class FilterTest < Test::Unit::TestCase @ran_filter ||= [] @ran_filter << "clean_up_tmp" end - + def rescue_action(e) raise(e) end end @@ -94,7 +94,7 @@ class FilterTest < Test::Unit::TestCase before_filter :ensure_login, :except => [ :show_without_filter, :another_action ] end - class OnlyConditionSymController < ConditionalFilterController + class OnlyConditionSymController < ConditionalFilterController before_filter :ensure_login, :only => :show end @@ -104,10 +104,10 @@ class FilterTest < Test::Unit::TestCase class BeforeAndAfterConditionController < ConditionalFilterController before_filter :ensure_login, :only => :show - after_filter :clean_up_tmp, :only => :show + after_filter :clean_up_tmp, :only => :show end - - class OnlyConditionProcController < ConditionalFilterController + + class OnlyConditionProcController < ConditionalFilterController before_filter(:only => :show) {|c| c.assigns["ran_proc_filter"] = true } end @@ -131,6 +131,14 @@ class FilterTest < Test::Unit::TestCase before_filter(ConditionalClassFilter, :ensure_login, Proc.new {|c| c.assigns["ran_proc_filter1"] = true }, :except => :show_without_filter) { |c| c.assigns["ran_proc_filter2"] = true} end + class EmptyFilterChainController < TestController + self.filter_chain.clear + def show + @action_executed = true + render :text => "yawp!" + end + end + class PrependingController < TestController prepend_before_filter :wonderful_life # skip_before_filter :fire_flash @@ -145,7 +153,7 @@ class FilterTest < Test::Unit::TestCase class ConditionalSkippingController < TestController skip_before_filter :ensure_login, :only => [ :login ] skip_after_filter :clean_up, :only => [ :login ] - + before_filter :find_user, :only => [ :change_password ] def login @@ -155,7 +163,7 @@ class FilterTest < Test::Unit::TestCase def change_password render :inline => "ran action" end - + protected def find_user @ran_filter ||= [] @@ -166,15 +174,15 @@ class FilterTest < Test::Unit::TestCase class ConditionalParentOfConditionalSkippingController < ConditionalFilterController before_filter :conditional_in_parent, :only => [:show, :another_action] after_filter :conditional_in_parent, :only => [:show, :another_action] - + private - + def conditional_in_parent @ran_filter ||= [] @ran_filter << 'conditional_in_parent' end end - + class ChildOfConditionalParentController < ConditionalParentOfConditionalSkippingController skip_before_filter :conditional_in_parent, :only => :another_action skip_after_filter :conditional_in_parent, :only => :another_action @@ -197,7 +205,7 @@ class FilterTest < Test::Unit::TestCase controller.assigns["was_audited"] = true end end - + class AroundFilter def before(controller) @execution_log = "before" @@ -209,7 +217,7 @@ class FilterTest < Test::Unit::TestCase controller.assigns["execution_log"] = @execution_log + " and after" controller.assigns["after_ran"] = true controller.class.execution_log << " after aroundfilter " if controller.respond_to? :execution_log - end + end end class AppendedAroundFilter @@ -219,12 +227,12 @@ class FilterTest < Test::Unit::TestCase def after(controller) controller.class.execution_log << " after appended aroundfilter " - end - end - + end + end + class AuditController < ActionController::Base before_filter(AuditFilter) - + def show render_text "hello" end @@ -234,6 +242,14 @@ class FilterTest < Test::Unit::TestCase around_filter AroundFilter.new end + class BeforeAfterClassFilterController < PrependingController + begin + filter = AroundFilter.new + before_filter filter + after_filter filter + end + end + class MixedFilterController < PrependingController cattr_accessor :execution_log @@ -247,7 +263,7 @@ class FilterTest < Test::Unit::TestCase after_filter { |c| c.class.execution_log << " after procfilter " } append_around_filter AppendedAroundFilter.new end - + class MixedSpecializationController < ActionController::Base class OutOfOrder < StandardError; end @@ -285,6 +301,101 @@ class FilterTest < Test::Unit::TestCase end end + class PrependingBeforeAndAfterController < ActionController::Base + prepend_before_filter :before_all + prepend_after_filter :after_all + before_filter :between_before_all_and_after_all + + def before_all + @ran_filter ||= [] + @ran_filter << 'before_all' + end + + def after_all + @ran_filter ||= [] + @ran_filter << 'after_all' + end + + def between_before_all_and_after_all + @ran_filter ||= [] + @ran_filter << 'between_before_all_and_after_all' + end + def show + render :text => 'hello' + end + end + + class NonYieldingAroundFilterController < ActionController::Base + + before_filter :filter_one + around_filter :non_yielding_filter + before_filter :filter_two + after_filter :filter_three + + def index + render :inline => "index" + end + + #make sure the controller complains + def rescue_action(e); raise e; end + + private + + def filter_one + @filters ||= [] + @filters << "filter_one" + end + + def filter_two + @filters << "filter_two" + end + + def non_yielding_filter + @filters << "zomg it didn't yield" + @filter_return_value + end + + def filter_three + @filters << "filter_three" + end + + end + + def test_non_yielding_around_filters_not_returning_false_do_not_raise + controller = NonYieldingAroundFilterController.new + controller.instance_variable_set "@filter_return_value", true + assert_nothing_raised do + test_process(controller, "index") + end + end + + def test_non_yielding_around_filters_returning_false_do_not_raise + controller = NonYieldingAroundFilterController.new + controller.instance_variable_set "@filter_return_value", false + assert_nothing_raised do + test_process(controller, "index") + end + end + + def test_after_filters_are_not_run_if_around_filter_returns_false + controller = NonYieldingAroundFilterController.new + controller.instance_variable_set "@filter_return_value", false + test_process(controller, "index") + assert_equal ["filter_one", "zomg it didn't yield"], controller.assigns['filters'] + end + + def test_after_filters_are_not_run_if_around_filter_does_not_yield + controller = NonYieldingAroundFilterController.new + controller.instance_variable_set "@filter_return_value", true + test_process(controller, "index") + assert_equal ["filter_one", "zomg it didn't yield"], controller.assigns['filters'] + end + + def test_empty_filter_chain + assert_equal 0, EmptyFilterChainController.filter_chain.size + assert test_process(EmptyFilterChainController).template.assigns['action_executed'] + end + def test_added_filter_to_inheritance_graph assert_equal [ :ensure_login ], TestController.before_filters end @@ -292,11 +403,11 @@ class FilterTest < Test::Unit::TestCase def test_base_class_in_isolation assert_equal [ ], ActionController::Base.before_filters end - + def test_prepending_filter assert_equal [ :wonderful_life, :ensure_login ], PrependingController.before_filters end - + def test_running_filters assert_equal %w( wonderful_life ensure_login ), test_process(PrependingController).template.assigns["ran_filter"] end @@ -304,11 +415,11 @@ class FilterTest < Test::Unit::TestCase def test_running_filters_with_proc assert test_process(ProcController).template.assigns["ran_proc_filter"] end - + def test_running_filters_with_implicit_proc assert test_process(ImplicitProcController).template.assigns["ran_proc_filter"] end - + def test_running_filters_with_class assert test_process(AuditController).template.assigns["was_audited"] end @@ -319,7 +430,7 @@ class FilterTest < Test::Unit::TestCase assert response.template.assigns["ran_class_filter"] assert response.template.assigns["ran_proc_filter1"] assert response.template.assigns["ran_proc_filter2"] - + response = test_process(AnomolousYetValidConditionController, "show_without_filter") assert_equal nil, response.template.assigns["ran_filter"] assert !response.template.assigns["ran_class_filter"] @@ -373,6 +484,12 @@ class FilterTest < Test::Unit::TestCase assert controller.template.assigns["after_ran"] end + def test_before_after_class_filter + controller = test_process(BeforeAfterClassFilterController) + assert controller.template.assigns["before_ran"] + assert controller.template.assigns["after_ran"] + end + def test_having_properties_in_around_filter controller = test_process(AroundFilterController) assert_equal "before and after", controller.template.assigns["execution_log"] @@ -381,10 +498,10 @@ class FilterTest < Test::Unit::TestCase def test_prepending_and_appending_around_filter controller = test_process(MixedFilterController) assert_equal " before aroundfilter before procfilter before appended aroundfilter " + - " after appended aroundfilter after aroundfilter after procfilter ", + " after appended aroundfilter after aroundfilter after procfilter ", MixedFilterController.execution_log end - + def test_rendering_breaks_filtering_chain response = test_process(RenderingController) assert_equal "something else", response.body @@ -412,6 +529,12 @@ class FilterTest < Test::Unit::TestCase end end + def test_running_prepended_before_and_after_filter + assert_equal 3, PrependingBeforeAndAfterController.filter_chain.length + response = test_process(PrependingBeforeAndAfterController) + assert_equal %w( before_all between_before_all_and_after_all after_all ), response.template.assigns["ran_filter"] + end + def test_conditional_skipping_of_filters assert_nil test_process(ConditionalSkippingController, "login").template.assigns["ran_filter"] assert_equal %w( ensure_login find_user ), test_process(ConditionalSkippingController, "change_password").template.assigns["ran_filter"] diff --git a/vendor/rails/actionpack/test/controller/integration_test.rb b/vendor/rails/actionpack/test/controller/integration_test.rb index 665c5901..6006a8b9 100644 --- a/vendor/rails/actionpack/test/controller/integration_test.rb +++ b/vendor/rails/actionpack/test/controller/integration_test.rb @@ -11,7 +11,7 @@ require 'stubba' module ActionController module Integration class Session - def process + def process(*args) end def generic_url_rewriter @@ -56,8 +56,7 @@ class SessionTest < Test::Unit::TestCase @session.expects(:get).with(path,args) - redirects = [true, true, false] - @session.stubs(:redirect?).returns(lambda { redirects.shift }) + @session.stubs(:redirect?).returns(true).then.returns(true).then.returns(false) @session.expects(:follow_redirect!).times(2) @session.stubs(:status).returns(200) @@ -69,8 +68,7 @@ class SessionTest < Test::Unit::TestCase @session.expects(:post).with(path,args) - redirects = [true, true, false] - @session.stubs(:redirect?).returns(lambda { redirects.shift }) + @session.stubs(:redirect?).returns(true).then.returns(true).then.returns(false) @session.expects(:follow_redirect!).times(2) @session.stubs(:status).returns(200) @@ -134,15 +132,102 @@ class SessionTest < Test::Unit::TestCase @session.head(path,params,headers) end - def test_xml_http_request + def test_xml_http_request_deprecated_call path = "/index"; params = "blah"; headers = {:location => 'blah'} headers_after_xhr = headers.merge( "X-Requested-With" => "XMLHttpRequest", "Accept" => "text/javascript, text/html, application/xml, text/xml, */*" ) - @session.expects(:post).with(path,params,headers_after_xhr) - @session.xml_http_request(path,params,headers) + @session.expects(:process).with(:post,path,params,headers_after_xhr) + assert_deprecated { @session.xml_http_request(path,params,headers) } end + + def test_xml_http_request_get + path = "/index"; params = "blah"; headers = {:location => 'blah'} + headers_after_xhr = headers.merge( + "X-Requested-With" => "XMLHttpRequest", + "Accept" => "text/javascript, text/html, application/xml, text/xml, */*" + ) + @session.expects(:process).with(:get,path,params,headers_after_xhr) + @session.xml_http_request(:get,path,params,headers) + end + + def test_xml_http_request_post + path = "/index"; params = "blah"; headers = {:location => 'blah'} + headers_after_xhr = headers.merge( + "X-Requested-With" => "XMLHttpRequest", + "Accept" => "text/javascript, text/html, application/xml, text/xml, */*" + ) + @session.expects(:process).with(:post,path,params,headers_after_xhr) + @session.xml_http_request(:post,path,params,headers) + end + + def test_xml_http_request_put + path = "/index"; params = "blah"; headers = {:location => 'blah'} + headers_after_xhr = headers.merge( + "X-Requested-With" => "XMLHttpRequest", + "Accept" => "text/javascript, text/html, application/xml, text/xml, */*" + ) + @session.expects(:process).with(:put,path,params,headers_after_xhr) + @session.xml_http_request(:put,path,params,headers) + end + + def test_xml_http_request_delete + path = "/index"; params = "blah"; headers = {:location => 'blah'} + headers_after_xhr = headers.merge( + "X-Requested-With" => "XMLHttpRequest", + "Accept" => "text/javascript, text/html, application/xml, text/xml, */*" + ) + @session.expects(:process).with(:delete,path,params,headers_after_xhr) + @session.xml_http_request(:delete,path,params,headers) + end + + def test_xml_http_request_head + path = "/index"; params = "blah"; headers = {:location => 'blah'} + headers_after_xhr = headers.merge( + "X-Requested-With" => "XMLHttpRequest", + "Accept" => "text/javascript, text/html, application/xml, text/xml, */*" + ) + @session.expects(:process).with(:head,path,params,headers_after_xhr) + @session.xml_http_request(:head,path,params,headers) + end +end + +class IntegrationTestTest < Test::Unit::TestCase + + def setup + @test = ::ActionController::IntegrationTest.new(:default_test) + @test.class.stubs(:fixture_table_names).returns([]) + @session = @test.open_session + end + + def test_opens_new_session + @test.class.expects(:fixture_table_names).times(2).returns(['foo']) + + session1 = @test.open_session { |sess| } + session2 = @test.open_session # implicit session + + assert_equal ::ActionController::Integration::Session, session1.class + assert_equal ::ActionController::Integration::Session, session2.class + assert_not_equal session1, session2 + end + +end + +# Tests that integration tests don't call Controller test methods for processing. +# Integration tests have their own setup and teardown. +class IntegrationTestUsesCorrectClass < ActionController::IntegrationTest + + def self.fixture_table_names + [] + end + + def test_integration_methods_called + %w( get post head put delete ).each do |verb| + assert_nothing_raised("'#{verb}' should use integration test methods") { send(verb, '/') } + end + end + end # TODO diff --git a/vendor/rails/actionpack/test/controller/render_test.rb b/vendor/rails/actionpack/test/controller/render_test.rb index 22683e51..d364dd6c 100644 --- a/vendor/rails/actionpack/test/controller/render_test.rb +++ b/vendor/rails/actionpack/test/controller/render_test.rb @@ -69,10 +69,6 @@ class TestController < ActionController::Base render "test/hello" end - def heading - head :ok - end - def greeting # let's just rely on the template end @@ -290,50 +286,8 @@ class RenderTest < Test::Unit::TestCase assert_equal "Goodbye, Local David", @response.body end - def test_render_200_should_set_etag - get :render_hello_world_from_variable - assert_equal etag_for("hello david"), @response.headers['Etag'] - end - - def test_render_against_etag_request_should_304_when_match - @request.headers["HTTP_IF_NONE_MATCH"] = etag_for("hello david") - get :render_hello_world_from_variable - assert_equal "304 Not Modified", @response.headers['Status'] - assert @response.body.empty? - end - - def test_render_against_etag_request_should_200_when_no_match - @request.headers["HTTP_IF_NONE_MATCH"] = etag_for("hello somewhere else") - get :render_hello_world_from_variable - assert_equal "200 OK", @response.headers['Status'] - assert !@response.body.empty? - end - - def test_render_with_etag - get :render_hello_world_from_variable - expected_etag = "\"#{MD5.new("hello david").to_s}\"" - assert_equal expected_etag, @response.headers['Etag'] - - @request.headers["HTTP_IF_NONE_MATCH"] = expected_etag - get :render_hello_world_from_variable - assert_equal "304 Not Modified", @response.headers['Status'] - - @request.headers["HTTP_IF_NONE_MATCH"] = "\"diftag\"" - get :render_hello_world_from_variable - assert_equal "200 OK", @response.headers['Status'] - end - - def render_with_404_shouldnt_have_etag - get :render_custom_code - assert_nil @response.headers['Etag'] - end - protected def assert_deprecated_render(&block) assert_deprecated(/render/, &block) end - - def etag_for(text) - "\"#{MD5.new(text).to_s}\"" - end end diff --git a/vendor/rails/actionpack/test/controller/resources_test.rb b/vendor/rails/actionpack/test/controller/resources_test.rb index e5605dff..26100d7d 100644 --- a/vendor/rails/actionpack/test/controller/resources_test.rb +++ b/vendor/rails/actionpack/test/controller/resources_test.rb @@ -10,8 +10,9 @@ class ThreadsController < ResourcesController; end class MessagesController < ResourcesController; end class CommentsController < ResourcesController; end -class AccountController < ResourcesController; end -class AdminController < ResourcesController; end +class AccountController < ResourcesController; end +class AdminController < ResourcesController; end +class ProductsController < ResourcesController; end class ResourcesTest < Test::Unit::TestCase def test_should_arrange_actions @@ -63,13 +64,13 @@ class ResourcesTest < Test::Unit::TestCase end end - def test_multile_with_path_prefix + def test_multiple_with_path_prefix with_restful_routing :messages, :comments, :path_prefix => '/thread/:thread_id' do assert_simply_restful_for :messages, :path_prefix => 'thread/5/', :options => { :thread_id => '5' } assert_simply_restful_for :comments, :path_prefix => 'thread/5/', :options => { :thread_id => '5' } end end - + def test_with_name_prefix with_restful_routing :messages, :name_prefix => 'post_' do assert_simply_restful_for :messages, :name_prefix => 'post_' @@ -78,7 +79,7 @@ class ResourcesTest < Test::Unit::TestCase def test_with_collection_action rss_options = {:action => 'rss'} - rss_path = "/messages;rss" + rss_path = "/messages/rss" actions = { 'a' => :put, 'b' => :post, 'c' => :delete } with_restful_routing :messages, :collection => { :rss => :get }.merge(actions) do @@ -86,14 +87,14 @@ class ResourcesTest < Test::Unit::TestCase assert_routing rss_path, options.merge(rss_options) actions.each do |action, method| - assert_recognizes(options.merge(:action => action), :path => "/messages;#{action}", :method => method) + assert_recognizes(options.merge(:action => action), :path => "/messages/#{action}", :method => method) end end assert_restful_named_routes_for :messages do |options| assert_named_route rss_path, :rss_messages_path, rss_options actions.keys.each do |action| - assert_named_route "/messages;#{action}", "#{action}_messages_path", :action => action + assert_named_route "/messages/#{action}", "#{action}_messages_path", :action => action end end end @@ -103,7 +104,7 @@ class ResourcesTest < Test::Unit::TestCase [:put, :post].each do |method| with_restful_routing :messages, :member => { :mark => method } do mark_options = {:action => 'mark', :id => '1'} - mark_path = "/messages/1;mark" + mark_path = "/messages/1/mark" assert_restful_routes_for :messages do |options| assert_recognizes(options.merge(mark_options), :path => mark_path, :method => method) end @@ -120,7 +121,7 @@ class ResourcesTest < Test::Unit::TestCase with_restful_routing :messages, :member => { :mark => method, :unmark => method } do %w(mark unmark).each do |action| action_options = {:action => action, :id => '1'} - action_path = "/messages/1;#{action}" + action_path = "/messages/1/#{action}" assert_restful_routes_for :messages do |options| assert_recognizes(options.merge(action_options), :path => action_path, :method => method) end @@ -136,7 +137,7 @@ class ResourcesTest < Test::Unit::TestCase def test_with_new_action with_restful_routing :messages, :new => { :preview => :post } do preview_options = {:action => 'preview'} - preview_path = "/messages/new;preview" + preview_path = "/messages/new/preview" assert_restful_routes_for :messages do |options| assert_recognizes(options.merge(preview_options), :path => preview_path, :method => :post) end @@ -178,9 +179,11 @@ class ResourcesTest < Test::Unit::TestCase assert_simply_restful_for :threads assert_simply_restful_for :messages, :path_prefix => 'threads/1/', + :name_prefix => 'thread_', :options => { :thread_id => '1' } assert_simply_restful_for :comments, :path_prefix => 'threads/1/messages/2/', + :name_prefix => 'thread_message_', :options => { :thread_id => '1', :message_id => '2' } end end @@ -217,9 +220,9 @@ class ResourcesTest < Test::Unit::TestCase admin.resource :account end end - + assert_singleton_restful_for :admin - assert_singleton_restful_for :account, :path_prefix => 'admin/' + assert_singleton_restful_for :account, :path_prefix => 'admin/', :name_prefix => 'admin_' end end @@ -227,7 +230,7 @@ class ResourcesTest < Test::Unit::TestCase [:put, :post].each do |method| with_singleton_resources :account, :member => { :reset => method } do reset_options = {:action => 'reset'} - reset_path = "/account;reset" + reset_path = "/account/reset" assert_singleton_routes_for :account do |options| assert_recognizes(options.merge(reset_options), :path => reset_path, :method => method) end @@ -244,7 +247,7 @@ class ResourcesTest < Test::Unit::TestCase with_singleton_resources :account, :member => { :reset => method, :disable => method } do %w(reset disable).each do |action| action_options = {:action => action} - action_path = "/account;#{action}" + action_path = "/account/#{action}" assert_singleton_routes_for :account do |options| assert_recognizes(options.merge(action_options), :path => action_path, :method => method) end @@ -264,9 +267,9 @@ class ResourcesTest < Test::Unit::TestCase account.resources :messages end end - + assert_singleton_restful_for :account - assert_simply_restful_for :messages, :path_prefix => 'account/' + assert_simply_restful_for :messages, :path_prefix => 'account/', :name_prefix => 'account_' end end @@ -279,10 +282,10 @@ class ResourcesTest < Test::Unit::TestCase end assert_singleton_restful_for :account, :path_prefix => '7/', :options => { :site_id => '7' } - assert_simply_restful_for :messages, :path_prefix => '7/account/', :options => { :site_id => '7' } + assert_simply_restful_for :messages, :path_prefix => '7/account/', :name_prefix => 'account_', :options => { :site_id => '7' } end end - + def test_should_nest_singleton_resource_in_resources with_routing do |set| set.draw do |map| @@ -290,9 +293,9 @@ class ResourcesTest < Test::Unit::TestCase thread.resource :admin end end - + assert_simply_restful_for :threads - assert_singleton_restful_for :admin, :path_prefix => 'threads/5/', :options => { :thread_id => '5' } + assert_singleton_restful_for :admin, :path_prefix => 'threads/5/', :name_prefix => 'thread_', :options => { :thread_id => '5' } end end @@ -312,6 +315,181 @@ class ResourcesTest < Test::Unit::TestCase end end + def test_resource_action_separator + with_routing do |set| + set.draw do |map| + map.resources :messages, :collection => {:search => :get}, :new => {:preview => :any}, :name_prefix => 'thread_', :path_prefix => '/threads/:thread_id' + map.resource :account, :member => {:login => :get}, :new => {:preview => :any}, :name_prefix => 'admin_', :path_prefix => '/admin' + end + + action_separator = ActionController::Base.resource_action_separator + + assert_simply_restful_for :messages, :name_prefix => 'thread_', :path_prefix => 'threads/1/', :options => { :thread_id => '1' } + assert_named_route "/threads/1/messages#{action_separator}search", "search_thread_messages_path", {} + assert_named_route "/threads/1/messages/new", "new_thread_message_path", {} + assert_named_route "/threads/1/messages/new#{action_separator}preview", "preview_new_thread_message_path", {} + assert_singleton_restful_for :account, :name_prefix => 'admin_', :path_prefix => 'admin/' + assert_named_route "/admin/account#{action_separator}login", "login_admin_account_path", {} + assert_named_route "/admin/account/new", "new_admin_account_path", {} + assert_named_route "/admin/account/new#{action_separator}preview", "preview_new_admin_account_path", {} + end + end + + def test_new_style_named_routes_for_resource + with_routing do |set| + set.draw do |map| + map.resources :messages, :collection => {:search => :get}, :new => {:preview => :any}, :name_prefix => 'thread_', :path_prefix => '/threads/:thread_id' + end + assert_simply_restful_for :messages, :name_prefix => 'thread_', :path_prefix => 'threads/1/', :options => { :thread_id => '1' } + assert_named_route "/threads/1/messages/search", "search_thread_messages_path", {} + assert_named_route "/threads/1/messages/new", "new_thread_message_path", {} + assert_named_route "/threads/1/messages/new/preview", "preview_new_thread_message_path", {} + end + end + + def test_new_style_named_routes_for_singleton_resource + with_routing do |set| + set.draw do |map| + map.resource :account, :member => {:login => :get}, :new => {:preview => :any}, :name_prefix => 'admin_', :path_prefix => '/admin' + end + assert_singleton_restful_for :account, :name_prefix => 'admin_', :path_prefix => 'admin/' + assert_named_route "/admin/account/login", "login_admin_account_path", {} + assert_named_route "/admin/account/new", "new_admin_account_path", {} + assert_named_route "/admin/account/new/preview", "preview_new_admin_account_path", {} + end + end + + def test_should_add_deprecated_named_routes_for_resource + with_routing do |set| + set.draw do |map| + map.resources :messages, :collection => {:search => :get}, :new => {:preview => :any}, :name_prefix => 'thread_', :path_prefix => '/threads/:thread_id' + end + assert_simply_restful_for :messages, :name_prefix => 'thread_', :path_prefix => 'threads/1/', :options => { :thread_id => '1' } + assert_deprecated do + assert_named_route "/threads/1/messages/search", "thread_search_messages_path", {} + assert_named_route "/threads/1/messages/new", "thread_new_message_path", {} + assert_named_route "/threads/1/messages/new/preview", "thread_preview_new_message_path", {} + end + end + end + + def test_should_add_deprecated_named_routes_for_singleton_resource + with_routing do |set| + set.draw do |map| + map.resource :account, :member => {:login => :get}, :new => {:preview => :any}, :name_prefix => 'admin_', :path_prefix => '/admin' + end + assert_singleton_restful_for :account, :name_prefix => 'admin_', :path_prefix => 'admin/' + assert_deprecated do + assert_named_route "/admin/account/login", "admin_login_account_path", {} + assert_named_route "/admin/account/new", "admin_new_account_path", {} + assert_named_route "/admin/account/new/preview", "admin_preview_new_account_path", {} + end + end + end + + def test_should_add_deprecated_named_routes_for_nested_resources + with_routing do |set| + set.draw do |map| + map.resources :threads do |map| + map.resources :messages do |map| + map.resources :comments + end + end + end + + assert_simply_restful_for :threads + assert_simply_restful_for :messages, + :path_prefix => 'threads/1/', + :name_prefix => 'thread_', + :options => { :thread_id => '1' } + assert_simply_restful_for :comments, + :path_prefix => 'threads/1/messages/2/', + :name_prefix => 'thread_message_', + :options => { :thread_id => '1', :message_id => '2' } + + assert_deprecated do + assert_named_route "/threads/1/messages", "messages_path", {} + assert_named_route "/threads/1/messages/1", "message_path", {:thread_id => '1', :id => '1'} + assert_named_route "/threads/1/messages/new", "new_message_path", {:thread_id => '1'} + assert_named_route "/threads/1/messages/1/edit", "edit_message_path", {:thread_id => '1', :id => '1'} + end + end + end + + def test_should_add_deprecated_named_routes_for_nested_singleton_resources + with_routing do |set| + set.draw do |map| + map.resource :admin do |admin| + admin.resource :account + end + end + + assert_singleton_restful_for :admin + assert_singleton_restful_for :account, :path_prefix => 'admin/', :name_prefix => 'admin_' + + assert_deprecated do + assert_named_route "/admin/account", "account_path", {} + assert_named_route "/admin/account/new", "new_account_path", {} + assert_named_route "/admin/account/edit", "edit_account_path", {} + end + end + end + + def test_should_add_deprecated_named_routes_for_nested_resources_in_singleton_resource + with_routing do |set| + set.draw do |map| + map.resource :account do |account| + account.resources :messages + end + end + + assert_singleton_restful_for :account + assert_simply_restful_for :messages, :path_prefix => 'account/', :name_prefix => 'account_' + + assert_deprecated do + assert_named_route "/account/messages", "messages_path", {} + assert_named_route "/account/messages/1", "message_path", {:id => '1'} + assert_named_route "/account/messages/new", "new_message_path", {} + assert_named_route "/account/messages/1/edit", "edit_message_path", {:id => '1'} + end + end + end + + def test_should_add_deprecated_named_routes_for_nested_singleton_resource_in_resources + with_routing do |set| + set.draw do |map| + map.resources :threads do |thread| + thread.resource :admin + end + end + + assert_simply_restful_for :threads + assert_singleton_restful_for :admin, :path_prefix => 'threads/5/', :name_prefix => 'thread_', :options => { :thread_id => '5' } + + assert_deprecated do + assert_named_route "/threads/5/admin", "admin_path", {} + assert_named_route "/threads/5/admin/new", "new_admin_path", {} + assert_named_route "/threads/5/admin/edit", "edit_admin_path", {} + end + end + end + + def test_should_add_deprecated_formatted_routes + with_routing do |set| + set.draw do |map| + map.resources :products, :collection => { :specials => :get }, :member => { :thumbnail => :get } + map.resource :account, :member => { :icon => :get } + end + assert_restful_routes_for :products do |options| + assert_recognizes options.merge({ :action => 'specials', :format => 'xml' }), :path => '/products.xml;specials', :method => :get + assert_recognizes options.merge({ :action => 'thumbnail', :format => 'jpg', :id => '1' }), :path => '/products/1.jpg;thumbnail', :method => :get + end + assert_singleton_restful_for :account do |options| + assert_recognizes options.merge({ :action => 'icon', :format => 'jpg' }), :path => '/account.jpg;icon', :method => :get + end + end + end + protected def with_restful_routing(*args) with_routing do |set| @@ -319,7 +497,7 @@ class ResourcesTest < Test::Unit::TestCase yield end end - + def with_singleton_resources(*args) with_routing do |set| set.draw { |map| map.resource(*args) } @@ -344,8 +522,8 @@ class ResourcesTest < Test::Unit::TestCase collection_path = "/#{options[:path_prefix]}#{controller_name}" member_path = "#{collection_path}/1" new_path = "#{collection_path}/new" - edit_member_path = "#{member_path};edit" - formatted_edit_member_path = "#{member_path}.xml;edit" + edit_member_path = "#{member_path}/edit" + formatted_edit_member_path = "#{member_path}/edit.xml" with_options(options[:options]) do |controller| controller.assert_routing collection_path, :action => 'index' @@ -395,13 +573,13 @@ class ResourcesTest < Test::Unit::TestCase name_prefix = options[:name_prefix] assert_named_route "#{full_prefix}", "#{name_prefix}#{controller_name}_path", options[:options] - assert_named_route "#{full_prefix}/new", "#{name_prefix}new_#{singular_name}_path", options[:options] + assert_named_route "#{full_prefix}/new", "new_#{name_prefix}#{singular_name}_path", options[:options] assert_named_route "#{full_prefix}/1", "#{name_prefix}#{singular_name}_path", options[:options].merge(:id => '1') - assert_named_route "#{full_prefix}/1;edit", "#{name_prefix}edit_#{singular_name}_path", options[:options].merge(:id => '1') + assert_named_route "#{full_prefix}/1/edit", "edit_#{name_prefix}#{singular_name}_path", options[:options].merge(:id => '1') assert_named_route "#{full_prefix}.xml", "formatted_#{name_prefix}#{controller_name}_path", options[:options].merge( :format => 'xml') - assert_named_route "#{full_prefix}/new.xml", "formatted_#{name_prefix}new_#{singular_name}_path", options[:options].merge( :format => 'xml') + assert_named_route "#{full_prefix}/new.xml", "formatted_new_#{name_prefix}#{singular_name}_path", options[:options].merge( :format => 'xml') assert_named_route "#{full_prefix}/1.xml", "formatted_#{name_prefix}#{singular_name}_path", options[:options].merge(:id => '1', :format => 'xml') - assert_named_route "#{full_prefix}/1.xml;edit", "formatted_#{name_prefix}edit_#{singular_name}_path", options[:options].merge(:id => '1', :format => 'xml') + assert_named_route "#{full_prefix}/1/edit.xml", "formatted_edit_#{name_prefix}#{singular_name}_path", options[:options].merge(:id => '1', :format => 'xml') yield options[:options] if block_given? end @@ -410,8 +588,8 @@ class ResourcesTest < Test::Unit::TestCase full_path = "/#{options[:path_prefix]}#{singleton_name}" new_path = "#{full_path}/new" - edit_path = "#{full_path};edit" - formatted_edit_path = "#{full_path}.xml;edit" + edit_path = "#{full_path}/edit" + formatted_edit_path = "#{full_path}/edit.xml" with_options options[:options] do |controller| controller.assert_routing full_path, :action => 'show' @@ -448,13 +626,14 @@ class ResourcesTest < Test::Unit::TestCase options[:options].delete :action full_path = "/#{options[:path_prefix]}#{singleton_name}" + full_name = "#{options[:name_prefix]}#{singleton_name}" - assert_named_route "#{full_path}", "#{singleton_name}_path", options[:options] - assert_named_route "#{full_path}/new", "new_#{singleton_name}_path", options[:options] - assert_named_route "#{full_path};edit", "edit_#{singleton_name}_path", options[:options] - assert_named_route "#{full_path}.xml", "formatted_#{singleton_name}_path", options[:options].merge(:format => 'xml') - assert_named_route "#{full_path}/new.xml", "formatted_new_#{singleton_name}_path", options[:options].merge(:format => 'xml') - assert_named_route "#{full_path}.xml;edit", "formatted_edit_#{singleton_name}_path", options[:options].merge(:format => 'xml') + assert_named_route "#{full_path}", "#{full_name}_path", options[:options] + assert_named_route "#{full_path}/new", "new_#{full_name}_path", options[:options] + assert_named_route "#{full_path}/edit", "edit_#{full_name}_path", options[:options] + assert_named_route "#{full_path}.xml", "formatted_#{full_name}_path", options[:options].merge(:format => 'xml') + assert_named_route "#{full_path}/new.xml", "formatted_new_#{full_name}_path", options[:options].merge(:format => 'xml') + assert_named_route "#{full_path}/edit.xml", "formatted_edit_#{full_name}_path", options[:options].merge(:format => 'xml') end def assert_named_route(expected, route, options) diff --git a/vendor/rails/actionpack/test/controller/routing_test.rb b/vendor/rails/actionpack/test/controller/routing_test.rb index 5e5f2b09..a201d9c4 100644 --- a/vendor/rails/actionpack/test/controller/routing_test.rb +++ b/vendor/rails/actionpack/test/controller/routing_test.rb @@ -265,7 +265,7 @@ class LegacyRouteSetTests < Test::Unit::TestCase map.content '/content/:query', :controller => 'content', :action => 'show' end exception = assert_raise(ActionController::RoutingError) { rs.generate(:controller => 'content', :action => 'show', :use_route => "content") } - expected_message = %[content_url failed to generate from {:action=>"show", :controller=>"content"} - you may have ambiguous routes, or you may need to supply additional parameters for this route. content_url has the following required parameters: ["content", :query] - are they all satisifed?] + expected_message = "content_url failed to generate from #{{:action=>"show", :controller=>"content"}.inspect} - you may have ambiguous routes, or you may need to supply additional parameters for this route. content_url has the following required parameters: [\"content\", :query] - are they all satisifed?" assert_equal expected_message, exception.message end @@ -946,7 +946,7 @@ class RouteTest < Test::Unit::TestCase end def test_expand_array_build_query_string - assert_equal '?x[]=1&x[]=2', order_query_string(@route.build_query_string(:x => [1, 2])) + assert_equal '?x%5B%5D=1&x%5B%5D=2', order_query_string(@route.build_query_string(:x => [1, 2])) end def test_escape_spaces_build_query_string_selected_keys diff --git a/vendor/rails/actionpack/test/controller/test_test.rb b/vendor/rails/actionpack/test/controller/test_test.rb index 2b0086c5..a8acd512 100644 --- a/vendor/rails/actionpack/test/controller/test_test.rb +++ b/vendor/rails/actionpack/test/controller/test_test.rb @@ -482,6 +482,22 @@ HTML end end + def test_request_uri_updates + get :test_params + uri = @request.request_uri + assert_equal @request.env['REQUEST_URI'], uri + + get :test_uri + assert_not_equal uri, @request.request_uri + uri = @request.request_uri + assert_equal @request.env['REQUEST_URI'], uri + + get :test_uri, :testing => true + assert_not_equal uri, @request.request_uri + uri = @request.request_uri + assert_equal @request.env['REQUEST_URI'], uri + end + protected def with_foo_routing with_routing do |set| diff --git a/vendor/rails/actionpack/test/controller/url_rewriter_test.rb b/vendor/rails/actionpack/test/controller/url_rewriter_test.rb index 882add49..6378c43d 100644 --- a/vendor/rails/actionpack/test/controller/url_rewriter_test.rb +++ b/vendor/rails/actionpack/test/controller/url_rewriter_test.rb @@ -17,15 +17,12 @@ class UrlRewriterTests < Test::Unit::TestCase assert_match %r(/hi/hi/2$), u end - - private - def split_query_string(str) - [str[0].chr] + str[1..-1].split(/&/).sort - end - - def assert_query_equal(q1, q2) - assert_equal(split_query_string(q1), split_query_string(q2)) - end + def test_anchor + assert_equal( + 'http://test.host/c/a/i#anchor', + @rewriter.rewrite(:controller => 'c', :action => 'a', :id => 'i', :anchor => 'anchor') + ) + end end class UrlWriterTests < Test::Unit::TestCase @@ -75,6 +72,12 @@ class UrlWriterTests < Test::Unit::TestCase W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => 'https') ) end + + def test_anchor + assert_equal('/c/a#anchor', + W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :anchor => 'anchor') + ) + end def test_named_route ActionController::Routing::Routes.draw do |map| @@ -111,5 +114,58 @@ class UrlWriterTests < Test::Unit::TestCase ensure ActionController::Routing::Routes.load! end - + + def test_one_parameter + assert_equal('/c/a?param=val', + W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :param => 'val') + ) + end + + def test_two_parameters + url = W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :p1 => 'X1', :p2 => 'Y2') + params = extract_params(url) + assert_equal params[0], { :p1 => 'X1' }.to_query + assert_equal params[1], { :p2 => 'Y2' }.to_query + end + + def test_hash_parameter + url = W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :query => {:name => 'Bob', :category => 'prof'}) + params = extract_params(url) + assert_equal params[0], { 'query[category]' => 'prof' }.to_query + assert_equal params[1], { 'query[name]' => 'Bob' }.to_query + end + + def test_array_parameter + url = W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :query => ['Bob', 'prof']) + params = extract_params(url) + assert_equal params[0], { 'query[]' => 'Bob' }.to_query + assert_equal params[1], { 'query[]' => 'prof' }.to_query + end + + def test_hash_recursive_parameters + url = W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :query => {:person => {:name => 'Bob', :position => 'prof'}, :hobby => 'piercing'}) + params = extract_params(url) + assert_equal params[0], { 'query[hobby]' => 'piercing' }.to_query + assert_equal params[1], { 'query[person][name]' => 'Bob' }.to_query + assert_equal params[2], { 'query[person][position]' => 'prof' }.to_query + end + + def test_hash_recursive_and_array_parameters + url = W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :id => 101, :query => {:person => {:name => 'Bob', :position => ['prof', 'art director']}, :hobby => 'piercing'}) + assert_match %r(^/c/a/101), url + params = extract_params(url) + assert_equal params[0], { 'query[hobby]' => 'piercing' }.to_query + assert_equal params[1], { 'query[person][name]' => 'Bob' }.to_query + assert_equal params[2], { 'query[person][position][]' => 'art director' }.to_query + assert_equal params[3], { 'query[person][position][]' => 'prof' }.to_query + end + + def test_path_generation_for_symbol_parameter_keys + assert_generates("/image", :controller=> :image) + end + + private + def extract_params(url) + url.split('?', 2).last.split('&') + end end diff --git a/vendor/rails/actionpack/test/controller/verification_test.rb b/vendor/rails/actionpack/test/controller/verification_test.rb index 05012cf7..bbcd7d59 100644 --- a/vendor/rails/actionpack/test/controller/verification_test.rb +++ b/vendor/rails/actionpack/test/controller/verification_test.rb @@ -34,9 +34,16 @@ class VerificationTest < Test::Unit::TestCase verify :only => :must_be_post, :method => :post, :render => { :status => 405, :text => "Must be post" }, :add_headers => { "Allow" => "POST" } + verify :only => :guarded_one_for_named_route_test, :params => "one", + :redirect_to => :foo_url + def guarded_one render :text => "#{params[:one]}" end + + def guarded_one_for_named_route_test + render :text => "#{params[:one]}" + end def guarded_with_flash render :text => "#{params[:one]}" @@ -94,6 +101,14 @@ class VerificationTest < Test::Unit::TestCase @controller = TestController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new + ActionController::Routing::Routes.add_named_route :foo, '/foo', :controller => 'test', :action => 'foo' + end + + def test_no_deprecation_warning_for_named_route + assert_not_deprecated do + get :guarded_one_for_named_route_test, :two => "not one" + assert_redirected_to '/foo' + end end def test_guarded_one_with_prereqs diff --git a/vendor/rails/actionpack/test/fixtures/test/hello_world.rxml b/vendor/rails/actionpack/test/fixtures/test/hello_world.rxml index bffd2191..8455b11e 100644 --- a/vendor/rails/actionpack/test/fixtures/test/hello_world.rxml +++ b/vendor/rails/actionpack/test/fixtures/test/hello_world.rxml @@ -1,3 +1,4 @@ xml.html do xml.p "Hello" -end \ No newline at end of file +end +"String return value" 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 f730f80a..739bc469 100644 --- a/vendor/rails/actionpack/test/template/asset_tag_helper_test.rb +++ b/vendor/rails/actionpack/test/template/asset_tag_helper_test.rb @@ -165,7 +165,12 @@ class AssetTagHelperTest < Test::Unit::TestCase def test_preset_empty_asset_id Object.send(:const_set, :RAILS_ROOT, File.dirname(__FILE__) + "/../fixtures/") + # on windows, setting ENV["XXX"] to "" makes ENV["XXX"] return nil + if RUBY_PLATFORM =~ /win32/ + ENV["RAILS_ASSET_ID"] = " " + else ENV["RAILS_ASSET_ID"] = "" + end assert_equal %(Rails), image_tag("rails.png") end diff --git a/vendor/rails/actionpack/test/template/compiled_templates_test.rb b/vendor/rails/actionpack/test/template/compiled_templates_test.rb index e46543d6..2e6327af 100644 --- a/vendor/rails/actionpack/test/template/compiled_templates_test.rb +++ b/vendor/rails/actionpack/test/template/compiled_templates_test.rb @@ -71,7 +71,12 @@ class CompiledTemplateTests < Test::Unit::TestCase end def test_compile_time - `echo '#{@a}' > #{@a}; echo '#{@b}' > #{@b}; ln -s #{@a} #{@s}` + File.open(@a, "w"){|f| f.puts @a} + File.open(@b, "w"){|f| f.puts @b} + + # windows doesn't support symlinks (even under cygwin) + windows = (RUBY_PLATFORM =~ /win32/) + `ln -s #{@a} #{@s}` unless windows v = ActionView::Base.new v.base_path = '.' @@ -79,47 +84,54 @@ class CompiledTemplateTests < Test::Unit::TestCase sleep 1 t = Time.now + sleep 1 + v.compile_and_render_template(:rhtml, '', @a) v.compile_and_render_template(:rhtml, '', @b) - v.compile_and_render_template(:rhtml, '', @s) + v.compile_and_render_template(:rhtml, '', @s) unless windows + a_n = v.method_names[@a] b_n = v.method_names[@b] - s_n = v.method_names[@s] + s_n = v.method_names[@s] unless windows + ct_a = v.compile_time[a_n] + ct_b = v.compile_time[b_n] + ct_s = v.compile_time[s_n] unless windows # all of the files have changed since last compile assert v.compile_time[a_n] > t assert v.compile_time[b_n] > t - assert v.compile_time[s_n] > t + assert v.compile_time[s_n] > t unless windows sleep 1 - t = Time.now v.compile_and_render_template(:rhtml, '', @a) v.compile_and_render_template(:rhtml, '', @b) - v.compile_and_render_template(:rhtml, '', @s) + v.compile_and_render_template(:rhtml, '', @s) unless windows # none of the files have changed since last compile - assert v.compile_time[a_n] < t - assert v.compile_time[b_n] < t - assert v.compile_time[s_n] < t + # so they should not have been recmpiled + assert_equal ct_a, v.compile_time[a_n] + assert_equal ct_b, v.compile_time[b_n] + assert_equal ct_s, v.compile_time[s_n] unless windows - `rm #{@s}; ln -s #{@b} #{@s}` + `rm #{@s}; ln -s #{@b} #{@s}` unless windows v.compile_and_render_template(:rhtml, '', @a) v.compile_and_render_template(:rhtml, '', @b) - v.compile_and_render_template(:rhtml, '', @s) + v.compile_and_render_template(:rhtml, '', @s) unless windows # the symlink has changed since last compile - assert v.compile_time[a_n] < t - assert v.compile_time[b_n] < t - assert v.compile_time[s_n] > t + assert_equal ct_a, v.compile_time[a_n] + assert_equal ct_b, v.compile_time[b_n] + assert v.compile_time[s_n] > t unless windows sleep 1 - `touch #{@b}` + FileUtils.touch @b t = Time.now + sleep 1 v.compile_and_render_template(:rhtml, '', @a) v.compile_and_render_template(:rhtml, '', @b) - v.compile_and_render_template(:rhtml, '', @s) + v.compile_and_render_template(:rhtml, '', @s) unless windows # the file at the end of the symlink has changed since last compile # both the symlink and the file at the end of it should be recompiled assert v.compile_time[a_n] < t assert v.compile_time[b_n] > t - assert v.compile_time[s_n] > t + assert v.compile_time[s_n] > t unless windows end end diff --git a/vendor/rails/actionpack/test/template/javascript_helper_test.rb b/vendor/rails/actionpack/test/template/javascript_helper_test.rb index ea13f1ab..a2a8863e 100644 --- a/vendor/rails/actionpack/test/template/javascript_helper_test.rb +++ b/vendor/rails/actionpack/test/template/javascript_helper_test.rb @@ -36,14 +36,14 @@ class JavaScriptHelperTest < Test::Unit::TestCase html = link_to_function( "Greet me!" ) do |page| page.replace_html 'header', "

Greetings

" end - assert_dom_equal %(Greet me!), html + assert_dom_equal %q(Greet me!), html end def test_link_to_function_with_rjs_block_and_options html = link_to_function( "Greet me!", :class => "updater" ) do |page| page.replace_html 'header', "

Greetings

" end - assert_dom_equal %(Greet me!), html + assert_dom_equal %q(Greet me!), html end def test_button_to_function @@ -55,13 +55,13 @@ class JavaScriptHelperTest < Test::Unit::TestCase html = button_to_function( "Greet me!" ) do |page| page.replace_html 'header', "

Greetings

" end - assert_dom_equal %(), html + assert_dom_equal %q(), html end def test_button_to_function_with_rjs_block_and_options html = button_to_function( "Greet me!", :class => "greeter" ) do |page| page.replace_html 'header', "

Greetings

" end - assert_dom_equal %(), html + assert_dom_equal %q(), html end end diff --git a/vendor/rails/actionpack/test/template/number_helper_test.rb b/vendor/rails/actionpack/test/template/number_helper_test.rb index df2c9183..3da1ae60 100644 --- a/vendor/rails/actionpack/test/template/number_helper_test.rb +++ b/vendor/rails/actionpack/test/template/number_helper_test.rb @@ -22,7 +22,7 @@ class NumberHelperTest < Test::Unit::TestCase def test_number_to_currency assert_equal("$1,234,567,890.50", number_to_currency(1234567890.50)) assert_equal("$1,234,567,890.51", number_to_currency(1234567890.506)) - assert_equal("$1,234,567,890", number_to_currency(1234567890.50, {:precision => 0})) + assert_equal("$1,234,567,891", number_to_currency(1234567890.51, {:precision => 0})) assert_equal("$1,234,567,890.5", number_to_currency(1234567890.50, {:precision => 1})) assert_equal("£1234567890,50", number_to_currency(1234567890.50, {:unit => "£", :separator => ",", :delimiter => ""})) assert_equal("$1,234,567,890.50", number_to_currency("1234567890.50")) diff --git a/vendor/rails/actionpack/test/template/prototype_helper_test.rb b/vendor/rails/actionpack/test/template/prototype_helper_test.rb index 7dc366b7..80c3d247 100644 --- a/vendor/rails/actionpack/test/template/prototype_helper_test.rb +++ b/vendor/rails/actionpack/test/template/prototype_helper_test.rb @@ -125,7 +125,7 @@ class PrototypeHelperTest < Test::Unit::TestCase end def test_observe_field - assert_dom_equal %(), + assert_dom_equal %(), observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }) end @@ -135,7 +135,7 @@ class PrototypeHelperTest < Test::Unit::TestCase end def test_observe_form - assert_dom_equal %(), + assert_dom_equal %(), observe_form("cart", :frequency => 2, :url => { :action => "cart_changed" }) end @@ -170,23 +170,23 @@ class JavaScriptGeneratorTest < Test::Unit::TestCase end def test_insert_html_with_string - assert_equal 'new Insertion.Top("element", "

This is a test

");', + assert_equal 'new Insertion.Top("element", "\074p\076This is a test\074/p\076");', @generator.insert_html(:top, 'element', '

This is a test

') - assert_equal 'new Insertion.Bottom("element", "

This is a test

");', + assert_equal 'new Insertion.Bottom("element", "\074p\076This is a test\074/p\076");', @generator.insert_html(:bottom, 'element', '

This is a test

') - assert_equal 'new Insertion.Before("element", "

This is a test

");', + assert_equal 'new Insertion.Before("element", "\074p\076This is a test\074/p\076");', @generator.insert_html(:before, 'element', '

This is a test

') - assert_equal 'new Insertion.After("element", "

This is a test

");', + assert_equal 'new Insertion.After("element", "\074p\076This is a test\074/p\076");', @generator.insert_html(:after, 'element', '

This is a test

') end def test_replace_html_with_string - assert_equal 'Element.update("element", "

This is a test

");', + assert_equal 'Element.update("element", "\074p\076This is a test\074/p\076");', @generator.replace_html('element', '

This is a test

') end def test_replace_element_with_string - assert_equal 'Element.replace("element", "

This is a test

");', + assert_equal 'Element.replace("element", "\074div id=\"element\"\076\074p\076This is a test\074/p\076\074/div\076");', @generator.replace('element', '

This is a test

') end @@ -241,12 +241,12 @@ class JavaScriptGeneratorTest < Test::Unit::TestCase @generator.remove('foo', 'bar') @generator.replace_html('baz', '

This is a test

') - assert_equal <<-EOS.chomp, @generator.to_s -new Insertion.Top("element", "

This is a test

"); -new Insertion.Bottom("element", "

This is a test

"); + expected = %q(new Insertion.Top("element", "\074p\076This is a test\074/p\076"); +new Insertion.Bottom("element", "\074p\076This is a test\074/p\076"); ["foo", "bar"].each(Element.remove); -Element.update("baz", "

This is a test

"); - EOS +Element.update("baz", "\074p\076This is a test\074/p\076");) + + assert_equal expected, @generator.to_s end def test_element_access diff --git a/vendor/rails/actionwebservice/CHANGELOG b/vendor/rails/actionwebservice/CHANGELOG index 2c3463e6..99134271 100644 --- a/vendor/rails/actionwebservice/CHANGELOG +++ b/vendor/rails/actionwebservice/CHANGELOG @@ -1,3 +1,17 @@ +*1.2.5* (October 12th, 2007) + +* Depend on Action Pack 1.13.5 + +* Depend on Active Record 1.15.5 + + +*1.2.4* (October 4th, 2007) + +* Depend on Action Pack 1.13.4 + +* Depend on Active Record 1.15.4 + + *1.2.3* (March 12th, 2007) * Depend on Action Pack 1.13.3 diff --git a/vendor/rails/actionwebservice/Rakefile b/vendor/rails/actionwebservice/Rakefile index fec9aae9..33d24d6a 100644 --- a/vendor/rails/actionwebservice/Rakefile +++ b/vendor/rails/actionwebservice/Rakefile @@ -71,8 +71,8 @@ spec = Gem::Specification.new do |s| s.rubyforge_project = "aws" s.homepage = "http://www.rubyonrails.org" - s.add_dependency('actionpack', '= 1.13.3' + PKG_BUILD) - s.add_dependency('activerecord', '= 1.15.3' + PKG_BUILD) + s.add_dependency('actionpack', '= 1.13.5' + PKG_BUILD) + s.add_dependency('activerecord', '= 1.15.5' + PKG_BUILD) s.has_rdoc = true s.requirements << 'none' diff --git a/vendor/rails/actionwebservice/lib/action_web_service/version.rb b/vendor/rails/actionwebservice/lib/action_web_service/version.rb index ebcb7eaa..a1b3d592 100644 --- a/vendor/rails/actionwebservice/lib/action_web_service/version.rb +++ b/vendor/rails/actionwebservice/lib/action_web_service/version.rb @@ -2,7 +2,7 @@ module ActionWebService module VERSION #:nodoc: MAJOR = 1 MINOR = 2 - TINY = 3 + TINY = 5 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/vendor/rails/activerecord/CHANGELOG b/vendor/rails/activerecord/CHANGELOG index 221f588a..07ed4d74 100644 --- a/vendor/rails/activerecord/CHANGELOG +++ b/vendor/rails/activerecord/CHANGELOG @@ -1,3 +1,37 @@ +*1.15.5* (October 12th, 2007) + +* Depend on Action Pack 1.4.4 + + +*1.15.4* (October 4th, 2007) + +* Fix #count on a has_many :through association so that it recognizes the :uniq option. Closes #8801 [lifofifo] + +* Don't clobber includes passed to has_many.count [danger] + +* Make sure has_many uses :include when counting [danger] + +* Save associated records only if the association is already loaded. #8713 [blaine] + +* Changing the :default Date format doesn't break date quoting. #6312 [bshand, Elias] + +* Allow nil serialized attributes with a set class constraint. #7293 [sandofsky] + +* belongs_to assignment creates a new proxy rather than modifying its target in-place. #8412 [mmangino@elevatedrails.com] + +* Fix column type detection while loading fixtures. Closes #7987 [roderickvd] + +* Document deep eager includes. #6267 [Josh Susser, Dan Manges] + +* Oracle: extract column length for CHAR also. #7866 [ymendel] + +* Small additions and fixes for ActiveRecord documentation. Closes #7342 [jeremymcanally] + +* SQLite: binary escaping works with $KCODE='u'. #7862 [tsuka] + +* Improved cloning performance by relying less on exception raising #8159 [Blaine] + + *1.15.3* (March 12th, 2007) * Allow a polymorphic :source for has_many :through associations. Closes #7143 [protocool] diff --git a/vendor/rails/activerecord/Rakefile b/vendor/rails/activerecord/Rakefile index fb3c2c74..e7fd12c4 100755 --- a/vendor/rails/activerecord/Rakefile +++ b/vendor/rails/activerecord/Rakefile @@ -151,7 +151,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', '= 1.4.2' + PKG_BUILD) + s.add_dependency('activesupport', '= 1.4.4' + PKG_BUILD) s.files.delete "test/fixtures/fixture_database.sqlite" s.files.delete "test/fixtures/fixture_database_2.sqlite" diff --git a/vendor/rails/activerecord/lib/active_record/acts/list.rb b/vendor/rails/activerecord/lib/active_record/acts/list.rb index 87bb1280..fdf1c14c 100644 --- a/vendor/rails/activerecord/lib/active_record/acts/list.rb +++ b/vendor/rails/activerecord/lib/active_record/acts/list.rb @@ -63,7 +63,7 @@ module ActiveRecord #{scope_condition_method} - after_destroy :remove_from_list + before_destroy :remove_from_list before_create :add_to_list_bottom EOV end @@ -74,6 +74,7 @@ module ActiveRecord # lower in the list of all chapters. Likewise, chapter.first? would return true if that chapter is # the first in the list of all chapters. module InstanceMethods + # Insert the item at the given position (defaults to the top position of 1). def insert_at(position = 1) insert_at_position(position) end @@ -118,8 +119,12 @@ module ActiveRecord end end + # Removes the item from the list. def remove_from_list - decrement_positions_on_lower_items if in_list? + if in_list? + decrement_positions_on_lower_items + update_attribute position_column, nil + end end # Increase the position of this item without adjusting the rest of the list. @@ -162,6 +167,7 @@ module ActiveRecord ) end + # Test if this record is in a list def in_list? !send(position_column).nil? end @@ -178,21 +184,26 @@ module ActiveRecord # Overwrite this method to define the scope of the list changes def scope_condition() "1" end + # Returns the bottom position number in the list. + # bottom_position_in_list # => 2 def bottom_position_in_list(except = nil) item = bottom_item(except) item ? item.send(position_column) : 0 end + # Returns the bottom item def bottom_item(except = nil) conditions = scope_condition conditions = "#{conditions} AND #{self.class.primary_key} != #{except.id}" if except acts_as_list_class.find(:first, :conditions => conditions, :order => "#{position_column} DESC") end + # Forces item to assume the bottom position in the list. def assume_bottom_position update_attribute(position_column, bottom_position_in_list(self).to_i + 1) end + # Forces item to assume the top position in the list. def assume_top_position update_attribute(position_column, 1) end @@ -227,6 +238,7 @@ module ActiveRecord ) end + # Increments position (position_column) of all items in the list. def increment_positions_on_all_items acts_as_list_class.update_all( "#{position_column} = (#{position_column} + 1)", "#{scope_condition}" diff --git a/vendor/rails/activerecord/lib/active_record/acts/tree.rb b/vendor/rails/activerecord/lib/active_record/acts/tree.rb index 44432d47..b92587e5 100644 --- a/vendor/rails/activerecord/lib/active_record/acts/tree.rb +++ b/vendor/rails/activerecord/lib/active_record/acts/tree.rb @@ -70,16 +70,23 @@ module ActiveRecord nodes end + # Returns the root node of the tree. def root node = self node = node.parent while node.parent node end + # Returns all siblings of the current node. + # + # subchild1.siblings # => [subchild2] def siblings self_and_siblings - [self] end + # Returns all siblings and a reference to the current node. + # + # subchild1.self_and_siblings # => [subchild1, subchild2] def self_and_siblings parent ? parent.children : self.class.roots end diff --git a/vendor/rails/activerecord/lib/active_record/associations.rb b/vendor/rails/activerecord/lib/active_record/associations.rb index 354d3c3f..8cdf748a 100755 --- a/vendor/rails/activerecord/lib/active_record/associations.rb +++ b/vendor/rails/activerecord/lib/active_record/associations.rb @@ -352,7 +352,15 @@ module ActiveRecord # for post in Post.find(:all, :include => [ :author, :comments ]) # # That'll add another join along the lines of: LEFT OUTER JOIN comments ON comments.post_id = posts.id. And we'll be down to 1 query. - # But that shouldn't fool you to think that you can pull out huge amounts of data with no performance penalty just because you've reduced + # + # To include a deep hierarchy of associations, using a hash: + # + # for post in Post.find(:all, :include => [ :author, { :comments => { :author => :gravatar } } ]) + # + # That'll grab not only all the comments but all their authors and gravatar pictures. You can mix and match + # symbols, arrays and hashes in any combination to describe the associations you want to load. + # + # All of this power shouldn't fool you into thinking that you can pull out huge amounts of data with no performance penalty just because you've reduced # the number of queries. The database still needs to send all the data to Active Record and it still needs to be processed. So it's no # catch-all for performance problems, but it's a great way to cut down on the number of queries in a situation as the one described above. # @@ -734,6 +742,7 @@ module ActiveRecord deprecated_association_comparison_method(reflection.name, reflection.class_name) end + # Create the callbacks to update counter cache if options[:counter_cache] cache_column = options[:counter_cache] == true ? "#{self.to_s.underscore.pluralize}_count" : @@ -871,6 +880,12 @@ module ActiveRecord end private + # Generate a join table name from two provided tables names. + # The order of names in join name is determined by lexical precedence. + # join_table_name("members", "clubs") + # => "clubs_members" + # join_table_name("members", "special_clubs") + # => "members_special_clubs" def join_table_name(first_table_name, second_table_name) if first_table_name < second_table_name join_table = "#{first_table_name}_#{second_table_name}" @@ -880,7 +895,7 @@ module ActiveRecord table_name_prefix + join_table + table_name_suffix end - + def association_accessor_methods(reflection, association_proxy_class) define_method(reflection.name) do |*params| force_reload = params.first unless params.empty? @@ -901,7 +916,7 @@ module ActiveRecord define_method("#{reflection.name}=") do |new_value| association = instance_variable_get("@#{reflection.name}") - if association.nil? + if association.nil? || association.target != new_value association = association_proxy_class.new(self, reflection) end @@ -911,10 +926,7 @@ module ActiveRecord instance_variable_set("@#{reflection.name}", association) else instance_variable_set("@#{reflection.name}", nil) - return nil end - - association end define_method("set_#{reflection.name}_target") do |target| @@ -981,18 +993,21 @@ module ActiveRecord after_callback = <<-end_eval association = instance_variable_get("@#{association_name}") - - if association.respond_to?(:loaded?) - if @new_record_before_save - records_to_save = association - else - records_to_save = association.select { |record| record.new_record? } - end + + records_to_save = if @new_record_before_save + association + elsif association.respond_to?(:loaded?) && association.loaded? + association.select { |record| record.new_record? } + else + [] + end + + if !records_to_save.blank? records_to_save.each { |record| association.send(:insert_record, record) } association.send(:construct_sql) # reconstruct the SQL queries now that we know the owner's id end end_eval - + # Doesn't use after_save as that would save associations added in after_create/after_update twice after_create(after_callback) after_update(after_callback) diff --git a/vendor/rails/activerecord/lib/active_record/associations/association_collection.rb b/vendor/rails/activerecord/lib/active_record/associations/association_collection.rb index 552c1ed0..e5bf157e 100644 --- a/vendor/rails/activerecord/lib/active_record/associations/association_collection.rb +++ b/vendor/rails/activerecord/lib/active_record/associations/association_collection.rb @@ -91,7 +91,11 @@ module ActiveRecord attributes.collect { |attr| create(attr) } else record = build(attributes) - record.save unless @owner.new_record? + if @owner.new_record? + ActiveSupport::Deprecation.warn("Calling .create on a has_many association without saving its owner will not work in rails 2.0, you probably want .build instead") + else + record.save + end record end end diff --git a/vendor/rails/activerecord/lib/active_record/associations/has_many_association.rb b/vendor/rails/activerecord/lib/active_record/associations/has_many_association.rb index 0a275ab4..5460c63e 100644 --- a/vendor/rails/activerecord/lib/active_record/associations/has_many_association.rb +++ b/vendor/rails/activerecord/lib/active_record/associations/has_many_association.rb @@ -50,7 +50,7 @@ module ActiveRecord options[:conditions] = options[:conditions].nil? ? @finder_sql : @finder_sql + " AND (#{sanitize_sql(options[:conditions])})" - options[:include] = @reflection.options[:include] + options[:include] ||= @reflection.options[:include] @reflection.klass.count(column_name, options) end @@ -138,7 +138,7 @@ module ActiveRecord elsif @reflection.options[:counter_sql] @reflection.klass.count_by_sql(@counter_sql) else - @reflection.klass.count(:conditions => @counter_sql) + @reflection.klass.count(:conditions => @counter_sql, :include => @reflection.options[:include]) end @target = [] and loaded if count == 0 diff --git a/vendor/rails/activerecord/lib/active_record/associations/has_many_through_association.rb b/vendor/rails/activerecord/lib/active_record/associations/has_many_through_association.rb index a8ad52be..61e6020b 100644 --- a/vendor/rails/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/vendor/rails/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -101,6 +101,16 @@ module ActiveRecord def sum(*args, &block) calculate(:sum, *args, &block) end + + def count(*args) + column_name, options = @reflection.klass.send(:construct_count_options_from_legacy_args, *args) + if @reflection.options[:uniq] + # This is needed becase 'SELECT count(DISTINCT *)..' is not valid sql statement. + column_name = "#{@reflection.klass.table_name}.#{@reflection.klass.primary_key}" if column_name == :all + options.merge!(:distinct => true) + end + @reflection.klass.send(:with_scope, construct_scope) { @reflection.klass.count(column_name, options) } + end protected def method_missing(method, *args, &block) diff --git a/vendor/rails/activerecord/lib/active_record/base.rb b/vendor/rails/activerecord/lib/active_record/base.rb index 258aa537..6ddb1c7a 100755 --- a/vendor/rails/activerecord/lib/active_record/base.rb +++ b/vendor/rails/activerecord/lib/active_record/base.rb @@ -575,7 +575,7 @@ module ActiveRecord #:nodoc: # Specifies that the attribute by the name of +attr_name+ should be serialized before saving to the database and unserialized # after loading from the database. The serialization is done through YAML. If +class_name+ is specified, the serialized - # object must be of that class on retrieval or +SerializationTypeMismatch+ will be raised. + # object must be of that class on retrieval, or nil. Otherwise, +SerializationTypeMismatch+ will be raised. def serialize(attr_name, class_name = Object) serialized_attributes[attr_name.to_s] = class_name end @@ -1188,6 +1188,9 @@ module ActiveRecord #:nodoc: # # It's even possible to use all the additional parameters to find. For example, the full interface for find_all_by_amount # is actually find_all_by_amount(amount, options). + # + # This also enables you to initialize a record if it is not found, such as find_or_initialize_by_amount(amount) + # or find_or_create_by_user_and_password(user, password). def method_missing(method_id, *arguments) if match = /^find_(all_by|by)_([_a-zA-Z]\w*)$/.match(method_id.to_s) finder, deprecated_finder = determine_finder(match), determine_deprecated_finder(match) @@ -1957,7 +1960,7 @@ module ActiveRecord #:nodoc: def unserialize_attribute(attr_name) unserialized_object = object_from_yaml(@attributes[attr_name]) - if unserialized_object.is_a?(self.class.serialized_attributes[attr_name]) + if unserialized_object.is_a?(self.class.serialized_attributes[attr_name]) || unserialized_object.nil? @attributes[attr_name] = unserialized_object else raise SerializationTypeMismatch, @@ -2156,7 +2159,13 @@ module ActiveRecord #:nodoc: def clone_attribute_value(reader_method, attribute_name) value = send(reader_method, attribute_name) - value.clone + + case value + when nil, Fixnum, true, false + value + else + value.clone + end rescue TypeError, NoMethodError value end diff --git a/vendor/rails/activerecord/lib/active_record/calculations.rb b/vendor/rails/activerecord/lib/active_record/calculations.rb index 6647458d..1d9ac4b1 100644 --- a/vendor/rails/activerecord/lib/active_record/calculations.rb +++ b/vendor/rails/activerecord/lib/active_record/calculations.rb @@ -242,8 +242,8 @@ module ActiveRecord options.assert_valid_keys(CALCULATIONS_OPTIONS) end - # converts a given key to the value that the database adapter returns as - # + # Converts a given key to the value that the database adapter returns as + # as a usable column name. # users.id #=> users_id # sum(id) #=> sum_id # count(distinct users.id) #=> count_distinct_users_id diff --git a/vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb index 0f2008de..38ba490a 100644 --- a/vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +++ b/vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb @@ -24,7 +24,7 @@ module ActiveRecord when Float, Fixnum, Bignum then value.to_s # BigDecimals need to be output in a non-normalized form and quoted. when BigDecimal then value.to_s('F') - when Date then "'#{value.to_s}'" + when Date then "'#{value.to_s(:db)}'" when Time, DateTime then "'#{quoted_date(value)}'" else "'#{quote_string(value.to_yaml)}'" end diff --git a/vendor/rails/activerecord/lib/active_record/connection_adapters/oracle_adapter.rb b/vendor/rails/activerecord/lib/active_record/connection_adapters/oracle_adapter.rb index 4e7c3c39..c69b8447 100644 --- a/vendor/rails/activerecord/lib/active_record/connection_adapters/oracle_adapter.rb +++ b/vendor/rails/activerecord/lib/active_record/connection_adapters/oracle_adapter.rb @@ -320,6 +320,7 @@ begin decode(data_type, 'NUMBER', data_precision, 'FLOAT', data_precision, 'VARCHAR2', data_length, + 'CHAR', data_length, null) as limit, decode(data_type, 'NUMBER', data_scale, null) as scale from all_tab_columns 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 2a268975..0a9c57e1 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 @@ -68,7 +68,7 @@ module ActiveRecord class SQLiteColumn < Column #:nodoc: class << self def string_to_binary(value) - value.gsub(/\0|\%/) do |b| + value.gsub(/\0|\%/n) do |b| case b when "\0" then "%00" when "%" then "%25" @@ -77,7 +77,7 @@ module ActiveRecord end def binary_to_string(value) - value.gsub(/%00|%25/) do |b| + value.gsub(/%00|%25/n) do |b| case b when "%00" then "\0" when "%25" then "%" diff --git a/vendor/rails/activerecord/lib/active_record/deprecated_finders.rb b/vendor/rails/activerecord/lib/active_record/deprecated_finders.rb index 4ab2dde5..d4dcaa3f 100644 --- a/vendor/rails/activerecord/lib/active_record/deprecated_finders.rb +++ b/vendor/rails/activerecord/lib/active_record/deprecated_finders.rb @@ -1,7 +1,7 @@ module ActiveRecord class Base class << self - # This method is deprecated in favor of find with the :conditions option. + # DEPRECATION NOTICE: This method is deprecated in favor of find with the :conditions option. # # Works like find, but the record matching +id+ must also meet the +conditions+. # +RecordNotFound+ is raised if no record can be found matching the +id+ or meeting the condition. @@ -12,7 +12,7 @@ module ActiveRecord end deprecate :find_on_conditions => "use find(ids, :conditions => conditions)" - # This method is deprecated in favor of find(:first, options). + # DEPRECATION NOTICE: This method is deprecated in favor of find(:first, options). # # Returns the object for the first record responding to the conditions in +conditions+, # such as "group = 'master'". If more than one record is returned from the query, it's the first that'll @@ -24,7 +24,7 @@ module ActiveRecord end deprecate :find_first => "use find(:first, ...)" - # This method is deprecated in favor of find(:all, options). + # DEPRECATION NOTICE: This method is deprecated in favor of find(:all, options). # # Returns an array of all the objects that could be instantiated from the associated # table in the database. The +conditions+ can be used to narrow the selection of objects (WHERE-part), diff --git a/vendor/rails/activerecord/lib/active_record/fixtures.rb b/vendor/rails/activerecord/lib/active_record/fixtures.rb index 4109d366..43d4bdae 100755 --- a/vendor/rails/activerecord/lib/active_record/fixtures.rb +++ b/vendor/rails/activerecord/lib/active_record/fixtures.rb @@ -412,7 +412,7 @@ class Fixture #:nodoc: klass = @class_name.constantize rescue nil list = @fixture.inject([]) do |fixtures, (key, value)| - col = klass.columns_hash[key] if klass.kind_of?(ActiveRecord::Base) + col = klass.columns_hash[key] if klass.respond_to?(:ancestors) && klass.ancestors.include?(ActiveRecord::Base) fixtures << ActiveRecord::Base.connection.quote(value, col).gsub('[^\]\\n', "\n").gsub('[^\]\\r', "\r") end list * ', ' diff --git a/vendor/rails/activerecord/lib/active_record/timestamp.rb b/vendor/rails/activerecord/lib/active_record/timestamp.rb index 9c7e7981..2fff7b9d 100644 --- a/vendor/rails/activerecord/lib/active_record/timestamp.rb +++ b/vendor/rails/activerecord/lib/active_record/timestamp.rb @@ -5,15 +5,6 @@ module ActiveRecord # Timestamping can be turned off by setting # ActiveRecord::Base.record_timestamps = false # - # Keep in mind that, via inheritance, you can turn off timestamps on a per - # model basis by setting record_timestamps to false in the desired - # models. - # - # class Feed < ActiveRecord::Base - # self.record_timestamps = false - # # ... - # end - # # Timestamps are in the local timezone by default but can use UTC by setting # ActiveRecord::Base.default_timezone = :utc module Timestamp diff --git a/vendor/rails/activerecord/lib/active_record/version.rb b/vendor/rails/activerecord/lib/active_record/version.rb index 4027561d..fb1a3716 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 = 1 MINOR = 15 - TINY = 3 + TINY = 5 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/vendor/rails/activerecord/test/associations/eager_test.rb b/vendor/rails/activerecord/test/associations/eager_test.rb index 0d69af1c..6c054e9e 100644 --- a/vendor/rails/activerecord/test/associations/eager_test.rb +++ b/vendor/rails/activerecord/test/associations/eager_test.rb @@ -168,6 +168,12 @@ class EagerAssociationTest < Test::Unit::TestCase posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => "posts.title = 'magic forest'") assert_equal 0, posts.size end + + def test_eager_count_performed_on_a_has_many_association_with_multi_table_conditional + author = authors(:david) + author_posts_without_comments = author.posts.select { |post| post.comments.blank? } + assert_equal author_posts_without_comments.size, author.posts.count(:all, :include => :comments, :conditions => 'comments.id is null') + end def test_eager_with_has_and_belongs_to_many_and_limit posts = Post.find(:all, :include => :categories, :order => "posts.id", :limit => 3) @@ -271,6 +277,13 @@ class EagerAssociationTest < Test::Unit::TestCase assert_not_nil f.account assert_equal companies(:first_firm, :reload).account, f.account end + + def test_eager_with_multi_table_conditional_properly_counts_the_records_when_using_size + author = authors(:david) + posts_with_no_comments = author.posts.select { |post| post.comments.blank? } + assert_equal posts_with_no_comments.size, author.posts_with_no_comments.size + assert_equal posts_with_no_comments, author.posts_with_no_comments + end def test_eager_with_invalid_association_reference assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { diff --git a/vendor/rails/activerecord/test/associations/join_model_test.rb b/vendor/rails/activerecord/test/associations/join_model_test.rb index a5e525c6..770b8038 100644 --- a/vendor/rails/activerecord/test/associations/join_model_test.rb +++ b/vendor/rails/activerecord/test/associations/join_model_test.rb @@ -29,7 +29,16 @@ class AssociationsJoinModelTest < Test::Unit::TestCase assert_equal 2, authors(:mary).categorized_posts.size assert_equal 1, authors(:mary).unique_categorized_posts.size end - + + def test_has_many_uniq_through_count + author = authors(:mary) + assert !authors(:mary).unique_categorized_posts.loaded? + assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count } + assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count(:title, {}) } + assert_queries(1) { assert_equal 0, author.unique_categorized_posts.count(:title, { :conditions => "title is NULL" }) } + assert !authors(:mary).unique_categorized_posts.loaded? + end + def test_polymorphic_has_many assert posts(:welcome).taggings.include?(taggings(:welcome_general)) end diff --git a/vendor/rails/activerecord/test/associations_test.rb b/vendor/rails/activerecord/test/associations_test.rb index f1b02cfd..1de094fd 100755 --- a/vendor/rails/activerecord/test/associations_test.rb +++ b/vendor/rails/activerecord/test/associations_test.rb @@ -67,8 +67,8 @@ class AssociationsTest < Test::Unit::TestCase end class AssociationProxyTest < Test::Unit::TestCase - fixtures :authors, :posts - + fixtures :authors, :posts, :developers, :projects, :developers_projects + def test_proxy_accessors welcome = posts(:welcome) assert_equal welcome, welcome.author.proxy_owner @@ -87,6 +87,19 @@ class AssociationProxyTest < Test::Unit::TestCase david.posts_with_extension.first # force load target assert_equal david.posts_with_extension, david.posts_with_extension.testing_proxy_target end + + def test_save_on_parent_does_not_load_target + david = developers(:david) + + assert !david.projects.loaded? + david.update_attribute(:created_at, Time.now) + assert !david.projects.loaded? + end + + def test_save_on_parent_saves_children + developer = Developer.create :name => "Bryan", :salary => 50_000 + assert_equal 1, developer.reload.audit_logs.size + end end class HasOneAssociationsTest < Test::Unit::TestCase @@ -583,6 +596,13 @@ class HasManyAssociationsTest < Test::Unit::TestCase assert_equal 3, first_firm.plain_clients.size end + def test_regular_create_on_has_many_when_parent_is_new_raises + assert_deprecated(/.build instead/) do + firm = Firm.new + firm.plain_clients.create :name=>"Whoever" + end + end + def test_adding_a_mismatch_class assert_raises(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << nil } assert_raises(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << 1 } @@ -1007,7 +1027,20 @@ class BelongsToAssociationsTest < Test::Unit::TestCase citibank.firm = apple assert_equal apple.id, citibank.firm_id end - + + def test_no_unexpected_aliasing + first_firm = companies(:first_firm) + another_firm = companies(:another_firm) + + citibank = Account.create("credit_limit" => 10) + citibank.firm = first_firm + original_proxy = citibank.firm + citibank.firm = another_firm + + assert_equal first_firm.object_id, original_proxy.object_id + assert_equal another_firm.object_id, citibank.firm.object_id + end + def test_creating_the_belonging_object citibank = Account.create("credit_limit" => 10) apple = citibank.create_firm("name" => "Apple") diff --git a/vendor/rails/activerecord/test/base_test.rb b/vendor/rails/activerecord/test/base_test.rb index 2e98952c..fd4ddc0a 100755 --- a/vendor/rails/activerecord/test/base_test.rb +++ b/vendor/rails/activerecord/test/base_test.rb @@ -1086,16 +1086,29 @@ class BasicsTest < Test::Unit::TestCase assert_equal(myobj, topic.content) end - def test_serialized_attribute_with_class_constraint + def test_nil_serialized_attribute_with_class_constraint myobj = MyObject.new('value1', 'value2') - topic = Topic.create("content" => myobj) + topic = Topic.new + assert_nil topic.content + end + + def test_should_raise_exception_on_serialized_attribute_with_type_mismatch + myobj = MyObject.new('value1', 'value2') + topic = Topic.new(:content => myobj) + assert topic.save Topic.serialize(:content, Hash) - assert_raise(ActiveRecord::SerializationTypeMismatch) { Topic.find(topic.id).content } + ensure + Topic.serialize(:content) + end + def test_serialized_attribute_with_class_constraint settings = { "color" => "blue" } - Topic.find(topic.id).update_attribute("content", settings) + Topic.serialize(:content, Hash) + topic = Topic.new(:content => settings) + assert topic.save assert_equal(settings, Topic.find(topic.id).content) + ensure Topic.serialize(:content) end diff --git a/vendor/rails/activerecord/test/fixtures/author.rb b/vendor/rails/activerecord/test/fixtures/author.rb index 6b34c752..5571f2cf 100644 --- a/vendor/rails/activerecord/test/fixtures/author.rb +++ b/vendor/rails/activerecord/test/fixtures/author.rb @@ -25,6 +25,7 @@ class Author < ActiveRecord::Base has_many :hello_posts, :class_name => "Post", :conditions => "posts.body = 'hello'" has_many :hello_post_comments, :through => :hello_posts, :source => :comments + has_many :posts_with_no_comments, :class_name => 'Post', :conditions => 'comments.id is null', :include => :comments has_many :other_posts, :class_name => "Post" has_many :posts_with_callbacks, :class_name => "Post", :before_add => :log_before_adding, diff --git a/vendor/rails/activerecord/test/fixtures/binaries.yml b/vendor/rails/activerecord/test/fixtures/binaries.yml new file mode 100644 index 00000000..b01e6902 --- /dev/null +++ b/vendor/rails/activerecord/test/fixtures/binaries.yml @@ -0,0 +1,437 @@ +flowers: + id: 1 + data: !binary | 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 + KKpVChRRRQAUUUUAFFFFABRRRQAUUUUAf//Z + diff --git a/vendor/rails/activerecord/test/fixtures/db_definitions/schema.rb b/vendor/rails/activerecord/test/fixtures/db_definitions/schema.rb index 9c851817..ca1cac51 100644 --- a/vendor/rails/activerecord/test/fixtures/db_definitions/schema.rb +++ b/vendor/rails/activerecord/test/fixtures/db_definitions/schema.rb @@ -57,4 +57,9 @@ ActiveRecord::Schema.define do create_table :lock_without_defaults_cust, :force => true do |t| t.column :custom_lock_version, :integer end + + create_table :audit_logs, :force => true do |t| + t.column :message, :string, :null=>false + t.column :developer_id, :integer, :null=>false + end end diff --git a/vendor/rails/activerecord/test/fixtures/developer.rb b/vendor/rails/activerecord/test/fixtures/developer.rb index 75fb307b..ebe91a48 100644 --- a/vendor/rails/activerecord/test/fixtures/developer.rb +++ b/vendor/rails/activerecord/test/fixtures/developer.rb @@ -31,8 +31,18 @@ class Developer < ActiveRecord::Base has_and_belongs_to_many :special_projects, :join_table => 'developers_projects', :association_foreign_key => 'project_id' + has_many :audit_logs + validates_inclusion_of :salary, :in => 50000..200000 validates_length_of :name, :within => 3..20 + + before_create do |developer| + developer.audit_logs.build :message => "Computer created" + end +end + +class AuditLog < ActiveRecord::Base + belongs_to :developer end DeveloperSalary = Struct.new(:amount) diff --git a/vendor/rails/activerecord/test/fixtures_test.rb b/vendor/rails/activerecord/test/fixtures_test.rb index 35882526..2a9c78e4 100755 --- a/vendor/rails/activerecord/test/fixtures_test.rb +++ b/vendor/rails/activerecord/test/fixtures_test.rb @@ -12,13 +12,15 @@ class FixturesTest < Test::Unit::TestCase self.use_instantiated_fixtures = true self.use_transactional_fixtures = false - fixtures :topics, :developers, :accounts, :tasks, :categories, :funny_jokes + fixtures :topics, :developers, :accounts, :tasks, :categories, :funny_jokes, :binaries - FIXTURES = %w( accounts companies customers + FIXTURES = %w( accounts binaries companies customers developers developers_projects entrants movies projects subscribers topics tasks ) MATCH_ATTRIBUTE_NAME = /[a-zA-Z][-_\w]*/ + BINARY_FIXTURE_PATH = File.dirname(__FILE__) + '/fixtures/flowers.jpg' + def test_clean_fixtures FIXTURES.each do |name| fixtures = nil @@ -100,7 +102,6 @@ class FixturesTest < Test::Unit::TestCase assert first end - def test_bad_format path = File.join(File.dirname(__FILE__), 'fixtures', 'bad_fixtures') Dir.entries(path).each do |file| @@ -174,7 +175,6 @@ class FixturesTest < Test::Unit::TestCase end end - def test_yml_file_in_subdirectory assert_equal(categories(:sub_special_1).name, "A special category in a subdir file") assert_equal(categories(:sub_special_1).class, SpecialCategory) @@ -185,7 +185,11 @@ class FixturesTest < Test::Unit::TestCase assert_equal(categories(:sub_special_3).class, SpecialCategory) end - + def test_binary_in_fixtures + assert_equal 1, @binaries.size + data = File.read(BINARY_FIXTURE_PATH).freeze + assert_equal data, @flowers.data + end end if Account.connection.respond_to?(:reset_pk_sequence!) diff --git a/vendor/rails/activerecord/test/migration_test.rb b/vendor/rails/activerecord/test/migration_test.rb index 0d78a4e4..8ae97c71 100644 --- a/vendor/rails/activerecord/test/migration_test.rb +++ b/vendor/rails/activerecord/test/migration_test.rb @@ -170,7 +170,7 @@ if ActiveRecord::Base.connection.supports_migrations? # SQL Server and Sybase will not allow you to add a NOT NULL column # to a table without specifying a default value, so the # following test must be skipped - unless current_adapter?(:SQLServerAdapter, :SybaseAdapter) + unless current_adapter?(:SQLServerAdapter, :SybaseAdapter, :SQLiteAdapter) def test_add_column_not_null_without_default Person.connection.create_table :testings do |t| t.column :foo, :string @@ -209,7 +209,7 @@ if ActiveRecord::Base.connection.supports_migrations? def test_native_decimal_insert_manual_vs_automatic # SQLite3 always uses float in violation of SQL # 16 decimal places - correct_value = (current_adapter?(:SQLiteAdapter) ? '0.123456789012346E20' : '0012345678901234567890.0123456789').to_d + correct_value = '0012345678901234567890.0123456789'.to_d Person.delete_all Person.connection.add_column "people", "wealth", :decimal, :precision => '30', :scale => '10' @@ -227,8 +227,9 @@ if ActiveRecord::Base.connection.supports_migrations? assert_kind_of BigDecimal, row.wealth # If this assert fails, that means the SELECT is broken! - assert_equal correct_value, row.wealth - + unless current_adapter?(:SQLite3Adapter) + assert_equal correct_value, row.wealth + end # Reset to old state Person.delete_all @@ -240,8 +241,9 @@ if ActiveRecord::Base.connection.supports_migrations? assert_kind_of BigDecimal, row.wealth # If these asserts fail, that means the INSERT (create function, or cast to SQL) is broken! - assert_equal correct_value, row.wealth - + unless current_adapter?(:SQLite3Adapter) + assert_equal correct_value, row.wealth + end # Reset to old state Person.connection.del_column "people", "wealth" rescue nil Person.reset_column_information @@ -267,10 +269,7 @@ if ActiveRecord::Base.connection.supports_migrations? # Test for 30 significent digits (beyond the 16 of float), 10 of them # after the decimal place. - if current_adapter?(:SQLiteAdapter) - # SQLite3 uses float in violation of SQL. Test for 16 decimal places. - assert_equal BigDecimal.new('0.123456789012346E20'), bob.wealth - else + unless current_adapter?(:SQLite3Adapter) assert_equal BigDecimal.new("0012345678901234567890.0123456789"), bob.wealth end diff --git a/vendor/rails/activerecord/test/mixin_test.rb b/vendor/rails/activerecord/test/mixin_test.rb index d4fbab85..e10650e7 100644 --- a/vendor/rails/activerecord/test/mixin_test.rb +++ b/vendor/rails/activerecord/test/mixin_test.rb @@ -211,6 +211,53 @@ class ListTest < Test::Unit::TestCase assert_equal [new2, new1, new3], ListMixin.find(:all, :conditions => 'parent_id IS NULL', :order => 'pos') end + def test_remove_from_list_should_then_fail_in_list? + assert_equal true, mixins(:list_1).in_list? + mixins(:list_1).remove_from_list + assert_equal false, mixins(:list_1).in_list? + end + + def test_remove_from_list_should_set_position_to_nil + assert_equal [mixins(:list_1), + mixins(:list_2), + mixins(:list_3), + mixins(:list_4)], + ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos') + + mixins(:list_2).remove_from_list + + assert_equal [mixins(:list_2, :reload), + mixins(:list_1, :reload), + mixins(:list_3, :reload), + mixins(:list_4, :reload)], + ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos') + + assert_equal 1, mixins(:list_1).pos + assert_equal nil, mixins(:list_2).pos + assert_equal 2, mixins(:list_3).pos + assert_equal 3, mixins(:list_4).pos + end + + def test_remove_before_destroy_does_not_shift_lower_items_twice + assert_equal [mixins(:list_1), + mixins(:list_2), + mixins(:list_3), + mixins(:list_4)], + ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos') + + mixins(:list_2).remove_from_list + mixins(:list_2).destroy + + assert_equal [mixins(:list_1, :reload), + mixins(:list_3, :reload), + mixins(:list_4, :reload)], + ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos') + + assert_equal 1, mixins(:list_1).pos + assert_equal 2, mixins(:list_3).pos + assert_equal 3, mixins(:list_4).pos + end + end class TreeTest < Test::Unit::TestCase diff --git a/vendor/rails/activerecord/test/validations_test.rb b/vendor/rails/activerecord/test/validations_test.rb index 9984b484..93c9ad48 100755 --- a/vendor/rails/activerecord/test/validations_test.rb +++ b/vendor/rails/activerecord/test/validations_test.rb @@ -631,7 +631,7 @@ class ValidationsTest < Test::Unit::TestCase t = Topic.new('title' => 'noreplies', 'content' => 'whatever') assert !t.save assert t.errors.on(:replies) - t.replies.create('title' => 'areply', 'content' => 'whateveragain') + t.replies.build('title' => 'areply', 'content' => 'whateveragain') assert t.valid? end @@ -824,7 +824,7 @@ class ValidationsTest < Test::Unit::TestCase t = Topic.new('title' => 'あいうえお', 'content' => 'かきくけこ') assert !t.save assert t.errors.on(:replies) - t.replies.create('title' => 'あいうえお', 'content' => 'かきくけこ') + t.replies.build('title' => 'あいうえお', 'content' => 'かきくけこ') assert t.valid? end end diff --git a/vendor/rails/activesupport/CHANGELOG b/vendor/rails/activesupport/CHANGELOG index a0f79489..f6a025f4 100644 --- a/vendor/rails/activesupport/CHANGELOG +++ b/vendor/rails/activesupport/CHANGELOG @@ -1,3 +1,19 @@ +*1.4.4* (October 12th, 2007) + +* Backport: allow array and hash query parameters. Array route parameters are converted/to/a/path as before. #6765, #7047, #7462 [bgipsy, Jeremy McAnally, Dan Kubb, brendan, Diego Algorta Casamayou] + + +*1.4.3* (October 4th, 2007) + +* Demote Hash#to_xml to use XmlSimple#xml_in_string so it can't read files or stdin. #8453 [candlerb, Jeremy Kemper] + +* Document Object#blank?. #6491 [Chris Mear] + +* Update Dependencies to ignore constants inherited from ancestors. Closes #6951. [Nicholas Seckar] + +* Improved multibyte performance by relying less on exception raising #8159 [Blaine] + + *1.4.2* (March 12th, 2007) * Ruby 1.8.6 and 1.9 define private Time#to_date and #to_datetime; make them diff --git a/vendor/rails/activesupport/lib/active_support/core_ext/blank.rb b/vendor/rails/activesupport/lib/active_support/core_ext/blank.rb index f7fbea3e..d2a940f5 100644 --- a/vendor/rails/activesupport/lib/active_support/core_ext/blank.rb +++ b/vendor/rails/activesupport/lib/active_support/core_ext/blank.rb @@ -1,5 +1,11 @@ -class Object #:nodoc: - # "", " ", nil, [], and {} are blank +class Object + # An object is blank if it's nil, empty, or a whitespace string. + # For example, "", " ", nil, [], and {} are blank. + # + # This simplifies + # if !address.nil? && !address.empty? + # to + # if !address.blank? def blank? if respond_to?(:empty?) && respond_to?(:strip) empty? or strip.empty? @@ -47,4 +53,4 @@ class Numeric #:nodoc: def blank? false end -end \ No newline at end of file +end 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 83054cde..93311404 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,5 +1,44 @@ require 'date' require 'xml_simple' +require 'cgi' + +# Extensions needed for Hash#to_query +class Object + def to_param #:nodoc: + to_s + end + + def to_query(key) #:nodoc: + "#{CGI.escape(key.to_s)}=#{CGI.escape(to_param.to_s)}" + end +end + +class Array + def to_query(key) #:nodoc: + collect { |value| value.to_query("#{key}[]") }.sort * '&' + end +end + +# Locked down XmlSimple#xml_in_string +class XmlSimple + # Same as xml_in but doesn't try to smartly shoot itself in the foot. + def xml_in_string(string, options = nil) + handle_options('in', options) + + @doc = parse(string) + result = collapse(@doc.root) + + if @options['keeproot'] + merge({}, @doc.root.name, result) + else + result + end + end + + def self.xml_in_string(string, options = nil) + new.xml_in_string(string, options) + end +end module ActiveSupport #:nodoc: module CoreExtensions #:nodoc: @@ -27,6 +66,12 @@ module ActiveSupport #:nodoc: klass.extend(ClassMethods) end + def to_query(namespace = nil) + collect do |key, value| + value.to_query(namespace ? "#{namespace}[#{key}]" : key) + end.sort * '&' + end + def to_xml(options = {}) options[:indent] ||= 2 options.reverse_merge!({ :builder => Builder::XmlMarkup.new(:indent => options[:indent]), @@ -81,14 +126,14 @@ module ActiveSupport #:nodoc: module ClassMethods def from_xml(xml) # TODO: Refactor this into something much cleaner that doesn't rely on XmlSimple - undasherize_keys(typecast_xml_value(XmlSimple.xml_in(xml, + undasherize_keys(typecast_xml_value(XmlSimple.xml_in_string(xml, 'forcearray' => false, 'forcecontent' => true, 'keeproot' => true, 'contentkey' => '__content__') - )) + )) end - + def create_from_xml(xml) ActiveSupport::Deprecation.warn("Hash.create_from_xml has been renamed to Hash.from_xml", caller) from_xml(xml) diff --git a/vendor/rails/activesupport/lib/active_support/core_ext/module/introspection.rb b/vendor/rails/activesupport/lib/active_support/core_ext/module/introspection.rb index 0cd0d1ff..36481927 100644 --- a/vendor/rails/activesupport/lib/active_support/core_ext/module/introspection.rb +++ b/vendor/rails/activesupport/lib/active_support/core_ext/module/introspection.rb @@ -18,4 +18,18 @@ class Module parents << Object unless parents.include? Object parents end + + # Return the constants that have been defined locally by this object and not + # in an ancestor. This method may miss some constants if their definition in + # the ancestor is identical to their definition in the receiver. + def local_constants + inherited = {} + ancestors.each do |anc| + next if anc == self + anc.constants.each { |const| inherited[const] = anc.const_get(const) } + end + constants.select do |const| + ! inherited.key?(const) || inherited[const].object_id != const_get(const).object_id + end + end end diff --git a/vendor/rails/activesupport/lib/active_support/dependencies.rb b/vendor/rails/activesupport/lib/active_support/dependencies.rb index 4880b708..2f6ae284 100644 --- a/vendor/rails/activesupport/lib/active_support/dependencies.rb +++ b/vendor/rails/activesupport/lib/active_support/dependencies.rb @@ -318,13 +318,13 @@ module Dependencies #:nodoc: watch_frames = descs.collect do |desc| if desc.is_a? Module mod_name = desc.name - initial_constants = desc.constants + initial_constants = desc.local_constants elsif desc.is_a?(String) || desc.is_a?(Symbol) mod_name = desc.to_s # Handle the case where the module has yet to be defined. initial_constants = if qualified_const_defined?(mod_name) - mod_name.constantize.constants + mod_name.constantize.local_constants else [] end @@ -349,7 +349,7 @@ module Dependencies #:nodoc: mod = mod_name.constantize next [] unless mod.is_a? Module - new_constants = mod.constants - prior_constants + new_constants = mod.local_constants - prior_constants # Make sure no other frames takes credit for these constants. constant_watch_stack.each do |frame_name, constants| diff --git a/vendor/rails/activesupport/lib/active_support/json/encoders/core.rb b/vendor/rails/activesupport/lib/active_support/json/encoders/core.rb index f6cdfbcd..df50c012 100644 --- a/vendor/rails/activesupport/lib/active_support/json/encoders/core.rb +++ b/vendor/rails/activesupport/lib/active_support/json/encoders/core.rb @@ -23,12 +23,14 @@ module ActiveSupport "\n" => '\n', "\r" => '\r', "\t" => '\t', - '"' => '\"', - '\\' => '\\\\' + '"' => '\"', + '\\' => '\\\\', + '<' => '\\074', + '>' => '\\076' } define_encoder String do |string| - '"' + string.gsub(/[\010\f\n\r\t"\\]/) { |s| + '"' + string.gsub(/[\010\f\n\r\t"\\<>]/) { |s| ESCAPED_CHARS[s] }.gsub(/([\xC0-\xDF][\x80-\xBF]| [\xE0-\xEF][\x80-\xBF]{2}| diff --git a/vendor/rails/activesupport/lib/active_support/multibyte/chars.rb b/vendor/rails/activesupport/lib/active_support/multibyte/chars.rb index 374adc78..90181509 100644 --- a/vendor/rails/activesupport/lib/active_support/multibyte/chars.rb +++ b/vendor/rails/activesupport/lib/active_support/multibyte/chars.rb @@ -43,7 +43,7 @@ module ActiveSupport::Multibyte #:nodoc: # Create a new Chars instance. def initialize(str) - @string = (str.string rescue str) + @string = str.respond_to?(:string) ? str.string : str end # Returns -1, 0 or +1 depending on whether the Chars object is to be sorted before, equal or after the @@ -70,18 +70,18 @@ module ActiveSupport::Multibyte #:nodoc: def method_missing(m, *a, &b) begin # Simulate methods with a ! at the end because we can't touch the enclosed string from the handlers. - if m.to_s =~ /^(.*)\!$/ + if m.to_s =~ /^(.*)\!$/ && handler.respond_to?($1) result = handler.send($1, @string, *a, &b) if result == @string result = nil else @string.replace result end - else + elsif handler.respond_to?(m) result = handler.send(m, @string, *a, &b) + else + result = @string.send(m, *a, &b) end - rescue NoMethodError - result = @string.send(m, *a, &b) rescue Handlers::EncodingError @string.replace handler.tidy_bytes(@string) retry @@ -126,4 +126,4 @@ begin ActiveSupport::Multibyte::Chars.handler = ActiveSupport::Multibyte::Handlers::UTF8HandlerProc rescue LoadError ActiveSupport::Multibyte::Chars.handler = ActiveSupport::Multibyte::Handlers::UTF8Handler -end \ No newline at end of file +end diff --git a/vendor/rails/activesupport/lib/active_support/version.rb b/vendor/rails/activesupport/lib/active_support/version.rb index d254873f..ff80ec6b 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 = 1 MINOR = 4 - TINY = 2 + TINY = 4 STRING = [MAJOR, MINOR, TINY].join('.') end 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 3ede4893..f4dbdf47 100644 --- a/vendor/rails/activesupport/test/core_ext/hash_ext_test.rb +++ b/vendor/rails/activesupport/test/core_ext/hash_ext_test.rb @@ -470,3 +470,40 @@ class HashToXmlTest < Test::Unit::TestCase end end end + +class QueryTest < Test::Unit::TestCase + def test_simple_conversion + assert_query_equal 'a=10', :a => 10 + end + + def test_cgi_escaping + assert_query_equal 'a%3Ab=c+d', 'a:b' => 'c d' + end + + def test_nil_parameter_value + empty = Object.new + def empty.to_param; nil end + assert_query_equal 'a=', 'a' => empty + end + + def test_nested_conversion + assert_query_equal 'person%5Bname%5D=Nicholas&person%5Blogin%5D=seckar', + :person => {:name => 'Nicholas', :login => 'seckar'} + end + + def test_multiple_nested + assert_query_equal 'account%5Bperson%5D%5Bid%5D=20&person%5Bid%5D=10', + :person => {:id => 10}, :account => {:person => {:id => 20}} + end + + def test_array_values + assert_query_equal 'person%5Bid%5D%5B%5D=10&person%5Bid%5D%5B%5D=20', + :person => {:id => [10, 20]} + end + + private + def assert_query_equal(expected, actual, message = nil) + assert_equal expected.split('&').sort, actual.to_query.split('&').sort + end +end + diff --git a/vendor/rails/activesupport/test/core_ext/module_test.rb b/vendor/rails/activesupport/test/core_ext/module_test.rb index bbf6dd16..884b4403 100644 --- a/vendor/rails/activesupport/test/core_ext/module_test.rb +++ b/vendor/rails/activesupport/test/core_ext/module_test.rb @@ -1,10 +1,14 @@ require File.dirname(__FILE__) + '/../abstract_unit' module One + Constant1 = "Hello World" + Constant2 = "What's up?" end class Ab include One + Constant1 = "Hello World" # Will have different object id than One::Constant1 + Constant3 = "Goodbye World" end module Xy @@ -91,6 +95,10 @@ class ModuleTest < Test::Unit::TestCase assert_equal [Yz::Zy, Yz, Object], Yz::Zy::Cd.parents assert_equal [Yz, Object], Yz::Zy.parents end + + def test_local_constants + assert_equal %w(Constant1 Constant3), Ab.local_constants.sort + end def test_as_load_path assert_equal 'yz/zy', Yz::Zy.as_load_path diff --git a/vendor/rails/activesupport/test/dependencies_test.rb b/vendor/rails/activesupport/test/dependencies_test.rb index 755cff2e..ad3472bd 100644 --- a/vendor/rails/activesupport/test/dependencies_test.rb +++ b/vendor/rails/activesupport/test/dependencies_test.rb @@ -9,6 +9,10 @@ module ModuleWithMissing end end +module ModuleWithConstant + InheritedConstant = "Hello" +end + class DependenciesTest < Test::Unit::TestCase def teardown Dependencies.clear @@ -574,6 +578,13 @@ class DependenciesTest < Test::Unit::TestCase Object.send :remove_const, :M rescue nil end + def test_new_constants_in_with_inherited_constants + m = Dependencies.new_constants_in(:Object) do + Object.send :include, ModuleWithConstant + end + assert_equal [], m + end + def test_file_with_multiple_constants_and_require_dependency with_loading 'autoloading_fixtures' do assert ! defined?(MultipleConstantFile) diff --git a/vendor/rails/activesupport/test/json_test.rb b/vendor/rails/activesupport/test/json_test.rb new file mode 100644 index 00000000..8d9833ec --- /dev/null +++ b/vendor/rails/activesupport/test/json_test.rb @@ -0,0 +1,97 @@ +require File.dirname(__FILE__) + '/abstract_unit' + +class JsonFoo + def initialize(a, b) + @a, @b = a, b + end +end + +class TestJSONEmitters < Test::Unit::TestCase + TrueTests = [[ true, %(true) ]] + FalseTests = [[ false, %(false) ]] + NilTests = [[ nil, %(null) ]] + NumericTests = [[ 1, %(1) ], + [ 2.5, %(2.5) ]] + + StringTests = [[ 'this is the string', %("this is the string") ], + [ 'a "string" with quotes