From 9b19a6f16cebf4257d2f0b839f6cc8ff5db5c47b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 28 Jun 2010 00:57:47 +0200 Subject: [PATCH 01/71] A few changes were done in this commit: * Added :autoload to engines path API and redefine usage to be in sync with 6f83a5036d8a9c3f8ed7; * Do not autoload code in *lib* for applications (now you need to explicitly require them). This makes an application behave closer to an engine (code in lib is still autoloaded for plugins); * Always autoload code in app/ for engines and plugins. This makes engines behave closer to an application and should allow us to get rid of the unloadable hack required when controllers inside engines inherit from ApplicationController; --- railties/lib/rails/application.rb | 7 +-- .../lib/rails/application/configuration.rb | 4 +- railties/lib/rails/engine.rb | 21 ++++--- railties/lib/rails/engine/configuration.rb | 4 +- railties/lib/rails/paths.rb | 51 ++++++++++------- railties/lib/rails/plugin.rb | 16 ++++-- railties/test/paths_test.rb | 56 +++++++++---------- railties/test/railties/engine_test.rb | 4 -- railties/test/railties/plugin_test.rb | 30 ++++++++-- railties/test/railties/shared_tests.rb | 45 +++------------ 10 files changed, 119 insertions(+), 119 deletions(-) diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index aabe86715c..4a7ed2d028 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -28,7 +28,7 @@ module Rails # Besides providing the same configuration as Rails::Engine and Rails::Railtie, # the application object has several specific configurations, for example # "allow_concurrency", "cache_classes", "consider_all_requests_local", "filter_parameters", - # "logger", "reload_engines", "reload_plugins" and so forth. + # "logger", "reload_plugins" and so forth. # # Check Rails::Application::Configuration to see them all. # @@ -217,10 +217,5 @@ module Rails def initialize_generators require "rails/generators" end - - # Application is always reloadable when config.cache_classes is false. - def reloadable?(app) - true - end end end diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index e3165b2d4c..465851c0e6 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -10,7 +10,7 @@ module Rails attr_accessor :allow_concurrency, :cache_classes, :cache_store, :encoding, :consider_all_requests_local, :dependency_loading, :filter_parameters, :log_level, :logger, :middleware, - :plugins, :preload_frameworks, :reload_engines, :reload_plugins, + :plugins, :preload_frameworks, :reload_plugins, :secret_token, :serve_static_assets, :session_options, :time_zone, :whiny_nils @@ -59,7 +59,7 @@ module Rails if File.exists?("#{root}/test/mocks/#{Rails.env}") ActiveSupport::Deprecation.warn "\"Rails.root/test/mocks/#{Rails.env}\" won't be added " << "automatically to load paths anymore in future releases" - paths.mocks_path "test/mocks", :load_path => true, :glob => Rails.env + paths.mocks_path "test/mocks", :autoload => true, :glob => Rails.env end paths diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 0a3f21fb1b..ee3e3ba040 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -142,7 +142,7 @@ module Rails # Add configured load paths to ruby load paths and remove duplicates. initializer :set_load_path, :before => :bootstrap_hook do - config.autoload_paths.reverse_each do |path| + _all_load_paths.reverse_each do |path| $LOAD_PATH.unshift(path) if File.directory?(path) end $LOAD_PATH.uniq! @@ -154,16 +154,12 @@ module Rails # This needs to be an initializer, since it needs to run once # per engine and get the engine as a block parameter initializer :set_autoload_paths, :before => :bootstrap_hook do |app| - ActiveSupport::Dependencies.autoload_paths.unshift(*config.autoload_paths) - - if reloadable?(app) - ActiveSupport::Dependencies.autoload_once_paths.unshift(*config.autoload_once_paths) - else - ActiveSupport::Dependencies.autoload_once_paths.unshift(*config.autoload_paths) - end + ActiveSupport::Dependencies.autoload_paths.unshift(*_all_autoload_paths) + ActiveSupport::Dependencies.autoload_once_paths.unshift(*config.autoload_once_paths) # Freeze so future modifications will fail rather than do nothing mysteriously config.autoload_paths.freeze + config.eager_load_paths.freeze config.autoload_once_paths.freeze end @@ -195,7 +191,6 @@ module Rails ActiveSupport.on_load(:action_controller) do prepend_view_path(views) end - ActiveSupport.on_load(:action_mailer) do prepend_view_path(views) end @@ -214,8 +209,12 @@ module Rails protected - def reloadable?(app) - app.config.reload_engines + def _all_autoload_paths + @_all_autoload_paths ||= (config.autoload_paths + config.eager_load_paths + config.autoload_once_paths).uniq + end + + def _all_load_paths + @_all_load_paths ||= (config.paths.load_paths + _all_autoload_paths).uniq end end end diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index 4e27180f1e..2f465670cf 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -42,11 +42,11 @@ module Rails end def autoload_once_paths - @autoload_once_paths ||= paths.load_once + @autoload_once_paths ||= paths.autoload_once end def autoload_paths - @autoload_paths ||= paths.load_paths + @autoload_paths ||= paths.autoload_paths end end end diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb index 1c9e308631..7a65188a9a 100644 --- a/railties/lib/rails/paths.rb +++ b/railties/lib/rails/paths.rb @@ -25,9 +25,7 @@ module Rails def initialize(path) raise if path.is_a?(Array) - @children = {} - @path = path @root = self @all_paths = [] @@ -38,14 +36,18 @@ module Rails @all_paths end - def load_once - filter_by(:load_once?) + def autoload_once + filter_by(:autoload_once?) end def eager_load filter_by(:eager_load?) end + def autoload_paths + filter_by(:autoload?) + end + def load_paths filter_by(:load_path?) end @@ -61,15 +63,17 @@ module Rails protected def filter_by(constraint) - all_paths.map do |path| + all = [] + all_paths.each do |path| if path.send(constraint) paths = path.paths paths -= path.children.values.map { |p| p.send(constraint) ? [] : p.paths }.flatten - paths - else - [] + all.concat(paths) end - end.flatten.uniq.select { |p| File.exists?(p) } + end + all.uniq! + all.reject! { |p| !File.exists?(p) } + all end end @@ -80,15 +84,16 @@ module Rails attr_accessor :glob def initialize(root, *paths) - @options = paths.last.is_a?(::Hash) ? paths.pop : {} + options = paths.last.is_a?(::Hash) ? paths.pop : {} @children = {} @root = root @paths = paths.flatten - @glob = @options.delete(:glob) + @glob = options[:glob] - @load_once = @options[:load_once] - @eager_load = @options[:eager_load] - @load_path = @options[:load_path] || @eager_load || @load_once + autoload_once! if options[:autoload_once] + eager_load! if options[:eager_load] + autoload! if options[:autoload] + load_path! if options[:load_path] @root.all_paths << self end @@ -111,24 +116,30 @@ module Rails @paths.concat paths end - def load_once! - @load_once = true - @load_path = true + def autoload_once! + @autoload_once = true end - def load_once? - @load_once + def autoload_once? + @autoload_once end def eager_load! @eager_load = true - @load_path = true end def eager_load? @eager_load end + def autoload! + @autoload = true + end + + def autoload? + @autoload + end + def load_path! @load_path = true end diff --git a/railties/lib/rails/plugin.rb b/railties/lib/rails/plugin.rb index fcdd099135..be229cc9a2 100644 --- a/railties/lib/rails/plugin.rb +++ b/railties/lib/rails/plugin.rb @@ -61,6 +61,16 @@ module Rails @config ||= Engine::Configuration.new end + initializer :handle_lib_autoload, :before => :set_load_path do |app| + paths = if app.config.reload_plugins + config.autoload_paths + else + config.autoload_once_paths + end + + paths.concat config.paths.lib.to_a + end + initializer :load_init_rb, :before => :load_config_initializers do |app| files = %w(rails/init.rb init.rb).map { |path| File.expand_path path, root } if initrb = files.find { |path| File.file? path } @@ -77,11 +87,5 @@ module Rails raise "\"#{name}\" is a Railtie/Engine and cannot be installed as plugin" end end - - protected - - def reloadable?(app) - app.config.reload_plugins - end end end diff --git a/railties/test/paths_test.rb b/railties/test/paths_test.rb index 92c7b2ba0e..008247cb1a 100644 --- a/railties/test/paths_test.rb +++ b/railties/test/paths_test.rb @@ -120,36 +120,36 @@ class PathsTest < ActiveSupport::TestCase test "it is possible to add a path that should be loaded only once" do @root.app = "/app" - @root.app.load_once! - assert @root.app.load_once? - assert @root.load_once.include?(@root.app.paths.first) + @root.app.autoload_once! + assert @root.app.autoload_once? + assert @root.autoload_once.include?(@root.app.paths.first) end test "it is possible to add a path without assignment and specify it should be loaded only once" do - @root.app "/app", :load_once => true - assert @root.app.load_once? - assert @root.load_once.include?("/app") + @root.app "/app", :autoload_once => true + assert @root.app.autoload_once? + assert @root.autoload_once.include?("/app") end test "it is possible to add multiple paths without assignment and specify it should be loaded only once" do - @root.app "/app", "/app2", :load_once => true - assert @root.app.load_once? - assert @root.load_once.include?("/app") - assert @root.load_once.include?("/app2") + @root.app "/app", "/app2", :autoload_once => true + assert @root.app.autoload_once? + assert @root.autoload_once.include?("/app") + assert @root.autoload_once.include?("/app2") end - test "making a path load_once more than once only includes it once in @root.load_once" do + test "making a path autoload_once more than once only includes it once in @root.load_once" do @root.app = "/app" - @root.app.load_once! - @root.app.load_once! - assert_equal 1, @root.load_once.select {|p| p == @root.app.paths.first }.size + @root.app.autoload_once! + @root.app.autoload_once! + assert_equal 1, @root.autoload_once.select {|p| p == @root.app.paths.first }.size end - test "paths added to a load_once path should be added to the load_once collection" do + test "paths added to a load_once path should be added to the autoload_once collection" do @root.app = "/app" - @root.app.load_once! + @root.app.autoload_once! @root.app << "/app2" - assert_equal 2, @root.load_once.size + assert_equal 2, @root.autoload_once.size end test "it is possible to mark a path as eager" do @@ -173,11 +173,11 @@ class PathsTest < ActiveSupport::TestCase end test "it is possible to create a path without assignment and mark it both as eager and load once" do - @root.app "/app", :eager_load => true, :load_once => true + @root.app "/app", :eager_load => true, :autoload_once => true assert @root.app.eager_load? - assert @root.app.load_once? + assert @root.app.autoload_once? assert @root.eager_load.include?("/app") - assert @root.load_once.include?("/app") + assert @root.autoload_once.include?("/app") end test "making a path eager more than once only includes it once in @root.eager_paths" do @@ -218,16 +218,16 @@ class PathsTest < ActiveSupport::TestCase assert_equal ["/app"], @root.load_paths end - test "adding a path to the eager paths also adds it to the load path" do + test "a path can be marked as autoload path" do @root.app = "app" - @root.app.eager_load! - assert_equal ["/foo/bar/app"], @root.load_paths + @root.app.autoload! + @root.app.models = "app/models" + assert_equal ["/foo/bar/app"], @root.autoload_paths end - test "adding a path to the load once paths also adds it to the load path" do - @root.app = "app" - @root.app.load_once! - assert_equal ["/foo/bar/app"], @root.load_paths + test "a path can be marked as autoload on creation" do + @root.app "/app", :autoload => true + assert @root.app.autoload? + assert_equal ["/app"], @root.autoload_paths end - end diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 3fe01e543c..7410a10712 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -20,10 +20,6 @@ module RailtiesTest end end - def reload_config - :reload_engines - end - test "Rails::Engine itself does not respond to config" do boot_rails assert !Rails::Engine.respond_to?(:config) diff --git a/railties/test/railties/plugin_test.rb b/railties/test/railties/plugin_test.rb index 0f5f29468c..b143f56484 100644 --- a/railties/test/railties/plugin_test.rb +++ b/railties/test/railties/plugin_test.rb @@ -15,10 +15,6 @@ module RailtiesTest end end - def reload_config - :reload_plugins - end - test "Rails::Plugin itself does not respond to config" do boot_rails assert !Rails::Plugin.respond_to?(:config) @@ -37,6 +33,32 @@ module RailtiesTest assert_equal "Bukkits", Bukkits.name end + test "plugin gets added to dependency list" do + boot_rails + assert_equal "Another", Another.name + end + + test "plugin constants get reloaded if config.reload_plugins is set to true" do + add_to_config <<-RUBY + config.reload_plugins = true + RUBY + + boot_rails + + assert_equal "Another", Another.name + ActiveSupport::Dependencies.clear + @plugin.delete("lib/another.rb") + assert_raises(NameError) { Another } + end + + test "plugin constants are not reloaded by default" do + boot_rails + assert_equal "Another", Another.name + ActiveSupport::Dependencies.clear + @plugin.delete("lib/another.rb") + assert_nothing_raised { Another } + end + test "it loads the plugin's init.rb file" do boot_rails assert_equal "loaded", BUKKITS diff --git a/railties/test/railties/shared_tests.rb b/railties/test/railties/shared_tests.rb index 3f78d7d3fe..ce7c55c11c 100644 --- a/railties/test/railties/shared_tests.rb +++ b/railties/test/railties/shared_tests.rb @@ -10,51 +10,25 @@ module RailtiesTest @app ||= Rails.application end - def test_plugin_puts_its_lib_directory_on_load_path + def test_puts_its_lib_directory_on_load_path boot_rails require "another" assert_equal "Another", Another.name end - def test_plugin_paths_get_added_to_as_dependency_list - boot_rails - assert_equal "Another", Another.name - end - - def test_plugins_constants_are_not_reloaded_by_default - boot_rails - assert_equal "Another", Another.name - ActiveSupport::Dependencies.clear - @plugin.delete("lib/another.rb") - assert_nothing_raised { Another } - end - - def test_plugin_constants_get_reloaded_if_config_reload_plugins - add_to_config <<-RUBY - config.#{reload_config} = true - RUBY - - boot_rails - - assert_equal "Another", Another.name - ActiveSupport::Dependencies.clear - @plugin.delete("lib/another.rb") - assert_raises(NameError) { Another } - end - - def test_plugin_puts_its_models_directory_on_load_path + def test_puts_its_models_directory_on_autoload_path @plugin.write "app/models/my_bukkit.rb", "class MyBukkit ; end" boot_rails assert_nothing_raised { MyBukkit } end - def test_plugin_puts_its_controllers_directory_on_the_load_path + def test_puts_its_controllers_directory_on_autoload_path @plugin.write "app/controllers/bukkit_controller.rb", "class BukkitController ; end" boot_rails assert_nothing_raised { BukkitController } end - def test_plugin_adds_its_views_to_view_paths + def test_adds_its_views_to_view_paths @plugin.write "app/controllers/bukkit_controller.rb", <<-RUBY class BukkitController < ActionController::Base def index @@ -72,7 +46,7 @@ module RailtiesTest assert_equal "Hello bukkits\n", response[2].body end - def test_plugin_adds_its_views_to_view_paths_with_lower_proriority + def test_adds_its_views_to_view_paths_with_lower_proriority_than_app_ones @plugin.write "app/controllers/bukkit_controller.rb", <<-RUBY class BukkitController < ActionController::Base def index @@ -91,7 +65,7 @@ module RailtiesTest assert_equal "Hi bukkits\n", response[2].body end - def test_plugin_adds_helpers_to_controller_views + def test_adds_helpers_to_controller_views @plugin.write "app/controllers/bukkit_controller.rb", <<-RUBY class BukkitController < ActionController::Base def index @@ -116,11 +90,10 @@ module RailtiesTest assert_equal "Hello bukkits\n", response[2].body end - def test_plugin_eager_load_any_path_under_app + def test_autoload_any_path_under_app @plugin.write "app/anything/foo.rb", <<-RUBY module Foo; end RUBY - boot_rails assert Foo end @@ -269,7 +242,7 @@ YAML assert_equal "Rendered from namespace", last_response.body end - def test_plugin_initializers + def test_initializers $plugin_initializer = false @plugin.write "config/initializers/foo.rb", <<-RUBY $plugin_initializer = true @@ -279,7 +252,7 @@ YAML assert $plugin_initializer end - def test_plugin_midleware_referenced_in_configuration + def test_midleware_referenced_in_configuration @plugin.write "lib/bukkits.rb", <<-RUBY class Bukkits def initialize(app) From cfb38319bcc96b39d75133925c9f5095178067d0 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 27 Jun 2010 18:22:14 -0300 Subject: [PATCH 02/71] Makes more sense to ask about method_defined? MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activesupport/lib/active_support/core_ext/string/conversions.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/core_ext/string/conversions.rb b/activesupport/lib/active_support/core_ext/string/conversions.rb index af277f9995..857ecfaa54 100644 --- a/activesupport/lib/active_support/core_ext/string/conversions.rb +++ b/activesupport/lib/active_support/core_ext/string/conversions.rb @@ -30,7 +30,7 @@ class String def getbyte(index) self[index] - end if RUBY_VERSION < '1.9' + end unless method_defined?(:getbyte) # Form can be either :utc (default) or :local. def to_time(form = :utc) From 824da60ae86ac26b5cbc7d6354d233205d2addc6 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 27 Jun 2010 18:53:06 -0300 Subject: [PATCH 03/71] Move Rails module to abstract_unit to make test in isolation work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/test/abstract_unit.rb | 3 +++ actionpack/test/controller/base_test.rb | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 2640e96453..3241b3d118 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -38,6 +38,9 @@ end require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late +module Rails +end + ActiveSupport::Dependencies.hook! # Show backtraces for deprecated behavior for quicker cleanup. diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb index 4f58b5d968..ae270b751e 100644 --- a/actionpack/test/controller/base_test.rb +++ b/actionpack/test/controller/base_test.rb @@ -2,9 +2,6 @@ require 'abstract_unit' require 'logger' require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late -module Rails -end - # Provide some controller to run the tests on. module Submodule class ContainedEmptyController < ActionController::Base From 3ab296fd594d9d9e8b96d12f81ac3582dd81fd1f Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 27 Jun 2010 19:46:57 -0300 Subject: [PATCH 04/71] AV::logger returns AC::logger if it's defined, workaround meanwhile AV doesn't have it's own logger MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_view/log_subscriber.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_view/log_subscriber.rb b/actionpack/lib/action_view/log_subscriber.rb index 4a52937c58..443a0eafd1 100644 --- a/actionpack/lib/action_view/log_subscriber.rb +++ b/actionpack/lib/action_view/log_subscriber.rb @@ -12,8 +12,9 @@ module ActionView alias :render_partial :render_template alias :render_collection :render_template + # TODO: Ideally, ActionView should have its own logger so it does not depend on AC.logger def logger - ActionController::Base.logger + ActionController::Base.logger if defined?(ActionController::Base) end protected @@ -24,4 +25,4 @@ module ActionView end end -ActionView::LogSubscriber.attach_to :action_view \ No newline at end of file +ActionView::LogSubscriber.attach_to :action_view From 6c28959e86222a6932f9cc62bf21aad7a2f9c067 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 27 Jun 2010 20:02:48 -0300 Subject: [PATCH 05/71] Move sqlite to sqlite3 for this tests to be run only on sqlite3 adapter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- .../test/cases/adapters/{sqlite => sqlite3}/copy_table_test.rb | 0 .../cases/adapters/{sqlite => sqlite3}/sqlite3_adapter_test.rb | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename activerecord/test/cases/adapters/{sqlite => sqlite3}/copy_table_test.rb (100%) rename activerecord/test/cases/adapters/{sqlite => sqlite3}/sqlite3_adapter_test.rb (100%) diff --git a/activerecord/test/cases/adapters/sqlite/copy_table_test.rb b/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb similarity index 100% rename from activerecord/test/cases/adapters/sqlite/copy_table_test.rb rename to activerecord/test/cases/adapters/sqlite3/copy_table_test.rb diff --git a/activerecord/test/cases/adapters/sqlite/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb similarity index 100% rename from activerecord/test/cases/adapters/sqlite/sqlite3_adapter_test.rb rename to activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb From d15256af6cb160d0cdd76695db22872f09d6e835 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 27 Jun 2010 13:11:09 -0700 Subject: [PATCH 06/71] Missing BigDecimal dependency --- .../test/cases/validations/numericality_validation_test.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/activemodel/test/cases/validations/numericality_validation_test.rb b/activemodel/test/cases/validations/numericality_validation_test.rb index 8e77a0222e..e1d7d40c47 100644 --- a/activemodel/test/cases/validations/numericality_validation_test.rb +++ b/activemodel/test/cases/validations/numericality_validation_test.rb @@ -4,6 +4,8 @@ require 'cases/helper' require 'models/topic' require 'models/person' +require 'bigdecimal' + class NumericalityValidationTest < ActiveModel::TestCase def teardown From 654929190170c174c8b844d0adcd968c3049d515 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 27 Jun 2010 13:11:49 -0700 Subject: [PATCH 07/71] Vendor unreleased rack-mount 0.6.6.pre dependency --- Gemfile | 2 +- actionpack/actionpack.gemspec | 2 +- .../lib/action_dispatch/routing/route_set.rb | 4 +- .../vendor/rack-mount-0.6.6.pre/rack/mount.rb | 32 + .../rack/mount/analysis/frequency.rb | 60 ++ .../rack/mount/analysis/histogram.rb | 74 +++ .../rack/mount/analysis/splitting.rb | 159 +++++ .../rack/mount/code_generation.rb | 113 ++++ .../rack/mount/generatable_regexp.rb | 210 +++++++ .../rack/mount/multimap.rb | 53 ++ .../rack-mount-0.6.6.pre/rack/mount/prefix.rb | 36 ++ .../rack/mount/regexp_with_named_groups.rb | 69 +++ .../rack-mount-0.6.6.pre/rack/mount/route.rb | 130 ++++ .../rack/mount/route_set.rb | 409 +++++++++++++ .../rack-mount-0.6.6.pre/rack/mount/strexp.rb | 68 +++ .../rack/mount/strexp/parser.rb | 160 +++++ .../rack/mount/strexp/parser.y | 34 ++ .../rack/mount/strexp/tokenizer.rb | 83 +++ .../rack/mount/strexp/tokenizer.rex | 12 + .../rack-mount-0.6.6.pre/rack/mount/utils.rb | 148 +++++ .../rack/mount/vendor/multimap/multimap.rb | 569 ++++++++++++++++++ .../rack/mount/vendor/multimap/multiset.rb | 185 ++++++ .../mount/vendor/multimap/nested_multimap.rb | 158 +++++ .../rack/mount/vendor/regin/regin.rb | 45 ++ .../mount/vendor/regin/regin/alternation.rb | 40 ++ .../rack/mount/vendor/regin/regin/anchor.rb | 4 + .../rack/mount/vendor/regin/regin/atom.rb | 59 ++ .../mount/vendor/regin/regin/character.rb | 56 ++ .../vendor/regin/regin/character_class.rb | 55 ++ .../mount/vendor/regin/regin/collection.rb | 83 +++ .../mount/vendor/regin/regin/expression.rb | 126 ++++ .../rack/mount/vendor/regin/regin/group.rb | 90 +++ .../rack/mount/vendor/regin/regin/options.rb | 55 ++ .../rack/mount/vendor/regin/regin/parser.rb | 415 +++++++++++++ .../mount/vendor/regin/regin/tokenizer.rb | 213 +++++++ .../rack/mount/vendor/regin/regin/version.rb | 3 + .../rack/mount/version.rb | 5 + 37 files changed, 4016 insertions(+), 3 deletions(-) create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/analysis/frequency.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/analysis/histogram.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/analysis/splitting.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/code_generation.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/generatable_regexp.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/multimap.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/prefix.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/regexp_with_named_groups.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/route.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/route_set.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/strexp.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/strexp/parser.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/strexp/parser.y create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/strexp/tokenizer.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/strexp/tokenizer.rex create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/utils.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/multimap/multimap.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/multimap/multiset.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/multimap/nested_multimap.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/alternation.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/anchor.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/atom.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/character.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/character_class.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/collection.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/expression.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/group.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/options.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/parser.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/tokenizer.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/version.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/version.rb diff --git a/Gemfile b/Gemfile index d0b11b04e4..827c67e522 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,7 @@ source 'http://rubygems.org' gem "arel", :git => "git://github.com/rails/arel.git" -gem "rack-mount", :git => "git://github.com/rails/rack-mount.git" +#gem "rack-mount", :git => "git://github.com/rails/rack-mount.git" gem "rails", :path => File.dirname(__FILE__) gem "rake", ">= 0.8.7" diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index 1dede257f9..54e8ad9acb 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -25,7 +25,7 @@ Gem::Specification.new do |s| s.add_dependency('i18n', '~> 0.4.1') s.add_dependency('rack', '~> 1.1.0') s.add_dependency('rack-test', '~> 0.5.4') - s.add_dependency('rack-mount', '~> 0.6.5') + #s.add_dependency('rack-mount', '~> 0.6.6') s.add_dependency('tzinfo', '~> 0.3.16') s.add_dependency('erubis', '~> 2.6.5') end diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 7be79d3200..05200f0338 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -1,8 +1,10 @@ -require 'rack/mount' require 'forwardable' require 'active_support/core_ext/object/to_query' require 'action_dispatch/routing/deprecated_mapper' +$: << File.expand_path('../../vendor/rack-mount-0.6.6.pre', __FILE__) +require 'rack/mount' + module ActionDispatch module Routing class RouteSet #:nodoc: diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount.rb new file mode 100644 index 0000000000..9fbf707724 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount.rb @@ -0,0 +1,32 @@ +require 'rack' + +module Rack #:nodoc: + # A stackable dynamic tree based Rack router. + # + # Rack::Mount supports Rack's Cascade style of trying several routes until + # it finds one that is not a 404. This allows multiple routes to be nested + # or stacked on top of each other. Since the application endpoint can + # trigger the router to continue matching, middleware can be used to add + # arbitrary conditions to any route. This allows you to route based on + # other request attributes, session information, or even data dynamically + # pulled from a database. + module Mount + autoload :CodeGeneration, 'rack/mount/code_generation' + autoload :GeneratableRegexp, 'rack/mount/generatable_regexp' + autoload :Multimap, 'rack/mount/multimap' + autoload :Prefix, 'rack/mount/prefix' + autoload :RegexpWithNamedGroups, 'rack/mount/regexp_with_named_groups' + autoload :Route, 'rack/mount/route' + autoload :RouteSet, 'rack/mount/route_set' + autoload :RoutingError, 'rack/mount/route_set' + autoload :Strexp, 'rack/mount/strexp' + autoload :Utils, 'rack/mount/utils' + autoload :Version, 'rack/mount/version' + + module Analysis #:nodoc: + autoload :Frequency, 'rack/mount/analysis/frequency' + autoload :Histogram, 'rack/mount/analysis/histogram' + autoload :Splitting, 'rack/mount/analysis/splitting' + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/analysis/frequency.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/analysis/frequency.rb new file mode 100644 index 0000000000..671258f807 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/analysis/frequency.rb @@ -0,0 +1,60 @@ +require 'rack/mount/utils' + +module Rack::Mount + module Analysis + class Frequency #:nodoc: + def initialize(*keys) + clear + keys.each { |key| self << key } + end + + def clear + @raw_keys = [] + @key_frequency = Analysis::Histogram.new + self + end + + def <<(key) + raise ArgumentError unless key.is_a?(Hash) + @raw_keys << key + nil + end + + def possible_keys + @possible_keys ||= begin + @raw_keys.map do |key| + key.inject({}) { |requirements, (method, requirement)| + process_key(requirements, method, requirement) + requirements + } + end + end + end + + def process_key(requirements, method, requirement) + if requirement.is_a?(Regexp) + expression = Utils.parse_regexp(requirement) + + if expression.is_a?(Regin::Expression) && expression.anchored_to_line? + expression = Regin::Expression.new(expression.reject { |e| e.is_a?(Regin::Anchor) }) + return requirements[method] = expression.to_s if expression.literal? + end + end + + requirements[method] = requirement + end + + def report + @report ||= begin + possible_keys.each { |keys| keys.each_pair { |key, _| @key_frequency << key } } + return [] if @key_frequency.count <= 1 + @key_frequency.keys_in_upper_quartile + end + end + + def expire! + @possible_keys = @report = nil + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/analysis/histogram.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/analysis/histogram.rb new file mode 100644 index 0000000000..20aaa132f9 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/analysis/histogram.rb @@ -0,0 +1,74 @@ +module Rack::Mount + module Analysis + class Histogram < Hash #:nodoc: + attr_reader :count + + def initialize + @count = 0 + super(0) + expire_caches! + end + + def <<(value) + @count += 1 + self[value] += 1 if value + expire_caches! + self + end + + def sorted_by_frequency + sort_by { |_, value| value }.reverse! + end + + def max + @max ||= values.max || 0 + end + + def min + @min ||= values.min || 0 + end + + def mean + @mean ||= calculate_mean + end + + def standard_deviation + @standard_deviation ||= calculate_standard_deviation + end + + def upper_quartile_limit + @upper_quartile_limit ||= calculate_upper_quartile_limit + end + + def keys_in_upper_quartile + @keys_in_upper_quartile ||= compute_keys_in_upper_quartile + end + + private + def calculate_mean + count / size + end + + def calculate_variance + values.inject(0) { |sum, e| sum + (e - mean) ** 2 } / count.to_f + end + + def calculate_standard_deviation + Math.sqrt(calculate_variance) + end + + def calculate_upper_quartile_limit + mean + standard_deviation + end + + def compute_keys_in_upper_quartile + sorted_by_frequency.select { |_, value| value >= upper_quartile_limit }.map! { |key, _| key } + end + + def expire_caches! + @max = @min = @mean = @standard_deviation = nil + @keys_in_upper_quartile = nil + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/analysis/splitting.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/analysis/splitting.rb new file mode 100644 index 0000000000..8a8c551302 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/analysis/splitting.rb @@ -0,0 +1,159 @@ +require 'rack/mount/utils' + +module Rack::Mount + module Analysis + class Splitting < Frequency + NULL = "\0".freeze + + class Key < Struct.new(:method, :index, :separators) + def self.split(value, separator_pattern) + keys = value.split(separator_pattern) + keys.shift if keys[0] == '' + keys << NULL + keys + end + + def call(cache, obj) + (cache[method] ||= self.class.split(obj.send(method), separators))[index] + end + + def call_source(cache, obj) + "(#{cache}[:#{method}] ||= Analysis::Splitting::Key.split(#{obj}.#{method}, #{separators.inspect}))[#{index}]" + end + + def inspect + "#{method}[#{index}]" + end + end + + def clear + @boundaries = {} + super + end + + def <<(key) + super + key.each_pair do |k, v| + analyze_capture_boundaries(v, @boundaries[k] ||= Histogram.new) + end + end + + def separators(key) + (@boundaries[key].keys_in_upper_quartile + ['/']).uniq + end + + def process_key(requirements, method, requirement) + separators = separators(method) + if requirement.is_a?(Regexp) && separators.any? + generate_split_keys(requirement, separators).each_with_index do |value, index| + requirements[Key.new(method, index, Regexp.union(*separators))] = value + end + else + super + end + end + + private + def analyze_capture_boundaries(regexp, boundaries) #:nodoc: + return boundaries unless regexp.is_a?(Regexp) + + parts = Utils.parse_regexp(regexp) + parts.each_with_index do |part, index| + if part.is_a?(Regin::Group) + if index > 0 + previous = parts[index-1] + if previous.is_a?(Regin::Character) && previous.literal? + boundaries << previous.to_s + end + end + + if inside = part.expression[0] + if inside.is_a?(Regin::Character) && inside.literal? + boundaries << inside.to_s + end + end + + if index < parts.length + following = parts[index+1] + if following.is_a?(Regin::Character) && following.literal? + boundaries << following.to_s + end + end + end + end + + boundaries + end + + def generate_split_keys(regexp, separators) #:nodoc: + segments = [] + buf = nil + parts = Utils.parse_regexp(regexp) + parts.each_with_index do |part, index| + case part + when Regin::Anchor + if part.value == '$' || part.value == '\Z' + segments << join_buffer(buf, regexp) if buf + segments << NULL + buf = nil + break + end + when Regin::CharacterClass + break if separators.any? { |s| part.include?(s) } + buf = nil + segments << part.to_regexp(true) + when Regin::Character + if separators.any? { |s| part.include?(s) } + segments << join_buffer(buf, regexp) if buf + peek = parts[index+1] + if peek.is_a?(Regin::Character) && separators.include?(peek.value) + segments << '' + end + buf = nil + else + buf ||= Regin::Expression.new([]) + buf += [part] + end + when Regin::Group + if part.quantifier == '?' + value = part.expression.first + if separators.any? { |s| value.include?(s) } + segments << join_buffer(buf, regexp) if buf + buf = nil + end + break + elsif part.quantifier == nil + break if separators.any? { |s| part.include?(s) } + buf = nil + segments << part.to_regexp(true) + else + break + end + else + break + end + + if index + 1 == parts.size + segments << join_buffer(buf, regexp) if buf + buf = nil + break + end + end + + while segments.length > 0 && (segments.last.nil? || segments.last == '') + segments.pop + end + + segments + end + + def join_buffer(parts, regexp) + if parts.literal? + parts.to_s + else + parts.to_regexp(true) + end + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/code_generation.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/code_generation.rb new file mode 100644 index 0000000000..903c79fdc6 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/code_generation.rb @@ -0,0 +1,113 @@ +module Rack::Mount + module CodeGeneration #:nodoc: + def _expired_recognize(env) #:nodoc: + raise 'route set not finalized' + end + + def rehash + super + optimize_recognize! + end + + private + def expire! + if @optimized_recognize_defined + remove_metaclass_method :recognize + + class << self + alias_method :recognize, :_expired_recognize + end + + @optimized_recognize_defined = false + end + + super + end + + def optimize_container_iterator(container) + body = [] + + container.each_with_index { |route, i| + body << "route = self[#{i}]" + body << 'matches = {}' + body << 'params = route.defaults.dup' + + conditions = [] + route.conditions.each do |method, condition| + b = [] + if condition.is_a?(Regexp) + b << "if m = obj.#{method}.match(#{condition.inspect})" + b << "matches[:#{method}] = m" + if (named_captures = route.named_captures[method]) && named_captures.any? + b << 'captures = m.captures' + b << 'p = nil' + b << named_captures.map { |k, j| "params[#{k.inspect}] = p if p = captures[#{j}]" }.join('; ') + end + else + b << "if m = obj.#{method} == route.conditions[:#{method}]" + end + b << 'true' + b << 'end' + conditions << "(#{b.join('; ')})" + end + + body << <<-RUBY + if #{conditions.join(' && ')} + yield route, matches, params + end + RUBY + } + + container.instance_eval(<<-RUBY, __FILE__, __LINE__) + def optimized_each(obj) + #{body.join("\n")} + nil + end + RUBY + end + + def optimize_recognize! + keys = @recognition_keys.map { |key| + if key.respond_to?(:call_source) + key.call_source(:cache, :obj) + else + "obj.#{key}" + end + }.join(', ') + + @optimized_recognize_defined = true + + remove_metaclass_method :recognize + + instance_eval(<<-RUBY, __FILE__, __LINE__) + def recognize(obj) + cache = {} + container = @recognition_graph[#{keys}] + optimize_container_iterator(container) unless container.respond_to?(:optimized_each) + + if block_given? + container.optimized_each(obj) do |route, matches, params| + yield route, matches, params + end + else + container.optimized_each(obj) do |route, matches, params| + return route, matches, params + end + end + + nil + end + RUBY + end + + # method_defined? can't distinguish between instance + # and meta methods. So we have to rescue if the method + # has not been defined in the metaclass yet. + def remove_metaclass_method(symbol) + metaclass = class << self; self; end + metaclass.send(:remove_method, symbol) + rescue NameError => e + nil + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/generatable_regexp.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/generatable_regexp.rb new file mode 100644 index 0000000000..47bbab3784 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/generatable_regexp.rb @@ -0,0 +1,210 @@ +require 'rack/mount/utils' + +module Rack::Mount + class GeneratableRegexp < Regexp #:nodoc: + class DynamicSegment #:nodoc: + attr_reader :name, :requirement + + def initialize(name, requirement) + @name, @requirement = name.to_sym, requirement + freeze + end + + def ==(obj) + @name == obj.name && @requirement == obj.requirement + end + + def =~(str) + @requirement =~ str + end + + def to_hash + { @name => @requirement } + end + + def inspect + "/(?<#{@name}>#{@requirement.source})/" + end + end + + module InstanceMethods + def self.extended(obj) + obj.segments + end + + def defaults=(defaults) + @required_captures = nil + @required_params = nil + @required_defaults = nil + @defaults = defaults + end + + def defaults + @defaults ||= {} + end + + def generatable? + segments.any? + end + + def generate(params = {}, recall = {}, options = {}) + return nil unless generatable? + + merged = recall.merge(params) + return nil unless required_params.all? { |p| merged.include?(p) } + return nil unless required_defaults.all? { |k, v| merged[k] == v } + + generate_from_segments(segments, params, merged, options) + end + + def segments + @segments ||= begin + defaults + segments = [] + catch(:halt) do + expression = Utils.parse_regexp(self) + segments = parse_segments(expression) + end + segments + end + end + + def captures + segments.flatten.find_all { |s| s.is_a?(DynamicSegment) } + end + + def required_captures + @required_captures ||= segments.find_all { |s| + s.is_a?(DynamicSegment) && !@defaults.include?(s.name) + }.freeze + end + + def required_params + @required_params ||= required_captures.map { |s| s.name }.freeze + end + + def required_defaults + @required_defaults ||= begin + required_defaults = @defaults.dup + captures.inject({}) { |h, s| h.merge!(s.to_hash) }.keys.each { |name| + required_defaults.delete(name) + } + required_defaults + end + end + + def freeze + segments + captures + required_captures + required_params + required_defaults + super + end + + private + def parse_segments(segments) + s = [] + segments.each_with_index do |part, index| + case part + when Regin::Anchor + # ignore + when Regin::Character + throw :halt unless part.literal? + + if s.last.is_a?(String) + s.last << part.value.dup + else + s << part.value.dup + end + when Regin::Group + if part.name + s << DynamicSegment.new(part.name, part.expression.to_regexp(true)) + else + s << parse_segments(part.expression) + end + when Regin::Expression + return parse_segments(part) + else + throw :halt + end + end + + s + end + + EMPTY_STRING = ''.freeze + + def generate_from_segments(segments, params, merged, options, optional = false) + if optional + return EMPTY_STRING if segments.all? { |s| s.is_a?(String) } + return EMPTY_STRING unless segments.flatten.any? { |s| + params.has_key?(s.name) if s.is_a?(DynamicSegment) + } + return EMPTY_STRING if segments.any? { |segment| + if segment.is_a?(DynamicSegment) + value = merged[segment.name] || @defaults[segment.name] + value = parameterize(segment.name, value, options) + + merged_value = parameterize(segment.name, merged[segment.name], options) + default_value = parameterize(segment.name, @defaults[segment.name], options) + + if value.nil? || segment !~ value + true + elsif merged_value == default_value + # Nasty control flow + return :clear_remaining_segments + else + false + end + end + } + end + + generated = segments.map do |segment| + case segment + when String + segment + when DynamicSegment + value = params[segment.name] || merged[segment.name] || @defaults[segment.name] + value = parameterize(segment.name, value, options) + if value && segment =~ value.to_s + value + else + return + end + when Array + value = generate_from_segments(segment, params, merged, options, true) + if value == :clear_remaining_segments + segment.each { |s| params.delete(s.name) if s.is_a?(DynamicSegment) } + EMPTY_STRING + elsif value.nil? + EMPTY_STRING + else + value + end + end + end + + # Delete any used items from the params + segments.each { |s| params.delete(s.name) if s.is_a?(DynamicSegment) } + + generated.join + end + + def parameterize(name, value, options) + if block = options[:parameterize] + block.call(name, value) + else + value + end + end + end + include InstanceMethods + + def initialize(regexp) + super + segments + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/multimap.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/multimap.rb new file mode 100644 index 0000000000..0f8eaaec67 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/multimap.rb @@ -0,0 +1,53 @@ +begin + require 'nested_multimap' +rescue LoadError + $: << File.expand_path(File.join(File.dirname(__FILE__), 'vendor/multimap')) + require 'nested_multimap' +end + +module Rack::Mount + class Multimap < NestedMultimap #:nodoc: + def store(*args) + keys = args.dup + value = keys.pop + key = keys.shift + + raise ArgumentError, 'wrong number of arguments (1 for 2)' unless value + + unless key.respond_to?(:=~) + raise ArgumentError, "unsupported key: #{args.first.inspect}" + end + + if key.is_a?(Regexp) + if keys.empty? + @hash.each_pair { |k, l| l << value if k =~ key } + self.default << value + else + @hash.each_pair { |k, _| + if k =~ key + args[0] = k + super(*args) + end + } + + self.default = self.class.new(default) unless default.is_a?(self.class) + default[*keys.dup] = value + end + else + super(*args) + end + end + alias_method :[]=, :store + + undef :index, :invert + + def height + containers_with_default.max { |a, b| a.length <=> b.length }.length + end + + def average_height + lengths = containers_with_default.map { |e| e.length } + lengths.inject(0) { |sum, len| sum += len }.to_f / lengths.size + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/prefix.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/prefix.rb new file mode 100644 index 0000000000..58892e4c4f --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/prefix.rb @@ -0,0 +1,36 @@ +require 'rack/mount/utils' + +module Rack::Mount + class Prefix #:nodoc: + EMPTY_STRING = ''.freeze + PATH_INFO = 'PATH_INFO'.freeze + SCRIPT_NAME = 'SCRIPT_NAME'.freeze + SLASH = '/'.freeze + + KEY = 'rack.mount.prefix'.freeze + + def initialize(app, prefix = nil) + @app, @prefix = app, prefix.freeze + freeze + end + + def call(env) + if prefix = env[KEY] || @prefix + old_path_info = env[PATH_INFO].dup + old_script_name = env[SCRIPT_NAME].dup + + begin + env[PATH_INFO] = Utils.normalize_path(env[PATH_INFO].sub(prefix, EMPTY_STRING)) + env[PATH_INFO] = EMPTY_STRING if env[PATH_INFO] == SLASH + env[SCRIPT_NAME] = Utils.normalize_path(env[SCRIPT_NAME].to_s + prefix) + @app.call(env) + ensure + env[PATH_INFO] = old_path_info + env[SCRIPT_NAME] = old_script_name + end + else + @app.call(env) + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/regexp_with_named_groups.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/regexp_with_named_groups.rb new file mode 100644 index 0000000000..c11292b2a2 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/regexp_with_named_groups.rb @@ -0,0 +1,69 @@ +module Rack::Mount + if Regin.regexp_supports_named_captures? + RegexpWithNamedGroups = Regexp + else + require 'strscan' + + # A wrapper that adds shim named capture support to older + # versions of Ruby. + # + # Because the named capture syntax causes a parse error, an + # alternate syntax is used to indicate named captures. + # + # Ruby 1.9+ named capture syntax: + # + # /(?[a-z]+)/ + # + # Ruby 1.8 shim syntax: + # + # /(?:[a-z]+)/ + class RegexpWithNamedGroups < Regexp + def self.new(regexp) #:nodoc: + if regexp.is_a?(RegexpWithNamedGroups) + regexp + else + super + end + end + + # Wraps Regexp with named capture support. + def initialize(regexp) + regexp = Regexp.compile(regexp) unless regexp.is_a?(Regexp) + source, options = regexp.source, regexp.options + @names, scanner = [], StringScanner.new(source) + + while scanner.skip_until(/\(/) + if scanner.scan(/\?:<([^>]+)>/) + @names << scanner[1] + elsif scanner.scan(/\?(i?m?x?\-?i?m?x?)?:/) + # ignore noncapture + else + @names << nil + end + end + source.gsub!(/\?:<([^>]+)>/, '') + + @names = [] unless @names.any? + @names.freeze + + super(source, options) + end + + def names + @names.dup + end + + def named_captures + named_captures = {} + names.each_with_index { |n, i| + named_captures[n] = [i+1] if n + } + named_captures + end + + def eql?(other) + super && @names.eql?(other.names) + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/route.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/route.rb new file mode 100644 index 0000000000..680c40f147 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/route.rb @@ -0,0 +1,130 @@ +require 'rack/mount/generatable_regexp' +require 'rack/mount/regexp_with_named_groups' +require 'rack/mount/utils' + +module Rack::Mount + # Route is an internal class used to wrap a single route attributes. + # + # Plugins should not depend on any method on this class or instantiate + # new Route objects. Instead use the factory method, RouteSet#add_route + # to create new routes and add them to the set. + class Route + # Valid rack application to call if conditions are met + attr_reader :app + + # A hash of conditions to match against. Conditions may be expressed + # as strings or regexps to match against. + attr_reader :conditions + + # A hash of values that always gets merged into the parameters hash + attr_reader :defaults + + # Symbol identifier for the route used with named route generations + attr_reader :name + + attr_reader :named_captures + + def initialize(app, conditions, defaults, name) + unless app.respond_to?(:call) + raise ArgumentError, 'app must be a valid rack application' \ + ' and respond to call' + end + @app = app + + @name = name ? name.to_sym : nil + @defaults = (defaults || {}).freeze + + @conditions = {} + + conditions.each do |method, pattern| + next unless method && pattern + + pattern = Regexp.compile("\\A#{Regexp.escape(pattern)}\\Z") if pattern.is_a?(String) + + if pattern.is_a?(Regexp) + pattern = Utils.normalize_extended_expression(pattern) + pattern = RegexpWithNamedGroups.new(pattern) + pattern.extend(GeneratableRegexp::InstanceMethods) + pattern.defaults = @defaults + end + + @conditions[method] = pattern.freeze + end + + @named_captures = {} + @conditions.map { |method, condition| + next unless condition.respond_to?(:named_captures) + @named_captures[method] = condition.named_captures.inject({}) { |named_captures, (k, v)| + named_captures[k.to_sym] = v.last - 1 + named_captures + }.freeze + } + @named_captures.freeze + + @has_significant_params = @conditions.any? { |method, condition| + (condition.respond_to?(:required_params) && condition.required_params.any?) || + (condition.respond_to?(:required_defaults) && condition.required_defaults.any?) + } + + if @conditions.has_key?(:path_info) && + !Utils.regexp_anchored?(@conditions[:path_info]) + @prefix = true + @app = Prefix.new(@app) + else + @prefix = false + end + + @conditions.freeze + end + + def prefix? + @prefix + end + + + def generation_keys + @conditions.inject({}) { |keys, (method, condition)| + if condition.respond_to?(:required_defaults) + keys.merge!(condition.required_defaults) + else + keys + end + } + end + + def significant_params? + @has_significant_params + end + + def generate(method, params = {}, recall = {}, options = {}) + if method.nil? + result = @conditions.inject({}) { |h, (m, condition)| + if condition.respond_to?(:generate) + h[m] = condition.generate(params, recall, options) + end + h + } + return nil if result.values.compact.empty? + else + if condition = @conditions[method] + if condition.respond_to?(:generate) + result = condition.generate(params, recall, options) + end + end + end + + if result + @defaults.each do |key, value| + params.delete(key) if params[key] == value + end + end + + result + end + + + def inspect #:nodoc: + "#<#{self.class.name} @app=#{@app.inspect} @conditions=#{@conditions.inspect} @defaults=#{@defaults.inspect} @name=#{@name.inspect}>" + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/route_set.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/route_set.rb new file mode 100644 index 0000000000..0e5a65a640 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/route_set.rb @@ -0,0 +1,409 @@ +require 'rack/mount/multimap' +require 'rack/mount/route' +require 'rack/mount/utils' + +module Rack::Mount + class RoutingError < StandardError; end + + class RouteSet + # Initialize a new RouteSet without optimizations + def self.new_without_optimizations(options = {}, &block) + new(options.merge(:_optimize => false), &block) + end + + # Basic RouteSet initializer. + # + # If a block is given, the set is yielded and finalized. + # + # See other aspects for other valid options: + # - Generation::RouteSet.new + # - Recognition::RouteSet.new + def initialize(options = {}, &block) + @parameters_key = options.delete(:parameters_key) || 'rack.routing_args' + @parameters_key.freeze + + @named_routes = {} + + @recognition_key_analyzer = Analysis::Splitting.new + @generation_key_analyzer = Analysis::Frequency.new + + @request_class = options.delete(:request_class) || Rack::Request + @valid_conditions = @request_class.public_instance_methods.map! { |m| m.to_sym } + + extend CodeGeneration unless options[:_optimize] == false + @optimized_recognize_defined = false + + @routes = [] + expire! + + if block_given? + yield self + rehash + end + end + + # Builder method to add a route to the set + # + # app:: A valid Rack app to call if the conditions are met. + # conditions:: A hash of conditions to match against. + # Conditions may be expressed as strings or + # regexps to match against. + # defaults:: A hash of values that always gets merged in + # name:: Symbol identifier for the route used with named + # route generations + def add_route(app, conditions = {}, defaults = {}, name = nil) + unless conditions.is_a?(Hash) + raise ArgumentError, 'conditions must be a Hash' + end + + unless conditions.all? { |method, pattern| + @valid_conditions.include?(method) + } + raise ArgumentError, 'conditions may only include ' + + @valid_conditions.inspect + end + + route = Route.new(app, conditions, defaults, name) + @routes << route + + @recognition_key_analyzer << route.conditions + + @named_routes[route.name] = route if route.name + @generation_key_analyzer << route.generation_keys + + expire! + route + end + + def recognize(obj) + raise 'route set not finalized' unless @recognition_graph + + cache = {} + keys = @recognition_keys.map { |key| + if key.respond_to?(:call) + key.call(cache, obj) + else + obj.send(key) + end + } + + @recognition_graph[*keys].each do |route| + matches = {} + params = route.defaults.dup + + if route.conditions.all? { |method, condition| + value = obj.send(method) + if condition.is_a?(Regexp) && (m = value.match(condition)) + matches[method] = m + captures = m.captures + route.named_captures[method].each do |k, i| + if v = captures[i] + params[k] = v + end + end + true + elsif value == condition + true + else + false + end + } + if block_given? + yield route, matches, params + else + return route, matches, params + end + end + end + + nil + end + + X_CASCADE = 'X-Cascade'.freeze + PASS = 'pass'.freeze + PATH_INFO = 'PATH_INFO'.freeze + + # Rack compatible recognition and dispatching method. Routes are + # tried until one returns a non-catch status code. If no routes + # match, the catch status code is returned. + # + # This method can only be invoked after the RouteSet has been + # finalized. + def call(env) + raise 'route set not finalized' unless @recognition_graph + + env[PATH_INFO] = Utils.normalize_path(env[PATH_INFO]) + + request = nil + req = @request_class.new(env) + recognize(req) do |route, matches, params| + # TODO: We only want to unescape params from uri related methods + params.each { |k, v| params[k] = Utils.unescape_uri(v) if v.is_a?(String) } + + if route.prefix? + env[Prefix::KEY] = matches[:path_info].to_s + end + + env[@parameters_key] = params + result = route.app.call(env) + return result unless result[1][X_CASCADE] == PASS + end + + request || [404, {'Content-Type' => 'text/html', 'X-Cascade' => 'pass'}, ['Not Found']] + end + + # Generates a url from Rack env and identifiers or significant keys. + # + # To generate a url by named route, pass the name in as a +Symbol+. + # url(env, :dashboard) # => "/dashboard" + # + # Additional parameters can be passed in as a hash + # url(env, :people, :id => "1") # => "/people/1" + # + # If no name route is given, it will fall back to a slower + # generation search. + # url(env, :controller => "people", :action => "show", :id => "1") + # # => "/people/1" + def url(env, *args) + named_route, params = nil, {} + + case args.length + when 2 + named_route, params = args[0], args[1].dup + when 1 + if args[0].is_a?(Hash) + params = args[0].dup + else + named_route = args[0] + end + else + raise ArgumentError + end + + only_path = params.delete(:only_path) + recall = env[@parameters_key] || {} + + unless result = generate(:all, named_route, params, recall, + :parameterize => lambda { |name, param| Utils.escape_uri(param) }) + return + end + + parts, params = result + return unless parts + + params.each do |k, v| + if v + params[k] = v + else + params.delete(k) + end + end + + req = stubbed_request_class.new(env) + req._stubbed_values = parts.merge(:query_string => Utils.build_nested_query(params)) + only_path ? req.fullpath : req.url + end + + def generate(method, *args) #:nodoc: + raise 'route set not finalized' unless @generation_graph + + method = nil if method == :all + named_route, params, recall, options = extract_params!(*args) + merged = recall.merge(params) + route = nil + + if named_route + if route = @named_routes[named_route.to_sym] + recall = route.defaults.merge(recall) + url = route.generate(method, params, recall, options) + [url, params] + else + raise RoutingError, "#{named_route} failed to generate from #{params.inspect}" + end + else + keys = @generation_keys.map { |key| + if k = merged[key] + k.to_s + else + nil + end + } + @generation_graph[*keys].each do |r| + next unless r.significant_params? + if url = r.generate(method, params, recall, options) + return [url, params] + end + end + + raise RoutingError, "No route matches #{params.inspect}" + end + end + + # Number of routes in the set + def length + @routes.length + end + + def rehash #:nodoc: + @recognition_keys = build_recognition_keys + @recognition_graph = build_recognition_graph + @generation_keys = build_generation_keys + @generation_graph = build_generation_graph + end + + # Finalizes the set and builds optimized data structures. You *must* + # freeze the set before you can use call and url. + # So remember to call freeze after you are done adding routes. + def freeze + unless frozen? + rehash + + @recognition_key_analyzer = nil + @generation_key_analyzer = nil + @valid_conditions = nil + + @routes.each { |route| route.freeze } + @routes.freeze + end + + super + end + + def marshal_dump #:nodoc: + hash = {} + + instance_variables_to_serialize.each do |ivar| + hash[ivar] = instance_variable_get(ivar) + end + + if graph = hash[:@recognition_graph] + hash[:@recognition_graph] = graph.dup + end + + hash + end + + def marshal_load(hash) #:nodoc: + hash.each do |ivar, value| + instance_variable_set(ivar, value) + end + end + + protected + def recognition_stats + { :keys => @recognition_keys, + :keys_size => @recognition_keys.size, + :graph_size => @recognition_graph.size, + :graph_height => @recognition_graph.height, + :graph_average_height => @recognition_graph.average_height } + end + + private + def expire! #:nodoc: + @recognition_keys = @recognition_graph = nil + @recognition_key_analyzer.expire! + + @generation_keys = @generation_graph = nil + @generation_key_analyzer.expire! + end + + def instance_variables_to_serialize + instance_variables.map { |ivar| ivar.to_sym } - [:@stubbed_request_class, :@optimized_recognize_defined] + end + + # An internal helper method for constructing a nested set from + # the linear route set. + # + # build_nested_route_set([:request_method, :path_info]) { |route, method| + # route.send(method) + # } + def build_nested_route_set(keys, &block) + graph = Multimap.new + @routes.each_with_index do |route, index| + catch(:skip) do + k = keys.map { |key| block.call(key, index) } + Utils.pop_trailing_nils!(k) + k.map! { |key| key || /.+/ } + graph[*k] = route + end + end + graph + end + + def build_recognition_graph + build_nested_route_set(@recognition_keys) { |k, i| + @recognition_key_analyzer.possible_keys[i][k] + } + end + + def build_recognition_keys + @recognition_key_analyzer.report + end + + def build_generation_graph + build_nested_route_set(@generation_keys) { |k, i| + throw :skip unless @routes[i].significant_params? + + if k = @generation_key_analyzer.possible_keys[i][k] + k.to_s + else + nil + end + } + end + + def build_generation_keys + @generation_key_analyzer.report + end + + def extract_params!(*args) + case args.length + when 4 + named_route, params, recall, options = args + when 3 + if args[0].is_a?(Hash) + params, recall, options = args + else + named_route, params, recall = args + end + when 2 + if args[0].is_a?(Hash) + params, recall = args + else + named_route, params = args + end + when 1 + if args[0].is_a?(Hash) + params = args[0] + else + named_route = args[0] + end + else + raise ArgumentError + end + + named_route ||= nil + params ||= {} + recall ||= {} + options ||= {} + + [named_route, params.dup, recall.dup, options.dup] + end + + def stubbed_request_class + @stubbed_request_class ||= begin + klass = Class.new(@request_class) + klass.public_instance_methods.each do |method| + next if method =~ /^__|object_id/ + klass.class_eval <<-RUBY + def #{method}(*args, &block) + @_stubbed_values[:#{method}] || super + end + RUBY + end + klass.class_eval { attr_accessor :_stubbed_values } + klass + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/strexp.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/strexp.rb new file mode 100644 index 0000000000..d0d8797008 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/strexp.rb @@ -0,0 +1,68 @@ +require 'rack/mount/strexp/parser' + +module Rack::Mount + class Strexp + class << self + # Parses segmented string expression and converts it into a Regexp + # + # Strexp.compile('foo') + # # => %r{\Afoo\Z} + # + # Strexp.compile('foo/:bar', {}, ['/']) + # # => %r{\Afoo/(?[^/]+)\Z} + # + # Strexp.compile(':foo.example.com') + # # => %r{\A(?.+)\.example\.com\Z} + # + # Strexp.compile('foo/:bar', {:bar => /[a-z]+/}, ['/']) + # # => %r{\Afoo/(?[a-z]+)\Z} + # + # Strexp.compile('foo(.:extension)') + # # => %r{\Afoo(\.(?.+))?\Z} + # + # Strexp.compile('src/*files') + # # => %r{\Asrc/(?.+)\Z} + def compile(str, requirements = {}, separators = [], anchor = true) + return Regexp.compile(str) if str.is_a?(Regexp) + + requirements = requirements ? requirements.dup : {} + normalize_requirements!(requirements, separators) + + parser = StrexpParser.new + parser.anchor = anchor + parser.requirements = requirements + + begin + re = parser.scan_str(str) + rescue Racc::ParseError => e + raise RegexpError, e.message + end + + Regexp.compile(re) + end + alias_method :new, :compile + + private + def normalize_requirements!(requirements, separators) + requirements.each do |key, value| + if value.is_a?(Regexp) + if regexp_has_modifiers?(value) + requirements[key] = value + else + requirements[key] = value.source + end + else + requirements[key] = Regexp.escape(value) + end + end + requirements.default ||= separators.any? ? + "[^#{separators.join}]+" : '.+' + requirements + end + + def regexp_has_modifiers?(regexp) + regexp.options & (Regexp::IGNORECASE | Regexp::EXTENDED) != 0 + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/strexp/parser.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/strexp/parser.rb new file mode 100644 index 0000000000..cfe05afc61 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/strexp/parser.rb @@ -0,0 +1,160 @@ +# +# DO NOT MODIFY!!!! +# This file is automatically generated by Racc 1.4.6 +# from Racc grammer file "". +# + +require 'racc/parser.rb' + +require 'rack/mount/utils' +require 'rack/mount/strexp/tokenizer' + +module Rack + module Mount + class StrexpParser < Racc::Parser + + +if Regin.regexp_supports_named_captures? + REGEXP_NAMED_CAPTURE = '(?<%s>%s)'.freeze +else + REGEXP_NAMED_CAPTURE = '(?:<%s>%s)'.freeze +end + +attr_accessor :anchor, :requirements +##### State transition tables begin ### + +racc_action_table = [ + 1, 2, 3, 9, 4, 1, 2, 3, 12, 4, + 1, 2, 3, 11, 4, 1, 2, 3, nil, 4 ] + +racc_action_check = [ + 0, 0, 0, 5, 0, 3, 3, 3, 9, 3, + 8, 8, 8, 8, 8, 6, 6, 6, nil, 6 ] + +racc_action_pointer = [ + -2, nil, nil, 3, nil, 3, 13, nil, 8, 8, + nil, nil, nil ] + +racc_action_default = [ + -8, -4, -5, -8, -7, -8, -1, -3, -8, -8, + -2, -6, 13 ] + +racc_goto_table = [ + 6, 5, 10, 8, 10 ] + +racc_goto_check = [ + 2, 1, 3, 2, 3 ] + +racc_goto_pointer = [ + nil, 1, 0, -4 ] + +racc_goto_default = [ + nil, nil, nil, 7 ] + +racc_reduce_table = [ + 0, 0, :racc_error, + 1, 8, :_reduce_1, + 2, 9, :_reduce_2, + 1, 9, :_reduce_none, + 1, 10, :_reduce_4, + 1, 10, :_reduce_5, + 3, 10, :_reduce_6, + 1, 10, :_reduce_7 ] + +racc_reduce_n = 8 + +racc_shift_n = 13 + +racc_token_table = { + false => 0, + :error => 1, + :PARAM => 2, + :GLOB => 3, + :LPAREN => 4, + :RPAREN => 5, + :CHAR => 6 } + +racc_nt_base = 7 + +racc_use_result_var = true + +Racc_arg = [ + racc_action_table, + racc_action_check, + racc_action_default, + racc_action_pointer, + racc_goto_table, + racc_goto_check, + racc_goto_default, + racc_goto_pointer, + racc_nt_base, + racc_reduce_table, + racc_token_table, + racc_shift_n, + racc_reduce_n, + racc_use_result_var ] + +Racc_token_to_s_table = [ + "$end", + "error", + "PARAM", + "GLOB", + "LPAREN", + "RPAREN", + "CHAR", + "$start", + "target", + "expr", + "token" ] + +Racc_debug_parser = false + +##### State transition tables end ##### + +# reduce 0 omitted + +def _reduce_1(val, _values, result) + result = anchor ? "\\A#{val.join}\\Z" : "\\A#{val.join}" + result +end + +def _reduce_2(val, _values, result) + result = val.join + result +end + +# reduce 3 omitted + +def _reduce_4(val, _values, result) + name = val[0].to_sym + requirement = requirements[name] + result = REGEXP_NAMED_CAPTURE % [name, requirement] + + result +end + +def _reduce_5(val, _values, result) + name = val[0].to_sym + requirement = requirements[name] + result = REGEXP_NAMED_CAPTURE % [name, '.+' || requirement] + + result +end + +def _reduce_6(val, _values, result) + result = "(?:#{val[1]})?" + result +end + +def _reduce_7(val, _values, result) + result = Regexp.escape(val[0]) + result +end + +def _reduce_none(val, _values, result) + val[0] +end + + end # class StrexpParser + end # module Mount +end # module Rack diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/strexp/parser.y b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/strexp/parser.y new file mode 100644 index 0000000000..ffbd9fae11 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/strexp/parser.y @@ -0,0 +1,34 @@ +class Rack::Mount::StrexpParser +rule + target: expr { result = anchor ? "\\A#{val.join}\\Z" : "\\A#{val.join}" } + + expr: expr token { result = val.join } + | token + + token: PARAM { + name = val[0].to_sym + requirement = requirements[name] + result = REGEXP_NAMED_CAPTURE % [name, requirement] + } + | GLOB { + name = val[0].to_sym + requirement = requirements[name] + result = REGEXP_NAMED_CAPTURE % [name, '.+' || requirement] + } + | LPAREN expr RPAREN { result = "(?:#{val[1]})?" } + | CHAR { result = Regexp.escape(val[0]) } +end + +---- header ---- +require 'rack/mount/utils' +require 'rack/mount/strexp/tokenizer' + +---- inner + +if Regin.regexp_supports_named_captures? + REGEXP_NAMED_CAPTURE = '(?<%s>%s)'.freeze +else + REGEXP_NAMED_CAPTURE = '(?:<%s>%s)'.freeze +end + +attr_accessor :anchor, :requirements diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/strexp/tokenizer.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/strexp/tokenizer.rb new file mode 100644 index 0000000000..0ff7f67661 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/strexp/tokenizer.rb @@ -0,0 +1,83 @@ +#-- +# DO NOT MODIFY!!!! +# This file is automatically generated by rex 1.0.5.beta1 +# from lexical definition file "lib/rack/mount/strexp/tokenizer.rex". +#++ + +require 'racc/parser' +class Rack::Mount::StrexpParser < Racc::Parser + require 'strscan' + + class ScanError < StandardError ; end + + attr_reader :lineno + attr_reader :filename + attr_accessor :state + + def scan_setup(str) + @ss = StringScanner.new(str) + @lineno = 1 + @state = nil + end + + def action + yield + end + + def scan_str(str) + scan_setup(str) + do_parse + end + alias :scan :scan_str + + def load_file( filename ) + @filename = filename + open(filename, "r") do |f| + scan_setup(f.read) + end + end + + def scan_file( filename ) + load_file(filename) + do_parse + end + + + def next_token + return if @ss.eos? + + text = @ss.peek(1) + @lineno += 1 if text == "\n" + token = case @state + when nil + case + when (text = @ss.scan(/\\(\(|\)|:|\*)/)) + action { [:CHAR, @ss[1]] } + + when (text = @ss.scan(/\:([a-zA-Z_]\w*)/)) + action { [:PARAM, @ss[1]] } + + when (text = @ss.scan(/\*([a-zA-Z_]\w*)/)) + action { [:GLOB, @ss[1]] } + + when (text = @ss.scan(/\(/)) + action { [:LPAREN, text] } + + when (text = @ss.scan(/\)/)) + action { [:RPAREN, text] } + + when (text = @ss.scan(/./)) + action { [:CHAR, text] } + + else + text = @ss.string[@ss.pos .. -1] + raise ScanError, "can not match: '" + text + "'" + end # if + + else + raise ScanError, "undefined state: '" + state.to_s + "'" + end # case state + token + end # def next_token + +end # class diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/strexp/tokenizer.rex b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/strexp/tokenizer.rex new file mode 100644 index 0000000000..473bd096e1 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/strexp/tokenizer.rex @@ -0,0 +1,12 @@ +class Rack::Mount::StrexpParser +macro + RESERVED \(|\)|:|\* + ALPHA_U [a-zA-Z_] +rule + \\({RESERVED}) { [:CHAR, @ss[1]] } + \:({ALPHA_U}\w*) { [:PARAM, @ss[1]] } + \*({ALPHA_U}\w*) { [:GLOB, @ss[1]] } + \( { [:LPAREN, text] } + \) { [:RPAREN, text] } + . { [:CHAR, text] } +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/utils.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/utils.rb new file mode 100644 index 0000000000..aa23b1162f --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/utils.rb @@ -0,0 +1,148 @@ +begin + require 'regin' +rescue LoadError + $: << File.expand_path(File.join(File.dirname(__FILE__), 'vendor/regin')) + require 'regin' +end + +require 'uri' + +module Rack::Mount + # Private utility methods used throughout Rack::Mount. + #-- + # This module is a trash can. Try to move these functions into + # more appropriate contexts. + #++ + module Utils + # Normalizes URI path. + # + # Strips off trailing slash and ensures there is a leading slash. + # + # normalize_path("/foo") # => "/foo" + # normalize_path("/foo/") # => "/foo" + # normalize_path("foo") # => "/foo" + # normalize_path("") # => "/" + def normalize_path(path) + path = "/#{path}" + path.squeeze!('/') + path.sub!(%r{/+\Z}, '') + path = '/' if path == '' + path + end + module_function :normalize_path + + # Removes trailing nils from array. + # + # pop_trailing_nils!([1, 2, 3]) # => [1, 2, 3] + # pop_trailing_nils!([1, 2, 3, nil, nil]) # => [1, 2, 3] + # pop_trailing_nils!([nil]) # => [] + def pop_trailing_nils!(ary) + while ary.length > 0 && ary.last.nil? + ary.pop + end + ary + end + module_function :pop_trailing_nils! + + RESERVED_PCHAR = ':@&=+$,;%' + SAFE_PCHAR = "#{URI::REGEXP::PATTERN::UNRESERVED}#{RESERVED_PCHAR}" + if RUBY_VERSION >= '1.9' + UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false).freeze + else + UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false, 'N').freeze + end + + Parser = URI.const_defined?(:Parser) ? URI::Parser.new : URI + + def escape_uri(uri) + Parser.escape(uri.to_s, UNSAFE_PCHAR) + end + module_function :escape_uri + + if ''.respond_to?(:force_encoding) + def unescape_uri(uri) + Parser.unescape(uri).force_encoding('utf-8') + end + else + def unescape_uri(uri) + URI.unescape(uri) + end + end + module_function :unescape_uri + + # Taken from Rack 1.1.x to build nested query strings + def build_nested_query(value, prefix = nil) #:nodoc: + case value + when Array + value.map { |v| + build_nested_query(v, "#{prefix}[]") + }.join("&") + when Hash + value.map { |k, v| + build_nested_query(v, prefix ? "#{prefix}[#{Rack::Utils.escape(k)}]" : Rack::Utils.escape(k)) + }.join("&") + when String + raise ArgumentError, "value must be a Hash" if prefix.nil? + "#{prefix}=#{Rack::Utils.escape(value)}" + else + prefix + end + end + module_function :build_nested_query + + # Determines whether the regexp must match the entire string. + # + # regexp_anchored?(/^foo$/) # => true + # regexp_anchored?(/foo/) # => false + # regexp_anchored?(/^foo/) # => false + # regexp_anchored?(/foo$/) # => false + def regexp_anchored?(regexp) + regexp.source =~ /\A(\\A|\^).*(\\Z|\$)\Z/m ? true : false + end + module_function :regexp_anchored? + + def normalize_extended_expression(regexp) + return regexp unless regexp.options & Regexp::EXTENDED != 0 + source = regexp.source + source.gsub!(/#.+$/, '') + source.gsub!(/\s+/, '') + source.gsub!(/\\\//, '/') + Regexp.compile(source) + end + module_function :normalize_extended_expression + + def parse_regexp(regexp) + cache = @@_parse_regexp_cache ||= {} + + if expression = cache[regexp] + return expression + end + + unless regexp.is_a?(RegexpWithNamedGroups) + regexp = RegexpWithNamedGroups.new(regexp) + end + + expression = Regin.parse(regexp) + + unless Regin.regexp_supports_named_captures? + tag_captures = Proc.new do |group| + case group + when Regin::Group + # TODO: dup instead of mutating + group.instance_variable_set('@name', regexp.names[group.index]) if group.index + tag_captures.call(group.expression) + when Regin::Expression + group.each { |child| tag_captures.call(child) } + end + end + tag_captures.call(expression) + end + + cache[regexp] = expression.freeze + expression + rescue Racc::ParseError, Regin::Parser::ScanError + [] + end + module_function :parse_regexp + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/multimap/multimap.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/multimap/multimap.rb new file mode 100644 index 0000000000..0b49b49280 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/multimap/multimap.rb @@ -0,0 +1,569 @@ +require 'forwardable' +require 'multiset' + +# Multimap is a generalization of a map or associative array +# abstract data type in which more than one value may be associated +# with and returned for a given key. +# +# == Example +# +# require 'multimap' +# map = Multimap.new +# map["a"] = 100 +# map["b"] = 200 +# map["a"] = 300 +# map["a"] # -> [100, 300] +# map["b"] # -> [200] +# map.keys # -> # +class Multimap + extend Forwardable + + include Enumerable + + # call-seq: + # Multimap[ [key =>|, value]* ] => multimap + # + # Creates a new multimap populated with the given objects. + # + # Multimap["a", 100, "b", 200] #=> {"a"=>[100], "b"=>[200]} + # Multimap["a" => 100, "b" => 200] #=> {"a"=>[100], "b"=>[200]} + def self.[](*args) + default = [] + + if args.size == 2 && args.last.is_a?(Hash) + default = args.shift + elsif !args.first.is_a?(Hash) && args.size % 2 == 1 + default = args.shift + end + + if args.size == 1 && args.first.is_a?(Hash) + args[0] = args.first.inject({}) { |hash, (key, value)| + unless value.is_a?(default.class) + value = (default.dup << value) + end + hash[key] = value + hash + } + else + index = 0 + args.map! { |value| + unless index % 2 == 0 || value.is_a?(default.class) + value = (default.dup << value) + end + index += 1 + value + } + end + + map = new + map.instance_variable_set(:@hash, Hash[*args]) + map.default = default + map + end + + # call-seq: + # Multimap.new => multimap + # Multimap.new(default) => multimap + # + # Returns a new, empty multimap. + # + # map = Multimap.new(Set.new) + # h["a"] = 100 + # h["b"] = 200 + # h["a"] #=> [100].to_set + # h["c"] #=> [].to_set + def initialize(default = []) + @hash = Hash.new(default) + end + + def initialize_copy(original) #:nodoc: + @hash = Hash.new(original.default.dup) + original._internal_hash.each_pair do |key, container| + @hash[key] = container.dup + end + end + + def_delegators :@hash, :clear, :default, :default=, :empty?, + :fetch, :has_key?, :key? + + # Retrieves the value object corresponding to the + # *keys object. + def [](key) + @hash[key] + end + + # call-seq: + # map[key] = value => value + # map.store(key, value) => value + # + # Associates the value given by value with the key + # given by key. Unlike a regular hash, multiple can be + # assoicated with the same value. + # + # map = Multimap["a" => 100, "b" => 200] + # map["a"] = 9 + # map["c"] = 4 + # map #=> {"a" => [100, 9], "b" => [200], "c" => [4]} + def store(key, value) + update_container(key) do |container| + container << value + container + end + end + alias_method :[]=, :store + + # call-seq: + # map.delete(key, value) => value + # map.delete(key) => value + # + # Deletes and returns a key-value pair from map. If only + # key is given, all the values matching that key will be + # deleted. + # + # map = Multimap["a" => 100, "b" => [200, 300]] + # map.delete("b", 300) #=> 300 + # map.delete("a") #=> [100] + def delete(key, value = nil) + if value + @hash[key].delete(value) + else + @hash.delete(key) + end + end + + # call-seq: + # map.each { |key, value| block } => map + # + # Calls block for each key/value pair in map, passing + # the key and value to the block as a two-element array. + # + # map = Multimap["a" => 100, "b" => [200, 300]] + # map.each { |key, value| puts "#{key} is #{value}" } + # + # produces: + # + # a is 100 + # b is 200 + # b is 300 + def each + each_pair do |key, value| + yield [key, value] + end + end + + # call-seq: + # map.each_association { |key, container| block } => map + # + # Calls block once for each key/container in map, passing + # the key and container to the block as parameters. + # + # map = Multimap["a" => 100, "b" => [200, 300]] + # map.each_association { |key, container| puts "#{key} is #{container}" } + # + # produces: + # + # a is [100] + # b is [200, 300] + def each_association(&block) + @hash.each_pair(&block) + end + + # call-seq: + # map.each_container { |container| block } => map + # + # Calls block for each container in map, passing the + # container as a parameter. + # + # map = Multimap["a" => 100, "b" => [200, 300]] + # map.each_container { |container| puts container } + # + # produces: + # + # [100] + # [200, 300] + def each_container + each_association do |_, container| + yield container + end + end + + # call-seq: + # map.each_key { |key| block } => map + # + # Calls block for each key in hsh, passing the key + # as a parameter. + # + # map = Multimap["a" => 100, "b" => [200, 300]] + # map.each_key { |key| puts key } + # + # produces: + # + # a + # b + # b + def each_key + each_pair do |key, _| + yield key + end + end + + # call-seq: + # map.each_pair { |key_value_array| block } => map + # + # Calls block for each key/value pair in map, + # passing the key and value as parameters. + # + # map = Multimap["a" => 100, "b" => [200, 300]] + # map.each_pair { |key, value| puts "#{key} is #{value}" } + # + # produces: + # + # a is 100 + # b is 200 + # b is 300 + def each_pair + each_association do |key, values| + values.each do |value| + yield key, value + end + end + end + + # call-seq: + # map.each_value { |value| block } => map + # + # Calls block for each key in map, passing the + # value as a parameter. + # + # map = Multimap["a" => 100, "b" => [200, 300]] + # map.each_value { |value| puts value } + # + # produces: + # + # 100 + # 200 + # 300 + def each_value + each_pair do |_, value| + yield value + end + end + + def ==(other) #:nodoc: + case other + when Multimap + @hash == other._internal_hash + else + @hash == other + end + end + + def eql?(other) #:nodoc: + case other + when Multimap + @hash.eql?(other._internal_hash) + else + @hash.eql?(other) + end + end + + def freeze #:nodoc: + each_container { |container| container.freeze } + default.freeze + super + end + + # call-seq: + # map.has_value?(value) => true or false + # map.value?(value) => true or false + # + # Returns true if the given value is present for any key + # in map. + # + # map = Multimap["a" => 100, "b" => [200, 300]] + # map.has_value?(300) #=> true + # map.has_value?(999) #=> false + def has_value?(value) + values.include?(value) + end + alias_method :value?, :has_value? + + # call-seq: + # map.index(value) => key + # + # Returns the key for a given value. If not found, returns + # nil. + # + # map = Multimap["a" => 100, "b" => [200, 300]] + # map.index(100) #=> "a" + # map.index(200) #=> "b" + # map.index(999) #=> nil + def index(value) + invert[value] + end + + # call-seq: + # map.delete_if {| key, value | block } -> map + # + # Deletes every key-value pair from map for which block + # evaluates to true. + # + # map = Multimap["a" => 100, "b" => [200, 300]] + # map.delete_if {|key, value| value >= 300 } + # #=> Multimap["a" => 100, "b" => 200] + # + def delete_if + each_association do |key, container| + container.delete_if do |value| + yield [key, value] + end + end + self + end + + # call-seq: + # map.reject {| key, value | block } -> map + # + # Same as Multimap#delete_if, but works on (and returns) a + # copy of the map. Equivalent to + # map.dup.delete_if. + # + def reject(&block) + dup.delete_if(&block) + end + + # call-seq: + # map.reject! {| key, value | block } -> map or nil + # + # Equivalent to Multimap#delete_if, but returns + # nil if no changes were made. + # + def reject!(&block) + old_size = size + delete_if(&block) + old_size == size ? nil : self + end + + # call-seq: + # map.replace(other_map) => map + # + # Replaces the contents of map with the contents of + # other_map. + # + # map = Multimap["a" => 100, "b" => 200] + # map.replace({ "c" => 300, "d" => 400 }) + # #=> Multimap["c" => 300, "d" => 400] + def replace(other) + case other + when Array + @hash.replace(self.class[self.default, *other]) + when Hash + @hash.replace(self.class[self.default, other]) + when self.class + @hash.replace(other) + else + raise ArgumentError + end + end + + # call-seq: + # map.invert => multimap + # + # Returns a new multimap created by using map's values as keys, + # and the keys as values. + # + # map = Multimap["n" => 100, "m" => 100, "d" => [200, 300]] + # map.invert #=> Multimap[100 => ["n", "m"], 200 => "d", 300 => "d"] + def invert + h = self.class.new(default.dup) + each_pair { |key, value| h[value] = key } + h + end + + # call-seq: + # map.keys => multiset + # + # Returns a new +Multiset+ populated with the keys from this hash. See also + # Multimap#values and Multimap#containers. + # + # map = Multimap["a" => 100, "b" => [200, 300], "c" => 400] + # map.keys #=> Multiset.new(["a", "b", "b", "c"]) + def keys + keys = Multiset.new + each_key { |key| keys << key } + keys + end + + # Returns true if the given key is present in Multimap. + def include?(key) + keys.include?(key) + end + alias_method :member?, :include? + + # call-seq: + # map.length => fixnum + # map.size => fixnum + # + # Returns the number of key-value pairs in the map. + # + # map = Multimap["a" => 100, "b" => [200, 300], "c" => 400] + # map.length #=> 4 + # map.delete("a") #=> 100 + # map.length #=> 3 + def size + values.size + end + alias_method :length, :size + + # call-seq: + # map.merge(other_map) => multimap + # + # Returns a new multimap containing the contents of other_map and + # the contents of map. + # + # map1 = Multimap["a" => 100, "b" => 200] + # map2 = Multimap["a" => 254, "c" => 300] + # map2.merge(map2) #=> Multimap["a" => 100, "b" => [200, 254], "c" => 300] + # map1 #=> Multimap["a" => 100, "b" => 200] + def merge(other) + dup.update(other) + end + + # call-seq: + # map.merge!(other_map) => multimap + # map.update(other_map) => multimap + # + # Adds each pair from other_map to map. + # + # map1 = Multimap["a" => 100, "b" => 200] + # map2 = Multimap["b" => 254, "c" => 300] + # + # map1.merge!(map2) + # #=> Multimap["a" => 100, "b" => [200, 254], "c" => 300] + def update(other) + case other + when self.class + other.each_pair { |key, value| store(key, value) } + when Hash + update(self.class[self.default, other]) + else + raise ArgumentError + end + self + end + alias_method :merge!, :update + + # call-seq: + # map.select { |key, value| block } => multimap + # + # Returns a new Multimap consisting of the pairs for which the + # block returns true. + # + # map = Multimap["a" => 100, "b" => 200, "c" => 300] + # map.select { |k,v| k > "a" } #=> Multimap["b" => 200, "c" => 300] + # map.select { |k,v| v < 200 } #=> Multimap["a" => 100] + def select + inject(self.class.new) { |map, (key, value)| + map[key] = value if yield([key, value]) + map + } + end + + # call-seq: + # map.to_a => array + # + # Converts map to a nested array of [key, + # value] arrays. + # + # map = Multimap["a" => 100, "b" => [200, 300], "c" => 400] + # map.to_a #=> [["a", 100], ["b", 200], ["b", 300], ["c", 400]] + def to_a + ary = [] + each_pair do |key, value| + ary << [key, value] + end + ary + end + + # call-seq: + # map.to_hash => hash + # + # Converts map to a basic hash. + # + # map = Multimap["a" => 100, "b" => [200, 300]] + # map.to_hash #=> { "a" => [100], "b" => [200, 300] } + def to_hash + @hash.dup + end + + # call-seq: + # map.containers => array + # + # Returns a new array populated with the containers from map. See + # also Multimap#keys and Multimap#values. + # + # map = Multimap["a" => 100, "b" => [200, 300]] + # map.containers #=> [[100], [200, 300]] + def containers + containers = [] + each_container { |container| containers << container } + containers + end + + # call-seq: + # map.values => array + # + # Returns a new array populated with the values from map. See + # also Multimap#keys and Multimap#containers. + # + # map = Multimap["a" => 100, "b" => [200, 300]] + # map.values #=> [100, 200, 300] + def values + values = [] + each_value { |value| values << value } + values + end + + # Return an array containing the values associated with the given keys. + def values_at(*keys) + @hash.values_at(*keys) + end + + def marshal_dump #:nodoc: + @hash + end + + def marshal_load(hash) #:nodoc: + @hash = hash + end + + def to_yaml(opts = {}) #:nodoc: + YAML::quick_emit(self, opts) do |out| + out.map(taguri, to_yaml_style) do |map| + @hash.each do |k, v| + map.add(k, v) + end + map.add('__default__', @hash.default) + end + end + end + + def yaml_initialize(tag, val) #:nodoc: + default = val.delete('__default__') + @hash = val + @hash.default = default + self + end + + protected + def _internal_hash #:nodoc: + @hash + end + + def update_container(key) #:nodoc: + container = @hash[key] + container = container.dup if container.equal?(default) + container = yield(container) + @hash[key] = container + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/multimap/multiset.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/multimap/multiset.rb new file mode 100644 index 0000000000..119bf12646 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/multimap/multiset.rb @@ -0,0 +1,185 @@ +require 'set' + +# Multiset implements a collection of unordered values and +# allows duplicates. +# +# == Example +# +# require 'multiset' +# s1 = Multiset.new [1, 2] # -> # +# s1.add(2) # -> # +# s1.merge([2, 6]) # -> # +# s1.multiplicity(2) # -> 3 +# s1.multiplicity(3) # -> 1 +class Multiset < Set + def initialize(*args, &block) #:nodoc: + @hash = Hash.new(0) + super + end + + # Returns the number of times an element belongs to the multiset. + def multiplicity(e) + @hash[e] + end + + # Returns the total number of elements in a multiset, including + # repeated memberships + def cardinality + @hash.inject(0) { |s, (e, m)| s += m } + end + alias_method :size, :cardinality + alias_method :length, :cardinality + + # Converts the set to an array. The order of elements is uncertain. + def to_a + inject([]) { |ary, (key, _)| ary << key } + end + + # Returns true if the set is a superset of the given set. + def superset?(set) + set.is_a?(self.class) or raise ArgumentError, "value must be a set" + return false if cardinality < set.cardinality + set.all? { |o| set.multiplicity(o) <= multiplicity(o) } + end + + # Returns true if the set is a proper superset of the given set. + def proper_superset?(set) + set.is_a?(self.class) or raise ArgumentError, "value must be a set" + return false if cardinality <= set.cardinality + set.all? { |o| set.multiplicity(o) <= multiplicity(o) } + end + + # Returns true if the set is a subset of the given set. + def subset?(set) + set.is_a?(self.class) or raise ArgumentError, "value must be a set" + return false if set.cardinality < cardinality + all? { |o| multiplicity(o) <= set.multiplicity(o) } + end + + # Returns true if the set is a proper subset of the given set. + def proper_subset?(set) + set.is_a?(self.class) or raise ArgumentError, "value must be a set" + return false if set.cardinality <= cardinality + all? { |o| multiplicity(o) <= set.multiplicity(o) } + end + + # Calls the given block once for each element in the set, passing + # the element as parameter. Returns an enumerator if no block is + # given. + def each + @hash.each_pair do |key, multiplicity| + multiplicity.times do + yield(key) + end + end + self + end + + # Adds the given object to the set and returns self. Use +merge+ to + # add many elements at once. + def add(o) + @hash[o] ||= 0 + @hash[o] += 1 + self + end + alias << add + + undef :add? + + # Deletes all the identical object from the set and returns self. + # If +n+ is given, it will remove that amount of identical objects + # from the set. Use +subtract+ to delete many different items at + # once. + def delete(o, n = nil) + if n + @hash[o] ||= 0 + @hash[o] -= n if @hash[o] > 0 + @hash.delete(o) if @hash[o] == 0 + else + @hash.delete(o) + end + self + end + + undef :delete? + + # Deletes every element of the set for which block evaluates to + # true, and returns self. + def delete_if + each { |o| delete(o) if yield(o) } + self + end + + # Merges the elements of the given enumerable object to the set and + # returns self. + def merge(enum) + enum.each { |o| add(o) } + self + end + + # Deletes every element that appears in the given enumerable object + # and returns self. + def subtract(enum) + enum.each { |o| delete(o, 1) } + self + end + + # Returns a new set containing elements common to the set and the + # given enumerable object. + def &(enum) + s = dup + n = self.class.new + enum.each { |o| + if s.include?(o) + s.delete(o, 1) + n.add(o) + end + } + n + end + alias intersection & + + # Returns a new set containing elements exclusive between the set + # and the given enumerable object. (set ^ enum) is equivalent to + # ((set | enum) - (set & enum)). + def ^(enum) + n = self.class.new(enum) + each { |o| n.include?(o) ? n.delete(o, 1) : n.add(o) } + n + end + + # Returns true if two sets are equal. Two multisets are equal if + # they have the same cardinalities and each element has the same + # multiplicity in both sets. The equality of each element inside + # the multiset is defined according to Object#eql?. + def eql?(set) + return true if equal?(set) + set = self.class.new(set) unless set.is_a?(self.class) + return false unless cardinality == set.cardinality + superset?(set) && subset?(set) + end + alias_method :==, :eql? + + def marshal_dump #:nodoc: + @hash + end + + def marshal_load(hash) #:nodoc: + @hash = hash + end + + def to_yaml(opts = {}) #:nodoc: + YAML::quick_emit(self, opts) do |out| + out.map(taguri, to_yaml_style) do |map| + @hash.each do |k, v| + map.add(k, v) + end + end + end + end + + def yaml_initialize(tag, val) #:nodoc: + @hash = val + self + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/multimap/nested_multimap.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/multimap/nested_multimap.rb new file mode 100644 index 0000000000..4eb088b91a --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/multimap/nested_multimap.rb @@ -0,0 +1,158 @@ +require 'multimap' + +# NestedMultimap allows values to be assoicated with a nested +# set of keys. +class NestedMultimap < Multimap + # call-seq: + # multimap[*keys] = value => value + # multimap.store(*keys, value) => value + # + # Associates the value given by value with multiple key + # given by keys. + # + # map = NestedMultimap.new + # map["a"] = 100 + # map["a", "b"] = 101 + # map["a"] = 102 + # map #=> {"a"=>{"b"=>[100, 101, 102], default => [100, 102]}} + def store(*args) + keys = args + value = args.pop + + raise ArgumentError, 'wrong number of arguments (1 for 2)' unless value + + if keys.length > 1 + update_container(keys.shift) do |container| + container = self.class.new(container) unless container.is_a?(self.class) + container[*keys] = value + container + end + elsif keys.length == 1 + super(keys.first, value) + else + self << value + end + end + alias_method :[]=, :store + + # call-seq: + # multimap << obj => multimap + # + # Pushes the given object on to the end of all the containers. + # + # map = NestedMultimap["a" => [100], "b" => [200, 300]] + # map << 300 + # map["a"] #=> [100, 300] + # map["c"] #=> [300] + def <<(value) + @hash.each_value { |container| container << value } + self.default << value + self + end + + # call-seq: + # multimap[*keys] => value + # multimap[key1, key2, key3] => value + # + # Retrieves the value object corresponding to the + # *keys object. + def [](*keys) + i, l, r, k = 0, keys.length, self, self.class + while r.is_a?(k) + r = i < l ? r._internal_hash[keys[i]] : r.default + i += 1 + end + r + end + + # call-seq: + # multimap.each_association { |key, container| block } => multimap + # + # Calls block once for each key/container in map, passing + # the key and container to the block as parameters. + # + # map = NestedMultimap.new + # map["a"] = 100 + # map["a", "b"] = 101 + # map["a"] = 102 + # map["c"] = 200 + # map.each_association { |key, container| puts "#{key} is #{container}" } + # + # produces: + # + # ["a", "b"] is [100, 101, 102] + # "c" is [200] + def each_association + super() do |key, container| + if container.respond_to?(:each_association) + container.each_association do |nested_key, value| + yield [key, nested_key].flatten, value + end + else + yield key, container + end + end + end + + # call-seq: + # multimap.each_container_with_default { |container| block } => map + # + # Calls block for every container in map including + # the default, passing the container as a parameter. + # + # map = NestedMultimap.new + # map["a"] = 100 + # map["a", "b"] = 101 + # map["a"] = 102 + # map.each_container_with_default { |container| puts container } + # + # produces: + # + # [100, 101, 102] + # [100, 102] + # [] + def each_container_with_default(&block) + @hash.each_value do |container| + iterate_over_container(container, &block) + end + iterate_over_container(default, &block) + self + end + + # call-seq: + # multimap.containers_with_default => array + # + # Returns a new array populated with all the containers from + # map including the default. + # + # map = NestedMultimap.new + # map["a"] = 100 + # map["a", "b"] = 101 + # map["a"] = 102 + # map.containers_with_default #=> [[100, 101, 102], [100, 102], []] + def containers_with_default + containers = [] + each_container_with_default { |container| containers << container } + containers + end + + def inspect #:nodoc: + super.gsub(/\}$/, ", default => #{default.inspect}}") + end + + private + def iterate_over_container(container) + if container.respond_to?(:each_container_with_default) + container.each_container_with_default do |value| + yield value + end + else + yield container + end + end +end + +begin + require 'nested_multimap_ext' +rescue LoadError +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin.rb new file mode 100644 index 0000000000..d38922bcc6 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin.rb @@ -0,0 +1,45 @@ +module Regin + autoload :Alternation, 'regin/alternation' + autoload :Anchor, 'regin/anchor' + autoload :Atom, 'regin/atom' + autoload :Character, 'regin/character' + autoload :CharacterClass, 'regin/character_class' + autoload :Collection, 'regin/collection' + autoload :Expression, 'regin/expression' + autoload :Group, 'regin/group' + autoload :Options, 'regin/options' + autoload :Parser, 'regin/parser' + + class << self + begin + eval('foo = /(?.*)/').named_captures + + # Returns true if the interpreter is using the Oniguruma Regexp lib + # and supports named captures. + # + # /(?bar)/ + def regexp_supports_named_captures? + true + end + rescue SyntaxError, NoMethodError + def regexp_supports_named_captures? #:nodoc: + false + end + end + + # Parses Regexp and returns a Expression data structure. + def parse(regexp) + Parser.parse_regexp(regexp) + end + + # Recompiles Regexp by parsing it and turning it back into a Regexp. + # + # (In the future Regin will perform some Regexp optimizations + # such as removing unnecessary captures and options) + def compile(source) + regexp = Regexp.compile(source) + expression = parse(regexp) + Regexp.compile(expression.to_s(true), expression.flags) + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/alternation.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/alternation.rb new file mode 100644 index 0000000000..ce4f52bfdb --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/alternation.rb @@ -0,0 +1,40 @@ +module Regin + class Alternation < Collection + def initialize(*args) + args, options = extract_options(args) + + if args.length == 1 && args.first.instance_of?(Array) + super(args.first) + else + super(args) + end + + if options.key?(:ignorecase) + @array.map! { |e| e.dup(:ignorecase => options[:ignorecase]) } + end + end + + # Returns true if expression could be treated as a literal string. + # + # Alternation groups are never literal. + def literal? + false + end + + def flags + 0 + end + + def dup(options = {}) + self.class.new(to_a, options) + end + + def to_s(parent = false) + map { |e| e.to_s(parent) }.join('|') + end + + def inspect #:nodoc: + to_s.inspect + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/anchor.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/anchor.rb new file mode 100644 index 0000000000..05520dd5e0 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/anchor.rb @@ -0,0 +1,4 @@ +module Regin + class Anchor < Atom + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/atom.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/atom.rb new file mode 100644 index 0000000000..eb1923a5a1 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/atom.rb @@ -0,0 +1,59 @@ +module Regin + class Atom + attr_reader :value, :ignorecase + + def initialize(value, options = {}) + @value = value + @ignorecase = options[:ignorecase] + end + + def option_names + %w( ignorecase ) + end + + # Returns true if expression could be treated as a literal string. + def literal? + false + end + + def casefold? + ignorecase ? true : false + end + + def dup(options = {}) + original_options = option_names.inject({}) do |h, m| + h[m.to_sym] = send(m) + h + end + self.class.new(value, original_options.merge(options)) + end + + def to_s(parent = false) + "#{value}" + end + + def inspect #:nodoc: + "#<#{self.class.to_s.sub('Regin::', '')} #{to_s.inspect}>" + end + + def ==(other) #:nodoc: + case other + when String + other == to_s + else + eql?(other) + end + end + + def eql?(other) #:nodoc: + other.instance_of?(self.class) && + self.value.eql?(other.value) && + (!!self.ignorecase).eql?(!!other.ignorecase) + end + + def freeze #:nodoc: + value.freeze + super + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/character.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/character.rb new file mode 100644 index 0000000000..12a9199d2a --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/character.rb @@ -0,0 +1,56 @@ +module Regin + class Character < Atom + attr_reader :quantifier + + def initialize(value, options = {}) + @quantifier = options[:quantifier] + super + end + + def option_names + %w( quantifier ) + super + end + + # Returns true if expression could be treated as a literal string. + # + # A Character is literal is there is no quantifier attached to it. + def literal? + quantifier.nil? && !ignorecase + end + + def to_s(parent = false) + if !parent && ignorecase + "(?i-mx:#{value})#{quantifier}" + else + "#{value}#{quantifier}" + end + end + + def to_regexp(anchored = false) + re = to_s(true) + re = "\\A#{re}\\Z" if anchored + Regexp.compile(re, ignorecase) + end + + def match(char) + to_regexp(true).match(char) + end + + def include?(char) + if ignorecase + value.downcase == char.downcase + else + value == char + end + end + + def eql?(other) #:nodoc: + super && quantifier.eql?(other.quantifier) + end + + def freeze #:nodoc: + quantifier.freeze if quantifier + super + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/character_class.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/character_class.rb new file mode 100644 index 0000000000..caed5ef9d0 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/character_class.rb @@ -0,0 +1,55 @@ +module Regin + class CharacterClass < Character + def initialize(value, options = {}) + @negate = options[:negate] + super + end + + def option_names + %w( negate ) + super + end + + attr_reader :negate + + def negated? + negate ? true : false + end + + # Returns true if expression could be treated as a literal string. + # + # A CharacterClass is never literal. + def literal? + false + end + + def bracketed? + value != '.' && value !~ /^\\[dDsSwW]$/ + end + + def to_s(parent = false) + if bracketed? + if !parent && ignorecase + "(?i-mx:[#{negate && '^'}#{value}])#{quantifier}" + else + "[#{negate && '^'}#{value}]#{quantifier}" + end + else + super + end + end + + def include?(char) + re = quantifier ? to_s.sub(/#{Regexp.escape(quantifier)}$/, '') : to_s + Regexp.compile("\\A#{re}\\Z").match(char) + end + + def eql?(other) #:nodoc: + super && negate == other.negate + end + + def freeze #:nodoc: + negate.freeze if negate + super + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/collection.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/collection.rb new file mode 100644 index 0000000000..b60353268a --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/collection.rb @@ -0,0 +1,83 @@ +module Regin + class Collection + include Enumerable + + def initialize(*args) + @array = Array.new(*args) + end + + def each + @array.each{ |item| yield item } + end + + def [](i) + @array[i] + end + + def length + @array.length + end + alias_method :size, :length + + def first + @array.first + end + + def last + @array.last + end + + def +(other) + ary = other.is_a?(self.class) ? other.internal_array : other + self.class.new(@array + ary) + end + + def to_regexp(anchored = false) + re = to_s(true) + re = "\\A#{re}\\Z" if anchored + Regexp.compile(re, flags) + end + + def match(char) + to_regexp.match(char) + end + + def include?(char) + any? { |e| e.include?(char) } + end + + def ==(other) #:nodoc: + case other + when String + other == to_s + when Array + other == @array + else + eql?(other) + end + end + + def eql?(other) #:nodoc: + other.instance_of?(self.class) && @array.eql?(other.internal_array) + end + + def freeze #:nodoc: + each { |e| e.freeze } + @array.freeze + super + end + + protected + def internal_array #:nodoc: + @array + end + + def extract_options(args) + if args.last.is_a?(Hash) + return args[0..-2], args.last + else + return args, {} + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/expression.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/expression.rb new file mode 100644 index 0000000000..18e4965097 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/expression.rb @@ -0,0 +1,126 @@ +module Regin + class Expression < Collection + attr_reader :ignorecase, :multiline, :extended + + def initialize(*args) + args, options = extract_options(args) + + @multiline = @ignorecase = @extended = nil + + if args.length == 1 && args.first.instance_of?(Array) + super(args.first) + else + args = args.map { |e| e.instance_of?(String) ? Character.new(e) : e } + super(args) + end + + self.multiline = options[:multiline] if options.key?(:multiline) + self.ignorecase = options[:ignorecase] if options.key?(:ignorecase) + self.extended = options[:extended] if options.key?(:extended) + end + + # Returns true if expression could be treated as a literal string. + # + # A Expression is literal if all its elements are literal. + def literal? + !ignorecase && all? { |e| e.literal? } + end + + def anchored? + anchored_to_start? && anchored_to_end? + end + + def anchored_to_start? + first.is_a?(Anchor) && first == '\A' + end + + def anchored_to_end? + last.is_a?(Anchor) && last == '\Z' + end + + def anchored_to_line? + anchored_to_start_of_line? && anchored_to_end_of_line? + end + + def anchored_to_start_of_line? + anchored_to_start? || (first.is_a?(Anchor) && first == '^') + end + + def anchored_to_end_of_line? + anchored_to_end? || (last.is_a?(Anchor) && last == '$') + end + + def options? + options.any?(true) + end + + def flags + options.to_i + end + + def +(other) + ary = other.is_a?(self.class) ? other.internal_array : other + ary = @array + ary + [options.to_h(true)] + self.class.new(*ary) + end + + def dup(options = {}) + expression = super() + expression.multiline = options[:multiline] if options.key?(:multiline) + expression.ignorecase = options[:ignorecase] if options.key?(:ignorecase) + expression.extended = options[:extended] if options.key?(:extended) + expression + end + + def to_s(parent = false) + if parent || !options? + map { |e| e.to_s(parent) }.join + else + with, without = [], [] + multiline ? (with << 'm') : (without << 'm') + ignorecase ? (with << 'i') : (without << 'i') + extended ? (with << 'x') : (without << 'x') + + with = with.join + without = without.any? ? "-#{without.join}" : '' + + "(?#{with}#{without}:#{map { |e| e.to_s(true) }.join})" + end + end + + def inspect #:nodoc: + "#" + end + + def casefold? + ignorecase + end + + def eql?(other) #:nodoc: + super && + !!self.multiline == !!other.multiline && + !!self.ignorecase == !!other.ignorecase && + !!self.extended == !!other.extended + end + + protected + def options + Options.new(multiline, ignorecase, extended) + end + + def multiline=(multiline) + @multiline = multiline + end + + def ignorecase=(ignorecase) + if @ignorecase.nil? + @array.map! { |e| e.dup(:ignorecase => ignorecase) } + @ignorecase = ignorecase + end + end + + def extended=(extended) + @extended = extended + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/group.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/group.rb new file mode 100644 index 0000000000..d682148bd9 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/group.rb @@ -0,0 +1,90 @@ +module Regin + class Group + attr_reader :expression, :quantifier, :capture, :index, :name + + def initialize(expression, options = {}) + @quantifier = @index = @name = nil + @capture = true + @expression = expression.dup(options) + + @quantifier = options[:quantifier] if options.key?(:quantifier) + @capture = options[:capture] if options.key?(:capture) + @index = options[:index] if options.key?(:index) + @name = options[:name] if options.key?(:name) + end + + def option_names + %w( quantifier capture index name ) + end + + # Returns true if expression could be treated as a literal string. + # + # A Group is literal if its expression is literal and it has no quantifier. + def literal? + quantifier.nil? && expression.literal? + end + + def to_s(parent = false) + if !expression.options? + "(#{capture ? '' : '?:'}#{expression.to_s(parent)})#{quantifier}" + elsif capture == false + "#{expression.to_s}#{quantifier}" + else + "(#{expression.to_s})#{quantifier}" + end + end + + def to_regexp(anchored = false) + re = to_s + re = "\\A#{re}\\Z" if anchored + Regexp.compile(re) + end + + def dup(options = {}) + original_options = option_names.inject({}) do |h, m| + h[m.to_sym] = send(m) + h + end + self.class.new(expression, original_options.merge(options)) + end + + def inspect #:nodoc: + to_s.inspect + end + + def match(char) + to_regexp.match(char) + end + + def include?(char) + expression.include?(char) + end + + def capture? + capture + end + + def ==(other) #:nodoc: + case other + when String + other == to_s + else + eql?(other) + end + end + + def eql?(other) #:nodoc: + other.is_a?(self.class) && + self.expression == other.expression && + self.quantifier == other.quantifier && + self.capture == other.capture && + self.index == other.index && + self.name == other.name + end + + def freeze #:nodoc: + expression.freeze if expression + super + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/options.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/options.rb new file mode 100644 index 0000000000..03ba29d9a5 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/options.rb @@ -0,0 +1,55 @@ +module Regin + class Options + def self.from_int(flags) + multiline = flags & Regexp::MULTILINE != 0 + ignorecase = flags & Regexp::IGNORECASE != 0 + extended = flags & Regexp::EXTENDED != 0 + + new(multiline, ignorecase, extended) + end + + attr_reader :multiline, :ignorecase, :extended + + def initialize(*args) + if args.first.is_a?(Hash) + @multiline = args[0][:multiline] + @ignorecase = args[0][:ignorecase] + @extended = args[0][:extended] + else + @multiline = args[0] + @ignorecase = args[1] + @extended = args[2] + end + end + + def any?(explicit = false) + if explicit + !multiline.nil? || !ignorecase.nil? || !extended.nil? + else + multiline || ignorecase || extended + end + end + + def to_h(explicit = false) + if explicit + options = {} + options[:multiline] = multiline unless multiline.nil? + options[:ignorecase] = ignorecase unless ignorecase.nil? + options[:extended] = extended unless extended.nil? + options + else + { :multiline => multiline, + :ignorecase => ignorecase, + :extended => extended } + end + end + + def to_i + flag = 0 + flag |= Regexp::MULTILINE if multiline + flag |= Regexp::IGNORECASE if ignorecase + flag |= Regexp::EXTENDED if extended + flag + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/parser.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/parser.rb new file mode 100644 index 0000000000..0bb9b87e9c --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/parser.rb @@ -0,0 +1,415 @@ +# +# DO NOT MODIFY!!!! +# This file is automatically generated by Racc 1.4.6 +# from Racc grammer file "". +# + +require 'racc/parser.rb' +module Regin + class Parser < Racc::Parser #:nodoc: all + +def self.parse_regexp(regexp) + options = Options.from_int(regexp.options) + + parser = new + parser.options_stack << options.to_h + + expression = parser.scan_str(regexp.source) + expression = expression.dup(options.to_h) if options.any? + expression +end + +attr_accessor :options_stack + +def initialize + @capture_index = 0 + @capture_index_stack = [] + @options_stack = [] +end + +##### State transition tables begin ### + +racc_action_table = [ + 2, 18, 19, 19, 8, 10, 11, 13, 48, 19, + 2, 45, 3, 5, 8, 10, 11, 13, 64, 47, + 2, 55, 3, 5, 8, 10, 11, 13, 29, 19, + 2, 16, 3, 5, 8, 10, 11, 13, 61, 19, + 2, 63, 3, 5, 8, 10, 11, 13, 60, 36, + 2, 34, 3, 5, 8, 10, 11, 13, 28, 49, + 2, nil, 3, 5, 8, 10, 11, 13, nil, nil, + 2, nil, 3, 5, 8, 10, 11, 13, nil, 26, + 42, 43, 3, 5, 37, 38, 40, 21, 44, 37, + 38, 40, 22, 23, 24, 14, nil, 15, 31, 32, + 16, nil, 33, 46, 32, nil, nil, 33, 51, 37, + 38, 40, 58, 37, 38, 40, 37, 38, 40, 37, + 38, 40, 37, 38, 40, 37, 38, 40, 37, 38, + 40 ] + +racc_action_check = [ + 0, 4, 27, 4, 0, 0, 0, 0, 36, 56, + 49, 27, 0, 0, 49, 49, 49, 49, 56, 36, + 43, 48, 49, 49, 43, 43, 43, 43, 15, 53, + 6, 15, 43, 43, 6, 6, 6, 6, 53, 52, + 42, 55, 6, 6, 42, 42, 42, 42, 52, 24, + 35, 18, 42, 42, 35, 35, 35, 35, 14, 39, + 19, nil, 35, 35, 19, 19, 19, 19, nil, nil, + 13, nil, 19, 19, 13, 13, 13, 13, nil, 13, + 26, 26, 13, 13, 54, 54, 54, 9, 26, 26, + 26, 26, 9, 9, 9, 2, nil, 2, 17, 17, + 2, nil, 17, 30, 30, nil, nil, 30, 41, 41, + 41, 41, 50, 50, 50, 50, 44, 44, 44, 59, + 59, 59, 58, 58, 58, 51, 51, 51, 62, 62, + 62 ] + +racc_action_pointer = [ + -3, nil, 91, nil, 1, nil, 27, nil, nil, 75, + nil, nil, nil, 67, 53, 22, nil, 93, 51, 57, + nil, nil, nil, nil, 40, nil, 67, 0, nil, nil, + 98, nil, nil, nil, nil, 47, -1, nil, nil, 46, + nil, 87, 37, 17, 94, nil, nil, nil, 12, 7, + 91, 103, 37, 27, 62, 21, 7, nil, 100, 97, + nil, nil, 106, nil, nil, nil, nil, nil ] + +racc_action_default = [ + -37, -13, -37, -19, -37, -20, -2, -4, -11, -6, + -12, -14, -7, -37, -37, -29, -28, -37, -37, -37, + -3, -23, -21, -22, -37, -5, -37, -37, -8, -29, + -37, -9, -27, -26, 68, -1, -37, -34, -35, -37, + -36, -37, -37, -37, -37, -15, -10, -25, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -33, -37, -37, + -17, -18, -37, -24, -16, -32, -31, -30 ] + +racc_goto_table = [ + 4, 41, 20, 35, 17, 39, 25, nil, nil, nil, + nil, nil, nil, 27, nil, nil, 50, 30, nil, 54, + nil, nil, nil, nil, nil, 57, 59, nil, nil, 62, + nil, 20, nil, 65, 66, nil, nil, 67, nil, nil, + nil, nil, 52, 53, nil, nil, nil, nil, nil, 56 ] + +racc_goto_check = [ + 1, 10, 3, 2, 7, 9, 5, nil, nil, nil, + nil, nil, nil, 1, nil, nil, 10, 7, nil, 10, + nil, nil, nil, nil, nil, 10, 10, nil, nil, 10, + nil, 3, nil, 10, 10, nil, nil, 10, nil, nil, + nil, nil, 1, 1, nil, nil, nil, nil, nil, 1 ] + +racc_goto_pointer = [ + nil, 0, -16, -4, nil, -3, nil, 2, nil, -21, + -25 ] + +racc_goto_default = [ + nil, nil, 6, 7, 9, nil, 12, nil, 1, nil, + nil ] + +racc_reduce_table = [ + 0, 0, :racc_error, + 3, 26, :_reduce_1, + 1, 26, :_reduce_2, + 2, 27, :_reduce_3, + 1, 27, :_reduce_4, + 2, 28, :_reduce_5, + 1, 28, :_reduce_none, + 1, 29, :_reduce_none, + 3, 29, :_reduce_8, + 3, 29, :_reduce_9, + 4, 29, :_reduce_10, + 1, 29, :_reduce_11, + 1, 29, :_reduce_12, + 1, 29, :_reduce_13, + 1, 29, :_reduce_14, + 3, 31, :_reduce_15, + 6, 31, :_reduce_16, + 5, 31, :_reduce_17, + 5, 31, :_reduce_18, + 1, 33, :_reduce_none, + 1, 33, :_reduce_none, + 1, 30, :_reduce_none, + 1, 30, :_reduce_none, + 1, 30, :_reduce_none, + 5, 30, :_reduce_24, + 3, 30, :_reduce_25, + 2, 32, :_reduce_26, + 2, 32, :_reduce_27, + 1, 32, :_reduce_none, + 1, 32, :_reduce_none, + 4, 34, :_reduce_30, + 4, 34, :_reduce_31, + 4, 34, :_reduce_32, + 3, 34, :_reduce_33, + 1, 35, :_reduce_34, + 1, 35, :_reduce_35, + 1, 35, :_reduce_36 ] + +racc_reduce_n = 37 + +racc_shift_n = 68 + +racc_token_table = { + false => 0, + :error => 1, + :BAR => 2, + :LBRACK => 3, + :CTYPE => 4, + :RBRACK => 5, + :NEGATE => 6, + :CCLASS => 7, + :DOT => 8, + :CHAR => 9, + :LPAREN => 10, + :RPAREN => 11, + :QMARK => 12, + :COLON => 13, + :NAME => 14, + :L_ANCHOR => 15, + :R_ANCHOR => 16, + :STAR => 17, + :PLUS => 18, + :LCURLY => 19, + :RCURLY => 20, + :MINUS => 21, + :MULTILINE => 22, + :IGNORECASE => 23, + :EXTENDED => 24 } + +racc_nt_base = 25 + +racc_use_result_var = true + +Racc_arg = [ + racc_action_table, + racc_action_check, + racc_action_default, + racc_action_pointer, + racc_goto_table, + racc_goto_check, + racc_goto_default, + racc_goto_pointer, + racc_nt_base, + racc_reduce_table, + racc_token_table, + racc_shift_n, + racc_reduce_n, + racc_use_result_var ] + +Racc_token_to_s_table = [ + "$end", + "error", + "BAR", + "LBRACK", + "CTYPE", + "RBRACK", + "NEGATE", + "CCLASS", + "DOT", + "CHAR", + "LPAREN", + "RPAREN", + "QMARK", + "COLON", + "NAME", + "L_ANCHOR", + "R_ANCHOR", + "STAR", + "PLUS", + "LCURLY", + "RCURLY", + "MINUS", + "MULTILINE", + "IGNORECASE", + "EXTENDED", + "$start", + "expression", + "subexpression", + "quantified_atom", + "atom", + "quantifier", + "group", + "bracket_expression", + "anchor", + "options", + "modifier" ] + +Racc_debug_parser = false + +##### State transition tables end ##### + +# reduce 0 omitted + +def _reduce_1(val, _values, result) + # TODO remove this conditional by breaking + # it into another production + if val[0][0].is_a?(Regin::Alternation) + alt = val[0][0] + [Expression.new(val[2])] + else + alt = Alternation.new(val[0], Expression.new(val[2])) + end + result = Expression.new(alt) + + result +end + +def _reduce_2(val, _values, result) + result = Expression.new(val[0]) + result +end + +def _reduce_3(val, _values, result) + result = val[0] + [val[1]] + result +end + +def _reduce_4(val, _values, result) + result = [val[0]] + result +end + +def _reduce_5(val, _values, result) + result = val[0].dup(:quantifier => val[1]) + result +end + +# reduce 6 omitted + +# reduce 7 omitted + +def _reduce_8(val, _values, result) + result = CharacterClass.new(val[1]) + result +end + +def _reduce_9(val, _values, result) + result = CharacterClass.new(val[1]) + result +end + +def _reduce_10(val, _values, result) + result = CharacterClass.new(val[2], :negate => true) + result +end + +def _reduce_11(val, _values, result) + result = CharacterClass.new(val[0]) + result +end + +def _reduce_12(val, _values, result) + result = CharacterClass.new('.') + result +end + +def _reduce_13(val, _values, result) + result = Anchor.new(val[0]) + result +end + +def _reduce_14(val, _values, result) + result = Character.new(val[0]) + result +end + +def _reduce_15(val, _values, result) + result = Group.new(val[1], :index => @capture_index_stack.pop) + + result +end + +def _reduce_16(val, _values, result) + result = Group.new(val[4], val[2].merge(:capture => false)) + @options_stack.pop + + result +end + +def _reduce_17(val, _values, result) + result = Group.new(val[3], :capture => false); + + result +end + +def _reduce_18(val, _values, result) + result = Group.new(val[3], :name => val[2], :index => @capture_index_stack.pop); + + result +end + +# reduce 19 omitted + +# reduce 20 omitted + +# reduce 21 omitted + +# reduce 22 omitted + +# reduce 23 omitted + +def _reduce_24(val, _values, result) + result = val.join + result +end + +def _reduce_25(val, _values, result) + result = val.join + result +end + +def _reduce_26(val, _values, result) + result = val.join + result +end + +def _reduce_27(val, _values, result) + result = val.join + result +end + +# reduce 28 omitted + +# reduce 29 omitted + +def _reduce_30(val, _values, result) + @options_stack << result = { val[1] => false, val[2] => false, val[3] => false } + + result +end + +def _reduce_31(val, _values, result) + @options_stack << result = { val[0] => true, val[2] => false, val[3] => false } + + result +end + +def _reduce_32(val, _values, result) + @options_stack << result = { val[0] => true, val[1] => true, val[3] => false } + + result +end + +def _reduce_33(val, _values, result) + @options_stack << result = { val[0] => true, val[1] => true, val[2] => true } + + result +end + +def _reduce_34(val, _values, result) + result = :multiline + result +end + +def _reduce_35(val, _values, result) + result = :ignorecase + result +end + +def _reduce_36(val, _values, result) + result = :extended + result +end + +def _reduce_none(val, _values, result) + val[0] +end + + end # class Parser +end # module Regin + +require 'regin/tokenizer' diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/tokenizer.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/tokenizer.rb new file mode 100644 index 0000000000..59e4ffb611 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/tokenizer.rb @@ -0,0 +1,213 @@ +#-- +# DO NOT MODIFY!!!! +# This file is automatically generated by rex 1.0.5.beta1 +# from lexical definition file "lib/regin/tokenizer.rex". +#++ + +require 'racc/parser' +class Regin::Parser < Racc::Parser + require 'strscan' + + class ScanError < StandardError ; end + + attr_reader :lineno + attr_reader :filename + attr_accessor :state + + def scan_setup(str) + @ss = StringScanner.new(str) + @lineno = 1 + @state = nil + end + + def action + yield + end + + def scan_str(str) + scan_setup(str) + do_parse + end + alias :scan :scan_str + + def load_file( filename ) + @filename = filename + open(filename, "r") do |f| + scan_setup(f.read) + end + end + + def scan_file( filename ) + load_file(filename) + do_parse + end + + + def next_token + return if @ss.eos? + + text = @ss.peek(1) + @lineno += 1 if text == "\n" + token = case @state + when nil + case + when (text = @ss.scan(/\\[dDsSwW]/)) + action { [:CCLASS, text] } + + when (text = @ss.scan(/\^|\\A/)) + action { [:L_ANCHOR, text] } + + when (text = @ss.scan(/\$|\\Z/)) + action { [:R_ANCHOR, text] } + + when (text = @ss.scan(/<(\w+)>/)) + action { [:NAME, @ss[1]] } + + when (text = @ss.scan(/\(/)) + action { + @capture_index_stack << @capture_index + @capture_index += 1 + @state = :OPTIONS if @ss.peek(1) == '?'; + [:LPAREN, text] + } + + + when (text = @ss.scan(/\)/)) + action { [:RPAREN, text] } + + when (text = @ss.scan(/\[/)) + action { @state = :CCLASS; [:LBRACK, text] } + + when (text = @ss.scan(/\{/)) + action { [:LCURLY, text] } + + when (text = @ss.scan(/\}/)) + action { [:RCURLY, text] } + + when (text = @ss.scan(/\|/)) + action { [:BAR, text] } + + when (text = @ss.scan(/\./)) + action { [:DOT, text] } + + when (text = @ss.scan(/\?/)) + action { [:QMARK, text] } + + when (text = @ss.scan(/\+(?:\?)/)) + action { [:PLUS, text] } + + when (text = @ss.scan(/\*(?:\?)/)) + action { [:STAR, text] } + + when (text = @ss.scan(/\#/)) + action { + if @options_stack[-1][:extended] + @state = :COMMENT; + next_token + else + [:CHAR, text] + end + } + + + when (text = @ss.scan(/\s|\n/)) + action { + if @options_stack[-1][:extended] + next_token + else + [:CHAR, text] + end + } + + + when (text = @ss.scan(/\\(.)/)) + action { [:CHAR, @ss[1]] } + + when (text = @ss.scan(/./)) + action { [:CHAR, text] } + + else + text = @ss.string[@ss.pos .. -1] + raise ScanError, "can not match: '" + text + "'" + end # if + + when :CCLASS + case + when (text = @ss.scan(/\]/)) + action { @state = nil; [:RBRACK, text] } + + when (text = @ss.scan(/\^/)) + action { [:NEGATE, text] } + + when (text = @ss.scan(/:(alnum|alpha|ascii|blank|cntrl|digit|graph|lower|print|punct|space|upper|word|xdigit):/)) + action { [:CTYPE, text] } + + when (text = @ss.scan(/\\-/)) + action { [:CHAR, text] } + + when (text = @ss.scan(/\\(.)/)) + action { [:CHAR, @ss[1]] } + + when (text = @ss.scan(/./)) + action { [:CHAR, text] } + + else + text = @ss.string[@ss.pos .. -1] + raise ScanError, "can not match: '" + text + "'" + end # if + + when :OPTIONS + case + when (text = @ss.scan(/\?/)) + action { + @state = nil unless @ss.peek(1) =~ /-|m|i|x|:/ + [:QMARK, text] + } + + + when (text = @ss.scan(/\-/)) + action { [:MINUS, text] } + + when (text = @ss.scan(/m/)) + action { [:MULTILINE, text] } + + when (text = @ss.scan(/i/)) + action { [:IGNORECASE, text] } + + when (text = @ss.scan(/x/)) + action { [:EXTENDED, text] } + + when (text = @ss.scan(/\:/)) + action { + @capture_index_stack.pop + @capture_index -= 1 + @state = nil; + [:COLON, text] + } + + + else + text = @ss.string[@ss.pos .. -1] + raise ScanError, "can not match: '" + text + "'" + end # if + + when :COMMENT + case + when (text = @ss.scan(/\n/)) + action { @state = nil; next_token } + + when (text = @ss.scan(/./)) + action { next_token } + + else + text = @ss.string[@ss.pos .. -1] + raise ScanError, "can not match: '" + text + "'" + end # if + + else + raise ScanError, "undefined state: '" + state.to_s + "'" + end # case state + token + end # def next_token + +end # class diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/version.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/version.rb new file mode 100644 index 0000000000..7ad2a5a25e --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/vendor/regin/regin/version.rb @@ -0,0 +1,3 @@ +module Regin + Version = '0.3.3' +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/version.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/version.rb new file mode 100644 index 0000000000..a3688b102e --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/version.rb @@ -0,0 +1,5 @@ +module Rack + module Mount + Version = '0.6.6.pre' + end +end From f61d923d284062b4e4864d81c603157020198d06 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 27 Jun 2010 16:42:27 -0700 Subject: [PATCH 08/71] Update to latest rails.js [#4411 state:resolved] --- .../app/templates/public/javascripts/rails.js | 173 ++++++++++++------ 1 file changed, 115 insertions(+), 58 deletions(-) diff --git a/railties/lib/rails/generators/rails/app/templates/public/javascripts/rails.js b/railties/lib/rails/generators/rails/app/templates/public/javascripts/rails.js index c5fa02ae35..4283ed8982 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/javascripts/rails.js +++ b/railties/lib/rails/generators/rails/app/templates/public/javascripts/rails.js @@ -1,87 +1,148 @@ -document.observe("dom:loaded", function() { +(function() { + // Technique from Juriy Zaytsev + // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ + function isEventSupported(eventName) { + var el = document.createElement('div'); + eventName = 'on' + eventName; + var isSupported = (eventName in el); + if (!isSupported) { + el.setAttribute(eventName, 'return;'); + isSupported = typeof el[eventName] == 'function'; + } + el = null; + return isSupported; + } + + function isForm(element) { + return Object.isElement(element) && element.nodeName.toUpperCase() == 'FORM' + } + + function isInput(element) { + if (Object.isElement(element)) { + var name = element.nodeName.toUpperCase() + return name == 'INPUT' || name == 'SELECT' || name == 'TEXTAREA' + } + else return false + } + + var submitBubbles = isEventSupported('submit'), + changeBubbles = isEventSupported('change') + + if (!submitBubbles || !changeBubbles) { + // augment the Event.Handler class to observe custom events when needed + Event.Handler.prototype.initialize = Event.Handler.prototype.initialize.wrap( + function(init, element, eventName, selector, callback) { + init(element, eventName, selector, callback) + // is the handler being attached to an element that doesn't support this event? + if ( (!submitBubbles && this.eventName == 'submit' && !isForm(this.element)) || + (!changeBubbles && this.eventName == 'change' && !isInput(this.element)) ) { + // "submit" => "emulated:submit" + this.eventName = 'emulated:' + this.eventName + } + } + ) + } + + if (!submitBubbles) { + // discover forms on the page by observing focus events which always bubble + document.on('focusin', 'form', function(focusEvent, form) { + // special handler for the real "submit" event (one-time operation) + if (!form.retrieve('emulated:submit')) { + form.on('submit', function(submitEvent) { + var emulated = form.fire('emulated:submit', submitEvent, true) + // if custom event received preventDefault, cancel the real one too + if (emulated.returnValue === false) submitEvent.preventDefault() + }) + form.store('emulated:submit', true) + } + }) + } + + if (!changeBubbles) { + // discover form inputs on the page + document.on('focusin', 'input, select, texarea', function(focusEvent, input) { + // special handler for real "change" events + if (!input.retrieve('emulated:change')) { + input.on('change', function(changeEvent) { + input.fire('emulated:change', changeEvent, true) + }) + input.store('emulated:change', true) + } + }) + } + function handleRemote(element) { var method, url, params; + var event = element.fire("ajax:before"); + if (event.stopped) return false; + if (element.tagName.toLowerCase() === 'form') { method = element.readAttribute('method') || 'post'; url = element.readAttribute('action'); - params = element.serialize(true); + params = element.serialize(); } else { method = element.readAttribute('data-method') || 'get'; url = element.readAttribute('href'); params = {}; } - var event = element.fire("ajax:before"); - if (event.stopped) return false; - new Ajax.Request(url, { method: method, parameters: params, - asynchronous: true, evalScripts: true, - onLoading: function(request) { element.fire("ajax:loading", {request: request}); }, - onLoaded: function(request) { element.fire("ajax:loaded", {request: request}); }, - onInteractive: function(request) { element.fire("ajax:interactive", {request: request}); }, - onComplete: function(request) { element.fire("ajax:complete", {request: request}); }, - onSuccess: function(request) { element.fire("ajax:success", {request: request}); }, - onFailure: function(request) { element.fire("ajax:failure", {request: request}); } + onComplete: function(request) { element.fire("ajax:complete", request); }, + onSuccess: function(request) { element.fire("ajax:success", request); }, + onFailure: function(request) { element.fire("ajax:failure", request); } }); element.fire("ajax:after"); } function handleMethod(element) { - var method, url, token_name, token; - - method = element.readAttribute('data-method'); - url = element.readAttribute('href'); - csrf_param = $$('meta[name=csrf-param]').first(); - csrf_token = $$('meta[name=csrf-token]').first(); + var method = element.readAttribute('data-method'), + url = element.readAttribute('href'), + csrf_param = $$('meta[name=csrf-param]')[0], + csrf_token = $$('meta[name=csrf-token]')[0]; var form = new Element('form', { method: "POST", action: url, style: "display: none;" }); - element.parentNode.appendChild(form); + element.parentNode.insert(form); - if (method != 'post') { + if (method !== 'post') { var field = new Element('input', { type: 'hidden', name: '_method', value: method }); - form.appendChild(field); + form.insert(field); } if (csrf_param) { - var param = csrf_param.readAttribute('content'); - var token = csrf_token.readAttribute('content'); - var field = new Element('input', { type: 'hidden', name: param, value: token }); - form.appendChild(field); + var param = csrf_param.readAttribute('content'), + token = csrf_token.readAttribute('content'), + field = new Element('input', { type: 'hidden', name: param, value: token }); + form.insert(field); } form.submit(); } - $(document.body).observe("click", function(event) { - var message = event.findElement().readAttribute('data-confirm'); - if (message && !confirm(message)) { - event.stop(); - return false; - } - var element = event.findElement("a[data-remote]"); - if (element) { - handleRemote(element); - event.stop(); - return true; - } - - var element = event.findElement("a[data-method]"); - if (element) { - handleMethod(element); - event.stop(); - return true; - } + document.on("click", "*[data-confirm]", function(event, element) { + var message = element.readAttribute('data-confirm'); + if (!confirm(message)) event.stop(); }); - // TODO: I don't think submit bubbles in IE - $(document.body).observe("submit", function(event) { + document.on("click", "a[data-remote]", function(event, element) { + if (event.stopped) return; + handleRemote(element); + event.stop(); + }); + + document.on("click", "a[data-method]", function(event, element) { + if (event.stopped) return; + handleMethod(element); + event.stop(); + }); + + document.on("submit", function(event) { var element = event.findElement(), message = element.readAttribute('data-confirm'); if (message && !confirm(message)) { @@ -103,16 +164,12 @@ document.observe("dom:loaded", function() { } }); - $(document.body).observe("ajax:after", function(event) { - var element = event.findElement(); - - if (element.tagName.toLowerCase() === 'form') { - var inputs = element.select("input[type=submit][disabled=true][data-disable-with]"); - inputs.each(function(input) { - input.value = input.readAttribute('data-original-value'); - input.writeAttribute('data-original-value', null); - input.disabled = false; - }); - } + document.on("ajax:after", "form", function(event, element) { + var inputs = element.select("input[type=submit][disabled=true][data-disable-with]"); + inputs.each(function(input) { + input.value = input.readAttribute('data-original-value'); + input.removeAttribute('data-original-value'); + input.disabled = false; + }); }); -}); \ No newline at end of file +})(); From 6cc29ab65f7efc460aee1e374f100f03f32713a9 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 27 Jun 2010 20:30:51 -0300 Subject: [PATCH 09/71] Implemented getbyte as an aliased method and RDoc added Signed-off-by: Xavier Noria --- .../lib/active_support/core_ext/string/conversions.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/string/conversions.rb b/activesupport/lib/active_support/core_ext/string/conversions.rb index 857ecfaa54..5b2cb6e331 100644 --- a/activesupport/lib/active_support/core_ext/string/conversions.rb +++ b/activesupport/lib/active_support/core_ext/string/conversions.rb @@ -28,9 +28,8 @@ class String self[0] end unless method_defined?(:ord) - def getbyte(index) - self[index] - end unless method_defined?(:getbyte) + # +getbyte+ backport from Ruby 1.9 + alias_method :getbyte, :[] unless method_defined?(:getbyte) # Form can be either :utc (default) or :local. def to_time(form = :utc) From f3bb185b03e746b52a4035a6df002597d8552e74 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 27 Jun 2010 17:53:52 -0700 Subject: [PATCH 10/71] Upgrade to Rack 1.2.1 --- actionpack/actionpack.gemspec | 2 +- .../request/multipart_params_parsing_test.rb | 20 ++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index 54e8ad9acb..b4311599a9 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -23,7 +23,7 @@ Gem::Specification.new do |s| s.add_dependency('activemodel', version) s.add_dependency('builder', '~> 2.1.2') s.add_dependency('i18n', '~> 0.4.1') - s.add_dependency('rack', '~> 1.1.0') + s.add_dependency('rack', '~> 1.2.1') s.add_dependency('rack-test', '~> 0.5.4') #s.add_dependency('rack-mount', '~> 0.6.6') s.add_dependency('tzinfo', '~> 0.3.16') diff --git a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb index 40c5ac2d09..e3ec5cf182 100644 --- a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb @@ -89,15 +89,21 @@ class MultipartParamsParsingTest < ActionController::IntegrationTest assert_equal 19512, file.size end + # Pending fix in Rack 1.2.2 + # http://rack.lighthouseapp.com/projects/22435-rack/tickets/79-multipart-handling-incorrectly-assuming-file-upload test "parses mixed files" do - params = parse_multipart('mixed_files') - assert_equal %w(files foo), params.keys.sort - assert_equal 'bar', params['foo'] + if Rack.release <= '1.2.1' + $stderr.puts 'multipart/mixed parsing pending fix in Rack 1.2.2' + else + params = parse_multipart('mixed_files') + assert_equal %w(files foo), params.keys.sort + assert_equal 'bar', params['foo'] - # Rack doesn't handle multipart/mixed for us. - files = params['files'] - files.force_encoding('ASCII-8BIT') if files.respond_to?(:force_encoding) - assert_equal 19756, files.size + # Rack doesn't handle multipart/mixed for us. + files = params['files'] + files.force_encoding('ASCII-8BIT') if files.respond_to?(:force_encoding) + assert_equal 19756, files.size + end end test "does not create tempfile if no file has been selected" do From fb7715b2491380becbaa111a4c5a211bac662e97 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 27 Jun 2010 18:33:34 -0700 Subject: [PATCH 11/71] Warn that ActiveRecord::Base.reset_subclasses is gone in Rails 3 final. --- activerecord/lib/active_record/base.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index e7b52287a5..a4a5faad77 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -278,6 +278,18 @@ module ActiveRecord #:nodoc: # on to any new database connections made and which can be retrieved on both a class and instance level by calling +logger+. cattr_accessor :logger, :instance_writer => false + class << self + def reset_subclasses #:nodoc: + ActiveSupport::Deprecation.warn 'ActiveRecord::Base.reset_subclasses no longer does anything in Rails 3. It will be removed in the final release; please update your apps and plugins.', caller + end + + def subclasses + descendants + end + + deprecate :subclasses => :descendants + end + ## # :singleton-method: # Contains the database configuration - as is typically stored in config/database.yml - From 8e3e117dbe58fd4fedbb78a3d8e398ab0e415634 Mon Sep 17 00:00:00 2001 From: Kevin Skoglund Date: Wed, 23 Jun 2010 12:45:23 -0400 Subject: [PATCH 12/71] rake db:migrate:status displays status of migrations [#4947 state:resolved] Signed-off-by: Michael Koziarski --- .../lib/active_record/railties/databases.rake | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 006e64b115..80218d6ff9 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -171,6 +171,31 @@ namespace :db do ActiveRecord::Migrator.run(:down, "db/migrate/", version) Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby end + + desc "Display status of migrations" + task :status => :environment do + config = ActiveRecord::Base.configurations[Rails.env || 'development'] + db_list = ActiveRecord::Base.connection.select_values("SELECT version FROM schema_migrations") + file_list = [] + Dir.foreach(File.join(Rails.root, 'db', 'migrate')) do |file| + # only files matching "20091231235959_some_name.rb" pattern + if match_data = /(\d{14})_(.+)\.rb/.match(file) + status = db_list.delete(match_data[1]) ? 'up' : 'down' + file_list << [status, match_data[1], match_data[2]] + end + end + # output + puts "\ndatabase: #{config['database']}\n\n" + puts "#{"Status".center(8)} #{"Migration ID".ljust(14)} Migration Name" + puts "-" * 50 + file_list.each do |file| + puts "#{file[0].center(8)} #{file[1].ljust(14)} #{file[2].humanize}" + end + db_list.each do |version| + puts "#{'up'.center(8)} #{version.ljust(14)} *** NO FILE ***" + end + puts + end end desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n).' From 06b0d6e5cdcfab8d49bcf559008f1753f3e7853c Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 28 Jun 2010 00:30:36 -0300 Subject: [PATCH 13/71] Add missing require, Base use deprecate method --- activerecord/lib/active_record/base.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index a4a5faad77..fa239bafc6 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -15,6 +15,7 @@ require 'active_support/core_ext/hash/slice' require 'active_support/core_ext/string/behavior' require 'active_support/core_ext/kernel/singleton_class' require 'active_support/core_ext/module/delegation' +require 'active_support/core_ext/module/deprecation' require 'active_support/core_ext/module/introspection' require 'active_support/core_ext/object/duplicable' require 'active_support/core_ext/object/blank' From 25215d7285db10e2c04d903f251b791342e4dd6a Mon Sep 17 00:00:00 2001 From: wycats Date: Sun, 27 Jun 2010 21:12:10 -0700 Subject: [PATCH 14/71] Fix several known web encoding issues: * Specify accept-charset on all forms. All recent browsers, as well as IE5+, will use the encoding specified for form parameters * Unfortunately, IE5+ will not look at accept-charset unless at least one character in the form's values is not in the page's charset. Since the user can override the default charset (which Rails sets to UTF-8), we provide a hidden input containing a unicode character, forcing IE to look at the accept-charset. * Now that the vast majority of web input is UTF-8, we set the inbound parameters to UTF-8. This will eliminate many cases of incompatible encodings between ASCII-8BIT and UTF-8. * You can safely ignore params[:_snowman_] TODO: * Validate inbound text to confirm it is UTF-8 * Combine the whole_form implementations in form_helper_test and form_tag_helper_test --- .../lib/action_dispatch/http/parameters.rb | 31 +- .../action_view/helpers/form_tag_helper.rb | 15 +- .../url_encoded_params_parsing_test.rb | 23 ++ actionpack/test/template/erb/form_for_test.rb | 2 +- .../test/template/erb/tag_helper_test.rb | 4 +- actionpack/test/template/form_helper_test.rb | 385 ++++++++++-------- .../test/template/form_tag_helper_test.rb | 56 ++- 7 files changed, 318 insertions(+), 198 deletions(-) diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb index 0a37bd7fc1..add8cab2ab 100644 --- a/actionpack/lib/action_dispatch/http/parameters.rb +++ b/actionpack/lib/action_dispatch/http/parameters.rb @@ -6,7 +6,11 @@ module ActionDispatch module Parameters # Returns both GET and POST \parameters in a single hash. def parameters - @env["action_dispatch.request.parameters"] ||= request_parameters.merge(query_parameters).update(path_parameters).with_indifferent_access + @env["action_dispatch.request.parameters"] ||= begin + params = request_parameters.merge(query_parameters) + params.merge!(path_parameters) + encode_params(params).with_indifferent_access + end end alias :params :parameters @@ -32,6 +36,31 @@ module ActionDispatch end private + + # TODO: Validate that the characters are UTF-8. If they aren't, + # you'll get a weird error down the road, but our form handling + # should really prevent that from happening + def encode_params(params) + return params unless "ruby".encoding_aware? + + if params.is_a?(String) + return params.force_encoding("UTF-8").encode! + elsif !params.is_a?(Hash) + return params + end + + params.each do |k, v| + case v + when Hash + encode_params(v) + when Array + v.map! {|el| encode_params(el) } + else + encode_params(v) + end + end + end + # Convert nested Hash to HashWithIndifferentAccess def normalize_parameters(value) case value diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index ea491b2db8..0e9cb2349f 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -530,22 +530,31 @@ module ActionView returning options.stringify_keys do |html_options| html_options["enctype"] = "multipart/form-data" if html_options.delete("multipart") html_options["action"] = url_for(url_for_options, *parameters_for_url) + html_options["accept-encoding"] = "UTF-8" html_options["data-remote"] = true if html_options.delete("remote") end end def extra_tags_for_form(html_options) - case method = html_options.delete("method").to_s + snowman_tag = tag(:input, :type => "hidden", + :name => "_snowman_", :value => "☃") + + method = html_options.delete("method").to_s + + method_tag = case method when /^get$/i # must be case-insensitive, but can't use downcase as might be nil html_options["method"] = "get" '' when /^post$/i, "", nil html_options["method"] = "post" - protect_against_forgery? ? content_tag(:div, token_tag, :style => 'margin:0;padding:0;display:inline') : '' + token_tag else html_options["method"] = "post" - content_tag(:div, tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag, :style => 'margin:0;padding:0;display:inline') + tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag end + + tags = snowman_tag << method_tag + content_tag(:div, tags, :style => 'margin:0;padding:0;display:inline') end def form_tag_html(html_options) diff --git a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb index 69dbd7f528..0bcef81534 100644 --- a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb @@ -141,6 +141,29 @@ class UrlEncodedParamsParsingTest < ActionController::IntegrationTest post "/parse", actual assert_response :ok assert_equal(expected, TestController.last_request_parameters) + assert_utf8(TestController.last_request_parameters) + end + end + + def assert_utf8(object) + return unless "ruby".encoding_aware? + + correct_encoding = Encoding.default_internal + + unless object.is_a?(Hash) + assert_equal correct_encoding, object.encoding, "#{object.inspect} should have been UTF-8" + return + end + + object.each do |k,v| + case v + when Hash + assert_utf8(v) + when Array + v.each {|el| assert_utf8(el) } + else + assert_utf8(v) + end end end end diff --git a/actionpack/test/template/erb/form_for_test.rb b/actionpack/test/template/erb/form_for_test.rb index ec6e872735..e722b40a9a 100644 --- a/actionpack/test/template/erb/form_for_test.rb +++ b/actionpack/test/template/erb/form_for_test.rb @@ -5,7 +5,7 @@ module ERBTest class TagHelperTest < BlockTestCase test "form_for works" do output = render_content "form_for(:staticpage, :url => {:controller => 'blah', :action => 'update'})", "" - assert_equal "
", output + assert_match %r{.*}, output end end end diff --git a/actionpack/test/template/erb/tag_helper_test.rb b/actionpack/test/template/erb/tag_helper_test.rb index 64a88bde1d..d073100986 100644 --- a/actionpack/test/template/erb/tag_helper_test.rb +++ b/actionpack/test/template/erb/tag_helper_test.rb @@ -28,8 +28,8 @@ module ERBTest end test "percent equals works with form tags" do - expected_output = "
hello
" - maybe_deprecated { assert_equal expected_output, render_content("form_tag('foo')", "<%= 'hello' %>") } + expected_output = %r{.*hello*} + maybe_deprecated { assert_match expected_output, render_content("form_tag('foo')", "<%= 'hello' %>") } end test "percent equals works with fieldset tags" do diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 6ba407e230..eb6cf92805 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -583,7 +583,8 @@ class FormHelperTest < ActionView::TestCase end expected = - "
" + + "" + + snowman + "" + "" + "" + @@ -604,15 +605,14 @@ class FormHelperTest < ActionView::TestCase concat f.submit('Create post') end - expected = - "" + - "
" + + expected = whole_form("/posts/123", "create-post", "other_name_edit", :method => "put") do "" + "" + "" + "" + "" + - "
" + "" + end assert_dom_equal expected, output_buffer end @@ -626,14 +626,12 @@ class FormHelperTest < ActionView::TestCase end end - expected = - "
" + - "
" + + expected = whole_form("http://www.example.com", "create-post", nil, "put") do "" + "" + "" + - "" + - "
" + "" + end assert_dom_equal expected, output_buffer end @@ -647,14 +645,12 @@ class FormHelperTest < ActionView::TestCase end end - expected = - "
" + - "
" + + expected = whole_form("http://www.example.com", "create-post", nil, :method => "put", :remote => true) do "" + "" + "" + - "" + - "
" + "" + end assert_dom_equal expected, output_buffer end @@ -668,13 +664,12 @@ class FormHelperTest < ActionView::TestCase end end - expected = - "
" + + expected = whole_form("http://www.example.com", nil, nil, :remote => true) do "" + "" + "" + - "" + - "
" + "" + end assert_dom_equal expected, output_buffer end @@ -686,13 +681,12 @@ class FormHelperTest < ActionView::TestCase concat f.check_box(:secret) end - expected = - "
" + + expected = whole_form("http://www.example.com", "create-post") do "" + "" + "" + - "" + - "
" + "" + end assert_dom_equal expected, output_buffer end @@ -707,14 +701,13 @@ class FormHelperTest < ActionView::TestCase end end - expected = - "
" + + expected = whole_form do "" + "" + "" + "" + - "" + - "
" + "" + end assert_dom_equal expected, output_buffer end @@ -728,13 +721,12 @@ class FormHelperTest < ActionView::TestCase end end - expected = - "
" + + expected = whole_form do "" + "" + "" + - "" + - "
" + "" + end assert_dom_equal expected, output_buffer end @@ -749,9 +741,10 @@ class FormHelperTest < ActionView::TestCase end end - expected = "
" + - "" + - "
" + expected = whole_form do + "" + end + assert_dom_equal expected, output_buffer ensure I18n.locale = old_locale @@ -766,9 +759,10 @@ class FormHelperTest < ActionView::TestCase end end - expected = "
" + - "" + - "
" + expected = whole_form do + "" + end + assert_dom_equal expected, output_buffer ensure I18n.locale = old_locale @@ -781,9 +775,10 @@ class FormHelperTest < ActionView::TestCase concat f.submit :class => "extra" end - expected = "
" + - "" + - "
" + expected = whole_form do + "" + end + assert_dom_equal expected, output_buffer ensure I18n.locale = old_locale @@ -798,9 +793,10 @@ class FormHelperTest < ActionView::TestCase end end - expected = "
" + - "" + - "
" + expected = whole_form do + "" + end + assert_dom_equal expected, output_buffer ensure I18n.locale = old_locale @@ -815,9 +811,9 @@ class FormHelperTest < ActionView::TestCase end end - expected = "
" + - "" + - "
" + expected = whole_form do + "" + end assert_dom_equal expected, output_buffer end @@ -832,10 +828,10 @@ class FormHelperTest < ActionView::TestCase end end - expected = "
" + - "" + - "" + - "
" + expected = whole_form do + "" + + "" + end assert_dom_equal expected, output_buffer end @@ -850,10 +846,10 @@ class FormHelperTest < ActionView::TestCase end end - expected = "
" + - "" + - "" + - "
" + expected = whole_form do + "" + + "" + end assert_dom_equal expected, output_buffer end @@ -867,9 +863,9 @@ class FormHelperTest < ActionView::TestCase end end - expected = "
" + - "" + - "
" + expected = whole_form do + "" + end assert_dom_equal expected, output_buffer end @@ -883,9 +879,9 @@ class FormHelperTest < ActionView::TestCase end end - expected = "
" + - "" + - "
" + expected = whole_form do + "" + end assert_dom_equal expected, output_buffer end @@ -899,9 +895,9 @@ class FormHelperTest < ActionView::TestCase end end - expected = "
" + - "" + - "
" + expected = whole_form do + "" + end assert_dom_equal expected, output_buffer end @@ -915,9 +911,9 @@ class FormHelperTest < ActionView::TestCase end end - expected = "
" + - "" + - "
" + expected = whole_form do + "" + end assert_dom_equal expected, output_buffer end @@ -931,9 +927,9 @@ class FormHelperTest < ActionView::TestCase end end - expected = "
" + - "" + - "
" + expected = whole_form do + "" + end assert_dom_equal expected, output_buffer end @@ -952,12 +948,11 @@ class FormHelperTest < ActionView::TestCase } end - expected = "
" + - "" + - "
" + - "
" + - "" + - "
" + expected = whole_form do + "" + end + whole_form do + "" + end assert_dom_equal expected, output_buffer end @@ -975,10 +970,10 @@ class FormHelperTest < ActionView::TestCase end end - expected = '
' + - '' + - '' + - '
' + expected = whole_form do + '' + + '' + end assert_dom_equal expected, output_buffer end @@ -1006,11 +1001,11 @@ class FormHelperTest < ActionView::TestCase end end - expected = '
' + - '' + - '' + - '' + - '
' + expected = whole_form do + '' + + '' + + '' + end assert_dom_equal expected, output_buffer end @@ -1028,11 +1023,11 @@ class FormHelperTest < ActionView::TestCase end end - expected = '
' + - '' + - '' + - '' + - '
' + expected = whole_form do + '' + + '' + + '' + end assert_dom_equal expected, output_buffer end @@ -1051,13 +1046,13 @@ class FormHelperTest < ActionView::TestCase end end - expected = '
' + - '' + - '' + - '' + - '' + - '' + - '
' + expected = whole_form do + '' + + '' + + '' + + '' + + '' + end assert_dom_equal expected, output_buffer end @@ -1077,13 +1072,13 @@ class FormHelperTest < ActionView::TestCase end end - expected = '
' + - '' + - '' + - '' + - '' + - '' + - '
' + expected = whole_form do + '' + + '' + + '' + + '' + + '' + end assert_dom_equal expected, output_buffer end @@ -1102,11 +1097,11 @@ class FormHelperTest < ActionView::TestCase end end - expected = '
' + - '' + - '' + - '' + - '
' + expected = whole_form do + '' + + '' + + '' + end assert_dom_equal expected, output_buffer end @@ -1125,12 +1120,12 @@ class FormHelperTest < ActionView::TestCase end end - expected = '
' + - '' + - '' + - '' + - '' + - '
' + expected = whole_form do + '' + + '' + + '' + + '' + end assert_dom_equal expected, output_buffer end @@ -1145,9 +1140,9 @@ class FormHelperTest < ActionView::TestCase end end - expected = '
' + - '' + - '
' + expected = whole_form do + '' + end assert_dom_equal expected, output_buffer end @@ -1164,13 +1159,13 @@ class FormHelperTest < ActionView::TestCase end end - expected = '
' + - '' + - '' + - '' + - '' + - '' + - '
' + expected = whole_form do + '' + + '' + + '' + + '' + + '' + end assert_dom_equal expected, output_buffer end @@ -1188,13 +1183,13 @@ class FormHelperTest < ActionView::TestCase end end - expected = '
' + - '' + - '' + - '' + - '' + - '' + - '
' + expected = whole_form do + '' + + '' + + '' + + '' + + '' + end assert_dom_equal expected, output_buffer end @@ -1213,12 +1208,12 @@ class FormHelperTest < ActionView::TestCase end end - expected = '
' + - '' + - '' + - '' + - '' + - '
' + expected = whole_form do + '' + + '' + + '' + + '' + end assert_dom_equal expected, output_buffer assert_equal yielded_comments, @post.comments @@ -1235,10 +1230,10 @@ class FormHelperTest < ActionView::TestCase end end - expected = '
' + - '' + - '' + - '
' + expected = whole_form do + '' + + '' + end assert_dom_equal expected, output_buffer end @@ -1273,20 +1268,20 @@ class FormHelperTest < ActionView::TestCase end end - expected = '
' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '
' + expected = whole_form do + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + end assert_dom_equal expected, output_buffer end @@ -1426,7 +1421,8 @@ class FormHelperTest < ActionView::TestCase end expected = - "
" + + "" + + snowman + "" + "" + "" + @@ -1449,11 +1445,11 @@ class FormHelperTest < ActionView::TestCase end expected = - "" + - "" + - "" + - "" + - "
" + whole_form("http://www.example.com", "create-post") do + "" + + "" + + "" + end assert_dom_equal expected, output_buffer end @@ -1477,16 +1473,42 @@ class FormHelperTest < ActionView::TestCase end end - expected = - "
" + - "
" + - "
" + - "
" + - "
" + expected = whole_form do + "
" + + "
" + + "
" + end assert_dom_equal expected, output_buffer end + def snowman(method = nil) + txt = %{
} + txt << %{} + txt << %{} if method + txt << %{
} + end + + def form_text(action = "http://www.example.com", id = nil, html_class = nil, remote = nil) + txt = %{
} + end + + def whole_form(action = "http://www.example.com", id = nil, html_class = nil, options = nil) + contents = block_given? ? yield : "" + + if options.is_a?(Hash) + method, remote = options.values_at(:method, :remote) + else + method = options + end + + form_text(action, id, html_class, remote) + snowman(method) + contents + "
" + end + def test_default_form_builder old_default_form_builder, ActionView::Base.default_form_builder = ActionView::Base.default_form_builder, LabelledFormBuilder @@ -1499,12 +1521,11 @@ class FormHelperTest < ActionView::TestCase end end - expected = - "
" + + expected = whole_form do "
" + "
" + - "
" + - "
" + "
" + end assert_dom_equal expected, output_buffer ensure @@ -1577,7 +1598,7 @@ class FormHelperTest < ActionView::TestCase assert_deprecated do form_for(:post, @post, :html => {:id => 'some_form', :class => 'some_class'}) do |f| end end - expected = "
" + expected = whole_form("http://www.example.com", "some_form", "some_class") assert_dom_equal expected, output_buffer end @@ -1587,7 +1608,8 @@ class FormHelperTest < ActionView::TestCase form_for(:post, @post, :url => 'http://www.otherdomain.com') do |f| end end - assert_equal '
', output_buffer + assert_equal whole_form("http://www.otherdomain.com"), output_buffer + # assert_equal '
', output_buffer end def test_form_for_with_hash_url_option @@ -1604,14 +1626,15 @@ class FormHelperTest < ActionView::TestCase form_for(:post, @post, :url => @post) do |f| end end - expected = "
" + expected = whole_form("/posts/123") + # expected = "
" assert_equal expected, output_buffer end def test_form_for_with_existing_object form_for(@post) do |f| end - expected = "
" + expected = whole_form("/posts/123", "edit_post_123", "edit_post", "put") assert_equal expected, output_buffer end @@ -1622,7 +1645,7 @@ class FormHelperTest < ActionView::TestCase form_for(post) do |f| end - expected = "
" + expected = whole_form("/posts", "new_post", "new_post") assert_equal expected, output_buffer end @@ -1630,14 +1653,14 @@ class FormHelperTest < ActionView::TestCase @comment.save form_for([@post, @comment]) {} - expected = %(
) + expected = whole_form(comment_path(@post, @comment), "edit_comment_1", "edit_comment", "put") assert_dom_equal expected, output_buffer end def test_form_for_with_new_object_in_list form_for([@post, @comment]) {} - expected = %(
) + expected = whole_form(comments_path(@post), "new_comment", "new_comment") assert_dom_equal expected, output_buffer end @@ -1645,21 +1668,21 @@ class FormHelperTest < ActionView::TestCase @comment.save form_for([:admin, @post, @comment]) {} - expected = %(
) + expected = whole_form(admin_comment_path(@post, @comment), "edit_comment_1", "edit_comment", "put") assert_dom_equal expected, output_buffer end def test_form_for_with_new_object_and_namespace_in_list form_for([:admin, @post, @comment]) {} - expected = %(
) + expected = whole_form(admin_comments_path(@post), "new_comment", "new_comment") assert_dom_equal expected, output_buffer end def test_form_for_with_existing_object_and_custom_url form_for(@post, :url => "/super_posts") do |f| end - expected = "
" + expected = whole_form("/super_posts", "edit_post_123", "edit_post", "put") assert_equal expected, output_buffer end diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index b75863bb6a..75d2773c0a 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -8,6 +8,36 @@ class FormTagHelperTest < ActionView::TestCase @controller = BasicController.new end + def snowman(options = {}) + method = options[:method] + + txt = %{
} + txt << %{} + txt << %{} if method + txt << %{
} + end + + def form_text(action = "http://www.example.com", options = {}) + remote, enctype, html_class, id = options.values_at(:remote, :enctype, :html_class, :id) + + txt = %{
} + end + + def whole_form(action = "http://www.example.com", options = {}) + out = form_text(action, options) + snowman(options) + + if block_given? + out << yield << "
" + end + + out + end + def url_for(options) if options.is_a?(Hash) "http://www.example.com" @@ -31,51 +61,57 @@ class FormTagHelperTest < ActionView::TestCase def test_form_tag actual = form_tag - expected = %(
) + expected = whole_form assert_dom_equal expected, actual end def test_form_tag_multipart actual = form_tag({}, { 'multipart' => true }) - expected = %() + expected = whole_form("http://www.example.com", :enctype => true) assert_dom_equal expected, actual end def test_form_tag_with_method_put actual = form_tag({}, { :method => :put }) - expected = %(
) + expected = whole_form("http://www.example.com", :method => :put) assert_dom_equal expected, actual end def test_form_tag_with_method_delete actual = form_tag({}, { :method => :delete }) - expected = %(
) + + expected = whole_form("http://www.example.com", :method => :delete) assert_dom_equal expected, actual end def test_form_tag_with_remote actual = form_tag({}, :remote => true) - expected = %() + + expected = whole_form("http://www.example.com", :remote => true) assert_dom_equal expected, actual end def test_form_tag_with_remote_false actual = form_tag({}, :remote => false) - expected = %() + + expected = whole_form assert_dom_equal expected, actual end def test_form_tag_with_block_in_erb - output_buffer = form_tag("http://example.com") { concat "Hello world!" } + output_buffer = form_tag("http://www.example.com") { concat "Hello world!" } - expected = %(Hello world!
) + expected = whole_form { "Hello world!" } assert_dom_equal expected, output_buffer end def test_form_tag_with_block_and_method_in_erb - output_buffer = form_tag("http://example.com", :method => :put) { concat "Hello world!" } + output_buffer = form_tag("http://www.example.com", :method => :put) { concat "Hello world!" } + + expected = whole_form("http://www.example.com", :method => "put") do + "Hello world!" + end - expected = %(
Hello world!
) assert_dom_equal expected, output_buffer end From 0e5d7c6f6458d279c59d34f1e37289e338784e7b Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Mon, 28 Jun 2010 12:08:29 +0900 Subject: [PATCH 15/71] Use ActiveRecord::Migrator.schema_migrations_table_name instead of hardcoding "schema_migrations" Signed-off-by: Jeremy Kemper --- activerecord/lib/active_record/railties/databases.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 80218d6ff9..3cb6d63727 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -175,7 +175,7 @@ namespace :db do desc "Display status of migrations" task :status => :environment do config = ActiveRecord::Base.configurations[Rails.env || 'development'] - db_list = ActiveRecord::Base.connection.select_values("SELECT version FROM schema_migrations") + db_list = ActiveRecord::Base.connection.select_values("SELECT version FROM #{ActiveRecord::Migrator.schema_migrations_table_name}") file_list = [] Dir.foreach(File.join(Rails.root, 'db', 'migrate')) do |file| # only files matching "20091231235959_some_name.rb" pattern From 4f74d449eee1e3d1621ed032532076492a1bf0b3 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Mon, 28 Jun 2010 12:12:36 +0900 Subject: [PATCH 16/71] Avoid "no such table" exception when schema migrations table does not exist [#4990 state:resolved] Signed-off-by: Jeremy Kemper --- activerecord/lib/active_record/railties/databases.rake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 3cb6d63727..cfa84cbb76 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -175,6 +175,11 @@ namespace :db do desc "Display status of migrations" task :status => :environment do config = ActiveRecord::Base.configurations[Rails.env || 'development'] + ActiveRecord::Base.establish_connection(config) + unless ActiveRecord::Base.connection.table_exists?(ActiveRecord::Migrator.schema_migrations_table_name) + puts 'Schema migrations table does not exist yet.' + next # means "return" for rake task + end db_list = ActiveRecord::Base.connection.select_values("SELECT version FROM #{ActiveRecord::Migrator.schema_migrations_table_name}") file_list = [] Dir.foreach(File.join(Rails.root, 'db', 'migrate')) do |file| From ab96c71a52b7b950fba6090e6a091a1f951eaa44 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 28 Jun 2010 01:19:24 -0300 Subject: [PATCH 17/71] Add this rule to run common tests and specifics ones from adapters dir --- activerecord/Rakefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/activerecord/Rakefile b/activerecord/Rakefile index 22a17a62af..392b717e0a 100644 --- a/activerecord/Rakefile +++ b/activerecord/Rakefile @@ -62,7 +62,9 @@ end adapter_short = adapter == 'db2' ? adapter : adapter[/^[a-z]+/] puts [adapter, adapter_short, connection_path].inspect ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME')) - Dir["test/cases/**/*_test{,_#{adapter_short}}.rb"].all? do |file| + (Dir["test/cases/**/*_test.rb"].reject { + |x| x =~ /\/adapters\// + } + Dir["test/cases/adapters/#{adapter_short}/**/*_test.rb"]).all? do |file| system(ruby, "-Ilib:test:#{connection_path}", file) end or raise "Failures" end From 6fe424aecaae3683866a1af5605998fa6842a8e0 Mon Sep 17 00:00:00 2001 From: wycats Date: Sun, 27 Jun 2010 21:50:15 -0700 Subject: [PATCH 18/71] Small typo --- actionpack/lib/action_view/helpers/form_tag_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 0e9cb2349f..28ef9a05ef 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -530,7 +530,7 @@ module ActionView returning options.stringify_keys do |html_options| html_options["enctype"] = "multipart/form-data" if html_options.delete("multipart") html_options["action"] = url_for(url_for_options, *parameters_for_url) - html_options["accept-encoding"] = "UTF-8" + html_options["accept-charset"] = "UTF-8" html_options["data-remote"] = true if html_options.delete("remote") end end From be994e2c50af6c7cb31602fd45f4e718f011b165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Mon, 28 Jun 2010 11:15:47 +0200 Subject: [PATCH 19/71] Information about new rake task in CHANGELOG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activerecord/CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 09f897eaac..6c07467535 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,6 +1,7 @@ *Rails 3.0.0 [RC1] (unreleased)* * PostgreSQL: ensure the database time zone matches Ruby's time zone. #4895 [Aaron Patterson] +* New rake task, db:migrate:status, displays status of migrations #4947 [Kevin Skoglund] *Rails 3.0.0 [beta 4] (June 8th, 2010)* From dd8b7417a9b793b7780bf5ca5e04b1c05ac3a8f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 28 Jun 2010 11:37:14 +0200 Subject: [PATCH 20/71] Update CHANGELOGs. --- actionpack/CHANGELOG | 3 ++- activerecord/CHANGELOG | 5 ++++- railties/CHANGELOG | 4 ++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index b17a48003c..23f1d9606f 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.0.0 [Release Candidate] (unreleased)* +* Upgrade to Rack 1.2.1 [Jeremy Kemper] + * Allow :path to be given to match/get/post/put/delete instead of :path_names in the new router [Carlos Antônio da Silva] * Added resources_path_names to the new router DSL [José Valim] @@ -22,7 +24,6 @@ * Removed textilize, textilize_without_paragraph and markdown helpers. [Santiago Pastorino] - *Rails 3.0.0 [beta 4] (June 8th, 2010)* * Remove middleware laziness [José Valim] diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 6c07467535..60739fbd91 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,8 +1,11 @@ *Rails 3.0.0 [RC1] (unreleased)* -* PostgreSQL: ensure the database time zone matches Ruby's time zone. #4895 [Aaron Patterson] * New rake task, db:migrate:status, displays status of migrations #4947 [Kevin Skoglund] +* select and order for ActiveRecord now always concatenate nested calls. Use reorder if you want the original order to be overwritten [Santiago Pastorino] + +* PostgreSQL: ensure the database time zone matches Ruby's time zone #4895 [Aaron Patterson] + *Rails 3.0.0 [beta 4] (June 8th, 2010)* diff --git a/railties/CHANGELOG b/railties/CHANGELOG index 61d84e104a..8e2bac7f00 100644 --- a/railties/CHANGELOG +++ b/railties/CHANGELOG @@ -1,5 +1,9 @@ *Rails 3.0.0 [Release Candidate] (unreleased)* +* Rails no longer autoload code in lib for application. You need to explicitly require it. [José Valim] + +* Rails::LogSubscriber was renamed to ActiveSupport::LogSubscriber [José Valim] + * config.load_(once_)paths in config/application.rb got renamed to config.autoload_(once_)paths. [fxn] * Abort generation/booting on Ruby 1.9.1. [fxn] From 2002e5877efa40b336b70b707670e734c6389958 Mon Sep 17 00:00:00 2001 From: Bruno Michel Date: Sat, 26 Jun 2010 19:00:57 +0200 Subject: [PATCH 21/71] Strip_tags never ending attribute should not raise a TypeError [#4870 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- .../lib/action_controller/vendor/html-scanner/html/node.rb | 1 + .../action_controller/vendor/html-scanner/html/tokenizer.rb | 1 + actionpack/test/template/html-scanner/sanitizer_test.rb | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/node.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/node.rb index 6c0331636c..a874519978 100644 --- a/actionpack/lib/action_controller/vendor/html-scanner/html/node.rb +++ b/actionpack/lib/action_controller/vendor/html-scanner/html/node.rb @@ -177,6 +177,7 @@ module HTML #:nodoc: case text when "\\" then value << text + break if scanner.eos? value << scanner.getch when delim break diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/tokenizer.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/tokenizer.rb index 064ff3724d..240dc1890f 100644 --- a/actionpack/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +++ b/actionpack/lib/action_controller/vendor/html-scanner/html/tokenizer.rb @@ -96,6 +96,7 @@ module HTML #:nodoc: while match = @scanner.scan_until(/[\\#{delim}]/) text << match break if @scanner.matched == delim + break if @scanner.eos? text << @scanner.getch # skip the escaped character end end diff --git a/actionpack/test/template/html-scanner/sanitizer_test.rb b/actionpack/test/template/html-scanner/sanitizer_test.rb index a6e760b0b6..c9edde8892 100644 --- a/actionpack/test/template/html-scanner/sanitizer_test.rb +++ b/actionpack/test/template/html-scanner/sanitizer_test.rb @@ -257,6 +257,10 @@ class SanitizerTest < ActionController::TestCase assert_sanitized %{my link} end + def test_should_sanitize_neverending_attribute + assert_sanitized "" + end + protected def assert_sanitized(input, expected = nil) @sanitizer ||= HTML::WhiteListSanitizer.new From 6d04fa6dc4865af1112c4d35a456a81008815ee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 28 Jun 2010 12:23:41 +0200 Subject: [PATCH 22/71] Deprecate the old router DSL. Since it is still used intensively across ActionPack test suite, patches that translates Rails internal tests to the new router DSL are welcome (note though that a few tests shouldn't be translated since they are testing exactly the old mapper API, like the ones in actionpack/test/controller/resource_test.rb and actionpack/test/controller/routing_test.rb) --- .../routing/deprecated_mapper.rb | 2 ++ actionpack/test/abstract_unit.rb | 8 +++++ .../activerecord/polymorphic_routes_test.rb | 30 +++++++++---------- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb b/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb index 61c2253763..bc3f62fb48 100644 --- a/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb +++ b/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb @@ -30,6 +30,8 @@ module ActionDispatch class DeprecatedMapper #:nodoc: def initialize(set) #:nodoc: + ActiveSupport::Deprecation.warn "You are using the old router DSL which will be removed in Rails 3.1. " << + "Please check how to update your router file at: http://www.engineyard.com/blog/2010/the-lowdown-on-routes-in-rails-3/" @set = set end diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 3241b3d118..c8477fb83f 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -41,6 +41,14 @@ require 'pp' # require 'pp' early to prevent hidden_methods from not picking up module Rails end +# Monkey patch the old router initialization to be silenced. +class ActionDispatch::Routing::DeprecatedMapper + def initialize_with_silencer(*args) + ActiveSupport::Deprecation.silence { initialize_without_silencer(*args) } + end + alias_method_chain :initialize, :silencer +end + ActiveSupport::Dependencies.hook! # Show backtraces for deprecated behavior for quicker cleanup. diff --git a/actionpack/test/activerecord/polymorphic_routes_test.rb b/actionpack/test/activerecord/polymorphic_routes_test.rb index 6e1e6cdd20..90a1ef982c 100644 --- a/actionpack/test/activerecord/polymorphic_routes_test.rb +++ b/actionpack/test/activerecord/polymorphic_routes_test.rb @@ -408,18 +408,18 @@ class PolymorphicRoutesTest < ActionController::TestCase def with_admin_test_routes(options = {}) with_routing do |set| - set.draw do |map| - map.namespace :admin do |admin| - admin.resources :projects do |projects| - projects.resources :tasks - projects.resource :bid do |bid| - bid.resources :tasks + set.draw do + namespace :admin do + resources :projects do + resources :tasks + resource :bid do + resources :tasks end end - admin.resources :taxes do |taxes| - taxes.resources :faxes + resources :taxes do + resources :faxes end - admin.resources :series + resources :series end end @@ -430,12 +430,12 @@ class PolymorphicRoutesTest < ActionController::TestCase def with_admin_and_site_test_routes(options = {}) with_routing do |set| - set.draw do |map| - map.namespace :admin do |admin| - admin.resources :projects do |projects| - projects.namespace :site do |site| - site.resources :tasks do |tasks| - tasks.resources :steps + set.draw do + namespace :admin do + resources :projects do + namespace :site do + resources :tasks do + resources :steps end end end From 19ccd4628c1ab4aebc00dc8d480d6cbf1688a312 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Mon, 28 Jun 2010 00:53:36 +0100 Subject: [PATCH 23/71] Remove invalid conditions from route [#4989 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_dispatch/routing/route.rb | 13 +++++++++++-- actionpack/lib/action_dispatch/routing/route_set.rb | 5 +++-- actionpack/test/dispatch/routing_test.rb | 12 ++++++++++++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/route.rb b/actionpack/lib/action_dispatch/routing/route.rb index 6f37eadd6b..aefebf8f80 100644 --- a/actionpack/lib/action_dispatch/routing/route.rb +++ b/actionpack/lib/action_dispatch/routing/route.rb @@ -2,9 +2,10 @@ module ActionDispatch module Routing class Route #:nodoc: attr_reader :app, :conditions, :defaults, :name - attr_reader :path, :requirements + attr_reader :path, :requirements, :set - def initialize(app, conditions, requirements, defaults, name, anchor) + def initialize(set, app, conditions, requirements, defaults, name, anchor) + @set = set @app = app @defaults = defaults @name = name @@ -24,6 +25,9 @@ module ActionDispatch h[k] = Rack::Mount::RegexpWithNamedGroups.new(v) h } + + @conditions.delete_if{ |k,v| k != :path_info && !valid_condition?(k) } + @requirements.delete_if{ |k,v| !valid_condition?(k) } end def verb @@ -50,6 +54,11 @@ module ActionDispatch "%-6s %-40s %s" % [(verb || :any).to_s.upcase, path, requirements.inspect] end end + + private + def valid_condition?(method) + segment_keys.include?(method) || set.valid_conditions.include?(method) + end end end end diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 05200f0338..10de4853c5 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -189,7 +189,7 @@ module ActionDispatch attr_accessor :set, :routes, :named_routes attr_accessor :disable_clear_and_finalize, :resources_path_names - attr_accessor :default_url_options, :request_class + attr_accessor :default_url_options, :request_class, :valid_conditions def self.default_resources_path_names { :new => 'new', :edit => 'edit' } @@ -202,6 +202,7 @@ module ActionDispatch self.controller_namespaces = Set.new self.default_url_options = {} self.request_class = request_class + self.valid_conditions = request_class.public_instance_methods.select{ |m| m != "id" }.map{ |m| m.to_sym } @disable_clear_and_finalize = false clear! @@ -279,7 +280,7 @@ module ActionDispatch end def add_route(app, conditions = {}, requirements = {}, defaults = {}, name = nil, anchor = true) - route = Route.new(app, conditions, requirements, defaults, name, anchor) + route = Route.new(self, app, conditions, requirements, defaults, name, anchor) @set.add_route(*route) named_routes[name] = route if name routes << route diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index cf92b039e3..0548456b63 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -330,6 +330,10 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest resources :content + scope :constraints => { :id => /\d+/ } do + get '/tickets', :to => 'tickets#index', :as => :tickets + end + match '/:locale/*file.:format', :to => 'files#show', :file => /path\/to\/existing\/file/ end end @@ -1546,6 +1550,14 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + def test_router_removes_invalid_conditions + with_test_routes do + get '/tickets' + assert_equal 'tickets#index', @response.body + assert_equal '/tickets', tickets_path + end + end + private def with_test_routes yield From ccb21f20d86ffc17c10cb5e476912157c739dd96 Mon Sep 17 00:00:00 2001 From: rohit Date: Mon, 28 Jun 2010 16:41:01 +0530 Subject: [PATCH 24/71] Convert instance_variables to symbols before excluding internal vars [#4965 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_view/test_case.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index 757e4cf77c..e5614c9e3b 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -181,7 +181,7 @@ module ActionView } def _instance_variables - instance_variables - EXCLUDE_IVARS + instance_variables.map(&:to_s) - EXCLUDE_IVARS end def _assigns From e717631a8481935e8ac1eeb2445da341bdd4c868 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Mon, 28 Jun 2010 12:04:13 +0100 Subject: [PATCH 25/71] Merge :constraints from scope into resource options [#2694 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- .../lib/action_dispatch/routing/mapper.rb | 10 +++-- actionpack/test/dispatch/routing_test.rb | 43 +++++++++++++++++++ 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 388f695187..62fb7977cc 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -433,6 +433,8 @@ module ActionDispatch end module Resources + MERGE_FROM_SCOPE_OPTIONS = [:shallow, :constraints] + class Resource #:nodoc: def self.default_actions [:index, :create, :new, :show, :update, :destroy, :edit] @@ -591,8 +593,6 @@ module ActionDispatch def resource(*resources, &block) options = resources.extract_options! - options = (@scope[:options] || {}).merge(options) - options[:shallow] = true if @scope[:shallow] && !options.has_key?(:shallow) if apply_common_behavior_for(:resource, resources, options, &block) return self @@ -619,8 +619,6 @@ module ActionDispatch def resources(*resources, &block) options = resources.extract_options! - options = (@scope[:options] || {}).merge(options) - options[:shallow] = true if @scope[:shallow] && !options.has_key?(:shallow) if apply_common_behavior_for(:resources, resources, options, &block) return self @@ -804,6 +802,10 @@ module ActionDispatch return true end + scope_options = @scope.slice(*MERGE_FROM_SCOPE_OPTIONS).delete_if{ |k,v| v.blank? } + options.reverse_merge!(scope_options) unless scope_options.empty? + options.reverse_merge!(@scope[:options]) unless @scope[:options].blank? + if resource_scope? nested do send(method, resources.pop, options, &block) diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 0548456b63..b5653a391a 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -334,6 +334,13 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest get '/tickets', :to => 'tickets#index', :as => :tickets end + scope :constraints => { :id => /\d{4}/ } do + resources :movies do + resources :reviews + resource :trailer + end + end + match '/:locale/*file.:format', :to => 'files#show', :file => /path\/to\/existing\/file/ end end @@ -1558,6 +1565,42 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + def test_constraints_are_merged_from_scope + with_test_routes do + get '/movies/0001' + assert_equal 'movies#show', @response.body + assert_equal '/movies/0001', movie_path(:id => '0001') + + get '/movies/00001' + assert_equal 'Not Found', @response.body + assert_raises(ActionController::RoutingError){ movie_path(:id => '00001') } + + get '/movies/0001/reviews' + assert_equal 'reviews#index', @response.body + assert_equal '/movies/0001/reviews', movie_reviews_path(:movie_id => '0001') + + get '/movies/00001/reviews' + assert_equal 'Not Found', @response.body + assert_raises(ActionController::RoutingError){ movie_reviews_path(:movie_id => '00001') } + + get '/movies/0001/reviews/0001' + assert_equal 'reviews#show', @response.body + assert_equal '/movies/0001/reviews/0001', movie_review_path(:movie_id => '0001', :id => '0001') + + get '/movies/00001/reviews/0001' + assert_equal 'Not Found', @response.body + assert_raises(ActionController::RoutingError){ movie_path(:movie_id => '00001', :id => '00001') } + + get '/movies/0001/trailer' + assert_equal 'trailers#show', @response.body + assert_equal '/movies/0001/trailer', movie_trailer_path(:movie_id => '0001') + + get '/movies/00001/trailer' + assert_equal 'Not Found', @response.body + assert_raises(ActionController::RoutingError){ movie_trailer_path(:movie_id => '00001') } + end + end + private def with_test_routes yield From 0b6ce3422370647cad3e91263a291f69b313d65b Mon Sep 17 00:00:00 2001 From: Andrew White Date: Sun, 27 Jun 2010 09:16:46 +0100 Subject: [PATCH 26/71] Restores the escaping of urls generated from hashes. [#4765 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HTML specifications recommend the escaping of urls in web pages, which url_for does by default for string urls and consquently urls generated by path helpers as these return strings. Hashes passed to url_for are not escaped by default and this commit reverses this default so that they are escaped. Undoes the changes of this commit: http://github.com/rails/rails/commit/1b3195b63ca44f0a70b61b75fcf4991cb2fbb944 Signed-off-by: José Valim --- actionpack/lib/action_view/helpers/url_helper.rb | 2 +- actionpack/test/template/url_helper_test.rb | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index 6af11e632f..cbde9b94a7 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -104,7 +104,7 @@ module ActionView options when Hash options = { :only_path => options[:host].nil? }.update(options.symbolize_keys) - escape = options.key?(:escape) ? options.delete(:escape) : false + escape = options.key?(:escape) ? options.delete(:escape) : true super when :back escape = false diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index 72d4897630..897228677b 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -41,7 +41,7 @@ class UrlHelperTest < ActiveSupport::TestCase alias url_hash hash_for def test_url_for_escapes_urls - assert_equal "/?a=b&c=d", url_for(abcd) + assert_equal "/?a=b&c=d", url_for(abcd) assert_equal "/?a=b&c=d", url_for(abcd(:escape => true)) assert_equal "/?a=b&c=d", url_for(abcd(:escape => false)) end @@ -53,6 +53,7 @@ class UrlHelperTest < ActiveSupport::TestCase def test_url_for_escapes_url_once assert_equal "/?a=b&c=d", url_for("/?a=b&c=d") + assert_equal "/?a=b&c=d", url_for(abcd) end def test_url_for_with_back @@ -67,11 +68,6 @@ class UrlHelperTest < ActiveSupport::TestCase assert_equal 'javascript:history.back()', url_for(:back) end - def test_url_for_from_hash_doesnt_escape_ampersand - path = url_for(hash_for(:foo => :bar, :baz => :quux)) - assert_equal '/?baz=quux&foo=bar', sort_query_string_params(path) - end - # todo: missing test cases def test_button_to_with_straight_url assert_dom_equal "
", button_to("Hello", "http://www.example.com") @@ -345,7 +341,7 @@ class UrlHelperTest < ActiveSupport::TestCase link_to_unless_current("Showing", "http://www.example.com/?order=asc") @request = request_for_url("/?order=desc") - assert_equal %{Showing}, + assert_equal %{Showing}, link_to_unless_current("Showing", hash_for(:order => "desc", :page => 2)) assert_equal %{Showing}, link_to_unless_current("Showing", "http://www.example.com/?order=desc&page=2") @@ -415,7 +411,7 @@ class UrlHelperTest < ActiveSupport::TestCase private def sort_query_string_params(uri) path, qs = uri.split('?') - qs = qs.split('&').sort.join('&') if qs + qs = qs.split('&').sort.join('&') if qs qs ? "#{path}?#{qs}" : path end end From e4f9132f6a355de50511fcb75a5186a1a8af17e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 28 Jun 2010 15:36:47 +0200 Subject: [PATCH 27/71] Do not trigger the old mapper to avoid deprecation messages. --- .../lib/rails/generators/rails/app/templates/config/routes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/rails/generators/rails/app/templates/config/routes.rb b/railties/lib/rails/generators/rails/app/templates/config/routes.rb index d6c0365c04..d42cf3bfdf 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/routes.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/routes.rb @@ -1,4 +1,4 @@ -<%= app_const %>.routes.draw do |map| +<%= app_const %>.routes.draw do # The priority is based upon order of creation: # first created -> highest priority. From 02a1a4edc8cce6a9f86ba56b4143e69cf25c2f7e Mon Sep 17 00:00:00 2001 From: Andrew White Date: Mon, 28 Jun 2010 15:44:27 +0100 Subject: [PATCH 28/71] Add :controller and :action to the list of valid conditions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_dispatch/routing/route_set.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 10de4853c5..4b6d4fef97 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -203,6 +203,7 @@ module ActionDispatch self.default_url_options = {} self.request_class = request_class self.valid_conditions = request_class.public_instance_methods.select{ |m| m != "id" }.map{ |m| m.to_sym } + self.valid_conditions += [:controller, :action] @disable_clear_and_finalize = false clear! From 6dfa8d8e95ebd4b6bc177954173adf5cdd9b28b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 28 Jun 2010 16:57:14 +0200 Subject: [PATCH 29/71] Tidy up valid conditions in router a bit. --- actionpack/lib/action_dispatch/routing/route_set.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 4b6d4fef97..5ecad6bc04 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -201,9 +201,11 @@ module ActionDispatch self.resources_path_names = self.class.default_resources_path_names.dup self.controller_namespaces = Set.new self.default_url_options = {} + self.request_class = request_class - self.valid_conditions = request_class.public_instance_methods.select{ |m| m != "id" }.map{ |m| m.to_sym } - self.valid_conditions += [:controller, :action] + self.valid_conditions = request_class.public_instance_methods.map { |m| m.to_sym } + self.valid_conditions.delete(:id) + self.valid_conditions.push(:controller, :action) @disable_clear_and_finalize = false clear! From b5b42af33f446ca3de1d80f92b8c9138dbf6c05d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 28 Jun 2010 17:09:09 +0200 Subject: [PATCH 30/71] Make the sentinel flag for route a bit more robust. --- railties/lib/rails/generators/actions.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index 7af329bbf0..199afbdc30 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -275,7 +275,7 @@ module Rails # def route(routing_code) log :route, routing_code - sentinel = "routes.draw do |map|" + sentinel = /\.routes\.draw do(\s*\|map\|)?\s*$/ in_root do inject_into_file 'config/routes.rb', "\n #{routing_code}\n", { :after => sentinel, :verbose => false } From 97a92a4cfddf819357ca09b4a91a5937b044e4d8 Mon Sep 17 00:00:00 2001 From: Leigh Caplan Date: Mon, 28 Jun 2010 14:04:11 -0300 Subject: [PATCH 31/71] test that unknown zones don't store mapping keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#4942] Signed-off-by: Santiago Pastorino Signed-off-by: José Valim --- activesupport/test/time_zone_test.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb index 620623b389..922449988b 100644 --- a/activesupport/test/time_zone_test.rb +++ b/activesupport/test/time_zone_test.rb @@ -285,6 +285,11 @@ class TimeZoneTest < Test::Unit::TestCase assert_equal(-21_600, zone.utc_offset) end + def test_unknown_zones_dont_store_mapping_keys + ActiveSupport::TimeZone["bogus"] + assert !ActiveSupport::TimeZone.zones_map.key?("bogus") + end + def test_new assert_equal ActiveSupport::TimeZone["Central Time (US & Canada)"], ActiveSupport::TimeZone.new("Central Time (US & Canada)") end From b2633f9f9323f5d5eca1c2c94bb7ae88ad276cda Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 28 Jun 2010 14:01:48 -0300 Subject: [PATCH 32/71] Don't store incorrect values in zones_map MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#4942 state:committed] Signed-off-by: José Valim --- activesupport/lib/active_support/values/time_zone.rb | 6 +++++- activesupport/test/core_ext/time_with_zone_test.rb | 4 +--- activesupport/test/time_zone_test.rb | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 0a08016522..05b40298d3 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -350,7 +350,11 @@ module ActiveSupport def [](arg) case arg when String - zones_map[arg] ||= lookup(arg) + begin + zones_map[arg] ||= lookup(arg).tap { |tz| tz.utc_offset } + rescue TZInfo::InvalidTimezoneIdentifier + nil + end when Numeric, ActiveSupport::Duration arg *= 3600 if arg.abs <= 13 all.find { |z| z.utc_offset == arg.to_i } diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb index cf11f4d28f..5ce4277672 100644 --- a/activesupport/test/core_ext/time_with_zone_test.rb +++ b/activesupport/test/core_ext/time_with_zone_test.rb @@ -832,9 +832,7 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < Test::Unit::TestCase def test_time_zone_setter_with_invalid_zone Time.zone = 'foo' - assert_not_nil Time.zone - assert_equal 'foo', Time.zone.name - assert_raise(TZInfo::InvalidTimezoneIdentifier) { Time.zone.utc_offset } + assert_nil Time.zone Time.zone = -15.hours assert_nil Time.zone diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb index 922449988b..af6eee69e5 100644 --- a/activesupport/test/time_zone_test.rb +++ b/activesupport/test/time_zone_test.rb @@ -268,7 +268,7 @@ class TimeZoneTest < Test::Unit::TestCase end def test_index - assert_not_nil ActiveSupport::TimeZone["bogus"] + assert_nil ActiveSupport::TimeZone["bogus"] assert_instance_of ActiveSupport::TimeZone, ActiveSupport::TimeZone["Central Time (US & Canada)"] assert_instance_of ActiveSupport::TimeZone, ActiveSupport::TimeZone[8] assert_raise(ArgumentError) { ActiveSupport::TimeZone[false] } From ec18719b81e117215fefb33aff5ed43472bce048 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 27 Jun 2010 23:42:13 -0700 Subject: [PATCH 33/71] ETag: use body instead of @body since the method will always return a string --- actionpack/lib/action_dispatch/http/cache.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_dispatch/http/cache.rb b/actionpack/lib/action_dispatch/http/cache.rb index 9b9e81440b..e9fdf75cc8 100644 --- a/actionpack/lib/action_dispatch/http/cache.rb +++ b/actionpack/lib/action_dispatch/http/cache.rb @@ -89,7 +89,7 @@ module ActionDispatch if etag? || last_modified? || !@cache_control.empty? set_conditional_cache_control! elsif nonempty_ok_response? - self.etag = @body + self.etag = body if request && request.etag_matches?(etag) self.status = 304 @@ -137,4 +137,4 @@ module ActionDispatch end end end -end \ No newline at end of file +end From 198ec03f5220f9c8ba363011f70a1c487c10b07e Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 11 Jun 2010 23:20:19 -0700 Subject: [PATCH 34/71] returning -> tap --- actionpack/lib/action_view/helpers/prototype_helper.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index bfb8f74a00..678e6348b6 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -1,6 +1,5 @@ require 'set' require 'active_support/json' -require 'active_support/core_ext/object/returning' require 'active_support/core_ext/object/blank' module ActionView @@ -228,7 +227,7 @@ module ActionView # ".html_safe @@ -508,9 +511,9 @@ module ActionView char = c.chr string << (char =~ /\w/ ? sprintf("%%%x", c) : char) end - content_tag "a", name || email_address_encoded.html_safe, html_options.merge({ "href" => "#{string}#{extras}" }) + content_tag "a", name || email_address_encoded.html_safe, html_options.merge("href" => "#{string}#{extras}".html_safe) else - content_tag "a", name || email_address_obfuscated.html_safe, html_options.merge({ "href" => "mailto:#{email_address}#{extras}" }) + content_tag "a", name || email_address_obfuscated.html_safe, html_options.merge("href" => "mailto:#{email_address}#{extras}".html_safe) end end diff --git a/actionpack/test/template/tag_helper_test.rb b/actionpack/test/template/tag_helper_test.rb index ec5fe3d1d7..507cdca8d0 100644 --- a/actionpack/test/template/tag_helper_test.rb +++ b/actionpack/test/template/tag_helper_test.rb @@ -95,9 +95,9 @@ class TagHelperTest < ActionView::TestCase assert_equal '1 < 2 & 3', escape_once('1 < 2 & 3') end - def test_double_escaping_attributes + def test_tag_honors_html_safe_for_param_values ['1&2', '1 < 2', '“test“'].each do |escaped| - assert_equal %(), tag('a', :href => escaped) + assert_equal %(), tag('a', :href => escaped.html_safe) end end diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index 035f501f03..befb55fb48 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -65,8 +65,8 @@ class UrlHelperTest < ActiveSupport::TestCase assert_dom_equal "
", button_to("Hello", "http://www.example.com/q1=v1&q2=v2") end - def test_button_to_with_escaped_query - assert_dom_equal "
", button_to("Hello", "http://www.example.com/q1=v1&q2=v2") + def test_button_to_with_html_safe_URL + assert_dom_equal "
", button_to("Hello", "http://www.example.com/q1=v1&q2=v2".html_safe) end def test_button_to_with_query_and_no_name From d7c2e52c6c04dec4e4665c8f0f9988bfe913cb15 Mon Sep 17 00:00:00 2001 From: Tekin Date: Tue, 29 Jun 2010 20:59:52 +0100 Subject: [PATCH 59/71] migrations.rb requires active_support/core_ext/module/aliasing [#5008 state:committed] Signed-off-by: Xavier Noria --- activerecord/lib/active_record/migration.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index b273c33e50..4c5e1ae218 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -1,4 +1,5 @@ require 'active_support/core_ext/kernel/singleton_class' +require 'active_support/core_ext/module/aliasing' module ActiveRecord # Exception that can be raised to stop migrations from going backwards. From 3f563f169612ec340816f0a549fe9db7ff95c238 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 29 Jun 2010 15:42:06 -0700 Subject: [PATCH 60/71] AssociationCollection#create_by_*, find_or_create_by_* work properly now. [#1108 state:resolved] Signed-off-by: Jeremy Kemper --- .../associations/association_collection.rb | 11 ++++ .../has_many_associations_test.rb | 62 +++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 186b531ffb..ddf4ce4058 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -409,6 +409,17 @@ module ActiveRecord end def method_missing(method, *args) + case method.to_s + when 'find_or_create' + return find(:first, :conditions => args.first) || create(args.first) + when /^find_or_create_by_(.*)$/ + rest = $1 + return send("find_by_#{rest}", *args) || + method_missing("create_by_#{rest}", *args) + when /^create_by_(.*)$/ + return create Hash[$1.split('_and_').zip(args)] + end + if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method)) if block_given? super { |*block_args| yield(*block_args) } diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 45c7498013..5e3ba778f3 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -21,6 +21,68 @@ class HasManyAssociationsTest < ActiveRecord::TestCase Client.destroyed_client_ids.clear end + def test_create_by + person = Person.create! :first_name => 'tenderlove' + post = Post.find :first + + assert_equal [], person.readers + assert_nil person.readers.find_by_post_id post.id + + reader = person.readers.create_by_post_id post.id + + assert_equal 1, person.readers.count + assert_equal 1, person.readers.length + assert_equal post, person.readers.first.post + assert_equal person, person.readers.first.person + end + + def test_create_by_multi + person = Person.create! :first_name => 'tenderlove' + post = Post.find :first + + assert_equal [], person.readers + + reader = person.readers.create_by_post_id_and_skimmer post.id, false + + assert_equal 1, person.readers.count + assert_equal 1, person.readers.length + assert_equal post, person.readers.first.post + assert_equal person, person.readers.first.person + end + + def test_find_or_create_by + person = Person.create! :first_name => 'tenderlove' + post = Post.find :first + + assert_equal [], person.readers + assert_nil person.readers.find_by_post_id post.id + + reader = person.readers.find_or_create_by_post_id post.id + + assert_equal 1, person.readers.count + assert_equal 1, person.readers.length + assert_equal post, person.readers.first.post + assert_equal person, person.readers.first.person + end + + def test_find_or_create + person = Person.create! :first_name => 'tenderlove' + post = Post.find :first + + assert_equal [], person.readers + assert_nil person.readers.find(:first, :conditions => { + :post_id => post.id + }) + + reader = person.readers.find_or_create :post_id => post.id + + assert_equal 1, person.readers.count + assert_equal 1, person.readers.length + assert_equal post, person.readers.first.post + assert_equal person, person.readers.first.person + end + + def force_signal37_to_load_all_clients_of_firm companies(:first_firm).clients_of_firm.each {|f| } end From 68bd46ffb99282ecb589c9ed2cd0c74d0da3396e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Silva?= Date: Fri, 18 Jun 2010 22:23:11 +0100 Subject: [PATCH 61/71] performance tests now working accurately on 1.9, using Ruby with the GCdata patch --- .../lib/active_support/testing/performance.rb | 54 +++++++------------ 1 file changed, 18 insertions(+), 36 deletions(-) diff --git a/activesupport/lib/active_support/testing/performance.rb b/activesupport/lib/active_support/testing/performance.rb index cd628a956d..a124c6e0ca 100644 --- a/activesupport/lib/active_support/testing/performance.rb +++ b/activesupport/lib/active_support/testing/performance.rb @@ -260,16 +260,14 @@ begin end protected - # Ruby 1.9 + extented GC profiler patch - if defined?(GC::Profiler) and GC::Profiler.respond_to?(:data) + # Ruby 1.9 with GC::Profiler + if defined?(GC::Profiler) def with_gc_stats - GC.start - GC.disable GC::Profiler.enable + GC.start yield ensure GC::Profiler.disable - GC.enable end # Ruby 1.8 + ruby-prof wrapper (enable/disable stats for Benchmarker) @@ -294,7 +292,7 @@ begin end def format(measurement) - if measurement < 2 + if measurement < 1 '%d ms' % (measurement * 1000) else '%.2f sec' % measurement @@ -335,14 +333,10 @@ begin class Memory < Base Mode = RubyProf::MEMORY if RubyProf.const_defined?(:MEMORY) - # Ruby 1.9 + extended GC profiler patch - if defined?(GC::Profiler) and GC::Profiler.respond_to?(:data) + # Ruby 1.9 + GCdata patch + if GC.respond_to?(:malloc_allocated_size) def measure - GC.enable - GC.start - kb = GC::Profiler.data.last[:HEAP_USE_SIZE] / 1024.0 - GC.disable - kb + GC.malloc_allocated_size / 1024.0 end # Ruby 1.8 + ruby-prof wrapper @@ -360,14 +354,10 @@ begin class Objects < Base Mode = RubyProf::ALLOCATIONS if RubyProf.const_defined?(:ALLOCATIONS) - # Ruby 1.9 + extented GC profiler patch - if defined?(GC::Profiler) and GC::Profiler.respond_to?(:data) + # Ruby 1.9 + GCdata patch + if GC.respond_to?(:malloc_allocations) def measure - GC.enable - GC.start - count = GC::Profiler.data.last[:HEAP_TOTAL_OBJECTS] - GC.disable - count + GC.malloc_allocations end # Ruby 1.8 + ruby-prof wrapper @@ -385,14 +375,10 @@ begin class GcRuns < Base Mode = RubyProf::GC_RUNS if RubyProf.const_defined?(:GC_RUNS) - # Ruby 1.9 + extented GC profiler patch - if defined?(GC::Profiler) and GC::Profiler.respond_to?(:data) + # Ruby 1.9 + if GC.respond_to?(:count) def measure - GC.enable - GC.start - count = GC::Profiler.data.last[:GC_RUNS] - GC.disable - count + GC.count end # Ruby 1.8 + ruby-prof wrapper @@ -410,25 +396,21 @@ begin class GcTime < Base Mode = RubyProf::GC_TIME if RubyProf.const_defined?(:GC_TIME) - # Ruby 1.9 + extented GC profiler patch - if defined?(GC::Profiler) and GC::Profiler.respond_to?(:data) + # Ruby 1.9 with GC::Profiler + if GC.respond_to?(:total_time) def measure - GC.enable - GC.start - sec = GC::Profiler.data.inject(0) { |total, run| total += run[:GC_TIME] } - GC.disable - sec + GC::Profiler.total_time end # Ruby 1.8 + ruby-prof wrapper elsif RubyProf.respond_to?(:measure_gc_time) def measure - RubyProf.measure_gc_time + RubyProf.measure_gc_time / 1000 end end def format(measurement) - '%d ms' % (measurement / 1000) + '%.2f ms' % measurement end end end From 7bd00fcb7f8e7f94811387cd809480a727b61f11 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 29 Jun 2010 21:41:27 -0300 Subject: [PATCH 62/71] We are trying to test that & escapes here not that & is being escaped, also added a cosmetic change to test_link_tag_with_query_and_no_name Signed-off-by: Jeremy Kemper --- actionpack/test/template/url_helper_test.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index befb55fb48..765beebfa3 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -135,13 +135,12 @@ class UrlHelperTest < ActiveSupport::TestCase def test_link_tag_with_query expected = %{
Hello} - assert_dom_equal expected, link_to("Hello", "http://www.example.com?q1=v1&q2=v2") + assert_dom_equal expected, link_to("Hello", "http://www.example.com?q1=v1&q2=v2") end def test_link_tag_with_query_and_no_name - link = link_to(nil, "http://www.example.com?q1=v1&q2=v2") expected = %{http://www.example.com?q1=v1&q2=v2} - assert_dom_equal expected, link + assert_dom_equal expected, link_to(nil, "http://www.example.com?q1=v1&q2=v2") end def test_link_tag_with_back From ccbb3bb3d87a48c8763a8afff4c9b21a9bf2539e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 30 Jun 2010 11:33:15 +0200 Subject: [PATCH 63/71] Clean up the logic to specify the name and path for action a bit. --- .../lib/action_dispatch/routing/mapper.rb | 138 +++++++----------- 1 file changed, 51 insertions(+), 87 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 62fb7977cc..e6855d10d3 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -433,12 +433,14 @@ module ActionDispatch end module Resources + # CANONICAL_ACTIONS holds all actions that does not need a prefix or + # a path appended since they fit properly in their scope level. + VALID_ON_OPTIONS = [:new, :collection, :member] + CANONICAL_ACTIONS = [:index, :create, :new, :show, :update, :destroy] MERGE_FROM_SCOPE_OPTIONS = [:shallow, :constraints] class Resource #:nodoc: - def self.default_actions - [:index, :create, :new, :show, :update, :destroy, :edit] - end + DEFAULT_ACTIONS = [:index, :create, :new, :show, :update, :destroy, :edit] attr_reader :controller, :path, :options @@ -451,7 +453,7 @@ module ActionDispatch end def default_actions - self.class.default_actions + self.class::DEFAULT_ACTIONS end def actions @@ -535,8 +537,8 @@ module ActionDispatch ["#{path}/:id", options] end - def new_scope - [path] + def new_scope(new_path) + ["#{path}/#{new_path}"] end def nested_scope @@ -545,9 +547,7 @@ module ActionDispatch end class SingletonResource < Resource #:nodoc: - def self.default_actions - [:show, :create, :update, :destroy, :new, :edit] - end + DEFAULT_ACTIONS = [:show, :create, :update, :destroy, :new, :edit] def initialize(entities, options) @name = entities.to_s @@ -602,9 +602,12 @@ module ActionDispatch yield if block_given? collection_scope do - post :create if parent_resource.actions.include?(:create) - get :new if parent_resource.actions.include?(:new) - end + post :create + end if parent_resource.actions.include?(:create) + + new_scope do + get :new + end if parent_resource.actions.include?(:new) member_scope do get :show if parent_resource.actions.include?(:show) @@ -630,9 +633,12 @@ module ActionDispatch collection_scope do get :index if parent_resource.actions.include?(:index) post :create if parent_resource.actions.include?(:create) - get :new if parent_resource.actions.include?(:new) end + new_scope do + get :new + end if parent_resource.actions.include?(:new) + member_scope do get :show if parent_resource.actions.include?(:show) put :update if parent_resource.actions.include?(:update) @@ -669,12 +675,8 @@ module ActionDispatch raise ArgumentError, "can't use new outside resource(s) scope" end - with_scope_level(:new) do - scope(*parent_resource.new_scope) do - scope(action_path(:new)) do - yield - end - end + new_scope do + yield end end @@ -716,7 +718,6 @@ module ActionDispatch def match(*args) options = args.extract_options! - options[:anchor] = true unless options.key?(:anchor) if args.length > 1 @@ -724,17 +725,12 @@ module ActionDispatch return self end - if [:collection, :member, :new].include?(options[:on]) + on = options.delete(:on) + if VALID_ON_OPTIONS.include?(on) args.push(options) - - case options.delete(:on) - when :collection - return collection { match(*args) } - when :member - return member { match(*args) } - when :new - return new { match(*args) } - end + return send(on){ match(*args) } + elsif on + raise ArgumentError, "Unknown scope #{on.inspect} given to :on" end if @scope[:scope_level] == :resource @@ -784,11 +780,11 @@ module ActionDispatch end protected + def parent_resource #:nodoc: @scope[:scope_level_resource] end - private def apply_common_behavior_for(method, resources, options, &block) if resources.length > 1 resources.each { |r| send(method, r, options, &block) } @@ -854,6 +850,14 @@ module ActionDispatch end end + def new_scope + with_scope_level(:new) do + scope(*parent_resource.new_scope(action_path(:new))) do + yield + end + end + end + def collection_scope with_scope_level(:collection) do scope(*parent_resource.collection_scope) do @@ -871,34 +875,13 @@ module ActionDispatch end def path_for_action(action, path) - case action - when :index, :create - "#{@scope[:path]}(.:format)" - when :show, :update, :destroy - if parent_resource.shallow? - "#{@scope[:shallow_path]}/#{parent_resource.path}/:id(.:format)" - else - "#{@scope[:path]}(.:format)" - end - when :new - "#{@scope[:path]}/#{action_path(:new)}(.:format)" - when :edit - if parent_resource.shallow? - "#{@scope[:shallow_path]}/#{parent_resource.path}/:id/#{action_path(:edit)}(.:format)" - else - "#{@scope[:path]}/#{action_path(:edit)}(.:format)" - end + prefix = parent_resource.shallow? && @scope[:scope_level] == :member ? + "#{@scope[:shallow_path]}/#{parent_resource.path}/:id" : @scope[:path] + + if CANONICAL_ACTIONS.include?(action) + "#{prefix}(.:format)" else - case @scope[:scope_level] - when :collection, :new - "#{@scope[:path]}/#{action_path(action, path)}(.:format)" - else - if parent_resource.shallow? - "#{@scope[:shallow_path]}/#{parent_resource.path}/:id/#{action_path(action, path)}(.:format)" - else - "#{@scope[:path]}/#{action_path(action, path)}(.:format)" - end - end + "#{prefix}/#{action_path(action, path)}(.:format)" end end @@ -927,42 +910,23 @@ module ActionDispatch end def name_for_action(action) - name_prefix = @scope[:as].blank? ? "" : "#{@scope[:as]}_" - shallow_prefix = @scope[:shallow_prefix].blank? ? "" : "#{@scope[:shallow_prefix]}_" + prefix = "#{action}_" unless CANONICAL_ACTIONS.include?(action) + name_prefix = "#{@scope[:as]}_" if @scope[:as].present? - case action - when :index, :create - "#{name_prefix}#{parent_resource.collection_name}" - when :show, :update, :destroy - if parent_resource.shallow? - "#{shallow_prefix}#{parent_resource.member_name}" - else - "#{name_prefix}#{parent_resource.member_name}" - end - when :edit - if parent_resource.shallow? - "edit_#{shallow_prefix}#{parent_resource.member_name}" - else - "edit_#{name_prefix}#{parent_resource.member_name}" - end + case @scope[:scope_level] + when :collection + "#{prefix}#{name_prefix}#{parent_resource.collection_name}" when :new - "new_#{name_prefix}#{parent_resource.member_name}" + "#{prefix}new_#{name_prefix}#{parent_resource.member_name}" else - case @scope[:scope_level] - when :collection - "#{action}_#{name_prefix}#{parent_resource.collection_name}" - when :new - "#{action}_new_#{name_prefix}#{parent_resource.member_name}" + if parent_resource.shallow? + shallow_prefix = "#{@scope[:shallow_prefix]}_" if @scope[:shallow_prefix].present? + "#{prefix}#{shallow_prefix}#{parent_resource.member_name}" else - if parent_resource.shallow? - "#{action}_#{shallow_prefix}#{parent_resource.member_name}" - else - "#{action}_#{name_prefix}#{parent_resource.member_name}" - end + "#{prefix}#{name_prefix}#{parent_resource.member_name}" end end end - end include Base From 06681af518036dcc84f4565b59a0dee460b01108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 30 Jun 2010 12:34:15 +0200 Subject: [PATCH 64/71] A couple enhancements to the router: * Allow to use the get :symbol shortcut outside resources scopes as well; * Fix a bug where :action was not being picked from given options; * Giving :as option inside a resource now changes just the relative name instead of the full name; --- .../lib/action_dispatch/routing/mapper.rb | 75 ++++++++++++------- actionpack/test/dispatch/routing_test.rb | 27 +++++++ 2 files changed, 75 insertions(+), 27 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index e6855d10d3..0b4ba8c9f5 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -131,6 +131,7 @@ module ActionDispatch end defaults[:controller] ||= default_controller + defaults[:action] ||= default_action defaults.delete(:controller) if defaults[:controller].blank? defaults.delete(:action) if defaults[:action].blank? @@ -187,6 +188,12 @@ module ActionDispatch @scope[:controller].to_s end end + + def default_action + if @options[:action] + @options[:action].to_s + end + end end # Invokes Rack::Mount::Utils.normalize path and ensure that @@ -717,7 +724,7 @@ module ActionDispatch end def match(*args) - options = args.extract_options! + options = args.extract_options!.dup options[:anchor] = true unless options.key?(:anchor) if args.length > 1 @@ -739,10 +746,12 @@ module ActionDispatch end path = options.delete(:path) + action = args.first - if args.first.is_a?(Symbol) - path = path_for_action(args.first, path) - options = options_for_action(args.first, options) + if action.is_a?(Symbol) + path = path_for_action(action, path) + options[:to] ||= action + options[:as] = name_for_action(action, options[:as]) with_exclusive_scope do return super(path, options) @@ -874,11 +883,19 @@ module ActionDispatch end end + def canonical_action?(action, flag) + flag && CANONICAL_ACTIONS.include?(action) + end + + def shallow_scoping? + parent_resource && parent_resource.shallow? && @scope[:scope_level] == :member + end + def path_for_action(action, path) - prefix = parent_resource.shallow? && @scope[:scope_level] == :member ? + prefix = shallow_scoping? ? "#{@scope[:shallow_path]}/#{parent_resource.path}/:id" : @scope[:path] - if CANONICAL_ACTIONS.include?(action) + if canonical_action?(action, path.blank?) "#{prefix}(.:format)" else "#{prefix}/#{action_path(action, path)}(.:format)" @@ -886,15 +903,10 @@ module ActionDispatch end def path_for_custom_action - case @scope[:scope_level] - when :collection, :new - @scope[:path] + if shallow_scoping? + "#{@scope[:shallow_path]}/#{parent_resource.path}/:id" else - if parent_resource.shallow? - "#{@scope[:shallow_path]}/#{parent_resource.path}/:id" - else - @scope[:path] - end + @scope[:path] end end @@ -902,28 +914,37 @@ module ActionDispatch path || @scope[:path_names][name.to_sym] || name.to_s end - def options_for_action(action, options) - options.reverse_merge( - :to => action, - :as => name_for_action(action) - ) + def prefix_name_for_action(action, as) + if as.present? + "#{as}_" + elsif as + "" + elsif !canonical_action?(action, @scope[:scope_level]) + "#{action}_" + end end - def name_for_action(action) - prefix = "#{action}_" unless CANONICAL_ACTIONS.include?(action) - name_prefix = "#{@scope[:as]}_" if @scope[:as].present? + def name_for_action(action, as=nil) + prefix = prefix_name_for_action(action, as) + name_prefix = @scope[:as] + + if parent_resource + collection_name = parent_resource.collection_name + member_name = parent_resource.member_name + name_prefix = "#{name_prefix}_" if name_prefix.present? + end case @scope[:scope_level] when :collection - "#{prefix}#{name_prefix}#{parent_resource.collection_name}" + "#{prefix}#{name_prefix}#{collection_name}" when :new - "#{prefix}new_#{name_prefix}#{parent_resource.member_name}" + "#{prefix}new_#{name_prefix}#{member_name}" else - if parent_resource.shallow? + if shallow_scoping? shallow_prefix = "#{@scope[:shallow_prefix]}_" if @scope[:shallow_prefix].present? - "#{prefix}#{shallow_prefix}#{parent_resource.member_name}" + "#{prefix}#{shallow_prefix}#{member_name}" else - "#{prefix}#{name_prefix}#{parent_resource.member_name}" + "#{prefix}#{name_prefix}#{member_name}" end end end diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index b5653a391a..26bd641cd6 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -35,6 +35,13 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + scope "bookmark", :controller => "bookmarks", :as => :bookmark do + get :new, :path => "build" + post :create, :path => "create", :as => "" + put :update + get "remove", :action => :destroy, :as => :remove + end + match 'account/logout' => redirect("/logout"), :as => :logout_redirect match 'account/login', :to => redirect("/login") @@ -545,6 +552,26 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + def test_bookmarks + with_test_routes do + get '/bookmark/build' + assert_equal 'bookmarks#new', @response.body + assert_equal '/bookmark/build', new_bookmark_path + + post '/bookmark/create' + assert_equal 'bookmarks#create', @response.body + assert_equal '/bookmark/create', bookmark_path + + put '/bookmark' + assert_equal 'bookmarks#update', @response.body + assert_equal '/bookmark', update_bookmark_path + + get '/bookmark/remove' + assert_equal 'bookmarks#destroy', @response.body + assert_equal '/bookmark/remove', bookmark_remove_path + end + end + def test_admin with_test_routes do get '/admin', {}, {'REMOTE_ADDR' => '192.168.1.100'} From 13a36902718d452b31d13f2f7aba5770e51844a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 30 Jun 2010 12:38:25 +0200 Subject: [PATCH 65/71] Add missing CHANGELOG items. --- activerecord/CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 60739fbd91..a1a82fdff5 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.0.0 [RC1] (unreleased)* +* Add scoping and unscoped as the syntax to replace the old with_scope and with_exclusive_scope [José Valim] + * New rake task, db:migrate:status, displays status of migrations #4947 [Kevin Skoglund] * select and order for ActiveRecord now always concatenate nested calls. Use reorder if you want the original order to be overwritten [Santiago Pastorino] From 16cef77d37ffe3e2cdc6f7db76b4ae59ce4cbc5b Mon Sep 17 00:00:00 2001 From: James MacAulay Date: Tue, 18 May 2010 15:19:53 -0400 Subject: [PATCH 66/71] Fix AS::MB::Chars#+ to not alter self [#4646 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- .../lib/active_support/multibyte/chars.rb | 2 +- activesupport/test/multibyte_chars_test.rb | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb index c107aad6bb..1134d1ccc6 100644 --- a/activesupport/lib/active_support/multibyte/chars.rb +++ b/activesupport/lib/active_support/multibyte/chars.rb @@ -105,7 +105,7 @@ module ActiveSupport #:nodoc: # Example: # ('Café'.mb_chars + ' périferôl').to_s #=> "Café périferôl" def +(other) - self << other + chars(@wrapped_string + other) end # Like String#=~ only it returns the character offset (in codepoints) instead of the byte offset. diff --git a/activesupport/test/multibyte_chars_test.rb b/activesupport/test/multibyte_chars_test.rb index 602828ef5f..66aa22ec20 100644 --- a/activesupport/test/multibyte_chars_test.rb +++ b/activesupport/test/multibyte_chars_test.rb @@ -49,13 +49,15 @@ class MultibyteCharsTest < Test::Unit::TestCase end def test_should_concatenate - assert_equal 'ab', 'a'.mb_chars + 'b' - assert_equal 'ab', 'a' + 'b'.mb_chars - assert_equal 'ab', 'a'.mb_chars + 'b'.mb_chars + mb_a = 'a'.mb_chars + mb_b = 'b'.mb_chars + assert_equal 'ab', mb_a + 'b' + assert_equal 'ab', 'a' + mb_b + assert_equal 'ab', mb_a + mb_b - assert_equal 'ab', 'a'.mb_chars << 'b' - assert_equal 'ab', 'a' << 'b'.mb_chars - assert_equal 'ab', 'a'.mb_chars << 'b'.mb_chars + assert_equal 'ab', mb_a << 'b' + assert_equal 'ab', 'a' << mb_b + assert_equal 'abb', mb_a << mb_b end def test_consumes_utf8_strings From 4dbb6e3ff001bed14c64af3ddef87b3359a43505 Mon Sep 17 00:00:00 2001 From: Norman Clarke Date: Tue, 29 Jun 2010 23:25:17 -0300 Subject: [PATCH 67/71] Update Unicode database to 5.2.0. [#5011 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- .../lib/active_support/multibyte/unicode.rb | 2 +- .../active_support/values/unicode_tables.dat | Bin 710743 -> 813343 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/multibyte/unicode.rb b/activesupport/lib/active_support/multibyte/unicode.rb index f91e50c755..11c72d873b 100644 --- a/activesupport/lib/active_support/multibyte/unicode.rb +++ b/activesupport/lib/active_support/multibyte/unicode.rb @@ -9,7 +9,7 @@ module ActiveSupport NORMALIZATION_FORMS = [:c, :kc, :d, :kd] # The Unicode version that is supported by the implementation - UNICODE_VERSION = '5.1.0' + UNICODE_VERSION = '5.2.0' # The default normalization used for operations that require normalization. It can be set to any of the # normalizations in NORMALIZATION_FORMS. diff --git a/activesupport/lib/active_support/values/unicode_tables.dat b/activesupport/lib/active_support/values/unicode_tables.dat index 10f2cae46553ba73cd8abc867b5fbbeed332d1d7..4fe0268cca05e7912a9fdcb8ce50dbc47b8ff844 100644 GIT binary patch literal 813343 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 z�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%0DXacA^Jl3BJ@S_#psLWOVF3dm!dC~ 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 literal 710743 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

nC_R51-zn@98~=Jw2$NE=T^$#h)Mf^Nar) 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%0ArlVpyflMdF^dd67=$V3RMPm9GnLZZN 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 Nxi!q1igQxf{{vb}fpP!< From 265b7c5edfe9b60d1ab547bfef569d94df05b8e9 Mon Sep 17 00:00:00 2001 From: Alex Muntean Date: Fri, 28 May 2010 13:22:29 +0900 Subject: [PATCH 68/71] Fix ActiveSupport::Multibyte::Chars#slice for empty strings when starting offset is negative [#4717 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activesupport/lib/active_support/multibyte/chars.rb | 3 ++- activesupport/test/multibyte_chars_test.rb | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb index 1134d1ccc6..9251b26f62 100644 --- a/activesupport/lib/active_support/multibyte/chars.rb +++ b/activesupport/lib/active_support/multibyte/chars.rb @@ -318,7 +318,8 @@ module ActiveSupport #:nodoc: character = Unicode.u_unpack(@wrapped_string)[args[0]] result = character.nil? ? nil : [character].pack('U') else - result = Unicode.u_unpack(@wrapped_string).slice(*args).pack('U*') + cps = Unicode.u_unpack(@wrapped_string).slice(*args) + result = cps.nil? ? nil : cps.pack('U*') end result.nil? ? nil : chars(result) end diff --git a/activesupport/test/multibyte_chars_test.rb b/activesupport/test/multibyte_chars_test.rb index 66aa22ec20..610295fa89 100644 --- a/activesupport/test/multibyte_chars_test.rb +++ b/activesupport/test/multibyte_chars_test.rb @@ -397,6 +397,7 @@ class MultibyteCharsUTF8BehaviourTest < Test::Unit::TestCase assert_equal 'こ', @chars.slice(0) assert_equal 'わ', @chars.slice(3) assert_equal nil, ''.mb_chars.slice(-1..1) + assert_equal nil, ''.mb_chars.slice(-1, 1) assert_equal '', ''.mb_chars.slice(0..10) assert_equal 'にちわ', @chars.slice(1..3) assert_equal 'にちわ', @chars.slice(1, 3) From 9ab8cfc21ab07b9a65388ce3643e5558642dbc2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 30 Jun 2010 15:01:23 +0200 Subject: [PATCH 69/71] Improve the idiom used in multibyte chars a bit. --- activesupport/lib/active_support/multibyte/chars.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb index 9251b26f62..8823e4a5ed 100644 --- a/activesupport/lib/active_support/multibyte/chars.rb +++ b/activesupport/lib/active_support/multibyte/chars.rb @@ -316,12 +316,12 @@ module ActiveSupport #:nodoc: result = @wrapped_string.slice(*args) elsif args.size == 1 && args[0].kind_of?(Numeric) character = Unicode.u_unpack(@wrapped_string)[args[0]] - result = character.nil? ? nil : [character].pack('U') + result = character && [character].pack('U') else cps = Unicode.u_unpack(@wrapped_string).slice(*args) - result = cps.nil? ? nil : cps.pack('U*') + result = cps && cps.pack('U*') end - result.nil? ? nil : chars(result) + result && chars(result) end alias_method :[], :slice From 2eaae1f50b7fc34b90b2b7c83c55478b85d1130c Mon Sep 17 00:00:00 2001 From: bodhi Date: Wed, 30 Jun 2010 12:50:41 +1000 Subject: [PATCH 70/71] add note of which configuration option to set in deprecation warning message [#5012 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activesupport/lib/active_support/railtie.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/activesupport/lib/active_support/railtie.rb b/activesupport/lib/active_support/railtie.rb index 7970d39faf..c2deba3b1b 100644 --- a/activesupport/lib/active_support/railtie.rb +++ b/activesupport/lib/active_support/railtie.rb @@ -25,14 +25,16 @@ module ActiveSupport if defaults.key?(env) msg = "You did not specify how you would like Rails to report " \ "deprecation notices for your #{env} environment, please " \ - "set it to :#{defaults[env]} at config/environments/#{env}.rb" + "set config.active_support.deprecation to :#{defaults[env]} " \ + "at config/environments/#{env}.rb" warn msg ActiveSupport::Deprecation.behavior = defaults[env] else msg = "You did not specify how you would like Rails to report " \ "deprecation notices for your #{env} environment, please " \ - "set it to :log, :notify or :stderr at config/environments/#{env}.rb" + "set config.active_support.deprecation to :log, :notify or " \ + ":stderr at config/environments/#{env}.rb" warn msg ActiveSupport::Deprecation.behavior = :stderr @@ -55,4 +57,4 @@ module ActiveSupport Time.zone_default = zone_default end end -end \ No newline at end of file +end From b07e6fdaa0aa07016d1425ada5b7f966142d0212 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 30 Jun 2010 10:38:37 -0700 Subject: [PATCH 71/71] Support any mysql-like adapter --- .../lib/active_record/railties/databases.rake | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index cfa84cbb76..7882f05d07 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -57,7 +57,7 @@ namespace :db do end rescue case config['adapter'] - when 'mysql' + when /mysql/ @charset = ENV['CHARSET'] || 'utf8' @collation = ENV['COLLATION'] || 'utf8_unicode_ci' creation_options = {:charset => (config['charset'] || @charset), :collation => (config['collation'] || @collation)} @@ -224,7 +224,7 @@ namespace :db do task :charset => :environment do config = ActiveRecord::Base.configurations[Rails.env || 'development'] case config['adapter'] - when 'mysql' + when /mysql/ ActiveRecord::Base.establish_connection(config) puts ActiveRecord::Base.connection.charset when 'postgresql' @@ -242,7 +242,7 @@ namespace :db do task :collation => :environment do config = ActiveRecord::Base.configurations[Rails.env || 'development'] case config['adapter'] - when 'mysql' + when /mysql/ ActiveRecord::Base.establish_connection(config) puts ActiveRecord::Base.connection.collation else @@ -343,7 +343,7 @@ namespace :db do task :dump => :environment do abcs = ActiveRecord::Base.configurations case abcs[Rails.env]["adapter"] - when "mysql", "oci", "oracle" + when /mysql/, "oci", "oracle" ActiveRecord::Base.establish_connection(abcs[Rails.env]) File.open("#{Rails.root}/db/#{Rails.env}_structure.sql", "w+") { |f| f << ActiveRecord::Base.connection.structure_dump } when "postgresql" @@ -391,7 +391,7 @@ namespace :db do task :clone_structure => [ "db:structure:dump", "db:test:purge" ] do abcs = ActiveRecord::Base.configurations case abcs["test"]["adapter"] - when "mysql" + when /mysql/ ActiveRecord::Base.establish_connection(:test) ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0') IO.readlines("#{Rails.root}/db/#{Rails.env}_structure.sql").join.split("\n\n").each do |table| @@ -425,7 +425,7 @@ namespace :db do task :purge => :environment do abcs = ActiveRecord::Base.configurations case abcs["test"]["adapter"] - when "mysql" + when /mysql/ ActiveRecord::Base.establish_connection(:test) ActiveRecord::Base.connection.recreate_database(abcs["test"]["database"], abcs["test"]) when "postgresql" @@ -481,7 +481,7 @@ task 'test:prepare' => 'db:test:prepare' def drop_database(config) case config['adapter'] - when 'mysql' + when /mysql/ ActiveRecord::Base.establish_connection(config) ActiveRecord::Base.connection.drop_database config['database'] when /^sqlite/