aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionmailer/lib/action_mailer/base.rb3
-rw-r--r--actionpack/CHANGELOG6
-rwxr-xr-xactionpack/lib/action_controller/base.rb7
-rw-r--r--actionpack/lib/action_controller/caching/actions.rb41
-rw-r--r--actionpack/lib/action_controller/rack_process.rb2
-rw-r--r--actionpack/lib/action_controller/record_identifier.rb29
-rw-r--r--actionpack/lib/action_controller/routing/segments.rb2
-rw-r--r--actionpack/lib/action_controller/session_management.rb9
-rw-r--r--actionpack/lib/action_view.rb7
-rw-r--r--actionpack/lib/action_view/base.rb23
-rw-r--r--actionpack/lib/action_view/helpers/capture_helper.rb55
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb14
-rw-r--r--actionpack/lib/action_view/helpers/javascript_helper.rb28
-rw-r--r--actionpack/lib/action_view/helpers/prototype_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/record_tag_helper.rb5
-rw-r--r--actionpack/lib/action_view/helpers/tag_helper.rb18
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb18
-rw-r--r--actionpack/lib/action_view/partial_template.rb2
-rw-r--r--actionpack/lib/action_view/template.rb91
-rw-r--r--actionpack/lib/action_view/template_finder.rb34
-rw-r--r--actionpack/lib/action_view/template_handler.rb1
-rw-r--r--actionpack/lib/action_view/template_handlers.rb46
-rw-r--r--actionpack/lib/action_view/template_handlers/builder.rb7
-rw-r--r--actionpack/lib/action_view/template_handlers/compilable.rb4
-rw-r--r--actionpack/lib/action_view/template_handlers/erb.rb6
-rw-r--r--actionpack/lib/action_view/test_case.rb5
-rw-r--r--actionpack/test/controller/caching_test.rb58
-rw-r--r--actionpack/test/controller/capture_test.rb20
-rwxr-xr-xactionpack/test/controller/cgi_test.rb50
-rw-r--r--actionpack/test/controller/new_render_test.rb29
-rw-r--r--actionpack/test/controller/routing_test.rb3231
-rw-r--r--actionpack/test/controller/session/mem_cache_store_test.rb2
-rw-r--r--actionpack/test/fixtures/test/block_content_for.erb2
-rw-r--r--actionpack/test/fixtures/test/erb_content_for.erb2
-rw-r--r--actionpack/test/fixtures/test/render_file_from_template.html.erb1
-rwxr-xr-xactionpack/test/template/date_helper_test.rb12
-rw-r--r--actionpack/test/template/form_helper_test.rb251
-rw-r--r--actionpack/test/template/form_options_helper_test.rb36
-rw-r--r--actionpack/test/template/form_tag_helper_test.rb29
-rw-r--r--actionpack/test/template/javascript_helper_test.rb14
-rw-r--r--actionpack/test/template/prototype_helper_test.rb20
-rw-r--r--actionpack/test/template/record_tag_helper_test.rb9
-rw-r--r--actionpack/test/template/tag_helper_test.rb11
-rw-r--r--actionpack/test/template/template_finder_test.rb13
-rw-r--r--actionpack/test/template/text_helper_test.rb8
-rw-r--r--activerecord/CHANGELOG6
-rw-r--r--activerecord/lib/active_record/association_preload.rb4
-rwxr-xr-xactiverecord/lib/active_record/associations.rb28
-rwxr-xr-xactiverecord/lib/active_record/base.rb29
-rw-r--r--activerecord/lib/active_record/calculations.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb4
-rwxr-xr-xactiverecord/lib/active_record/connection_adapters/mysql_adapter.rb79
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb77
-rwxr-xr-xactiverecord/lib/active_record/fixtures.rb2
-rwxr-xr-xactiverecord/lib/active_record/validations.rb9
-rw-r--r--activerecord/lib/active_record/vendor/db2.rb362
-rw-r--r--activerecord/lib/active_record/vendor/mysql.rb1214
-rw-r--r--activerecord/test/cases/active_schema_test_postgresql.rb4
-rwxr-xr-xactiverecord/test/cases/associations/belongs_to_associations_test.rb19
-rw-r--r--activerecord/test/cases/associations/eager_test.rb13
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb17
-rwxr-xr-xactiverecord/test/cases/associations/has_one_associations_test.rb12
-rw-r--r--activerecord/test/cases/calculations_test.rb46
-rw-r--r--activerecord/test/cases/database_statements_test.rb12
-rw-r--r--activerecord/test/cases/reflection_test.rb6
-rwxr-xr-xactiverecord/test/models/company.rb4
-rw-r--r--activerecord/test/models/developer.rb3
-rw-r--r--activeresource/lib/active_resource/base.rb6
-rw-r--r--activeresource/test/base_test.rb48
-rw-r--r--activeresource/test/fixtures/customer.rb3
-rw-r--r--activesupport/lib/active_support/cache.rb9
-rw-r--r--activesupport/lib/active_support/cache/compressed_mem_cache_store.rb2
-rw-r--r--activesupport/lib/active_support/cache/drb_store.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/enumerable.rb17
-rw-r--r--activesupport/lib/active_support/core_ext/hash/except.rb7
-rw-r--r--activesupport/lib/active_support/core_ext/hash/slice.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/module.rb5
-rw-r--r--activesupport/lib/active_support/core_ext/module/model_naming.rb22
-rw-r--r--activesupport/lib/active_support/core_ext/object/extending.rb17
-rw-r--r--activesupport/lib/active_support/core_ext/string/unicode.rb24
-rw-r--r--activesupport/lib/active_support/inflector.rb12
-rw-r--r--activesupport/lib/active_support/ordered_hash.rb1
-rw-r--r--activesupport/lib/active_support/testing/setup_and_teardown.rb38
-rw-r--r--activesupport/test/core_ext/class_test.rb2
-rw-r--r--activesupport/test/core_ext/module/model_naming_test.rb19
-rw-r--r--activesupport/test/core_ext/time_with_zone_test.rb34
-rw-r--r--activesupport/test/test_test.rb6
-rw-r--r--railties/configs/initializers/inflections.rb2
-rw-r--r--railties/lib/rails/gem_dependency.rb31
-rw-r--r--railties/lib/rails/plugin.rb10
-rw-r--r--railties/lib/webrick_server.rb13
-rw-r--r--railties/test/fixtures/plugins/default/gemlike/init.rb1
-rw-r--r--railties/test/fixtures/plugins/default/gemlike/lib/gemlike.rb2
-rw-r--r--railties/test/fixtures/plugins/default/gemlike/rails/init.rb7
-rw-r--r--railties/test/initializer_test.rb102
-rw-r--r--railties/test/plugin_loader_test.rb12
-rw-r--r--railties/test/plugin_locator_test.rb4
-rw-r--r--railties/test/plugin_test.rb16
-rw-r--r--railties/test/rails_info_controller_test.rb4
101 files changed, 2686 insertions, 4032 deletions
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/CHANGELOG b/actionpack/CHANGELOG
index 66af5fd745..8d1acb265f 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,11 @@
*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]
+
* 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]
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 <tt>@@param_parsers</tt> hash lets you register handlers which will process the HTTP body and add parameters to the
# <tt>params</tt> hash. These handlers are invoked for POST and PUT requests.
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/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
diff --git a/actionpack/lib/action_controller/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb
index 643ff7e5f4..f69c3d6163 100644
--- a/actionpack/lib/action_controller/record_identifier.rb
+++ b/actionpack/lib/action_controller/record_identifier.rb
@@ -31,18 +31,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.partial_path}"
else
- "#{klass.name.tableize}/#{klass.name.demodulize.underscore}"
+ name.partial_path
end
end
@@ -56,7 +59,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 +73,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 +85,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 +93,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
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
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:
# <tt>:p_store</tt>, <tt>:drb_store</tt>, <tt>:mem_cache_store</tt>, or
# <tt>:memory_store</tt>) 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/lib/action_view.rb b/actionpack/lib/action_view.rb
index 5f4126e4e9..2f6894a8f9 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -21,12 +21,7 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
-require 'action_view/template_handler'
-require 'action_view/template_handlers/compilable'
-require 'action_view/template_handlers/builder'
-require 'action_view/template_handlers/erb'
-require 'action_view/template_handlers/rjs'
-
+require 'action_view/template_handlers'
require 'action_view/template_finder'
require 'action_view/template'
require 'action_view/partial_template'
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index f398756550..c417cc07ac 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 = '-'
@@ -178,14 +180,11 @@ 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,
- :flash, :logger, :action_name, :to => :controller
+ :flash, :logger, :action_name, :controller_name, :to => :controller
module CompiledTemplates #:nodoc:
# holds compiled template code
@@ -253,12 +252,13 @@ 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)
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
@@ -266,7 +266,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]
@@ -316,9 +316,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 9ea06568cf..9cd9d3d06a 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
# </body></html>
#
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
+ if output_buffer
+ with_output_buffer { block.call(*args) }
else
- capture_erb_with_buffer(buffer, *args, &block).to_s
+ block.call(*args)
end
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 <tt>yield</tt>.
@@ -121,40 +114,18 @@ module ActionView
# named <tt>@content_for_#{name_of_the_content_block}</tt>. The preferred usage is now
# <tt><%= yield :footer %></tt>.
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}"
+ content = capture(&block) if block_given?
+ instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{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)"
- end
-
- def block_content_for(name, &block)
- eval "@content_for_#{name} = (@content_for_#{name} || '') + capture_block(&block)"
+ def with_output_buffer(buf = '')
+ self.output_buffer, old_buffer = buf, output_buffer
+ yield
+ output_buffer
+ ensure
+ self.output_buffer = old_buffer
end
end
end
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('</form>', proc.binding)
+ concat('</form>')
end
def apply_form_for_options!(object_or_array, options) #:nodoc:
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
)
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
# # => <fieldset><legend>Your details</legend><p><input id="name" name="name" type="text" /></p></fieldset>
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("</fieldset>", block.binding)
+ concat(tag(:fieldset, {}, true))
+ concat(content_tag(:legend, legend)) unless legend.blank?
+ concat(content)
+ concat("</fieldset>")
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("</form>", block.binding)
+ concat(form_tag_html(html_options))
+ concat(content)
+ concat("</form>")
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 1ea3cbd74e..7404a251e4 100644
--- a/actionpack/lib/action_view/helpers/javascript_helper.rb
+++ b/actionpack/lib/action_view/helpers/javascript_helper.rb
@@ -172,20 +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
- 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
+ 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:
@@ -205,11 +202,6 @@ module ActionView
end
js_option
end
-
- private
- def block_is_within_action_view?(block)
- eval("defined? _erbout", block.binding)
- end
end
JavascriptHelper = JavaScriptHelper unless const_defined? :JavascriptHelper
diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb
index 5a1012954e..a7c3b9ddc3 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('</form>', proc.binding)
+ concat('</form>')
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 999cbfb52a..e1abec1847 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 &amp; shut.png" }, false, false)
# # => <img src="open &amp; shut.png" />
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
@@ -66,12 +68,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
@@ -114,7 +113,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
@@ -124,10 +122,6 @@ module ActionView
" #{attrs.sort * ' '}" unless attrs.empty?
end
end
-
- def block_is_within_action_view?(block)
- eval("defined? _erbout", block.binding)
- 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 669a285424..a1a91f6b3d 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -15,18 +15,26 @@ 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)
- eval(ActionView::Base.erb_variable, binding) << 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
+ string
+ end
end
if RUBY_VERSION < '1.9'
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/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb
index 369526188f..500ff713bb 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template.rb
@@ -1,5 +1,6 @@
module ActionView #:nodoc:
class Template #:nodoc:
+ extend TemplateHandlers
attr_accessor :locals
attr_reader :handler, :path, :extension, :filename, :path_without_extension, :method
@@ -13,7 +14,7 @@ module ActionView #:nodoc:
@view.first_render ||= @path
@source = nil # Don't read the source until we know that it is required
set_extension_and_file_name(use_full_path)
-
+
@locals = locals || {}
@handler = self.class.handler_class_for_extension(@extension).new(@view)
end
@@ -29,7 +30,7 @@ module ActionView #:nodoc:
raise TemplateError.new(self, @view.assigns, e)
end
end
-
+
def render
prepare!
@handler.render(self)
@@ -46,11 +47,11 @@ module ActionView #:nodoc:
def base_path_for_exception
@finder.find_base_path_for("#{@path_without_extension}.#{@extension}") || @finder.view_paths.first
end
-
+
def prepare!
@view.send :evaluate_assigns
@view.current_render_extension = @extension
-
+
if @handler.compilable?
@handler.compile_template(self) # compile the given template, if necessary
@method = @view.method_names[method_key] # Set the method name for this template and run it
@@ -58,70 +59,30 @@ module ActionView #:nodoc:
end
private
-
- def set_extension_and_file_name(use_full_path)
- @path_without_extension, @extension = @finder.path_and_extension(@path)
- if use_full_path
- if @extension
- @filename = @finder.pick_template(@path_without_extension, @extension)
+ def set_extension_and_file_name(use_full_path)
+ @path_without_extension, @extension = @finder.path_and_extension(@path)
+ if use_full_path
+ if @extension
+ @filename = @finder.pick_template(@path_without_extension, @extension)
+ else
+ @extension = @finder.pick_template_extension(@path).to_s
+ raise_missing_template_exception unless @extension
+
+ @filename = @finder.pick_template(@path, @extension)
+ @extension = @extension.gsub(/^.+\./, '') # strip off any formats
+ end
else
- @extension = @finder.pick_template_extension(@path).to_s
- raise_missing_template_exception unless @extension
-
- @filename = @finder.pick_template(@path, @extension)
- @extension = @extension.gsub(/^.+\./, '') # strip off any formats
+ @filename = @path
end
- else
- @filename = @path
- end
-
- raise_missing_template_exception if @filename.blank?
- end
-
- def raise_missing_template_exception
- full_template_path = @path.include?('.') ? @path : "#{@path}.#{@view.template_format}.erb"
- display_paths = @finder.view_paths.join(':')
- template_type = (@path =~ /layouts/i) ? 'layout' : 'template'
- raise(MissingTemplate, "Missing #{template_type} #{full_template_path} in view path #{display_paths}")
- end
- # Template Handlers
-
- @@template_handlers = HashWithIndifferentAccess.new
- @@default_template_handlers = nil
-
- # Register a class that knows how to handle template files with the given
- # extension. This can be used to implement new template types.
- # The constructor for the class must take the ActiveView::Base instance
- # as a parameter, and the class must implement a +render+ method that
- # takes the contents of the template to render as well as the Hash of
- # local assigns available to the template. The +render+ method ought to
- # return the rendered template as a string.
- def self.register_template_handler(extension, klass)
- @@template_handlers[extension.to_sym] = klass
- TemplateFinder.update_extension_cache_for(extension.to_s)
- end
-
- def self.template_handler_extensions
- @@template_handlers.keys.map(&:to_s).sort
- end
-
- def self.register_default_template_handler(extension, klass)
- register_template_handler(extension, klass)
- @@default_template_handlers = klass
- end
-
- def self.handler_class_for_extension(extension)
- (extension && @@template_handlers[extension.to_sym]) || @@default_template_handlers
- end
-
- register_default_template_handler :erb, TemplateHandlers::ERB
- register_template_handler :rjs, TemplateHandlers::RJS
- register_template_handler :builder, TemplateHandlers::Builder
+ raise_missing_template_exception if @filename.blank?
+ end
- # TODO: Depreciate old template extensions
- register_template_handler :rhtml, TemplateHandlers::ERB
- register_template_handler :rxml, TemplateHandlers::Builder
-
+ def raise_missing_template_exception
+ full_template_path = @path.include?('.') ? @path : "#{@path}.#{@view.template_format}.erb"
+ display_paths = @finder.view_paths.join(':')
+ template_type = (@path =~ /layouts/i) ? 'layout' : 'template'
+ raise(MissingTemplate, "Missing #{template_type} #{full_template_path} in view path #{display_paths}")
+ end
end
end
diff --git a/actionpack/lib/action_view/template_finder.rb b/actionpack/lib/action_view/template_finder.rb
index 83b7e27c09..7e9a310810 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] = []}
@@ -18,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|
@@ -35,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
@@ -44,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
@@ -76,7 +53,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)
@@ -166,12 +143,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
diff --git a/actionpack/lib/action_view/template_handler.rb b/actionpack/lib/action_view/template_handler.rb
index ec407e3fb3..39e578e586 100644
--- a/actionpack/lib/action_view/template_handler.rb
+++ b/actionpack/lib/action_view/template_handler.rb
@@ -1,6 +1,5 @@
module ActionView
class TemplateHandler
-
def self.line_offset
0
end
diff --git a/actionpack/lib/action_view/template_handlers.rb b/actionpack/lib/action_view/template_handlers.rb
new file mode 100644
index 0000000000..1471e99e01
--- /dev/null
+++ b/actionpack/lib/action_view/template_handlers.rb
@@ -0,0 +1,46 @@
+require 'action_view/template_handler'
+require 'action_view/template_handlers/compilable'
+require 'action_view/template_handlers/builder'
+require 'action_view/template_handlers/erb'
+require 'action_view/template_handlers/rjs'
+
+module ActionView #:nodoc:
+ module TemplateHandlers #:nodoc:
+ def self.extended(base)
+ base.register_default_template_handler :erb, TemplateHandlers::ERB
+ base.register_template_handler :rjs, TemplateHandlers::RJS
+ base.register_template_handler :builder, TemplateHandlers::Builder
+
+ # TODO: Depreciate old template extensions
+ base.register_template_handler :rhtml, TemplateHandlers::ERB
+ base.register_template_handler :rxml, TemplateHandlers::Builder
+ end
+
+ @@template_handlers = {}
+ @@default_template_handlers = nil
+
+ # Register a class that knows how to handle template files with the given
+ # extension. This can be used to implement new template types.
+ # The constructor for the class must take the ActiveView::Base instance
+ # as a parameter, and the class must implement a +render+ method that
+ # takes the contents of the template to render as well as the Hash of
+ # local assigns available to the template. The +render+ method ought to
+ # return the rendered template as a string.
+ def register_template_handler(extension, klass)
+ @@template_handlers[extension.to_sym] = klass
+ end
+
+ def template_handler_extensions
+ @@template_handlers.keys.map(&:to_s).sort
+ end
+
+ def register_default_template_handler(extension, klass)
+ register_template_handler(extension, klass)
+ @@default_template_handlers = klass
+ end
+
+ def handler_class_for_extension(extension)
+ (extension && @@template_handlers[extension.to_sym]) || @@default_template_handlers
+ end
+ end
+end
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/compilable.rb b/actionpack/lib/action_view/template_handlers/compilable.rb
index 25bd0fea7f..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)\n#{locals_code}#{body}\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
@@ -125,4 +125,4 @@ module ActionView
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_view/template_handlers/erb.rb b/actionpack/lib/action_view/template_handlers/erb.rb
index 15a9064461..ad4ccc7c42 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.response.template.output_buffer ||= '' }
end
end
end
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/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index c6d61bb504..89e12ddae3 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
@@ -188,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
@@ -213,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
@@ -326,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
@@ -370,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
@@ -436,6 +480,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
@@ -525,7 +571,7 @@ class FragmentCachingTest < Test::Unit::TestCase
def test_cache_erb_fragment
@store.write('views/expensive', 'fragment content')
- _erbout = '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'))
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,16 +11,8 @@ 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
+ def content_for_concatenated
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/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!"
+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\nHello, World!", @output.string
- end
+ def test_simple_output
+ @response.body = "Hello, World!"
- 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\nHello, World!", @output.string
+ end
- @response.out(@output)
- assert_equal "HTTP/1.0 200 OK\nContent-Type: text/html\n", @output.string
- end
+ def test_head_request
+ @fake_cgi.env_table['REQUEST_METHOD'] = 'HEAD'
+ @response.body = "Hello, World!"
- def test_streaming_block
- @response.body = Proc.new do |response, output|
- 5.times { |n| output.write(n) }
+ @response.out(@output)
+ assert_equal "HTTP/1.0 200 OK\nContent-Type: text/html\n", @output.string
end
- @response.out(@output)
- assert_equal "HTTP/1.0 200 OK\nContent-Type: text/html\n01234", @output.string
+ 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/new_render_test.rb b/actionpack/test/controller/new_render_test.rb
index 6e2c6d90c6..b77b3ceffa 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')
@@ -215,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"
@@ -246,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
@@ -531,6 +540,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 }
@@ -549,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 "<html>\n <p>Hello David</p>\n<p>This is grand!</p>\n</html>\n", @response.body
@@ -742,7 +761,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 +781,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
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,866 +626,1699 @@ class RouteBuilderTest < Test::Unit::TestCase
assert_equal expected, found, "Route #{i + 1} has #{found} segments, expected #{expected}"
end
end
-
end
+class RoutingTest < Test::Unit::TestCase
+ def test_possible_controllers
+ true_controller_paths = ActionController::Routing.controller_paths
+ ActionController::Routing.use_controllers! nil
+ silence_warnings do
+ Object.send(:const_set, :RAILS_ROOT, File.dirname(__FILE__) + '/controller_fixtures')
+ end
-class RouteSetTest < Test::Unit::TestCase
+ ActionController::Routing.controller_paths = [
+ RAILS_ROOT, RAILS_ROOT + '/app/controllers', RAILS_ROOT + '/vendor/plugins/bad_plugin/lib'
+ ]
- def set
- @set ||= ROUTING::RouteSet.new
+ assert_equal ["admin/user", "plugin", "user"], ActionController::Routing.possible_controllers.sort
+ ensure
+ if true_controller_paths
+ ActionController::Routing.controller_paths = true_controller_paths
+ end
+ ActionController::Routing.use_controllers! nil
+ Object.send(:remove_const, :RAILS_ROOT) rescue nil
end
- def request
- @request ||= MockRequest.new(:host => "named.routes.test", :method => :get)
+ 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_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
+ def test_with_controllers
+ c = %w(admin/accounts admin/users account pages)
+ ActionController::Routing.with_controllers c do
+ assert_equal c, ActionController::Routing.possible_controllers
+ end
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
+ def test_normalize_unix_paths
+ load_paths = %w(. config/../app/controllers config/../app//helpers script/../config/../vendor/rails/actionpack/lib vendor/rails/railties/builtin/rails_info app/models lib script/../config/../foo/bar/../../app/models .foo/../.bar foo.bar/../config)
+ 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_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
+
+ def test_normalize_windows_paths
+ load_paths = %w(. config\\..\\app\\controllers config\\..\\app\\\\helpers script\\..\\config\\..\\vendor\\rails\\actionpack\\lib vendor\\rails\\railties\\builtin\\rails_info app\\models lib script\\..\\config\\..\\foo\\bar\\..\\..\\app\\models .foo\\..\\.bar foo.bar\\..\\config)
+ 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_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")
+
+ 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
-
- def test_extra_keys_not_first
- set.draw do |map|
- map.connect ':controller/:action/:id.:format'
- map.connect ':controller/:action/:id'
+end
+
+uses_mocha 'LegacyRouteSet, Route, RouteSet and RouteLoading' do
+ class MockController
+ attr_accessor :routes
+
+ def initialize(routes)
+ self.routes = routes
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'
+ 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
- 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'
+
+ def request
+ @request ||= MockRequest.new(:host => "named.route.test", :method => :get)
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'
+
+ def relative_url_root=(value)
+ request.relative_url_root=value
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'
+ 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
- klass = Class.new(MockController)
- set.install_helpers(klass)
- klass.new(set)
+ def host_with_port
+ (subdomains * '.') + '.' + domain
+ end
end
- def test_named_route_hash_access_method
- controller = setup_named_route_test
+ class LegacyRouteSetTests < Test::Unit::TestCase
+ attr_reader :rs
- assert_equal(
- { :controller => 'people', :action => 'show', :id => 5, :use_route => :show, :only_path => false },
- controller.send(:hash_for_show_url, :id => 5))
+ def setup
+ # These tests assume optimisation is on, so re-enable it.
+ ActionController::Base.optimise_named_routes = true
- 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
+ @rs = ::ActionController::Routing::RouteSet.new
+ @rs.draw {|m| m.connect ':controller/:action/:id' }
- 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)
+ ActionController::Routing.use_controllers! %w(content admin/user admin/news_feed)
+ end
- 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_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"))
- def test_named_route_url_method_with_anchor
- controller = setup_named_route_test
+ assert_equal({:controller => "admin/user", :action => 'show', :id => '10'}, rs.recognize_path("/admin/user/show/10"))
- 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 '/admin/user/show/10', rs.generate(:controller => 'admin/user', :action => 'show', :id => 10)
- 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 '/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 "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 '/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
- assert_equal "http://named.route.test/people/go/7/hello/joe/5#location",
- controller.send(:multi_url, 7, "hello", 5, :anchor => 'location')
+ def test_ignores_leading_slash
+ @rs.draw {|m| m.connect '/:controller/:action/:id'}
+ test_default_setup
+ end
- 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')
+ 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
- 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
-
+ 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
- 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
+ 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_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'
+ 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
- assert_equal 1, set.routes.size
- route = set.routes.first
+ 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
- assert route.segments.last.optional?
+ 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
- assert_equal '/users/show/10', set.generate(:controller => 'users', :action => 'show', :id => 10)
- assert_equal '/users/index/10', set.generate(:controller => 'users', :id => 10)
+ 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
- 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/'))
+ 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
- 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('/'))
+ 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
- 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'
+ 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
- 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'))
+ 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
- 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'))
+ def test_changing_controller
+ assert_equal '/admin/stuff/show/10', rs.generate(
+ {:controller => 'stuff', :action => 'show', :id => 10},
+ {:controller => 'admin/user', :action => 'index'}
+ )
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+/
+ 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
- assert_raises ArgumentError do
- set.draw do |map|
- map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\A\d+/
+
+ 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
- assert_raises ArgumentError do
- set.draw do |map|
- map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+$/
+
+ 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
- assert_raises ArgumentError do
- set.draw do |map|
- map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+\Z/
+
+ 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
- assert_raises ArgumentError do
- set.draw do |map|
- map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+\z/
+
+ 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
- assert_nothing_raised do
- set.draw do |map|
- map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+/, :name => /^(david|jamis)/
+
+ 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
- set.generate :controller => 'pages', :action => 'show', :id => 10
+ rs.generate(:controller => 'post', :action => 'show')
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)/
+ 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
- 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')
+
+ 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
- assert_raises ActionController::RoutingError do
- set.generate(:controller => 'pages', :action => 'show', :name => 'nor_jamis_and_david')
+
+ 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
- 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\+]+/
+
+ 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
- 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_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_recognize_with_conditions
- Object.const_set(:PeopleController, Class.new)
+ def test_named_route_method
+ rs.draw do |map|
+ map.categories 'categories', :controller => 'content', :action => 'categories'
+ map.connect ':controller/:action/:id'
+ end
- 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 }
+ 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
- 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])
+ def setup_request_method_routes_for(method)
+ @request = ActionController::TestRequest.new
+ @request.env["REQUEST_METHOD"] = method
+ @request.request_uri = "/match"
- 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
+ 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
- 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])
+ %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)
- request.method = :put
- assert_nothing_raised { set.recognize(request) }
- assert_equal("update", request.path_parameters[:action])
- assert_equal("5", request.path_parameters[:id])
+ 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
- request.method = :delete
- assert_nothing_raised { set.recognize(request) }
- assert_equal("destroy", request.path_parameters[:action])
- assert_equal("5", request.path_parameters[:id])
+ def test_subpath_recognized
+ Object.const_set(:SubpathBooksController, Class.new(ActionController::Base))
- begin
- request.method = :post
- set.recognize(request)
- flunk 'Should have raised MethodNotAllowed'
- rescue ActionController::MethodNotAllowed => e
- assert_equal [:get, :put, :delete], e.allowed_methods
+ 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
- ensure
- Object.send(:remove_const, :PeopleController)
- end
-
- def test_recognize_with_alias_in_conditions
- Object.const_set(:PeopleController, Class.new)
+ 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
- set.draw do |map|
- map.people "/people", :controller => 'people', :action => "index",
- :conditions => { :method => :get }
- map.root :people
+ 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
- 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])
+ 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
- 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)
+ x = setup_for_named_route
+ assert_raises(ActionController::RoutingError) do
+ x.send(:foo_with_requirement_url, "I am Against the requirements")
+ end
+ end
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'
+ class RouteTest < Test::Unit::TestCase
+ def setup
+ @route = ROUTING::Route.new
end
- request.path = '/profile'
+ def slash_segment(is_optional = false)
+ returning ROUTING::DividerSegment.new('/') do |s|
+ s.is_optional = is_optional
+ end
+ end
- set.recognize(request) rescue nil
-
- assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"
- 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
- def test_recognize_with_conditions_and_format
- Object.const_set(:PeopleController, Class.new)
+ @default_route.segments << slash_segment(:optional)
+ @default_route.segments << (s = ROUTING::DynamicSegment.new)
+ s.key = :id
+ s.is_optional = true
- 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 }
+ @default_route.segments << slash_segment(:optional)
end
+ @default_route
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])
+ 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/')
- request.method = :put
- assert_nothing_raised { set.recognize(request) }
- assert_equal("update", request.path_parameters[:action])
+ expected[:id] = 'jamis'
+ assert_equal expected, default_route.recognize('/accounts/show/jamis/')
- 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
+ expected.delete :id
+ assert_equal expected, default_route.recognize('/accounts/show')
+ assert_equal expected, default_route.recognize('/accounts/show/')
- def test_generate_with_default_action
- set.draw do |map|
- map.connect "/people", :controller => "people"
- map.connect "/people/list", :controller => "people", :action => "list"
+ 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
- url = set.generate(:controller => "people", :action => "list")
- assert_equal "/people/list", url
- end
-
- def test_root_map
- Object.const_set(:PeopleController, Class.new)
+ def test_default_route_should_omit_default_action
+ o = {:controller => 'accounts', :action => 'index'}
+ assert_equal '/accounts', default_route.generate(o, o, {})
+ end
- set.draw { |map| map.root :controller => "people" }
+ 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
- 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) })
+ 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
- set.draw do |map|
-
- map.namespace 'api' do |api|
- api.route 'inventory', :controller => "products", :action => 'inventory'
+ 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
- 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)
+ 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
-
- def test_namespaced_root_map
- Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) })
+ 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
- set.draw do |map|
-
- map.namespace 'api' do |api|
- api.root :controller => "products"
+ 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
- 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_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_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
+ 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
- url = set.generate(:controller => "people", :action => "index", :ws => true)
- assert_equal "/ws/people", url
- 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_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_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_id_is_not_impossibly_sticky
- set.draw do |map|
- map.connect 'foo/:number', :controller => "people", :action => "index"
- map.connect ':controller/:action/:id'
+ 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
- url = set.generate({:controller => "people", :action => "index", :number => 3},
- {:controller => "people", :action => "index", :id => "21"})
- assert_equal "/foo/3", url
- 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
- def test_id_is_sticky_when_it_ought_to_be
- set.draw do |map|
- map.connect ':controller/:id/:action'
+ klass = Class.new(MockController)
+ set.install_helpers(klass)
+ klass.new(set)
end
- url = set.generate({:action => "destroy"}, {:controller => "people", :action => "show", :id => "7"})
- assert_equal "/people/7/destroy", url
- 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))
- def test_use_static_path_when_possible
- set.draw do |map|
- map.connect 'about', :controller => "welcome", :action => "about"
- map.connect ':controller/:action/:id'
+ assert_equal(
+ { :controller => 'people', :action => 'show', :id => 5, :use_route => :show, :only_path => true },
+ controller.send(:hash_for_show_path, :id => 5)
+ )
end
- url = set.generate({:controller => "welcome", :action => "about"},
- {:controller => "welcome", :action => "get", :id => "7"})
- assert_equal "/about", url
- end
+ def test_named_route_url_method
+ controller = setup_named_route_test
- def test_generate
- set.draw { |map| map.connect ':controller/:action/:id' }
+ assert_equal "http://named.route.test/people/5", controller.send(:show_url, :id => 5)
+ assert_equal "/people/5", controller.send(:show_path, :id => 5)
- 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
+ assert_equal "http://named.route.test/people", controller.send(:index_url)
+ assert_equal "/people", controller.send(:index_path)
- 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"
+ 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
- url = set.generate({:controller => "connection"}, {:controller => 'connection/manage'})
- assert_equal "/connection/connection", url
+ def test_named_route_url_method_with_anchor
+ controller = setup_named_route_test
- 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'
+ 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
- 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'
+
+ 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
- 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_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_generate_all
- set.draw do |map|
- map.connect 'show_post/:id', :controller => 'post', :action => 'show'
- map.connect ':controller/:action/:id'
+ 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
- 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
+
+ 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.namespace :admin do |admin|
- admin.root :controller => 'home'
+ 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
- end
-
- def test_setting_root_in_namespace_using_string
- assert_nothing_raised do
+
+ 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.namespace 'admin' do |admin|
- admin.root :controller => 'home'
+ 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
- end
- def test_route_requirements_with_unsupported_regexp_options_must_error
- assert_raises ArgumentError do
+ def test_generate_with_default_action
set.draw do |map|
- map.connect 'page/:name', :controller => 'pages',
- :action => 'show',
- :requirements => {:name => /(david|jamis)/m}
+ 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
- end
- def test_route_requirements_with_supported_options_must_not_error
- assert_nothing_raised do
+ 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.connect 'page/:name', :controller => 'pages',
- :action => 'show',
- :requirements => {:name => /(david|jamis)/i}
+
+ 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
- assert_nothing_raised do
+
+ def test_namespaced_root_map
+ Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) })
+
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}
+
+ 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
- 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}
+ 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
- assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis'))
- assert_raises ActionController::RoutingError do
- set.recognize_path('/page/davidjamis')
+
+ 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
- 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}
+ 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
- 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'})
+
+ 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
- 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}
+ 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
- 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')
+
+ 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
- assert_raises ActionController::RoutingError do
- set.recognize_path('/page/David')
+
+ 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
- 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}
+ 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
- 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'})
+
+ 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
- assert_raises ActionController::RoutingError do
- url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
+
+ 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
- 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}
+ 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
- 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}
+ 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
- assert_equal({:controller => 'pages', :action => 'show', :name => 'JAMIS'}, set.recognize_path('/page/JAMIS'))
- end
-
-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
-class RoutingTest < Test::Unit::TestCase
-
- def test_possible_controllers
- true_controller_paths = ActionController::Routing.controller_paths
+ 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
- ActionController::Routing.use_controllers! nil
+ 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
- silence_warnings do
- Object.send(:const_set, :RAILS_ROOT, File.dirname(__FILE__) + '/controller_fixtures')
+ 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
- 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
- ActionController::Routing.controller_paths = true_controller_paths
+ 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
- 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
- assert_equal c, ActionController::Routing.possible_controllers
+
+ 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
- end
- def test_normalize_unix_paths
- load_paths = %w(. config/../app/controllers config/../app//helpers script/../config/../vendor/rails/actionpack/lib vendor/rails/railties/builtin/rails_info app/models lib script/../config/../foo/bar/../../app/models .foo/../.bar foo.bar/../config)
- 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_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_normalize_windows_paths
- load_paths = %w(. config\\..\\app\\controllers config\\..\\app\\\\helpers script\\..\\config\\..\\vendor\\rails\\actionpack\\lib vendor\\rails\\railties\\builtin\\rails_info app\\models lib script\\..\\config\\..\\foo\\bar\\..\\..\\app\\models .foo\\..\\.bar foo.bar\\..\\config)
- 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
+ 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
-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
-uses_mocha 'route loading' do
- class RouteLoadingTest < Test::Unit::TestCase
+ 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
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/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
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
diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb
index 0a7b19ba96..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)
- _erbout = ''
-
fields_for :post, @post do |f|
- _erbout.concat f.date_select(:written_on)
+ concat f.date_select(:written_on)
end
expected = "<select id='post_written_on_1i' name='post[written_on(1i)]'>\n<option value='1999'>1999</option>\n<option value='2000'>2000</option>\n<option value='2001'>2001</option>\n<option value='2002'>2002</option>\n<option value='2003'>2003</option>\n<option selected='selected' value='2004'>2004</option>\n<option value='2005'>2005</option>\n<option value='2006'>2006</option>\n<option value='2007'>2007</option>\n<option value='2008'>2008</option>\n<option value='2009'>2009</option>\n</select>\n"
expected << "<select id='post_written_on_2i' name='post[written_on(2i)]'>\n<option value='1'>January</option>\n<option value='2'>February</option>\n<option value='3'>March</option>\n<option value='4'>April</option>\n<option value='5'>May</option>\n<option selected='selected' value='6'>June</option>\n<option value='7'>July</option>\n<option value='8'>August</option>\n<option value='9'>September</option>\n<option value='10'>October</option>\n<option value='11'>November</option>\n<option value='12'>December</option>\n</select>\n"
expected << "<select id='post_written_on_3i' name='post[written_on(3i)]'>\n<option value='1'>1</option>\n<option value='2'>2</option>\n<option value='3'>3</option>\n<option value='4'>4</option>\n<option value='5'>5</option>\n<option value='6'>6</option>\n<option value='7'>7</option>\n<option value='8'>8</option>\n<option value='9'>9</option>\n<option value='10'>10</option>\n<option value='11'>11</option>\n<option value='12'>12</option>\n<option value='13'>13</option>\n<option value='14'>14</option>\n<option selected='selected' value='15'>15</option>\n<option value='16'>16</option>\n<option value='17'>17</option>\n<option value='18'>18</option>\n<option value='19'>19</option>\n<option value='20'>20</option>\n<option value='21'>21</option>\n<option value='22'>22</option>\n<option value='23'>23</option>\n<option value='24'>24</option>\n<option value='25'>25</option>\n<option value='26'>26</option>\n<option value='27'>27</option>\n<option value='28'>28</option>\n<option value='29'>29</option>\n<option value='30'>30</option>\n<option value='31'>31</option>\n</select>\n"
- assert_dom_equal(expected, _erbout)
+ 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)
- _erbout = ''
-
fields_for :post, @post do |f|
- _erbout.concat f.datetime_select(:updated_at)
+ concat f.datetime_select(:updated_at)
end
expected = "<select id='post_updated_at_1i' name='post[updated_at(1i)]'>\n<option value='1999'>1999</option>\n<option value='2000'>2000</option>\n<option value='2001'>2001</option>\n<option value='2002'>2002</option>\n<option value='2003'>2003</option>\n<option selected='selected' value='2004'>2004</option>\n<option value='2005'>2005</option>\n<option value='2006'>2006</option>\n<option value='2007'>2007</option>\n<option value='2008'>2008</option>\n<option value='2009'>2009</option>\n</select>\n"
@@ -1299,7 +1295,7 @@ class DateHelperTest < ActionView::TestCase
expected << " &mdash; <select id='post_updated_at_4i' name='post[updated_at(4i)]'>\n<option value='00'>00</option>\n<option value='01'>01</option>\n<option value='02'>02</option>\n<option value='03'>03</option>\n<option value='04'>04</option>\n<option value='05'>05</option>\n<option value='06'>06</option>\n<option value='07'>07</option>\n<option value='08'>08</option>\n<option value='09'>09</option>\n<option value='10'>10</option>\n<option value='11'>11</option>\n<option value='12'>12</option>\n<option value='13'>13</option>\n<option value='14'>14</option>\n<option value='15'>15</option>\n<option selected='selected' value='16'>16</option>\n<option value='17'>17</option>\n<option value='18'>18</option>\n<option value='19'>19</option>\n<option value='20'>20</option>\n<option value='21'>21</option>\n<option value='22'>22</option>\n<option value='23'>23</option>\n</select>\n"
expected << " : <select id='post_updated_at_5i' name='post[updated_at(5i)]'>\n<option value='00'>00</option>\n<option value='01'>01</option>\n<option value='02'>02</option>\n<option value='03'>03</option>\n<option value='04'>04</option>\n<option value='05'>05</option>\n<option value='06'>06</option>\n<option value='07'>07</option>\n<option value='08'>08</option>\n<option value='09'>09</option>\n<option value='10'>10</option>\n<option value='11'>11</option>\n<option value='12'>12</option>\n<option value='13'>13</option>\n<option value='14'>14</option>\n<option value='15'>15</option>\n<option value='16'>16</option>\n<option value='17'>17</option>\n<option value='18'>18</option>\n<option value='19'>19</option>\n<option value='20'>20</option>\n<option value='21'>21</option>\n<option value='22'>22</option>\n<option value='23'>23</option>\n<option value='24'>24</option>\n<option value='25'>25</option>\n<option value='26'>26</option>\n<option value='27'>27</option>\n<option value='28'>28</option>\n<option value='29'>29</option>\n<option value='30'>30</option>\n<option value='31'>31</option>\n<option value='32'>32</option>\n<option value='33'>33</option>\n<option value='34'>34</option>\n<option selected='selected' value='35'>35</option>\n<option value='36'>36</option>\n<option value='37'>37</option>\n<option value='38'>38</option>\n<option value='39'>39</option>\n<option value='40'>40</option>\n<option value='41'>41</option>\n<option value='42'>42</option>\n<option value='43'>43</option>\n<option value='44'>44</option>\n<option value='45'>45</option>\n<option value='46'>46</option>\n<option value='47'>47</option>\n<option value='48'>48</option>\n<option value='49'>49</option>\n<option value='50'>50</option>\n<option value='51'>51</option>\n<option value='52'>52</option>\n<option value='53'>53</option>\n<option value='54'>54</option>\n<option value='55'>55</option>\n<option value='56'>56</option>\n<option value='57'>57</option>\n<option value='58'>58</option>\n<option value='59'>59</option>\n</select>\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..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
- _erbout = ''
-
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')
+ 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
"<input name='commit' id='post_submit' type='submit' value='Create post' />" +
"</form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_form_for_with_method
- _erbout = ''
-
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)
+ 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
"<input name='post[secret]' type='hidden' value='0' />" +
"</form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_form_for_without_object
- _erbout = ''
-
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)
+ 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
"<input name='post[secret]' type='hidden' value='0' />" +
"</form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_form_for_with_index
- _erbout = ''
-
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)
+ 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
"<input name='post[123][secret]' type='hidden' value='0' />" +
"</form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_form_for_with_nil_index_option_override
- _erbout = ''
-
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)
+ 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
"<input name='post[][secret]' type='hidden' value='0' />" +
"</form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_nested_fields_for
- _erbout = ''
form_for(:post, @post) do |f|
f.fields_for(:comment, @post) do |c|
- _erbout.concat c.text_field(:title)
+ concat c.text_field(:title)
end
end
@@ -455,16 +444,14 @@ class FormHelperTest < ActionView::TestCase
"<input name='post[comment][title]' size='30' type='text' id='post_comment_title' value='Hello World' />" +
"</form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_fields_for
- _erbout = ''
-
fields_for(:post, @post) do |f|
- _erbout.concat f.text_field(:title)
- _erbout.concat f.text_area(:body)
- _erbout.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
"<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" +
"<input name='post[secret]' type='hidden' value='0' />"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_fields_for_with_index
- _erbout = ''
-
fields_for("post[]", @post) do |f|
- _erbout.concat f.text_field(:title)
- _erbout.concat f.text_area(:body)
- _erbout.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
"<input name='post[123][secret]' checked='checked' type='checkbox' id='post_123_secret' value='1' />" +
"<input name='post[123][secret]' type='hidden' value='0' />"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_fields_for_with_nil_index_option_override
- _erbout = ''
-
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)
+ 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
"<input name='post[][secret]' checked='checked' type='checkbox' id='post__secret' value='1' />" +
"<input name='post[][secret]' type='hidden' value='0' />"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_fields_for_with_index_option_override
- _erbout = ''
-
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)
+ 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
"<input name='post[abc][secret]' checked='checked' type='checkbox' id='post_abc_secret' value='1' />" +
"<input name='post[abc][secret]' type='hidden' value='0' />"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_fields_for_without_object
- _erbout = ''
fields_for(:post) do |f|
- _erbout.concat f.text_field(:title)
- _erbout.concat f.text_area(:body)
- _erbout.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
"<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" +
"<input name='post[secret]' type='hidden' value='0' />"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_fields_for_with_only_object
- _erbout = ''
fields_for(@post) do |f|
- _erbout.concat f.text_field(:title)
- _erbout.concat f.text_area(:body)
- _erbout.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
"<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" +
"<input name='post[secret]' type='hidden' value='0' />"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_fields_for_object_with_bracketed_name
- _erbout = ''
fields_for("author[post]", @post) do |f|
- _erbout.concat f.label(:title)
- _erbout.concat f.text_field(:title)
+ concat f.label(:title)
+ concat f.text_field(:title)
end
assert_dom_equal "<label for=\"author_post_title\">Title</label>" +
"<input name='author[post][title]' size='30' type='text' id='author_post_title' value='Hello World' />",
- _erbout
+ output_buffer
end
def test_fields_for_object_with_bracketed_name_and_index
- _erbout = ''
fields_for("author[post]", @post, :index => 1) do |f|
- _erbout.concat f.label(:title)
- _erbout.concat f.text_field(:title)
+ concat f.label(:title)
+ concat f.text_field(:title)
end
assert_dom_equal "<label for=\"author_post_1_title\">Title</label>" +
"<input name='author[post][1][title]' size='30' type='text' id='author_post_1_title' value='Hello World' />",
- _erbout
+ 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
- _erbout = ''
-
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)
+ concat post_form.text_field(:title)
+ concat post_form.text_area(:body)
fields_for(:parent_post, @post) do |parent_fields|
- _erbout.concat parent_fields.check_box(:secret)
+ concat parent_fields.check_box(:secret)
end
end
@@ -612,18 +587,16 @@ class FormHelperTest < ActionView::TestCase
"<input name='parent_post[secret]' type='hidden' value='0' />" +
"</form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_form_for_and_fields_for_with_object
- _erbout = ''
-
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)
+ concat post_form.text_field(:title)
+ concat post_form.text_area(:body)
post_form.fields_for(@comment) do |comment_fields|
- _erbout.concat comment_fields.text_field(:name)
+ concat comment_fields.text_field(:name)
end
end
@@ -634,7 +607,7 @@ class FormHelperTest < ActionView::TestCase
"<input name='post[comment][name]' type='text' id='post_comment_name' value='new comment' size='30' />" +
"</form>"
- assert_dom_equal expected, _erbout
+ 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
- _erbout = ''
-
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)
+ 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
"<input name='post[secret]' type='hidden' value='0' /><br/>" +
"</form>"
- 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 = ''
form_for(:post, @post) do |f|
- _erbout.concat f.text_field(:title)
- _erbout.concat f.text_area(:body)
- _erbout.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
"<input name='post[secret]' type='hidden' value='0' /><br/>" +
"</form>"
- 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 = ''
form_for(:post, @post) do |f|
- _erbout.concat f.error_message_on('author_name')
- _erbout.concat f.error_messages
+ concat f.error_message_on('author_name')
+ concat f.error_messages
end
expected = %(<form action='http://www.example.com' method='post'>) +
@@ -705,7 +673,7 @@ class FormHelperTest < ActionView::TestCase
%(<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>) +
%(</form>)
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
@@ -713,10 +681,9 @@ class FormHelperTest < ActionView::TestCase
post = @post
@post = nil
- _erbout = ''
form_for(:post, post) do |f|
- _erbout.concat f.error_message_on('author_name')
- _erbout.concat f.error_messages
+ concat f.error_message_on('author_name')
+ concat f.error_messages
end
expected = %(<form action='http://www.example.com' method='post'>) +
@@ -724,19 +691,18 @@ class FormHelperTest < ActionView::TestCase
%(<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>) +
%(</form>)
- 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 = ''
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)
+ 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
"<input name='post[secret]' type='hidden' value='0' /><br/>" +
"</form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_fields_for_with_labelled_builder
- _erbout = ''
-
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)
+ 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
"<label for='secret'>Secret:</label> <input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" +
"<input name='post[secret]' type='hidden' value='0' /><br/>"
- 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 = ''
-
form_for(:post, @post, :html => {:id => 'some_form', :class => 'some_class'}) do |f| end
expected = "<form action=\"http://www.example.com\" class=\"some_class\" id=\"some_form\" method=\"post\"></form>"
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_form_for_with_string_url_option
- _erbout = ''
-
form_for(:post, @post, :url => 'http://www.otherdomain.com') do |f| end
- assert_equal '<form action="http://www.otherdomain.com" method="post"></form>', _erbout
+ assert_equal '<form action="http://www.otherdomain.com" method="post"></form>', output_buffer
end
def test_form_for_with_hash_url_option
- _erbout = ''
-
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
- _erbout = ''
-
form_for(:post, @post, :url => @post) do |f| end
expected = "<form action=\"/posts/123\" method=\"post\"></form>"
- assert_equal expected, _erbout
+ assert_equal expected, output_buffer
end
def test_form_for_with_existing_object
- _erbout = ''
-
form_for(@post) do |f| end
expected = "<form action=\"/posts/123\" class=\"edit_post\" id=\"edit_post_123\" method=\"post\"><div style=\"margin:0;padding:0\"><input name=\"_method\" type=\"hidden\" value=\"put\" /></div></form>"
- assert_equal expected, _erbout
+ assert_equal expected, output_buffer
end
def test_form_for_with_new_object
- _erbout = ''
-
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 = "<form action=\"/posts\" class=\"new_post\" id=\"new_post\" method=\"post\"></form>"
- 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 = ''
+
form_for([@post, @comment]) {}
expected = %(<form action="#{comment_path(@post, @comment)}" class="edit_comment" id="edit_comment_1" method="post"><div style="margin:0;padding:0"><input name="_method" type="hidden" value="put" /></div></form>)
- 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 = ''
+
form_for([@post, @comment]) {}
expected = %(<form action="#{comments_path(@post)}" class="new_comment" id="new_comment" method="post"></form>)
- 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 = ''
+
form_for([:admin, @post, @comment]) {}
expected = %(<form action="#{admin_comment_path(@post, @comment)}" class="edit_comment" id="edit_comment_1" method="post"><div style="margin:0;padding:0"><input name="_method" type="hidden" value="put" /></div></form>)
- 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 = ''
+
form_for([:admin, @post, @comment]) {}
expected = %(<form action="#{admin_comments_path(@post)}" class="new_comment" id="new_comment" method="post"></form>)
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_form_for_with_existing_object_and_custom_url
- _erbout = ''
-
form_for(@post, :url => "/super_posts") do |f| end
expected = "<form action=\"/super_posts\" class=\"edit_post\" id=\"edit_post_123\" method=\"post\"><div style=\"margin:0;padding:0\"><input name=\"_method\" type=\"hidden\" value=\"put\" /></div></form>"
- 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 = ''
remote_form_for(:post, @post, :html => {:id => 'some_form', :class => 'some_class'}) do |f| end
expected = "<form action=\"http://www.example.com\" class=\"some_class\" id=\"some_form\" method=\"post\" onsubmit=\"new Ajax.Request('http://www.example.com', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\"></form>"
- 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..3f89a5e426 100644
--- a/actionpack/test/template/form_options_helper_test.rb
+++ b/actionpack/test/template/form_options_helper_test.rb
@@ -20,8 +20,6 @@ class MockTimeZone
end
end
-ActionView::Helpers::FormOptionsHelper::TimeZone = MockTimeZone
-
class FormOptionsHelperTest < ActionView::TestCase
tests ActionView::Helpers::FormOptionsHelper
@@ -31,6 +29,8 @@ class FormOptionsHelperTest < ActionView::TestCase
Country = Struct.new('Country', :country_id, :country_name)
Firm = Struct.new('Firm', :time_zone)
Album = Struct.new('Album', :id, :title, :genre)
+
+ ActiveSupport::TimeZone = MockTimeZone
end
def test_collection_options
@@ -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 "<option value=\"B\">B</option>\n" +
"<option value=\"E\">E</option>" +
@@ -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 "<option value=\"B\">B</option>\n" +
"<option value=\"E\" selected=\"selected\">E</option>" +
@@ -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 "<option value=\"B\">B</option>\n" +
"<option value=\"E\">E</option>" +
@@ -230,16 +230,14 @@ class FormOptionsHelperTest < ActionView::TestCase
def test_select_under_fields_for
@post = Post.new
@post.category = "<mus>"
-
- _erbout = ''
-
+
fields_for :post, @post do |f|
- _erbout.concat f.select(:category, %w( abe <mus> hest))
+ concat f.select(:category, %w( abe <mus> hest))
end
assert_dom_equal(
"<select id=\"post_category\" name=\"post[category]\"><option value=\"abe\">abe</option>\n<option value=\"&lt;mus&gt;\" selected=\"selected\">&lt;mus&gt;</option>\n<option value=\"hest\">hest</option></select>",
- _erbout
+ output_buffer
)
end
@@ -352,16 +350,14 @@ class FormOptionsHelperTest < ActionView::TestCase
@post = Post.new
@post.author_name = "Babe"
-
- _erbout = ''
-
+
fields_for :post, @post do |f|
- _erbout.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(
"<select id=\"post_author_name\" name=\"post[author_name]\"><option value=\"&lt;Abe&gt;\">&lt;Abe&gt;</option>\n<option value=\"Babe\" selected=\"selected\">Babe</option>\n<option value=\"Cabe\">Cabe</option></select>",
- _erbout
+ output_buffer
)
end
@@ -1194,11 +1190,9 @@ COUNTRIES
def test_time_zone_select_under_fields_for
@firm = Firm.new("D")
-
- _erbout = ''
-
+
fields_for :firm, @firm do |f|
- _erbout.concat f.time_zone_select(:time_zone)
+ concat f.time_zone_select(:time_zone)
end
assert_dom_equal(
@@ -1209,7 +1203,7 @@ COUNTRIES
"<option value=\"D\" selected=\"selected\">D</option>\n" +
"<option value=\"E\">E</option>" +
"</select>",
- _erbout
+ output_buffer
)
end
@@ -1293,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 "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" +
"<option value=\"A\">A</option>\n" +
diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb
index 73a8bd4d87..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
- _erbout = ''
- form_tag("http://example.com") { _erbout.concat "Hello world!" }
+ form_tag("http://example.com") { concat "Hello world!" }
expected = %(<form action="http://example.com" method="post">Hello world!</form>)
- 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!" }
+ form_tag("http://example.com", :method => :put) { concat "Hello world!" }
expected = %(<form action="http://example.com" method="post"><div style='margin:0;padding:0'><input type="hidden" name="_method" value="put" /></div>Hello world!</form>)
- assert_dom_equal expected, _erbout
+ 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
- _erbout = ''
- field_set_tag("Your details") { _erbout.concat "Hello world!" }
+ field_set_tag("Your details") { concat "Hello world!" }
expected = %(<fieldset><legend>Your details</legend>Hello world!</fieldset>)
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
- _erbout = ''
- field_set_tag { _erbout.concat "Hello world!" }
+ self.output_buffer = ''
+ field_set_tag { concat "Hello world!" }
expected = %(<fieldset>Hello world!</fieldset>)
- assert_dom_equal expected, _erbout
-
- _erbout = ''
- field_set_tag('') { _erbout.concat "Hello world!" }
+ assert_dom_equal expected, output_buffer
+
+ self.output_buffer = ''
+ field_set_tag('') { concat "Hello world!" }
expected = %(<fieldset>Hello world!</fieldset>)
- 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..8c649ea544 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
+ self.output_buffer = 'foo'
+
assert_dom_equal "<script type=\"text/javascript\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>",
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
@@ -92,15 +96,13 @@ class JavaScriptHelperTest < ActionView::TestCase
end
def test_javascript_tag_with_block
- _erbout = ''
- javascript_tag { _erbout.concat "alert('hello')" }
- assert_dom_equal "<script type=\"text/javascript\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", _erbout
+ javascript_tag { concat "alert('hello')" }
+ assert_dom_equal "<script type=\"text/javascript\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", 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 "<script id=\"the_js_tag\" type=\"text/javascript\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", _erbout
+ javascript_tag(:id => "the_js_tag") { concat "alert('hello')" }
+ assert_dom_equal "<script id=\"the_js_tag\" type=\"text/javascript\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", 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 b63d8a368c..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
- _erbout = ''
- form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) { _erbout.concat "Hello world!" }
- assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">Hello world!</form>), _erbout
+ form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) { concat "Hello world!" }
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">Hello world!</form>), output_buffer
end
def test_remote_form_for_with_record_identification_with_new_record
- _erbout = ''
remote_form_for(@record, {:html => { :id => 'create-author' }}) {}
expected = %(<form action='#{authors_path}' onsubmit="new Ajax.Request('#{authors_path}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_author' id='create-author' method='post'></form>)
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_remote_form_for_with_record_identification_without_html_options
- _erbout = ''
remote_form_for(@record) {}
expected = %(<form action='#{authors_path}' onsubmit="new Ajax.Request('#{authors_path}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_author' method='post' id='new_author'></form>)
- 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 = ''
remote_form_for(@record) {}
expected = %(<form action='#{author_path(@record)}' id='edit_author_1' method='post' onsubmit="new Ajax.Request('#{author_path(@record)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='edit_author'><div style='margin:0;padding:0'><input name='_method' type='hidden' value='put' /></div></form>)
- assert_dom_equal expected, _erbout
+ assert_dom_equal expected, output_buffer
end
def test_remote_form_for_with_new_object_in_list
- _erbout = ''
remote_form_for([@author, @article]) {}
expected = %(<form action='#{author_articles_path(@author)}' onsubmit="new Ajax.Request('#{author_articles_path(@author)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_article' method='post' id='new_article'></form>)
- 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 = ''
remote_form_for([@author, @article]) {}
expected = %(<form action='#{author_article_path(@author, @article)}' id='edit_article_1' method='post' onsubmit="new Ajax.Request('#{author_article_path(@author, @article)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='edit_article'><div style='margin:0;padding:0'><input name='_method' type='hidden' value='put' /></div></form>)
- 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..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
- _erbout = ''
expected = %(<li class="post bar" id="post_45"></li>)
actual = content_tag_for(:li, @post, :class => 'bar') { }
assert_dom_equal expected, actual
end
def test_content_tag_for_prefix
- _erbout = ''
expected = %(<ul class="post" id="archived_post_45"></ul>)
actual = content_tag_for(:ul, @post, :archived) { }
assert_dom_equal expected, actual
end
def test_content_tag_for_with_extra_html_tags
- _erbout = ''
expected = %(<tr class="post bar" id="post_45" style='background-color: #f0f0f0'></tr>)
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 = ''
expected = %(<tr class="post" id="post_45">#{@post.body}</tr>)
- actual = content_tag_for(:tr, @post) { _erbout.concat @post.body }
+ actual = content_tag_for(:tr, @post) { concat @post.body }
assert_dom_equal expected, actual
end
def test_div_for
- _erbout = ''
expected = %(<div class="post bar" id="post_45">#{@post.body}</div>)
- actual = div_for(@post, :class => "bar") { _erbout.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 4da6116095..2941dfe217 100644
--- a/actionpack/test/template/tag_helper_test.rb
+++ b/actionpack/test/template/tag_helper_test.rb
@@ -35,18 +35,17 @@ class TagHelperTest < ActionView::TestCase
end
def test_content_tag_with_block
- _erbout = ''
- content_tag(:div) { _erbout.concat "Hello world!" }
- assert_dom_equal "<div>Hello world!</div>", _erbout
+ content_tag(:div) { concat "Hello world!" }
+ assert_dom_equal "<div>Hello world!</div>", output_buffer
end
def test_content_tag_with_block_and_options
- _erbout = ''
- content_tag(:div, :class => "green") { _erbout.concat "Hello world!" }
- assert_dom_equal %(<div class="green">Hello world!</div>), _erbout
+ content_tag(:div, :class => "green") { concat "Hello world!" }
+ assert_dom_equal %(<div class="green">Hello world!</div>), output_buffer
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
diff --git a/actionpack/test/template/template_finder_test.rb b/actionpack/test/template/template_finder_test.rb
index 3d6baff5fb..07fc4b8c56 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
@@ -63,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
diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb
index 62cdca03d1..cbb5c7ee74 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
+ self.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 "<p></p>", simple_format(nil)
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index a65771648e..a1d82fb45d 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,5 +1,11 @@
*Edge*
+* Add :from option to calculations. #397 [Ben Munat]
+
+* 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/association_preload.rb b/activerecord/lib/active_record/association_preload.rb
index a3d1f12b03..49f5270396 100644
--- a/activerecord/lib/active_record/association_preload.rb
+++ b/activerecord/lib/active_record/association_preload.rb
@@ -103,10 +103,10 @@ module ActiveRecord
associated_records = reflection.klass.find(:all, :conditions => [conditions, ids],
:include => options[:include],
:joins => "INNER JOIN #{connection.quote_table_name options[:join_table]} as t0 ON #{reflection.klass.quoted_table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}",
- :select => "#{options[:select] || table_name+'.*'}, t0.#{reflection.primary_key_name} as _parent_record_id",
+ :select => "#{options[:select] || table_name+'.*'}, t0.#{reflection.primary_key_name} as the_parent_record_id",
:order => options[:order])
- set_association_collection_records(id_to_record_map, reflection.name, associated_records, '_parent_record_id')
+ set_association_collection_records(id_to_record_map, reflection.name, associated_records, 'the_parent_record_id')
end
def preload_has_one_association(records, reflection, preload_options={})
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index a3d1bbbada..5f42b5a459 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+.
# * <tt>:uniq</tt> - If true, duplicates will be omitted from the collection. Useful in conjunction with <tt>:through</tt>.
# * <tt>:readonly</tt> - If true, all the associated objects are readonly through the association.
+ # * <tt>:validate</tt> - 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
# * <tt>:source_type</tt> - Specifies type of the source association used by <tt>has_one :through</tt> queries where the source
# association is a polymorphic +belongs_to+.
# * <tt>:readonly</tt> - If true, the associated object is readonly through the association.
+ # * <tt>:validate</tt> - 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. <tt>class Post; attr_readonly :comments_count; end</tt>).
# * <tt>:readonly</tt> - If true, the associated object is readonly through the association.
+ # * <tt>:validate</tt> - 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"
@@ -937,6 +940,8 @@ module ActiveRecord
)
end
+ add_single_associated_save_callbacks(reflection.name) if options[:validate] == true
+
configure_dependency_for_belongs_to(reflection)
end
@@ -1025,6 +1030,7 @@ module ActiveRecord
# * <tt>:select</tt> - By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, 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.
# * <tt>:readonly</tt> - If true, all the associated objects are readonly through the association.
+ # * <tt>:validate</tt> - 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])
@@ -1638,7 +1646,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/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 8dd07eb478..1c16d5de03 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -1903,10 +1903,12 @@ module ActiveRecord #:nodoc:
# MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
def compute_type(type_name)
modularized_name = type_name_with_module(type_name)
- begin
- class_eval(modularized_name, __FILE__, __LINE__)
- rescue NameError
- class_eval(type_name, __FILE__, __LINE__)
+ silence_warnings do
+ begin
+ class_eval(modularized_name, __FILE__, __LINE__)
+ rescue NameError
+ class_eval(type_name, __FILE__, __LINE__)
+ end
end
end
@@ -2064,13 +2066,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:
@@ -2247,12 +2254,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/calculations.rb b/activerecord/lib/active_record/calculations.rb
index caa8c539d5..2ca1a0aaa3 100644
--- a/activerecord/lib/active_record/calculations.rb
+++ b/activerecord/lib/active_record/calculations.rb
@@ -1,6 +1,6 @@
module ActiveRecord
module Calculations #:nodoc:
- CALCULATIONS_OPTIONS = [:conditions, :joins, :order, :select, :group, :having, :distinct, :limit, :offset, :include]
+ CALCULATIONS_OPTIONS = [:conditions, :joins, :order, :select, :group, :having, :distinct, :limit, :offset, :include, :from]
def self.included(base)
base.extend(ClassMethods)
end
@@ -27,6 +27,8 @@ module ActiveRecord
# * <tt>:select</tt>: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not
# include the joined columns.
# * <tt>:distinct</tt>: Set this to true to make this a distinct calculation, such as SELECT COUNT(DISTINCT posts.id) ...
+ # * <tt>:from</tt> - By default, this is the table name of the class, but can be changed to an alternate table name (or even the name
+ # of a database view).
#
# Examples for counting all:
# Person.count # returns the total count of all people
@@ -178,8 +180,12 @@ module ActiveRecord
sql = "SELECT COUNT(*) AS #{aggregate_alias}" if use_workaround
sql << ", #{options[:group_field]} AS #{options[:group_alias]}" if options[:group]
- sql << " FROM (SELECT #{distinct}#{column_name}" if use_workaround
- sql << " FROM #{connection.quote_table_name(table_name)} "
+ if options[:from]
+ sql << " FROM #{options[:from]} "
+ else
+ sql << " FROM (SELECT #{distinct}#{column_name}" if use_workaround
+ sql << " FROM #{connection.quote_table_name(table_name)} "
+ end
if merged_includes.any?
join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, merged_includes, options[:joins])
sql << join_dependency.join_associations.collect{|join| join.association_join }.join
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 653b45021d..93aafaaad1 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,17 @@ module ActiveRecord
raise ArgumentError, "No database specified. Missing argument: database."
end
- require_mysql
+ # Require the MySQL driver and define Mysql::Result.all_hashes
+ 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
mysql.ssl_set(config[:sslkey], config[:sslcert], config[:sslca], config[:sslcapath], config[:sslcipher]) if config[:sslkey]
@@ -165,8 +151,10 @@ 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
LOST_CONNECTION_ERROR_MESSAGES = [
"Server shutdown in progress",
@@ -174,7 +162,22 @@ 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,
+ :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)
@@ -184,7 +187,7 @@ module ActiveRecord
end
def adapter_name #:nodoc:
- 'MySQL'
+ ADAPTER_NAME
end
def supports_migrations? #:nodoc:
@@ -192,20 +195,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
@@ -498,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.
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 7dbfbb41f6..294f4c1929 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
# * <tt>:min_messages</tt> - An optional client min messages that is used in a <tt>SET client_min_messages TO <min_messages></tt> call on the connection.
# * <tt>:allow_concurrency</tt> - 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?
@@ -319,6 +323,15 @@ module ActiveRecord
has_support
end
+ def supports_insert_with_returning?
+ unless defined? @supports_insert_with_returning
+ @supports_insert_with_returning =
+ @connection.respond_to?(:server_version) &&
+ @connection.server_version >= 80200
+ end
+ @supports_insert_with_returning
+ end
+
# Returns the configured supported identifier length supported by PostgreSQL,
# or report the default of 63 on PostgreSQL 7.x.
def table_alias_length
@@ -411,8 +424,34 @@ 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('"', '')
- super || pk && last_insert_id(table, sequence_name || default_sequence_name(table, pk))
+
+ # 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
+ # 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
@@ -506,7 +545,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 +553,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 +715,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.
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
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
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
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
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
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/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
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index dbfa025efb..b638143c5a 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -37,15 +37,15 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_counting_with_single_conditions
- assert_equal 2, Firm.find(:first).plain_clients.count(:conditions => '1=1')
+ assert_equal 1, Firm.find(:first).plain_clients.count(:conditions => ['name=?', "Microsoft"])
end
def test_counting_with_single_hash
- assert_equal 2, Firm.find(:first).plain_clients.count(:conditions => '1=1')
+ assert_equal 1, Firm.find(:first).plain_clients.count(:conditions => {:name => "Microsoft"})
end
def test_counting_with_column_name_and_hash
- assert_equal 2, Firm.find(:first).plain_clients.count(:all, :conditions => '1=1')
+ assert_equal 2, Firm.find(:first).plain_clients.count(:name)
end
def test_finding
@@ -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/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index aefb13ea9a..754fd58f35 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -1,6 +1,7 @@
require "cases/helper"
require 'models/company'
require 'models/topic'
+require 'models/edge'
Company.has_many :accounts
@@ -274,4 +275,49 @@ class CalculationsTest < ActiveRecord::TestCase
def test_should_sum_expression
assert_equal 636, Account.sum("2 * credit_limit")
end
+
+ def test_count_with_from_option
+ assert_equal Company.count(:all), Company.count(:all, :from => 'companies')
+ assert_equal Account.count(:all, :conditions => "credit_limit = 50"),
+ Account.count(:all, :from => 'accounts', :conditions => "credit_limit = 50")
+ assert_equal Company.count(:type, :conditions => {:type => "Firm"}),
+ Company.count(:type, :conditions => {:type => "Firm"}, :from => 'companies')
+ end
+
+ def test_sum_with_from_option
+ assert_equal Account.sum(:credit_limit), Account.sum(:credit_limit, :from => 'accounts')
+ assert_equal Account.sum(:credit_limit, :conditions => "credit_limit > 50"),
+ Account.sum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
+ end
+
+ def test_average_with_from_option
+ assert_equal Account.average(:credit_limit), Account.average(:credit_limit, :from => 'accounts')
+ assert_equal Account.average(:credit_limit, :conditions => "credit_limit > 50"),
+ Account.average(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
+ end
+
+ def test_minimum_with_from_option
+ assert_equal Account.minimum(:credit_limit), Account.minimum(:credit_limit, :from => 'accounts')
+ assert_equal Account.minimum(:credit_limit, :conditions => "credit_limit > 50"),
+ Account.minimum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
+ end
+
+ def test_maximum_with_from_option
+ assert_equal Account.maximum(:credit_limit), Account.maximum(:credit_limit, :from => 'accounts')
+ assert_equal Account.maximum(:credit_limit, :conditions => "credit_limit > 50"),
+ Account.maximum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
+ end
+
+ def test_from_option_with_specified_index
+ if Edge.connection.adapter_name == 'MySQL'
+ assert_equal Edge.count(:all), Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)')
+ assert_equal Edge.count(:all, :conditions => 'sink_id < 5'),
+ Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)', :conditions => 'sink_id < 5')
+ end
+ end
+
+ def test_from_option_with_table_different_than_class
+ assert_equal Account.count(:all), Company.count(:all, :from => 'accounts')
+ end
+
end
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
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..9f26cacdec 100644
--- a/activerecord/test/models/developer.rb
+++ b/activerecord/test/models/developer.rb
@@ -56,7 +56,8 @@ class Developer < ActiveRecord::Base
end
class AuditLog < ActiveRecord::Base
- belongs_to :developer
+ belongs_to :developer, :validate => true
+ belongs_to :unvalidated_developer, :class_name => 'Developer'
end
DeveloperSalary = Struct.new(:amount)
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
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/compressed_mem_cache_store.rb b/activesupport/lib/active_support/cache/compressed_mem_cache_store.rb
index 9470ac9f66..3f1f9ad179 100644
--- a/activesupport/lib/active_support/cache/compressed_mem_cache_store.rb
+++ b/activesupport/lib/active_support/cache/compressed_mem_cache_store.rb
@@ -1,3 +1,5 @@
+require "active_support/cache/mem_cache_store"
+
module ActiveSupport
module Cache
class CompressedMemCacheStore < MemCacheStore
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
diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb
index 47ff19e963..8e148cc1b4 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/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
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
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/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/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?
diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb
index fc88d80cdb..47bd6e1767 100644
--- a/activesupport/lib/active_support/inflector.rb
+++ b/activesupport/lib/active_support/inflector.rb
@@ -10,10 +10,12 @@ 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:
#
- # Inflector.inflections do |inflect|
+ # ActiveSupport::Inflector.inflections do |inflect|
# inflect.plural /^(ox)$/i, '\1\2en'
# inflect.singular /^(ox)en/i, '\1'
#
@@ -91,13 +93,11 @@ module ActiveSupport
end
end
- extend self
-
# Yields a singleton instance of Inflector::Inflections so you can specify additional
# inflector rules.
#
# Example:
- # Inflector.inflections do |inflect|
+ # ActiveSupport::Inflector.inflections do |inflect|
# inflect.uncountable "rails"
# end
def inflections
@@ -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'
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)
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
+ 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
- require 'mocha'
- base.alias_method_chain :run, :callbacks_and_mocha
- rescue LoadError
- base.alias_method_chain :run, :callbacks
+ 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)
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
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
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
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 = []
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'
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
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/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 <tt>/</tt>.
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
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 efce4f292d..dee7abe05f 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"
- end
- config.after_initialize do
- $test_after_initialize_block2 = "congratulations"
- end
- assert_nil $test_after_initialize_block1
- assert_nil $test_after_initialize_block2
+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
+ 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 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_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
+ def test_should_have_called_the_second_after_initialize_block
+ assert_equal "congratulations", $test_after_initialize_block2
+ end
end
-end
-class Initializer_after_initialize_with_no_block_environment_Test < Test::Unit::TestCase
+ 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 setup
- config = ConfigurationMock.new("")
- config.after_initialize do
- $test_after_initialize_block1 = "success"
+ Rails::Initializer.any_instance.expects(:gems_dependencies_loaded).returns(true)
+ Rails::Initializer.run(:after_initialize, config)
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
-
- 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 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_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
+ 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
@@ -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)
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