From 933697a5fc5f4c56c4fd7fbbd31b8973df9c1054 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 2 Jun 2008 09:12:00 -0700 Subject: [PATCH 01/75] Try replacing _erbout with @output_buffer --- actionpack/lib/action_view/base.rb | 5 +- .../lib/action_view/helpers/capture_helper.rb | 56 +++++-------------- .../action_view/helpers/javascript_helper.rb | 2 +- .../lib/action_view/helpers/tag_helper.rb | 2 +- .../lib/action_view/helpers/text_helper.rb | 8 ++- .../lib/action_view/template_handlers/erb.rb | 6 +- 6 files changed, 25 insertions(+), 54 deletions(-) diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index f398756550..5fae2d4dd6 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -178,10 +178,7 @@ module ActionView #:nodoc: # that alert()s the caught exception (and then re-raises it). @@debug_rjs = false cattr_accessor :debug_rjs - - @@erb_variable = '_erbout' - cattr_accessor :erb_variable - + attr_internal :request delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers, diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index 9ea06568cf..f9a73a4c8d 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -31,20 +31,13 @@ module ActionView # # def capture(*args, &block) - # execute the block - begin - buffer = eval(ActionView::Base.erb_variable, block.binding) - rescue - buffer = nil - end - - if buffer.nil? - capture_block(*args, &block).to_s - else - capture_erb_with_buffer(buffer, *args, &block).to_s - end + @output_buffer, old_buffer = '', @output_buffer + yield *args + @output_buffer + ensure + @output_buffer = old_buffer end - + # Calling content_for stores a block of markup in an identifier for later use. # You can make subsequent calls to the stored content in other templates or the layout # by passing the identifier as an argument to yield. @@ -121,40 +114,19 @@ module ActionView # named @content_for_#{name_of_the_content_block}. The preferred usage is now # <%= yield :footer %>. def content_for(name, content = nil, &block) - existing_content_for = instance_variable_get("@content_for_#{name}").to_s - new_content_for = existing_content_for + (block_given? ? capture(&block) : content) - instance_variable_set("@content_for_#{name}", new_content_for) + ivar = "@content_for_#{name}" + instance_variable_set("@content_for_#{name}", "#{instance_variable_get(ivar)}#{block_given? ? capture(&block) : content}") end private - def capture_block(*args, &block) - block.call(*args) - end - - def capture_erb(*args, &block) - buffer = eval(ActionView::Base.erb_variable, block.binding) - capture_erb_with_buffer(buffer, *args, &block) - end - - def capture_erb_with_buffer(buffer, *args, &block) - pos = buffer.length - block.call(*args) - - # extract the block - data = buffer[pos..-1] - - # replace it in the original with empty string - buffer[pos..-1] = '' - - data - end - def erb_content_for(name, &block) - eval "@content_for_#{name} = (@content_for_#{name} || '') + capture_erb(&block)" + ivar = "@content_for_#{name}" + instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{capture(&block)}") end - - def block_content_for(name, &block) - eval "@content_for_#{name} = (@content_for_#{name} || '') + capture_block(&block)" + + def block_content_for(name) + ivar = "@content_for_#{name}" + instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{yield}") end end end diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb index 1ea3cbd74e..8c880dee2f 100644 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ b/actionpack/lib/action_view/helpers/javascript_helper.rb @@ -208,7 +208,7 @@ module ActionView private def block_is_within_action_view?(block) - eval("defined? _erbout", block.binding) + !@output_buffer.nil? end end diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb index 999cbfb52a..df3d69c0d8 100644 --- a/actionpack/lib/action_view/helpers/tag_helper.rb +++ b/actionpack/lib/action_view/helpers/tag_helper.rb @@ -126,7 +126,7 @@ module ActionView end def block_is_within_action_view?(block) - eval("defined? _erbout", block.binding) + !@output_buffer.nil? end end end diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 669a285424..4711b84ae7 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -25,8 +25,12 @@ module ActionView # end # # will either display "Logged in!" or a login link # %> - def concat(string, binding) - eval(ActionView::Base.erb_variable, binding) << string + def concat(string, binding = nil) + if @output_buffer + @output_buffer << string + else + string + end end if RUBY_VERSION < '1.9' diff --git a/actionpack/lib/action_view/template_handlers/erb.rb b/actionpack/lib/action_view/template_handlers/erb.rb index 15a9064461..d1416b89d1 100644 --- a/actionpack/lib/action_view/template_handlers/erb.rb +++ b/actionpack/lib/action_view/template_handlers/erb.rb @@ -43,13 +43,11 @@ module ActionView include Compilable def compile(template) - ::ERB.new(template.source, nil, @view.erb_trim_mode).src + ::ERB.new(template.source, nil, @view.erb_trim_mode, '@output_buffer').src end def cache_fragment(block, name = {}, options = nil) #:nodoc: - @view.fragment_for(block, name, options) do - eval(ActionView::Base.erb_variable, block.binding) - end + @view.fragment_for(block, name, options) { @view.output_buffer } end end end From 0bdb7d353b4ac6f5470884360f9a480a16bd709c Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 2 Jun 2008 13:32:58 -0700 Subject: [PATCH 02/75] Work with @output_buffer instead of _erbout --- actionpack/lib/action_view/base.rb | 11 +- .../lib/action_view/helpers/capture_helper.rb | 18 +- .../action_view/template_handlers/builder.rb | 7 +- .../lib/action_view/template_handlers/erb.rb | 2 +- actionpack/test/controller/caching_test.rb | 4 +- actionpack/test/template/date_helper_test.rb | 12 +- actionpack/test/template/form_helper_test.rb | 260 +++++++++--------- .../test/template/form_options_helper_test.rb | 18 +- .../test/template/form_tag_helper_test.rb | 30 +- .../test/template/javascript_helper_test.rb | 12 +- .../test/template/prototype_helper_test.rb | 26 +- .../test/template/record_tag_helper_test.rb | 14 +- actionpack/test/template/tag_helper_test.rb | 12 +- 13 files changed, 220 insertions(+), 206 deletions(-) diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 5fae2d4dd6..7a603f150f 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -156,10 +156,12 @@ module ActionView #:nodoc: attr_reader :finder attr_accessor :base_path, :assigns, :template_extension, :first_render attr_accessor :controller - + attr_writer :template_format attr_accessor :current_render_extension + attr_accessor :output_buffer + # Specify trim mode for the ERB compiler. Defaults to '-'. # See ERb documentation for suitable values. @@erb_trim_mode = '-' @@ -313,9 +315,10 @@ If you are rendering a subtemplate, you must now use controller-like partial syn private def wrap_content_for_layout(content) - original_content_for_layout = @content_for_layout - @content_for_layout = content - returning(yield) { @content_for_layout = original_content_for_layout } + original_content_for_layout, @content_for_layout = @content_for_layout, content + yield + ensure + @content_for_layout = original_content_for_layout end # Evaluate the local assigns and pushes them to the view. diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index f9a73a4c8d..837305d96c 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -31,11 +31,11 @@ module ActionView # # def capture(*args, &block) - @output_buffer, old_buffer = '', @output_buffer - yield *args - @output_buffer - ensure - @output_buffer = old_buffer + if @output_buffer + with_temporary_output_buffer { yield *args } + else + block.call(*args) + end end # Calling content_for stores a block of markup in an identifier for later use. @@ -119,6 +119,14 @@ module ActionView end private + def with_temporary_output_buffer + @output_buffer, old_buffer = '', @output_buffer + yield + @output_buffer + ensure + @output_buffer = old_buffer + end + def erb_content_for(name, &block) ivar = "@content_for_#{name}" instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{capture(&block)}") diff --git a/actionpack/lib/action_view/template_handlers/builder.rb b/actionpack/lib/action_view/template_handlers/builder.rb index f76d89777a..ee02ce1a6f 100644 --- a/actionpack/lib/action_view/template_handlers/builder.rb +++ b/actionpack/lib/action_view/template_handlers/builder.rb @@ -11,10 +11,11 @@ module ActionView def compile(template) content_type_handler = (@view.send!(:controller).respond_to?(:response) ? "controller.response" : "controller") + "#{content_type_handler}.content_type ||= Mime::XML\n" + - "xml = ::Builder::XmlMarkup.new(:indent => 2)\n" + - template.source + - "\nxml.target!\n" + "xml = ::Builder::XmlMarkup.new(:indent => 2)\n" + + template.source + + "\nxml.target!\n" end def cache_fragment(block, name = {}, options = nil) diff --git a/actionpack/lib/action_view/template_handlers/erb.rb b/actionpack/lib/action_view/template_handlers/erb.rb index d1416b89d1..ad4ccc7c42 100644 --- a/actionpack/lib/action_view/template_handlers/erb.rb +++ b/actionpack/lib/action_view/template_handlers/erb.rb @@ -47,7 +47,7 @@ module ActionView end def cache_fragment(block, name = {}, options = nil) #:nodoc: - @view.fragment_for(block, name, options) { @view.output_buffer } + @view.fragment_for(block, name, options) { @view.response.template.output_buffer ||= '' } end end end diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index f9b6b87bc6..d0ee93cf3f 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -421,6 +421,8 @@ class FragmentCachingTest < Test::Unit::TestCase @controller.request = @request @controller.response = @response @controller.send(:initialize_current_url) + @controller.send(:initialize_template_class, @response) + @controller.send(:assign_shortcuts, @request, @response) end def test_fragment_cache_key @@ -510,7 +512,7 @@ class FragmentCachingTest < Test::Unit::TestCase def test_cache_erb_fragment @store.write('views/expensive', 'fragment content') - _erbout = 'generated till now -> ' + @controller.template.output_buffer = 'generated till now -> ' assert_equal( 'generated till now -> fragment content', ActionView::TemplateHandlers::ERB.new(@controller).cache_fragment(Proc.new{ }, 'expensive')) diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb index 0a7b19ba96..3399b03dd2 100755 --- a/actionpack/test/template/date_helper_test.rb +++ b/actionpack/test/template/date_helper_test.rb @@ -1002,17 +1002,17 @@ class DateHelperTest < ActionView::TestCase @post = Post.new @post.written_on = Date.new(2004, 6, 15) - _erbout = '' + @output_buffer = '' fields_for :post, @post do |f| - _erbout.concat f.date_select(:written_on) + @output_buffer.concat f.date_select(:written_on) end expected = "\n" expected << "\n" expected << "\n" - assert_dom_equal(expected, _erbout) + assert_dom_equal(expected, @output_buffer) end def test_date_select_with_index @@ -1287,10 +1287,10 @@ class DateHelperTest < ActionView::TestCase @post = Post.new @post.updated_at = Time.local(2004, 6, 15, 16, 35) - _erbout = '' + @output_buffer = '' fields_for :post, @post do |f| - _erbout.concat f.datetime_select(:updated_at) + @output_buffer.concat f.datetime_select(:updated_at) end expected = "\n" @@ -1299,7 +1299,7 @@ class DateHelperTest < ActionView::TestCase expected << " — \n" expected << " : \n" - assert_dom_equal(expected, _erbout) + assert_dom_equal(expected, @output_buffer) end def test_date_select_with_zero_value_and_no_start_year diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index af99e6243d..65984fac44 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -337,14 +337,14 @@ class FormHelperTest < ActionView::TestCase end def test_form_for - _erbout = '' + @output_buffer = '' form_for(:post, @post, :html => { :id => 'create-post' }) do |f| - _erbout.concat f.label(:title) - _erbout.concat f.text_field(:title) - _erbout.concat f.text_area(:body) - _erbout.concat f.check_box(:secret) - _erbout.concat f.submit('Create post') + @output_buffer.concat f.label(:title) + @output_buffer.concat f.text_field(:title) + @output_buffer.concat f.text_area(:body) + @output_buffer.concat f.check_box(:secret) + @output_buffer.concat f.submit('Create post') end expected = @@ -357,16 +357,16 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_form_for_with_method - _erbout = '' + @output_buffer = '' form_for(:post, @post, :html => { :id => 'create-post', :method => :put }) do |f| - _erbout.concat f.text_field(:title) - _erbout.concat f.text_area(:body) - _erbout.concat f.check_box(:secret) + @output_buffer.concat f.text_field(:title) + @output_buffer.concat f.text_area(:body) + @output_buffer.concat f.check_box(:secret) end expected = @@ -378,16 +378,16 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_form_for_without_object - _erbout = '' + @output_buffer = '' form_for(:post, :html => { :id => 'create-post' }) do |f| - _erbout.concat f.text_field(:title) - _erbout.concat f.text_area(:body) - _erbout.concat f.check_box(:secret) + @output_buffer.concat f.text_field(:title) + @output_buffer.concat f.text_area(:body) + @output_buffer.concat f.check_box(:secret) end expected = @@ -398,17 +398,17 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_form_for_with_index - _erbout = '' + @output_buffer = '' form_for("post[]", @post) do |f| - _erbout.concat f.label(:title) - _erbout.concat f.text_field(:title) - _erbout.concat f.text_area(:body) - _erbout.concat f.check_box(:secret) + @output_buffer.concat f.label(:title) + @output_buffer.concat f.text_field(:title) + @output_buffer.concat f.text_area(:body) + @output_buffer.concat f.check_box(:secret) end expected = @@ -420,16 +420,16 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_form_for_with_nil_index_option_override - _erbout = '' + @output_buffer = '' form_for("post[]", @post, :index => nil) do |f| - _erbout.concat f.text_field(:title) - _erbout.concat f.text_area(:body) - _erbout.concat f.check_box(:secret) + @output_buffer.concat f.text_field(:title) + @output_buffer.concat f.text_area(:body) + @output_buffer.concat f.check_box(:secret) end expected = @@ -440,14 +440,14 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_nested_fields_for - _erbout = '' + @output_buffer = '' form_for(:post, @post) do |f| f.fields_for(:comment, @post) do |c| - _erbout.concat c.text_field(:title) + @output_buffer.concat c.text_field(:title) end end @@ -455,16 +455,16 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_fields_for - _erbout = '' + @output_buffer = '' fields_for(:post, @post) do |f| - _erbout.concat f.text_field(:title) - _erbout.concat f.text_area(:body) - _erbout.concat f.check_box(:secret) + @output_buffer.concat f.text_field(:title) + @output_buffer.concat f.text_area(:body) + @output_buffer.concat f.check_box(:secret) end expected = @@ -473,16 +473,16 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_fields_for_with_index - _erbout = '' + @output_buffer = '' fields_for("post[]", @post) do |f| - _erbout.concat f.text_field(:title) - _erbout.concat f.text_area(:body) - _erbout.concat f.check_box(:secret) + @output_buffer.concat f.text_field(:title) + @output_buffer.concat f.text_area(:body) + @output_buffer.concat f.check_box(:secret) end expected = @@ -491,16 +491,16 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_fields_for_with_nil_index_option_override - _erbout = '' + @output_buffer = '' fields_for("post[]", @post, :index => nil) do |f| - _erbout.concat f.text_field(:title) - _erbout.concat f.text_area(:body) - _erbout.concat f.check_box(:secret) + @output_buffer.concat f.text_field(:title) + @output_buffer.concat f.text_area(:body) + @output_buffer.concat f.check_box(:secret) end expected = @@ -509,16 +509,16 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_fields_for_with_index_option_override - _erbout = '' + @output_buffer = '' fields_for("post[]", @post, :index => "abc") do |f| - _erbout.concat f.text_field(:title) - _erbout.concat f.text_area(:body) - _erbout.concat f.check_box(:secret) + @output_buffer.concat f.text_field(:title) + @output_buffer.concat f.text_area(:body) + @output_buffer.concat f.check_box(:secret) end expected = @@ -527,15 +527,15 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_fields_for_without_object - _erbout = '' + @output_buffer = '' fields_for(:post) do |f| - _erbout.concat f.text_field(:title) - _erbout.concat f.text_area(:body) - _erbout.concat f.check_box(:secret) + @output_buffer.concat f.text_field(:title) + @output_buffer.concat f.text_area(:body) + @output_buffer.concat f.check_box(:secret) end expected = @@ -544,15 +544,15 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_fields_for_with_only_object - _erbout = '' + @output_buffer = '' fields_for(@post) do |f| - _erbout.concat f.text_field(:title) - _erbout.concat f.text_area(:body) - _erbout.concat f.check_box(:secret) + @output_buffer.concat f.text_field(:title) + @output_buffer.concat f.text_area(:body) + @output_buffer.concat f.check_box(:secret) end expected = @@ -561,31 +561,31 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_fields_for_object_with_bracketed_name - _erbout = '' + @output_buffer = '' fields_for("author[post]", @post) do |f| - _erbout.concat f.label(:title) - _erbout.concat f.text_field(:title) + @output_buffer.concat f.label(:title) + @output_buffer.concat f.text_field(:title) end assert_dom_equal "" + "", - _erbout + @output_buffer end def test_fields_for_object_with_bracketed_name_and_index - _erbout = '' + @output_buffer = '' fields_for("author[post]", @post, :index => 1) do |f| - _erbout.concat f.label(:title) - _erbout.concat f.text_field(:title) + @output_buffer.concat f.label(:title) + @output_buffer.concat f.text_field(:title) end assert_dom_equal "" + "", - _erbout + @output_buffer end def test_form_builder_does_not_have_form_for_method @@ -593,14 +593,14 @@ class FormHelperTest < ActionView::TestCase end def test_form_for_and_fields_for - _erbout = '' + @output_buffer = '' form_for(:post, @post, :html => { :id => 'create-post' }) do |post_form| - _erbout.concat post_form.text_field(:title) - _erbout.concat post_form.text_area(:body) + @output_buffer.concat post_form.text_field(:title) + @output_buffer.concat post_form.text_area(:body) fields_for(:parent_post, @post) do |parent_fields| - _erbout.concat parent_fields.check_box(:secret) + @output_buffer.concat parent_fields.check_box(:secret) end end @@ -612,18 +612,18 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_form_for_and_fields_for_with_object - _erbout = '' + @output_buffer = '' form_for(:post, @post, :html => { :id => 'create-post' }) do |post_form| - _erbout.concat post_form.text_field(:title) - _erbout.concat post_form.text_area(:body) + @output_buffer.concat post_form.text_field(:title) + @output_buffer.concat post_form.text_area(:body) post_form.fields_for(@comment) do |comment_fields| - _erbout.concat comment_fields.text_field(:name) + @output_buffer.concat comment_fields.text_field(:name) end end @@ -634,7 +634,7 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end class LabelledFormBuilder < ActionView::Helpers::FormBuilder @@ -649,12 +649,12 @@ class FormHelperTest < ActionView::TestCase end def test_form_for_with_labelled_builder - _erbout = '' + @output_buffer = '' form_for(:post, @post, :builder => LabelledFormBuilder) do |f| - _erbout.concat f.text_field(:title) - _erbout.concat f.text_area(:body) - _erbout.concat f.check_box(:secret) + @output_buffer.concat f.text_field(:title) + @output_buffer.concat f.text_area(:body) + @output_buffer.concat f.check_box(:secret) end expected = @@ -665,18 +665,18 @@ class FormHelperTest < ActionView::TestCase "
" + "" - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_default_form_builder old_default_form_builder, ActionView::Base.default_form_builder = ActionView::Base.default_form_builder, LabelledFormBuilder - _erbout = '' + @output_buffer = '' form_for(:post, @post) do |f| - _erbout.concat f.text_field(:title) - _erbout.concat f.text_area(:body) - _erbout.concat f.check_box(:secret) + @output_buffer.concat f.text_field(:title) + @output_buffer.concat f.text_area(:body) + @output_buffer.concat f.check_box(:secret) end expected = @@ -687,17 +687,17 @@ class FormHelperTest < ActionView::TestCase "
" + "" - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer ensure ActionView::Base.default_form_builder = old_default_form_builder end def test_default_form_builder_with_active_record_helpers - _erbout = '' + @output_buffer = '' form_for(:post, @post) do |f| - _erbout.concat f.error_message_on('author_name') - _erbout.concat f.error_messages + @output_buffer.concat f.error_message_on('author_name') + @output_buffer.concat f.error_messages end expected = %(
) + @@ -705,7 +705,7 @@ class FormHelperTest < ActionView::TestCase %(

1 error prohibited this post from being saved

There were problems with the following fields:

  • Author name can't be empty
) + %(
) - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end @@ -713,10 +713,10 @@ class FormHelperTest < ActionView::TestCase post = @post @post = nil - _erbout = '' + @output_buffer = '' form_for(:post, post) do |f| - _erbout.concat f.error_message_on('author_name') - _erbout.concat f.error_messages + @output_buffer.concat f.error_message_on('author_name') + @output_buffer.concat f.error_messages end expected = %(
) + @@ -724,19 +724,19 @@ class FormHelperTest < ActionView::TestCase %(

1 error prohibited this post from being saved

There were problems with the following fields:

  • Author name can't be empty
) + %(
) - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end # Perhaps this test should be moved to prototype helper tests. def test_remote_form_for_with_labelled_builder self.extend ActionView::Helpers::PrototypeHelper - _erbout = '' + @output_buffer = '' remote_form_for(:post, @post, :builder => LabelledFormBuilder) do |f| - _erbout.concat f.text_field(:title) - _erbout.concat f.text_area(:body) - _erbout.concat f.check_box(:secret) + @output_buffer.concat f.text_field(:title) + @output_buffer.concat f.text_area(:body) + @output_buffer.concat f.check_box(:secret) end expected = @@ -747,16 +747,16 @@ class FormHelperTest < ActionView::TestCase "
" + "" - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_fields_for_with_labelled_builder - _erbout = '' + @output_buffer = '' fields_for(:post, @post, :builder => LabelledFormBuilder) do |f| - _erbout.concat f.text_field(:title) - _erbout.concat f.text_area(:body) - _erbout.concat f.check_box(:secret) + @output_buffer.concat f.text_field(:title) + @output_buffer.concat f.text_area(:body) + @output_buffer.concat f.check_box(:secret) end expected = @@ -765,28 +765,28 @@ class FormHelperTest < ActionView::TestCase " " + "
" - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_form_for_with_html_options_adds_options_to_form_tag - _erbout = '' + @output_buffer = '' form_for(:post, @post, :html => {:id => 'some_form', :class => 'some_class'}) do |f| end expected = "
" - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_form_for_with_string_url_option - _erbout = '' + @output_buffer = '' form_for(:post, @post, :url => 'http://www.otherdomain.com') do |f| end - assert_equal '
', _erbout + assert_equal '
', @output_buffer end def test_form_for_with_hash_url_option - _erbout = '' + @output_buffer = '' form_for(:post, @post, :url => {:controller => 'controller', :action => 'action'}) do |f| end @@ -795,25 +795,25 @@ class FormHelperTest < ActionView::TestCase end def test_form_for_with_record_url_option - _erbout = '' + @output_buffer = '' form_for(:post, @post, :url => @post) do |f| end expected = "
" - assert_equal expected, _erbout + assert_equal expected, @output_buffer end def test_form_for_with_existing_object - _erbout = '' + @output_buffer = '' form_for(@post) do |f| end expected = "
" - assert_equal expected, _erbout + assert_equal expected, @output_buffer end def test_form_for_with_new_object - _erbout = '' + @output_buffer = '' post = Post.new post.new_record = true @@ -822,64 +822,64 @@ class FormHelperTest < ActionView::TestCase form_for(post) do |f| end expected = "
" - assert_equal expected, _erbout + assert_equal expected, @output_buffer end def test_form_for_with_existing_object_in_list @post.new_record = false @comment.save - _erbout = '' + @output_buffer = '' form_for([@post, @comment]) {} expected = %(
) - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_form_for_with_new_object_in_list @post.new_record = false - _erbout = '' + @output_buffer = '' form_for([@post, @comment]) {} expected = %(
) - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_form_for_with_existing_object_and_namespace_in_list @post.new_record = false @comment.save - _erbout = '' + @output_buffer = '' form_for([:admin, @post, @comment]) {} expected = %(
) - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_form_for_with_new_object_and_namespace_in_list @post.new_record = false - _erbout = '' + @output_buffer = '' form_for([:admin, @post, @comment]) {} expected = %(
) - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_form_for_with_existing_object_and_custom_url - _erbout = '' + @output_buffer = '' form_for(@post, :url => "/super_posts") do |f| end expected = "
" - assert_equal expected, _erbout + assert_equal expected, @output_buffer end def test_remote_form_for_with_html_options_adds_options_to_form_tag self.extend ActionView::Helpers::PrototypeHelper - _erbout = '' + @output_buffer = '' remote_form_for(:post, @post, :html => {:id => 'some_form', :class => 'some_class'}) do |f| end expected = "
" - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb index 48a26deea9..3c9fb297c3 100644 --- a/actionpack/test/template/form_options_helper_test.rb +++ b/actionpack/test/template/form_options_helper_test.rb @@ -231,15 +231,15 @@ class FormOptionsHelperTest < ActionView::TestCase @post = Post.new @post.category = "" - _erbout = '' + @output_buffer = '' fields_for :post, @post do |f| - _erbout.concat f.select(:category, %w( abe hest)) + @output_buffer.concat f.select(:category, %w( abe hest)) end assert_dom_equal( "", - _erbout + @output_buffer ) end @@ -353,15 +353,15 @@ class FormOptionsHelperTest < ActionView::TestCase @post = Post.new @post.author_name = "Babe" - _erbout = '' + @output_buffer = '' fields_for :post, @post do |f| - _erbout.concat f.collection_select(:author_name, @posts, :author_name, :author_name) + @output_buffer.concat f.collection_select(:author_name, @posts, :author_name, :author_name) end assert_dom_equal( "", - _erbout + @output_buffer ) end @@ -1195,10 +1195,10 @@ COUNTRIES def test_time_zone_select_under_fields_for @firm = Firm.new("D") - _erbout = '' + @output_buffer = '' fields_for :firm, @firm do |f| - _erbout.concat f.time_zone_select(:time_zone) + @output_buffer.concat f.time_zone_select(:time_zone) end assert_dom_equal( @@ -1209,7 +1209,7 @@ COUNTRIES "\n" + "" + "", - _erbout + @output_buffer ) end diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index 73a8bd4d87..b281db18bd 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -43,19 +43,19 @@ class FormTagHelperTest < ActionView::TestCase end def test_form_tag_with_block - _erbout = '' - form_tag("http://example.com") { _erbout.concat "Hello world!" } + @output_buffer = '' + form_tag("http://example.com") { @output_buffer.concat "Hello world!" } expected = %(
Hello world!
) - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_form_tag_with_block_and_method - _erbout = '' - form_tag("http://example.com", :method => :put) { _erbout.concat "Hello world!" } + @output_buffer = '' + form_tag("http://example.com", :method => :put) { @output_buffer.concat "Hello world!" } expected = %(
Hello world!
) - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_hidden_field_tag @@ -234,23 +234,23 @@ class FormTagHelperTest < ActionView::TestCase end def test_field_set_tag - _erbout = '' - field_set_tag("Your details") { _erbout.concat "Hello world!" } + @output_buffer = '' + field_set_tag("Your details") { @output_buffer.concat "Hello world!" } expected = %(
Your detailsHello world!
) - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer - _erbout = '' - field_set_tag { _erbout.concat "Hello world!" } + @output_buffer = '' + field_set_tag { @output_buffer.concat "Hello world!" } expected = %(
Hello world!
) - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer - _erbout = '' - field_set_tag('') { _erbout.concat "Hello world!" } + @output_buffer = '' + field_set_tag('') { @output_buffer.concat "Hello world!" } expected = %(
Hello world!
) - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def protect_against_forgery? diff --git a/actionpack/test/template/javascript_helper_test.rb b/actionpack/test/template/javascript_helper_test.rb index f18adb990c..f136f56777 100644 --- a/actionpack/test/template/javascript_helper_test.rb +++ b/actionpack/test/template/javascript_helper_test.rb @@ -92,15 +92,15 @@ class JavaScriptHelperTest < ActionView::TestCase end def test_javascript_tag_with_block - _erbout = '' - javascript_tag { _erbout.concat "alert('hello')" } - assert_dom_equal "", _erbout + @output_buffer = '' + javascript_tag { @output_buffer.concat "alert('hello')" } + assert_dom_equal "", @output_buffer end def test_javascript_tag_with_block_and_options - _erbout = '' - javascript_tag(:id => "the_js_tag") { _erbout.concat "alert('hello')" } - assert_dom_equal "", _erbout + @output_buffer = '' + javascript_tag(:id => "the_js_tag") { @output_buffer.concat "alert('hello')" } + assert_dom_equal "", @output_buffer end def test_javascript_cdata_section diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb index 53a250f9d5..dd6f6ab741 100644 --- a/actionpack/test/template/prototype_helper_test.rb +++ b/actionpack/test/template/prototype_helper_test.rb @@ -118,52 +118,52 @@ class PrototypeHelperTest < PrototypeHelperBaseTest end def test_form_remote_tag_with_block - _erbout = '' - form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) { _erbout.concat "Hello world!" } - assert_dom_equal %(
Hello world!
), _erbout + @output_buffer = '' + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) { @output_buffer.concat "Hello world!" } + assert_dom_equal %(
Hello world!
), @output_buffer end def test_remote_form_for_with_record_identification_with_new_record - _erbout = '' + @output_buffer = '' remote_form_for(@record, {:html => { :id => 'create-author' }}) {} expected = %(
) - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_remote_form_for_with_record_identification_without_html_options - _erbout = '' + @output_buffer = '' remote_form_for(@record) {} expected = %(
) - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_remote_form_for_with_record_identification_with_existing_record @record.save - _erbout = '' + @output_buffer = '' remote_form_for(@record) {} expected = %(
) - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_remote_form_for_with_new_object_in_list - _erbout = '' + @output_buffer = '' remote_form_for([@author, @article]) {} expected = %(
) - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_remote_form_for_with_existing_object_in_list @author.save @article.save - _erbout = '' + @output_buffer = '' remote_form_for([@author, @article]) {} expected = %(
) - assert_dom_equal expected, _erbout + assert_dom_equal expected, @output_buffer end def test_on_callbacks diff --git a/actionpack/test/template/record_tag_helper_test.rb b/actionpack/test/template/record_tag_helper_test.rb index 0afbb54f57..c39e5c69bf 100644 --- a/actionpack/test/template/record_tag_helper_test.rb +++ b/actionpack/test/template/record_tag_helper_test.rb @@ -17,37 +17,37 @@ class RecordTagHelperTest < ActionView::TestCase end def test_content_tag_for - _erbout = '' + @output_buffer = '' expected = %(
  • ) actual = content_tag_for(:li, @post, :class => 'bar') { } assert_dom_equal expected, actual end def test_content_tag_for_prefix - _erbout = '' + @output_buffer = '' expected = %(
      ) actual = content_tag_for(:ul, @post, :archived) { } assert_dom_equal expected, actual end def test_content_tag_for_with_extra_html_tags - _erbout = '' + @output_buffer = '' expected = %() actual = content_tag_for(:tr, @post, {:class => "bar", :style => "background-color: #f0f0f0"}) { } assert_dom_equal expected, actual end def test_block_works_with_content_tag_for - _erbout = '' + @output_buffer = '' expected = %(#{@post.body}) - actual = content_tag_for(:tr, @post) { _erbout.concat @post.body } + actual = content_tag_for(:tr, @post) { @output_buffer.concat @post.body } assert_dom_equal expected, actual end def test_div_for - _erbout = '' + @output_buffer = '' expected = %(
      #{@post.body}
      ) - actual = div_for(@post, :class => "bar") { _erbout.concat @post.body } + actual = div_for(@post, :class => "bar") { @output_buffer.concat @post.body } assert_dom_equal expected, actual end diff --git a/actionpack/test/template/tag_helper_test.rb b/actionpack/test/template/tag_helper_test.rb index 4da6116095..7db04d178f 100644 --- a/actionpack/test/template/tag_helper_test.rb +++ b/actionpack/test/template/tag_helper_test.rb @@ -35,15 +35,15 @@ class TagHelperTest < ActionView::TestCase end def test_content_tag_with_block - _erbout = '' - content_tag(:div) { _erbout.concat "Hello world!" } - assert_dom_equal "
      Hello world!
      ", _erbout + @output_buffer = '' + content_tag(:div) { @output_buffer.concat "Hello world!" } + assert_dom_equal "
      Hello world!
      ", @output_buffer end def test_content_tag_with_block_and_options - _erbout = '' - content_tag(:div, :class => "green") { _erbout.concat "Hello world!" } - assert_dom_equal %(
      Hello world!
      ), _erbout + @output_buffer = '' + content_tag(:div, :class => "green") { @output_buffer.concat "Hello world!" } + assert_dom_equal %(
      Hello world!
      ), @output_buffer end def test_content_tag_with_block_and_options_outside_of_action_view From 4d4c8e298f5396e6b8ace0a10d7f991594aace2d Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 2 Jun 2008 13:49:14 -0700 Subject: [PATCH 03/75] Don't pass block binding to concat --- actionpack/lib/action_view/base.rb | 2 +- actionpack/lib/action_view/helpers/form_helper.rb | 4 ++-- .../lib/action_view/helpers/form_tag_helper.rb | 14 +++++++------- .../lib/action_view/helpers/javascript_helper.rb | 8 +------- .../lib/action_view/helpers/prototype_helper.rb | 4 ++-- .../lib/action_view/helpers/record_tag_helper.rb | 5 ++--- actionpack/lib/action_view/helpers/tag_helper.rb | 7 ++----- actionpack/lib/action_view/helpers/text_helper.rb | 8 ++++---- 8 files changed, 21 insertions(+), 31 deletions(-) diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 7a603f150f..ad114acc6c 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -257,7 +257,7 @@ If you are rendering a subtemplate, you must now use controller-like partial syn if partial_layout = options.delete(:layout) if block_given? wrap_content_for_layout capture(&block) do - concat(render(options.merge(:partial => partial_layout)), block.binding) + concat(render(options.merge(:partial => partial_layout))) end else wrap_content_for_layout render(options) do diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 0791feb9ac..63a932320e 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -249,9 +249,9 @@ module ActionView args.unshift object end - concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {}), proc.binding) + concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {})) fields_for(object_name, *(args << options), &proc) - concat('', proc.binding) + concat('') end def apply_form_for_options!(object_or_array, options) #:nodoc: diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index ca58f4ba26..3a97f1390f 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -407,10 +407,10 @@ module ActionView # # =>
      Your details

      def field_set_tag(legend = nil, &block) content = capture(&block) - concat(tag(:fieldset, {}, true), block.binding) - concat(content_tag(:legend, legend), block.binding) unless legend.blank? - concat(content, block.binding) - concat("", block.binding) + concat(tag(:fieldset, {}, true)) + concat(content_tag(:legend, legend)) unless legend.blank? + concat(content) + concat("") end private @@ -442,9 +442,9 @@ module ActionView def form_tag_in_block(html_options, &block) content = capture(&block) - concat(form_tag_html(html_options), block.binding) - concat(content, block.binding) - concat("", block.binding) + concat(form_tag_html(html_options)) + concat(content) + concat("") end def token_tag diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb index 8c880dee2f..a2f2577636 100644 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ b/actionpack/lib/action_view/helpers/javascript_helper.rb @@ -179,13 +179,7 @@ module ActionView content = content_or_options_with_block end - javascript_tag = content_tag("script", javascript_cdata_section(content), html_options.merge(:type => Mime::JS)) - - if block_given? && block_is_within_action_view?(block) - concat(javascript_tag, block.binding) - else - javascript_tag - end + concat(content_tag("script", javascript_cdata_section(content), html_options.merge(:type => Mime::JS))) end def javascript_cdata_section(content) #:nodoc: diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index 602832e470..ed2abba17a 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -382,9 +382,9 @@ module ActionView args.unshift object end - concat(form_remote_tag(options), proc.binding) + concat(form_remote_tag(options)) fields_for(object_name, *(args << options), &proc) - concat('', proc.binding) + concat('') end alias_method :form_remote_for, :remote_form_for diff --git a/actionpack/lib/action_view/helpers/record_tag_helper.rb b/actionpack/lib/action_view/helpers/record_tag_helper.rb index 66c596f3a9..9bb235175e 100644 --- a/actionpack/lib/action_view/helpers/record_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/record_tag_helper.rb @@ -51,9 +51,8 @@ module ActionView prefix = args.first.is_a?(Hash) ? nil : args.shift options = args.first.is_a?(Hash) ? args.shift : {} concat content_tag(tag_name, capture(&block), - options.merge({ :class => "#{dom_class(record)} #{options[:class]}".strip, :id => dom_id(record, prefix) })), - block.binding + options.merge({ :class => "#{dom_class(record)} #{options[:class]}".strip, :id => dom_id(record, prefix) })) end end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb index df3d69c0d8..e669620381 100644 --- a/actionpack/lib/action_view/helpers/tag_helper.rb +++ b/actionpack/lib/action_view/helpers/tag_helper.rb @@ -66,12 +66,9 @@ module ActionView def content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block) if block_given? options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash) - content = capture(&block) - content_tag = content_tag_string(name, content, options, escape) - block_is_within_action_view?(block) ? concat(content_tag, block.binding) : content_tag + concat(content_tag_string(name, capture(&block), options, escape)) else - content = content_or_options_with_block - content_tag_string(name, content, options, escape) + content_tag_string(name, content_or_options_with_block, options, escape) end end diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 4711b84ae7..3be4843386 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -15,17 +15,17 @@ module ActionView # # ==== Examples # <% - # concat "hello", binding + # concat "hello" # # is the equivalent of <%= "hello" %> # # if (logged_in == true): - # concat "Logged in!", binding + # concat "Logged in!" # else - # concat link_to('login', :action => login), binding + # concat link_to('login', :action => login) # end # # will either display "Logged in!" or a login link # %> - def concat(string, binding = nil) + def concat(string) if @output_buffer @output_buffer << string else From f55ad960d22337d0d92a93724f1cc3ad45200836 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Tue, 3 Jun 2008 01:10:00 -0700 Subject: [PATCH 04/75] Stack @output_buffer for nested rendering --- actionpack/lib/action_view/template_handlers/compilable.rb | 4 ++-- actionpack/test/controller/caching_test.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_view/template_handlers/compilable.rb b/actionpack/lib/action_view/template_handlers/compilable.rb index 25bd0fea7f..28c72172a0 100644 --- a/actionpack/lib/action_view/template_handlers/compilable.rb +++ b/actionpack/lib/action_view/template_handlers/compilable.rb @@ -106,7 +106,7 @@ module ActionView locals_code << "#{key} = local_assigns[:#{key}]\n" end - "def #{render_symbol}(local_assigns)\n#{locals_code}#{body}\nend" + "def #{render_symbol}(local_assigns)\nold_output_buffer = @output_buffer;#{locals_code}#{body}\nensure\n@output_buffer = old_output_buffer\nend" end # Return true if the given template was compiled for a superset of the keys in local_assigns @@ -125,4 +125,4 @@ module ActionView end end -end \ No newline at end of file +end diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index d0ee93cf3f..8b3ddc7603 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -512,7 +512,7 @@ class FragmentCachingTest < Test::Unit::TestCase def test_cache_erb_fragment @store.write('views/expensive', 'fragment content') - @controller.template.output_buffer = 'generated till now -> ' + @controller.response.template.output_buffer = 'generated till now -> ' assert_equal( 'generated till now -> fragment content', ActionView::TemplateHandlers::ERB.new(@controller).cache_fragment(Proc.new{ }, 'expensive')) From df8154c845f8fb251c58f1fd882cc221cfdcbbc2 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Thu, 5 Jun 2008 20:41:22 +0100 Subject: [PATCH 05/75] Fix that Rails::InfoController tests --- railties/test/rails_info_controller_test.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/railties/test/rails_info_controller_test.rb b/railties/test/rails_info_controller_test.rb index 17c7d9deea..e1872ebf33 100644 --- a/railties/test/rails_info_controller_test.rb +++ b/railties/test/rails_info_controller_test.rb @@ -30,6 +30,8 @@ class Rails::InfoControllerTest < Test::Unit::TestCase @controller = Rails::InfoController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new + + ActionController::Base.consider_all_requests_local = true end def test_rails_info_properties_table_rendered_for_local_request @@ -41,6 +43,8 @@ class Rails::InfoControllerTest < Test::Unit::TestCase def test_rails_info_properties_error_rendered_for_non_local_request Rails::InfoController.local_request = false + ActionController::Base.consider_all_requests_local = false + get :properties assert_tag :tag => 'p' assert_response 500 From 2e0765a00361781fb9bff2a7ca8996eab1f01bd4 Mon Sep 17 00:00:00 2001 From: Frederick Cheung Date: Thu, 5 Jun 2008 20:48:42 +0100 Subject: [PATCH 06/75] Make partial counter start from 0. Signed-off-by: Pratik Naik --- actionpack/lib/action_view/partial_template.rb | 2 +- actionpack/test/controller/new_render_test.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_view/partial_template.rb b/actionpack/lib/action_view/partial_template.rb index 1fb3aaee02..0b374db888 100644 --- a/actionpack/lib/action_view/partial_template.rb +++ b/actionpack/lib/action_view/partial_template.rb @@ -22,10 +22,10 @@ module ActionView #:nodoc: end def render_member(object) - @locals[@counter_name] += 1 @locals[:object] = @locals[@variable_name] = object template = render_template + @locals[@counter_name] += 1 @locals.delete(@variable_name) @locals.delete(:object) diff --git a/actionpack/test/controller/new_render_test.rb b/actionpack/test/controller/new_render_test.rb index 6e2c6d90c6..3b439a3b18 100644 --- a/actionpack/test/controller/new_render_test.rb +++ b/actionpack/test/controller/new_render_test.rb @@ -742,7 +742,7 @@ EOS def test_partial_collection_with_counter get :partial_collection_with_counter - assert_equal "david1mary2", @response.body + assert_equal "david0mary1", @response.body end def test_partial_collection_with_locals @@ -762,7 +762,7 @@ EOS def test_partial_collection_shorthand_with_different_types_of_records get :partial_collection_shorthand_with_different_types_of_records - assert_equal "Bonjour bad customer: mark1Bonjour good customer: craig2Bonjour bad customer: john3Bonjour good customer: zach4Bonjour good customer: brandon5Bonjour bad customer: dan6", @response.body + assert_equal "Bonjour bad customer: mark0Bonjour good customer: craig1Bonjour bad customer: john2Bonjour good customer: zach3Bonjour good customer: brandon4Bonjour bad customer: dan5", @response.body end def test_empty_partial_collection From 1dbfe9766e00282c56523f6969550494bbffbbf4 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Thu, 5 Jun 2008 23:27:27 +0100 Subject: [PATCH 07/75] Ensure render :file works inside templates --- actionmailer/lib/action_mailer/base.rb | 3 ++- actionpack/lib/action_view/base.rb | 3 ++- actionpack/test/controller/new_render_test.rb | 10 ++++++++++ .../fixtures/test/render_file_from_template.html.erb | 1 + 4 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 actionpack/test/fixtures/test/render_file_from_template.html.erb diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index e065132107..51fc6032cc 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -530,7 +530,7 @@ module ActionMailer #:nodoc: end def render_message(method_name, body) - render :file => method_name, :body => body + render :file => method_name, :body => body, :use_full_path => true end def render(opts) @@ -538,6 +538,7 @@ module ActionMailer #:nodoc: if opts[:file] && opts[:file] !~ /\// opts[:file] = "#{mailer_name}/#{opts[:file]}" end + opts[:use_full_path] = true initialize_template_class(body).render(opts) end diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index f398756550..b2fcbfa554 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -253,6 +253,7 @@ If you are rendering a subtemplate, you must now use controller-like partial syn elsif options == :update update_page(&block) elsif options.is_a?(Hash) + use_full_path = options[:use_full_path] options = options.reverse_merge(:locals => {}, :use_full_path => true) if partial_layout = options.delete(:layout) @@ -266,7 +267,7 @@ If you are rendering a subtemplate, you must now use controller-like partial syn end end elsif options[:file] - render_file(options[:file], options[:use_full_path], options[:locals]) + render_file(options[:file], use_full_path || false, options[:locals]) elsif options[:partial] && options[:collection] render_partial_collection(options[:partial], options[:collection], options[:spacer_template], options[:locals]) elsif options[:partial] diff --git a/actionpack/test/controller/new_render_test.rb b/actionpack/test/controller/new_render_test.rb index 3b439a3b18..6b83b8337e 100644 --- a/actionpack/test/controller/new_render_test.rb +++ b/actionpack/test/controller/new_render_test.rb @@ -68,6 +68,11 @@ class NewRenderTestController < ActionController::Base path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb') render :file => path end + + def render_file_from_template + @secret = 'in the sauce' + @path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb')) + end def render_file_with_locals path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_locals.erb') @@ -531,6 +536,11 @@ class NewRenderTest < Test::Unit::TestCase get :render_file_with_locals assert_equal "The secret is in the sauce\n", @response.body end + + def test_render_file_from_template + get :render_file_from_template + assert_equal "The secret is in the sauce\n", @response.body + end def test_attempt_to_access_object_method assert_raises(ActionController::UnknownAction, "No action responded to [clone]") { get :clone } diff --git a/actionpack/test/fixtures/test/render_file_from_template.html.erb b/actionpack/test/fixtures/test/render_file_from_template.html.erb new file mode 100644 index 0000000000..fde9f4bb64 --- /dev/null +++ b/actionpack/test/fixtures/test/render_file_from_template.html.erb @@ -0,0 +1 @@ +<%= render :file => @path %> \ No newline at end of file From 0ccd0b569ad4df7acc37a14531606ba6f74c69f4 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 6 Jun 2008 03:02:22 -0700 Subject: [PATCH 08/75] Fix doc typo. Move extend self so it's more immediately obvious. Require inflections from load path. --- activesupport/lib/active_support/inflector.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb index fc88d80cdb..9d549eaae1 100644 --- a/activesupport/lib/active_support/inflector.rb +++ b/activesupport/lib/active_support/inflector.rb @@ -10,6 +10,8 @@ module ActiveSupport # If you discover an incorrect inflection and require it for your application, you'll need # to correct it yourself (explained below). module Inflector + extend self + # A singleton instance of this class is yielded by Inflector.inflections, which can then be used to specify additional # inflection rules. Examples: # @@ -91,8 +93,6 @@ module ActiveSupport end end - extend self - # Yields a singleton instance of Inflector::Inflections so you can specify additional # inflector rules. # @@ -134,7 +134,7 @@ module ActiveSupport # "posts".singularize # => "post" # "octopi".singularize # => "octopus" # "sheep".singluarize # => "sheep" - # "word".singluarize # => "word" + # "word".singularize # => "word" # "the blue mailmen".singularize # => "the blue mailman" # "CamelOctopi".singularize # => "CamelOctopus" def singularize(word) @@ -307,4 +307,4 @@ module ActiveSupport end end -require File.dirname(__FILE__) + '/inflections' +require 'active_support/inflections' From c1a98209da7422965f5dd4f475603b8a3cc887e4 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 6 Jun 2008 03:03:30 -0700 Subject: [PATCH 09/75] Cache RecordIdentifier methods in Class#model_name wrapper --- .../action_controller/record_identifier.rb | 45 ++++++++++++++----- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/actionpack/lib/action_controller/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb index 643ff7e5f4..77fe5cbe2a 100644 --- a/actionpack/lib/action_controller/record_identifier.rb +++ b/actionpack/lib/action_controller/record_identifier.rb @@ -1,3 +1,19 @@ +class Class + def model_name + @model_name ||= ModelName.new(name) + end + + class ModelName + attr_reader :singular, :plural, :path + + def initialize(name) + @singular = name.underscore.tr('/', '_').freeze + @plural = @singular.pluralize.freeze + @path = "#{name.tableize}/#{name.demodulize.underscore}".freeze + end + end +end + module ActionController # The record identifier encapsulates a number of naming conventions for dealing with records, like Active Records or # Active Resources or pretty much any other model type that has an id. These patterns are then used to try elevate @@ -31,18 +47,21 @@ module ActionController module RecordIdentifier extend self + JOIN = '_'.freeze + NEW = 'new'.freeze + # Returns plural/singular for a record or class. Example: # # partial_path(post) # => "posts/post" # partial_path(Person) # => "people/person" # partial_path(Person, "admin/games") # => "admin/people/person" def partial_path(record_or_class, controller_path = nil) - klass = class_from_record_or_class(record_or_class) + name = model_name_from_record_or_class(record_or_class) if controller_path && controller_path.include?("/") - "#{File.dirname(controller_path)}/#{klass.name.tableize}/#{klass.name.demodulize.underscore}" + "#{File.dirname(controller_path)}/#{name.path}" else - "#{klass.name.tableize}/#{klass.name.demodulize.underscore}" + name.path end end @@ -56,7 +75,8 @@ module ActionController # dom_class(post, :edit) # => "edit_post" # dom_class(Person, :edit) # => "edit_person" def dom_class(record_or_class, prefix = nil) - [ prefix, singular_class_name(record_or_class) ].compact * '_' + singular = singular_class_name(record_or_class) + prefix ? "#{prefix}#{JOIN}#{singular}" : singular end # The DOM id convention is to use the singular form of an object or class with the id following an underscore. @@ -69,8 +89,11 @@ module ActionController # # dom_id(Post.new(:id => 45), :edit) # => "edit_post_45" def dom_id(record, prefix = nil) - prefix ||= 'new' unless record.id - [ prefix, singular_class_name(record), record.id ].compact * '_' + if record_id = record.id + "#{dom_class(record, prefix)}#{JOIN}#{record_id}" + else + dom_class(record, prefix || NEW) + end end # Returns the plural class name of a record or class. Examples: @@ -78,7 +101,7 @@ module ActionController # plural_class_name(post) # => "posts" # plural_class_name(Highrise::Person) # => "highrise_people" def plural_class_name(record_or_class) - singular_class_name(record_or_class).pluralize + model_name_from_record_or_class(record_or_class).plural end # Returns the singular class name of a record or class. Examples: @@ -86,12 +109,12 @@ module ActionController # singular_class_name(post) # => "post" # singular_class_name(Highrise::Person) # => "highrise_person" def singular_class_name(record_or_class) - class_from_record_or_class(record_or_class).name.underscore.tr('/', '_') + model_name_from_record_or_class(record_or_class).singular end private - def class_from_record_or_class(record_or_class) - record_or_class.is_a?(Class) ? record_or_class : record_or_class.class + def model_name_from_record_or_class(record_or_class) + (record_or_class.is_a?(Class) ? record_or_class : record_or_class.class).model_name end end -end \ No newline at end of file +end From 566d717d783f56563cd602198be2177c972c9a81 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 6 Jun 2008 03:38:05 -0700 Subject: [PATCH 10/75] Move Class::ModelName to Active Support module core_ext --- .../action_controller/record_identifier.rb | 20 ++--------------- .../lib/active_support/core_ext/module.rb | 5 +++++ .../core_ext/module/model_naming.rb | 22 +++++++++++++++++++ .../test/core_ext/module/model_naming_test.rb | 19 ++++++++++++++++ 4 files changed, 48 insertions(+), 18 deletions(-) create mode 100644 activesupport/lib/active_support/core_ext/module/model_naming.rb create mode 100644 activesupport/test/core_ext/module/model_naming_test.rb diff --git a/actionpack/lib/action_controller/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb index 77fe5cbe2a..f69c3d6163 100644 --- a/actionpack/lib/action_controller/record_identifier.rb +++ b/actionpack/lib/action_controller/record_identifier.rb @@ -1,19 +1,3 @@ -class Class - def model_name - @model_name ||= ModelName.new(name) - end - - class ModelName - attr_reader :singular, :plural, :path - - def initialize(name) - @singular = name.underscore.tr('/', '_').freeze - @plural = @singular.pluralize.freeze - @path = "#{name.tableize}/#{name.demodulize.underscore}".freeze - end - end -end - module ActionController # The record identifier encapsulates a number of naming conventions for dealing with records, like Active Records or # Active Resources or pretty much any other model type that has an id. These patterns are then used to try elevate @@ -59,9 +43,9 @@ module ActionController name = model_name_from_record_or_class(record_or_class) if controller_path && controller_path.include?("/") - "#{File.dirname(controller_path)}/#{name.path}" + "#{File.dirname(controller_path)}/#{name.partial_path}" else - name.path + name.partial_path end end diff --git a/activesupport/lib/active_support/core_ext/module.rb b/activesupport/lib/active_support/core_ext/module.rb index da8d5b3762..34fcbd124b 100644 --- a/activesupport/lib/active_support/core_ext/module.rb +++ b/activesupport/lib/active_support/core_ext/module.rb @@ -6,3 +6,8 @@ require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/module/introspection' require 'active_support/core_ext/module/loading' require 'active_support/core_ext/module/aliasing' +require 'active_support/core_ext/module/model_naming' + +class Module + include ActiveSupport::CoreExt::Module::ModelNaming +end diff --git a/activesupport/lib/active_support/core_ext/module/model_naming.rb b/activesupport/lib/active_support/core_ext/module/model_naming.rb new file mode 100644 index 0000000000..26e76ab556 --- /dev/null +++ b/activesupport/lib/active_support/core_ext/module/model_naming.rb @@ -0,0 +1,22 @@ +module ActiveSupport + class ModelName < String + attr_reader :singular, :plural, :partial_path + + def initialize(name) + super + @singular = underscore.tr('/', '_').freeze + @plural = @singular.pluralize.freeze + @partial_path = "#{tableize}/#{demodulize.underscore}".freeze + end + end + + module CoreExt + module Module + module ModelNaming + def model_name + @model_name ||= ModelName.new(name) + end + end + end + end +end diff --git a/activesupport/test/core_ext/module/model_naming_test.rb b/activesupport/test/core_ext/module/model_naming_test.rb new file mode 100644 index 0000000000..fc73fa5c36 --- /dev/null +++ b/activesupport/test/core_ext/module/model_naming_test.rb @@ -0,0 +1,19 @@ +require 'abstract_unit' + +class ModelNamingTest < Test::Unit::TestCase + def setup + @name = ActiveSupport::ModelName.new('Post::TrackBack') + end + + def test_singular + assert_equal 'post_track_back', @name.singular + end + + def test_plural + assert_equal 'post_track_backs', @name.plural + end + + def test_partial_path + assert_equal 'post/track_backs/track_back', @name.partial_path + end +end From fd40fbc1983a96587cc25729985191573a03e04c Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 6 Jun 2008 03:54:16 -0700 Subject: [PATCH 11/75] Generate less garbage when expanding range bind variables in conditions --- activerecord/lib/active_record/base.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 8dd07eb478..110902b590 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -2064,13 +2064,18 @@ module ActiveRecord #:nodoc: end def expand_range_bind_variables(bind_vars) #:nodoc: - bind_vars.sum do |var| + expanded = [] + + bind_vars.each do |var| if var.is_a?(Range) - [var.first, var.last] + expanded << var.first + expanded << var.last else - [var] + expanded << var end end + + expanded end def quote_bound_value(value) #:nodoc: From e2c49e6a59f1b969a526586a3dd4dfd9c6f12b10 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 6 Jun 2008 04:13:09 -0700 Subject: [PATCH 12/75] Drop a string conversion from the often-called tag_options helper --- actionpack/lib/action_view/helpers/tag_helper.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb index 999cbfb52a..ba43b5e8ef 100644 --- a/actionpack/lib/action_view/helpers/tag_helper.rb +++ b/actionpack/lib/action_view/helpers/tag_helper.rb @@ -1,5 +1,6 @@ require 'cgi' require 'erb' +require 'set' module ActionView module Helpers #:nodoc: @@ -8,7 +9,8 @@ module ActionView module TagHelper include ERB::Util - BOOLEAN_ATTRIBUTES = Set.new(%w(disabled readonly multiple)) + BOOLEAN_ATTRIBUTES = %w(disabled readonly multiple).to_set + BOOLEAN_ATTRIBUTES.merge(BOOLEAN_ATTRIBUTES.map(&:to_sym)) # Returns an empty HTML tag of type +name+ which by default is XHTML # compliant. Set +open+ to true to create an open tag compatible @@ -37,7 +39,7 @@ module ActionView # tag("img", { :src => "open & shut.png" }, false, false) # # => def tag(name, options = nil, open = false, escape = true) - "<#{name}#{tag_options(options, escape) if options}" + (open ? ">" : " />") + "<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}" end # Returns an HTML block tag of type +name+ surrounding the +content+. Add @@ -114,7 +116,6 @@ module ActionView if escape options.each do |key, value| next unless value - key = key.to_s value = BOOLEAN_ATTRIBUTES.include?(key) ? key : escape_once(value) attrs << %(#{key}="#{value}") end From e79d47847a75d63a66a3ed2296271fd28d41f24c Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 6 Jun 2008 13:03:59 -0700 Subject: [PATCH 13/75] Qualify Inflector in rdoc examples also. [#356 state:resolved] --- activesupport/lib/active_support/inflector.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb index 9d549eaae1..47bd6e1767 100644 --- a/activesupport/lib/active_support/inflector.rb +++ b/activesupport/lib/active_support/inflector.rb @@ -15,7 +15,7 @@ module ActiveSupport # A singleton instance of this class is yielded by Inflector.inflections, which can then be used to specify additional # inflection rules. Examples: # - # Inflector.inflections do |inflect| + # ActiveSupport::Inflector.inflections do |inflect| # inflect.plural /^(ox)$/i, '\1\2en' # inflect.singular /^(ox)en/i, '\1' # @@ -97,7 +97,7 @@ module ActiveSupport # inflector rules. # # Example: - # Inflector.inflections do |inflect| + # ActiveSupport::Inflector.inflections do |inflect| # inflect.uncountable "rails" # end def inflections From 89ea7bee3609e513b21151eb4a7991b074fc0e8f Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 7 Jun 2008 01:25:27 +0100 Subject: [PATCH 14/75] Simplify ActiveRecord::Base#update_attribute --- activerecord/lib/active_record/base.rb | 8 ++++---- activerecord/lib/active_record/validations.rb | 9 --------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 110902b590..450ea5cb33 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -2252,12 +2252,12 @@ module ActiveRecord #:nodoc: end end - # Updates a single attribute and saves the record. This is especially useful for boolean flags on existing records. - # Note: This method is overwritten by the Validation module that'll make sure that updates made with this method - # aren't subjected to validation checks. Hence, attributes can be updated even if the full object isn't valid. + # Updates a single attribute and saves the record without going through the normal validation procedure. + # This is especially useful for boolean flags on existing records. The regular +update_attribute+ method + # in Base is replaced with this when the validations module is mixed in, which it is by default. def update_attribute(name, value) send(name.to_s + '=', value) - save + save(false) end # Updates all the attributes from the passed-in Hash and saves the record. If the object is invalid, the saving will diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index c97aafb126..c4e370d017 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -277,7 +277,6 @@ module ActiveRecord base.class_eval do alias_method_chain :save, :validation alias_method_chain :save!, :validation - alias_method_chain :update_attribute, :validation_skipping end base.send :include, ActiveSupport::Callbacks @@ -914,14 +913,6 @@ module ActiveRecord end end - # Updates a single attribute and saves the record without going through the normal validation procedure. - # This is especially useful for boolean flags on existing records. The regular +update_attribute+ method - # in Base is replaced with this when the validations module is mixed in, which it is by default. - def update_attribute_with_validation_skipping(name, value) - send(name.to_s + '=', value) - save(false) - end - # Runs +validate+ and +validate_on_create+ or +validate_on_update+ and returns true if no errors were added otherwise false. def valid? errors.clear From e732a405ab7d0d04f8a254764970c9dcda988f01 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 6 Jun 2008 17:59:41 -0700 Subject: [PATCH 15/75] javascript_tag should only concat when block_given? --- .../action_view/helpers/javascript_helper.rb | 17 ++++++++++------- .../test/template/javascript_helper_test.rb | 4 ++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb index a2f2577636..85b205c264 100644 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ b/actionpack/lib/action_view/helpers/javascript_helper.rb @@ -172,14 +172,17 @@ module ActionView # alert('All is good') # <% end -%> def javascript_tag(content_or_options_with_block = nil, html_options = {}, &block) - if block_given? - html_options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash) - content = capture(&block) - else - content = content_or_options_with_block - end + content = + if block_given? + html_options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash) + capture(&block) + else + content_or_options_with_block + end - concat(content_tag("script", javascript_cdata_section(content), html_options.merge(:type => Mime::JS))) + tag = content_tag("script", javascript_cdata_section(content), html_options.merge(:type => Mime::JS)) + + block_given? ? concat(tag) : tag end def javascript_cdata_section(content) #:nodoc: diff --git a/actionpack/test/template/javascript_helper_test.rb b/actionpack/test/template/javascript_helper_test.rb index f136f56777..4924074c3e 100644 --- a/actionpack/test/template/javascript_helper_test.rb +++ b/actionpack/test/template/javascript_helper_test.rb @@ -82,8 +82,12 @@ class JavaScriptHelperTest < ActionView::TestCase end def test_javascript_tag + @output_buffer = 'foo' + assert_dom_equal "", javascript_tag("alert('hello')") + + assert_equal 'foo', @output_buffer, 'javascript_tag without a block should not concat to @output_buffer' end def test_javascript_tag_with_options From 26ec1be24a820327d00e22fb65764a3dc06977e2 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 6 Jun 2008 18:00:01 -0700 Subject: [PATCH 16/75] concat should ignore nil --- actionpack/lib/action_view/helpers/text_helper.rb | 2 +- actionpack/test/template/text_helper_test.rb | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 3be4843386..f81f7eded6 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -26,7 +26,7 @@ module ActionView # # will either display "Logged in!" or a login link # %> def concat(string) - if @output_buffer + if @output_buffer && string @output_buffer << string else string diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb index 62cdca03d1..0f5c62acad 100644 --- a/actionpack/test/template/text_helper_test.rb +++ b/actionpack/test/template/text_helper_test.rb @@ -11,6 +11,14 @@ class TextHelperTest < ActionView::TestCase @_cycles = nil if (defined? @_cycles) end + def test_concat + @output_buffer = 'foo' + concat 'bar' + assert_equal 'foobar', @output_buffer + assert_nothing_raised { concat nil } + assert_equal 'foobar', @output_buffer + end + def test_simple_format assert_equal "

      ", simple_format(nil) From fe9d2ad6e84626d34f1850ef4668a87787d5c6b0 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 6 Jun 2008 18:01:14 -0700 Subject: [PATCH 17/75] Remove some internal dead code that supported content_for --- .../lib/action_view/helpers/capture_helper.rb | 20 +++++-------------- actionpack/test/controller/capture_test.rb | 20 +------------------ .../test/fixtures/test/block_content_for.erb | 2 -- .../test/fixtures/test/erb_content_for.erb | 2 -- 4 files changed, 6 insertions(+), 38 deletions(-) delete mode 100644 actionpack/test/fixtures/test/block_content_for.erb delete mode 100644 actionpack/test/fixtures/test/erb_content_for.erb diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index 837305d96c..25e62f78fb 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -32,7 +32,7 @@ module ActionView # def capture(*args, &block) if @output_buffer - with_temporary_output_buffer { yield *args } + with_output_buffer { block.call(*args) } else block.call(*args) end @@ -115,27 +115,17 @@ module ActionView # <%= yield :footer %>. def content_for(name, content = nil, &block) ivar = "@content_for_#{name}" - instance_variable_set("@content_for_#{name}", "#{instance_variable_get(ivar)}#{block_given? ? capture(&block) : content}") + content = capture(&block) if block_given? + instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{content}") end private - def with_temporary_output_buffer - @output_buffer, old_buffer = '', @output_buffer + def with_output_buffer(buf = '') + @output_buffer, old_buffer = buf, @output_buffer yield - @output_buffer ensure @output_buffer = old_buffer end - - def erb_content_for(name, &block) - ivar = "@content_for_#{name}" - instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{capture(&block)}") - end - - def block_content_for(name) - ivar = "@content_for_#{name}" - instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{yield}") - end end end end diff --git a/actionpack/test/controller/capture_test.rb b/actionpack/test/controller/capture_test.rb index aaafea3920..2604844b84 100644 --- a/actionpack/test/controller/capture_test.rb +++ b/actionpack/test/controller/capture_test.rb @@ -11,19 +11,11 @@ class CaptureController < ActionController::Base def content_for_with_parameter render :layout => "talk_from_action" end - + def content_for_concatenated render :layout => "talk_from_action" end - def erb_content_for - render :layout => "talk_from_action" - end - - def block_content_for - render :layout => "talk_from_action" - end - def non_erb_block_content_for render :layout => "talk_from_action" end @@ -62,21 +54,11 @@ class CaptureTest < Test::Unit::TestCase assert_equal expected_content_for_output, @response.body end - def test_erb_content_for - get :erb_content_for - assert_equal expected_content_for_output, @response.body - end - def test_should_set_content_for_with_parameter get :content_for_with_parameter assert_equal expected_content_for_output, @response.body end - def test_block_content_for - get :block_content_for - assert_equal expected_content_for_output, @response.body - end - def test_non_erb_block_content_for get :non_erb_block_content_for assert_equal expected_content_for_output, @response.body diff --git a/actionpack/test/fixtures/test/block_content_for.erb b/actionpack/test/fixtures/test/block_content_for.erb deleted file mode 100644 index 9510337365..0000000000 --- a/actionpack/test/fixtures/test/block_content_for.erb +++ /dev/null @@ -1,2 +0,0 @@ -<% block_content_for :title do 'Putting stuff in the title!' end %> -Great stuff! \ No newline at end of file diff --git a/actionpack/test/fixtures/test/erb_content_for.erb b/actionpack/test/fixtures/test/erb_content_for.erb deleted file mode 100644 index c3bdd13643..0000000000 --- a/actionpack/test/fixtures/test/erb_content_for.erb +++ /dev/null @@ -1,2 +0,0 @@ -<% erb_content_for :title do %>Putting stuff in the title!<% end %> -Great stuff! \ No newline at end of file From 1d1ea92f405ab6f47942b21233da04aa21498cb7 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 6 Jun 2008 20:41:22 -0700 Subject: [PATCH 18/75] GemDependency#specification should be public --- railties/lib/rails/gem_dependency.rb | 31 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/railties/lib/rails/gem_dependency.rb b/railties/lib/rails/gem_dependency.rb index 30bdf416fc..4cac7f725a 100644 --- a/railties/lib/rails/gem_dependency.rb +++ b/railties/lib/rails/gem_dependency.rb @@ -98,27 +98,26 @@ module Rails self.name == other.name && self.requirement == other.requirement end -private ################################################################### - def specification @spec ||= Gem.source_index.search(Gem::Dependency.new(@name, @requirement)).sort_by { |s| s.version }.last end - def gem_command - RUBY_PLATFORM =~ /win32/ ? 'gem.bat' : 'gem' - end + private + def gem_command + RUBY_PLATFORM =~ /win32/ ? 'gem.bat' : 'gem' + end - def install_command - cmd = %w(install) << @name - cmd << "--version" << %("#{@requirement.to_s}") if @requirement - cmd << "--source" << @source if @source - cmd - end + def install_command + cmd = %w(install) << @name + cmd << "--version" << %("#{@requirement.to_s}") if @requirement + cmd << "--source" << @source if @source + cmd + end - def unpack_command - cmd = %w(unpack) << @name - cmd << "--version" << %("#{@requirement.to_s}") if @requirement - cmd - end + def unpack_command + cmd = %w(unpack) << @name + cmd << "--version" << %("#{@requirement.to_s}") if @requirement + cmd + end end end From 84fb971c2f3f26452fbc73467c13d039fe4c2024 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 6 Jun 2008 21:34:36 -0700 Subject: [PATCH 19/75] Remove 1.9's String#chars also --- .../active_support/core_ext/string/unicode.rb | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/string/unicode.rb b/activesupport/lib/active_support/core_ext/string/unicode.rb index 5e20534d1d..666f7bcb65 100644 --- a/activesupport/lib/active_support/core_ext/string/unicode.rb +++ b/activesupport/lib/active_support/core_ext/string/unicode.rb @@ -1,16 +1,16 @@ module ActiveSupport #:nodoc: module CoreExtensions #:nodoc: module String #:nodoc: - unless '1.9'.respond_to?(:force_encoding) - # Define methods for handling unicode data. - module Unicode - def self.append_features(base) - if '1.8.7'.respond_to?(:chars) - base.class_eval { remove_method :chars } - end - super + # Define methods for handling unicode data. + module Unicode + def self.append_features(base) + if '1.8.7 and later'.respond_to?(:chars) + base.class_eval { remove_method :chars } end + super + end + unless '1.9'.respond_to?(:force_encoding) # +chars+ is a Unicode safe proxy for string methods. It creates and returns an instance of the # ActiveSupport::Multibyte::Chars class which encapsulates the original string. A Unicode safe version of all # the String methods are defined on this proxy class. Undefined methods are forwarded to String, so all of the @@ -44,14 +44,12 @@ module ActiveSupport #:nodoc: def is_utf8? ActiveSupport::Multibyte::Handlers::UTF8Handler.consumes?(self) end - end - else - module Unicode #:nodoc: - def chars + else + def chars #:nodoc: self end - def is_utf8? + def is_utf8? #:nodoc: case encoding when Encoding::UTF_8 valid_encoding? From 5eb893f72d189a7ad82c9a6f45873e2317f202d5 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 6 Jun 2008 22:02:23 -0700 Subject: [PATCH 20/75] Don't use deprecated String#each --- actionpack/lib/action_controller/rack_process.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/actionpack/lib/action_controller/rack_process.rb b/actionpack/lib/action_controller/rack_process.rb index 37b56dabca..9b4aa9b7cf 100644 --- a/actionpack/lib/action_controller/rack_process.rb +++ b/actionpack/lib/action_controller/rack_process.rb @@ -189,6 +189,8 @@ end_msg if @body.respond_to?(:call) @writer = lambda { |x| callback.call(x) } @body.call(self, self) + elsif @body.is_a?(String) + @body.each_line(&callback) else @body.each(&callback) end From 5b53a0695904afb6a576fe5a9badbf14261909b5 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 6 Jun 2008 22:02:48 -0700 Subject: [PATCH 21/75] Ensure we have an array to collect --- actionpack/lib/action_controller/routing/segments.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_controller/routing/segments.rb b/actionpack/lib/action_controller/routing/segments.rb index 864e068004..f0ad066bad 100644 --- a/actionpack/lib/action_controller/routing/segments.rb +++ b/actionpack/lib/action_controller/routing/segments.rb @@ -249,7 +249,7 @@ module ActionController end def extract_value - "#{local_name} = hash[:#{key}] && hash[:#{key}].collect { |path_component| URI.escape(path_component.to_param, ActionController::Routing::Segment::UNSAFE_PCHAR) }.to_param #{"|| #{default.inspect}" if default}" + "#{local_name} = hash[:#{key}] && Array(hash[:#{key}]).collect { |path_component| URI.escape(path_component.to_param, ActionController::Routing::Segment::UNSAFE_PCHAR) }.to_param #{"|| #{default.inspect}" if default}" end def default From 21bb0f40b075e7b878e7ae0fd6c40c9a9ad5b00a Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 7 Jun 2008 13:39:03 -0700 Subject: [PATCH 22/75] PostgreSQL: quote bare table names --- .../active_record/connection_adapters/postgresql_adapter.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 7dbfbb41f6..049e6f61de 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -506,7 +506,7 @@ module ActiveRecord end end - execute "CREATE DATABASE #{name}#{option_string}" + execute "CREATE DATABASE #{quote_table_name(name)}#{option_string}" end # Drops a PostgreSQL database @@ -514,7 +514,7 @@ module ActiveRecord # Example: # drop_database 'matt_development' def drop_database(name) #:nodoc: - execute "DROP DATABASE IF EXISTS #{name}" + execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}" end @@ -676,7 +676,7 @@ module ActiveRecord # Renames a table. def rename_table(name, new_name) - execute "ALTER TABLE #{name} RENAME TO #{new_name}" + execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}" end # Adds a new column to the named table. From d0956335a677aeb3b78393aa6ecd05cb7e4384f4 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 7 Jun 2008 13:43:52 -0700 Subject: [PATCH 23/75] PostgreSQL: update create_database_with_encoding test also --- activerecord/test/cases/active_schema_test_postgresql.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/test/cases/active_schema_test_postgresql.rb b/activerecord/test/cases/active_schema_test_postgresql.rb index db325e3fb4..af80f724f2 100644 --- a/activerecord/test/cases/active_schema_test_postgresql.rb +++ b/activerecord/test/cases/active_schema_test_postgresql.rb @@ -13,8 +13,8 @@ class PostgresqlActiveSchemaTest < Test::Unit::TestCase end def test_create_database_with_encoding - assert_equal "CREATE DATABASE matt ENCODING = 'utf8'", create_database(:matt) - assert_equal "CREATE DATABASE aimonetti ENCODING = 'latin1'", create_database(:aimonetti, :encoding => :latin1) + assert_equal %(CREATE DATABASE "matt" ENCODING = 'utf8'), create_database(:matt) + assert_equal %(CREATE DATABASE "aimonetti" ENCODING = 'latin1'), create_database(:aimonetti, :encoding => :latin1) end private From 63679733d8217b69e242a00083abfc4cd8a9dca0 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 7 Jun 2008 17:48:44 -0700 Subject: [PATCH 24/75] Changelog: More efficient concat and capture helpers. Remove ActionView::Base.erb_variable. --- actionpack/CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 66af5fd745..8265b5b04f 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *Edge* +* More efficient concat and capture helpers. Remove ActionView::Base.erb_variable. [Jeremy Kemper] + * Added page.reload functionality. Resolves #277. [Sean Huber] * Fixed Request#remote_ip to only raise hell if the HTTP_CLIENT_IP and HTTP_X_FORWARDED_FOR doesn't match (not just if they're both present) [Mark Imbriaco, Bradford Folkens] From 67e4f16fc5303ae35bdfe9ef4ef016127751ce35 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 7 Jun 2008 18:06:45 -0700 Subject: [PATCH 25/75] No need to build a Set since we're iterating instead of checking for inclusion now --- activesupport/lib/active_support/core_ext/hash/slice.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/hash/slice.rb b/activesupport/lib/active_support/core_ext/hash/slice.rb index 1b2c8f63e3..be4dec6e53 100644 --- a/activesupport/lib/active_support/core_ext/hash/slice.rb +++ b/activesupport/lib/active_support/core_ext/hash/slice.rb @@ -1,5 +1,3 @@ -require 'set' - module ActiveSupport #:nodoc: module CoreExtensions #:nodoc: module Hash #:nodoc: @@ -14,9 +12,9 @@ module ActiveSupport #:nodoc: module Slice # Returns a new hash with only the given keys. def slice(*keys) - allowed = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys) + keys = keys.map! { |key| convert_key(key) } if respond_to?(:convert_key) hash = {} - allowed.each { |k| hash[k] = self[k] if has_key?(k) } + keys.each { |k| hash[k] = self[k] if has_key?(k) } hash end From ceb5b6dbb141888ae56788a3d40ccb7017c92f7d Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sat, 7 Jun 2008 23:25:34 -0500 Subject: [PATCH 26/75] Wrap date part value method tests inside a uses mocha block. --- .../test/core_ext/time_with_zone_test.rb | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb index 012ec373c9..0977cd8e50 100644 --- a/activesupport/test/core_ext/time_with_zone_test.rb +++ b/activesupport/test/core_ext/time_with_zone_test.rb @@ -336,24 +336,26 @@ class TimeWithZoneTest < Test::Unit::TestCase end end - def test_method_missing_with_non_time_return_value - silence_warnings do # silence warnings raised by tzinfo gem - @twz.time.expects(:foo).returns('bar') - assert_equal 'bar', @twz.foo + uses_mocha 'TestDatePartValueMethods' do + def test_method_missing_with_non_time_return_value + silence_warnings do # silence warnings raised by tzinfo gem + @twz.time.expects(:foo).returns('bar') + assert_equal 'bar', @twz.foo + end end - end - def test_date_part_value_methods - silence_warnings do # silence warnings raised by tzinfo gem - twz = ActiveSupport::TimeWithZone.new(Time.utc(1999,12,31,19,18,17,500), @time_zone) - twz.stubs(:method_missing).returns(nil) #ensure these methods are defined directly on class - assert_equal 1999, twz.year - assert_equal 12, twz.month - assert_equal 31, twz.day - assert_equal 14, twz.hour - assert_equal 18, twz.min - assert_equal 17, twz.sec - assert_equal 500, twz.usec + def test_date_part_value_methods + silence_warnings do # silence warnings raised by tzinfo gem + twz = ActiveSupport::TimeWithZone.new(Time.utc(1999,12,31,19,18,17,500), @time_zone) + twz.stubs(:method_missing).returns(nil) #ensure these methods are defined directly on class + assert_equal 1999, twz.year + assert_equal 12, twz.month + assert_equal 31, twz.day + assert_equal 14, twz.hour + assert_equal 18, twz.min + assert_equal 17, twz.sec + assert_equal 500, twz.usec + end end end From d5539958a892ece562ba3dcb36df12e046bd4879 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sat, 7 Jun 2008 23:42:05 -0500 Subject: [PATCH 27/75] Wrap CGIResponse, LegacyRouteSet, Route, RouteSet and RouteLoading tests inside mocha block. --- actionpack/test/controller/cgi_test.rb | 58 +- actionpack/test/controller/routing_test.rb | 3471 ++++++++++---------- 2 files changed, 1751 insertions(+), 1778 deletions(-) diff --git a/actionpack/test/controller/cgi_test.rb b/actionpack/test/controller/cgi_test.rb index f0f3a4b826..1b1ded4615 100755 --- a/actionpack/test/controller/cgi_test.rb +++ b/actionpack/test/controller/cgi_test.rb @@ -115,35 +115,37 @@ class CgiRequestNeedsRewoundTest < BaseCgiTest end end -class CgiResponseTest < BaseCgiTest - def setup - super - @fake_cgi.expects(:header).returns("HTTP/1.0 200 OK\nContent-Type: text/html\n") - @response = ActionController::CgiResponse.new(@fake_cgi) - @output = StringIO.new('') - end - - def test_simple_output - @response.body = "Hello, World!" - - @response.out(@output) - assert_equal "HTTP/1.0 200 OK\nContent-Type: text/html\nHello, World!", @output.string - end - - def test_head_request - @fake_cgi.env_table['REQUEST_METHOD'] = 'HEAD' - @response.body = "Hello, World!" - - @response.out(@output) - assert_equal "HTTP/1.0 200 OK\nContent-Type: text/html\n", @output.string - end - - def test_streaming_block - @response.body = Proc.new do |response, output| - 5.times { |n| output.write(n) } +uses_mocha 'CGI Response' do + class CgiResponseTest < BaseCgiTest + def setup + super + @fake_cgi.expects(:header).returns("HTTP/1.0 200 OK\nContent-Type: text/html\n") + @response = ActionController::CgiResponse.new(@fake_cgi) + @output = StringIO.new('') end - @response.out(@output) - assert_equal "HTTP/1.0 200 OK\nContent-Type: text/html\n01234", @output.string + def test_simple_output + @response.body = "Hello, World!" + + @response.out(@output) + assert_equal "HTTP/1.0 200 OK\nContent-Type: text/html\nHello, World!", @output.string + end + + def test_head_request + @fake_cgi.env_table['REQUEST_METHOD'] = 'HEAD' + @response.body = "Hello, World!" + + @response.out(@output) + assert_equal "HTTP/1.0 200 OK\nContent-Type: text/html\n", @output.string + end + + def test_streaming_block + @response.body = Proc.new do |response, output| + 5.times { |n| output.write(n) } + end + + @response.out(@output) + assert_equal "HTTP/1.0 200 OK\nContent-Type: text/html\n01234", @output.string + end end end diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index 068d71a8f8..07c13ebbf7 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -59,647 +59,30 @@ class UriReservedCharactersRoutingTest < Test::Unit::TestCase end end -class LegacyRouteSetTests < Test::Unit::TestCase - attr_reader :rs - def setup - # These tests assume optimisation is on, so re-enable it. - ActionController::Base.optimise_named_routes = true - - @rs = ::ActionController::Routing::RouteSet.new - @rs.draw {|m| m.connect ':controller/:action/:id' } - - ActionController::Routing.use_controllers! %w(content admin/user admin/news_feed) - end - - def test_default_setup - assert_equal({:controller => "content", :action => 'index'}, rs.recognize_path("/content")) - assert_equal({:controller => "content", :action => 'list'}, rs.recognize_path("/content/list")) - assert_equal({:controller => "content", :action => 'show', :id => '10'}, rs.recognize_path("/content/show/10")) - - assert_equal({:controller => "admin/user", :action => 'show', :id => '10'}, rs.recognize_path("/admin/user/show/10")) - - assert_equal '/admin/user/show/10', rs.generate(:controller => 'admin/user', :action => 'show', :id => 10) - - assert_equal '/admin/user/show', rs.generate({:action => 'show'}, {:controller => 'admin/user', :action => 'list', :id => '10'}) - assert_equal '/admin/user/list/10', rs.generate({}, {:controller => 'admin/user', :action => 'list', :id => '10'}) - - assert_equal '/admin/stuff', rs.generate({:controller => 'stuff'}, {:controller => 'admin/user', :action => 'list', :id => '10'}) - assert_equal '/stuff', rs.generate({:controller => '/stuff'}, {:controller => 'admin/user', :action => 'list', :id => '10'}) - end - - def test_ignores_leading_slash - @rs.draw {|m| m.connect '/:controller/:action/:id'} - test_default_setup - end - - def test_time_recognition - # We create many routes to make situation more realistic - @rs = ::ActionController::Routing::RouteSet.new - @rs.draw { |map| - map.frontpage '', :controller => 'search', :action => 'new' - map.resources :videos do |video| - video.resources :comments - video.resource :file, :controller => 'video_file' - video.resource :share, :controller => 'video_shares' - video.resource :abuse, :controller => 'video_abuses' - end - map.resources :abuses, :controller => 'video_abuses' - map.resources :video_uploads - map.resources :video_visits - - map.resources :users do |user| - user.resource :settings - user.resources :videos - end - map.resources :channels do |channel| - channel.resources :videos, :controller => 'channel_videos' - end - map.resource :session - map.resource :lost_password - map.search 'search', :controller => 'search' - map.resources :pages - map.connect ':controller/:action/:id' - } - n = 1000 - if RunTimeTests - GC.start - rectime = Benchmark.realtime do - n.times do - rs.recognize_path("/videos/1234567", {:method => :get}) - rs.recognize_path("/videos/1234567/abuse", {:method => :get}) - rs.recognize_path("/users/1234567/settings", {:method => :get}) - rs.recognize_path("/channels/1234567", {:method => :get}) - rs.recognize_path("/session/new", {:method => :get}) - rs.recognize_path("/admin/user/show/10", {:method => :get}) - end - end - puts "\n\nRecognition (#{rs.routes.size} routes):" - per_url = rectime / (n * 6) - puts "#{per_url * 1000} ms/url" - puts "#{1 / per_url} url/s\n\n" - end - end - def test_time_generation - n = 5000 - if RunTimeTests - GC.start - pairs = [ - [{:controller => 'content', :action => 'index'}, {:controller => 'content', :action => 'show'}], - [{:controller => 'content'}, {:controller => 'content', :action => 'index'}], - [{:controller => 'content', :action => 'list'}, {:controller => 'content', :action => 'index'}], - [{:controller => 'content', :action => 'show', :id => '10'}, {:controller => 'content', :action => 'list'}], - [{:controller => 'admin/user', :action => 'index'}, {:controller => 'admin/user', :action => 'show'}], - [{:controller => 'admin/user'}, {:controller => 'admin/user', :action => 'index'}], - [{:controller => 'admin/user', :action => 'list'}, {:controller => 'admin/user', :action => 'index'}], - [{:controller => 'admin/user', :action => 'show', :id => '10'}, {:controller => 'admin/user', :action => 'list'}], - ] - p = nil - gentime = Benchmark.realtime do - n.times do - pairs.each {|(a, b)| rs.generate(a, b)} - end - end - - puts "\n\nGeneration (RouteSet): (#{(n * 8)} urls)" - per_url = gentime / (n * 8) - puts "#{per_url * 1000} ms/url" - puts "#{1 / per_url} url/s\n\n" - end - end - - def test_route_with_colon_first - rs.draw do |map| - map.connect '/:controller/:action/:id', :action => 'index', :id => nil - map.connect ':url', :controller => 'tiny_url', :action => 'translate' - end - end - - def test_route_with_regexp_for_controller - rs.draw do |map| - map.connect ':controller/:admintoken/:action/:id', :controller => /admin\/.+/ - map.connect ':controller/:action/:id' - end - assert_equal({:controller => "admin/user", :admintoken => "foo", :action => "index"}, - rs.recognize_path("/admin/user/foo")) - assert_equal({:controller => "content", :action => "foo"}, rs.recognize_path("/content/foo")) - assert_equal '/admin/user/foo', rs.generate(:controller => "admin/user", :admintoken => "foo", :action => "index") - assert_equal '/content/foo', rs.generate(:controller => "content", :action => "foo") - end - - def test_route_with_regexp_and_dot - rs.draw do |map| - map.connect ':controller/:action/:file', - :controller => /admin|user/, - :action => /upload|download/, - :defaults => {:file => nil}, - :requirements => {:file => %r{[^/]+(\.[^/]+)?}} - end - # Without a file extension - assert_equal '/user/download/file', - rs.generate(:controller => "user", :action => "download", :file => "file") - assert_equal( - {:controller => "user", :action => "download", :file => "file"}, - rs.recognize_path("/user/download/file")) - - # Now, let's try a file with an extension, really a dot (.) - assert_equal '/user/download/file.jpg', - rs.generate( - :controller => "user", :action => "download", :file => "file.jpg") - assert_equal( - {:controller => "user", :action => "download", :file => "file.jpg"}, - rs.recognize_path("/user/download/file.jpg")) - end - - def test_basic_named_route - rs.add_named_route :home, '', :controller => 'content', :action => 'list' - x = setup_for_named_route - assert_equal("http://named.route.test/", - x.send(:home_url)) - end - - def test_basic_named_route_with_relative_url_root - rs.add_named_route :home, '', :controller => 'content', :action => 'list' - x = setup_for_named_route - x.relative_url_root="/foo" - assert_equal("http://named.route.test/foo/", - x.send(:home_url)) - assert_equal "/foo/", x.send(:home_path) - end - - def test_named_route_with_option - rs.add_named_route :page, 'page/:title', :controller => 'content', :action => 'show_page' - x = setup_for_named_route - assert_equal("http://named.route.test/page/new%20stuff", - x.send(:page_url, :title => 'new stuff')) - end - - def test_named_route_with_default - rs.add_named_route :page, 'page/:title', :controller => 'content', :action => 'show_page', :title => 'AboutPage' - x = setup_for_named_route - assert_equal("http://named.route.test/page/AboutRails", - x.send(:page_url, :title => "AboutRails")) - - end - - def test_named_route_with_nested_controller - rs.add_named_route :users, 'admin/user', :controller => 'admin/user', :action => 'index' - x = setup_for_named_route - assert_equal("http://named.route.test/admin/user", - x.send(:users_url)) - end - - uses_mocha "named route optimisation" do - def test_optimised_named_route_call_never_uses_url_for - rs.add_named_route :users, 'admin/user', :controller => '/admin/user', :action => 'index' - rs.add_named_route :user, 'admin/user/:id', :controller=>'/admin/user', :action=>'show' - x = setup_for_named_route - x.expects(:url_for).never - x.send(:users_url) - x.send(:users_path) - x.send(:user_url, 2, :foo=>"bar") - x.send(:user_path, 3, :bar=>"foo") - end - - def test_optimised_named_route_with_host - rs.add_named_route :pages, 'pages', :controller => 'content', :action => 'show_page', :host => 'foo.com' - x = setup_for_named_route - x.expects(:url_for).with(:host => 'foo.com', :only_path => false, :controller => 'content', :action => 'show_page', :use_route => :pages).once - x.send(:pages_url) - end - end - - def setup_for_named_route - klass = Class.new(MockController) - rs.install_helpers(klass) - klass.new(rs) - end - - def test_named_route_without_hash - rs.draw do |map| - map.normal ':controller/:action/:id' - end - end - - def test_named_route_root - rs.draw do |map| - map.root :controller => "hello" - end - x = setup_for_named_route - assert_equal("http://named.route.test/", x.send(:root_url)) - assert_equal("/", x.send(:root_path)) - end - - def test_named_route_with_regexps - rs.draw do |map| - map.article 'page/:year/:month/:day/:title', :controller => 'page', :action => 'show', - :year => /\d+/, :month => /\d+/, :day => /\d+/ - map.connect ':controller/:action/:id' - end - x = setup_for_named_route - # assert_equal( - # {:controller => 'page', :action => 'show', :title => 'hi', :use_route => :article, :only_path => false}, - # x.send(:article_url, :title => 'hi') - # ) - assert_equal( - "http://named.route.test/page/2005/6/10/hi", - x.send(:article_url, :title => 'hi', :day => 10, :year => 2005, :month => 6) - ) - end - - def test_changing_controller - assert_equal '/admin/stuff/show/10', rs.generate( - {:controller => 'stuff', :action => 'show', :id => 10}, - {:controller => 'admin/user', :action => 'index'} - ) - end - - def test_paths_escaped - rs.draw do |map| - map.path 'file/*path', :controller => 'content', :action => 'show_file' - map.connect ':controller/:action/:id' - end - - # No + to space in URI escaping, only for query params. - results = rs.recognize_path "/file/hello+world/how+are+you%3F" - assert results, "Recognition should have succeeded" - assert_equal ['hello+world', 'how+are+you?'], results[:path] - - # Use %20 for space instead. - results = rs.recognize_path "/file/hello%20world/how%20are%20you%3F" - assert results, "Recognition should have succeeded" - assert_equal ['hello world', 'how are you?'], results[:path] - - results = rs.recognize_path "/file" - assert results, "Recognition should have succeeded" - assert_equal [], results[:path] - end - - def test_paths_slashes_unescaped_with_ordered_parameters - rs.add_named_route :path, '/file/*path', :controller => 'content' - - # No / to %2F in URI, only for query params. - x = setup_for_named_route - assert_equal("/file/hello/world", x.send(:path_path, 'hello/world')) - end - - def test_non_controllers_cannot_be_matched - rs.draw do |map| - map.connect ':controller/:action/:id' - end - assert_raises(ActionController::RoutingError) { rs.recognize_path("/not_a/show/10") } - end - - def test_paths_do_not_accept_defaults - assert_raises(ActionController::RoutingError) do - rs.draw do |map| - map.path 'file/*path', :controller => 'content', :action => 'show_file', :path => %w(fake default) - map.connect ':controller/:action/:id' - end - end - - rs.draw do |map| - map.path 'file/*path', :controller => 'content', :action => 'show_file', :path => [] - map.connect ':controller/:action/:id' - end - end - - def test_should_list_options_diff_when_routing_requirements_dont_match - rs.draw do |map| - map.post 'post/:id', :controller=> 'post', :action=> 'show', :requirements => {:id => /\d+/} - end - exception = assert_raise(ActionController::RoutingError) { rs.generate(:controller => 'post', :action => 'show', :bad_param => "foo", :use_route => "post") } - assert_match /^post_url failed to generate/, exception.message - from_match = exception.message.match(/from \{[^\}]+\}/).to_s - assert_match /:bad_param=>"foo"/, from_match - assert_match /:action=>"show"/, from_match - assert_match /:controller=>"post"/, from_match - - expected_match = exception.message.match(/expected: \{[^\}]+\}/).to_s - assert_no_match /:bad_param=>"foo"/, expected_match - assert_match /:action=>"show"/, expected_match - assert_match /:controller=>"post"/, expected_match - - diff_match = exception.message.match(/diff: \{[^\}]+\}/).to_s - assert_match /:bad_param=>"foo"/, diff_match - assert_no_match /:action=>"show"/, diff_match - assert_no_match /:controller=>"post"/, diff_match - end - - # this specifies the case where your formerly would get a very confusing error message with an empty diff - def test_should_have_better_error_message_when_options_diff_is_empty - rs.draw do |map| - map.content '/content/:query', :controller => 'content', :action => 'show' - end - - exception = assert_raise(ActionController::RoutingError) { rs.generate(:controller => 'content', :action => 'show', :use_route => "content") } - assert_match %r[:action=>"show"], exception.message - assert_match %r[:controller=>"content"], exception.message - assert_match %r[you may have ambiguous routes, or you may need to supply additional parameters for this route], exception.message - assert_match %r[content_url has the following required parameters: \["content", :query\] - are they all satisfied?], exception.message - end - - def test_dynamic_path_allowed - rs.draw do |map| - map.connect '*path', :controller => 'content', :action => 'show_file' - end - - assert_equal '/pages/boo', rs.generate(:controller => 'content', :action => 'show_file', :path => %w(pages boo)) - end - - def test_dynamic_recall_paths_allowed - rs.draw do |map| - map.connect '*path', :controller => 'content', :action => 'show_file' - end - - recall_path = ActionController::Routing::PathSegment::Result.new(%w(pages boo)) - assert_equal '/pages/boo', rs.generate({}, :controller => 'content', :action => 'show_file', :path => recall_path) - end - - def test_backwards - rs.draw do |map| - map.connect 'page/:id/:action', :controller => 'pages', :action => 'show' - map.connect ':controller/:action/:id' - end - - assert_equal '/page/20', rs.generate({:id => 20}, {:controller => 'pages', :action => 'show'}) - assert_equal '/page/20', rs.generate(:controller => 'pages', :id => 20, :action => 'show') - assert_equal '/pages/boo', rs.generate(:controller => 'pages', :action => 'boo') - end - - def test_route_with_fixnum_default - rs.draw do |map| - map.connect 'page/:id', :controller => 'content', :action => 'show_page', :id => 1 - map.connect ':controller/:action/:id' - end - - assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page') - assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page', :id => 1) - assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page', :id => '1') - assert_equal '/page/10', rs.generate(:controller => 'content', :action => 'show_page', :id => 10) - - assert_equal({:controller => "content", :action => 'show_page', :id => '1'}, rs.recognize_path("/page")) - assert_equal({:controller => "content", :action => 'show_page', :id => '1'}, rs.recognize_path("/page/1")) - assert_equal({:controller => "content", :action => 'show_page', :id => '10'}, rs.recognize_path("/page/10")) - end - - # For newer revision - def test_route_with_text_default - rs.draw do |map| - map.connect 'page/:id', :controller => 'content', :action => 'show_page', :id => 1 - map.connect ':controller/:action/:id' - end - - assert_equal '/page/foo', rs.generate(:controller => 'content', :action => 'show_page', :id => 'foo') - assert_equal({:controller => "content", :action => 'show_page', :id => 'foo'}, rs.recognize_path("/page/foo")) - - token = "\321\202\320\265\320\272\321\201\321\202" # 'text' in russian - escaped_token = CGI::escape(token) - - assert_equal '/page/' + escaped_token, rs.generate(:controller => 'content', :action => 'show_page', :id => token) - assert_equal({:controller => "content", :action => 'show_page', :id => token}, rs.recognize_path("/page/#{escaped_token}")) - end - - def test_action_expiry - assert_equal '/content', rs.generate({:controller => 'content'}, {:controller => 'content', :action => 'show'}) - end - - def test_recognition_with_uppercase_controller_name - assert_equal({:controller => "content", :action => 'index'}, rs.recognize_path("/Content")) - assert_equal({:controller => "content", :action => 'list'}, rs.recognize_path("/ConTent/list")) - assert_equal({:controller => "content", :action => 'show', :id => '10'}, rs.recognize_path("/CONTENT/show/10")) - - # these used to work, before the routes rewrite, but support for this was pulled in the new version... - #assert_equal({'controller' => "admin/news_feed", 'action' => 'index'}, rs.recognize_path("Admin/NewsFeed")) - #assert_equal({'controller' => "admin/news_feed", 'action' => 'index'}, rs.recognize_path("Admin/News_Feed")) - end - - def test_requirement_should_prevent_optional_id - rs.draw do |map| - map.post 'post/:id', :controller=> 'post', :action=> 'show', :requirements => {:id => /\d+/} - end - - assert_equal '/post/10', rs.generate(:controller => 'post', :action => 'show', :id => 10) - - assert_raises ActionController::RoutingError do - rs.generate(:controller => 'post', :action => 'show') - end - end - - def test_both_requirement_and_optional - rs.draw do |map| - map.blog('test/:year', :controller => 'post', :action => 'show', - :defaults => { :year => nil }, - :requirements => { :year => /\d{4}/ } - ) - map.connect ':controller/:action/:id' - end - - assert_equal '/test', rs.generate(:controller => 'post', :action => 'show') - assert_equal '/test', rs.generate(:controller => 'post', :action => 'show', :year => nil) - - x = setup_for_named_route - assert_equal("http://named.route.test/test", - x.send(:blog_url)) - end - - def test_set_to_nil_forgets - rs.draw do |map| - map.connect 'pages/:year/:month/:day', :controller => 'content', :action => 'list_pages', :month => nil, :day => nil - map.connect ':controller/:action/:id' - end - - assert_equal '/pages/2005', - rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005) - assert_equal '/pages/2005/6', - rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005, :month => 6) - assert_equal '/pages/2005/6/12', - rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005, :month => 6, :day => 12) - - assert_equal '/pages/2005/6/4', - rs.generate({:day => 4}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'}) - - assert_equal '/pages/2005/6', - rs.generate({:day => nil}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'}) - - assert_equal '/pages/2005', - rs.generate({:day => nil, :month => nil}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'}) - end - - def test_url_with_no_action_specified - rs.draw do |map| - map.connect '', :controller => 'content' - map.connect ':controller/:action/:id' - end - - assert_equal '/', rs.generate(:controller => 'content', :action => 'index') - assert_equal '/', rs.generate(:controller => 'content') - end - - def test_named_url_with_no_action_specified - rs.draw do |map| - map.home '', :controller => 'content' - map.connect ':controller/:action/:id' - end - - assert_equal '/', rs.generate(:controller => 'content', :action => 'index') - assert_equal '/', rs.generate(:controller => 'content') - - x = setup_for_named_route - assert_equal("http://named.route.test/", - x.send(:home_url)) - end - - def test_url_generated_when_forgetting_action - [{:controller => 'content', :action => 'index'}, {:controller => 'content'}].each do |hash| - rs.draw do |map| - map.home '', hash - map.connect ':controller/:action/:id' - end - assert_equal '/', rs.generate({:action => nil}, {:controller => 'content', :action => 'hello'}) - assert_equal '/', rs.generate({:controller => 'content'}) - assert_equal '/content/hi', rs.generate({:controller => 'content', :action => 'hi'}) - end - end - - def test_named_route_method - rs.draw do |map| - map.categories 'categories', :controller => 'content', :action => 'categories' - map.connect ':controller/:action/:id' - end - - assert_equal '/categories', rs.generate(:controller => 'content', :action => 'categories') - assert_equal '/content/hi', rs.generate({:controller => 'content', :action => 'hi'}) - end - - def test_named_routes_array - test_named_route_method - assert_equal [:categories], rs.named_routes.names - end - - def test_nil_defaults - rs.draw do |map| - map.connect 'journal', - :controller => 'content', - :action => 'list_journal', - :date => nil, :user_id => nil - map.connect ':controller/:action/:id' - end - - assert_equal '/journal', rs.generate(:controller => 'content', :action => 'list_journal', :date => nil, :user_id => nil) - end - - def setup_request_method_routes_for(method) - @request = ActionController::TestRequest.new - @request.env["REQUEST_METHOD"] = method - @request.request_uri = "/match" - - rs.draw do |r| - r.connect '/match', :controller => 'books', :action => 'get', :conditions => { :method => :get } - r.connect '/match', :controller => 'books', :action => 'post', :conditions => { :method => :post } - r.connect '/match', :controller => 'books', :action => 'put', :conditions => { :method => :put } - r.connect '/match', :controller => 'books', :action => 'delete', :conditions => { :method => :delete } - end - end - - %w(GET POST PUT DELETE).each do |request_method| - define_method("test_request_method_recognized_with_#{request_method}") do - begin - Object.const_set(:BooksController, Class.new(ActionController::Base)) - - setup_request_method_routes_for(request_method) - - assert_nothing_raised { rs.recognize(@request) } - assert_equal request_method.downcase, @request.path_parameters[:action] - ensure - Object.send(:remove_const, :BooksController) rescue nil - end - end - end - - def test_subpath_recognized - Object.const_set(:SubpathBooksController, Class.new(ActionController::Base)) - - rs.draw do |r| - r.connect '/books/:id/edit', :controller => 'subpath_books', :action => 'edit' - r.connect '/items/:id/:action', :controller => 'subpath_books' - r.connect '/posts/new/:action', :controller => 'subpath_books' - r.connect '/posts/:id', :controller => 'subpath_books', :action => "show" - end - - hash = rs.recognize_path "/books/17/edit" - assert_not_nil hash - assert_equal %w(subpath_books 17 edit), [hash[:controller], hash[:id], hash[:action]] - - hash = rs.recognize_path "/items/3/complete" - assert_not_nil hash - assert_equal %w(subpath_books 3 complete), [hash[:controller], hash[:id], hash[:action]] - - hash = rs.recognize_path "/posts/new/preview" - assert_not_nil hash - assert_equal %w(subpath_books preview), [hash[:controller], hash[:action]] - - hash = rs.recognize_path "/posts/7" - assert_not_nil hash - assert_equal %w(subpath_books show 7), [hash[:controller], hash[:action], hash[:id]] - ensure - Object.send(:remove_const, :SubpathBooksController) rescue nil - end - - def test_subpath_generated - Object.const_set(:SubpathBooksController, Class.new(ActionController::Base)) - - rs.draw do |r| - r.connect '/books/:id/edit', :controller => 'subpath_books', :action => 'edit' - r.connect '/items/:id/:action', :controller => 'subpath_books' - r.connect '/posts/new/:action', :controller => 'subpath_books' - end - - assert_equal "/books/7/edit", rs.generate(:controller => "subpath_books", :id => 7, :action => "edit") - assert_equal "/items/15/complete", rs.generate(:controller => "subpath_books", :id => 15, :action => "complete") - assert_equal "/posts/new/preview", rs.generate(:controller => "subpath_books", :action => "preview") - ensure - Object.send(:remove_const, :SubpathBooksController) rescue nil - end - - def test_failed_requirements_raises_exception_with_violated_requirements - rs.draw do |r| - r.foo_with_requirement 'foos/:id', :controller=>'foos', :requirements=>{:id=>/\d+/} - end - - x = setup_for_named_route - assert_raises(ActionController::RoutingError) do - x.send(:foo_with_requirement_url, "I am Against the requirements") - end - end -end - class SegmentTest < Test::Unit::TestCase - def test_first_segment_should_interpolate_for_structure s = ROUTING::Segment.new def s.interpolation_statement(array) 'hello' end assert_equal 'hello', s.continue_string_structure([]) end - + def test_interpolation_statement s = ROUTING::StaticSegment.new s.value = "Hello" assert_equal "Hello", eval(s.interpolation_statement([])) assert_equal "HelloHello", eval(s.interpolation_statement([s])) - + s2 = ROUTING::StaticSegment.new s2.value = "-" assert_equal "Hello-Hello", eval(s.interpolation_statement([s, s2])) - + s3 = ROUTING::StaticSegment.new s3.value = "World" assert_equal "Hello-World", eval(s3.interpolation_statement([s, s2])) end - end class StaticSegmentTest < Test::Unit::TestCase - def test_interpolation_chunk_should_respect_raw s = ROUTING::StaticSegment.new s.value = 'Hello World' @@ -713,28 +96,26 @@ class StaticSegmentTest < Test::Unit::TestCase def test_regexp_chunk_should_escape_specials s = ROUTING::StaticSegment.new - + s.value = 'Hello*World' assert_equal 'Hello\*World', s.regexp_chunk - + s.value = 'HelloWorld' assert_equal 'HelloWorld', s.regexp_chunk end - + def test_regexp_chunk_should_add_question_mark_for_optionals s = ROUTING::StaticSegment.new s.value = "/" s.is_optional = true assert_equal "/?", s.regexp_chunk - + s.value = "hello" assert_equal "(?:hello)?", s.regexp_chunk end - end class DynamicSegmentTest < Test::Unit::TestCase - def segment unless @segment @segment = ROUTING::DynamicSegment.new @@ -742,126 +123,126 @@ class DynamicSegmentTest < Test::Unit::TestCase end @segment end - + def test_extract_value s = ROUTING::DynamicSegment.new s.key = :a - + hash = {:a => '10', :b => '20'} assert_equal '10', eval(s.extract_value) - + hash = {:b => '20'} assert_equal nil, eval(s.extract_value) - + s.default = '20' assert_equal '20', eval(s.extract_value) end - + def test_default_local_name assert_equal 'a_value', segment.local_name, "Unexpected name -- all value_check tests will fail!" end - + def test_presence_value_check a_value = 10 assert eval(segment.value_check) end - + def test_regexp_value_check_rejects_nil segment.regexp = /\d+/ a_value = nil assert ! eval(segment.value_check) end - + def test_optional_regexp_value_check_should_accept_nil segment.regexp = /\d+/ segment.is_optional = true a_value = nil assert eval(segment.value_check) end - + def test_regexp_value_check_rejects_no_match segment.regexp = /\d+/ - + a_value = "Hello20World" assert ! eval(segment.value_check) - + a_value = "20Hi" assert ! eval(segment.value_check) end - + def test_regexp_value_check_accepts_match segment.regexp = /\d+/ - + a_value = "30" assert eval(segment.value_check) end - + def test_value_check_fails_on_nil a_value = nil assert ! eval(segment.value_check) end - + def test_optional_value_needs_no_check segment.is_optional = true a_value = nil assert_equal nil, segment.value_check end - + def test_regexp_value_check_should_accept_match_with_default segment.regexp = /\d+/ segment.default = '200' - + a_value = '100' assert eval(segment.value_check) end - + def test_expiry_should_not_trigger_once_expired expired = true hash = merged = {:a => 2, :b => 3} options = {:b => 3} expire_on = Hash.new { raise 'No!!!' } - + eval(segment.expiry_statement) rescue RuntimeError flunk "Expiry check should not have occurred!" end - + def test_expiry_should_occur_according_to_expire_on expired = false hash = merged = {:a => 2, :b => 3} options = {:b => 3} - + expire_on = {:b => true, :a => false} eval(segment.expiry_statement) assert !expired assert_equal({:a => 2, :b => 3}, hash) - + expire_on = {:b => true, :a => true} eval(segment.expiry_statement) assert expired assert_equal({:b => 3}, hash) end - + def test_extraction_code_should_return_on_nil hash = merged = {:b => 3} options = {:b => 3} a_value = nil - + # Local jump because of return inside eval. assert_raises(LocalJumpError) { eval(segment.extraction_code) } end - + def test_extraction_code_should_return_on_mismatch segment.regexp = /\d+/ hash = merged = {:a => 'Hi', :b => '3'} options = {:b => '3'} a_value = nil - + # Local jump because of return inside eval. assert_raises(LocalJumpError) { eval(segment.extraction_code) } end - + def test_extraction_code_should_accept_value_and_set_local hash = merged = {:a => 'Hi', :b => '3'} options = {:b => '3'} @@ -871,45 +252,45 @@ class DynamicSegmentTest < Test::Unit::TestCase eval(segment.extraction_code) assert_equal 'Hi', a_value end - + def test_extraction_should_work_without_value_check segment.default = 'hi' hash = merged = {:b => '3'} options = {:b => '3'} a_value = nil expired = true - + eval(segment.extraction_code) assert_equal 'hi', a_value end - + def test_extraction_code_should_perform_expiry expired = false hash = merged = {:a => 'Hi', :b => '3'} options = {:b => '3'} expire_on = {:a => true} a_value = nil - + eval(segment.extraction_code) assert_equal 'Hi', a_value assert expired assert_equal options, hash end - + def test_interpolation_chunk_should_replace_value a_value = 'Hi' assert_equal a_value, eval(%("#{segment.interpolation_chunk}")) end - + def test_interpolation_chunk_should_accept_nil a_value = nil assert_equal '', eval(%("#{segment.interpolation_chunk('a_value')}")) end - + def test_value_regexp_should_be_nil_without_regexp assert_equal nil, segment.value_regexp end - + def test_value_regexp_should_match_exacly segment.regexp = /\d+/ assert_no_match segment.value_regexp, "Hello 10 World" @@ -917,12 +298,12 @@ class DynamicSegmentTest < Test::Unit::TestCase assert_no_match segment.value_regexp, "10 World" assert_match segment.value_regexp, "10" end - + def test_regexp_chunk_should_return_string segment.regexp = /\d+/ assert_kind_of String, segment.regexp_chunk end - + def test_build_pattern_non_optional_with_no_captures # Non optional a_segment = ROUTING::DynamicSegment.new @@ -958,264 +339,23 @@ class DynamicSegmentTest < Test::Unit::TestCase end class ControllerSegmentTest < Test::Unit::TestCase - def test_regexp_should_only_match_possible_controllers ActionController::Routing.with_controllers %w(admin/accounts admin/users account pages) do cs = ROUTING::ControllerSegment.new :controller regexp = %r{\A#{cs.regexp_chunk}\Z} - + ActionController::Routing.possible_controllers.each do |name| assert_match regexp, name assert_no_match regexp, "#{name}_fake" - + match = regexp.match name assert_equal name, match[1] end end end - end -uses_mocha 'RouteTest' do - - class MockController - attr_accessor :routes - - def initialize(routes) - self.routes = routes - end - - def url_for(options) - only_path = options.delete(:only_path) - - port = options.delete(:port) || 80 - port_string = port == 80 ? '' : ":#{port}" - - host = options.delete(:host) || "named.route.test" - anchor = "##{options.delete(:anchor)}" if options.key?(:anchor) - - path = routes.generate(options) - - only_path ? "#{path}#{anchor}" : "http://#{host}#{port_string}#{path}#{anchor}" - end - - def request - @request ||= MockRequest.new(:host => "named.route.test", :method => :get) - end - - def relative_url_root=(value) - request.relative_url_root=value - end - end - - class MockRequest - attr_accessor :path, :path_parameters, :host, :subdomains, :domain, - :method, :relative_url_root - - def initialize(values={}) - values.each { |key, value| send("#{key}=", value) } - if values[:host] - subdomain, self.domain = values[:host].split(/\./, 2) - self.subdomains = [subdomain] - end - end - - def protocol - "http://" - end - - def host_with_port - (subdomains * '.') + '.' + domain - end - end - -class RouteTest < Test::Unit::TestCase - - def setup - @route = ROUTING::Route.new - end - - def slash_segment(is_optional = false) - returning ROUTING::DividerSegment.new('/') do |s| - s.is_optional = is_optional - end - end - - def default_route - unless defined?(@default_route) - @default_route = ROUTING::Route.new - - @default_route.segments << (s = ROUTING::StaticSegment.new) - s.value = '/' - s.raw = true - - @default_route.segments << (s = ROUTING::DynamicSegment.new) - s.key = :controller - - @default_route.segments << slash_segment(:optional) - @default_route.segments << (s = ROUTING::DynamicSegment.new) - s.key = :action - s.default = 'index' - s.is_optional = true - - @default_route.segments << slash_segment(:optional) - @default_route.segments << (s = ROUTING::DynamicSegment.new) - s.key = :id - s.is_optional = true - - @default_route.segments << slash_segment(:optional) - end - @default_route - end - - def test_default_route_recognition - expected = {:controller => 'accounts', :action => 'show', :id => '10'} - assert_equal expected, default_route.recognize('/accounts/show/10') - assert_equal expected, default_route.recognize('/accounts/show/10/') - - expected[:id] = 'jamis' - assert_equal expected, default_route.recognize('/accounts/show/jamis/') - - expected.delete :id - assert_equal expected, default_route.recognize('/accounts/show') - assert_equal expected, default_route.recognize('/accounts/show/') - - expected[:action] = 'index' - assert_equal expected, default_route.recognize('/accounts/') - assert_equal expected, default_route.recognize('/accounts') - - assert_equal nil, default_route.recognize('/') - assert_equal nil, default_route.recognize('/accounts/how/goood/it/is/to/be/free') - end - - def test_default_route_should_omit_default_action - o = {:controller => 'accounts', :action => 'index'} - assert_equal '/accounts', default_route.generate(o, o, {}) - end - - def test_default_route_should_include_default_action_when_id_present - o = {:controller => 'accounts', :action => 'index', :id => '20'} - assert_equal '/accounts/index/20', default_route.generate(o, o, {}) - end - - def test_default_route_should_work_with_action_but_no_id - o = {:controller => 'accounts', :action => 'list_all'} - assert_equal '/accounts/list_all', default_route.generate(o, o, {}) - end - - def test_default_route_should_uri_escape_pluses - expected = { :controller => 'accounts', :action => 'show', :id => 'hello world' } - assert_equal expected, default_route.recognize('/accounts/show/hello world') - assert_equal expected, default_route.recognize('/accounts/show/hello%20world') - assert_equal '/accounts/show/hello%20world', default_route.generate(expected, expected, {}) - - expected[:id] = 'hello+world' - assert_equal expected, default_route.recognize('/accounts/show/hello+world') - assert_equal expected, default_route.recognize('/accounts/show/hello%2Bworld') - assert_equal '/accounts/show/hello+world', default_route.generate(expected, expected, {}) - end - - def test_matches_controller_and_action - # requirement_for should only be called for the action and controller _once_ - @route.expects(:requirement_for).with(:controller).times(1).returns('pages') - @route.expects(:requirement_for).with(:action).times(1).returns('show') - - @route.requirements = {:controller => 'pages', :action => 'show'} - assert @route.matches_controller_and_action?('pages', 'show') - assert !@route.matches_controller_and_action?('not_pages', 'show') - assert !@route.matches_controller_and_action?('pages', 'not_show') - end - - def test_parameter_shell - page_url = ROUTING::Route.new - page_url.requirements = {:controller => 'pages', :action => 'show', :id => /\d+/} - assert_equal({:controller => 'pages', :action => 'show'}, page_url.parameter_shell) - end - - def test_defaults - route = ROUTING::RouteBuilder.new.build '/users/:id.:format', :controller => "users", :action => "show", :format => "html" - assert_equal( - { :controller => "users", :action => "show", :format => "html" }, - route.defaults) - end - - def test_builder_complains_without_controller - assert_raises(ArgumentError) do - ROUTING::RouteBuilder.new.build '/contact', :contoller => "contact", :action => "index" - end - end - - def test_significant_keys_for_default_route - keys = default_route.significant_keys.sort_by {|k| k.to_s } - assert_equal [:action, :controller, :id], keys - end - - def test_significant_keys - user_url = ROUTING::Route.new - user_url.segments << (s = ROUTING::StaticSegment.new) - s.value = '/' - s.raw = true - - user_url.segments << (s = ROUTING::StaticSegment.new) - s.value = 'user' - - user_url.segments << (s = ROUTING::StaticSegment.new) - s.value = '/' - s.raw = true - s.is_optional = true - - user_url.segments << (s = ROUTING::DynamicSegment.new) - s.key = :user - - user_url.segments << (s = ROUTING::StaticSegment.new) - s.value = '/' - s.raw = true - s.is_optional = true - - user_url.requirements = {:controller => 'users', :action => 'show'} - - keys = user_url.significant_keys.sort_by { |k| k.to_s } - assert_equal [:action, :controller, :user], keys - end - - def test_build_empty_query_string - assert_equal '', @route.build_query_string({}) - end - - def test_build_query_string_with_nil_value - assert_equal '', @route.build_query_string({:x => nil}) - end - - def test_simple_build_query_string - assert_equal '?x=1&y=2', order_query_string(@route.build_query_string(:x => '1', :y => '2')) - end - - def test_convert_ints_build_query_string - assert_equal '?x=1&y=2', order_query_string(@route.build_query_string(:x => 1, :y => 2)) - end - - def test_escape_spaces_build_query_string - assert_equal '?x=hello+world&y=goodbye+world', order_query_string(@route.build_query_string(:x => 'hello world', :y => 'goodbye world')) - end - - def test_expand_array_build_query_string - assert_equal '?x%5B%5D=1&x%5B%5D=2', order_query_string(@route.build_query_string(:x => [1, 2])) - end - - def test_escape_spaces_build_query_string_selected_keys - assert_equal '?x=hello+world', order_query_string(@route.build_query_string({:x => 'hello world', :y => 'goodbye world'}, [:x])) - end - - private - def order_query_string(qs) - '?' + qs[1..-1].split('&').sort.join('&') - end -end - -end # uses_mocha - class RouteBuilderTest < Test::Unit::TestCase - def builder @builder ||= ROUTING::RouteBuilder.new end @@ -1244,7 +384,7 @@ class RouteBuilderTest < Test::Unit::TestCase assert_kind_of ROUTING::StaticSegment, segment assert_equal 'ulysses', segment.value end - + def test_segment_for_action segment, rest = builder.segment_for ':action' assert_equal '', rest @@ -1252,7 +392,7 @@ class RouteBuilderTest < Test::Unit::TestCase assert_equal :action, segment.key assert_equal 'index', segment.default end - + def test_segment_for_dynamic segment, rest = builder.segment_for ':login' assert_equal '', rest @@ -1261,7 +401,7 @@ class RouteBuilderTest < Test::Unit::TestCase assert_equal nil, segment.default assert ! segment.optional? end - + def test_segment_for_with_rest segment, rest = builder.segment_for ':login/:action' assert_equal :login, segment.key @@ -1273,105 +413,104 @@ class RouteBuilderTest < Test::Unit::TestCase assert_equal :action, segment.key assert_equal '', rest end - + def test_segments_for segments = builder.segments_for_route_path '/:controller/:action/:id' - + assert_kind_of ROUTING::DividerSegment, segments[0] assert_equal '/', segments[2].value - + assert_kind_of ROUTING::DynamicSegment, segments[1] assert_equal :controller, segments[1].key - + assert_kind_of ROUTING::DividerSegment, segments[2] assert_equal '/', segments[2].value - + assert_kind_of ROUTING::DynamicSegment, segments[3] assert_equal :action, segments[3].key - + assert_kind_of ROUTING::DividerSegment, segments[4] assert_equal '/', segments[4].value - + assert_kind_of ROUTING::DynamicSegment, segments[5] assert_equal :id, segments[5].key end - + def test_segment_for_action s, r = builder.segment_for(':action/something/else') assert_equal '/something/else', r assert_equal :action, s.key end - + def test_action_default_should_not_trigger_on_prefix s, r = builder.segment_for ':action_name/something/else' assert_equal '/something/else', r assert_equal :action_name, s.key assert_equal nil, s.default end - + def test_divide_route_options segments = builder.segments_for_route_path '/cars/:action/:person/:car/' defaults, requirements = builder.divide_route_options(segments, :action => 'buy', :person => /\w+/, :car => /\w+/, :defaults => {:person => nil, :car => nil} ) - + assert_equal({:action => 'buy', :person => nil, :car => nil}, defaults) assert_equal({:person => /\w+/, :car => /\w+/}, requirements) end - + def test_assign_route_options segments = builder.segments_for_route_path '/cars/:action/:person/:car/' defaults = {:action => 'buy', :person => nil, :car => nil} requirements = {:person => /\w+/, :car => /\w+/} - + route_requirements = builder.assign_route_options(segments, defaults, requirements) assert_equal({}, route_requirements) - + assert_equal :action, segments[3].key assert_equal 'buy', segments[3].default - + assert_equal :person, segments[5].key assert_equal %r/\w+/, segments[5].regexp assert segments[5].optional? - + assert_equal :car, segments[7].key assert_equal %r/\w+/, segments[7].regexp assert segments[7].optional? end - + def test_assign_route_options_with_anchor_chars segments = builder.segments_for_route_path '/cars/:action/:person/:car/' defaults = {:action => 'buy', :person => nil, :car => nil} requirements = {:person => /\w+/, :car => /^\w+$/} - + assert_raises ArgumentError do route_requirements = builder.assign_route_options(segments, defaults, requirements) end - + requirements[:car] = /[^\/]+/ route_requirements = builder.assign_route_options(segments, defaults, requirements) end - def test_optional_segments_preceding_required_segments segments = builder.segments_for_route_path '/cars/:action/:person/:car/' defaults = {:action => 'buy', :person => nil, :car => "model-t"} assert builder.assign_route_options(segments, defaults, {}).empty? - + 0.upto(1) { |i| assert !segments[i].optional?, "segment #{i} is optional and it shouldn't be" } assert segments[2].optional? - + assert_equal nil, builder.warn_output # should only warn on the :person segment end - + def test_segmentation_of_dot_path segments = builder.segments_for_route_path '/books/:action.rss' assert builder.assign_route_options(segments, {}, {}).empty? assert_equal 6, segments.length # "/", "books", "/", ":action", ".", "rss" assert !segments.any? { |seg| seg.optional? } end - + def test_segmentation_of_dynamic_dot_path segments = builder.segments_for_route_path '/books/:action.:format' assert builder.assign_route_options(segments, {}, {}).empty? @@ -1379,56 +518,56 @@ class RouteBuilderTest < Test::Unit::TestCase assert !segments.any? { |seg| seg.optional? } assert_kind_of ROUTING::DynamicSegment, segments.last end - + def test_assignment_of_default_options segments = builder.segments_for_route_path '/:controller/:action/:id/' action, id = segments[-4], segments[-2] - + assert_equal :action, action.key assert_equal :id, id.key assert ! action.optional? assert ! id.optional? - + builder.assign_default_route_options(segments) - + assert_equal 'index', action.default assert action.optional? assert id.optional? end - + def test_assignment_of_default_options_respects_existing_defaults segments = builder.segments_for_route_path '/:controller/:action/:id/' action, id = segments[-4], segments[-2] - + assert_equal :action, action.key assert_equal :id, id.key action.default = 'show' action.is_optional = true - + id.default = 'Welcome' id.is_optional = true - + builder.assign_default_route_options(segments) - + assert_equal 'show', action.default assert action.optional? assert_equal 'Welcome', id.default assert id.optional? end - + def test_assignment_of_default_options_respects_regexps segments = builder.segments_for_route_path '/:controller/:action/:id/' action = segments[-4] - + assert_equal :action, action.key action.regexp = /show|in/ # Use 'in' to check partial matches - + builder.assign_default_route_options(segments) - + assert_equal nil, action.default assert ! action.optional? end - + def test_assignment_of_is_optional_when_default segments = builder.segments_for_route_path '/books/:action.rss' assert_equal segments[3].key, :action @@ -1436,44 +575,44 @@ class RouteBuilderTest < Test::Unit::TestCase builder.ensure_required_segments(segments) assert ! segments[3].optional? end - + def test_is_optional_is_assigned_to_default_segments segments = builder.segments_for_route_path '/books/:action' builder.assign_route_options(segments, {:action => 'index'}, {}) - + assert_equal segments[3].key, :action assert segments[3].optional? assert_kind_of ROUTING::DividerSegment, segments[2] assert segments[2].optional? end - + # XXX is optional not being set right? # /blah/:defaulted_segment <-- is the second slash optional? it should be. - + def test_route_build ActionController::Routing.with_controllers %w(users pages) do r = builder.build '/:controller/:action/:id/', :action => nil - + [0, 2, 4].each do |i| assert_kind_of ROUTING::DividerSegment, r.segments[i] assert_equal '/', r.segments[i].value assert r.segments[i].optional? if i > 1 end - + assert_kind_of ROUTING::DynamicSegment, r.segments[1] assert_equal :controller, r.segments[1].key assert_equal nil, r.segments[1].default - + assert_kind_of ROUTING::DynamicSegment, r.segments[3] assert_equal :action, r.segments[3].key assert_equal 'index', r.segments[3].default - + assert_kind_of ROUTING::DynamicSegment, r.segments[5] assert_equal :id, r.segments[5].key assert r.segments[5].optional? end end - + def test_slashes_are_implied routes = [ builder.build('/:controller/:action/:id/', :action => nil), @@ -1487,785 +626,9 @@ class RouteBuilderTest < Test::Unit::TestCase assert_equal expected, found, "Route #{i + 1} has #{found} segments, expected #{expected}" end end - -end - - - - -class RouteSetTest < Test::Unit::TestCase - - def set - @set ||= ROUTING::RouteSet.new - end - - def request - @request ||= MockRequest.new(:host => "named.routes.test", :method => :get) - end - - def test_generate_extras - set.draw { |m| m.connect ':controller/:action/:id' } - path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world") - assert_equal "/foo/bar/15", path - assert_equal %w(that this), extras.map(&:to_s).sort - end - - def test_extra_keys - set.draw { |m| m.connect ':controller/:action/:id' } - extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world") - assert_equal %w(that this), extras.map(&:to_s).sort - end - - def test_generate_extras_not_first - set.draw do |map| - map.connect ':controller/:action/:id.:format' - map.connect ':controller/:action/:id' - end - path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world") - assert_equal "/foo/bar/15", path - assert_equal %w(that this), extras.map(&:to_s).sort - end - - def test_generate_not_first - set.draw do |map| - map.connect ':controller/:action/:id.:format' - map.connect ':controller/:action/:id' - end - assert_equal "/foo/bar/15?this=hello", set.generate(:controller => "foo", :action => "bar", :id => 15, :this => "hello") - end - - def test_extra_keys_not_first - set.draw do |map| - map.connect ':controller/:action/:id.:format' - map.connect ':controller/:action/:id' - end - extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world") - assert_equal %w(that this), extras.map(&:to_s).sort - end - - def test_draw - assert_equal 0, set.routes.size - set.draw do |map| - map.connect '/hello/world', :controller => 'a', :action => 'b' - end - assert_equal 1, set.routes.size - end - - def test_named_draw - assert_equal 0, set.routes.size - set.draw do |map| - map.hello '/hello/world', :controller => 'a', :action => 'b' - end - assert_equal 1, set.routes.size - assert_equal set.routes.first, set.named_routes[:hello] - end - - def test_later_named_routes_take_precedence - set.draw do |map| - map.hello '/hello/world', :controller => 'a', :action => 'b' - map.hello '/hello', :controller => 'a', :action => 'b' - end - assert_equal set.routes.last, set.named_routes[:hello] - end - - def setup_named_route_test - set.draw do |map| - map.show '/people/:id', :controller => 'people', :action => 'show' - map.index '/people', :controller => 'people', :action => 'index' - map.multi '/people/go/:foo/:bar/joe/:id', :controller => 'people', :action => 'multi' - map.users '/admin/users', :controller => 'admin/users', :action => 'index' - end - - klass = Class.new(MockController) - set.install_helpers(klass) - klass.new(set) - end - - def test_named_route_hash_access_method - controller = setup_named_route_test - - assert_equal( - { :controller => 'people', :action => 'show', :id => 5, :use_route => :show, :only_path => false }, - controller.send(:hash_for_show_url, :id => 5)) - - assert_equal( - { :controller => 'people', :action => 'index', :use_route => :index, :only_path => false }, - controller.send(:hash_for_index_url)) - - assert_equal( - { :controller => 'people', :action => 'show', :id => 5, :use_route => :show, :only_path => true }, - controller.send(:hash_for_show_path, :id => 5) - ) - end - - def test_named_route_url_method - controller = setup_named_route_test - - assert_equal "http://named.route.test/people/5", controller.send(:show_url, :id => 5) - assert_equal "/people/5", controller.send(:show_path, :id => 5) - - assert_equal "http://named.route.test/people", controller.send(:index_url) - assert_equal "/people", controller.send(:index_path) - - assert_equal "http://named.route.test/admin/users", controller.send(:users_url) - assert_equal '/admin/users', controller.send(:users_path) - assert_equal '/admin/users', set.generate(controller.send(:hash_for_users_url), {:controller => 'users', :action => 'index'}) - end - - def test_named_route_url_method_with_anchor - controller = setup_named_route_test - - assert_equal "http://named.route.test/people/5#location", controller.send(:show_url, :id => 5, :anchor => 'location') - assert_equal "/people/5#location", controller.send(:show_path, :id => 5, :anchor => 'location') - - assert_equal "http://named.route.test/people#location", controller.send(:index_url, :anchor => 'location') - assert_equal "/people#location", controller.send(:index_path, :anchor => 'location') - - assert_equal "http://named.route.test/admin/users#location", controller.send(:users_url, :anchor => 'location') - assert_equal '/admin/users#location', controller.send(:users_path, :anchor => 'location') - - assert_equal "http://named.route.test/people/go/7/hello/joe/5#location", - controller.send(:multi_url, 7, "hello", 5, :anchor => 'location') - - assert_equal "http://named.route.test/people/go/7/hello/joe/5?baz=bar#location", - controller.send(:multi_url, 7, "hello", 5, :baz => "bar", :anchor => 'location') - - assert_equal "http://named.route.test/people?baz=bar#location", - controller.send(:index_url, :baz => "bar", :anchor => 'location') - end - - def test_named_route_url_method_with_port - controller = setup_named_route_test - assert_equal "http://named.route.test:8080/people/5", controller.send(:show_url, 5, :port=>8080) - end - - def test_named_route_url_method_with_host - controller = setup_named_route_test - assert_equal "http://some.example.com/people/5", controller.send(:show_url, 5, :host=>"some.example.com") - end - - - def test_named_route_url_method_with_ordered_parameters - controller = setup_named_route_test - assert_equal "http://named.route.test/people/go/7/hello/joe/5", - controller.send(:multi_url, 7, "hello", 5) - end - - def test_named_route_url_method_with_ordered_parameters_and_hash - controller = setup_named_route_test - assert_equal "http://named.route.test/people/go/7/hello/joe/5?baz=bar", - controller.send(:multi_url, 7, "hello", 5, :baz => "bar") - end - - def test_named_route_url_method_with_no_positional_arguments - controller = setup_named_route_test - assert_equal "http://named.route.test/people?baz=bar", - controller.send(:index_url, :baz => "bar") - end - - def test_draw_default_route - ActionController::Routing.with_controllers(['users']) do - set.draw do |map| - map.connect '/:controller/:action/:id' - end - - assert_equal 1, set.routes.size - route = set.routes.first - - assert route.segments.last.optional? - - assert_equal '/users/show/10', set.generate(:controller => 'users', :action => 'show', :id => 10) - assert_equal '/users/index/10', set.generate(:controller => 'users', :id => 10) - - assert_equal({:controller => 'users', :action => 'index', :id => '10'}, set.recognize_path('/users/index/10')) - assert_equal({:controller => 'users', :action => 'index', :id => '10'}, set.recognize_path('/users/index/10/')) - end - end - - def test_draw_default_route_with_default_controller - ActionController::Routing.with_controllers(['users']) do - set.draw do |map| - map.connect '/:controller/:action/:id', :controller => 'users' - end - assert_equal({:controller => 'users', :action => 'index'}, set.recognize_path('/')) - end - end - - def test_route_with_parameter_shell - ActionController::Routing.with_controllers(['users', 'pages']) do - set.draw do |map| - map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+/ - map.connect '/:controller/:action/:id' - end - - assert_equal({:controller => 'pages', :action => 'index'}, set.recognize_path('/pages')) - assert_equal({:controller => 'pages', :action => 'index'}, set.recognize_path('/pages/index')) - assert_equal({:controller => 'pages', :action => 'list'}, set.recognize_path('/pages/list')) - - assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, set.recognize_path('/pages/show/10')) - assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, set.recognize_path('/page/10')) - end - end - - def test_route_requirements_with_anchor_chars_are_invalid - assert_raises ArgumentError do - set.draw do |map| - map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /^\d+/ - end - end - assert_raises ArgumentError do - set.draw do |map| - map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\A\d+/ - end - end - assert_raises ArgumentError do - set.draw do |map| - map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+$/ - end - end - assert_raises ArgumentError do - set.draw do |map| - map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+\Z/ - end - end - assert_raises ArgumentError do - set.draw do |map| - map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+\z/ - end - end - assert_nothing_raised do - set.draw do |map| - map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+/, :name => /^(david|jamis)/ - end - assert_raises ActionController::RoutingError do - set.generate :controller => 'pages', :action => 'show', :id => 10 - end - end - end - - def test_non_path_route_requirements_match_all - set.draw do |map| - map.connect 'page/37s', :controller => 'pages', :action => 'show', :name => /(jamis|david)/ - end - assert_equal '/page/37s', set.generate(:controller => 'pages', :action => 'show', :name => 'jamis') - assert_raises ActionController::RoutingError do - set.generate(:controller => 'pages', :action => 'show', :name => 'not_jamis') - end - assert_raises ActionController::RoutingError do - set.generate(:controller => 'pages', :action => 'show', :name => 'nor_jamis_and_david') - end - end - - def test_recognize_with_encoded_id_and_regex - set.draw do |map| - map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /[a-zA-Z0-9\+]+/ - end - - assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, set.recognize_path('/page/10')) - assert_equal({:controller => 'pages', :action => 'show', :id => 'hello+world'}, set.recognize_path('/page/hello+world')) - end - - def test_recognize_with_conditions - Object.const_set(:PeopleController, Class.new) - - set.draw do |map| - map.with_options(:controller => "people") do |people| - people.people "/people", :action => "index", :conditions => { :method => :get } - people.connect "/people", :action => "create", :conditions => { :method => :post } - people.person "/people/:id", :action => "show", :conditions => { :method => :get } - people.connect "/people/:id", :action => "update", :conditions => { :method => :put } - people.connect "/people/:id", :action => "destroy", :conditions => { :method => :delete } - end - end - - request.path = "/people" - request.method = :get - assert_nothing_raised { set.recognize(request) } - assert_equal("index", request.path_parameters[:action]) - - request.method = :post - assert_nothing_raised { set.recognize(request) } - assert_equal("create", request.path_parameters[:action]) - - request.method = :put - assert_nothing_raised { set.recognize(request) } - assert_equal("update", request.path_parameters[:action]) - - begin - request.method = :bacon - set.recognize(request) - flunk 'Should have raised NotImplemented' - rescue ActionController::NotImplemented => e - assert_equal [:get, :post, :put, :delete], e.allowed_methods - end - - request.path = "/people/5" - request.method = :get - assert_nothing_raised { set.recognize(request) } - assert_equal("show", request.path_parameters[:action]) - assert_equal("5", request.path_parameters[:id]) - - request.method = :put - assert_nothing_raised { set.recognize(request) } - assert_equal("update", request.path_parameters[:action]) - assert_equal("5", request.path_parameters[:id]) - - request.method = :delete - assert_nothing_raised { set.recognize(request) } - assert_equal("destroy", request.path_parameters[:action]) - assert_equal("5", request.path_parameters[:id]) - - begin - request.method = :post - set.recognize(request) - flunk 'Should have raised MethodNotAllowed' - rescue ActionController::MethodNotAllowed => e - assert_equal [:get, :put, :delete], e.allowed_methods - end - - ensure - Object.send(:remove_const, :PeopleController) - end - - def test_recognize_with_alias_in_conditions - Object.const_set(:PeopleController, Class.new) - - set.draw do |map| - map.people "/people", :controller => 'people', :action => "index", - :conditions => { :method => :get } - map.root :people - end - - request.path = "/people" - request.method = :get - assert_nothing_raised { set.recognize(request) } - assert_equal("people", request.path_parameters[:controller]) - assert_equal("index", request.path_parameters[:action]) - - request.path = "/" - request.method = :get - assert_nothing_raised { set.recognize(request) } - assert_equal("people", request.path_parameters[:controller]) - assert_equal("index", request.path_parameters[:action]) - ensure - Object.send(:remove_const, :PeopleController) - end - - def test_typo_recognition - Object.const_set(:ArticlesController, Class.new) - - set.draw do |map| - map.connect 'articles/:year/:month/:day/:title', - :controller => 'articles', :action => 'permalink', - :year => /\d{4}/, :day => /\d{1,2}/, :month => /\d{1,2}/ - end - - request.path = "/articles/2005/11/05/a-very-interesting-article" - request.method = :get - assert_nothing_raised { set.recognize(request) } - assert_equal("permalink", request.path_parameters[:action]) - assert_equal("2005", request.path_parameters[:year]) - assert_equal("11", request.path_parameters[:month]) - assert_equal("05", request.path_parameters[:day]) - assert_equal("a-very-interesting-article", request.path_parameters[:title]) - - ensure - Object.send(:remove_const, :ArticlesController) - end - - def test_routing_traversal_does_not_load_extra_classes - assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded" - set.draw do |map| - map.connect '/profile', :controller => 'profile' - end - - request.path = '/profile' - - set.recognize(request) rescue nil - - assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded" - end - - def test_recognize_with_conditions_and_format - Object.const_set(:PeopleController, Class.new) - - set.draw do |map| - map.with_options(:controller => "people") do |people| - people.person "/people/:id", :action => "show", :conditions => { :method => :get } - people.connect "/people/:id", :action => "update", :conditions => { :method => :put } - people.connect "/people/:id.:_format", :action => "show", :conditions => { :method => :get } - end - end - - request.path = "/people/5" - request.method = :get - assert_nothing_raised { set.recognize(request) } - assert_equal("show", request.path_parameters[:action]) - assert_equal("5", request.path_parameters[:id]) - - request.method = :put - assert_nothing_raised { set.recognize(request) } - assert_equal("update", request.path_parameters[:action]) - - request.path = "/people/5.png" - request.method = :get - assert_nothing_raised { set.recognize(request) } - assert_equal("show", request.path_parameters[:action]) - assert_equal("5", request.path_parameters[:id]) - assert_equal("png", request.path_parameters[:_format]) - ensure - Object.send(:remove_const, :PeopleController) - end - - def test_generate_with_default_action - set.draw do |map| - map.connect "/people", :controller => "people" - map.connect "/people/list", :controller => "people", :action => "list" - end - - url = set.generate(:controller => "people", :action => "list") - assert_equal "/people/list", url - end - - def test_root_map - Object.const_set(:PeopleController, Class.new) - - set.draw { |map| map.root :controller => "people" } - - request.path = "" - request.method = :get - assert_nothing_raised { set.recognize(request) } - assert_equal("people", request.path_parameters[:controller]) - assert_equal("index", request.path_parameters[:action]) - ensure - Object.send(:remove_const, :PeopleController) - end - - - def test_namespace - Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) }) - - set.draw do |map| - - map.namespace 'api' do |api| - api.route 'inventory', :controller => "products", :action => 'inventory' - end - - end - - request.path = "/api/inventory" - request.method = :get - assert_nothing_raised { set.recognize(request) } - assert_equal("api/products", request.path_parameters[:controller]) - assert_equal("inventory", request.path_parameters[:action]) - ensure - Object.send(:remove_const, :Api) - end - - - def test_namespaced_root_map - Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) }) - - set.draw do |map| - - map.namespace 'api' do |api| - api.root :controller => "products" - end - - end - - request.path = "/api" - request.method = :get - assert_nothing_raised { set.recognize(request) } - assert_equal("api/products", request.path_parameters[:controller]) - assert_equal("index", request.path_parameters[:action]) - ensure - Object.send(:remove_const, :Api) - end - - def test_generate_finds_best_fit - set.draw do |map| - map.connect "/people", :controller => "people", :action => "index" - map.connect "/ws/people", :controller => "people", :action => "index", :ws => true - end - - url = set.generate(:controller => "people", :action => "index", :ws => true) - assert_equal "/ws/people", url - end - - def test_generate_changes_controller_module - set.draw { |map| map.connect ':controller/:action/:id' } - current = { :controller => "bling/bloop", :action => "bap", :id => 9 } - url = set.generate({:controller => "foo/bar", :action => "baz", :id => 7}, current) - assert_equal "/foo/bar/baz/7", url - end - - def test_id_is_not_impossibly_sticky - set.draw do |map| - map.connect 'foo/:number', :controller => "people", :action => "index" - map.connect ':controller/:action/:id' - end - - url = set.generate({:controller => "people", :action => "index", :number => 3}, - {:controller => "people", :action => "index", :id => "21"}) - assert_equal "/foo/3", url - end - - def test_id_is_sticky_when_it_ought_to_be - set.draw do |map| - map.connect ':controller/:id/:action' - end - - url = set.generate({:action => "destroy"}, {:controller => "people", :action => "show", :id => "7"}) - assert_equal "/people/7/destroy", url - end - - def test_use_static_path_when_possible - set.draw do |map| - map.connect 'about', :controller => "welcome", :action => "about" - map.connect ':controller/:action/:id' - end - - url = set.generate({:controller => "welcome", :action => "about"}, - {:controller => "welcome", :action => "get", :id => "7"}) - assert_equal "/about", url - end - - def test_generate - set.draw { |map| map.connect ':controller/:action/:id' } - - args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" } - assert_equal "/foo/bar/7?x=y", set.generate(args) - assert_equal ["/foo/bar/7", [:x]], set.generate_extras(args) - assert_equal [:x], set.extra_keys(args) - end - - def test_named_routes_are_never_relative_to_modules - set.draw do |map| - map.connect "/connection/manage/:action", :controller => 'connection/manage' - map.connect "/connection/connection", :controller => "connection/connection" - map.family_connection "/connection", :controller => "connection" - end - - url = set.generate({:controller => "connection"}, {:controller => 'connection/manage'}) - assert_equal "/connection/connection", url - - url = set.generate({:use_route => :family_connection, :controller => "connection"}, {:controller => 'connection/manage'}) - assert_equal "/connection", url - end - - def test_action_left_off_when_id_is_recalled - set.draw do |map| - map.connect ':controller/:action/:id' - end - assert_equal '/post', set.generate( - {:controller => 'post', :action => 'index'}, - {:controller => 'post', :action => 'show', :id => '10'} - ) - end - - def test_query_params_will_be_shown_when_recalled - set.draw do |map| - map.connect 'show_post/:parameter', :controller => 'post', :action => 'show' - map.connect ':controller/:action/:id' - end - assert_equal '/post/edit?parameter=1', set.generate( - {:action => 'edit', :parameter => 1}, - {:controller => 'post', :action => 'show', :parameter => 1} - ) - end - - def test_expiry_determination_should_consider_values_with_to_param - set.draw { |map| map.connect 'projects/:project_id/:controller/:action' } - assert_equal '/projects/1/post/show', set.generate( - {:action => 'show', :project_id => 1}, - {:controller => 'post', :action => 'show', :project_id => '1'}) - end - - def test_generate_all - set.draw do |map| - map.connect 'show_post/:id', :controller => 'post', :action => 'show' - map.connect ':controller/:action/:id' - end - all = set.generate( - {:action => 'show', :id => 10, :generate_all => true}, - {:controller => 'post', :action => 'show'} - ) - assert_equal 2, all.length - assert_equal '/show_post/10', all.first - assert_equal '/post/show/10', all.last - end - - def test_named_route_in_nested_resource - set.draw do |map| - map.resources :projects do |project| - project.milestones 'milestones', :controller => 'milestones', :action => 'index' - end - end - - request.path = "/projects/1/milestones" - request.method = :get - assert_nothing_raised { set.recognize(request) } - assert_equal("milestones", request.path_parameters[:controller]) - assert_equal("index", request.path_parameters[:action]) - end - - def test_setting_root_in_namespace_using_symbol - assert_nothing_raised do - set.draw do |map| - map.namespace :admin do |admin| - admin.root :controller => 'home' - end - end - end - end - - def test_setting_root_in_namespace_using_string - assert_nothing_raised do - set.draw do |map| - map.namespace 'admin' do |admin| - admin.root :controller => 'home' - end - end - end - end - - def test_route_requirements_with_unsupported_regexp_options_must_error - assert_raises ArgumentError do - set.draw do |map| - map.connect 'page/:name', :controller => 'pages', - :action => 'show', - :requirements => {:name => /(david|jamis)/m} - end - end - end - - def test_route_requirements_with_supported_options_must_not_error - assert_nothing_raised do - set.draw do |map| - map.connect 'page/:name', :controller => 'pages', - :action => 'show', - :requirements => {:name => /(david|jamis)/i} - end - end - assert_nothing_raised do - set.draw do |map| - map.connect 'page/:name', :controller => 'pages', - :action => 'show', - :requirements => {:name => / # Desperately overcommented regexp - ( #Either - david #The Creator - | #Or - jamis #The Deployer - )/x} - end - end - end - - def test_route_requirement_recognize_with_ignore_case - set.draw do |map| - map.connect 'page/:name', :controller => 'pages', - :action => 'show', - :requirements => {:name => /(david|jamis)/i} - end - assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis')) - assert_raises ActionController::RoutingError do - set.recognize_path('/page/davidjamis') - end - assert_equal({:controller => 'pages', :action => 'show', :name => 'DAVID'}, set.recognize_path('/page/DAVID')) - end - - def test_route_requirement_generate_with_ignore_case - set.draw do |map| - map.connect 'page/:name', :controller => 'pages', - :action => 'show', - :requirements => {:name => /(david|jamis)/i} - end - url = set.generate({:controller => 'pages', :action => 'show', :name => 'david'}) - assert_equal "/page/david", url - assert_raises ActionController::RoutingError do - url = set.generate({:controller => 'pages', :action => 'show', :name => 'davidjamis'}) - end - url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'}) - assert_equal "/page/JAMIS", url - end - - def test_route_requirement_recognize_with_extended_syntax - set.draw do |map| - map.connect 'page/:name', :controller => 'pages', - :action => 'show', - :requirements => {:name => / # Desperately overcommented regexp - ( #Either - david #The Creator - | #Or - jamis #The Deployer - )/x} - end - assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis')) - assert_equal({:controller => 'pages', :action => 'show', :name => 'david'}, set.recognize_path('/page/david')) - assert_raises ActionController::RoutingError do - set.recognize_path('/page/david #The Creator') - end - assert_raises ActionController::RoutingError do - set.recognize_path('/page/David') - end - end - - def test_route_requirement_generate_with_extended_syntax - set.draw do |map| - map.connect 'page/:name', :controller => 'pages', - :action => 'show', - :requirements => {:name => / # Desperately overcommented regexp - ( #Either - david #The Creator - | #Or - jamis #The Deployer - )/x} - end - url = set.generate({:controller => 'pages', :action => 'show', :name => 'david'}) - assert_equal "/page/david", url - assert_raises ActionController::RoutingError do - url = set.generate({:controller => 'pages', :action => 'show', :name => 'davidjamis'}) - end - assert_raises ActionController::RoutingError do - url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'}) - end - end - - def test_route_requirement_generate_with_xi_modifiers - set.draw do |map| - map.connect 'page/:name', :controller => 'pages', - :action => 'show', - :requirements => {:name => / # Desperately overcommented regexp - ( #Either - david #The Creator - | #Or - jamis #The Deployer - )/xi} - end - url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'}) - assert_equal "/page/JAMIS", url - end - - def test_route_requirement_recognize_with_xi_modifiers - set.draw do |map| - map.connect 'page/:name', :controller => 'pages', - :action => 'show', - :requirements => {:name => / # Desperately overcommented regexp - ( #Either - david #The Creator - | #Or - jamis #The Deployer - )/xi} - end - assert_equal({:controller => 'pages', :action => 'show', :name => 'JAMIS'}, set.recognize_path('/page/JAMIS')) - end - - end class RoutingTest < Test::Unit::TestCase - def test_possible_controllers true_controller_paths = ActionController::Routing.controller_paths @@ -2278,7 +641,7 @@ class RoutingTest < Test::Unit::TestCase ActionController::Routing.controller_paths = [ RAILS_ROOT, RAILS_ROOT + '/app/controllers', RAILS_ROOT + '/vendor/plugins/bad_plugin/lib' ] - + assert_equal ["admin/user", "plugin", "user"], ActionController::Routing.possible_controllers.sort ensure if true_controller_paths @@ -2287,32 +650,32 @@ class RoutingTest < Test::Unit::TestCase ActionController::Routing.use_controllers! nil Object.send(:remove_const, :RAILS_ROOT) rescue nil end - + def test_possible_controllers_are_reset_on_each_load true_possible_controllers = ActionController::Routing.possible_controllers true_controller_paths = ActionController::Routing.controller_paths - + ActionController::Routing.use_controllers! nil root = File.dirname(__FILE__) + '/controller_fixtures' - + ActionController::Routing.controller_paths = [] assert_equal [], ActionController::Routing.possible_controllers - + ActionController::Routing::Routes.load! ActionController::Routing.controller_paths = [ root, root + '/app/controllers', root + '/vendor/plugins/bad_plugin/lib' ] - + assert_equal ["admin/user", "plugin", "user"], ActionController::Routing.possible_controllers.sort ensure ActionController::Routing.controller_paths = true_controller_paths ActionController::Routing.use_controllers! true_possible_controllers Object.send(:remove_const, :RAILS_ROOT) rescue nil - + ActionController::Routing::Routes.clear! ActionController::Routing::Routes.load_routes! end - + def test_with_controllers c = %w(admin/accounts admin/users account pages) ActionController::Routing.with_controllers c do @@ -2331,22 +694,1631 @@ class RoutingTest < Test::Unit::TestCase paths = ActionController::Routing.normalize_paths(load_paths) assert_equal %w(vendor\\rails\\railties\\builtin\\rails_info vendor\\rails\\actionpack\\lib app\\controllers app\\helpers app\\models config .bar lib .), paths end - + def test_routing_helper_module assert_kind_of Module, ActionController::Routing::Helpers - + h = ActionController::Routing::Helpers c = Class.new assert ! c.ancestors.include?(h) ActionController::Routing::Routes.install_helpers c assert c.ancestors.include?(h) end - end -uses_mocha 'route loading' do - class RouteLoadingTest < Test::Unit::TestCase +uses_mocha 'LegacyRouteSet, Route, RouteSet and RouteLoading' do + class MockController + attr_accessor :routes + def initialize(routes) + self.routes = routes + end + + def url_for(options) + only_path = options.delete(:only_path) + + port = options.delete(:port) || 80 + port_string = port == 80 ? '' : ":#{port}" + + host = options.delete(:host) || "named.route.test" + anchor = "##{options.delete(:anchor)}" if options.key?(:anchor) + + path = routes.generate(options) + + only_path ? "#{path}#{anchor}" : "http://#{host}#{port_string}#{path}#{anchor}" + end + + def request + @request ||= MockRequest.new(:host => "named.route.test", :method => :get) + end + + def relative_url_root=(value) + request.relative_url_root=value + end + end + + class MockRequest + attr_accessor :path, :path_parameters, :host, :subdomains, :domain, + :method, :relative_url_root + + def initialize(values={}) + values.each { |key, value| send("#{key}=", value) } + if values[:host] + subdomain, self.domain = values[:host].split(/\./, 2) + self.subdomains = [subdomain] + end + end + + def protocol + "http://" + end + + def host_with_port + (subdomains * '.') + '.' + domain + end + end + + class LegacyRouteSetTests < Test::Unit::TestCase + attr_reader :rs + + def setup + # These tests assume optimisation is on, so re-enable it. + ActionController::Base.optimise_named_routes = true + + @rs = ::ActionController::Routing::RouteSet.new + @rs.draw {|m| m.connect ':controller/:action/:id' } + + ActionController::Routing.use_controllers! %w(content admin/user admin/news_feed) + end + + def test_default_setup + assert_equal({:controller => "content", :action => 'index'}, rs.recognize_path("/content")) + assert_equal({:controller => "content", :action => 'list'}, rs.recognize_path("/content/list")) + assert_equal({:controller => "content", :action => 'show', :id => '10'}, rs.recognize_path("/content/show/10")) + + assert_equal({:controller => "admin/user", :action => 'show', :id => '10'}, rs.recognize_path("/admin/user/show/10")) + + assert_equal '/admin/user/show/10', rs.generate(:controller => 'admin/user', :action => 'show', :id => 10) + + assert_equal '/admin/user/show', rs.generate({:action => 'show'}, {:controller => 'admin/user', :action => 'list', :id => '10'}) + assert_equal '/admin/user/list/10', rs.generate({}, {:controller => 'admin/user', :action => 'list', :id => '10'}) + + assert_equal '/admin/stuff', rs.generate({:controller => 'stuff'}, {:controller => 'admin/user', :action => 'list', :id => '10'}) + assert_equal '/stuff', rs.generate({:controller => '/stuff'}, {:controller => 'admin/user', :action => 'list', :id => '10'}) + end + + def test_ignores_leading_slash + @rs.draw {|m| m.connect '/:controller/:action/:id'} + test_default_setup + end + + def test_time_recognition + # We create many routes to make situation more realistic + @rs = ::ActionController::Routing::RouteSet.new + @rs.draw { |map| + map.frontpage '', :controller => 'search', :action => 'new' + map.resources :videos do |video| + video.resources :comments + video.resource :file, :controller => 'video_file' + video.resource :share, :controller => 'video_shares' + video.resource :abuse, :controller => 'video_abuses' + end + map.resources :abuses, :controller => 'video_abuses' + map.resources :video_uploads + map.resources :video_visits + + map.resources :users do |user| + user.resource :settings + user.resources :videos + end + map.resources :channels do |channel| + channel.resources :videos, :controller => 'channel_videos' + end + map.resource :session + map.resource :lost_password + map.search 'search', :controller => 'search' + map.resources :pages + map.connect ':controller/:action/:id' + } + n = 1000 + if RunTimeTests + GC.start + rectime = Benchmark.realtime do + n.times do + rs.recognize_path("/videos/1234567", {:method => :get}) + rs.recognize_path("/videos/1234567/abuse", {:method => :get}) + rs.recognize_path("/users/1234567/settings", {:method => :get}) + rs.recognize_path("/channels/1234567", {:method => :get}) + rs.recognize_path("/session/new", {:method => :get}) + rs.recognize_path("/admin/user/show/10", {:method => :get}) + end + end + puts "\n\nRecognition (#{rs.routes.size} routes):" + per_url = rectime / (n * 6) + puts "#{per_url * 1000} ms/url" + puts "#{1 / per_url} url/s\n\n" + end + end + def test_time_generation + n = 5000 + if RunTimeTests + GC.start + pairs = [ + [{:controller => 'content', :action => 'index'}, {:controller => 'content', :action => 'show'}], + [{:controller => 'content'}, {:controller => 'content', :action => 'index'}], + [{:controller => 'content', :action => 'list'}, {:controller => 'content', :action => 'index'}], + [{:controller => 'content', :action => 'show', :id => '10'}, {:controller => 'content', :action => 'list'}], + [{:controller => 'admin/user', :action => 'index'}, {:controller => 'admin/user', :action => 'show'}], + [{:controller => 'admin/user'}, {:controller => 'admin/user', :action => 'index'}], + [{:controller => 'admin/user', :action => 'list'}, {:controller => 'admin/user', :action => 'index'}], + [{:controller => 'admin/user', :action => 'show', :id => '10'}, {:controller => 'admin/user', :action => 'list'}], + ] + p = nil + gentime = Benchmark.realtime do + n.times do + pairs.each {|(a, b)| rs.generate(a, b)} + end + end + + puts "\n\nGeneration (RouteSet): (#{(n * 8)} urls)" + per_url = gentime / (n * 8) + puts "#{per_url * 1000} ms/url" + puts "#{1 / per_url} url/s\n\n" + end + end + + def test_route_with_colon_first + rs.draw do |map| + map.connect '/:controller/:action/:id', :action => 'index', :id => nil + map.connect ':url', :controller => 'tiny_url', :action => 'translate' + end + end + + def test_route_with_regexp_for_controller + rs.draw do |map| + map.connect ':controller/:admintoken/:action/:id', :controller => /admin\/.+/ + map.connect ':controller/:action/:id' + end + assert_equal({:controller => "admin/user", :admintoken => "foo", :action => "index"}, + rs.recognize_path("/admin/user/foo")) + assert_equal({:controller => "content", :action => "foo"}, rs.recognize_path("/content/foo")) + assert_equal '/admin/user/foo', rs.generate(:controller => "admin/user", :admintoken => "foo", :action => "index") + assert_equal '/content/foo', rs.generate(:controller => "content", :action => "foo") + end + + def test_route_with_regexp_and_dot + rs.draw do |map| + map.connect ':controller/:action/:file', + :controller => /admin|user/, + :action => /upload|download/, + :defaults => {:file => nil}, + :requirements => {:file => %r{[^/]+(\.[^/]+)?}} + end + # Without a file extension + assert_equal '/user/download/file', + rs.generate(:controller => "user", :action => "download", :file => "file") + assert_equal( + {:controller => "user", :action => "download", :file => "file"}, + rs.recognize_path("/user/download/file")) + + # Now, let's try a file with an extension, really a dot (.) + assert_equal '/user/download/file.jpg', + rs.generate( + :controller => "user", :action => "download", :file => "file.jpg") + assert_equal( + {:controller => "user", :action => "download", :file => "file.jpg"}, + rs.recognize_path("/user/download/file.jpg")) + end + + def test_basic_named_route + rs.add_named_route :home, '', :controller => 'content', :action => 'list' + x = setup_for_named_route + assert_equal("http://named.route.test/", + x.send(:home_url)) + end + + def test_basic_named_route_with_relative_url_root + rs.add_named_route :home, '', :controller => 'content', :action => 'list' + x = setup_for_named_route + x.relative_url_root="/foo" + assert_equal("http://named.route.test/foo/", + x.send(:home_url)) + assert_equal "/foo/", x.send(:home_path) + end + + def test_named_route_with_option + rs.add_named_route :page, 'page/:title', :controller => 'content', :action => 'show_page' + x = setup_for_named_route + assert_equal("http://named.route.test/page/new%20stuff", + x.send(:page_url, :title => 'new stuff')) + end + + def test_named_route_with_default + rs.add_named_route :page, 'page/:title', :controller => 'content', :action => 'show_page', :title => 'AboutPage' + x = setup_for_named_route + assert_equal("http://named.route.test/page/AboutRails", + x.send(:page_url, :title => "AboutRails")) + + end + + def test_named_route_with_nested_controller + rs.add_named_route :users, 'admin/user', :controller => 'admin/user', :action => 'index' + x = setup_for_named_route + assert_equal("http://named.route.test/admin/user", + x.send(:users_url)) + end + + def test_optimised_named_route_call_never_uses_url_for + rs.add_named_route :users, 'admin/user', :controller => '/admin/user', :action => 'index' + rs.add_named_route :user, 'admin/user/:id', :controller=>'/admin/user', :action=>'show' + x = setup_for_named_route + x.expects(:url_for).never + x.send(:users_url) + x.send(:users_path) + x.send(:user_url, 2, :foo=>"bar") + x.send(:user_path, 3, :bar=>"foo") + end + + def test_optimised_named_route_with_host + rs.add_named_route :pages, 'pages', :controller => 'content', :action => 'show_page', :host => 'foo.com' + x = setup_for_named_route + x.expects(:url_for).with(:host => 'foo.com', :only_path => false, :controller => 'content', :action => 'show_page', :use_route => :pages).once + x.send(:pages_url) + end + + def setup_for_named_route + klass = Class.new(MockController) + rs.install_helpers(klass) + klass.new(rs) + end + + def test_named_route_without_hash + rs.draw do |map| + map.normal ':controller/:action/:id' + end + end + + def test_named_route_root + rs.draw do |map| + map.root :controller => "hello" + end + x = setup_for_named_route + assert_equal("http://named.route.test/", x.send(:root_url)) + assert_equal("/", x.send(:root_path)) + end + + def test_named_route_with_regexps + rs.draw do |map| + map.article 'page/:year/:month/:day/:title', :controller => 'page', :action => 'show', + :year => /\d+/, :month => /\d+/, :day => /\d+/ + map.connect ':controller/:action/:id' + end + x = setup_for_named_route + # assert_equal( + # {:controller => 'page', :action => 'show', :title => 'hi', :use_route => :article, :only_path => false}, + # x.send(:article_url, :title => 'hi') + # ) + assert_equal( + "http://named.route.test/page/2005/6/10/hi", + x.send(:article_url, :title => 'hi', :day => 10, :year => 2005, :month => 6) + ) + end + + def test_changing_controller + assert_equal '/admin/stuff/show/10', rs.generate( + {:controller => 'stuff', :action => 'show', :id => 10}, + {:controller => 'admin/user', :action => 'index'} + ) + end + + def test_paths_escaped + rs.draw do |map| + map.path 'file/*path', :controller => 'content', :action => 'show_file' + map.connect ':controller/:action/:id' + end + + # No + to space in URI escaping, only for query params. + results = rs.recognize_path "/file/hello+world/how+are+you%3F" + assert results, "Recognition should have succeeded" + assert_equal ['hello+world', 'how+are+you?'], results[:path] + + # Use %20 for space instead. + results = rs.recognize_path "/file/hello%20world/how%20are%20you%3F" + assert results, "Recognition should have succeeded" + assert_equal ['hello world', 'how are you?'], results[:path] + + results = rs.recognize_path "/file" + assert results, "Recognition should have succeeded" + assert_equal [], results[:path] + end + + def test_paths_slashes_unescaped_with_ordered_parameters + rs.add_named_route :path, '/file/*path', :controller => 'content' + + # No / to %2F in URI, only for query params. + x = setup_for_named_route + assert_equal("/file/hello/world", x.send(:path_path, 'hello/world')) + end + + def test_non_controllers_cannot_be_matched + rs.draw do |map| + map.connect ':controller/:action/:id' + end + assert_raises(ActionController::RoutingError) { rs.recognize_path("/not_a/show/10") } + end + + def test_paths_do_not_accept_defaults + assert_raises(ActionController::RoutingError) do + rs.draw do |map| + map.path 'file/*path', :controller => 'content', :action => 'show_file', :path => %w(fake default) + map.connect ':controller/:action/:id' + end + end + + rs.draw do |map| + map.path 'file/*path', :controller => 'content', :action => 'show_file', :path => [] + map.connect ':controller/:action/:id' + end + end + + def test_should_list_options_diff_when_routing_requirements_dont_match + rs.draw do |map| + map.post 'post/:id', :controller=> 'post', :action=> 'show', :requirements => {:id => /\d+/} + end + exception = assert_raise(ActionController::RoutingError) { rs.generate(:controller => 'post', :action => 'show', :bad_param => "foo", :use_route => "post") } + assert_match /^post_url failed to generate/, exception.message + from_match = exception.message.match(/from \{[^\}]+\}/).to_s + assert_match /:bad_param=>"foo"/, from_match + assert_match /:action=>"show"/, from_match + assert_match /:controller=>"post"/, from_match + + expected_match = exception.message.match(/expected: \{[^\}]+\}/).to_s + assert_no_match /:bad_param=>"foo"/, expected_match + assert_match /:action=>"show"/, expected_match + assert_match /:controller=>"post"/, expected_match + + diff_match = exception.message.match(/diff: \{[^\}]+\}/).to_s + assert_match /:bad_param=>"foo"/, diff_match + assert_no_match /:action=>"show"/, diff_match + assert_no_match /:controller=>"post"/, diff_match + end + + # this specifies the case where your formerly would get a very confusing error message with an empty diff + def test_should_have_better_error_message_when_options_diff_is_empty + rs.draw do |map| + map.content '/content/:query', :controller => 'content', :action => 'show' + end + + exception = assert_raise(ActionController::RoutingError) { rs.generate(:controller => 'content', :action => 'show', :use_route => "content") } + assert_match %r[:action=>"show"], exception.message + assert_match %r[:controller=>"content"], exception.message + assert_match %r[you may have ambiguous routes, or you may need to supply additional parameters for this route], exception.message + assert_match %r[content_url has the following required parameters: \["content", :query\] - are they all satisfied?], exception.message + end + + def test_dynamic_path_allowed + rs.draw do |map| + map.connect '*path', :controller => 'content', :action => 'show_file' + end + + assert_equal '/pages/boo', rs.generate(:controller => 'content', :action => 'show_file', :path => %w(pages boo)) + end + + def test_dynamic_recall_paths_allowed + rs.draw do |map| + map.connect '*path', :controller => 'content', :action => 'show_file' + end + + recall_path = ActionController::Routing::PathSegment::Result.new(%w(pages boo)) + assert_equal '/pages/boo', rs.generate({}, :controller => 'content', :action => 'show_file', :path => recall_path) + end + + def test_backwards + rs.draw do |map| + map.connect 'page/:id/:action', :controller => 'pages', :action => 'show' + map.connect ':controller/:action/:id' + end + + assert_equal '/page/20', rs.generate({:id => 20}, {:controller => 'pages', :action => 'show'}) + assert_equal '/page/20', rs.generate(:controller => 'pages', :id => 20, :action => 'show') + assert_equal '/pages/boo', rs.generate(:controller => 'pages', :action => 'boo') + end + + def test_route_with_fixnum_default + rs.draw do |map| + map.connect 'page/:id', :controller => 'content', :action => 'show_page', :id => 1 + map.connect ':controller/:action/:id' + end + + assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page') + assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page', :id => 1) + assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page', :id => '1') + assert_equal '/page/10', rs.generate(:controller => 'content', :action => 'show_page', :id => 10) + + assert_equal({:controller => "content", :action => 'show_page', :id => '1'}, rs.recognize_path("/page")) + assert_equal({:controller => "content", :action => 'show_page', :id => '1'}, rs.recognize_path("/page/1")) + assert_equal({:controller => "content", :action => 'show_page', :id => '10'}, rs.recognize_path("/page/10")) + end + + # For newer revision + def test_route_with_text_default + rs.draw do |map| + map.connect 'page/:id', :controller => 'content', :action => 'show_page', :id => 1 + map.connect ':controller/:action/:id' + end + + assert_equal '/page/foo', rs.generate(:controller => 'content', :action => 'show_page', :id => 'foo') + assert_equal({:controller => "content", :action => 'show_page', :id => 'foo'}, rs.recognize_path("/page/foo")) + + token = "\321\202\320\265\320\272\321\201\321\202" # 'text' in russian + escaped_token = CGI::escape(token) + + assert_equal '/page/' + escaped_token, rs.generate(:controller => 'content', :action => 'show_page', :id => token) + assert_equal({:controller => "content", :action => 'show_page', :id => token}, rs.recognize_path("/page/#{escaped_token}")) + end + + def test_action_expiry + assert_equal '/content', rs.generate({:controller => 'content'}, {:controller => 'content', :action => 'show'}) + end + + def test_recognition_with_uppercase_controller_name + assert_equal({:controller => "content", :action => 'index'}, rs.recognize_path("/Content")) + assert_equal({:controller => "content", :action => 'list'}, rs.recognize_path("/ConTent/list")) + assert_equal({:controller => "content", :action => 'show', :id => '10'}, rs.recognize_path("/CONTENT/show/10")) + + # these used to work, before the routes rewrite, but support for this was pulled in the new version... + #assert_equal({'controller' => "admin/news_feed", 'action' => 'index'}, rs.recognize_path("Admin/NewsFeed")) + #assert_equal({'controller' => "admin/news_feed", 'action' => 'index'}, rs.recognize_path("Admin/News_Feed")) + end + + def test_requirement_should_prevent_optional_id + rs.draw do |map| + map.post 'post/:id', :controller=> 'post', :action=> 'show', :requirements => {:id => /\d+/} + end + + assert_equal '/post/10', rs.generate(:controller => 'post', :action => 'show', :id => 10) + + assert_raises ActionController::RoutingError do + rs.generate(:controller => 'post', :action => 'show') + end + end + + def test_both_requirement_and_optional + rs.draw do |map| + map.blog('test/:year', :controller => 'post', :action => 'show', + :defaults => { :year => nil }, + :requirements => { :year => /\d{4}/ } + ) + map.connect ':controller/:action/:id' + end + + assert_equal '/test', rs.generate(:controller => 'post', :action => 'show') + assert_equal '/test', rs.generate(:controller => 'post', :action => 'show', :year => nil) + + x = setup_for_named_route + assert_equal("http://named.route.test/test", + x.send(:blog_url)) + end + + def test_set_to_nil_forgets + rs.draw do |map| + map.connect 'pages/:year/:month/:day', :controller => 'content', :action => 'list_pages', :month => nil, :day => nil + map.connect ':controller/:action/:id' + end + + assert_equal '/pages/2005', + rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005) + assert_equal '/pages/2005/6', + rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005, :month => 6) + assert_equal '/pages/2005/6/12', + rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005, :month => 6, :day => 12) + + assert_equal '/pages/2005/6/4', + rs.generate({:day => 4}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'}) + + assert_equal '/pages/2005/6', + rs.generate({:day => nil}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'}) + + assert_equal '/pages/2005', + rs.generate({:day => nil, :month => nil}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'}) + end + + def test_url_with_no_action_specified + rs.draw do |map| + map.connect '', :controller => 'content' + map.connect ':controller/:action/:id' + end + + assert_equal '/', rs.generate(:controller => 'content', :action => 'index') + assert_equal '/', rs.generate(:controller => 'content') + end + + def test_named_url_with_no_action_specified + rs.draw do |map| + map.home '', :controller => 'content' + map.connect ':controller/:action/:id' + end + + assert_equal '/', rs.generate(:controller => 'content', :action => 'index') + assert_equal '/', rs.generate(:controller => 'content') + + x = setup_for_named_route + assert_equal("http://named.route.test/", + x.send(:home_url)) + end + + def test_url_generated_when_forgetting_action + [{:controller => 'content', :action => 'index'}, {:controller => 'content'}].each do |hash| + rs.draw do |map| + map.home '', hash + map.connect ':controller/:action/:id' + end + assert_equal '/', rs.generate({:action => nil}, {:controller => 'content', :action => 'hello'}) + assert_equal '/', rs.generate({:controller => 'content'}) + assert_equal '/content/hi', rs.generate({:controller => 'content', :action => 'hi'}) + end + end + + def test_named_route_method + rs.draw do |map| + map.categories 'categories', :controller => 'content', :action => 'categories' + map.connect ':controller/:action/:id' + end + + assert_equal '/categories', rs.generate(:controller => 'content', :action => 'categories') + assert_equal '/content/hi', rs.generate({:controller => 'content', :action => 'hi'}) + end + + def test_named_routes_array + test_named_route_method + assert_equal [:categories], rs.named_routes.names + end + + def test_nil_defaults + rs.draw do |map| + map.connect 'journal', + :controller => 'content', + :action => 'list_journal', + :date => nil, :user_id => nil + map.connect ':controller/:action/:id' + end + + assert_equal '/journal', rs.generate(:controller => 'content', :action => 'list_journal', :date => nil, :user_id => nil) + end + + def setup_request_method_routes_for(method) + @request = ActionController::TestRequest.new + @request.env["REQUEST_METHOD"] = method + @request.request_uri = "/match" + + rs.draw do |r| + r.connect '/match', :controller => 'books', :action => 'get', :conditions => { :method => :get } + r.connect '/match', :controller => 'books', :action => 'post', :conditions => { :method => :post } + r.connect '/match', :controller => 'books', :action => 'put', :conditions => { :method => :put } + r.connect '/match', :controller => 'books', :action => 'delete', :conditions => { :method => :delete } + end + end + + %w(GET POST PUT DELETE).each do |request_method| + define_method("test_request_method_recognized_with_#{request_method}") do + begin + Object.const_set(:BooksController, Class.new(ActionController::Base)) + + setup_request_method_routes_for(request_method) + + assert_nothing_raised { rs.recognize(@request) } + assert_equal request_method.downcase, @request.path_parameters[:action] + ensure + Object.send(:remove_const, :BooksController) rescue nil + end + end + end + + def test_subpath_recognized + Object.const_set(:SubpathBooksController, Class.new(ActionController::Base)) + + rs.draw do |r| + r.connect '/books/:id/edit', :controller => 'subpath_books', :action => 'edit' + r.connect '/items/:id/:action', :controller => 'subpath_books' + r.connect '/posts/new/:action', :controller => 'subpath_books' + r.connect '/posts/:id', :controller => 'subpath_books', :action => "show" + end + + hash = rs.recognize_path "/books/17/edit" + assert_not_nil hash + assert_equal %w(subpath_books 17 edit), [hash[:controller], hash[:id], hash[:action]] + + hash = rs.recognize_path "/items/3/complete" + assert_not_nil hash + assert_equal %w(subpath_books 3 complete), [hash[:controller], hash[:id], hash[:action]] + + hash = rs.recognize_path "/posts/new/preview" + assert_not_nil hash + assert_equal %w(subpath_books preview), [hash[:controller], hash[:action]] + + hash = rs.recognize_path "/posts/7" + assert_not_nil hash + assert_equal %w(subpath_books show 7), [hash[:controller], hash[:action], hash[:id]] + ensure + Object.send(:remove_const, :SubpathBooksController) rescue nil + end + + def test_subpath_generated + Object.const_set(:SubpathBooksController, Class.new(ActionController::Base)) + + rs.draw do |r| + r.connect '/books/:id/edit', :controller => 'subpath_books', :action => 'edit' + r.connect '/items/:id/:action', :controller => 'subpath_books' + r.connect '/posts/new/:action', :controller => 'subpath_books' + end + + assert_equal "/books/7/edit", rs.generate(:controller => "subpath_books", :id => 7, :action => "edit") + assert_equal "/items/15/complete", rs.generate(:controller => "subpath_books", :id => 15, :action => "complete") + assert_equal "/posts/new/preview", rs.generate(:controller => "subpath_books", :action => "preview") + ensure + Object.send(:remove_const, :SubpathBooksController) rescue nil + end + + def test_failed_requirements_raises_exception_with_violated_requirements + rs.draw do |r| + r.foo_with_requirement 'foos/:id', :controller=>'foos', :requirements=>{:id=>/\d+/} + end + + x = setup_for_named_route + assert_raises(ActionController::RoutingError) do + x.send(:foo_with_requirement_url, "I am Against the requirements") + end + end + end + + class RouteTest < Test::Unit::TestCase + def setup + @route = ROUTING::Route.new + end + + def slash_segment(is_optional = false) + returning ROUTING::DividerSegment.new('/') do |s| + s.is_optional = is_optional + end + end + + def default_route + unless defined?(@default_route) + @default_route = ROUTING::Route.new + + @default_route.segments << (s = ROUTING::StaticSegment.new) + s.value = '/' + s.raw = true + + @default_route.segments << (s = ROUTING::DynamicSegment.new) + s.key = :controller + + @default_route.segments << slash_segment(:optional) + @default_route.segments << (s = ROUTING::DynamicSegment.new) + s.key = :action + s.default = 'index' + s.is_optional = true + + @default_route.segments << slash_segment(:optional) + @default_route.segments << (s = ROUTING::DynamicSegment.new) + s.key = :id + s.is_optional = true + + @default_route.segments << slash_segment(:optional) + end + @default_route + end + + def test_default_route_recognition + expected = {:controller => 'accounts', :action => 'show', :id => '10'} + assert_equal expected, default_route.recognize('/accounts/show/10') + assert_equal expected, default_route.recognize('/accounts/show/10/') + + expected[:id] = 'jamis' + assert_equal expected, default_route.recognize('/accounts/show/jamis/') + + expected.delete :id + assert_equal expected, default_route.recognize('/accounts/show') + assert_equal expected, default_route.recognize('/accounts/show/') + + expected[:action] = 'index' + assert_equal expected, default_route.recognize('/accounts/') + assert_equal expected, default_route.recognize('/accounts') + + assert_equal nil, default_route.recognize('/') + assert_equal nil, default_route.recognize('/accounts/how/goood/it/is/to/be/free') + end + + def test_default_route_should_omit_default_action + o = {:controller => 'accounts', :action => 'index'} + assert_equal '/accounts', default_route.generate(o, o, {}) + end + + def test_default_route_should_include_default_action_when_id_present + o = {:controller => 'accounts', :action => 'index', :id => '20'} + assert_equal '/accounts/index/20', default_route.generate(o, o, {}) + end + + def test_default_route_should_work_with_action_but_no_id + o = {:controller => 'accounts', :action => 'list_all'} + assert_equal '/accounts/list_all', default_route.generate(o, o, {}) + end + + def test_default_route_should_uri_escape_pluses + expected = { :controller => 'accounts', :action => 'show', :id => 'hello world' } + assert_equal expected, default_route.recognize('/accounts/show/hello world') + assert_equal expected, default_route.recognize('/accounts/show/hello%20world') + assert_equal '/accounts/show/hello%20world', default_route.generate(expected, expected, {}) + + expected[:id] = 'hello+world' + assert_equal expected, default_route.recognize('/accounts/show/hello+world') + assert_equal expected, default_route.recognize('/accounts/show/hello%2Bworld') + assert_equal '/accounts/show/hello+world', default_route.generate(expected, expected, {}) + end + + def test_matches_controller_and_action + # requirement_for should only be called for the action and controller _once_ + @route.expects(:requirement_for).with(:controller).times(1).returns('pages') + @route.expects(:requirement_for).with(:action).times(1).returns('show') + + @route.requirements = {:controller => 'pages', :action => 'show'} + assert @route.matches_controller_and_action?('pages', 'show') + assert !@route.matches_controller_and_action?('not_pages', 'show') + assert !@route.matches_controller_and_action?('pages', 'not_show') + end + + def test_parameter_shell + page_url = ROUTING::Route.new + page_url.requirements = {:controller => 'pages', :action => 'show', :id => /\d+/} + assert_equal({:controller => 'pages', :action => 'show'}, page_url.parameter_shell) + end + + def test_defaults + route = ROUTING::RouteBuilder.new.build '/users/:id.:format', :controller => "users", :action => "show", :format => "html" + assert_equal( + { :controller => "users", :action => "show", :format => "html" }, + route.defaults) + end + + def test_builder_complains_without_controller + assert_raises(ArgumentError) do + ROUTING::RouteBuilder.new.build '/contact', :contoller => "contact", :action => "index" + end + end + + def test_significant_keys_for_default_route + keys = default_route.significant_keys.sort_by {|k| k.to_s } + assert_equal [:action, :controller, :id], keys + end + + def test_significant_keys + user_url = ROUTING::Route.new + user_url.segments << (s = ROUTING::StaticSegment.new) + s.value = '/' + s.raw = true + + user_url.segments << (s = ROUTING::StaticSegment.new) + s.value = 'user' + + user_url.segments << (s = ROUTING::StaticSegment.new) + s.value = '/' + s.raw = true + s.is_optional = true + + user_url.segments << (s = ROUTING::DynamicSegment.new) + s.key = :user + + user_url.segments << (s = ROUTING::StaticSegment.new) + s.value = '/' + s.raw = true + s.is_optional = true + + user_url.requirements = {:controller => 'users', :action => 'show'} + + keys = user_url.significant_keys.sort_by { |k| k.to_s } + assert_equal [:action, :controller, :user], keys + end + + def test_build_empty_query_string + assert_equal '', @route.build_query_string({}) + end + + def test_build_query_string_with_nil_value + assert_equal '', @route.build_query_string({:x => nil}) + end + + def test_simple_build_query_string + assert_equal '?x=1&y=2', order_query_string(@route.build_query_string(:x => '1', :y => '2')) + end + + def test_convert_ints_build_query_string + assert_equal '?x=1&y=2', order_query_string(@route.build_query_string(:x => 1, :y => 2)) + end + + def test_escape_spaces_build_query_string + assert_equal '?x=hello+world&y=goodbye+world', order_query_string(@route.build_query_string(:x => 'hello world', :y => 'goodbye world')) + end + + def test_expand_array_build_query_string + assert_equal '?x%5B%5D=1&x%5B%5D=2', order_query_string(@route.build_query_string(:x => [1, 2])) + end + + def test_escape_spaces_build_query_string_selected_keys + assert_equal '?x=hello+world', order_query_string(@route.build_query_string({:x => 'hello world', :y => 'goodbye world'}, [:x])) + end + + private + def order_query_string(qs) + '?' + qs[1..-1].split('&').sort.join('&') + end + end + + class RouteSetTest < Test::Unit::TestCase + def set + @set ||= ROUTING::RouteSet.new + end + + def request + @request ||= MockRequest.new(:host => "named.routes.test", :method => :get) + end + + def test_generate_extras + set.draw { |m| m.connect ':controller/:action/:id' } + path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world") + assert_equal "/foo/bar/15", path + assert_equal %w(that this), extras.map(&:to_s).sort + end + + def test_extra_keys + set.draw { |m| m.connect ':controller/:action/:id' } + extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world") + assert_equal %w(that this), extras.map(&:to_s).sort + end + + def test_generate_extras_not_first + set.draw do |map| + map.connect ':controller/:action/:id.:format' + map.connect ':controller/:action/:id' + end + path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world") + assert_equal "/foo/bar/15", path + assert_equal %w(that this), extras.map(&:to_s).sort + end + + def test_generate_not_first + set.draw do |map| + map.connect ':controller/:action/:id.:format' + map.connect ':controller/:action/:id' + end + assert_equal "/foo/bar/15?this=hello", set.generate(:controller => "foo", :action => "bar", :id => 15, :this => "hello") + end + + def test_extra_keys_not_first + set.draw do |map| + map.connect ':controller/:action/:id.:format' + map.connect ':controller/:action/:id' + end + extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world") + assert_equal %w(that this), extras.map(&:to_s).sort + end + + def test_draw + assert_equal 0, set.routes.size + set.draw do |map| + map.connect '/hello/world', :controller => 'a', :action => 'b' + end + assert_equal 1, set.routes.size + end + + def test_named_draw + assert_equal 0, set.routes.size + set.draw do |map| + map.hello '/hello/world', :controller => 'a', :action => 'b' + end + assert_equal 1, set.routes.size + assert_equal set.routes.first, set.named_routes[:hello] + end + + def test_later_named_routes_take_precedence + set.draw do |map| + map.hello '/hello/world', :controller => 'a', :action => 'b' + map.hello '/hello', :controller => 'a', :action => 'b' + end + assert_equal set.routes.last, set.named_routes[:hello] + end + + def setup_named_route_test + set.draw do |map| + map.show '/people/:id', :controller => 'people', :action => 'show' + map.index '/people', :controller => 'people', :action => 'index' + map.multi '/people/go/:foo/:bar/joe/:id', :controller => 'people', :action => 'multi' + map.users '/admin/users', :controller => 'admin/users', :action => 'index' + end + + klass = Class.new(MockController) + set.install_helpers(klass) + klass.new(set) + end + + def test_named_route_hash_access_method + controller = setup_named_route_test + + assert_equal( + { :controller => 'people', :action => 'show', :id => 5, :use_route => :show, :only_path => false }, + controller.send(:hash_for_show_url, :id => 5)) + + assert_equal( + { :controller => 'people', :action => 'index', :use_route => :index, :only_path => false }, + controller.send(:hash_for_index_url)) + + assert_equal( + { :controller => 'people', :action => 'show', :id => 5, :use_route => :show, :only_path => true }, + controller.send(:hash_for_show_path, :id => 5) + ) + end + + def test_named_route_url_method + controller = setup_named_route_test + + assert_equal "http://named.route.test/people/5", controller.send(:show_url, :id => 5) + assert_equal "/people/5", controller.send(:show_path, :id => 5) + + assert_equal "http://named.route.test/people", controller.send(:index_url) + assert_equal "/people", controller.send(:index_path) + + assert_equal "http://named.route.test/admin/users", controller.send(:users_url) + assert_equal '/admin/users', controller.send(:users_path) + assert_equal '/admin/users', set.generate(controller.send(:hash_for_users_url), {:controller => 'users', :action => 'index'}) + end + + def test_named_route_url_method_with_anchor + controller = setup_named_route_test + + assert_equal "http://named.route.test/people/5#location", controller.send(:show_url, :id => 5, :anchor => 'location') + assert_equal "/people/5#location", controller.send(:show_path, :id => 5, :anchor => 'location') + + assert_equal "http://named.route.test/people#location", controller.send(:index_url, :anchor => 'location') + assert_equal "/people#location", controller.send(:index_path, :anchor => 'location') + + assert_equal "http://named.route.test/admin/users#location", controller.send(:users_url, :anchor => 'location') + assert_equal '/admin/users#location', controller.send(:users_path, :anchor => 'location') + + assert_equal "http://named.route.test/people/go/7/hello/joe/5#location", + controller.send(:multi_url, 7, "hello", 5, :anchor => 'location') + + assert_equal "http://named.route.test/people/go/7/hello/joe/5?baz=bar#location", + controller.send(:multi_url, 7, "hello", 5, :baz => "bar", :anchor => 'location') + + assert_equal "http://named.route.test/people?baz=bar#location", + controller.send(:index_url, :baz => "bar", :anchor => 'location') + end + + def test_named_route_url_method_with_port + controller = setup_named_route_test + assert_equal "http://named.route.test:8080/people/5", controller.send(:show_url, 5, :port=>8080) + end + + def test_named_route_url_method_with_host + controller = setup_named_route_test + assert_equal "http://some.example.com/people/5", controller.send(:show_url, 5, :host=>"some.example.com") + end + + def test_named_route_url_method_with_ordered_parameters + controller = setup_named_route_test + assert_equal "http://named.route.test/people/go/7/hello/joe/5", + controller.send(:multi_url, 7, "hello", 5) + end + + def test_named_route_url_method_with_ordered_parameters_and_hash + controller = setup_named_route_test + assert_equal "http://named.route.test/people/go/7/hello/joe/5?baz=bar", + controller.send(:multi_url, 7, "hello", 5, :baz => "bar") + end + + def test_named_route_url_method_with_no_positional_arguments + controller = setup_named_route_test + assert_equal "http://named.route.test/people?baz=bar", + controller.send(:index_url, :baz => "bar") + end + + def test_draw_default_route + ActionController::Routing.with_controllers(['users']) do + set.draw do |map| + map.connect '/:controller/:action/:id' + end + + assert_equal 1, set.routes.size + route = set.routes.first + + assert route.segments.last.optional? + + assert_equal '/users/show/10', set.generate(:controller => 'users', :action => 'show', :id => 10) + assert_equal '/users/index/10', set.generate(:controller => 'users', :id => 10) + + assert_equal({:controller => 'users', :action => 'index', :id => '10'}, set.recognize_path('/users/index/10')) + assert_equal({:controller => 'users', :action => 'index', :id => '10'}, set.recognize_path('/users/index/10/')) + end + end + + def test_draw_default_route_with_default_controller + ActionController::Routing.with_controllers(['users']) do + set.draw do |map| + map.connect '/:controller/:action/:id', :controller => 'users' + end + assert_equal({:controller => 'users', :action => 'index'}, set.recognize_path('/')) + end + end + + def test_route_with_parameter_shell + ActionController::Routing.with_controllers(['users', 'pages']) do + set.draw do |map| + map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+/ + map.connect '/:controller/:action/:id' + end + + assert_equal({:controller => 'pages', :action => 'index'}, set.recognize_path('/pages')) + assert_equal({:controller => 'pages', :action => 'index'}, set.recognize_path('/pages/index')) + assert_equal({:controller => 'pages', :action => 'list'}, set.recognize_path('/pages/list')) + + assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, set.recognize_path('/pages/show/10')) + assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, set.recognize_path('/page/10')) + end + end + + def test_route_requirements_with_anchor_chars_are_invalid + assert_raises ArgumentError do + set.draw do |map| + map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /^\d+/ + end + end + assert_raises ArgumentError do + set.draw do |map| + map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\A\d+/ + end + end + assert_raises ArgumentError do + set.draw do |map| + map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+$/ + end + end + assert_raises ArgumentError do + set.draw do |map| + map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+\Z/ + end + end + assert_raises ArgumentError do + set.draw do |map| + map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+\z/ + end + end + assert_nothing_raised do + set.draw do |map| + map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+/, :name => /^(david|jamis)/ + end + assert_raises ActionController::RoutingError do + set.generate :controller => 'pages', :action => 'show', :id => 10 + end + end + end + + def test_non_path_route_requirements_match_all + set.draw do |map| + map.connect 'page/37s', :controller => 'pages', :action => 'show', :name => /(jamis|david)/ + end + assert_equal '/page/37s', set.generate(:controller => 'pages', :action => 'show', :name => 'jamis') + assert_raises ActionController::RoutingError do + set.generate(:controller => 'pages', :action => 'show', :name => 'not_jamis') + end + assert_raises ActionController::RoutingError do + set.generate(:controller => 'pages', :action => 'show', :name => 'nor_jamis_and_david') + end + end + + def test_recognize_with_encoded_id_and_regex + set.draw do |map| + map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /[a-zA-Z0-9\+]+/ + end + + assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, set.recognize_path('/page/10')) + assert_equal({:controller => 'pages', :action => 'show', :id => 'hello+world'}, set.recognize_path('/page/hello+world')) + end + + def test_recognize_with_conditions + Object.const_set(:PeopleController, Class.new) + + set.draw do |map| + map.with_options(:controller => "people") do |people| + people.people "/people", :action => "index", :conditions => { :method => :get } + people.connect "/people", :action => "create", :conditions => { :method => :post } + people.person "/people/:id", :action => "show", :conditions => { :method => :get } + people.connect "/people/:id", :action => "update", :conditions => { :method => :put } + people.connect "/people/:id", :action => "destroy", :conditions => { :method => :delete } + end + end + + request.path = "/people" + request.method = :get + assert_nothing_raised { set.recognize(request) } + assert_equal("index", request.path_parameters[:action]) + + request.method = :post + assert_nothing_raised { set.recognize(request) } + assert_equal("create", request.path_parameters[:action]) + + request.method = :put + assert_nothing_raised { set.recognize(request) } + assert_equal("update", request.path_parameters[:action]) + + begin + request.method = :bacon + set.recognize(request) + flunk 'Should have raised NotImplemented' + rescue ActionController::NotImplemented => e + assert_equal [:get, :post, :put, :delete], e.allowed_methods + end + + request.path = "/people/5" + request.method = :get + assert_nothing_raised { set.recognize(request) } + assert_equal("show", request.path_parameters[:action]) + assert_equal("5", request.path_parameters[:id]) + + request.method = :put + assert_nothing_raised { set.recognize(request) } + assert_equal("update", request.path_parameters[:action]) + assert_equal("5", request.path_parameters[:id]) + + request.method = :delete + assert_nothing_raised { set.recognize(request) } + assert_equal("destroy", request.path_parameters[:action]) + assert_equal("5", request.path_parameters[:id]) + + begin + request.method = :post + set.recognize(request) + flunk 'Should have raised MethodNotAllowed' + rescue ActionController::MethodNotAllowed => e + assert_equal [:get, :put, :delete], e.allowed_methods + end + + ensure + Object.send(:remove_const, :PeopleController) + end + + def test_recognize_with_alias_in_conditions + Object.const_set(:PeopleController, Class.new) + + set.draw do |map| + map.people "/people", :controller => 'people', :action => "index", + :conditions => { :method => :get } + map.root :people + end + + request.path = "/people" + request.method = :get + assert_nothing_raised { set.recognize(request) } + assert_equal("people", request.path_parameters[:controller]) + assert_equal("index", request.path_parameters[:action]) + + request.path = "/" + request.method = :get + assert_nothing_raised { set.recognize(request) } + assert_equal("people", request.path_parameters[:controller]) + assert_equal("index", request.path_parameters[:action]) + ensure + Object.send(:remove_const, :PeopleController) + end + + def test_typo_recognition + Object.const_set(:ArticlesController, Class.new) + + set.draw do |map| + map.connect 'articles/:year/:month/:day/:title', + :controller => 'articles', :action => 'permalink', + :year => /\d{4}/, :day => /\d{1,2}/, :month => /\d{1,2}/ + end + + request.path = "/articles/2005/11/05/a-very-interesting-article" + request.method = :get + assert_nothing_raised { set.recognize(request) } + assert_equal("permalink", request.path_parameters[:action]) + assert_equal("2005", request.path_parameters[:year]) + assert_equal("11", request.path_parameters[:month]) + assert_equal("05", request.path_parameters[:day]) + assert_equal("a-very-interesting-article", request.path_parameters[:title]) + + ensure + Object.send(:remove_const, :ArticlesController) + end + + def test_routing_traversal_does_not_load_extra_classes + assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded" + set.draw do |map| + map.connect '/profile', :controller => 'profile' + end + + request.path = '/profile' + + set.recognize(request) rescue nil + + assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded" + end + + def test_recognize_with_conditions_and_format + Object.const_set(:PeopleController, Class.new) + + set.draw do |map| + map.with_options(:controller => "people") do |people| + people.person "/people/:id", :action => "show", :conditions => { :method => :get } + people.connect "/people/:id", :action => "update", :conditions => { :method => :put } + people.connect "/people/:id.:_format", :action => "show", :conditions => { :method => :get } + end + end + + request.path = "/people/5" + request.method = :get + assert_nothing_raised { set.recognize(request) } + assert_equal("show", request.path_parameters[:action]) + assert_equal("5", request.path_parameters[:id]) + + request.method = :put + assert_nothing_raised { set.recognize(request) } + assert_equal("update", request.path_parameters[:action]) + + request.path = "/people/5.png" + request.method = :get + assert_nothing_raised { set.recognize(request) } + assert_equal("show", request.path_parameters[:action]) + assert_equal("5", request.path_parameters[:id]) + assert_equal("png", request.path_parameters[:_format]) + ensure + Object.send(:remove_const, :PeopleController) + end + + def test_generate_with_default_action + set.draw do |map| + map.connect "/people", :controller => "people" + map.connect "/people/list", :controller => "people", :action => "list" + end + + url = set.generate(:controller => "people", :action => "list") + assert_equal "/people/list", url + end + + def test_root_map + Object.const_set(:PeopleController, Class.new) + + set.draw { |map| map.root :controller => "people" } + + request.path = "" + request.method = :get + assert_nothing_raised { set.recognize(request) } + assert_equal("people", request.path_parameters[:controller]) + assert_equal("index", request.path_parameters[:action]) + ensure + Object.send(:remove_const, :PeopleController) + end + + def test_namespace + Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) }) + + set.draw do |map| + + map.namespace 'api' do |api| + api.route 'inventory', :controller => "products", :action => 'inventory' + end + + end + + request.path = "/api/inventory" + request.method = :get + assert_nothing_raised { set.recognize(request) } + assert_equal("api/products", request.path_parameters[:controller]) + assert_equal("inventory", request.path_parameters[:action]) + ensure + Object.send(:remove_const, :Api) + end + + def test_namespaced_root_map + Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) }) + + set.draw do |map| + + map.namespace 'api' do |api| + api.root :controller => "products" + end + + end + + request.path = "/api" + request.method = :get + assert_nothing_raised { set.recognize(request) } + assert_equal("api/products", request.path_parameters[:controller]) + assert_equal("index", request.path_parameters[:action]) + ensure + Object.send(:remove_const, :Api) + end + + def test_generate_finds_best_fit + set.draw do |map| + map.connect "/people", :controller => "people", :action => "index" + map.connect "/ws/people", :controller => "people", :action => "index", :ws => true + end + + url = set.generate(:controller => "people", :action => "index", :ws => true) + assert_equal "/ws/people", url + end + + def test_generate_changes_controller_module + set.draw { |map| map.connect ':controller/:action/:id' } + current = { :controller => "bling/bloop", :action => "bap", :id => 9 } + url = set.generate({:controller => "foo/bar", :action => "baz", :id => 7}, current) + assert_equal "/foo/bar/baz/7", url + end + + def test_id_is_not_impossibly_sticky + set.draw do |map| + map.connect 'foo/:number', :controller => "people", :action => "index" + map.connect ':controller/:action/:id' + end + + url = set.generate({:controller => "people", :action => "index", :number => 3}, + {:controller => "people", :action => "index", :id => "21"}) + assert_equal "/foo/3", url + end + + def test_id_is_sticky_when_it_ought_to_be + set.draw do |map| + map.connect ':controller/:id/:action' + end + + url = set.generate({:action => "destroy"}, {:controller => "people", :action => "show", :id => "7"}) + assert_equal "/people/7/destroy", url + end + + def test_use_static_path_when_possible + set.draw do |map| + map.connect 'about', :controller => "welcome", :action => "about" + map.connect ':controller/:action/:id' + end + + url = set.generate({:controller => "welcome", :action => "about"}, + {:controller => "welcome", :action => "get", :id => "7"}) + assert_equal "/about", url + end + + def test_generate + set.draw { |map| map.connect ':controller/:action/:id' } + + args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" } + assert_equal "/foo/bar/7?x=y", set.generate(args) + assert_equal ["/foo/bar/7", [:x]], set.generate_extras(args) + assert_equal [:x], set.extra_keys(args) + end + + def test_named_routes_are_never_relative_to_modules + set.draw do |map| + map.connect "/connection/manage/:action", :controller => 'connection/manage' + map.connect "/connection/connection", :controller => "connection/connection" + map.family_connection "/connection", :controller => "connection" + end + + url = set.generate({:controller => "connection"}, {:controller => 'connection/manage'}) + assert_equal "/connection/connection", url + + url = set.generate({:use_route => :family_connection, :controller => "connection"}, {:controller => 'connection/manage'}) + assert_equal "/connection", url + end + + def test_action_left_off_when_id_is_recalled + set.draw do |map| + map.connect ':controller/:action/:id' + end + assert_equal '/post', set.generate( + {:controller => 'post', :action => 'index'}, + {:controller => 'post', :action => 'show', :id => '10'} + ) + end + + def test_query_params_will_be_shown_when_recalled + set.draw do |map| + map.connect 'show_post/:parameter', :controller => 'post', :action => 'show' + map.connect ':controller/:action/:id' + end + assert_equal '/post/edit?parameter=1', set.generate( + {:action => 'edit', :parameter => 1}, + {:controller => 'post', :action => 'show', :parameter => 1} + ) + end + + def test_expiry_determination_should_consider_values_with_to_param + set.draw { |map| map.connect 'projects/:project_id/:controller/:action' } + assert_equal '/projects/1/post/show', set.generate( + {:action => 'show', :project_id => 1}, + {:controller => 'post', :action => 'show', :project_id => '1'}) + end + + def test_generate_all + set.draw do |map| + map.connect 'show_post/:id', :controller => 'post', :action => 'show' + map.connect ':controller/:action/:id' + end + all = set.generate( + {:action => 'show', :id => 10, :generate_all => true}, + {:controller => 'post', :action => 'show'} + ) + assert_equal 2, all.length + assert_equal '/show_post/10', all.first + assert_equal '/post/show/10', all.last + end + + def test_named_route_in_nested_resource + set.draw do |map| + map.resources :projects do |project| + project.milestones 'milestones', :controller => 'milestones', :action => 'index' + end + end + + request.path = "/projects/1/milestones" + request.method = :get + assert_nothing_raised { set.recognize(request) } + assert_equal("milestones", request.path_parameters[:controller]) + assert_equal("index", request.path_parameters[:action]) + end + + def test_setting_root_in_namespace_using_symbol + assert_nothing_raised do + set.draw do |map| + map.namespace :admin do |admin| + admin.root :controller => 'home' + end + end + end + end + + def test_setting_root_in_namespace_using_string + assert_nothing_raised do + set.draw do |map| + map.namespace 'admin' do |admin| + admin.root :controller => 'home' + end + end + end + end + + def test_route_requirements_with_unsupported_regexp_options_must_error + assert_raises ArgumentError do + set.draw do |map| + map.connect 'page/:name', :controller => 'pages', + :action => 'show', + :requirements => {:name => /(david|jamis)/m} + end + end + end + + def test_route_requirements_with_supported_options_must_not_error + assert_nothing_raised do + set.draw do |map| + map.connect 'page/:name', :controller => 'pages', + :action => 'show', + :requirements => {:name => /(david|jamis)/i} + end + end + assert_nothing_raised do + set.draw do |map| + map.connect 'page/:name', :controller => 'pages', + :action => 'show', + :requirements => {:name => / # Desperately overcommented regexp + ( #Either + david #The Creator + | #Or + jamis #The Deployer + )/x} + end + end + end + + def test_route_requirement_recognize_with_ignore_case + set.draw do |map| + map.connect 'page/:name', :controller => 'pages', + :action => 'show', + :requirements => {:name => /(david|jamis)/i} + end + assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis')) + assert_raises ActionController::RoutingError do + set.recognize_path('/page/davidjamis') + end + assert_equal({:controller => 'pages', :action => 'show', :name => 'DAVID'}, set.recognize_path('/page/DAVID')) + end + + def test_route_requirement_generate_with_ignore_case + set.draw do |map| + map.connect 'page/:name', :controller => 'pages', + :action => 'show', + :requirements => {:name => /(david|jamis)/i} + end + url = set.generate({:controller => 'pages', :action => 'show', :name => 'david'}) + assert_equal "/page/david", url + assert_raises ActionController::RoutingError do + url = set.generate({:controller => 'pages', :action => 'show', :name => 'davidjamis'}) + end + url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'}) + assert_equal "/page/JAMIS", url + end + + def test_route_requirement_recognize_with_extended_syntax + set.draw do |map| + map.connect 'page/:name', :controller => 'pages', + :action => 'show', + :requirements => {:name => / # Desperately overcommented regexp + ( #Either + david #The Creator + | #Or + jamis #The Deployer + )/x} + end + assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis')) + assert_equal({:controller => 'pages', :action => 'show', :name => 'david'}, set.recognize_path('/page/david')) + assert_raises ActionController::RoutingError do + set.recognize_path('/page/david #The Creator') + end + assert_raises ActionController::RoutingError do + set.recognize_path('/page/David') + end + end + + def test_route_requirement_generate_with_extended_syntax + set.draw do |map| + map.connect 'page/:name', :controller => 'pages', + :action => 'show', + :requirements => {:name => / # Desperately overcommented regexp + ( #Either + david #The Creator + | #Or + jamis #The Deployer + )/x} + end + url = set.generate({:controller => 'pages', :action => 'show', :name => 'david'}) + assert_equal "/page/david", url + assert_raises ActionController::RoutingError do + url = set.generate({:controller => 'pages', :action => 'show', :name => 'davidjamis'}) + end + assert_raises ActionController::RoutingError do + url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'}) + end + end + + def test_route_requirement_generate_with_xi_modifiers + set.draw do |map| + map.connect 'page/:name', :controller => 'pages', + :action => 'show', + :requirements => {:name => / # Desperately overcommented regexp + ( #Either + david #The Creator + | #Or + jamis #The Deployer + )/xi} + end + url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'}) + assert_equal "/page/JAMIS", url + end + + def test_route_requirement_recognize_with_xi_modifiers + set.draw do |map| + map.connect 'page/:name', :controller => 'pages', + :action => 'show', + :requirements => {:name => / # Desperately overcommented regexp + ( #Either + david #The Creator + | #Or + jamis #The Deployer + )/xi} + end + assert_equal({:controller => 'pages', :action => 'show', :name => 'JAMIS'}, set.recognize_path('/page/JAMIS')) + end + end + + class RouteLoadingTest < Test::Unit::TestCase def setup routes.instance_variable_set '@routes_last_modified', nil silence_warnings { Object.const_set :RAILS_ROOT, '.' } @@ -2397,7 +2369,7 @@ uses_mocha 'route loading' do ActiveSupport::Inflector.inflections { |inflect| inflect.uncountable('equipment') } end - + def test_load_with_configuration routes.configuration_file = "foobarbaz" File.expects(:stat).returns(@stat) @@ -2407,9 +2379,8 @@ uses_mocha 'route loading' do end private - def routes - ActionController::Routing::Routes - end - + def routes + ActionController::Routing::Routes + end end end From 06b6f435cb7ed4b171eb600d3a9286829b8b2482 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sat, 7 Jun 2008 23:46:06 -0500 Subject: [PATCH 28/75] Wrap Initializer after_initialize inside mocha block. --- railties/test/initializer_test.rb | 100 +++++++++++++++--------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/railties/test/initializer_test.rb b/railties/test/initializer_test.rb index efce4f292d..e5da491947 100644 --- a/railties/test/initializer_test.rb +++ b/railties/test/initializer_test.rb @@ -30,66 +30,66 @@ class Initializer_load_environment_Test < Test::Unit::TestCase end -class Initializer_after_initialize_with_blocks_environment_Test < Test::Unit::TestCase - def setup - config = ConfigurationMock.new("") - config.after_initialize do - $test_after_initialize_block1 = "success" +uses_mocha 'Initializer after_initialize' do + class Initializer_after_initialize_with_blocks_environment_Test < Test::Unit::TestCase + def setup + config = ConfigurationMock.new("") + config.after_initialize do + $test_after_initialize_block1 = "success" + end + config.after_initialize do + $test_after_initialize_block2 = "congratulations" + end + assert_nil $test_after_initialize_block1 + assert_nil $test_after_initialize_block2 + + Rails::Initializer.any_instance.expects(:gems_dependencies_loaded).returns(true) + Rails::Initializer.run(:after_initialize, config) end - config.after_initialize do - $test_after_initialize_block2 = "congratulations" + + def teardown + $test_after_initialize_block1 = nil + $test_after_initialize_block2 = nil end - assert_nil $test_after_initialize_block1 - assert_nil $test_after_initialize_block2 - Rails::Initializer.any_instance.expects(:gems_dependencies_loaded).returns(true) - Rails::Initializer.run(:after_initialize, config) - end - - def teardown - $test_after_initialize_block1 = nil - $test_after_initialize_block2 = nil - end - - def test_should_have_called_the_first_after_initialize_block - assert_equal "success", $test_after_initialize_block1 - end - - def test_should_have_called_the_second_after_initialize_block - assert_equal "congratulations", $test_after_initialize_block2 - end -end - -class Initializer_after_initialize_with_no_block_environment_Test < Test::Unit::TestCase - - def setup - config = ConfigurationMock.new("") - config.after_initialize do - $test_after_initialize_block1 = "success" + def test_should_have_called_the_first_after_initialize_block + assert_equal "success", $test_after_initialize_block1 end - config.after_initialize # don't pass a block, this is what we're testing! - config.after_initialize do - $test_after_initialize_block2 = "congratulations" + + def test_should_have_called_the_second_after_initialize_block + assert_equal "congratulations", $test_after_initialize_block2 end - assert_nil $test_after_initialize_block1 - - Rails::Initializer.any_instance.expects(:gems_dependencies_loaded).returns(true) - Rails::Initializer.run(:after_initialize, config) end - def teardown - $test_after_initialize_block1 = nil - $test_after_initialize_block2 = nil - end + class Initializer_after_initialize_with_no_block_environment_Test < Test::Unit::TestCase + def setup + config = ConfigurationMock.new("") + config.after_initialize do + $test_after_initialize_block1 = "success" + end + config.after_initialize # don't pass a block, this is what we're testing! + config.after_initialize do + $test_after_initialize_block2 = "congratulations" + end + assert_nil $test_after_initialize_block1 - def test_should_have_called_the_first_after_initialize_block - assert_equal "success", $test_after_initialize_block1, "should still get set" - end + Rails::Initializer.any_instance.expects(:gems_dependencies_loaded).returns(true) + Rails::Initializer.run(:after_initialize, config) + end - def test_should_have_called_the_second_after_initialize_block - assert_equal "congratulations", $test_after_initialize_block2 - end + def teardown + $test_after_initialize_block1 = nil + $test_after_initialize_block2 = nil + end + def test_should_have_called_the_first_after_initialize_block + assert_equal "success", $test_after_initialize_block1, "should still get set" + end + + def test_should_have_called_the_second_after_initialize_block + assert_equal "congratulations", $test_after_initialize_block2 + end + end end uses_mocha 'framework paths' do From 6c970d79a064b953d3d9555a362a1ad1e0058d1c Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 7 Jun 2008 17:23:25 -0700 Subject: [PATCH 29/75] Performance: faster Object.subclasses_of --- .../active_support/core_ext/object/extending.rb | 17 +++++++++-------- activesupport/test/core_ext/class_test.rb | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/object/extending.rb b/activesupport/lib/active_support/core_ext/object/extending.rb index 43a2be916e..082e98a297 100644 --- a/activesupport/lib/active_support/core_ext/object/extending.rb +++ b/activesupport/lib/active_support/core_ext/object/extending.rb @@ -3,17 +3,18 @@ class Object Class.remove_class(*subclasses_of(*superclasses)) end + # Exclude this class unless it's a subclass of our supers and is defined. + # We check defined? in case we find a removed class that has yet to be + # garbage collected. This also fails for anonymous classes -- please + # submit a patch if you have a workaround. def subclasses_of(*superclasses) #:nodoc: subclasses = [] - # Exclude this class unless it's a subclass of our supers and is defined. - # We check defined? in case we find a removed class that has yet to be - # garbage collected. This also fails for anonymous classes -- please - # submit a patch if you have a workaround. - ObjectSpace.each_object(Class) do |k| - if superclasses.any? { |superclass| k < superclass } && - (k.name.blank? || eval("defined?(::#{k}) && ::#{k}.object_id == k.object_id")) - subclasses << k + superclasses.each do |sup| + ObjectSpace.each_object(class << sup; self; end) do |k| + if k != sup && (k.name.blank? || eval("defined?(::#{k}) && ::#{k}.object_id == k.object_id")) + subclasses << k + end end end diff --git a/activesupport/test/core_ext/class_test.rb b/activesupport/test/core_ext/class_test.rb index 0346fad190..9c6071d478 100644 --- a/activesupport/test/core_ext/class_test.rb +++ b/activesupport/test/core_ext/class_test.rb @@ -38,9 +38,9 @@ class ClassTest < Test::Unit::TestCase @parent = eval("class D; end; D") @sub = eval("class E < D; end; E") @subofsub = eval("class F < E; end; F") - assert @parent.subclasses.all? { |i| [@sub.to_s, @subofsub.to_s].include?(i) } assert_equal 2, @parent.subclasses.size assert_equal [@subofsub.to_s], @sub.subclasses assert_equal [], @subofsub.subclasses + assert_equal [@sub.to_s, @subofsub.to_s].sort, @parent.subclasses.sort end end From 56f5c5582c97b60a89ce44f5dfccba0b5aed4357 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 8 Jun 2008 01:32:57 -0700 Subject: [PATCH 30/75] Missed add: deprecated erb_variable test --- actionpack/test/template/deprecated_erb_variable_test.rb | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 actionpack/test/template/deprecated_erb_variable_test.rb diff --git a/actionpack/test/template/deprecated_erb_variable_test.rb b/actionpack/test/template/deprecated_erb_variable_test.rb new file mode 100644 index 0000000000..b07c590164 --- /dev/null +++ b/actionpack/test/template/deprecated_erb_variable_test.rb @@ -0,0 +1,9 @@ +require 'abstract_unit' + +class DeprecatedErbVariableTest < ActionView::TestCase + def test_setting_erb_variable_warns + assert_deprecated 'erb_variable' do + ActionView::Base.erb_variable = '_erbout' + end + end +end From f42dab8221a2cfc13b49f6ac713e0845f25b65c3 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 8 Jun 2008 01:36:33 -0700 Subject: [PATCH 31/75] Revert "Missed add: deprecated erb_variable test" This reverts commit 56f5c5582c97b60a89ce44f5dfccba0b5aed4357. --- actionpack/test/template/deprecated_erb_variable_test.rb | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 actionpack/test/template/deprecated_erb_variable_test.rb diff --git a/actionpack/test/template/deprecated_erb_variable_test.rb b/actionpack/test/template/deprecated_erb_variable_test.rb deleted file mode 100644 index b07c590164..0000000000 --- a/actionpack/test/template/deprecated_erb_variable_test.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'abstract_unit' - -class DeprecatedErbVariableTest < ActionView::TestCase - def test_setting_erb_variable_warns - assert_deprecated 'erb_variable' do - ActionView::Base.erb_variable = '_erbout' - end - end -end From b336ce9e062e4de0d20aa359b08e86fe83b6dd89 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 8 Jun 2008 01:36:33 -0700 Subject: [PATCH 32/75] Revert "Missed add: deprecated erb_variable test" This reverts commit 56f5c5582c97b60a89ce44f5dfccba0b5aed4357. --- actionpack/test/template/deprecated_erb_variable_test.rb | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 actionpack/test/template/deprecated_erb_variable_test.rb diff --git a/actionpack/test/template/deprecated_erb_variable_test.rb b/actionpack/test/template/deprecated_erb_variable_test.rb deleted file mode 100644 index b07c590164..0000000000 --- a/actionpack/test/template/deprecated_erb_variable_test.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'abstract_unit' - -class DeprecatedErbVariableTest < ActionView::TestCase - def test_setting_erb_variable_warns - assert_deprecated 'erb_variable' do - ActionView::Base.erb_variable = '_erbout' - end - end -end From 86a042ddd9dba8f62e7328c7258a798aef73d57f Mon Sep 17 00:00:00 2001 From: Jacek Becela Date: Wed, 28 May 2008 21:30:44 +0200 Subject: [PATCH 33/75] Make plugins initialize also from rails/init.rb to ensure consistency with gems used as plugins [#272 state:resolved] --- railties/lib/rails/plugin.rb | 10 +++++++++- .../fixtures/plugins/default/gemlike/init.rb | 1 + .../plugins/default/gemlike/lib/gemlike.rb | 2 ++ .../plugins/default/gemlike/rails/init.rb | 7 +++++++ railties/test/initializer_test.rb | 6 +++--- railties/test/plugin_loader_test.rb | 12 ++++++------ railties/test/plugin_locator_test.rb | 4 ++-- railties/test/plugin_test.rb | 16 ++++++++++++---- 8 files changed, 42 insertions(+), 16 deletions(-) create mode 100644 railties/test/fixtures/plugins/default/gemlike/init.rb create mode 100644 railties/test/fixtures/plugins/default/gemlike/lib/gemlike.rb create mode 100644 railties/test/fixtures/plugins/default/gemlike/rails/init.rb diff --git a/railties/lib/rails/plugin.rb b/railties/lib/rails/plugin.rb index 256f4b0132..a54ab85dbe 100644 --- a/railties/lib/rails/plugin.rb +++ b/railties/lib/rails/plugin.rb @@ -74,10 +74,18 @@ module Rails File.join(directory, 'lib') end - def init_path + def classic_init_path File.join(directory, 'init.rb') end + def gem_init_path + File.join(directory, 'rails', 'init.rb') + end + + def init_path + File.file?(gem_init_path) ? gem_init_path : classic_init_path + end + def has_lib_directory? File.directory?(lib_path) end diff --git a/railties/test/fixtures/plugins/default/gemlike/init.rb b/railties/test/fixtures/plugins/default/gemlike/init.rb new file mode 100644 index 0000000000..6a771b5b68 --- /dev/null +++ b/railties/test/fixtures/plugins/default/gemlike/init.rb @@ -0,0 +1 @@ +raise 'This init.rb should not be evaluated because rails/init.rb exists' diff --git a/railties/test/fixtures/plugins/default/gemlike/lib/gemlike.rb b/railties/test/fixtures/plugins/default/gemlike/lib/gemlike.rb new file mode 100644 index 0000000000..2088103e45 --- /dev/null +++ b/railties/test/fixtures/plugins/default/gemlike/lib/gemlike.rb @@ -0,0 +1,2 @@ +module Gemlike +end \ No newline at end of file diff --git a/railties/test/fixtures/plugins/default/gemlike/rails/init.rb b/railties/test/fixtures/plugins/default/gemlike/rails/init.rb new file mode 100644 index 0000000000..171a293eb3 --- /dev/null +++ b/railties/test/fixtures/plugins/default/gemlike/rails/init.rb @@ -0,0 +1,7 @@ +# I have access to my directory and the Rails config. +raise 'directory expected but undefined in init.rb' unless defined? directory +raise 'config expected but undefined in init.rb' unless defined? config + +# My lib/ dir must be in the load path. +require 'gemlike' +raise 'missing mixin from my lib/ dir' unless defined? Gemlike diff --git a/railties/test/initializer_test.rb b/railties/test/initializer_test.rb index e5da491947..dee7abe05f 100644 --- a/railties/test/initializer_test.rb +++ b/railties/test/initializer_test.rb @@ -173,7 +173,7 @@ uses_mocha "Initializer plugin loading tests" do def test_all_plugins_are_loaded_when_registered_plugin_list_is_untouched failure_tip = "It's likely someone has added a new plugin fixture without updating this list" load_plugins! - assert_plugins [:a, :acts_as_chunky_bacon, :plugin_with_no_lib_dir, :stubby], @initializer.loaded_plugins, failure_tip + assert_plugins [:a, :acts_as_chunky_bacon, :gemlike, :plugin_with_no_lib_dir, :stubby], @initializer.loaded_plugins, failure_tip end def test_all_plugins_loaded_when_all_is_used @@ -181,7 +181,7 @@ uses_mocha "Initializer plugin loading tests" do only_load_the_following_plugins! plugin_names load_plugins! failure_tip = "It's likely someone has added a new plugin fixture without updating this list" - assert_plugins [:stubby, :acts_as_chunky_bacon, :a, :plugin_with_no_lib_dir], @initializer.loaded_plugins, failure_tip + assert_plugins [:stubby, :acts_as_chunky_bacon, :a, :gemlike, :plugin_with_no_lib_dir], @initializer.loaded_plugins, failure_tip end def test_all_plugins_loaded_after_all @@ -189,7 +189,7 @@ uses_mocha "Initializer plugin loading tests" do only_load_the_following_plugins! plugin_names load_plugins! failure_tip = "It's likely someone has added a new plugin fixture without updating this list" - assert_plugins [:stubby, :a, :plugin_with_no_lib_dir, :acts_as_chunky_bacon], @initializer.loaded_plugins, failure_tip + assert_plugins [:stubby, :a, :gemlike, :plugin_with_no_lib_dir, :acts_as_chunky_bacon], @initializer.loaded_plugins, failure_tip end def test_plugin_names_may_be_strings diff --git a/railties/test/plugin_loader_test.rb b/railties/test/plugin_loader_test.rb index bce4446f79..e5fc0926eb 100644 --- a/railties/test/plugin_loader_test.rb +++ b/railties/test/plugin_loader_test.rb @@ -48,16 +48,16 @@ uses_mocha "Plugin Loader Tests" do end def test_should_find_all_availble_plugins_and_return_as_all_plugins - assert_plugins [:stubby, :plugin_with_no_lib_dir, :acts_as_chunky_bacon, :a], @loader.all_plugins.reverse, @failure_tip + assert_plugins [:stubby, :plugin_with_no_lib_dir, :gemlike, :acts_as_chunky_bacon, :a], @loader.all_plugins.reverse, @failure_tip end def test_should_return_all_plugins_as_plugins_when_registered_plugin_list_is_untouched - assert_plugins [:a, :acts_as_chunky_bacon, :plugin_with_no_lib_dir, :stubby], @loader.plugins, @failure_tip + assert_plugins [:a, :acts_as_chunky_bacon, :gemlike, :plugin_with_no_lib_dir, :stubby], @loader.plugins, @failure_tip end def test_should_return_all_plugins_as_plugins_when_registered_plugin_list_is_nil @configuration.plugins = nil - assert_plugins [:a, :acts_as_chunky_bacon, :plugin_with_no_lib_dir, :stubby], @loader.plugins, @failure_tip + assert_plugins [:a, :acts_as_chunky_bacon, :gemlike, :plugin_with_no_lib_dir, :stubby], @loader.plugins, @failure_tip end def test_should_return_specific_plugins_named_in_config_plugins_array_if_set @@ -74,17 +74,17 @@ uses_mocha "Plugin Loader Tests" do def test_should_load_all_plugins_in_natural_order_when_all_is_used only_load_the_following_plugins! [:all] - assert_plugins [:a, :acts_as_chunky_bacon, :plugin_with_no_lib_dir, :stubby], @loader.plugins, @failure_tip + assert_plugins [:a, :acts_as_chunky_bacon, :gemlike, :plugin_with_no_lib_dir, :stubby], @loader.plugins, @failure_tip end def test_should_load_specified_plugins_in_order_and_then_all_remaining_plugins_when_all_is_used only_load_the_following_plugins! [:stubby, :acts_as_chunky_bacon, :all] - assert_plugins [:stubby, :acts_as_chunky_bacon, :a, :plugin_with_no_lib_dir], @loader.plugins, @failure_tip + assert_plugins [:stubby, :acts_as_chunky_bacon, :a, :gemlike, :plugin_with_no_lib_dir], @loader.plugins, @failure_tip end def test_should_be_able_to_specify_loading_of_plugins_loaded_after_all only_load_the_following_plugins! [:stubby, :all, :acts_as_chunky_bacon] - assert_plugins [:stubby, :a, :plugin_with_no_lib_dir, :acts_as_chunky_bacon], @loader.plugins, @failure_tip + assert_plugins [:stubby, :a, :gemlike, :plugin_with_no_lib_dir, :acts_as_chunky_bacon], @loader.plugins, @failure_tip end def test_should_accept_plugin_names_given_as_strings diff --git a/railties/test/plugin_locator_test.rb b/railties/test/plugin_locator_test.rb index 5f1dd991ea..363fa27f15 100644 --- a/railties/test/plugin_locator_test.rb +++ b/railties/test/plugin_locator_test.rb @@ -47,12 +47,12 @@ uses_mocha "Plugin Locator Tests" do end def test_should_return_all_plugins_found_under_the_set_plugin_paths - assert_equal ["a", "acts_as_chunky_bacon", "plugin_with_no_lib_dir", "stubby"].sort, @locator.plugins.map(&:name).sort + assert_equal ["a", "acts_as_chunky_bacon", "gemlike", "plugin_with_no_lib_dir", "stubby"].sort, @locator.plugins.map(&:name).sort end def test_should_find_plugins_only_under_the_plugin_paths_set_in_configuration @configuration.plugin_paths = [File.join(plugin_fixture_root_path, "default")] - assert_equal ["acts_as_chunky_bacon", "plugin_with_no_lib_dir", "stubby"].sort, @locator.plugins.map(&:name).sort + assert_equal ["acts_as_chunky_bacon", "gemlike", "plugin_with_no_lib_dir", "stubby"].sort, @locator.plugins.map(&:name).sort @configuration.plugin_paths = [File.join(plugin_fixture_root_path, "alternate")] assert_equal ["a"], @locator.plugins.map(&:name) diff --git a/railties/test/plugin_test.rb b/railties/test/plugin_test.rb index 1445338f14..50124240a5 100644 --- a/railties/test/plugin_test.rb +++ b/railties/test/plugin_test.rb @@ -5,9 +5,10 @@ uses_mocha "Plugin Tests" do class PluginTest < Test::Unit::TestCase def setup - @initializer = Rails::Initializer.new(Rails::Configuration.new) - @valid_plugin_path = plugin_fixture_path('default/stubby') - @empty_plugin_path = plugin_fixture_path('default/empty') + @initializer = Rails::Initializer.new(Rails::Configuration.new) + @valid_plugin_path = plugin_fixture_path('default/stubby') + @empty_plugin_path = plugin_fixture_path('default/empty') + @gemlike_plugin_path = plugin_fixture_path('default/gemlike') end def test_should_determine_plugin_name_from_the_directory_of_the_plugin @@ -70,7 +71,14 @@ uses_mocha "Plugin Tests" do plugin.stubs(:evaluate_init_rb) plugin.send(:load, @initializer) end - + + # This path is fine so nothing is raised + assert_nothing_raised do + plugin = plugin_for(@gemlike_plugin_path) + plugin.stubs(:evaluate_init_rb) + plugin.send(:load, @initializer) + end + # This is an empty path so it raises assert_raises(LoadError) do plugin = plugin_for(@empty_plugin_path) From a2f6ded73209eeb9c6843b16c0253bbe56236b29 Mon Sep 17 00:00:00 2001 From: Tiago Macedo Date: Sun, 8 Jun 2008 17:00:56 +0100 Subject: [PATCH 34/75] Fix conditions and order on join tables with limited eager loading. [#372 state:resolved] --- activerecord/lib/active_record/associations.rb | 4 +++- activerecord/test/cases/associations/eager_test.rb | 13 ++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index a3d1bbbada..8ddcc24daa 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1638,7 +1638,9 @@ module ActiveRecord end def join_for_table_name(table_name) - @joins.select{|j|j.aliased_table_name == table_name.gsub(/^\"(.*)\"$/){$1} }.first rescue nil + join = (@joins.select{|j|j.aliased_table_name == table_name.gsub(/^\"(.*)\"$/){$1} }.first) rescue nil + return join unless join.nil? + @joins.select{|j|j.is_a?(JoinAssociation) && j.aliased_join_table_name == table_name.gsub(/^\"(.*)\"$/){$1} }.first rescue nil end def joins_for_table_name(table_name) diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index 3a3358e39b..f65ada550b 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -14,11 +14,14 @@ require 'models/job' require 'models/subscriber' require 'models/subscription' require 'models/book' +require 'models/developer' +require 'models/project' class EagerAssociationTest < ActiveRecord::TestCase fixtures :posts, :comments, :authors, :categories, :categories_posts, :companies, :accounts, :tags, :taggings, :people, :readers, - :owners, :pets, :author_favorites, :jobs, :references, :subscribers, :subscriptions, :books + :owners, :pets, :author_favorites, :jobs, :references, :subscribers, :subscriptions, :books, + :developers, :projects def test_loading_with_one_association posts = Post.find(:all, :include => :comments) @@ -609,4 +612,12 @@ class EagerAssociationTest < ActiveRecord::TestCase Comment.find :all, :include => :post end end + + def test_conditions_on_join_table_with_include_and_limit + assert_equal 3, Developer.find(:all, :include => 'projects', :conditions => 'developers_projects.access_level = 1', :limit => 5).size + end + + def test_order_on_join_table_with_include_and_limit + assert_equal 5, Developer.find(:all, :include => 'projects', :order => 'developers_projects.joined_on DESC', :limit => 5).size + end end From 68af8c54af8294a8cf079dfaae0c1c04f5c23e59 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 8 Jun 2008 16:02:25 -0700 Subject: [PATCH 35/75] Remove vendor/mysql.rb. Deprecated in 2.1 stable, gone in 2.2. --- .../connection_adapters/mysql_adapter.rb | 29 +- .../lib/active_record/vendor/mysql.rb | 1214 ----------------- 2 files changed, 4 insertions(+), 1239 deletions(-) delete mode 100644 activerecord/lib/active_record/vendor/mysql.rb diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 653b45021d..b052c0328e 100755 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -42,30 +42,6 @@ end module ActiveRecord class Base - def self.require_mysql - # Include the MySQL driver if one hasn't already been loaded - unless defined? Mysql - begin - require_library_or_gem 'mysql' - rescue LoadError => cannot_require_mysql - # Use the bundled Ruby/MySQL driver if no driver is already in place - begin - ActiveRecord::Base.logger.info( - "WARNING: You're using the Ruby-based MySQL library that ships with Rails. This library is not suited for production. " + - "Please install the C-based MySQL library instead (gem install mysql)." - ) if ActiveRecord::Base.logger - - require 'active_record/vendor/mysql' - rescue LoadError - raise cannot_require_mysql - end - end - end - - # Define Mysql::Result.all_hashes - MysqlCompat.define_all_hashes_method! - end - # Establishes a connection to the database that's used by all Active Record objects. def self.mysql_connection(config) # :nodoc: config = config.symbolize_keys @@ -81,7 +57,10 @@ module ActiveRecord raise ArgumentError, "No database specified. Missing argument: database." end - require_mysql + # Require the MySQL driver and define Mysql::Result.all_hashes + require_library_or_gem('mysql') unless defined? Mysql + MysqlCompat.define_all_hashes_method! + mysql = Mysql.init mysql.ssl_set(config[:sslkey], config[:sslcert], config[:sslca], config[:sslcapath], config[:sslcipher]) if config[:sslkey] diff --git a/activerecord/lib/active_record/vendor/mysql.rb b/activerecord/lib/active_record/vendor/mysql.rb deleted file mode 100644 index 1c3294c719..0000000000 --- a/activerecord/lib/active_record/vendor/mysql.rb +++ /dev/null @@ -1,1214 +0,0 @@ -# $Id: mysql.rb,v 1.24 2005/02/12 11:37:15 tommy Exp $ -# -# Copyright (C) 2003-2005 TOMITA Masahiro -# tommy@tmtm.org -# - -class Mysql - - VERSION = "4.0-ruby-0.2.6-plus-changes" - - require "socket" - require "digest/sha1" - - MAX_PACKET_LENGTH = 256*256*256-1 - MAX_ALLOWED_PACKET = 1024*1024*1024 - - MYSQL_UNIX_ADDR = "/tmp/mysql.sock" - MYSQL_PORT = 3306 - PROTOCOL_VERSION = 10 - - SCRAMBLE_LENGTH = 20 - SCRAMBLE_LENGTH_323 = 8 - - # Command - COM_SLEEP = 0 - COM_QUIT = 1 - COM_INIT_DB = 2 - COM_QUERY = 3 - COM_FIELD_LIST = 4 - COM_CREATE_DB = 5 - COM_DROP_DB = 6 - COM_REFRESH = 7 - COM_SHUTDOWN = 8 - COM_STATISTICS = 9 - COM_PROCESS_INFO = 10 - COM_CONNECT = 11 - COM_PROCESS_KILL = 12 - COM_DEBUG = 13 - COM_PING = 14 - COM_TIME = 15 - COM_DELAYED_INSERT = 16 - COM_CHANGE_USER = 17 - COM_BINLOG_DUMP = 18 - COM_TABLE_DUMP = 19 - COM_CONNECT_OUT = 20 - COM_REGISTER_SLAVE = 21 - - # Client flag - CLIENT_LONG_PASSWORD = 1 - CLIENT_FOUND_ROWS = 1 << 1 - CLIENT_LONG_FLAG = 1 << 2 - CLIENT_CONNECT_WITH_DB= 1 << 3 - CLIENT_NO_SCHEMA = 1 << 4 - CLIENT_COMPRESS = 1 << 5 - CLIENT_ODBC = 1 << 6 - CLIENT_LOCAL_FILES = 1 << 7 - CLIENT_IGNORE_SPACE = 1 << 8 - CLIENT_PROTOCOL_41 = 1 << 9 - CLIENT_INTERACTIVE = 1 << 10 - CLIENT_SSL = 1 << 11 - CLIENT_IGNORE_SIGPIPE = 1 << 12 - CLIENT_TRANSACTIONS = 1 << 13 - CLIENT_RESERVED = 1 << 14 - CLIENT_SECURE_CONNECTION = 1 << 15 - CLIENT_CAPABILITIES = CLIENT_LONG_PASSWORD|CLIENT_LONG_FLAG|CLIENT_TRANSACTIONS - PROTO_AUTH41 = CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION - - # Connection Option - OPT_CONNECT_TIMEOUT = 0 - OPT_COMPRESS = 1 - OPT_NAMED_PIPE = 2 - INIT_COMMAND = 3 - READ_DEFAULT_FILE = 4 - READ_DEFAULT_GROUP = 5 - SET_CHARSET_DIR = 6 - SET_CHARSET_NAME = 7 - OPT_LOCAL_INFILE = 8 - - # Server Status - SERVER_STATUS_IN_TRANS = 1 - SERVER_STATUS_AUTOCOMMIT = 2 - - # Refresh parameter - REFRESH_GRANT = 1 - REFRESH_LOG = 2 - REFRESH_TABLES = 4 - REFRESH_HOSTS = 8 - REFRESH_STATUS = 16 - REFRESH_THREADS = 32 - REFRESH_SLAVE = 64 - REFRESH_MASTER = 128 - - def initialize(*args) - @client_flag = 0 - @max_allowed_packet = MAX_ALLOWED_PACKET - @query_with_result = true - @status = :STATUS_READY - if args[0] != :INIT then - real_connect(*args) - end - end - - def real_connect(host=nil, user=nil, passwd=nil, db=nil, port=nil, socket=nil, flag=nil) - @server_status = SERVER_STATUS_AUTOCOMMIT - if (host == nil or host == "localhost") and defined? UNIXSocket then - unix_socket = socket || ENV["MYSQL_UNIX_PORT"] || MYSQL_UNIX_ADDR - sock = UNIXSocket::new(unix_socket) - @host_info = Error::err(Error::CR_LOCALHOST_CONNECTION) - @unix_socket = unix_socket - else - sock = TCPSocket::new(host, port||ENV["MYSQL_TCP_PORT"]||(Socket::getservbyname("mysql","tcp") rescue MYSQL_PORT)) - @host_info = sprintf Error::err(Error::CR_TCP_CONNECTION), host - end - @host = host ? host.dup : nil - sock.setsockopt Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true - @net = Net::new sock - - a = read - @protocol_version = a.slice!(0) - @server_version, a = a.split(/\0/,2) - @thread_id, @scramble_buff = a.slice!(0,13).unpack("La8") - if a.size >= 2 then - @server_capabilities, = a.slice!(0,2).unpack("v") - end - if a.size >= 16 then - @server_language, @server_status = a.slice!(0,3).unpack("cv") - end - - flag = 0 if flag == nil - flag |= @client_flag | CLIENT_CAPABILITIES - flag |= CLIENT_CONNECT_WITH_DB if db - - @pre_411 = (0 == @server_capabilities & PROTO_AUTH41) - if @pre_411 - data = Net::int2str(flag)+Net::int3str(@max_allowed_packet)+ - (user||"")+"\0"+ - scramble(passwd, @scramble_buff, @protocol_version==9) - else - dummy, @salt2 = a.unpack("a13a12") - @scramble_buff += @salt2 - flag |= PROTO_AUTH41 - data = Net::int4str(flag) + Net::int4str(@max_allowed_packet) + - ([8] + Array.new(23, 0)).pack("c24") + (user||"")+"\0"+ - scramble41(passwd, @scramble_buff) - end - - if db and @server_capabilities & CLIENT_CONNECT_WITH_DB != 0 - data << "\0" if @pre_411 - data << db - @db = db.dup - end - write data - pkt = read - handle_auth_fallback(pkt, passwd) - ObjectSpace.define_finalizer(self, Mysql.finalizer(@net)) - self - end - alias :connect :real_connect - - def handle_auth_fallback(pkt, passwd) - # A packet like this means that we need to send an old-format password - if pkt.size == 1 and pkt[0] == 254 and - @server_capabilities & CLIENT_SECURE_CONNECTION != 0 then - data = scramble(passwd, @scramble_buff, @protocol_version == 9) - write data + "\0" - read - end - end - - def escape_string(str) - Mysql::escape_string str - end - alias :quote :escape_string - - def get_client_info() - VERSION - end - alias :client_info :get_client_info - - def options(option, arg=nil) - if option == OPT_LOCAL_INFILE then - if arg == false or arg == 0 then - @client_flag &= ~CLIENT_LOCAL_FILES - else - @client_flag |= CLIENT_LOCAL_FILES - end - else - raise "not implemented" - end - end - - def real_query(query) - command COM_QUERY, query, true - read_query_result - self - end - - def use_result() - if @status != :STATUS_GET_RESULT then - error Error::CR_COMMANDS_OUT_OF_SYNC - end - res = Result::new self, @fields, @field_count - @status = :STATUS_USE_RESULT - res - end - - def store_result() - if @status != :STATUS_GET_RESULT then - error Error::CR_COMMANDS_OUT_OF_SYNC - end - @status = :STATUS_READY - data = read_rows @field_count - res = Result::new self, @fields, @field_count, data - @fields = nil - @affected_rows = data.length - res - end - - def change_user(user="", passwd="", db="") - if @pre_411 - data = user+"\0"+scramble(passwd, @scramble_buff, @protocol_version==9)+"\0"+db - else - data = user+"\0"+scramble41(passwd, @scramble_buff)+db - end - pkt = command COM_CHANGE_USER, data - handle_auth_fallback(pkt, passwd) - @user = user - @passwd = passwd - @db = db - end - - def character_set_name() - raise "not implemented" - end - - def close() - @status = :STATUS_READY - command COM_QUIT, nil, true - @net.close - self - end - - def create_db(db) - command COM_CREATE_DB, db - self - end - - def drop_db(db) - command COM_DROP_DB, db - self - end - - def dump_debug_info() - command COM_DEBUG - self - end - - def get_host_info() - @host_info - end - alias :host_info :get_host_info - - def get_proto_info() - @protocol_version - end - alias :proto_info :get_proto_info - - def get_server_info() - @server_version - end - alias :server_info :get_server_info - - def kill(id) - command COM_PROCESS_KILL, Net::int4str(id) - self - end - - def list_dbs(db=nil) - real_query "show databases #{db}" - @status = :STATUS_READY - read_rows(1).flatten - end - - def list_fields(table, field=nil) - command COM_FIELD_LIST, "#{table}\0#{field}", true - if @pre_411 - f = read_rows 6 - else - f = read_rows 7 - end - fields = unpack_fields(f, @server_capabilities & CLIENT_LONG_FLAG != 0) - res = Result::new self, fields, f.length - res.eof = true - res - end - - def list_processes() - data = command COM_PROCESS_INFO - @field_count = get_length data - if @pre_411 - fields = read_rows 5 - else - fields = read_rows 7 - end - @fields = unpack_fields(fields, @server_capabilities & CLIENT_LONG_FLAG != 0) - @status = :STATUS_GET_RESULT - store_result - end - - def list_tables(table=nil) - real_query "show tables #{table}" - @status = :STATUS_READY - read_rows(1).flatten - end - - def ping() - command COM_PING - self - end - - def query(query) - real_query query - if not @query_with_result then - return self - end - if @field_count == 0 then - return nil - end - store_result - end - - def refresh(r) - command COM_REFRESH, r.chr - self - end - - def reload() - refresh REFRESH_GRANT - self - end - - def select_db(db) - command COM_INIT_DB, db - @db = db - self - end - - def shutdown() - command COM_SHUTDOWN - self - end - - def stat() - command COM_STATISTICS - end - - attr_reader :info, :insert_id, :affected_rows, :field_count, :thread_id - attr_accessor :query_with_result, :status - - def read_one_row(field_count) - data = read - if data[0] == 254 and data.length == 1 ## EOF - return - elsif data[0] == 254 and data.length == 5 - return - end - rec = [] - field_count.times do - len = get_length data - if len == nil then - rec << len - else - rec << data.slice!(0,len) - end - end - rec - end - - def skip_result() - if @status == :STATUS_USE_RESULT then - loop do - data = read - break if data[0] == 254 and data.length == 1 - end - @status = :STATUS_READY - end - end - - def inspect() - "#<#{self.class}>" - end - - private - - def read_query_result() - data = read - @field_count = get_length(data) - if @field_count == nil then # LOAD DATA LOCAL INFILE - File::open(data) do |f| - write f.read - end - write "" # mark EOF - data = read - @field_count = get_length(data) - end - if @field_count == 0 then - @affected_rows = get_length(data, true) - @insert_id = get_length(data, true) - if @server_capabilities & CLIENT_TRANSACTIONS != 0 then - a = data.slice!(0,2) - @server_status = a[0]+a[1]*256 - end - if data.size > 0 and get_length(data) then - @info = data - end - else - @extra_info = get_length(data, true) - if @pre_411 - fields = read_rows(5) - else - fields = read_rows(7) - end - @fields = unpack_fields(fields, @server_capabilities & CLIENT_LONG_FLAG != 0) - @status = :STATUS_GET_RESULT - end - self - end - - def unpack_fields(data, long_flag_protocol) - ret = [] - data.each do |f| - if @pre_411 - table = org_table = f[0] - name = f[1] - length = f[2][0]+f[2][1]*256+f[2][2]*256*256 - type = f[3][0] - if long_flag_protocol then - flags = f[4][0]+f[4][1]*256 - decimals = f[4][2] - else - flags = f[4][0] - decimals = f[4][1] - end - def_value = f[5] - max_length = 0 - else - catalog = f[0] - db = f[1] - table = f[2] - org_table = f[3] - name = f[4] - org_name = f[5] - length = f[6][2]+f[6][3]*256+f[6][4]*256*256 - type = f[6][6] - flags = f[6][7]+f[6][8]*256 - decimals = f[6][9] - def_value = "" - max_length = 0 - end - ret << Field::new(table, org_table, name, length, type, flags, decimals, def_value, max_length) - end - ret - end - - def read_rows(field_count) - ret = [] - while rec = read_one_row(field_count) do - ret << rec - end - ret - end - - def get_length(data, longlong=nil) - return if data.length == 0 - c = data.slice!(0) - case c - when 251 - return nil - when 252 - a = data.slice!(0,2) - return a[0]+a[1]*256 - when 253 - a = data.slice!(0,3) - return a[0]+a[1]*256+a[2]*256**2 - when 254 - a = data.slice!(0,8) - if longlong then - return a[0]+a[1]*256+a[2]*256**2+a[3]*256**3+ - a[4]*256**4+a[5]*256**5+a[6]*256**6+a[7]*256**7 - else - return a[0]+a[1]*256+a[2]*256**2+a[3]*256**3 - end - else - c - end - end - - def command(cmd, arg=nil, skip_check=nil) - unless @net then - error Error::CR_SERVER_GONE_ERROR - end - if @status != :STATUS_READY then - error Error::CR_COMMANDS_OUT_OF_SYNC - end - @net.clear - write cmd.chr+(arg||"") - read unless skip_check - end - - def read() - unless @net then - error Error::CR_SERVER_GONE_ERROR - end - a = @net.read - if a[0] == 255 then - if a.length > 3 then - @errno = a[1]+a[2]*256 - @error = a[3 .. -1] - else - @errno = Error::CR_UNKNOWN_ERROR - @error = Error::err @errno - end - raise Error::new(@errno, @error) - end - a - end - - def write(arg) - unless @net then - error Error::CR_SERVER_GONE_ERROR - end - @net.write arg - end - - def hash_password(password) - nr = 1345345333 - add = 7 - nr2 = 0x12345671 - password.each_byte do |i| - next if i == 0x20 or i == 9 - nr ^= (((nr & 63) + add) * i) + (nr << 8) - nr2 += (nr2 << 8) ^ nr - add += i - end - [nr & ((1 << 31) - 1), nr2 & ((1 << 31) - 1)] - end - - def scramble(password, message, old_ver) - return "" if password == nil or password == "" - raise "old version password is not implemented" if old_ver - hash_pass = hash_password password - hash_message = hash_password message.slice(0,SCRAMBLE_LENGTH_323) - rnd = Random::new hash_pass[0] ^ hash_message[0], hash_pass[1] ^ hash_message[1] - to = [] - 1.upto(SCRAMBLE_LENGTH_323) do - to << ((rnd.rnd*31)+64).floor - end - extra = (rnd.rnd*31).floor - to.map! do |t| (t ^ extra).chr end - to.join - end - - def scramble41(password, message) - return 0x00.chr if password.nil? or password.empty? - buf = [0x14] - s1 = Digest::SHA1.digest(password) - s2 = Digest::SHA1.digest(s1) - x = Digest::SHA1.digest(message + s2) - (0..s1.length - 1).each {|i| buf.push(s1[i] ^ x[i])} - buf.pack("C*") - end - - def error(errno) - @errno = errno - @error = Error::err errno - raise Error::new(@errno, @error) - end - - class Result - def initialize(mysql, fields, field_count, data=nil) - @handle = mysql - @fields = fields - @field_count = field_count - @data = data - @current_field = 0 - @current_row = 0 - @eof = false - @row_count = 0 - end - attr_accessor :eof - - def data_seek(n) - @current_row = n - end - - def fetch_field() - return if @current_field >= @field_count - f = @fields[@current_field] - @current_field += 1 - f - end - - def fetch_fields() - @fields - end - - def fetch_field_direct(n) - @fields[n] - end - - def fetch_lengths() - @data ? @data[@current_row].map{|i| i ? i.length : 0} : @lengths - end - - def fetch_row() - if @data then - if @current_row >= @data.length then - @handle.status = :STATUS_READY - return - end - ret = @data[@current_row] - @current_row += 1 - else - return if @eof - ret = @handle.read_one_row @field_count - if ret == nil then - @eof = true - return - end - @lengths = ret.map{|i| i ? i.length : 0} - @row_count += 1 - end - ret - end - - def fetch_hash(with_table=nil) - row = fetch_row - return if row == nil - hash = {} - @fields.each_index do |i| - f = with_table ? @fields[i].table+"."+@fields[i].name : @fields[i].name - hash[f] = row[i] - end - hash - end - - def field_seek(n) - @current_field = n - end - - def field_tell() - @current_field - end - - def free() - @handle.skip_result - @handle = @fields = @data = nil - end - - def num_fields() - @field_count - end - - def num_rows() - @data ? @data.length : @row_count - end - - def row_seek(n) - @current_row = n - end - - def row_tell() - @current_row - end - - def each() - while row = fetch_row do - yield row - end - end - - def each_hash(with_table=nil) - while hash = fetch_hash(with_table) do - yield hash - end - end - - def inspect() - "#<#{self.class}>" - end - - end - - class Field - # Field type - TYPE_DECIMAL = 0 - TYPE_TINY = 1 - TYPE_SHORT = 2 - TYPE_LONG = 3 - TYPE_FLOAT = 4 - TYPE_DOUBLE = 5 - TYPE_NULL = 6 - TYPE_TIMESTAMP = 7 - TYPE_LONGLONG = 8 - TYPE_INT24 = 9 - TYPE_DATE = 10 - TYPE_TIME = 11 - TYPE_DATETIME = 12 - TYPE_YEAR = 13 - TYPE_NEWDATE = 14 - TYPE_ENUM = 247 - TYPE_SET = 248 - TYPE_TINY_BLOB = 249 - TYPE_MEDIUM_BLOB = 250 - TYPE_LONG_BLOB = 251 - TYPE_BLOB = 252 - TYPE_VAR_STRING = 253 - TYPE_STRING = 254 - TYPE_GEOMETRY = 255 - TYPE_CHAR = TYPE_TINY - TYPE_INTERVAL = TYPE_ENUM - - # Flag - NOT_NULL_FLAG = 1 - PRI_KEY_FLAG = 2 - UNIQUE_KEY_FLAG = 4 - MULTIPLE_KEY_FLAG = 8 - BLOB_FLAG = 16 - UNSIGNED_FLAG = 32 - ZEROFILL_FLAG = 64 - BINARY_FLAG = 128 - ENUM_FLAG = 256 - AUTO_INCREMENT_FLAG = 512 - TIMESTAMP_FLAG = 1024 - SET_FLAG = 2048 - NUM_FLAG = 32768 - PART_KEY_FLAG = 16384 - GROUP_FLAG = 32768 - UNIQUE_FLAG = 65536 - - def initialize(table, org_table, name, length, type, flags, decimals, def_value, max_length) - @table = table - @org_table = org_table - @name = name - @length = length - @type = type - @flags = flags - @decimals = decimals - @def = def_value - @max_length = max_length - if (type <= TYPE_INT24 and (type != TYPE_TIMESTAMP or length == 14 or length == 8)) or type == TYPE_YEAR then - @flags |= NUM_FLAG - end - end - attr_reader :table, :org_table, :name, :length, :type, :flags, :decimals, :def, :max_length - - def inspect() - "#<#{self.class}:#{@name}>" - end - end - - class Error < StandardError - # Server Error - ER_HASHCHK = 1000 - ER_NISAMCHK = 1001 - ER_NO = 1002 - ER_YES = 1003 - ER_CANT_CREATE_FILE = 1004 - ER_CANT_CREATE_TABLE = 1005 - ER_CANT_CREATE_DB = 1006 - ER_DB_CREATE_EXISTS = 1007 - ER_DB_DROP_EXISTS = 1008 - ER_DB_DROP_DELETE = 1009 - ER_DB_DROP_RMDIR = 1010 - ER_CANT_DELETE_FILE = 1011 - ER_CANT_FIND_SYSTEM_REC = 1012 - ER_CANT_GET_STAT = 1013 - ER_CANT_GET_WD = 1014 - ER_CANT_LOCK = 1015 - ER_CANT_OPEN_FILE = 1016 - ER_FILE_NOT_FOUND = 1017 - ER_CANT_READ_DIR = 1018 - ER_CANT_SET_WD = 1019 - ER_CHECKREAD = 1020 - ER_DISK_FULL = 1021 - ER_DUP_KEY = 1022 - ER_ERROR_ON_CLOSE = 1023 - ER_ERROR_ON_READ = 1024 - ER_ERROR_ON_RENAME = 1025 - ER_ERROR_ON_WRITE = 1026 - ER_FILE_USED = 1027 - ER_FILSORT_ABORT = 1028 - ER_FORM_NOT_FOUND = 1029 - ER_GET_ERRNO = 1030 - ER_ILLEGAL_HA = 1031 - ER_KEY_NOT_FOUND = 1032 - ER_NOT_FORM_FILE = 1033 - ER_NOT_KEYFILE = 1034 - ER_OLD_KEYFILE = 1035 - ER_OPEN_AS_READONLY = 1036 - ER_OUTOFMEMORY = 1037 - ER_OUT_OF_SORTMEMORY = 1038 - ER_UNEXPECTED_EOF = 1039 - ER_CON_COUNT_ERROR = 1040 - ER_OUT_OF_RESOURCES = 1041 - ER_BAD_HOST_ERROR = 1042 - ER_HANDSHAKE_ERROR = 1043 - ER_DBACCESS_DENIED_ERROR = 1044 - ER_ACCESS_DENIED_ERROR = 1045 - ER_NO_DB_ERROR = 1046 - ER_UNKNOWN_COM_ERROR = 1047 - ER_BAD_NULL_ERROR = 1048 - ER_BAD_DB_ERROR = 1049 - ER_TABLE_EXISTS_ERROR = 1050 - ER_BAD_TABLE_ERROR = 1051 - ER_NON_UNIQ_ERROR = 1052 - ER_SERVER_SHUTDOWN = 1053 - ER_BAD_FIELD_ERROR = 1054 - ER_WRONG_FIELD_WITH_GROUP = 1055 - ER_WRONG_GROUP_FIELD = 1056 - ER_WRONG_SUM_SELECT = 1057 - ER_WRONG_VALUE_COUNT = 1058 - ER_TOO_LONG_IDENT = 1059 - ER_DUP_FIELDNAME = 1060 - ER_DUP_KEYNAME = 1061 - ER_DUP_ENTRY = 1062 - ER_WRONG_FIELD_SPEC = 1063 - ER_PARSE_ERROR = 1064 - ER_EMPTY_QUERY = 1065 - ER_NONUNIQ_TABLE = 1066 - ER_INVALID_DEFAULT = 1067 - ER_MULTIPLE_PRI_KEY = 1068 - ER_TOO_MANY_KEYS = 1069 - ER_TOO_MANY_KEY_PARTS = 1070 - ER_TOO_LONG_KEY = 1071 - ER_KEY_COLUMN_DOES_NOT_EXITS = 1072 - ER_BLOB_USED_AS_KEY = 1073 - ER_TOO_BIG_FIELDLENGTH = 1074 - ER_WRONG_AUTO_KEY = 1075 - ER_READY = 1076 - ER_NORMAL_SHUTDOWN = 1077 - ER_GOT_SIGNAL = 1078 - ER_SHUTDOWN_COMPLETE = 1079 - ER_FORCING_CLOSE = 1080 - ER_IPSOCK_ERROR = 1081 - ER_NO_SUCH_INDEX = 1082 - ER_WRONG_FIELD_TERMINATORS = 1083 - ER_BLOBS_AND_NO_TERMINATED = 1084 - ER_TEXTFILE_NOT_READABLE = 1085 - ER_FILE_EXISTS_ERROR = 1086 - ER_LOAD_INFO = 1087 - ER_ALTER_INFO = 1088 - ER_WRONG_SUB_KEY = 1089 - ER_CANT_REMOVE_ALL_FIELDS = 1090 - ER_CANT_DROP_FIELD_OR_KEY = 1091 - ER_INSERT_INFO = 1092 - ER_INSERT_TABLE_USED = 1093 - ER_NO_SUCH_THREAD = 1094 - ER_KILL_DENIED_ERROR = 1095 - ER_NO_TABLES_USED = 1096 - ER_TOO_BIG_SET = 1097 - ER_NO_UNIQUE_LOGFILE = 1098 - ER_TABLE_NOT_LOCKED_FOR_WRITE = 1099 - ER_TABLE_NOT_LOCKED = 1100 - ER_BLOB_CANT_HAVE_DEFAULT = 1101 - ER_WRONG_DB_NAME = 1102 - ER_WRONG_TABLE_NAME = 1103 - ER_TOO_BIG_SELECT = 1104 - ER_UNKNOWN_ERROR = 1105 - ER_UNKNOWN_PROCEDURE = 1106 - ER_WRONG_PARAMCOUNT_TO_PROCEDURE = 1107 - ER_WRONG_PARAMETERS_TO_PROCEDURE = 1108 - ER_UNKNOWN_TABLE = 1109 - ER_FIELD_SPECIFIED_TWICE = 1110 - ER_INVALID_GROUP_FUNC_USE = 1111 - ER_UNSUPPORTED_EXTENSION = 1112 - ER_TABLE_MUST_HAVE_COLUMNS = 1113 - ER_RECORD_FILE_FULL = 1114 - ER_UNKNOWN_CHARACTER_SET = 1115 - ER_TOO_MANY_TABLES = 1116 - ER_TOO_MANY_FIELDS = 1117 - ER_TOO_BIG_ROWSIZE = 1118 - ER_STACK_OVERRUN = 1119 - ER_WRONG_OUTER_JOIN = 1120 - ER_NULL_COLUMN_IN_INDEX = 1121 - ER_CANT_FIND_UDF = 1122 - ER_CANT_INITIALIZE_UDF = 1123 - ER_UDF_NO_PATHS = 1124 - ER_UDF_EXISTS = 1125 - ER_CANT_OPEN_LIBRARY = 1126 - ER_CANT_FIND_DL_ENTRY = 1127 - ER_FUNCTION_NOT_DEFINED = 1128 - ER_HOST_IS_BLOCKED = 1129 - ER_HOST_NOT_PRIVILEGED = 1130 - ER_PASSWORD_ANONYMOUS_USER = 1131 - ER_PASSWORD_NOT_ALLOWED = 1132 - ER_PASSWORD_NO_MATCH = 1133 - ER_UPDATE_INFO = 1134 - ER_CANT_CREATE_THREAD = 1135 - ER_WRONG_VALUE_COUNT_ON_ROW = 1136 - ER_CANT_REOPEN_TABLE = 1137 - ER_INVALID_USE_OF_NULL = 1138 - ER_REGEXP_ERROR = 1139 - ER_MIX_OF_GROUP_FUNC_AND_FIELDS = 1140 - ER_NONEXISTING_GRANT = 1141 - ER_TABLEACCESS_DENIED_ERROR = 1142 - ER_COLUMNACCESS_DENIED_ERROR = 1143 - ER_ILLEGAL_GRANT_FOR_TABLE = 1144 - ER_GRANT_WRONG_HOST_OR_USER = 1145 - ER_NO_SUCH_TABLE = 1146 - ER_NONEXISTING_TABLE_GRANT = 1147 - ER_NOT_ALLOWED_COMMAND = 1148 - ER_SYNTAX_ERROR = 1149 - ER_DELAYED_CANT_CHANGE_LOCK = 1150 - ER_TOO_MANY_DELAYED_THREADS = 1151 - ER_ABORTING_CONNECTION = 1152 - ER_NET_PACKET_TOO_LARGE = 1153 - ER_NET_READ_ERROR_FROM_PIPE = 1154 - ER_NET_FCNTL_ERROR = 1155 - ER_NET_PACKETS_OUT_OF_ORDER = 1156 - ER_NET_UNCOMPRESS_ERROR = 1157 - ER_NET_READ_ERROR = 1158 - ER_NET_READ_INTERRUPTED = 1159 - ER_NET_ERROR_ON_WRITE = 1160 - ER_NET_WRITE_INTERRUPTED = 1161 - ER_TOO_LONG_STRING = 1162 - ER_TABLE_CANT_HANDLE_BLOB = 1163 - ER_TABLE_CANT_HANDLE_AUTO_INCREMENT = 1164 - ER_DELAYED_INSERT_TABLE_LOCKED = 1165 - ER_WRONG_COLUMN_NAME = 1166 - ER_WRONG_KEY_COLUMN = 1167 - ER_WRONG_MRG_TABLE = 1168 - ER_DUP_UNIQUE = 1169 - ER_BLOB_KEY_WITHOUT_LENGTH = 1170 - ER_PRIMARY_CANT_HAVE_NULL = 1171 - ER_TOO_MANY_ROWS = 1172 - ER_REQUIRES_PRIMARY_KEY = 1173 - ER_NO_RAID_COMPILED = 1174 - ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE = 1175 - ER_KEY_DOES_NOT_EXITS = 1176 - ER_CHECK_NO_SUCH_TABLE = 1177 - ER_CHECK_NOT_IMPLEMENTED = 1178 - ER_CANT_DO_THIS_DURING_AN_TRANSACTION = 1179 - ER_ERROR_DURING_COMMIT = 1180 - ER_ERROR_DURING_ROLLBACK = 1181 - ER_ERROR_DURING_FLUSH_LOGS = 1182 - ER_ERROR_DURING_CHECKPOINT = 1183 - ER_NEW_ABORTING_CONNECTION = 1184 - ER_DUMP_NOT_IMPLEMENTED = 1185 - ER_FLUSH_MASTER_BINLOG_CLOSED = 1186 - ER_INDEX_REBUILD = 1187 - ER_MASTER = 1188 - ER_MASTER_NET_READ = 1189 - ER_MASTER_NET_WRITE = 1190 - ER_FT_MATCHING_KEY_NOT_FOUND = 1191 - ER_LOCK_OR_ACTIVE_TRANSACTION = 1192 - ER_UNKNOWN_SYSTEM_VARIABLE = 1193 - ER_CRASHED_ON_USAGE = 1194 - ER_CRASHED_ON_REPAIR = 1195 - ER_WARNING_NOT_COMPLETE_ROLLBACK = 1196 - ER_TRANS_CACHE_FULL = 1197 - ER_SLAVE_MUST_STOP = 1198 - ER_SLAVE_NOT_RUNNING = 1199 - ER_BAD_SLAVE = 1200 - ER_MASTER_INFO = 1201 - ER_SLAVE_THREAD = 1202 - ER_TOO_MANY_USER_CONNECTIONS = 1203 - ER_SET_CONSTANTS_ONLY = 1204 - ER_LOCK_WAIT_TIMEOUT = 1205 - ER_LOCK_TABLE_FULL = 1206 - ER_READ_ONLY_TRANSACTION = 1207 - ER_DROP_DB_WITH_READ_LOCK = 1208 - ER_CREATE_DB_WITH_READ_LOCK = 1209 - ER_WRONG_ARGUMENTS = 1210 - ER_NO_PERMISSION_TO_CREATE_USER = 1211 - ER_UNION_TABLES_IN_DIFFERENT_DIR = 1212 - ER_LOCK_DEADLOCK = 1213 - ER_TABLE_CANT_HANDLE_FULLTEXT = 1214 - ER_CANNOT_ADD_FOREIGN = 1215 - ER_NO_REFERENCED_ROW = 1216 - ER_ROW_IS_REFERENCED = 1217 - ER_CONNECT_TO_MASTER = 1218 - ER_QUERY_ON_MASTER = 1219 - ER_ERROR_WHEN_EXECUTING_COMMAND = 1220 - ER_WRONG_USAGE = 1221 - ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT = 1222 - ER_CANT_UPDATE_WITH_READLOCK = 1223 - ER_MIXING_NOT_ALLOWED = 1224 - ER_DUP_ARGUMENT = 1225 - ER_USER_LIMIT_REACHED = 1226 - ER_SPECIFIC_ACCESS_DENIED_ERROR = 1227 - ER_LOCAL_VARIABLE = 1228 - ER_GLOBAL_VARIABLE = 1229 - ER_NO_DEFAULT = 1230 - ER_WRONG_VALUE_FOR_VAR = 1231 - ER_WRONG_TYPE_FOR_VAR = 1232 - ER_VAR_CANT_BE_READ = 1233 - ER_CANT_USE_OPTION_HERE = 1234 - ER_NOT_SUPPORTED_YET = 1235 - ER_MASTER_FATAL_ERROR_READING_BINLOG = 1236 - ER_SLAVE_IGNORED_TABLE = 1237 - ER_ERROR_MESSAGES = 238 - - # Client Error - CR_MIN_ERROR = 2000 - CR_MAX_ERROR = 2999 - CR_UNKNOWN_ERROR = 2000 - CR_SOCKET_CREATE_ERROR = 2001 - CR_CONNECTION_ERROR = 2002 - CR_CONN_HOST_ERROR = 2003 - CR_IPSOCK_ERROR = 2004 - CR_UNKNOWN_HOST = 2005 - CR_SERVER_GONE_ERROR = 2006 - CR_VERSION_ERROR = 2007 - CR_OUT_OF_MEMORY = 2008 - CR_WRONG_HOST_INFO = 2009 - CR_LOCALHOST_CONNECTION = 2010 - CR_TCP_CONNECTION = 2011 - CR_SERVER_HANDSHAKE_ERR = 2012 - CR_SERVER_LOST = 2013 - CR_COMMANDS_OUT_OF_SYNC = 2014 - CR_NAMEDPIPE_CONNECTION = 2015 - CR_NAMEDPIPEWAIT_ERROR = 2016 - CR_NAMEDPIPEOPEN_ERROR = 2017 - CR_NAMEDPIPESETSTATE_ERROR = 2018 - CR_CANT_READ_CHARSET = 2019 - CR_NET_PACKET_TOO_LARGE = 2020 - CR_EMBEDDED_CONNECTION = 2021 - CR_PROBE_SLAVE_STATUS = 2022 - CR_PROBE_SLAVE_HOSTS = 2023 - CR_PROBE_SLAVE_CONNECT = 2024 - CR_PROBE_MASTER_CONNECT = 2025 - CR_SSL_CONNECTION_ERROR = 2026 - CR_MALFORMED_PACKET = 2027 - - CLIENT_ERRORS = [ - "Unknown MySQL error", - "Can't create UNIX socket (%d)", - "Can't connect to local MySQL server through socket '%-.64s' (%d)", - "Can't connect to MySQL server on '%-.64s' (%d)", - "Can't create TCP/IP socket (%d)", - "Unknown MySQL Server Host '%-.64s' (%d)", - "MySQL server has gone away", - "Protocol mismatch. Server Version = %d Client Version = %d", - "MySQL client run out of memory", - "Wrong host info", - "Localhost via UNIX socket", - "%-.64s via TCP/IP", - "Error in server handshake", - "Lost connection to MySQL server during query", - "Commands out of sync; You can't run this command now", - "%-.64s via named pipe", - "Can't wait for named pipe to host: %-.64s pipe: %-.32s (%lu)", - "Can't open named pipe to host: %-.64s pipe: %-.32s (%lu)", - "Can't set state of named pipe to host: %-.64s pipe: %-.32s (%lu)", - "Can't initialize character set %-.64s (path: %-.64s)", - "Got packet bigger than 'max_allowed_packet'", - "Embedded server", - "Error on SHOW SLAVE STATUS:", - "Error on SHOW SLAVE HOSTS:", - "Error connecting to slave:", - "Error connecting to master:", - "SSL connection error", - "Malformed packet" - ] - - def initialize(errno, error) - @errno = errno - @error = error - super error - end - attr_reader :errno, :error - - def Error::err(errno) - CLIENT_ERRORS[errno - Error::CR_MIN_ERROR] - end - end - - class Net - def initialize(sock) - @sock = sock - @pkt_nr = 0 - end - - def clear() - @pkt_nr = 0 - end - - def read() - buf = [] - len = nil - @sock.sync = false - while len == nil or len == MAX_PACKET_LENGTH do - a = @sock.read(4) - len = a[0]+a[1]*256+a[2]*256*256 - pkt_nr = a[3] - if @pkt_nr != pkt_nr then - raise "Packets out of order: #{@pkt_nr}<>#{pkt_nr}" - end - @pkt_nr = @pkt_nr + 1 & 0xff - buf << @sock.read(len) - end - @sock.sync = true - buf.join - rescue - errno = Error::CR_SERVER_LOST - raise Error::new(errno, Error::err(errno)) - end - - def write(data) - if data.is_a? Array then - data = data.join - end - @sock.sync = false - ptr = 0 - while data.length >= MAX_PACKET_LENGTH do - @sock.write Net::int3str(MAX_PACKET_LENGTH)+@pkt_nr.chr+data[ptr, MAX_PACKET_LENGTH] - @pkt_nr = @pkt_nr + 1 & 0xff - ptr += MAX_PACKET_LENGTH - end - @sock.write Net::int3str(data.length-ptr)+@pkt_nr.chr+data[ptr .. -1] - @pkt_nr = @pkt_nr + 1 & 0xff - @sock.sync = true - @sock.flush - rescue - errno = Error::CR_SERVER_LOST - raise Error::new(errno, Error::err(errno)) - end - - def close() - @sock.close - end - - def Net::int2str(n) - [n].pack("v") - end - - def Net::int3str(n) - [n%256, n>>8].pack("cv") - end - - def Net::int4str(n) - [n].pack("V") - end - - end - - class Random - def initialize(seed1, seed2) - @max_value = 0x3FFFFFFF - @seed1 = seed1 % @max_value - @seed2 = seed2 % @max_value - end - - def rnd() - @seed1 = (@seed1*3+@seed2) % @max_value - @seed2 = (@seed1+@seed2+33) % @max_value - @seed1.to_f / @max_value - end - end - -end - -class << Mysql - def init() - Mysql::new :INIT - end - - def real_connect(*args) - Mysql::new(*args) - end - alias :connect :real_connect - - def finalizer(net) - proc { - net.clear - begin - net.write(Mysql::COM_QUIT.chr) - net.close - rescue # Ignore IOError if socket is already closed. - end - } - end - - def escape_string(str) - str.gsub(/([\0\n\r\032\'\"\\])/) do - case $1 - when "\0" then "\\0" - when "\n" then "\\n" - when "\r" then "\\r" - when "\032" then "\\Z" - else "\\"+$1 - end - end - end - alias :quote :escape_string - - def get_client_info() - Mysql::VERSION - end - alias :client_info :get_client_info - - def debug(str) - raise "not implemented" - end -end - -# -# for compatibility -# - -MysqlRes = Mysql::Result -MysqlField = Mysql::Field -MysqlError = Mysql::Error From d9fb021845c0481c5119eebdc534aec427072f7d Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 8 Jun 2008 16:02:49 -0700 Subject: [PATCH 36/75] Remove dead, unused vendor/db2.rb --- activerecord/lib/active_record/vendor/db2.rb | 362 ------------------- 1 file changed, 362 deletions(-) delete mode 100644 activerecord/lib/active_record/vendor/db2.rb diff --git a/activerecord/lib/active_record/vendor/db2.rb b/activerecord/lib/active_record/vendor/db2.rb deleted file mode 100644 index 812c8cc517..0000000000 --- a/activerecord/lib/active_record/vendor/db2.rb +++ /dev/null @@ -1,362 +0,0 @@ -require 'db2/db2cli.rb' - -module DB2 - module DB2Util - include DB2CLI - - def free() SQLFreeHandle(@handle_type, @handle); end - def handle() @handle; end - - def check_rc(rc) - if ![SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NO_DATA_FOUND].include?(rc) - rec = 1 - msg = '' - loop do - a = SQLGetDiagRec(@handle_type, @handle, rec, 500) - break if a[0] != SQL_SUCCESS - msg << a[3] if !a[3].nil? and a[3] != '' # Create message. - rec += 1 - end - raise "DB2 error: #{msg}" - end - end - end - - class Environment - include DB2Util - - def initialize - @handle_type = SQL_HANDLE_ENV - rc, @handle = SQLAllocHandle(@handle_type, SQL_NULL_HANDLE) - check_rc(rc) - end - - def data_sources(buffer_length = 1024) - retval = [] - max_buffer_length = buffer_length - - a = SQLDataSources(@handle, SQL_FETCH_FIRST, SQL_MAX_DSN_LENGTH + 1, buffer_length) - retval << [a[1], a[3]] - max_buffer_length = [max_buffer_length, a[4]].max - - loop do - a = SQLDataSources(@handle, SQL_FETCH_NEXT, SQL_MAX_DSN_LENGTH + 1, buffer_length) - break if a[0] == SQL_NO_DATA_FOUND - - retval << [a[1], a[3]] - max_buffer_length = [max_buffer_length, a[4]].max - end - - if max_buffer_length > buffer_length - get_data_sources(max_buffer_length) - else - retval - end - end - end - - class Connection - include DB2Util - - def initialize(environment) - @env = environment - @handle_type = SQL_HANDLE_DBC - rc, @handle = SQLAllocHandle(@handle_type, @env.handle) - check_rc(rc) - end - - def connect(server_name, user_name = '', auth = '') - check_rc(SQLConnect(@handle, server_name, user_name.to_s, auth.to_s)) - end - - def set_connect_attr(attr, value) - value += "\0" if value.class == String - check_rc(SQLSetConnectAttr(@handle, attr, value)) - end - - def set_auto_commit_on - set_connect_attr(SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON) - end - - def set_auto_commit_off - set_connect_attr(SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF) - end - - def disconnect - check_rc(SQLDisconnect(@handle)) - end - - def rollback - check_rc(SQLEndTran(@handle_type, @handle, SQL_ROLLBACK)) - end - - def commit - check_rc(SQLEndTran(@handle_type, @handle, SQL_COMMIT)) - end - end - - class Statement - include DB2Util - - def initialize(connection) - @conn = connection - @handle_type = SQL_HANDLE_STMT - @parms = [] #yun - @sql = '' #yun - @numParms = 0 #yun - @prepared = false #yun - @parmArray = [] #yun. attributes of the parameter markers - rc, @handle = SQLAllocHandle(@handle_type, @conn.handle) - check_rc(rc) - end - - def columns(table_name, schema_name = '%') - check_rc(SQLColumns(@handle, '', schema_name.upcase, table_name.upcase, '%')) - fetch_all - end - - def tables(schema_name = '%') - check_rc(SQLTables(@handle, '', schema_name.upcase, '%', 'TABLE')) - fetch_all - end - - def indexes(table_name, schema_name = '') - check_rc(SQLStatistics(@handle, '', schema_name.upcase, table_name.upcase, SQL_INDEX_ALL, SQL_ENSURE)) - fetch_all - end - - def prepare(sql) - @sql = sql - check_rc(SQLPrepare(@handle, sql)) - rc, @numParms = SQLNumParams(@handle) #number of question marks - check_rc(rc) - #-------------------------------------------------------------------------- - # parameter attributes are stored in instance variable @parmArray so that - # they are available when execute method is called. - #-------------------------------------------------------------------------- - if @numParms > 0 # get parameter marker attributes - 1.upto(@numParms) do |i| # parameter number starts from 1 - rc, type, size, decimalDigits = SQLDescribeParam(@handle, i) - check_rc(rc) - @parmArray << Parameter.new(type, size, decimalDigits) - end - end - @prepared = true - self - end - - def execute(*parms) - raise "The statement was not prepared" if @prepared == false - - if parms.size == 1 and parms[0].class == Array - parms = parms[0] - end - - if @numParms != parms.size - raise "Number of parameters supplied does not match with the SQL statement" - end - - if @numParms > 0 #need to bind parameters - #-------------------------------------------------------------------- - #calling bindParms may not be safe. Look comment below. - #-------------------------------------------------------------------- - #bindParms(parms) - - valueArray = [] - 1.upto(@numParms) do |i| # parameter number starts from 1 - type = @parmArray[i - 1].class - size = @parmArray[i - 1].size - decimalDigits = @parmArray[i - 1].decimalDigits - - if parms[i - 1].class == String - valueArray << parms[i - 1] - else - valueArray << parms[i - 1].to_s - end - - rc = SQLBindParameter(@handle, i, type, size, decimalDigits, valueArray[i - 1]) - check_rc(rc) - end - end - - check_rc(SQLExecute(@handle)) - - if @numParms != 0 - check_rc(SQLFreeStmt(@handle, SQL_RESET_PARAMS)) # Reset parameters - end - - self - end - - #------------------------------------------------------------------------------- - # The last argument(value) to SQLBindParameter is a deferred argument, that is, - # it should be available when SQLExecute is called. Even though "value" is - # local to bindParms method, it seems that it is available when SQLExecute - # is called. I am not sure whether it would still work if garbage collection - # is done between bindParms call and SQLExecute call inside the execute method - # above. - #------------------------------------------------------------------------------- - def bindParms(parms) # This is the real thing. It uses SQLBindParms - 1.upto(@numParms) do |i| # parameter number starts from 1 - rc, dataType, parmSize, decimalDigits = SQLDescribeParam(@handle, i) - check_rc(rc) - if parms[i - 1].class == String - value = parms[i - 1] - else - value = parms[i - 1].to_s - end - rc = SQLBindParameter(@handle, i, dataType, parmSize, decimalDigits, value) - check_rc(rc) - end - end - - #------------------------------------------------------------------------------ - # bind method does not use DB2's SQLBindParams, but replaces "?" in the - # SQL statement with the value before passing the SQL statement to DB2. - # It is not efficient and can handle only strings since it puts everything in - # quotes. - #------------------------------------------------------------------------------ - def bind(sql, args) #does not use SQLBindParams - arg_index = 0 - result = "" - tokens(sql).each do |part| - case part - when '?' - result << "'" + (args[arg_index]) + "'" #put it into quotes - arg_index += 1 - when '??' - result << "?" - else - result << part - end - end - if arg_index < args.size - raise "Too many SQL parameters" - elsif arg_index > args.size - raise "Not enough SQL parameters" - end - result - end - - ## Break the sql string into parts. - # - # This is NOT a full lexer for SQL. It just breaks up the SQL - # string enough so that question marks, double question marks and - # quoted strings are separated. This is used when binding - # arguments to "?" in the SQL string. Note: comments are not - # handled. - # - def tokens(sql) - toks = sql.scan(/('([^'\\]|''|\\.)*'|"([^"\\]|""|\\.)*"|\?\??|[^'"?]+)/) - toks.collect { |t| t[0] } - end - - def exec_direct(sql) - check_rc(SQLExecDirect(@handle, sql)) - self - end - - def set_cursor_name(name) - check_rc(SQLSetCursorName(@handle, name)) - self - end - - def get_cursor_name - rc, name = SQLGetCursorName(@handle) - check_rc(rc) - name - end - - def row_count - rc, rowcount = SQLRowCount(@handle) - check_rc(rc) - rowcount - end - - def num_result_cols - rc, cols = SQLNumResultCols(@handle) - check_rc(rc) - cols - end - - def fetch_all - if block_given? - while row = fetch do - yield row - end - else - res = [] - while row = fetch do - res << row - end - res - end - end - - def fetch - cols = get_col_desc - rc = SQLFetch(@handle) - if rc == SQL_NO_DATA_FOUND - SQLFreeStmt(@handle, SQL_CLOSE) # Close cursor - SQLFreeStmt(@handle, SQL_RESET_PARAMS) # Reset parameters - return nil - end - raise "ERROR" unless rc == SQL_SUCCESS - - retval = [] - cols.each_with_index do |c, i| - rc, content = SQLGetData(@handle, i + 1, c[1], c[2] + 1) #yun added 1 to c[2] - retval << adjust_content(content) - end - retval - end - - def fetch_as_hash - cols = get_col_desc - rc = SQLFetch(@handle) - if rc == SQL_NO_DATA_FOUND - SQLFreeStmt(@handle, SQL_CLOSE) # Close cursor - SQLFreeStmt(@handle, SQL_RESET_PARAMS) # Reset parameters - return nil - end - raise "ERROR" unless rc == SQL_SUCCESS - - retval = {} - cols.each_with_index do |c, i| - rc, content = SQLGetData(@handle, i + 1, c[1], c[2] + 1) #yun added 1 to c[2] - retval[c[0]] = adjust_content(content) - end - retval - end - - def get_col_desc - rc, nr_cols = SQLNumResultCols(@handle) - cols = (1..nr_cols).collect do |c| - rc, name, bl, type, col_sz = SQLDescribeCol(@handle, c, 1024) - [name.downcase, type, col_sz] - end - end - - def adjust_content(c) - case c.class.to_s - when 'DB2CLI::NullClass' - return nil - when 'DB2CLI::Time' - "%02d:%02d:%02d" % [c.hour, c.minute, c.second] - when 'DB2CLI::Date' - "%04d-%02d-%02d" % [c.year, c.month, c.day] - when 'DB2CLI::Timestamp' - "%04d-%02d-%02d %02d:%02d:%02d" % [c.year, c.month, c.day, c.hour, c.minute, c.second] - else - return c - end - end - end - - class Parameter - attr_reader :type, :size, :decimalDigits - def initialize(type, size, decimalDigits) - @type, @size, @decimalDigits = type, size, decimalDigits - end - end -end From ff5f155f8dc1d2ba363718c3e17f99719399eab5 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 8 Jun 2008 20:05:39 -0700 Subject: [PATCH 37/75] Use output_buffer reader and writer methods exclusively instead of hitting the instance variable so others can override the methods. --- .../lib/action_view/helpers/capture_helper.rb | 6 +- .../action_view/helpers/javascript_helper.rb | 5 - .../lib/action_view/helpers/tag_helper.rb | 4 - .../lib/action_view/helpers/text_helper.rb | 4 +- .../template_handlers/compilable.rb | 2 +- actionpack/lib/action_view/test_case.rb | 5 + actionpack/test/template/date_helper_test.rb | 12 +- actionpack/test/template/form_helper_test.rb | 251 +++++++----------- .../test/template/form_options_helper_test.rb | 24 +- .../test/template/form_tag_helper_test.rb | 29 +- .../test/template/javascript_helper_test.rb | 14 +- .../test/template/prototype_helper_test.rb | 20 +- .../test/template/record_tag_helper_test.rb | 9 +- actionpack/test/template/tag_helper_test.rb | 10 +- actionpack/test/template/text_helper_test.rb | 6 +- 15 files changed, 159 insertions(+), 242 deletions(-) diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index 25e62f78fb..ab453fadf2 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -31,7 +31,7 @@ module ActionView # # def capture(*args, &block) - if @output_buffer + if output_buffer with_output_buffer { block.call(*args) } else block.call(*args) @@ -121,10 +121,10 @@ module ActionView private def with_output_buffer(buf = '') - @output_buffer, old_buffer = buf, @output_buffer + self.output_buffer, old_buffer = buf, output_buffer yield ensure - @output_buffer = old_buffer + self.output_buffer = old_buffer end end end diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb index 85b205c264..7404a251e4 100644 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ b/actionpack/lib/action_view/helpers/javascript_helper.rb @@ -202,11 +202,6 @@ module ActionView end js_option end - - private - def block_is_within_action_view?(block) - !@output_buffer.nil? - end end JavascriptHelper = JavaScriptHelper unless const_defined? :JavascriptHelper diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb index a8a5987b1f..e1abec1847 100644 --- a/actionpack/lib/action_view/helpers/tag_helper.rb +++ b/actionpack/lib/action_view/helpers/tag_helper.rb @@ -122,10 +122,6 @@ module ActionView " #{attrs.sort * ' '}" unless attrs.empty? end end - - def block_is_within_action_view?(block) - !@output_buffer.nil? - end end end end diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index f81f7eded6..85a3672678 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -26,8 +26,8 @@ module ActionView # # will either display "Logged in!" or a login link # %> def concat(string) - if @output_buffer && string - @output_buffer << string + if output_buffer && string + output_buffer << string else string end diff --git a/actionpack/lib/action_view/template_handlers/compilable.rb b/actionpack/lib/action_view/template_handlers/compilable.rb index 28c72172a0..1aef81ba1a 100644 --- a/actionpack/lib/action_view/template_handlers/compilable.rb +++ b/actionpack/lib/action_view/template_handlers/compilable.rb @@ -106,7 +106,7 @@ module ActionView locals_code << "#{key} = local_assigns[:#{key}]\n" end - "def #{render_symbol}(local_assigns)\nold_output_buffer = @output_buffer;#{locals_code}#{body}\nensure\n@output_buffer = old_output_buffer\nend" + "def #{render_symbol}(local_assigns)\nold_output_buffer = output_buffer;#{locals_code}#{body}\nensure\nself.output_buffer = old_output_buffer\nend" end # Return true if the given template was compiled for a superset of the keys in local_assigns diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index 16fedd9732..1a3c93c283 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -37,6 +37,8 @@ module ActionView if helper_class && !self.class.ancestors.include?(helper_class) self.class.send(:include, helper_class) end + + self.output_buffer = '' end class TestController < ActionController::Base @@ -48,6 +50,9 @@ module ActionView end end + protected + attr_accessor :output_buffer + private def method_missing(selector, *args) controller = TestController.new diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb index 3399b03dd2..11b3bdb3fa 100755 --- a/actionpack/test/template/date_helper_test.rb +++ b/actionpack/test/template/date_helper_test.rb @@ -1002,17 +1002,15 @@ class DateHelperTest < ActionView::TestCase @post = Post.new @post.written_on = Date.new(2004, 6, 15) - @output_buffer = '' - fields_for :post, @post do |f| - @output_buffer.concat f.date_select(:written_on) + concat f.date_select(:written_on) end expected = "\n" expected << "\n" expected << "\n" - assert_dom_equal(expected, @output_buffer) + assert_dom_equal(expected, output_buffer) end def test_date_select_with_index @@ -1287,10 +1285,8 @@ class DateHelperTest < ActionView::TestCase @post = Post.new @post.updated_at = Time.local(2004, 6, 15, 16, 35) - @output_buffer = '' - fields_for :post, @post do |f| - @output_buffer.concat f.datetime_select(:updated_at) + concat f.datetime_select(:updated_at) end expected = "\n" @@ -1299,7 +1295,7 @@ class DateHelperTest < ActionView::TestCase expected << " — \n" expected << " : \n" - assert_dom_equal(expected, @output_buffer) + assert_dom_equal(expected, output_buffer) end def test_date_select_with_zero_value_and_no_start_year diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 65984fac44..39649c3622 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -337,14 +337,12 @@ class FormHelperTest < ActionView::TestCase end def test_form_for - @output_buffer = '' - form_for(:post, @post, :html => { :id => 'create-post' }) do |f| - @output_buffer.concat f.label(:title) - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) - @output_buffer.concat f.submit('Create post') + concat f.label(:title) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + concat f.submit('Create post') end expected = @@ -357,16 +355,14 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_with_method - @output_buffer = '' - form_for(:post, @post, :html => { :id => 'create-post', :method => :put }) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -378,16 +374,14 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_without_object - @output_buffer = '' - form_for(:post, :html => { :id => 'create-post' }) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -398,17 +392,15 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_with_index - @output_buffer = '' - form_for("post[]", @post) do |f| - @output_buffer.concat f.label(:title) - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.label(:title) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -420,16 +412,14 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_with_nil_index_option_override - @output_buffer = '' - form_for("post[]", @post, :index => nil) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -440,14 +430,13 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_nested_fields_for - @output_buffer = '' form_for(:post, @post) do |f| f.fields_for(:comment, @post) do |c| - @output_buffer.concat c.text_field(:title) + concat c.text_field(:title) end end @@ -455,16 +444,14 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_fields_for - @output_buffer = '' - fields_for(:post, @post) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -473,16 +460,14 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_fields_for_with_index - @output_buffer = '' - fields_for("post[]", @post) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -491,16 +476,14 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_fields_for_with_nil_index_option_override - @output_buffer = '' - fields_for("post[]", @post, :index => nil) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -509,16 +492,14 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_fields_for_with_index_option_override - @output_buffer = '' - fields_for("post[]", @post, :index => "abc") do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -527,15 +508,14 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_fields_for_without_object - @output_buffer = '' fields_for(:post) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -544,15 +524,14 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_fields_for_with_only_object - @output_buffer = '' fields_for(@post) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -561,31 +540,29 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_fields_for_object_with_bracketed_name - @output_buffer = '' fields_for("author[post]", @post) do |f| - @output_buffer.concat f.label(:title) - @output_buffer.concat f.text_field(:title) + concat f.label(:title) + concat f.text_field(:title) end assert_dom_equal "" + "", - @output_buffer + output_buffer end def test_fields_for_object_with_bracketed_name_and_index - @output_buffer = '' fields_for("author[post]", @post, :index => 1) do |f| - @output_buffer.concat f.label(:title) - @output_buffer.concat f.text_field(:title) + concat f.label(:title) + concat f.text_field(:title) end assert_dom_equal "" + "", - @output_buffer + output_buffer end def test_form_builder_does_not_have_form_for_method @@ -593,14 +570,12 @@ class FormHelperTest < ActionView::TestCase end def test_form_for_and_fields_for - @output_buffer = '' - form_for(:post, @post, :html => { :id => 'create-post' }) do |post_form| - @output_buffer.concat post_form.text_field(:title) - @output_buffer.concat post_form.text_area(:body) + concat post_form.text_field(:title) + concat post_form.text_area(:body) fields_for(:parent_post, @post) do |parent_fields| - @output_buffer.concat parent_fields.check_box(:secret) + concat parent_fields.check_box(:secret) end end @@ -612,18 +587,16 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_and_fields_for_with_object - @output_buffer = '' - form_for(:post, @post, :html => { :id => 'create-post' }) do |post_form| - @output_buffer.concat post_form.text_field(:title) - @output_buffer.concat post_form.text_area(:body) + concat post_form.text_field(:title) + concat post_form.text_area(:body) post_form.fields_for(@comment) do |comment_fields| - @output_buffer.concat comment_fields.text_field(:name) + concat comment_fields.text_field(:name) end end @@ -634,7 +607,7 @@ class FormHelperTest < ActionView::TestCase "" + "" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end class LabelledFormBuilder < ActionView::Helpers::FormBuilder @@ -649,12 +622,10 @@ class FormHelperTest < ActionView::TestCase end def test_form_for_with_labelled_builder - @output_buffer = '' - form_for(:post, @post, :builder => LabelledFormBuilder) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -665,18 +636,17 @@ class FormHelperTest < ActionView::TestCase "
      " + "" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_default_form_builder old_default_form_builder, ActionView::Base.default_form_builder = ActionView::Base.default_form_builder, LabelledFormBuilder - @output_buffer = '' form_for(:post, @post) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -687,17 +657,15 @@ class FormHelperTest < ActionView::TestCase "
      " + "" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer ensure ActionView::Base.default_form_builder = old_default_form_builder end def test_default_form_builder_with_active_record_helpers - - @output_buffer = '' form_for(:post, @post) do |f| - @output_buffer.concat f.error_message_on('author_name') - @output_buffer.concat f.error_messages + concat f.error_message_on('author_name') + concat f.error_messages end expected = %(
      ) + @@ -705,7 +673,7 @@ class FormHelperTest < ActionView::TestCase %(

      1 error prohibited this post from being saved

      There were problems with the following fields:

      • Author name can't be empty
      ) + %(
      ) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end @@ -713,10 +681,9 @@ class FormHelperTest < ActionView::TestCase post = @post @post = nil - @output_buffer = '' form_for(:post, post) do |f| - @output_buffer.concat f.error_message_on('author_name') - @output_buffer.concat f.error_messages + concat f.error_message_on('author_name') + concat f.error_messages end expected = %(
      ) + @@ -724,19 +691,18 @@ class FormHelperTest < ActionView::TestCase %(

      1 error prohibited this post from being saved

      There were problems with the following fields:

      • Author name can't be empty
      ) + %(
      ) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end # Perhaps this test should be moved to prototype helper tests. def test_remote_form_for_with_labelled_builder self.extend ActionView::Helpers::PrototypeHelper - @output_buffer = '' remote_form_for(:post, @post, :builder => LabelledFormBuilder) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -747,16 +713,14 @@ class FormHelperTest < ActionView::TestCase "
      " + "" - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_fields_for_with_labelled_builder - @output_buffer = '' - fields_for(:post, @post, :builder => LabelledFormBuilder) do |f| - @output_buffer.concat f.text_field(:title) - @output_buffer.concat f.text_area(:body) - @output_buffer.concat f.check_box(:secret) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) end expected = @@ -765,29 +729,23 @@ class FormHelperTest < ActionView::TestCase " " + "
      " - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_with_html_options_adds_options_to_form_tag - @output_buffer = '' - form_for(:post, @post, :html => {:id => 'some_form', :class => 'some_class'}) do |f| end expected = "
      " - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_with_string_url_option - @output_buffer = '' - form_for(:post, @post, :url => 'http://www.otherdomain.com') do |f| end - assert_equal '
      ', @output_buffer + assert_equal '
      ', output_buffer end def test_form_for_with_hash_url_option - @output_buffer = '' - form_for(:post, @post, :url => {:controller => 'controller', :action => 'action'}) do |f| end assert_equal 'controller', @controller.url_for_options[:controller] @@ -795,26 +753,20 @@ class FormHelperTest < ActionView::TestCase end def test_form_for_with_record_url_option - @output_buffer = '' - form_for(:post, @post, :url => @post) do |f| end expected = "
      " - assert_equal expected, @output_buffer + assert_equal expected, output_buffer end def test_form_for_with_existing_object - @output_buffer = '' - form_for(@post) do |f| end expected = "
      " - assert_equal expected, @output_buffer + assert_equal expected, output_buffer end def test_form_for_with_new_object - @output_buffer = '' - post = Post.new post.new_record = true def post.id() nil end @@ -822,64 +774,61 @@ class FormHelperTest < ActionView::TestCase form_for(post) do |f| end expected = "
      " - assert_equal expected, @output_buffer + assert_equal expected, output_buffer end def test_form_for_with_existing_object_in_list @post.new_record = false @comment.save - @output_buffer = '' + form_for([@post, @comment]) {} expected = %(
      ) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_with_new_object_in_list @post.new_record = false - @output_buffer = '' + form_for([@post, @comment]) {} expected = %(
      ) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_with_existing_object_and_namespace_in_list @post.new_record = false @comment.save - @output_buffer = '' + form_for([:admin, @post, @comment]) {} expected = %(
      ) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_with_new_object_and_namespace_in_list @post.new_record = false - @output_buffer = '' + form_for([:admin, @post, @comment]) {} expected = %(
      ) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_for_with_existing_object_and_custom_url - @output_buffer = '' - form_for(@post, :url => "/super_posts") do |f| end expected = "
      " - assert_equal expected, @output_buffer + assert_equal expected, output_buffer end def test_remote_form_for_with_html_options_adds_options_to_form_tag self.extend ActionView::Helpers::PrototypeHelper - @output_buffer = '' remote_form_for(:post, @post, :html => {:id => 'some_form', :class => 'some_class'}) do |f| end expected = "
      " - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb index 3c9fb297c3..4fb2be9d3f 100644 --- a/actionpack/test/template/form_options_helper_test.rb +++ b/actionpack/test/template/form_options_helper_test.rb @@ -230,16 +230,14 @@ class FormOptionsHelperTest < ActionView::TestCase def test_select_under_fields_for @post = Post.new @post.category = "" - - @output_buffer = '' - + fields_for :post, @post do |f| - @output_buffer.concat f.select(:category, %w( abe hest)) + concat f.select(:category, %w( abe hest)) end assert_dom_equal( "", - @output_buffer + output_buffer ) end @@ -352,16 +350,14 @@ class FormOptionsHelperTest < ActionView::TestCase @post = Post.new @post.author_name = "Babe" - - @output_buffer = '' - + fields_for :post, @post do |f| - @output_buffer.concat f.collection_select(:author_name, @posts, :author_name, :author_name) + concat f.collection_select(:author_name, @posts, :author_name, :author_name) end assert_dom_equal( "", - @output_buffer + output_buffer ) end @@ -1194,11 +1190,9 @@ COUNTRIES def test_time_zone_select_under_fields_for @firm = Firm.new("D") - - @output_buffer = '' - + fields_for :firm, @firm do |f| - @output_buffer.concat f.time_zone_select(:time_zone) + concat f.time_zone_select(:time_zone) end assert_dom_equal( @@ -1209,7 +1203,7 @@ COUNTRIES "\n" + "" + "", - @output_buffer + output_buffer ) end diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index b281db18bd..47b3605849 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -43,19 +43,17 @@ class FormTagHelperTest < ActionView::TestCase end def test_form_tag_with_block - @output_buffer = '' - form_tag("http://example.com") { @output_buffer.concat "Hello world!" } + form_tag("http://example.com") { concat "Hello world!" } expected = %(
      Hello world!
      ) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_form_tag_with_block_and_method - @output_buffer = '' - form_tag("http://example.com", :method => :put) { @output_buffer.concat "Hello world!" } + form_tag("http://example.com", :method => :put) { concat "Hello world!" } expected = %(
      Hello world!
      ) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_hidden_field_tag @@ -234,23 +232,22 @@ class FormTagHelperTest < ActionView::TestCase end def test_field_set_tag - @output_buffer = '' - field_set_tag("Your details") { @output_buffer.concat "Hello world!" } + field_set_tag("Your details") { concat "Hello world!" } expected = %(
      Your detailsHello world!
      ) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer - @output_buffer = '' - field_set_tag { @output_buffer.concat "Hello world!" } + self.output_buffer = '' + field_set_tag { concat "Hello world!" } expected = %(
      Hello world!
      ) - assert_dom_equal expected, @output_buffer - - @output_buffer = '' - field_set_tag('') { @output_buffer.concat "Hello world!" } + assert_dom_equal expected, output_buffer + + self.output_buffer = '' + field_set_tag('') { concat "Hello world!" } expected = %(
      Hello world!
      ) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def protect_against_forgery? diff --git a/actionpack/test/template/javascript_helper_test.rb b/actionpack/test/template/javascript_helper_test.rb index 4924074c3e..8c649ea544 100644 --- a/actionpack/test/template/javascript_helper_test.rb +++ b/actionpack/test/template/javascript_helper_test.rb @@ -82,12 +82,12 @@ class JavaScriptHelperTest < ActionView::TestCase end def test_javascript_tag - @output_buffer = 'foo' + self.output_buffer = 'foo' assert_dom_equal "", javascript_tag("alert('hello')") - assert_equal 'foo', @output_buffer, 'javascript_tag without a block should not concat to @output_buffer' + assert_equal 'foo', output_buffer, 'javascript_tag without a block should not concat to output_buffer' end def test_javascript_tag_with_options @@ -96,15 +96,13 @@ class JavaScriptHelperTest < ActionView::TestCase end def test_javascript_tag_with_block - @output_buffer = '' - javascript_tag { @output_buffer.concat "alert('hello')" } - assert_dom_equal "", @output_buffer + javascript_tag { concat "alert('hello')" } + assert_dom_equal "", output_buffer end def test_javascript_tag_with_block_and_options - @output_buffer = '' - javascript_tag(:id => "the_js_tag") { @output_buffer.concat "alert('hello')" } - assert_dom_equal "", @output_buffer + javascript_tag(:id => "the_js_tag") { concat "alert('hello')" } + assert_dom_equal "", output_buffer end def test_javascript_cdata_section diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb index 3f5ec07214..a5be0d2789 100644 --- a/actionpack/test/template/prototype_helper_test.rb +++ b/actionpack/test/template/prototype_helper_test.rb @@ -118,52 +118,46 @@ class PrototypeHelperTest < PrototypeHelperBaseTest end def test_form_remote_tag_with_block - @output_buffer = '' - form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) { @output_buffer.concat "Hello world!" } - assert_dom_equal %(
      Hello world!
      ), @output_buffer + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) { concat "Hello world!" } + assert_dom_equal %(
      Hello world!
      ), output_buffer end def test_remote_form_for_with_record_identification_with_new_record - @output_buffer = '' remote_form_for(@record, {:html => { :id => 'create-author' }}) {} expected = %(
      ) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_remote_form_for_with_record_identification_without_html_options - @output_buffer = '' remote_form_for(@record) {} expected = %(
      ) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_remote_form_for_with_record_identification_with_existing_record @record.save - @output_buffer = '' remote_form_for(@record) {} expected = %(
      ) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_remote_form_for_with_new_object_in_list - @output_buffer = '' remote_form_for([@author, @article]) {} expected = %(
      ) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_remote_form_for_with_existing_object_in_list @author.save @article.save - @output_buffer = '' remote_form_for([@author, @article]) {} expected = %(
      ) - assert_dom_equal expected, @output_buffer + assert_dom_equal expected, output_buffer end def test_on_callbacks diff --git a/actionpack/test/template/record_tag_helper_test.rb b/actionpack/test/template/record_tag_helper_test.rb index c39e5c69bf..441dc6b720 100644 --- a/actionpack/test/template/record_tag_helper_test.rb +++ b/actionpack/test/template/record_tag_helper_test.rb @@ -17,37 +17,32 @@ class RecordTagHelperTest < ActionView::TestCase end def test_content_tag_for - @output_buffer = '' expected = %(
    • ) actual = content_tag_for(:li, @post, :class => 'bar') { } assert_dom_equal expected, actual end def test_content_tag_for_prefix - @output_buffer = '' expected = %(
        ) actual = content_tag_for(:ul, @post, :archived) { } assert_dom_equal expected, actual end def test_content_tag_for_with_extra_html_tags - @output_buffer = '' expected = %() actual = content_tag_for(:tr, @post, {:class => "bar", :style => "background-color: #f0f0f0"}) { } assert_dom_equal expected, actual end def test_block_works_with_content_tag_for - @output_buffer = '' expected = %(#{@post.body}) - actual = content_tag_for(:tr, @post) { @output_buffer.concat @post.body } + actual = content_tag_for(:tr, @post) { concat @post.body } assert_dom_equal expected, actual end def test_div_for - @output_buffer = '' expected = %(
        #{@post.body}
        ) - actual = div_for(@post, :class => "bar") { @output_buffer.concat @post.body } + actual = div_for(@post, :class => "bar") { concat @post.body } assert_dom_equal expected, actual end diff --git a/actionpack/test/template/tag_helper_test.rb b/actionpack/test/template/tag_helper_test.rb index 7db04d178f..bfdaf0d639 100644 --- a/actionpack/test/template/tag_helper_test.rb +++ b/actionpack/test/template/tag_helper_test.rb @@ -35,15 +35,13 @@ class TagHelperTest < ActionView::TestCase end def test_content_tag_with_block - @output_buffer = '' - content_tag(:div) { @output_buffer.concat "Hello world!" } - assert_dom_equal "
        Hello world!
        ", @output_buffer + content_tag(:div) { concat "Hello world!" } + assert_dom_equal "
        Hello world!
        ", output_buffer end def test_content_tag_with_block_and_options - @output_buffer = '' - content_tag(:div, :class => "green") { @output_buffer.concat "Hello world!" } - assert_dom_equal %(
        Hello world!
        ), @output_buffer + content_tag(:div, :class => "green") { concat "Hello world!" } + assert_dom_equal %(
        Hello world!
        ), output_buffer end def test_content_tag_with_block_and_options_outside_of_action_view diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb index 0f5c62acad..cbb5c7ee74 100644 --- a/actionpack/test/template/text_helper_test.rb +++ b/actionpack/test/template/text_helper_test.rb @@ -12,11 +12,11 @@ class TextHelperTest < ActionView::TestCase end def test_concat - @output_buffer = 'foo' + self.output_buffer = 'foo' concat 'bar' - assert_equal 'foobar', @output_buffer + assert_equal 'foobar', output_buffer assert_nothing_raised { concat nil } - assert_equal 'foobar', @output_buffer + assert_equal 'foobar', output_buffer end def test_simple_format From 0c9281e82140f3a69e4473b3bcefd5ccebd79e2d Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 8 Jun 2008 22:11:08 -0500 Subject: [PATCH 38/75] Drop ActionController::Base.allow_concurrency flag --- actionpack/CHANGELOG | 2 ++ actionpack/lib/action_controller/base.rb | 7 ------- railties/lib/webrick_server.rb | 13 ++----------- 3 files changed, 4 insertions(+), 18 deletions(-) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 8265b5b04f..3096716dba 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *Edge* +* Drop ActionController::Base.allow_concurrency flag [Josh Peek] + * More efficient concat and capture helpers. Remove ActionView::Base.erb_variable. [Jeremy Kemper] * Added page.reload functionality. Resolves #277. [Sean Huber] diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index a036600c2b..44269fc735 100755 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -283,13 +283,6 @@ module ActionController #:nodoc: @@debug_routes = true cattr_accessor :debug_routes - # Indicates to Mongrel or Webrick whether to allow concurrent action - # processing. Your controller actions and any other code they call must - # also behave well when called from concurrent threads. Turned off by - # default. - @@allow_concurrency = false - cattr_accessor :allow_concurrency - # Modern REST web services often need to submit complex data to the web application. # The @@param_parsers hash lets you register handlers which will process the HTTP body and add parameters to the # params hash. These handlers are invoked for POST and PUT requests. diff --git a/railties/lib/webrick_server.rb b/railties/lib/webrick_server.rb index ad4ca926ba..2f60151b22 100644 --- a/railties/lib/webrick_server.rb +++ b/railties/lib/webrick_server.rb @@ -43,8 +43,6 @@ end # can change this behavior by setting ActionController::Base.allow_concurrency # to true. class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet - REQUEST_MUTEX = Mutex.new - # Start the WEBrick server with the given options, mounting the # DispatchServlet at /. def self.dispatch(options = {}) @@ -73,15 +71,8 @@ class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet def service(req, res) #:nodoc: unless handle_file(req, res) - begin - REQUEST_MUTEX.lock unless ActionController::Base.allow_concurrency - unless handle_dispatch(req, res) - raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found." - end - ensure - unless ActionController::Base.allow_concurrency - REQUEST_MUTEX.unlock if REQUEST_MUTEX.locked? - end + unless handle_dispatch(req, res) + raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found." end end end From df44df945d6315238e7d94d9bdef82e435dc9b24 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 8 Jun 2008 22:31:54 -0500 Subject: [PATCH 39/75] Ensure ActionView::TemplateFinder view cache is rebuilt on initialize. --- actionpack/CHANGELOG | 2 ++ actionpack/lib/action_controller/dispatcher.rb | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 3096716dba..f9cb715400 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *Edge* +* Ensure ActionView::TemplateFinder view cache is rebuilt on initialize [Josh Peek] + * Drop ActionController::Base.allow_concurrency flag [Josh Peek] * More efficient concat and capture helpers. Remove ActionView::Base.erb_variable. [Jeremy Kemper] diff --git a/actionpack/lib/action_controller/dispatcher.rb b/actionpack/lib/action_controller/dispatcher.rb index fe4f6b4a7e..64553fb25d 100644 --- a/actionpack/lib/action_controller/dispatcher.rb +++ b/actionpack/lib/action_controller/dispatcher.rb @@ -10,6 +10,10 @@ module ActionController # Development mode callbacks before_dispatch :reload_application after_dispatch :cleanup_application + + to_prepare :reload_view_path_cache do + ActionView::TemplateFinder.reload! unless ActionView::Base.cache_template_loading + end end # Common callbacks @@ -134,7 +138,6 @@ module ActionController run_callbacks :prepare_dispatch Routing::Routes.reload - ActionView::TemplateFinder.reload! unless ActionView::Base.cache_template_loading end # Cleanup the application by clearing out loaded classes so they can From c88f2b5e23b0cb6c1a3b3687958f45d518414041 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 8 Jun 2008 20:35:14 -0700 Subject: [PATCH 40/75] with_output_buffer returns the temporary buffer instead of the result of the block --- actionpack/lib/action_view/helpers/capture_helper.rb | 1 + actionpack/test/template/tag_helper_test.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index ab453fadf2..9cd9d3d06a 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -123,6 +123,7 @@ module ActionView def with_output_buffer(buf = '') self.output_buffer, old_buffer = buf, output_buffer yield + output_buffer ensure self.output_buffer = old_buffer end diff --git a/actionpack/test/template/tag_helper_test.rb b/actionpack/test/template/tag_helper_test.rb index bfdaf0d639..2941dfe217 100644 --- a/actionpack/test/template/tag_helper_test.rb +++ b/actionpack/test/template/tag_helper_test.rb @@ -45,6 +45,7 @@ class TagHelperTest < ActionView::TestCase end def test_content_tag_with_block_and_options_outside_of_action_view + self.output_buffer = nil assert_equal content_tag("a", "Create", :href => "create"), content_tag("a", "href" => "create") { "Create" } end From 057768cd2c8541f9c466131cb6c77f13ce12204d Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 8 Jun 2008 21:21:54 -0700 Subject: [PATCH 41/75] Process view paths passed to AV::Base#initialize instead of raising. --- actionpack/lib/action_view/template_finder.rb | 11 +---------- actionpack/test/template/template_finder_test.rb | 6 ------ 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/actionpack/lib/action_view/template_finder.rb b/actionpack/lib/action_view/template_finder.rb index 83b7e27c09..fc2a07b30c 100644 --- a/actionpack/lib/action_view/template_finder.rb +++ b/actionpack/lib/action_view/template_finder.rb @@ -1,14 +1,5 @@ module ActionView #:nodoc: class TemplateFinder #:nodoc: - - class InvalidViewPath < StandardError #:nodoc: - attr_reader :unprocessed_path - def initialize(path) - @unprocessed_path = path - super("Unprocessed view path found: #{@unprocessed_path.inspect}. Set your view paths with #append_view_path, #prepend_view_path, or #view_paths=.") - end - end - cattr_reader :processed_view_paths @@processed_view_paths = Hash.new {|hash, key| hash[key] = []} @@ -76,7 +67,7 @@ module ActionView #:nodoc: @view_paths = args.flatten @view_paths = @view_paths.respond_to?(:find) ? @view_paths.dup : [*@view_paths].compact - check_view_paths(@view_paths) + self.class.process_view_paths(@view_paths) end def prepend_view_path(path) diff --git a/actionpack/test/template/template_finder_test.rb b/actionpack/test/template/template_finder_test.rb index 3d6baff5fb..d6aac87b13 100644 --- a/actionpack/test/template/template_finder_test.rb +++ b/actionpack/test/template/template_finder_test.rb @@ -11,12 +11,6 @@ class TemplateFinderTest < Test::Unit::TestCase @finder = ActionView::TemplateFinder.new(@template, LOAD_PATH_ROOT) end - def test_should_raise_exception_for_unprocessed_view_path - assert_raises ActionView::TemplateFinder::InvalidViewPath do - ActionView::TemplateFinder.new(@template, File.dirname(__FILE__)) - end - end - def test_should_cache_file_extension_properly assert_equal ["builder", "erb", "rhtml", "rjs", "rxml", "mab"].sort, ActionView::TemplateFinder.file_extension_cache[LOAD_PATH_ROOT].values.flatten.uniq.sort From def594b92d1e68db68a27d53dec7ae4e6246f5a5 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 8 Jun 2008 22:08:59 -0700 Subject: [PATCH 42/75] Don't append limit to primary key column definition. Freeze some constants. --- .../abstract/schema_statements.rb | 4 +-- .../connection_adapters/mysql_adapter.rb | 34 +++++++++++-------- .../connection_adapters/postgresql_adapter.rb | 34 +++++++++++-------- activerecord/lib/active_record/fixtures.rb | 2 +- 4 files changed, 41 insertions(+), 33 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 55f67995d1..7d8530ebef 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -356,7 +356,7 @@ module ActiveRecord def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc: if native = native_database_types[type] - column_type_sql = native.is_a?(Hash) ? native[:name] : native + column_type_sql = (native.is_a?(Hash) ? native[:name] : native).dup if type == :decimal # ignore limit, use precision and scale scale ||= native[:scale] @@ -371,7 +371,7 @@ module ActiveRecord raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale if specified" end - elsif limit ||= native.is_a?(Hash) && native[:limit] + elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit]) column_type_sql << "(#{limit})" end diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index b052c0328e..cfd2402d9d 100755 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -147,6 +147,8 @@ module ActiveRecord @@emulate_booleans = true cattr_accessor :emulate_booleans + ADAPTER_NAME = 'MySQL'.freeze + LOST_CONNECTION_ERROR_MESSAGES = [ "Server shutdown in progress", "Broken pipe", @@ -155,6 +157,21 @@ module ActiveRecord QUOTED_TRUE, QUOTED_FALSE = '1', '0' + NATIVE_DATABASE_TYPES = { + :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY".freeze, + :string => { :name => "varchar", :limit => 255 }, + :text => { :name => "text" }, + :integer => { :name => "int"}, + :float => { :name => "float" }, + :decimal => { :name => "decimal" }, + :datetime => { :name => "datetime" }, + :timestamp => { :name => "datetime" }, + :time => { :name => "time" }, + :date => { :name => "date" }, + :binary => { :name => "blob" }, + :boolean => { :name => "tinyint", :limit => 1 } + } + def initialize(connection, logger, connection_options, config) super(connection, logger) @connection_options, @config = connection_options, config @@ -163,7 +180,7 @@ module ActiveRecord end def adapter_name #:nodoc: - 'MySQL' + ADAPTER_NAME end def supports_migrations? #:nodoc: @@ -171,20 +188,7 @@ module ActiveRecord end def native_database_types #:nodoc: - { - :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY", - :string => { :name => "varchar", :limit => 255 }, - :text => { :name => "text" }, - :integer => { :name => "int"}, - :float => { :name => "float" }, - :decimal => { :name => "decimal" }, - :datetime => { :name => "datetime" }, - :timestamp => { :name => "datetime" }, - :time => { :name => "time" }, - :date => { :name => "date" }, - :binary => { :name => "blob" }, - :boolean => { :name => "tinyint", :limit => 1 } - } + NATIVE_DATABASE_TYPES end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 049e6f61de..ae070421f1 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -238,9 +238,26 @@ module ActiveRecord # * :min_messages - An optional client min messages that is used in a SET client_min_messages TO call on the connection. # * :allow_concurrency - If true, use async query methods so Ruby threads don't deadlock; otherwise, use blocking query methods. class PostgreSQLAdapter < AbstractAdapter + ADAPTER_NAME = 'PostgreSQL'.freeze + + NATIVE_DATABASE_TYPES = { + :primary_key => "serial primary key".freeze, + :string => { :name => "character varying", :limit => 255 }, + :text => { :name => "text" }, + :integer => { :name => "integer" }, + :float => { :name => "float" }, + :decimal => { :name => "decimal" }, + :datetime => { :name => "timestamp" }, + :timestamp => { :name => "timestamp" }, + :time => { :name => "time" }, + :date => { :name => "date" }, + :binary => { :name => "bytea" }, + :boolean => { :name => "boolean" } + } + # Returns 'PostgreSQL' as adapter name for identification purposes. def adapter_name - 'PostgreSQL' + ADAPTER_NAME end # Initializes and connects a PostgreSQL adapter. @@ -282,20 +299,7 @@ module ActiveRecord end def native_database_types #:nodoc: - { - :primary_key => "serial primary key", - :string => { :name => "character varying", :limit => 255 }, - :text => { :name => "text" }, - :integer => { :name => "integer" }, - :float => { :name => "float" }, - :decimal => { :name => "decimal" }, - :datetime => { :name => "timestamp" }, - :timestamp => { :name => "timestamp" }, - :time => { :name => "time" }, - :date => { :name => "date" }, - :binary => { :name => "bytea" }, - :boolean => { :name => "boolean" } - } + NATIVE_DATABASE_TYPES end # Does PostgreSQL support migrations? diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index c4cbe5d52f..e19614e31f 100755 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -547,7 +547,7 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash) @connection, @table_name, @fixture_path, @file_filter = connection, table_name, fixture_path, file_filter @class_name = class_name || (ActiveRecord::Base.pluralize_table_names ? @table_name.singularize.camelize : @table_name.camelize) - @table_name = ActiveRecord::Base.table_name_prefix + @table_name + ActiveRecord::Base.table_name_suffix + @table_name = "#{ActiveRecord::Base.table_name_prefix}#{@table_name}#{ActiveRecord::Base.table_name_suffix}" @table_name = class_name.table_name if class_name.respond_to?(:table_name) @connection = class_name.connection if class_name.respond_to?(:connection) read_fixture_files From d20035910c186401c1d957462f4ad7894347c398 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 8 Jun 2008 22:34:09 -0700 Subject: [PATCH 43/75] Give a more informative error message instead of just raising a load error when mysql gem isn't installed --- .../active_record/connection_adapters/mysql_adapter.rb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index cfd2402d9d..076b7f63c2 100755 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -58,7 +58,14 @@ module ActiveRecord end # Require the MySQL driver and define Mysql::Result.all_hashes - require_library_or_gem('mysql') unless defined? Mysql + unless defined? Mysql + begin + require_library_or_gem('mysql') + rescue LoadError + $stderr.puts '!!! The bundled mysql.rb driver has been removed from Rails 2.2. Please install the mysql gem and try again: gem install mysql.' + raise + end + end MysqlCompat.define_all_hashes_method! mysql = Mysql.init From 9051da90e4da2ab0db16530a7f7568e24a0ccaed Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 8 Jun 2008 19:40:50 -0700 Subject: [PATCH 44/75] Enable autoreconnect if available. Freeze constants. --- .../active_record/connection_adapters/mysql_adapter.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 076b7f63c2..93aafaaad1 100755 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -151,8 +151,8 @@ module ActiveRecord # # ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans = false class MysqlAdapter < AbstractAdapter - @@emulate_booleans = true cattr_accessor :emulate_booleans + self.emulate_booleans = true ADAPTER_NAME = 'MySQL'.freeze @@ -162,7 +162,7 @@ module ActiveRecord "Lost connection to MySQL server during query", "MySQL server has gone away" ] - QUOTED_TRUE, QUOTED_FALSE = '1', '0' + QUOTED_TRUE, QUOTED_FALSE = '1'.freeze, '0'.freeze NATIVE_DATABASE_TYPES = { :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY".freeze, @@ -488,12 +488,17 @@ module ActiveRecord private def connect + @connection.reconnect = true if @connection.respond_to?(:reconnect=) + encoding = @config[:encoding] if encoding @connection.options(Mysql::SET_CHARSET_NAME, encoding) rescue nil end + @connection.ssl_set(@config[:sslkey], @config[:sslcert], @config[:sslca], @config[:sslcapath], @config[:sslcipher]) if @config[:sslkey] + @connection.real_connect(*@connection_options) + execute("SET NAMES '#{encoding}'") if encoding # By default, MySQL 'where id is null' selects the last inserted id. From 55791c6c0012d0daea2a75b6a5927f459be25c54 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 9 Jun 2008 10:05:02 -0500 Subject: [PATCH 45/75] Removed used check_view_paths after 057768c --- actionpack/lib/action_view/template_finder.rb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/actionpack/lib/action_view/template_finder.rb b/actionpack/lib/action_view/template_finder.rb index fc2a07b30c..cd5e290644 100644 --- a/actionpack/lib/action_view/template_finder.rb +++ b/actionpack/lib/action_view/template_finder.rb @@ -157,12 +157,5 @@ module ActionView #:nodoc: def find_template_extension_from_first_render File.basename(@template.first_render.to_s)[/^[^.]+\.(.+)$/, 1] end - - private - def check_view_paths(view_paths) - view_paths.each do |path| - raise InvalidViewPath.new(path) unless @@processed_view_paths.has_key?(path) - end - end end end From 233643047104131565467787d0bbc0841bbc77cb Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 9 Jun 2008 10:21:30 -0500 Subject: [PATCH 46/75] Removed TemplateFinder.update_extension_cache_for since view path cache will be updated on boot. --- actionpack/lib/action_view/template.rb | 1 - actionpack/lib/action_view/template_finder.rb | 16 +--------------- actionpack/test/template/template_finder_test.rb | 7 ------- 3 files changed, 1 insertion(+), 23 deletions(-) diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index 369526188f..a878ac66d9 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -99,7 +99,6 @@ module ActionView #:nodoc: # return the rendered template as a string. def self.register_template_handler(extension, klass) @@template_handlers[extension.to_sym] = klass - TemplateFinder.update_extension_cache_for(extension.to_s) end def self.template_handler_extensions diff --git a/actionpack/lib/action_view/template_finder.rb b/actionpack/lib/action_view/template_finder.rb index cd5e290644..7e9a310810 100644 --- a/actionpack/lib/action_view/template_finder.rb +++ b/actionpack/lib/action_view/template_finder.rb @@ -9,7 +9,6 @@ module ActionView #:nodoc: } class << self #:nodoc: - # This method is not thread safe. Mutex should be used whenever this is accessed from an instance method def process_view_paths(*view_paths) view_paths.flatten.compact.each do |dir| @@ -26,7 +25,7 @@ module ActionView #:nodoc: # Build extension cache extension = file.split(".").last - if template_handler_extensions.include?(extension) + if ActionView::Template.template_handler_extensions.include?(extension) key = file.split(dir).last.sub(/^\//, '').sub(/\.(\w+)$/, '') @@file_extension_cache[dir][key] << extension end @@ -35,19 +34,6 @@ module ActionView #:nodoc: end end - def update_extension_cache_for(extension) - @@processed_view_paths.keys.each do |dir| - Dir.glob("#{dir}/**/*.#{extension}").each do |file| - key = file.split(dir).last.sub(/^\//, '').sub(/\.(\w+)$/, '') - @@file_extension_cache[dir][key] << extension - end - end - end - - def template_handler_extensions - ActionView::Template.template_handler_extensions - end - def reload! view_paths = @@processed_view_paths.keys diff --git a/actionpack/test/template/template_finder_test.rb b/actionpack/test/template/template_finder_test.rb index d6aac87b13..07fc4b8c56 100644 --- a/actionpack/test/template/template_finder_test.rb +++ b/actionpack/test/template/template_finder_test.rb @@ -57,11 +57,4 @@ class TemplateFinderTest < Test::Unit::TestCase assert_equal false, @finder.send(:file_exists?, 'baz') assert_equal false, @finder.send(:file_exists?, 'baz.rb') end - - uses_mocha 'Template finder tests' do - def test_should_update_extension_cache_when_template_handler_is_registered - ActionView::TemplateFinder.expects(:update_extension_cache_for).with("funky") - ActionView::Template::register_template_handler :funky, Class.new(ActionView::TemplateHandler) - end - end end From f545e19692c84eeaa8de38319766b5ceed1768c1 Mon Sep 17 00:00:00 2001 From: rick Date: Mon, 9 Jun 2008 12:06:23 -0400 Subject: [PATCH 47/75] add deprecation for the #concat helper's 2nd argument, which is no longer needed --- actionpack/lib/action_view/helpers/text_helper.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 85a3672678..a1a91f6b3d 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -25,7 +25,11 @@ module ActionView # end # # will either display "Logged in!" or a login link # %> - def concat(string) + def concat(string, unused_binding = nil) + if unused_binding + ActiveSupport::Deprecation.warn("The binding argument of #concat is no longer needed. Please remove it from your views and helpers.") + end + if output_buffer && string output_buffer << string else From 16a9787bf034a4de36a35b647c456ef142f814e1 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 9 Jun 2008 23:04:51 -0700 Subject: [PATCH 48/75] Add empty setup and teardown methods to rule out default setup behavior in base class --- activesupport/test/test_test.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/activesupport/test/test_test.rb b/activesupport/test/test_test.rb index 1e75e18602..26a45af255 100644 --- a/activesupport/test/test_test.rb +++ b/activesupport/test/test_test.rb @@ -84,6 +84,12 @@ class SetupAndTeardownTest < Test::Unit::TestCase assert_equal [:foo, :sentinel, :foo], self.class.teardown_callback_chain.map(&:method) end + def setup + end + + def teardown + end + protected def reset_callback_record @called_back = [] From 225065709c43dacd57e0904aef2075024ccf2744 Mon Sep 17 00:00:00 2001 From: Luis Hurtado Date: Mon, 9 Jun 2008 21:39:39 -0500 Subject: [PATCH 49/75] Fixes parsing deep nested resources from XML. [#380 state:resolved] --- activeresource/lib/active_resource/base.rb | 6 ++- activeresource/test/base_test.rb | 48 ++++++++++++++++++++++ activeresource/test/fixtures/customer.rb | 3 ++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 activeresource/test/fixtures/customer.rb diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index 55dacfdf06..347dbb82aa 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -988,7 +988,11 @@ module ActiveResource self.class.const_get(resource_name) end rescue NameError - resource = self.class.const_set(resource_name, Class.new(ActiveResource::Base)) + if self.class.const_defined?(resource_name) + resource = self.class.const_get(resource_name) + else + resource = self.class.const_set(resource_name, Class.new(ActiveResource::Base)) + end resource.prefix = self.class.prefix resource.site = self.class.site resource diff --git a/activeresource/test/base_test.rb b/activeresource/test/base_test.rb index 9e2f6c1831..4addd52636 100644 --- a/activeresource/test/base_test.rb +++ b/activeresource/test/base_test.rb @@ -1,5 +1,6 @@ require 'abstract_unit' require "fixtures/person" +require "fixtures/customer" require "fixtures/street_address" require "fixtures/beast" @@ -15,6 +16,37 @@ class BaseTest < Test::Unit::TestCase @people_david = [{ :id => 2, :name => 'David' }].to_xml(:root => 'people') @addresses = [{ :id => 1, :street => '12345 Street' }].to_xml(:root => 'addresses') + # - deep nested resource - + # - Luis (Customer) + # - JK (Customer::Friend) + # - Mateo (Customer::Friend::Brother) + # - Edith (Customer::Friend::Brother::Child) + # - Martha (Customer::Friend::Brother::Child) + # - Felipe (Customer::Friend::Brother) + # - Bryan (Customer::Friend::Brother::Child) + # - Luke (Customer::Friend::Brother::Child) + # - Eduardo (Customer::Friend) + # - Sebas (Customer::Friend::Brother) + # - Andres (Customer::Friend::Brother::Child) + # - Jorge (Customer::Friend::Brother::Child) + # - Elsa (Customer::Friend::Brother) + # - Natacha (Customer::Friend::Brother::Child) + # - Milena (Customer::Friend::Brother) + # + @luis = {:id => 1, :name => 'Luis', + :friends => [{:name => 'JK', + :brothers => [{:name => 'Mateo', + :children => [{:name => 'Edith'},{:name => 'Martha'}]}, + {:name => 'Felipe', + :children => [{:name => 'Bryan'},{:name => 'Luke'}]}]}, + {:name => 'Eduardo', + :brothers => [{:name => 'Sebas', + :children => [{:name => 'Andres'},{:name => 'Jorge'}]}, + {:name => 'Elsa', + :children => [{:name => 'Natacha'}]}, + {:name => 'Milena', + :children => []}]}]}.to_xml(:root => 'customer') + ActiveResource::HttpMock.respond_to do |mock| mock.get "/people/1.xml", {}, @matz mock.get "/people/2.xml", {}, @david @@ -46,6 +78,8 @@ class BaseTest < Test::Unit::TestCase mock.head "/people/1/addresses/2.xml", {}, nil, 404 mock.head "/people/2/addresses/1.xml", {}, nil, 404 mock.head "/people/Greg/addresses/1.xml", {}, nil, 200 + # customer + mock.get "/customers/1.xml", {}, @luis end Person.user = nil @@ -788,4 +822,18 @@ class BaseTest < Test::Unit::TestCase matz = Person.find(1) assert_equal '1', matz.to_param end + + def test_parse_deep_nested_resources + luis = Customer.find(1) + assert_kind_of Customer, luis + luis.friends.each do |friend| + assert_kind_of Customer::Friend, friend + friend.brothers.each do |brother| + assert_kind_of Customer::Friend::Brother, brother + brother.children.each do |child| + assert_kind_of Customer::Friend::Brother::Child, child + end + end + end + end end diff --git a/activeresource/test/fixtures/customer.rb b/activeresource/test/fixtures/customer.rb new file mode 100644 index 0000000000..845d5d11cb --- /dev/null +++ b/activeresource/test/fixtures/customer.rb @@ -0,0 +1,3 @@ +class Customer < ActiveResource::Base + self.site = "http://37s.sunrise.i:3000" +end From 19895f087c338d8385dff9d272d30fb87cb10330 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Tue, 10 Jun 2008 10:29:25 +0100 Subject: [PATCH 50/75] Lazy load cache and session stores --- actionpack/lib/action_controller/session_management.rb | 9 ++------- actionpack/test/controller/caching_test.rb | 1 + .../test/controller/session/mem_cache_store_test.rb | 2 +- activesupport/lib/active_support/cache.rb | 9 +++------ activesupport/lib/active_support/cache/drb_store.rb | 1 + 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/actionpack/lib/action_controller/session_management.rb b/actionpack/lib/action_controller/session_management.rb index 80a3ddd2c5..ad1013b379 100644 --- a/actionpack/lib/action_controller/session_management.rb +++ b/actionpack/lib/action_controller/session_management.rb @@ -1,10 +1,3 @@ -require 'action_controller/session/cookie_store' -require 'action_controller/session/drb_store' -require 'action_controller/session/mem_cache_store' -if Object.const_defined?(:ActiveRecord) - require 'action_controller/session/active_record_store' -end - module ActionController #:nodoc: module SessionManagement #:nodoc: def self.included(base) @@ -22,6 +15,8 @@ module ActionController #:nodoc: # :p_store, :drb_store, :mem_cache_store, or # :memory_store) or your own custom class. def session_store=(store) + require "action_controller/session/#{store.to_s}" if [:active_record_store, :drb_store, :mem_cache_store].include?(store) + ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:database_manager] = store.is_a?(Symbol) ? CGI::Session.const_get(store == :drb_store ? "DRbStore" : store.to_s.camelize) : store end diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index aee60b1c6f..4fb2397e5b 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -1,5 +1,6 @@ require 'fileutils' require 'abstract_unit' +require "active_support/cache/memory_store" CACHE_DIR = 'test_cache' # Don't change '/../temp/' cavalierly or you might hose something you don't want hosed diff --git a/actionpack/test/controller/session/mem_cache_store_test.rb b/actionpack/test/controller/session/mem_cache_store_test.rb index a7d48431f8..079a870ece 100644 --- a/actionpack/test/controller/session/mem_cache_store_test.rb +++ b/actionpack/test/controller/session/mem_cache_store_test.rb @@ -1,7 +1,7 @@ require 'abstract_unit' require 'action_controller/cgi_process' require 'action_controller/cgi_ext' - +require 'action_controller/session/mem_cache_store' class CGI::Session def cache diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index 2f1143e610..07c83774df 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -7,10 +7,13 @@ module ActiveSupport case store when Symbol + require "active_support/cache/#{store.to_s}" + store_class_name = (store == :drb_store ? "DRbStore" : store.to_s.camelize) store_class = ActiveSupport::Cache.const_get(store_class_name) store_class.new(*parameters) when nil + require "active_support/cache/memory_store" ActiveSupport::Cache::MemoryStore.new else store @@ -137,9 +140,3 @@ module ActiveSupport end end end - -require 'active_support/cache/file_store' -require 'active_support/cache/memory_store' -require 'active_support/cache/drb_store' -require 'active_support/cache/mem_cache_store' -require 'active_support/cache/compressed_mem_cache_store' diff --git a/activesupport/lib/active_support/cache/drb_store.rb b/activesupport/lib/active_support/cache/drb_store.rb index b80c2ee4d5..f06f08f566 100644 --- a/activesupport/lib/active_support/cache/drb_store.rb +++ b/activesupport/lib/active_support/cache/drb_store.rb @@ -1,4 +1,5 @@ require 'drb' +require 'active_support/cache/memory_store' module ActiveSupport module Cache From f5cbad21ac09822a61d6326cbadea16bbe86b623 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Tue, 10 Jun 2008 03:42:43 -0700 Subject: [PATCH 51/75] Rubinious: work around h[k] ||= v returning []= result instead of v --- .../lib/active_support/core_ext/enumerable.rb | 17 ++++++++++++++--- .../lib/active_support/ordered_hash.rb | 1 + 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb index f1469aa0e3..e7f537d045 100644 --- a/activesupport/lib/active_support/core_ext/enumerable.rb +++ b/activesupport/lib/active_support/core_ext/enumerable.rb @@ -1,3 +1,5 @@ +require 'active_support/ordered_hash' + module Enumerable # Ruby 1.8.7 introduces group_by, but the result isn't ordered. Override it. remove_method(:group_by) if [].respond_to?(:group_by) && RUBY_VERSION < '1.9' @@ -18,10 +20,19 @@ module Enumerable # "2006-02-24 -> Transcript, Transcript" # "2006-02-23 -> Transcript" def group_by - inject ActiveSupport::OrderedHash.new do |grouped, element| - (grouped[yield(element)] ||= []) << element - grouped + assoc = ActiveSupport::OrderedHash.new + + each do |element| + key = yield(element) + + if assoc.has_key?(key) + assoc[key] << element + else + assoc[key] = [element] + end end + + assoc end unless [].respond_to?(:group_by) # Calculates a sum from the elements. Examples: diff --git a/activesupport/lib/active_support/ordered_hash.rb b/activesupport/lib/active_support/ordered_hash.rb index 59ceaec696..9757054e43 100644 --- a/activesupport/lib/active_support/ordered_hash.rb +++ b/activesupport/lib/active_support/ordered_hash.rb @@ -12,6 +12,7 @@ module ActiveSupport else self << [key, value] end + value end def [](key) From 34c51c9e8f758a5fc892e654b6ca1ad8b86d1b3a Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Tue, 10 Jun 2008 03:46:23 -0700 Subject: [PATCH 52/75] Rubinious: setup/teardown override for miniunit --- .../testing/setup_and_teardown.rb | 40 +++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb index ed8e34510a..21d71eb92a 100644 --- a/activesupport/lib/active_support/testing/setup_and_teardown.rb +++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb @@ -10,19 +10,43 @@ module ActiveSupport end def self.included(base) - base.send :include, ActiveSupport::Callbacks - base.define_callbacks :setup, :teardown + base.class_eval do + include ActiveSupport::Callbacks + define_callbacks :setup, :teardown - begin - require 'mocha' - base.alias_method_chain :run, :callbacks_and_mocha - rescue LoadError - base.alias_method_chain :run, :callbacks + if defined?(::Mini) + alias_method :run, :run_with_callbacks_and_miniunit + else + begin + require 'mocha' + alias_method :run, :run_with_callbacks_and_mocha + rescue LoadError + alias_method :run, :run_with_callbacks_and_testunit + end + end end end + def run_with_callbacks_and_miniunit(runner) + result = '.' + begin + run_callbacks :setup + result = super + rescue Exception => e + result = runner.puke(self.class, self.name, e) + ensure + begin + teardown + run_callbacks :teardown, :enumerator => :reverse_each + rescue Exception => e + result = runner.puke(self.class, self.name, e) + end + end + result + end + # This redefinition is unfortunate but test/unit shows us no alternative. - def run_with_callbacks(result) #:nodoc: + def run_with_callbacks_and_testunit(result) #:nodoc: return if @method_name.to_s == "default_test" yield(Test::Unit::TestCase::STARTED, name) From fb14c88e39cd28f1e9bf54ef79b85cc085a9f034 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Tue, 10 Jun 2008 14:02:38 -0700 Subject: [PATCH 53/75] Inflector -> ActiveSupport::Inflector --- railties/configs/initializers/inflections.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/configs/initializers/inflections.rb b/railties/configs/initializers/inflections.rb index 09158b865c..d531b8bb82 100644 --- a/railties/configs/initializers/inflections.rb +++ b/railties/configs/initializers/inflections.rb @@ -2,7 +2,7 @@ # Add new inflection rules using the following format # (all these examples are active by default): -# Inflector.inflections do |inflect| +# ActiveSupport::Inflector.inflections do |inflect| # inflect.plural /^(ox)$/i, '\1en' # inflect.singular /^(ox)en/i, '\1' # inflect.irregular 'person', 'people' From b440aeb54a969ec25228881dd02eb019bbfd7c1e Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Tue, 10 Jun 2008 15:48:16 -0700 Subject: [PATCH 54/75] PostgreSQL: insert looks up pk and sequence name if not given. [#384 state:resolved] --- .../connection_adapters/postgresql_adapter.rb | 19 +++++++++++++++++-- .../test/cases/database_statements_test.rb | 12 ++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 activerecord/test/cases/database_statements_test.rb diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index ae070421f1..8a66ec82f9 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -415,8 +415,23 @@ module ActiveRecord # Executes an INSERT query and returns the new record's ID def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) - table = sql.split(" ", 4)[2].gsub('"', '') - super || pk && last_insert_id(table, sequence_name || default_sequence_name(table, pk)) + if insert_id = super + insert_id + else + # Extract the table from the insert sql. Yuck. + table = sql.split(" ", 4)[2].gsub('"', '') + + # If neither pk nor sequence name is given, look them up. + unless pk || sequence_name + pk, sequence_name = *pk_and_sequence_for(table) + end + + # If a pk is given, fallback to default sequence name. + # Don't fetch last insert id for a table without a pk. + if pk && sequence_name ||= default_sequence_name(table, pk) + last_insert_id(table, sequence_name) + end + end end # create a 2D array representing the result set diff --git a/activerecord/test/cases/database_statements_test.rb b/activerecord/test/cases/database_statements_test.rb new file mode 100644 index 0000000000..6274d5250f --- /dev/null +++ b/activerecord/test/cases/database_statements_test.rb @@ -0,0 +1,12 @@ +require "cases/helper" + +class DatabaseStatementsTest < ActiveRecord::TestCase + def setup + @connection = ActiveRecord::Base.connection + end + + def test_insert_should_return_the_inserted_id + id = @connection.insert("INSERT INTO accounts (firm_id,credit_limit) VALUES (42,5000)") + assert_not_nil id + end +end From 0ad0bdc01c4fe2d66dd2b405433186824e7ce136 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Tue, 10 Jun 2008 23:53:30 +0100 Subject: [PATCH 55/75] Delegate ActionView::Base#controller_name to controller --- actionpack/lib/action_view/base.rb | 2 +- actionpack/test/controller/new_render_test.rb | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index eeebf335dc..c417cc07ac 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -184,7 +184,7 @@ module ActionView #:nodoc: attr_internal :request delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers, - :flash, :logger, :action_name, :to => :controller + :flash, :logger, :action_name, :controller_name, :to => :controller module CompiledTemplates #:nodoc: # holds compiled template code diff --git a/actionpack/test/controller/new_render_test.rb b/actionpack/test/controller/new_render_test.rb index 6b83b8337e..b77b3ceffa 100644 --- a/actionpack/test/controller/new_render_test.rb +++ b/actionpack/test/controller/new_render_test.rb @@ -220,7 +220,7 @@ class NewRenderTestController < ActionController::Base render :action => "test/hello_world" end - def render_to_string_with_partial + def render_to_string_with_partial @partial_only = render_to_string :partial => "partial_only" @partial_with_locals = render_to_string :partial => "customer", :locals => { :customer => Customer.new("david") } render :action => "test/hello_world" @@ -251,11 +251,15 @@ class NewRenderTestController < ActionController::Base def accessing_logger_in_template render :inline => "<%= logger.class %>" end - + def accessing_action_name_in_template render :inline => "<%= action_name %>" end + def accessing_controller_name_in_template + render :inline => "<%= controller_name %>" + end + def accessing_params_in_template_with_layout render :layout => nil, :inline => "Hello: <%= params[:name] %>" end @@ -559,12 +563,17 @@ class NewRenderTest < Test::Unit::TestCase get :accessing_logger_in_template assert_equal "Logger", @response.body end - + def test_access_to_action_name_in_view get :accessing_action_name_in_template assert_equal "accessing_action_name_in_template", @response.body end + def test_access_to_controller_name_in_view + get :accessing_controller_name_in_template + assert_equal "test", @response.body # name is explicitly set to 'test' inside the controller. + end + def test_render_xml get :render_xml_hello assert_equal "\n

        Hello David

        \n

        This is grand!

        \n\n", @response.body From 03bf72721900049ce18750767a22cf8091886c07 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Tue, 10 Jun 2008 18:31:37 -0700 Subject: [PATCH 56/75] PostgreSQL: use 'INSERT ... RETURNING id' for 8.2 and later. --- activerecord/CHANGELOG | 2 ++ .../connection_adapters/postgresql_adapter.rb | 23 ++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index a65771648e..a899bfbd52 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *Edge* +* PostgreSQL: use 'INSERT ... RETURNING id' for 8.2 and later. [Jeremy Kemper] + * Added SQL escaping for :limit and :offset in MySQL [Jonathan Wiess] diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 8a66ec82f9..e759a74faf 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -323,6 +323,12 @@ module ActiveRecord has_support end + def supports_insert_with_returning? + @supports_insert_with_returning ||= + @connection.respond_to?(:server_version) && + @connection.server_version >= 80200 + end + # Returns the configured supported identifier length supported by PostgreSQL, # or report the default of 63 on PostgreSQL 7.x. def table_alias_length @@ -415,12 +421,23 @@ module ActiveRecord # Executes an INSERT query and returns the new record's ID def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) + # Extract the table from the insert sql. Yuck. + table = sql.split(" ", 4)[2].gsub('"', '') + + # Try an insert with 'returning id' if available (PG >= 8.2) + if supports_insert_with_returning? + pk, sequence_name = *pk_and_sequence_for(table) unless pk + if pk + id = select_value("#{sql} RETURNING #{quote_column_name(pk)}") + clear_query_cache + return id + end + end + + # Otherwise, insert then grab last_insert_id. if insert_id = super insert_id else - # Extract the table from the insert sql. Yuck. - table = sql.split(" ", 4)[2].gsub('"', '') - # If neither pk nor sequence name is given, look them up. unless pk || sequence_name pk, sequence_name = *pk_and_sequence_for(table) From e8a0ba4c93e2f0f811675bc6a6720725c866d1a5 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 10 Jun 2008 20:38:18 -0500 Subject: [PATCH 57/75] Ensure view path cache is rebuilt in production mode which was broke by df44df9. --- actionpack/lib/action_controller/dispatcher.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/action_controller/dispatcher.rb b/actionpack/lib/action_controller/dispatcher.rb index 64553fb25d..f20d9cc40f 100644 --- a/actionpack/lib/action_controller/dispatcher.rb +++ b/actionpack/lib/action_controller/dispatcher.rb @@ -10,10 +10,6 @@ module ActionController # Development mode callbacks before_dispatch :reload_application after_dispatch :cleanup_application - - to_prepare :reload_view_path_cache do - ActionView::TemplateFinder.reload! unless ActionView::Base.cache_template_loading - end end # Common callbacks @@ -25,6 +21,10 @@ module ActionController end end + to_prepare :reload_view_path_cache do + ActionView::TemplateFinder.reload! + end + if defined?(ActiveRecord) before_dispatch { ActiveRecord::Base.verify_active_connections! } to_prepare(:activerecord_instantiate_observers) { ActiveRecord::Base.instantiate_observers } From 634e462a0b70ddae2f21dbddddd07e7b340bb69c Mon Sep 17 00:00:00 2001 From: Grant Hollingworth Date: Tue, 10 Jun 2008 11:54:58 -0400 Subject: [PATCH 58/75] Performance: speed up Hash#except. [#382 state:resolved] --- activesupport/lib/active_support/core_ext/hash/except.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/hash/except.rb b/activesupport/lib/active_support/core_ext/hash/except.rb index 8362cd880e..bc97fa35a6 100644 --- a/activesupport/lib/active_support/core_ext/hash/except.rb +++ b/activesupport/lib/active_support/core_ext/hash/except.rb @@ -10,13 +10,14 @@ module ActiveSupport #:nodoc: module Except # Returns a new hash without the given keys. def except(*keys) - rejected = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys) - reject { |key,| rejected.include?(key) } + clone.except!(*keys) end # Replaces the hash without only the given keys. def except!(*keys) - replace(except(*keys)) + keys.map! { |key| convert_key(key) } if respond_to?(:convert_key) + keys.each { |key| delete(key) } + self end end end From 3f594299c85ef111ac479b845fa8c7e37563ff66 Mon Sep 17 00:00:00 2001 From: Ruy Asan Date: Tue, 10 Jun 2008 21:13:27 -0700 Subject: [PATCH 59/75] TimeZone -> ActiveSupport::TimeZone. [#387 state:resolved] --- actionpack/lib/action_view/helpers/form_options_helper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index e0a097e367..b3f8e63c1b 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -304,7 +304,7 @@ module ActionView # # NOTE: Only the option tags are returned, you have to wrap this call in # a regular HTML select tag. - def time_zone_options_for_select(selected = nil, priority_zones = nil, model = TimeZone) + def time_zone_options_for_select(selected = nil, priority_zones = nil, model = ::ActiveSupport::TimeZone) zone_options = "" zones = model.all @@ -417,7 +417,7 @@ module ActionView value = value(object) content_tag("select", add_options( - time_zone_options_for_select(value || options[:default], priority_zones, options[:model] || TimeZone), + time_zone_options_for_select(value || options[:default], priority_zones, options[:model] || ActiveSupport::TimeZone), options, value ), html_options ) From f728e57d2204a429f5282856ec89d4e047e72957 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Wed, 11 Jun 2008 09:11:08 +0100 Subject: [PATCH 60/75] Make sure cache_template_loading works and don't use to_prepare callback --- actionpack/CHANGELOG | 2 -- actionpack/lib/action_controller/dispatcher.rb | 5 +---- actionpack/lib/action_view/template.rb | 1 + 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index f9cb715400..3096716dba 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,7 +1,5 @@ *Edge* -* Ensure ActionView::TemplateFinder view cache is rebuilt on initialize [Josh Peek] - * Drop ActionController::Base.allow_concurrency flag [Josh Peek] * More efficient concat and capture helpers. Remove ActionView::Base.erb_variable. [Jeremy Kemper] diff --git a/actionpack/lib/action_controller/dispatcher.rb b/actionpack/lib/action_controller/dispatcher.rb index f20d9cc40f..fe4f6b4a7e 100644 --- a/actionpack/lib/action_controller/dispatcher.rb +++ b/actionpack/lib/action_controller/dispatcher.rb @@ -21,10 +21,6 @@ module ActionController end end - to_prepare :reload_view_path_cache do - ActionView::TemplateFinder.reload! - end - if defined?(ActiveRecord) before_dispatch { ActiveRecord::Base.verify_active_connections! } to_prepare(:activerecord_instantiate_observers) { ActiveRecord::Base.instantiate_observers } @@ -138,6 +134,7 @@ module ActionController run_callbacks :prepare_dispatch Routing::Routes.reload + ActionView::TemplateFinder.reload! unless ActionView::Base.cache_template_loading end # Cleanup the application by clearing out loaded classes so they can diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index a878ac66d9..25d5819af9 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -99,6 +99,7 @@ module ActionView #:nodoc: # return the rendered template as a string. def self.register_template_handler(extension, klass) @@template_handlers[extension.to_sym] = klass + ActionView::TemplateFinder.reload! end def self.template_handler_extensions From 7f140bbddaf70abc61570f6cfdcbfba5771ffc78 Mon Sep 17 00:00:00 2001 From: Jan De Poorter Date: Wed, 11 Jun 2008 13:08:35 +0200 Subject: [PATCH 61/75] Add :validate option to associations. [#301 state:resolved] Signed-off-by: Pratik Naik --- activerecord/CHANGELOG | 2 ++ .../lib/active_record/associations.rb | 24 ++++++++++++------- .../belongs_to_associations_test.rb | 19 +++++++++++++++ .../has_many_associations_test.rb | 11 +++++++++ .../associations/has_one_associations_test.rb | 12 ++++++++++ activerecord/test/cases/reflection_test.rb | 6 ++--- activerecord/test/models/company.rb | 4 +++- activerecord/test/models/developer.rb | 1 + 8 files changed, 67 insertions(+), 12 deletions(-) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index a899bfbd52..b726962872 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *Edge* +* Add :validate option to associations to enable/disable the automatic validation of associated models. Resolves #301. [Jan De Poorter] + * PostgreSQL: use 'INSERT ... RETURNING id' for 8.2 and later. [Jeremy Kemper] * Added SQL escaping for :limit and :offset in MySQL [Jonathan Wiess] diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 8ddcc24daa..cbdb145078 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -690,6 +690,7 @@ module ActiveRecord # association is a polymorphic +belongs_to+. # * :uniq - If true, duplicates will be omitted from the collection. Useful in conjunction with :through. # * :readonly - If true, all the associated objects are readonly through the association. + # * :validate - If false, don't validate the associated objects when saving the parent object. true by default. # # Option examples: # has_many :comments, :order => "posted_on" @@ -710,7 +711,7 @@ module ActiveRecord configure_dependency_for_has_many(reflection) - add_multiple_associated_save_callbacks(reflection.name) + add_multiple_associated_save_callbacks(reflection.name) unless options[:validate] == false add_association_callbacks(reflection.name, reflection.options) if options[:through] @@ -769,6 +770,7 @@ module ActiveRecord # * :source_type - Specifies type of the source association used by has_one :through queries where the source # association is a polymorphic +belongs_to+. # * :readonly - If true, the associated object is readonly through the association. + # * :validate - If false, don't validate the associated object when saving the parent object. +false+ by default. # # Option examples: # has_one :credit_card, :dependent => :destroy # destroys the associated credit card @@ -799,7 +801,7 @@ module ActiveRecord end after_save method_name - add_single_associated_save_callbacks(reflection.name) + add_single_associated_save_callbacks(reflection.name) if options[:validate] == true association_accessor_methods(reflection, HasOneAssociation) association_constructor_method(:build, reflection, HasOneAssociation) association_constructor_method(:create, reflection, HasOneAssociation) @@ -857,6 +859,7 @@ module ActiveRecord # Note: If you've enabled the counter cache, then you may want to add the counter cache attribute # to the +attr_readonly+ list in the associated classes (e.g. class Post; attr_readonly :comments_count; end). # * :readonly - If true, the associated object is readonly through the association. + # * :validate - If false, don't validate the associated objects when saving the parent object. +true+ by default. # # Option examples: # belongs_to :firm, :foreign_key => "client_of" @@ -937,6 +940,8 @@ module ActiveRecord ) end + add_single_associated_save_callbacks(reflection.name) unless options[:validate] == false + configure_dependency_for_belongs_to(reflection) end @@ -1025,6 +1030,7 @@ module ActiveRecord # * :select - By default, this is * as in SELECT * FROM, but can be changed if, for example, you want to do a join # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error. # * :readonly - If true, all the associated objects are readonly through the association. + # * :validate - If false, don't validate the associated objects when saving the parent object. +true+ by default. # # Option examples: # has_and_belongs_to_many :projects @@ -1037,7 +1043,7 @@ module ActiveRecord def has_and_belongs_to_many(association_id, options = {}, &extension) reflection = create_has_and_belongs_to_many_reflection(association_id, options, &extension) - add_multiple_associated_save_callbacks(reflection.name) + add_multiple_associated_save_callbacks(reflection.name) unless options[:validate] == false collection_accessor_methods(reflection, HasAndBelongsToManyAssociation) # Don't use a before_destroy callback since users' before_destroy @@ -1343,7 +1349,8 @@ module ActiveRecord :uniq, :finder_sql, :counter_sql, :before_add, :after_add, :before_remove, :after_remove, - :extend, :readonly + :extend, :readonly, + :validate ) options[:extend] = create_extension_modules(association_id, extension, options[:extend]) @@ -1353,7 +1360,7 @@ module ActiveRecord def create_has_one_reflection(association_id, options) options.assert_valid_keys( - :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly + :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly, :validate ) create_reflection(:has_one, association_id, options, self) @@ -1361,7 +1368,7 @@ module ActiveRecord def create_has_one_through_reflection(association_id, options) options.assert_valid_keys( - :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :through, :source, :source_type + :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :through, :source, :source_type, :validate ) create_reflection(:has_one, association_id, options, self) end @@ -1369,7 +1376,7 @@ module ActiveRecord def create_belongs_to_reflection(association_id, options) options.assert_valid_keys( :class_name, :foreign_key, :foreign_type, :remote, :select, :conditions, :include, :dependent, - :counter_cache, :extend, :polymorphic, :readonly + :counter_cache, :extend, :polymorphic, :readonly, :validate ) reflection = create_reflection(:belongs_to, association_id, options, self) @@ -1388,7 +1395,8 @@ module ActiveRecord :uniq, :finder_sql, :delete_sql, :insert_sql, :before_add, :after_add, :before_remove, :after_remove, - :extend, :readonly + :extend, :readonly, + :validate ) options[:extend] = create_extension_modules(association_id, extension, options[:extend]) diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index e0da8bfb7a..9c718c4fef 100755 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -409,4 +409,23 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase sponsor.sponsorable = new_member assert_equal nil, sponsor.sponsorable_id end + + def test_save_fails_for_invalid_belongs_to + assert log = AuditLog.create(:developer_id=>0,:message=>"") + + log.developer = Developer.new + assert !log.developer.valid? + assert !log.valid? + assert !log.save + assert_equal "is invalid", log.errors.on("developer") + end + + def test_save_succeeds_for_invalid_belongs_to_with_validate_false + assert log = AuditLog.create(:developer_id=>0,:message=>"") + + log.unvalidated_developer = Developer.new + assert !log.unvalidated_developer.valid? + assert log.valid? + assert log.save + end end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index dbfa025efb..1f23ff256c 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -342,6 +342,17 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert new_firm.new_record? end + def test_invalid_adding_with_validate_false + firm = Firm.find(:first) + client = Client.new + firm.unvalidated_clients_of_firm << Client.new + + assert firm.valid? + assert !client.valid? + assert firm.save + assert client.new_record? + end + def test_build company = companies(:first_firm) new_client = assert_no_queries { company.clients_of_firm.build("name" => "Another Client") } diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index abc7ee7e9d..d3ca0cae41 100755 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -275,6 +275,18 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert_equal "is invalid", firm.errors.on("account") end + + def test_save_succeeds_for_invalid_has_one_with_validate_false + firm = Firm.find(:first) + assert firm.valid? + + firm.unvalidated_account = Account.new + + assert !firm.unvalidated_account.valid? + assert firm.valid? + assert firm.save + end + def test_assignment_before_either_saved firm = Firm.new("name" => "GlobalMegaCorp") firm.account = a = Account.new("credit_limit" => 1000) diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index 8b4d232554..0c57b79401 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -160,9 +160,9 @@ class ReflectionTest < ActiveRecord::TestCase def test_reflection_of_all_associations # FIXME these assertions bust a lot - assert_equal 20, Firm.reflect_on_all_associations.size - assert_equal 16, Firm.reflect_on_all_associations(:has_many).size - assert_equal 4, Firm.reflect_on_all_associations(:has_one).size + assert_equal 22, Firm.reflect_on_all_associations.size + assert_equal 17, Firm.reflect_on_all_associations(:has_many).size + assert_equal 5, Firm.reflect_on_all_associations(:has_one).size assert_equal 0, Firm.reflect_on_all_associations(:belongs_to).size end diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb index 70f83fa8e6..9fa810ac68 100755 --- a/activerecord/test/models/company.rb +++ b/activerecord/test/models/company.rb @@ -26,6 +26,7 @@ class Firm < Company "AND (#{QUOTED_TYPE} = 'Client' OR #{QUOTED_TYPE} = 'SpecialClient' OR #{QUOTED_TYPE} = 'VerySpecialClient' )" has_many :clients_sorted_desc, :class_name => "Client", :order => "id DESC" has_many :clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id" + has_many :unvalidated_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :validate => false has_many :dependent_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id", :dependent => :destroy has_many :exclusively_dependent_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id", :dependent => :delete_all has_many :limited_clients, :class_name => "Client", :order => "id", :limit => 1 @@ -46,7 +47,8 @@ class Firm < Company has_many :plain_clients, :class_name => 'Client' has_many :readonly_clients, :class_name => 'Client', :readonly => true - has_one :account, :foreign_key => "firm_id", :dependent => :destroy + has_one :account, :foreign_key => "firm_id", :dependent => :destroy, :validate => true + has_one :unvalidated_account, :foreign_key => "firm_id", :class_name => 'Account', :validate => false has_one :account_with_select, :foreign_key => "firm_id", :select => "id, firm_id", :class_name=>'Account' has_one :readonly_account, :foreign_key => "firm_id", :class_name => "Account", :readonly => true end diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb index f77fd0e96d..7a64bed5ff 100644 --- a/activerecord/test/models/developer.rb +++ b/activerecord/test/models/developer.rb @@ -57,6 +57,7 @@ end class AuditLog < ActiveRecord::Base belongs_to :developer + belongs_to :unvalidated_developer, :class_name => 'Developer', :validate => false end DeveloperSalary = Struct.new(:amount) From 71bf756ea21f338771b53d02951d6654bd295649 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Wed, 11 Jun 2008 12:39:56 +0100 Subject: [PATCH 62/75] Disable validations for associated belongs_to record by default --- activerecord/lib/active_record/associations.rb | 2 +- activerecord/test/models/developer.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index cbdb145078..fc186f806c 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -940,7 +940,7 @@ module ActiveRecord ) end - add_single_associated_save_callbacks(reflection.name) unless options[:validate] == false + add_single_associated_save_callbacks(reflection.name) if options[:validate] == true configure_dependency_for_belongs_to(reflection) end diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb index 7a64bed5ff..9f26cacdec 100644 --- a/activerecord/test/models/developer.rb +++ b/activerecord/test/models/developer.rb @@ -56,8 +56,8 @@ class Developer < ActiveRecord::Base end class AuditLog < ActiveRecord::Base - belongs_to :developer - belongs_to :unvalidated_developer, :class_name => 'Developer', :validate => false + belongs_to :developer, :validate => true + belongs_to :unvalidated_developer, :class_name => 'Developer' end DeveloperSalary = Struct.new(:amount) From 6fd73442d83ee162af622b722b1e1b7356fa9fcb Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Wed, 11 Jun 2008 12:57:19 +0100 Subject: [PATCH 63/75] Update docs to reflect 71bf75 --- activerecord/lib/active_record/associations.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index fc186f806c..5f42b5a459 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -859,7 +859,7 @@ module ActiveRecord # Note: If you've enabled the counter cache, then you may want to add the counter cache attribute # to the +attr_readonly+ list in the associated classes (e.g. class Post; attr_readonly :comments_count; end). # * :readonly - If true, the associated object is readonly through the association. - # * :validate - If false, don't validate the associated objects when saving the parent object. +true+ by default. + # * :validate - If false, don't validate the associated objects when saving the parent object. +false+ by default. # # Option examples: # belongs_to :firm, :foreign_key => "client_of" From 3e07f320c10b53ec21b947d949d0063e724c5fd8 Mon Sep 17 00:00:00 2001 From: Jonathan del Strother Date: Thu, 6 Mar 2008 11:50:44 +0000 Subject: [PATCH 64/75] Improve ActionCaching's format-handling Make ActionCaching more aware of different mimetype formats. It will now use request.format to look up the cache type, in addition to the path extension. When expiring caches, the request format no longer affects which cache is expired. Signed-off-by: Pratik Naik --- actionpack/CHANGELOG | 2 + .../lib/action_controller/caching/actions.rb | 41 +++++++++----- actionpack/test/controller/caching_test.rb | 53 +++++++++++++++++-- 3 files changed, 79 insertions(+), 17 deletions(-) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 3096716dba..8d1acb265f 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *Edge* +* Make caching more aware of mime types. Ensure request format is not considered while expiring cache. [Jonathan del Strother] + * Drop ActionController::Base.allow_concurrency flag [Josh Peek] * More efficient concat and capture helpers. Remove ActionView::Base.erb_variable. [Jeremy Kemper] diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb index c4b0a97a33..65a36f7f98 100644 --- a/actionpack/lib/action_controller/caching/actions.rb +++ b/actionpack/lib/action_controller/caching/actions.rb @@ -67,10 +67,10 @@ module ActionController #:nodoc: if options[:action].is_a?(Array) options[:action].dup.each do |action| - expire_fragment(ActionCachePath.path_for(self, options.merge({ :action => action }))) + expire_fragment(ActionCachePath.path_for(self, options.merge({ :action => action }), false)) end else - expire_fragment(ActionCachePath.path_for(self, options)) + expire_fragment(ActionCachePath.path_for(self, options, false)) end end @@ -125,16 +125,24 @@ module ActionController #:nodoc: attr_reader :path, :extension class << self - def path_for(controller, options) - new(controller, options).path + def path_for(controller, options, infer_extension=true) + new(controller, options, infer_extension).path end end - - def initialize(controller, options = {}) - @extension = extract_extension(controller.request.path) + + # When true, infer_extension will look up the cache path extension from the request's path & format. + # This is desirable when reading and writing the cache, but not when expiring the cache - expire_action should expire the same files regardless of the request format. + def initialize(controller, options = {}, infer_extension=true) + if infer_extension and options.is_a? Hash + request_extension = extract_extension(controller.request) + options = options.reverse_merge(:format => request_extension) + end path = controller.url_for(options).split('://').last normalize!(path) - add_extension!(path, @extension) + if infer_extension + @extension = request_extension + add_extension!(path, @extension) + end @path = URI.unescape(path) end @@ -144,13 +152,22 @@ module ActionController #:nodoc: end def add_extension!(path, extension) - path << ".#{extension}" if extension + path << ".#{extension}" if extension and !path.ends_with?(extension) end - - def extract_extension(file_path) + + def extract_extension(request) # Don't want just what comes after the last '.' to accommodate multi part extensions # such as tar.gz. - file_path[/^[^.]+\.(.+)$/, 1] + extension = request.path[/^[^.]+\.(.+)$/, 1] + + # If there's no extension in the path, check request.format + if extension.nil? + extension = request.format.to_sym.to_s + if extension=='all' + extension = nil + end + end + extension end end end diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index 4fb2397e5b..89e12ddae3 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -189,6 +189,10 @@ class ActionCachingTestController < ActionController::Base expire_action :controller => 'action_caching_test', :action => 'index' render :nothing => true end + def expire_xml + expire_action :controller => 'action_caching_test', :action => 'index', :format => 'xml' + render :nothing => true + end end class MockTime < Time @@ -214,6 +218,7 @@ class ActionCachingMockController mocked_path = @mock_path Object.new.instance_eval(<<-EVAL) def path; '#{@mock_path}' end + def format; 'all' end self EVAL end @@ -327,6 +332,20 @@ class ActionCacheTest < Test::Unit::TestCase assert_equal new_cached_time, @response.body end + def test_cache_expiration_isnt_affected_by_request_format + get :index + cached_time = content_to_cache + reset! + + @request.set_REQUEST_URI "/action_caching_test/expire.xml" + get :expire, :format => :xml + reset! + + get :index + new_cached_time = content_to_cache + assert_not_equal cached_time, @response.body + end + def test_cache_is_scoped_by_subdomain @request.host = 'jamis.hostname.com' get :index @@ -371,11 +390,35 @@ class ActionCacheTest < Test::Unit::TestCase end def test_xml_version_of_resource_is_treated_as_different_cache - @mock_controller.mock_url_for = 'http://example.org/posts/' - @mock_controller.mock_path = '/posts/index.xml' - path_object = @path_class.new(@mock_controller, {}) - assert_equal 'xml', path_object.extension - assert_equal 'example.org/posts/index.xml', path_object.path + with_routing do |set| + ActionController::Routing::Routes.draw do |map| + map.connect ':controller/:action.:format' + map.connect ':controller/:action' + end + + get :index, :format => 'xml' + cached_time = content_to_cache + assert_equal cached_time, @response.body + assert fragment_exist?('hostname.com/action_caching_test/index.xml') + reset! + + get :index, :format => 'xml' + assert_equal cached_time, @response.body + assert_equal 'application/xml', @response.content_type + reset! + + @request.env['HTTP_ACCEPT'] = "application/xml" + get :index + assert_equal cached_time, @response.body + assert_equal 'application/xml', @response.content_type + reset! + + get :expire_xml + reset! + + get :index, :format => 'xml' + assert_not_equal cached_time, @response.body + end end def test_correct_content_type_is_returned_for_cache_hit From ca9641f8a7ca1142d0ea99405a079c8699bd443c Mon Sep 17 00:00:00 2001 From: Jan De Poorter Date: Wed, 11 Jun 2008 13:17:40 +0100 Subject: [PATCH 65/75] Fix FormOptionsHelper tests. Signed-off-by: Pratik Naik --- actionpack/test/template/form_options_helper_test.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb index 4fb2be9d3f..d5aeb4939e 100644 --- a/actionpack/test/template/form_options_helper_test.rb +++ b/actionpack/test/template/form_options_helper_test.rb @@ -20,7 +20,7 @@ class MockTimeZone end end -ActionView::Helpers::FormOptionsHelper::TimeZone = MockTimeZone +ActiveSupport::TimeZone = MockTimeZone class FormOptionsHelperTest < ActionView::TestCase tests ActionView::Helpers::FormOptionsHelper @@ -183,7 +183,7 @@ class FormOptionsHelperTest < ActionView::TestCase end def test_time_zone_options_with_priority_zones - zones = [ TimeZone.new( "B" ), TimeZone.new( "E" ) ] + zones = [ ActiveSupport::TimeZone.new( "B" ), ActiveSupport::TimeZone.new( "E" ) ] opts = time_zone_options_for_select( nil, zones ) assert_dom_equal "\n" + "" + @@ -195,7 +195,7 @@ class FormOptionsHelperTest < ActionView::TestCase end def test_time_zone_options_with_selected_priority_zones - zones = [ TimeZone.new( "B" ), TimeZone.new( "E" ) ] + zones = [ ActiveSupport::TimeZone.new( "B" ), ActiveSupport::TimeZone.new( "E" ) ] opts = time_zone_options_for_select( "E", zones ) assert_dom_equal "\n" + "" + @@ -207,7 +207,7 @@ class FormOptionsHelperTest < ActionView::TestCase end def test_time_zone_options_with_unselected_priority_zones - zones = [ TimeZone.new( "B" ), TimeZone.new( "E" ) ] + zones = [ ActiveSupport::TimeZone.new( "B" ), ActiveSupport::TimeZone.new( "E" ) ] opts = time_zone_options_for_select( "C", zones ) assert_dom_equal "\n" + "" + @@ -1287,7 +1287,7 @@ COUNTRIES def test_time_zone_select_with_priority_zones @firm = Firm.new("D") - zones = [ TimeZone.new("A"), TimeZone.new("D") ] + zones = [ ActiveSupport::TimeZone.new("A"), ActiveSupport::TimeZone.new("D") ] html = time_zone_select("firm", "time_zone", zones ) assert_dom_equal "