aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Rakefile14
-rwxr-xr-xactionmailer/Rakefile3
-rw-r--r--actionpack/CHANGELOG6
-rw-r--r--actionpack/Rakefile2
-rwxr-xr-xactionpack/lib/action_controller/base.rb5
-rw-r--r--actionpack/lib/action_controller/caching/fragments.rb18
-rw-r--r--actionpack/lib/action_controller/layout.rb2
-rw-r--r--actionpack/lib/action_controller/polymorphic_routes.rb37
-rw-r--r--actionpack/lib/action_controller/rescue.rb2
-rw-r--r--actionpack/lib/action_controller/templates/rescues/diagnostics.erb4
-rw-r--r--actionpack/lib/action_controller/templates/rescues/template_error.erb4
-rw-r--r--actionpack/lib/action_controller/vendor/html-scanner/html/document.rb2
-rw-r--r--actionpack/lib/action_view/base.rb58
-rw-r--r--actionpack/lib/action_view/helpers/capture_helper.rb8
-rwxr-xr-xactionpack/lib/action_view/helpers/date_helper.rb6
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb11
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb44
-rw-r--r--actionpack/lib/action_view/helpers/javascript_helper.rb129
-rw-r--r--actionpack/lib/action_view/helpers/tag_helper.rb32
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb8
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb2
-rw-r--r--actionpack/lib/action_view/template_handlers/compilable.rb8
-rw-r--r--actionpack/lib/action_view/template_handlers/erb.rb12
-rw-r--r--actionpack/lib/action_view/view_load_paths.rb10
-rw-r--r--actionpack/test/abstract_unit.rb1
-rw-r--r--actionpack/test/active_record_unit.rb58
-rw-r--r--actionpack/test/activerecord/render_partial_with_record_identification_test.rb26
-rw-r--r--actionpack/test/controller/action_pack_assertions_test.rb5
-rw-r--r--actionpack/test/controller/addresses_render_test.rb3
-rw-r--r--actionpack/test/controller/caching_test.rb5
-rw-r--r--actionpack/test/controller/capture_test.rb2
-rw-r--r--actionpack/test/controller/content_type_test.rb24
-rw-r--r--actionpack/test/controller/custom_handler_test.rb45
-rw-r--r--actionpack/test/controller/deprecation/deprecated_base_methods_test.rb3
-rw-r--r--actionpack/test/controller/html-scanner/document_test.rb25
-rw-r--r--actionpack/test/controller/mime_responds_test.rb53
-rw-r--r--actionpack/test/controller/new_render_test.rb109
-rw-r--r--actionpack/test/controller/polymorphic_routes_test.rb33
-rw-r--r--actionpack/test/controller/render_test.rb27
-rw-r--r--actionpack/test/controller/send_file_test.rb4
-rw-r--r--actionpack/test/controller/view_paths_test.rb48
-rw-r--r--actionpack/test/fixtures/test/hello.builder2
-rw-r--r--actionpack/test/fixtures/test/non_erb_block_content_for.builder2
-rwxr-xr-xactionpack/test/template/date_helper_test.rb63
-rw-r--r--actionpack/test/template/form_options_helper_test.rb18
-rw-r--r--actionpack/test/template/form_tag_helper_test.rb33
-rw-r--r--actionpack/test/template/javascript_helper_test.rb8
-rw-r--r--actionpack/test/template/prototype_helper_test.rb137
-rw-r--r--actionpack/test/template/record_tag_helper_test.rb27
-rw-r--r--actionpack/test/template/render_test.rb122
-rw-r--r--actionpack/test/template/tag_helper_test.rb35
-rw-r--r--actionpack/test/template/template_file_test.rb95
-rw-r--r--actionpack/test/template/template_object_test.rb92
-rw-r--r--actionpack/test/template/text_helper_test.rb5
-rw-r--r--actionpack/test/template/url_helper_test.rb24
-rw-r--r--activemodel/Rakefile4
-rw-r--r--activerecord/CHANGELOG17
-rwxr-xr-xactiverecord/Rakefile2
-rwxr-xr-xactiverecord/lib/active_record/associations.rb19
-rw-r--r--activerecord/lib/active_record/associations/association_proxy.rb6
-rw-r--r--activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb6
-rw-r--r--activerecord/lib/active_record/associations/has_many_association.rb6
-rw-r--r--activerecord/lib/active_record/associations/has_many_through_association.rb6
-rwxr-xr-xactiverecord/lib/active_record/associations/has_one_association.rb4
-rwxr-xr-xactiverecord/lib/active_record/base.rb41
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb7
-rwxr-xr-xactiverecord/lib/active_record/connection_adapters/mysql_adapter.rb34
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb39
-rw-r--r--activerecord/lib/active_record/dirty.rb4
-rw-r--r--activerecord/lib/active_record/locking/optimistic.rb1
-rw-r--r--activerecord/lib/active_record/migration.rb5
-rw-r--r--activerecord/lib/active_record/named_scope.rb1
-rw-r--r--activerecord/lib/active_record/reflection.rb4
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb19
-rw-r--r--activerecord/test/cases/dirty_test.rb46
-rw-r--r--activerecord/test/cases/finder_test.rb24
-rw-r--r--activerecord/test/cases/locking_test.rb20
-rw-r--r--activerecord/test/cases/method_scoping_test.rb10
-rw-r--r--activerecord/test/cases/migration_test.rb72
-rw-r--r--activerecord/test/cases/named_scope_test.rb31
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb46
-rw-r--r--activerecord/test/models/post.rb7
-rwxr-xr-xactiverecord/test/models/topic.rb2
-rw-r--r--activerecord/test/schema/schema.rb7
-rw-r--r--activeresource/Rakefile2
-rw-r--r--activesupport/CHANGELOG4
-rw-r--r--activesupport/Rakefile2
-rw-r--r--activesupport/lib/active_support/cache.rb16
-rw-r--r--activesupport/lib/active_support/core_ext/array/conversions.rb5
-rw-r--r--activesupport/lib/active_support/core_ext/enumerable.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/module/model_naming.rb5
-rw-r--r--activesupport/lib/active_support/dependencies.rb2
-rw-r--r--activesupport/lib/active_support/testing/performance.rb14
-rw-r--r--activesupport/lib/active_support/values/time_zone.rb6
-rw-r--r--activesupport/test/caching_test.rb6
-rw-r--r--activesupport/test/core_ext/enumerable_test.rb9
-rw-r--r--activesupport/test/time_zone_test.rb7
-rw-r--r--doc/template/horo.rb613
-rw-r--r--railties/CHANGELOG4
-rw-r--r--railties/Rakefile2
-rw-r--r--railties/bin/about3
-rw-r--r--railties/lib/commands/about.rb1
-rw-r--r--railties/lib/commands/server.rb14
-rw-r--r--railties/lib/commands/servers/thin.rb25
-rw-r--r--railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb2
-rw-r--r--railties/lib/rails_generator/generators/components/performance_test/USAGE8
-rw-r--r--railties/lib/rails_generator/generators/components/performance_test/performance_test_generator.rb16
-rw-r--r--railties/lib/rails_generator/generators/components/performance_test/templates/performance_test.rb8
-rw-r--r--railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb9
-rw-r--r--railties/test/generators/rails_scaffold_generator_test.rb42
111 files changed, 2026 insertions, 856 deletions
diff --git a/.gitignore b/.gitignore
index 96a1c2117a..bba7d5dce8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,5 @@
debug.log
-doc
+doc/rdoc
activeresource/doc
activerecord/doc
actionpack/doc
diff --git a/Rakefile b/Rakefile
index 368f36e56c..352fd632d9 100644
--- a/Rakefile
+++ b/Rakefile
@@ -13,7 +13,7 @@ end
desc 'Run all tests by default'
task :default => :test
-%w(test rdoc package release).each do |task_name|
+%w(test rdoc pgem package release).each do |task_name|
desc "Run #{task_name} task for all projects"
task task_name do
PROJECTS.each do |project|
@@ -25,14 +25,14 @@ end
desc "Generate documentation for the Rails framework"
Rake::RDocTask.new do |rdoc|
- rdoc.rdoc_dir = 'doc'
- rdoc.title = "Rails Framework Documentation"
+ rdoc.rdoc_dir = 'doc/rdoc'
+ rdoc.title = "Ruby on Rails Documentation"
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.options << '-A cattr_accessor=object'
rdoc.options << '--charset' << 'utf-8'
- rdoc.template = "#{ENV['template']}.rb" if ENV['template']
+ rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : './doc/template/horo'
rdoc.rdoc_files.include('railties/CHANGELOG')
rdoc.rdoc_files.include('railties/MIT-LICENSE')
@@ -68,13 +68,13 @@ end
# Enhance rdoc task to copy referenced images also
task :rdoc do
- FileUtils.mkdir_p "doc/files/examples/"
- FileUtils.copy "activerecord/examples/associations.png", "doc/files/examples/associations.png"
+ FileUtils.mkdir_p "doc/rdoc/files/examples/"
+ FileUtils.copy "activerecord/examples/associations.png", "doc/rdoc/files/examples/associations.png"
end
desc "Publish API docs for Rails as a whole and for each component"
task :pdoc => :rdoc do
- Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/api", "doc").upload
+ Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/api", "doc/rdoc").upload
PROJECTS.each do |project|
system %(cd #{project} && #{env} #{$0} pdoc)
end
diff --git a/actionmailer/Rakefile b/actionmailer/Rakefile
index b003f4d559..612bd27774 100755
--- a/actionmailer/Rakefile
+++ b/actionmailer/Rakefile
@@ -35,7 +35,7 @@ Rake::RDocTask.new { |rdoc|
rdoc.title = "Action Mailer -- Easy email delivery and testing"
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
rdoc.options << '--charset' << 'utf-8'
- rdoc.template = "#{ENV['template']}.rb" if ENV['template']
+ rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
rdoc.rdoc_files.include('README', 'CHANGELOG')
rdoc.rdoc_files.include('lib/action_mailer.rb')
rdoc.rdoc_files.include('lib/action_mailer/*.rb')
@@ -77,6 +77,7 @@ end
desc "Publish the API documentation"
task :pgem => [:package] do
Rake::SshFilePublisher.new("wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
+ `ssh wrath.rubyonrails.org './gemupdate.sh'`
end
desc "Publish the API documentation"
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 4a6e70a153..165db916ee 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,11 @@
*Edge*
+* time_zone_select: support for regexp matching of priority zones. Resolves #195 [Ernie Miller]
+
+* Made ActionView::Base#render_file private [Josh Peek]
+
+* Fix polymorphic_url with singleton resources. #461 [Tammer Saleh]
+
* Replaced TemplateFinder abstraction with ViewLoadPaths [Josh Peek]
* Added block-call style to link_to [Sam Stephenson/DHH]. Example:
diff --git a/actionpack/Rakefile b/actionpack/Rakefile
index 86a2f3af14..1880f21f67 100644
--- a/actionpack/Rakefile
+++ b/actionpack/Rakefile
@@ -49,7 +49,7 @@ Rake::RDocTask.new { |rdoc|
rdoc.title = "Action Pack -- On rails from request to response"
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.options << '--charset' << 'utf-8'
- rdoc.template = "#{ENV['template']}.rb" if ENV['template']
+ rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
if ENV['DOC_FILES']
rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/))
else
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index bf34edcd85..7cc670289d 100755
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -859,8 +859,7 @@ module ActionController #:nodoc:
elsif inline = options[:inline]
add_variables_to_assigns
- tmpl = ActionView::InlineTemplate.new(@template, options[:inline], options[:locals], options[:type])
- render_for_text(@template.render_template(tmpl), options[:status])
+ render_for_text(@template.render(options), options[:status])
elsif action_name = options[:action]
template = default_template_name(action_name.to_s)
@@ -1095,7 +1094,7 @@ module ActionController #:nodoc:
def render_for_file(template_path, status = nil, use_full_path = false, locals = {}) #:nodoc:
add_variables_to_assigns
logger.info("Rendering #{template_path}" + (status ? " (#{status})" : '')) if logger
- render_for_text(@template.render_file(template_path, use_full_path, locals), status)
+ render_for_text(@template.render(:file => template_path, :use_full_path => use_full_path, :locals => locals), status)
end
def render_for_text(text = nil, status = nil, append_response = false) #:nodoc:
diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/action_controller/caching/fragments.rb
index e4f5de44ab..57b31ec9d1 100644
--- a/actionpack/lib/action_controller/caching/fragments.rb
+++ b/actionpack/lib/action_controller/caching/fragments.rb
@@ -61,16 +61,18 @@ module ActionController #:nodoc:
end
def fragment_for(block, name = {}, options = nil) #:nodoc:
- unless perform_caching then block.call; return end
-
- buffer = yield
-
- if cache = read_fragment(name, options)
- buffer.concat(cache)
+ if perform_caching
+ buffer = yield
+
+ if cache = read_fragment(name, options)
+ buffer.concat(cache)
+ else
+ pos = buffer.length
+ block.call
+ write_fragment(name, buffer[pos..-1], options)
+ end
else
- pos = buffer.length
block.call
- write_fragment(name, buffer[pos..-1], options)
end
end
diff --git a/actionpack/lib/action_controller/layout.rb b/actionpack/lib/action_controller/layout.rb
index 0721f71498..d0c717ff67 100644
--- a/actionpack/lib/action_controller/layout.rb
+++ b/actionpack/lib/action_controller/layout.rb
@@ -254,7 +254,7 @@ module ActionController #:nodoc:
@template.instance_variable_set("@content_for_layout", content_for_layout)
response.layout = layout
status = template_with_options ? options[:status] : nil
- render_for_text(@template.render_file(layout, true), status)
+ render_for_text(@template.render(layout), status)
else
render_with_no_layout(options, extra_options, &block)
end
diff --git a/actionpack/lib/action_controller/polymorphic_routes.rb b/actionpack/lib/action_controller/polymorphic_routes.rb
index 509fa6a08e..7c30bf0778 100644
--- a/actionpack/lib/action_controller/polymorphic_routes.rb
+++ b/actionpack/lib/action_controller/polymorphic_routes.rb
@@ -48,6 +48,9 @@ module ActionController
#
# # calls post_url(post)
# polymorphic_url(post) # => "http://example.com/posts/1"
+ # polymorphic_url([blog, post]) # => "http://example.com/blogs/1/posts/1"
+ # polymorphic_url([:admin, blog, post]) # => "http://example.com/admin/blogs/1/posts/1"
+ # polymorphic_url([user, :blog, post]) # => "http://example.com/users/1/blog/posts/1"
#
# ==== Options
#
@@ -83,8 +86,6 @@ module ActionController
else [ record_or_hash_or_array ]
end
- args << format if format
-
inflection =
case
when options[:action].to_s == "new"
@@ -96,6 +97,9 @@ module ActionController
else
:singular
end
+
+ args.delete_if {|arg| arg.is_a?(Symbol) || arg.is_a?(String)}
+ args << format if format
named_route = build_named_route_call(record_or_hash_or_array, namespace, inflection, options)
send!(named_route, *args)
@@ -136,11 +140,19 @@ module ActionController
else
record = records.pop
route = records.inject("") do |string, parent|
- string << "#{RecordIdentifier.send!("singular_class_name", parent)}_"
+ if parent.is_a?(Symbol) || parent.is_a?(String)
+ string << "#{parent}_"
+ else
+ string << "#{RecordIdentifier.send!("singular_class_name", parent)}_"
+ end
end
end
- route << "#{RecordIdentifier.send!("#{inflection}_class_name", record)}_"
+ if record.is_a?(Symbol) || record.is_a?(String)
+ route << "#{record}_"
+ else
+ route << "#{RecordIdentifier.send!("#{inflection}_class_name", record)}_"
+ end
action_prefix(options) + namespace + route + routing_type(options).to_s
end
@@ -163,16 +175,17 @@ module ActionController
end
end
+ # Remove the first symbols from the array and return the url prefix
+ # implied by those symbols.
def extract_namespace(record_or_hash_or_array)
- returning "" do |namespace|
- if record_or_hash_or_array.is_a?(Array)
- record_or_hash_or_array.delete_if do |record_or_namespace|
- if record_or_namespace.is_a?(String) || record_or_namespace.is_a?(Symbol)
- namespace << "#{record_or_namespace}_"
- end
- end
- end
+ return "" unless record_or_hash_or_array.is_a?(Array)
+
+ namespace_keys = []
+ while (key = record_or_hash_or_array.first) && key.is_a?(String) || key.is_a?(Symbol)
+ namespace_keys << record_or_hash_or_array.shift
end
+
+ namespace_keys.map {|k| "#{k}_"}.join
end
end
end
diff --git a/actionpack/lib/action_controller/rescue.rb b/actionpack/lib/action_controller/rescue.rb
index 40ef4ea044..163ed87fbb 100644
--- a/actionpack/lib/action_controller/rescue.rb
+++ b/actionpack/lib/action_controller/rescue.rb
@@ -178,7 +178,7 @@ module ActionController #:nodoc:
@template.instance_variable_set("@rescues_path", File.dirname(rescues_path("stub")))
@template.send!(:assign_variables_from_controller)
- @template.instance_variable_set("@contents", @template.render_file(template_path_for_local_rescue(exception), false))
+ @template.instance_variable_set("@contents", @template.render(:file => template_path_for_local_rescue(exception), :use_full_path => false))
response.content_type = Mime::HTML
render_for_file(rescues_path("layout"), response_code_for_rescue(exception))
diff --git a/actionpack/lib/action_controller/templates/rescues/diagnostics.erb b/actionpack/lib/action_controller/templates/rescues/diagnostics.erb
index 032f945ed2..385c6c1b09 100644
--- a/actionpack/lib/action_controller/templates/rescues/diagnostics.erb
+++ b/actionpack/lib/action_controller/templates/rescues/diagnostics.erb
@@ -6,6 +6,6 @@
</h1>
<pre><%=h @exception.clean_message %></pre>
-<%= render_file(@rescues_path + "/_trace.erb", false) %>
+<%= render(:file => @rescues_path + "/_trace.erb", :use_full_path => false) %>
-<%= render_file(@rescues_path + "/_request_and_response.erb", false) %>
+<%= render(:file => @rescues_path + "/_request_and_response.erb", :use_full_path => false) %>
diff --git a/actionpack/lib/action_controller/templates/rescues/template_error.erb b/actionpack/lib/action_controller/templates/rescues/template_error.erb
index eda64db3e9..4aecc68d18 100644
--- a/actionpack/lib/action_controller/templates/rescues/template_error.erb
+++ b/actionpack/lib/action_controller/templates/rescues/template_error.erb
@@ -15,7 +15,7 @@
<% @real_exception = @exception
@exception = @exception.original_exception || @exception %>
-<%= render_file(@rescues_path + "/_trace.erb", false) %>
+<%= render(:file => @rescues_path + "/_trace.erb", :use_full_path => false) %>
<% @exception = @real_exception %>
-<%= render_file(@rescues_path + "/_request_and_response.erb", false) %>
+<%= render(:file => @rescues_path + "/_request_and_response.erb", :use_full_path => false) %>
diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/document.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/document.rb
index 607fd186b9..b8d73c350d 100644
--- a/actionpack/lib/action_controller/vendor/html-scanner/html/document.rb
+++ b/actionpack/lib/action_controller/vendor/html-scanner/html/document.rb
@@ -17,7 +17,7 @@ module HTML #:nodoc:
@root = Node.new(nil)
node_stack = [ @root ]
while token = tokenizer.next
- node = Node.parse(node_stack.last, tokenizer.line, tokenizer.position, token)
+ node = Node.parse(node_stack.last, tokenizer.line, tokenizer.position, token, strict)
node_stack.last.children << node unless node.tag? && node.closing == :close
if node.tag?
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index 4f3cc46a14..40b808a61e 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -161,10 +161,9 @@ module ActionView #:nodoc:
attr_accessor :output_buffer
- # Specify trim mode for the ERB compiler. Defaults to '-'.
- # See ERb documentation for suitable values.
- @@erb_trim_mode = '-'
- cattr_accessor :erb_trim_mode
+ class << self
+ delegate :erb_trim_mode=, :to => 'ActionView::TemplateHandlers::ERB'
+ end
# Specify whether file modification times should be checked to see if a template needs recompilation
@@cache_template_loading = false
@@ -229,26 +228,6 @@ module ActionView #:nodoc:
@view_paths = ViewLoadPaths.new(Array(paths))
end
- # Renders the template present at <tt>template_path</tt>. If <tt>use_full_path</tt> is set to true,
- # it's relative to the view_paths array, otherwise it's absolute. The hash in <tt>local_assigns</tt>
- # is made available as local variables.
- def render_file(template_path, use_full_path = true, local_assigns = {}) #:nodoc:
- if defined?(ActionMailer) && defined?(ActionMailer::Base) && controller.is_a?(ActionMailer::Base) && !template_path.include?("/")
- raise ActionViewError, <<-END_ERROR
-Due to changes in ActionMailer, you need to provide the mailer_name along with the template name.
-
- render "user_mailer/signup"
- render :file => "user_mailer/signup"
-
-If you are rendering a subtemplate, you must now use controller-like partial syntax:
-
- render :partial => 'signup' # no mailer_name necessary
- END_ERROR
- end
-
- Template.new(self, template_path, use_full_path, local_assigns).render_template
- end
-
# Renders the template present at <tt>template_path</tt> (relative to the view_paths array).
# The hash in <tt>local_assigns</tt> is made available as local variables.
def render(options = {}, local_assigns = {}, &block) #:nodoc:
@@ -277,16 +256,11 @@ If you are rendering a subtemplate, you must now use controller-like partial syn
elsif options[:partial]
render_partial(options[:partial], ActionView::Base::ObjectWrapper.new(options[:object]), options[:locals])
elsif options[:inline]
- template = InlineTemplate.new(self, options[:inline], options[:locals], options[:type])
- render_template(template)
+ render_inline(options[:inline], options[:locals], options[:type])
end
end
end
- def render_template(template) #:nodoc:
- template.render_template
- end
-
# Returns true is the file may be rendered implicitly.
def file_public?(template_path)#:nodoc:
template_path.split('/').last[0,1] != '_'
@@ -324,6 +298,30 @@ If you are rendering a subtemplate, you must now use controller-like partial syn
end
private
+ # Renders the template present at <tt>template_path</tt>. If <tt>use_full_path</tt> is set to true,
+ # it's relative to the view_paths array, otherwise it's absolute. The hash in <tt>local_assigns</tt>
+ # is made available as local variables.
+ def render_file(template_path, use_full_path = true, local_assigns = {}) #:nodoc:
+ if defined?(ActionMailer) && defined?(ActionMailer::Base) && controller.is_a?(ActionMailer::Base) && !template_path.include?("/")
+ raise ActionViewError, <<-END_ERROR
+ Due to changes in ActionMailer, you need to provide the mailer_name along with the template name.
+
+ render "user_mailer/signup"
+ render :file => "user_mailer/signup"
+
+ If you are rendering a subtemplate, you must now use controller-like partial syntax:
+
+ render :partial => 'signup' # no mailer_name necessary
+ END_ERROR
+ end
+
+ Template.new(self, template_path, use_full_path, local_assigns).render_template
+ end
+
+ def render_inline(text, local_assigns = {}, type = nil)
+ InlineTemplate.new(self, text, local_assigns, type).render_template
+ end
+
def wrap_content_for_layout(content)
original_content_for_layout, @content_for_layout = @content_for_layout, content
yield
diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb
index 9cd9d3d06a..990c30b90d 100644
--- a/actionpack/lib/action_view/helpers/capture_helper.rb
+++ b/actionpack/lib/action_view/helpers/capture_helper.rb
@@ -31,10 +31,13 @@ module ActionView
# </body></html>
#
def capture(*args, &block)
- if output_buffer
+ # Return captured buffer in erb.
+ if block_called_from_erb?(block)
with_output_buffer { block.call(*args) }
+
+ # Return block result otherwise, but protect buffer also.
else
- block.call(*args)
+ with_output_buffer { return block.call(*args) }
end
end
@@ -117,6 +120,7 @@ module ActionView
ivar = "@content_for_#{name}"
content = capture(&block) if block_given?
instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{content}")
+ nil
end
private
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index 7ed6272898..1aee9ef0a2 100755
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -696,15 +696,15 @@ module ActionView
class FormBuilder
def date_select(method, options = {}, html_options = {})
- @template.date_select(@object_name, method, options.merge(:object => @object))
+ @template.date_select(@object_name, method, options.merge(:object => @object), html_options)
end
def time_select(method, options = {}, html_options = {})
- @template.time_select(@object_name, method, options.merge(:object => @object))
+ @template.time_select(@object_name, method, options.merge(:object => @object), html_options)
end
def datetime_select(method, options = {}, html_options = {})
- @template.datetime_select(@object_name, method, options.merge(:object => @object))
+ @template.datetime_select(@object_name, method, options.merge(:object => @object), html_options)
end
end
end
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index b3f8e63c1b..0ca5cebcba 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -150,7 +150,8 @@ module ActionView
# You can also supply an array of TimeZone objects
# as +priority_zones+, so that they will be listed above the rest of the
# (long) list. (You can use TimeZone.us_zones as a convenience for
- # obtaining a list of the US time zones.)
+ # obtaining a list of the US time zones, or a Regexp to select the zones
+ # of your choice)
#
# Finally, this method supports a <tt>:default</tt> option, which selects
# a default TimeZone if the object's time zone is +nil+.
@@ -164,6 +165,8 @@ module ActionView
#
# time_zone_select( "user", 'time_zone', [ TimeZone['Alaska'], TimeZone['Hawaii'] ])
#
+ # time_zone_select( "user", 'time_zone', /Australia/)
+ #
# time_zone_select( "user", "time_zone", TZInfo::Timezone.all.sort, :model => TZInfo::Timezone)
def time_zone_select(object, method, priority_zones = nil, options = {}, html_options = {})
InstanceTag.new(object, method, self, nil, options.delete(:object)).to_time_zone_select_tag(priority_zones, options, html_options)
@@ -292,7 +295,8 @@ module ActionView
# selected option tag. You can also supply an array of TimeZone objects
# as +priority_zones+, so that they will be listed above the rest of the
# (long) list. (You can use TimeZone.us_zones as a convenience for
- # obtaining a list of the US time zones.)
+ # obtaining a list of the US time zones, or a Regexp to select the zones
+ # of your choice)
#
# The +selected+ parameter must be either +nil+, or a string that names
# a TimeZone.
@@ -311,6 +315,9 @@ module ActionView
convert_zones = lambda { |list| list.map { |z| [ z.to_s, z.name ] } }
if priority_zones
+ if priority_zones.is_a?(Regexp)
+ priority_zones = model.all.find_all {|z| z =~ priority_zones}
+ end
zone_options += options_for_select(convert_zones[priority_zones], selected)
zone_options += "<option value=\"\" disabled=\"disabled\">-------------</option>\n"
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index 3a97f1390f..ccebec3692 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -6,7 +6,7 @@ module ActionView
# Provides a number of methods for creating form tags that doesn't rely on an Active Record object assigned to the template like
# FormHelper does. Instead, you provide the names and values manually.
#
- # NOTE: The HTML options <tt>disabled</tt>, <tt>readonly</tt>, and <tt>multiple</tt> can all be treated as booleans. So specifying
+ # NOTE: The HTML options <tt>disabled</tt>, <tt>readonly</tt>, and <tt>multiple</tt> can all be treated as booleans. So specifying
# <tt>:disabled => true</tt> will give <tt>disabled="disabled"</tt>.
module FormTagHelper
# Starts a form tag that points the action to an url configured with <tt>url_for_options</tt> just like
@@ -20,15 +20,15 @@ module ActionView
# * A list of parameters to feed to the URL the form will be posted to.
#
# ==== Examples
- # form_tag('/posts')
+ # form_tag('/posts')
# # => <form action="/posts" method="post">
#
- # form_tag('/posts/1', :method => :put)
+ # form_tag('/posts/1', :method => :put)
# # => <form action="/posts/1" method="put">
#
- # form_tag('/upload', :multipart => true)
+ # form_tag('/upload', :multipart => true)
# # => <form action="/upload" method="post" enctype="multipart/form-data">
- #
+ #
# <% form_tag '/posts' do -%>
# <div><%= submit_tag 'Save' %></div>
# <% end -%>
@@ -88,7 +88,7 @@ module ActionView
# * <tt>:size</tt> - The number of visible characters that will fit in the input.
# * <tt>:maxlength</tt> - The maximum number of characters that the browser will allow the user to enter.
# * Any other key creates standard HTML attributes for the tag.
- #
+ #
# ==== Examples
# text_field_tag 'name'
# # => <input id="name" name="name" type="text" />
@@ -146,13 +146,13 @@ module ActionView
# # => <input id="token" name="token" type="hidden" value="VUBJKB23UIVI1UU1VOBVI@" />
#
# hidden_field_tag 'collected_input', '', :onchange => "alert('Input collected!')"
- # # => <input id="collected_input" name="collected_input" onchange="alert('Input collected!')"
+ # # => <input id="collected_input" name="collected_input" onchange="alert('Input collected!')"
# # type="hidden" value="" />
def hidden_field_tag(name, value = nil, options = {})
text_field_tag(name, value, options.stringify_keys.update("type" => "hidden"))
end
- # Creates a file upload field. If you are using file uploads then you will also need
+ # Creates a file upload field. If you are using file uploads then you will also need
# to set the multipart option for the form tag:
#
# <%= form_tag { :action => "post" }, { :multipart => true } %>
@@ -160,7 +160,7 @@ module ActionView
# <%= submit_tag %>
# <%= end_form_tag %>
#
- # The specified URL will then be passed a File object containing the selected file, or if the field
+ # The specified URL will then be passed a File object containing the selected file, or if the field
# was left blank, a StringIO object.
#
# ==== Options
@@ -181,7 +181,7 @@ module ActionView
# # => <input id="resume" name="resume" type="file" value="~/resume.doc" />
#
# file_field_tag 'user_pic', :accept => 'image/png,image/gif,image/jpeg'
- # # => <input accept="image/png,image/gif,image/jpeg" id="user_pic" name="user_pic" type="file" />
+ # # => <input accept="image/png,image/gif,image/jpeg" id="user_pic" name="user_pic" type="file" />
#
# file_field_tag 'file', :accept => 'text/html', :class => 'upload', :value => 'index.html'
# # => <input accept="text/html" class="upload" id="file" name="file" type="file" value="index.html" />
@@ -286,7 +286,7 @@ module ActionView
tag :input, html_options
end
- # Creates a radio button; use groups of radio buttons named the same to allow users to
+ # Creates a radio button; use groups of radio buttons named the same to allow users to
# select from a group of options.
#
# ==== Options
@@ -313,14 +313,14 @@ module ActionView
tag :input, html_options
end
- # Creates a submit button with the text <tt>value</tt> as the caption.
+ # Creates a submit button with the text <tt>value</tt> as the caption.
#
# ==== Options
# * <tt>:confirm => 'question?'</tt> - This will add a JavaScript confirm
# prompt with the question specified. If the user accepts, the form is
# processed normally, otherwise no action is taken.
# * <tt>:disabled</tt> - If true, the user will not be able to use this input.
- # * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a disabled version
+ # * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a disabled version
# of the submit button when the form is submitted.
# * Any other key creates standard HTML options for the tag.
#
@@ -335,7 +335,7 @@ module ActionView
# # => <input disabled="disabled" name="commit" type="submit" value="Save edits" />
#
# submit_tag "Complete sale", :disable_with => "Please wait..."
- # # => <input name="commit" onclick="this.disabled=true;this.value='Please wait...';this.form.submit();"
+ # # => <input name="commit" onclick="this.disabled=true;this.value='Please wait...';this.form.submit();"
# # type="submit" value="Complete sale" />
#
# submit_tag nil, :class => "form_submit"
@@ -346,7 +346,7 @@ module ActionView
# # name="commit" type="submit" value="Edit" />
def submit_tag(value = "Save changes", options = {})
options.stringify_keys!
-
+
if disable_with = options.delete("disable_with")
options["onclick"] = [
"this.setAttribute('originalValue', this.value)",
@@ -358,15 +358,15 @@ module ActionView
"return result;",
].join(";")
end
-
+
if confirm = options.delete("confirm")
options["onclick"] ||= ''
options["onclick"] += "return #{confirm_javascript_function(confirm)};"
end
-
+
tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options.stringify_keys)
end
-
+
# Displays an image which when clicked will submit the form.
#
# <tt>source</tt> is passed to AssetTagHelper#image_path
@@ -412,7 +412,7 @@ module ActionView
concat(content)
concat("</fieldset>")
end
-
+
private
def html_options_for_form(url_for_options, options, *parameters_for_url)
returning options.stringify_keys do |html_options|
@@ -420,7 +420,7 @@ module ActionView
html_options["action"] = url_for(url_for_options, *parameters_for_url)
end
end
-
+
def extra_tags_for_form(html_options)
case method = html_options.delete("method").to_s
when /^get$/i # must be case-insentive, but can't use downcase as might be nil
@@ -434,12 +434,12 @@ module ActionView
content_tag(:div, tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag, :style => 'margin:0;padding:0')
end
end
-
+
def form_tag_html(html_options)
extra_tags = extra_tags_for_form(html_options)
tag(:form, html_options, true) + extra_tags
end
-
+
def form_tag_in_block(html_options, &block)
content = capture(&block)
concat(form_tag_html(html_options))
diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb
index 7404a251e4..f89b6c2f70 100644
--- a/actionpack/lib/action_view/helpers/javascript_helper.rb
+++ b/actionpack/lib/action_view/helpers/javascript_helper.rb
@@ -4,10 +4,10 @@ require 'action_view/helpers/prototype_helper'
module ActionView
module Helpers
# Provides functionality for working with JavaScript in your views.
- #
+ #
# == Ajax, controls and visual effects
- #
- # * For information on using Ajax, see
+ #
+ # * For information on using Ajax, see
# ActionView::Helpers::PrototypeHelper.
# * For information on using controls and visual effects, see
# ActionView::Helpers::ScriptaculousHelper.
@@ -20,22 +20,22 @@ module ActionView
# and ActionView::Helpers::ScriptaculousHelper), you must do one of the
# following:
#
- # * Use <tt><%= javascript_include_tag :defaults %></tt> in the HEAD
- # section of your page (recommended): This function will return
+ # * Use <tt><%= javascript_include_tag :defaults %></tt> in the HEAD
+ # section of your page (recommended): This function will return
# references to the JavaScript files created by the +rails+ command in
# your <tt>public/javascripts</tt> directory. Using it is recommended as
- # the browser can then cache the libraries instead of fetching all the
+ # the browser can then cache the libraries instead of fetching all the
# functions anew on every request.
- # * Use <tt><%= javascript_include_tag 'prototype' %></tt>: As above, but
+ # * Use <tt><%= javascript_include_tag 'prototype' %></tt>: As above, but
# will only include the Prototype core library, which means you are able
- # to use all basic AJAX functionality. For the Scriptaculous-based
- # JavaScript helpers, like visual effects, autocompletion, drag and drop
+ # to use all basic AJAX functionality. For the Scriptaculous-based
+ # JavaScript helpers, like visual effects, autocompletion, drag and drop
# and so on, you should use the method described above.
# * Use <tt><%= define_javascript_functions %></tt>: this will copy all the
# JavaScript support functions within a single script block. Not
# recommended.
#
- # For documentation on +javascript_include_tag+ see
+ # For documentation on +javascript_include_tag+ see
# ActionView::Helpers::AssetTagHelper.
module JavaScriptHelper
unless const_defined? :JAVASCRIPT_PATH
@@ -43,13 +43,13 @@ module ActionView
end
include PrototypeHelper
-
- # Returns a link that will trigger a JavaScript +function+ using the
+
+ # Returns a link that will trigger a JavaScript +function+ using the
# onclick handler and return false after the fact.
#
# The +function+ argument can be omitted in favor of an +update_page+
# block, which evaluates to a string when the template is rendered
- # (instead of making an Ajax request first).
+ # (instead of making an Ajax request first).
#
# Examples:
# link_to_function "Greeting", "alert('Hello world!')"
@@ -70,36 +70,31 @@ module ActionView
# <a href="#" id="more_link" onclick="try {
# $(&quot;details&quot;).visualEffect(&quot;toggle_blind&quot;);
# $(&quot;more_link&quot;).update(&quot;Show me less&quot;);
- # }
- # catch (e) {
- # alert('RJS error:\n\n' + e.toString());
+ # }
+ # catch (e) {
+ # alert('RJS error:\n\n' + e.toString());
# alert('$(\&quot;details\&quot;).visualEffect(\&quot;toggle_blind\&quot;);
# \n$(\&quot;more_link\&quot;).update(\&quot;Show me less\&quot;);');
- # throw e
+ # throw e
# };
# return false;">Show me more</a>
#
def link_to_function(name, *args, &block)
- html_options = args.extract_options!
- function = args[0] || ''
-
- html_options.symbolize_keys!
- function = update_page(&block) if block_given?
- content_tag(
- "a", name,
- html_options.merge({
- :href => html_options[:href] || "#",
- :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function}; return false;"
- })
- )
+ html_options = args.extract_options!.symbolize_keys
+
+ function = block_given? ? update_page(&block) : args[0] || ''
+ onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function}; return false;"
+ href = html_options[:href] || '#'
+
+ content_tag(:a, name, html_options.merge(:href => href, :onclick => onclick))
end
-
- # Returns a button that'll trigger a JavaScript +function+ using the
+
+ # Returns a button that'll trigger a JavaScript +function+ using the
# onclick handler.
#
# The +function+ argument can be omitted in favor of an +update_page+
# block, which evaluates to a string when the template is rendered
- # (instead of making an Ajax request first).
+ # (instead of making an Ajax request first).
#
# Examples:
# button_to_function "Greeting", "alert('Hello world!')"
@@ -111,45 +106,56 @@ module ActionView
# page[:details].visual_effect :toggle_slide
# end
def button_to_function(name, *args, &block)
- html_options = args.extract_options!
- function = args[0] || ''
-
- html_options.symbolize_keys!
- function = update_page(&block) if block_given?
- tag(:input, html_options.merge({
- :type => "button", :value => name,
- :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
- }))
+ html_options = args.extract_options!.symbolize_keys
+
+ function = block_given? ? update_page(&block) : args[0] || ''
+ onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function};"
+
+ tag(:input, html_options.merge(:type => 'button', :value => name, :onclick => onclick))
end
- # Includes the Action Pack JavaScript libraries inside a single <script>
+ # Includes the Action Pack JavaScript libraries inside a single <script>
# tag. The function first includes prototype.js and then its core extensions,
# (determined by filenames starting with "prototype").
# Afterwards, any additional scripts will be included in undefined order.
#
# Note: The recommended approach is to copy the contents of
# lib/action_view/helpers/javascripts/ into your application's
- # public/javascripts/ directory, and use +javascript_include_tag+ to
+ # public/javascripts/ directory, and use +javascript_include_tag+ to
# create remote <script> links.
def define_javascript_functions
javascript = "<script type=\"#{Mime::JS}\">"
-
- # load prototype.js and its extensions first
+
+ # load prototype.js and its extensions first
prototype_libs = Dir.glob(File.join(JAVASCRIPT_PATH, 'prototype*')).sort.reverse
- prototype_libs.each do |filename|
+ prototype_libs.each do |filename|
javascript << "\n" << IO.read(filename)
end
-
+
# load other libraries
- (Dir.glob(File.join(JAVASCRIPT_PATH, '*')) - prototype_libs).each do |filename|
+ (Dir.glob(File.join(JAVASCRIPT_PATH, '*')) - prototype_libs).each do |filename|
javascript << "\n" << IO.read(filename)
end
javascript << '</script>'
end
+
+ JS_ESCAPE_MAP = {
+ '\\' => '\\\\',
+ '</' => '<\/',
+ "\r\n" => '\n',
+ "\n" => '\n',
+ "\r" => '\n',
+ '"' => '\\"',
+ "'" => "\\'" }
+
# Escape carrier returns and single and double quotes for JavaScript segments.
def escape_javascript(javascript)
- (javascript || '').gsub('\\','\0\0').gsub('</','<\/').gsub(/\r\n|\n|\r/, "\\n").gsub(/["']/) { |m| "\\#{m}" }
+ if javascript
+ javascript.gsub(/(\\|<\/|\r\n|[\n\r"'])/) { JS_ESCAPE_MAP[$1] }
+ else
+ ''
+ end
end
# Returns a JavaScript tag with the +content+ inside. Example:
@@ -163,7 +169,7 @@ module ActionView
# </script>
#
# +html_options+ may be a hash of attributes for the <script> tag. Example:
- # javascript_tag "alert('All is good')", :defer => 'defer'
+ # javascript_tag "alert('All is good')", :defer => 'defer'
# # => <script defer="defer" type="text/javascript">alert('All is good')</script>
#
# Instead of passing the content as an argument, you can also use a block
@@ -180,30 +186,37 @@ module ActionView
content_or_options_with_block
end
- tag = content_tag("script", javascript_cdata_section(content), html_options.merge(:type => Mime::JS))
+ tag = content_tag(:script, javascript_cdata_section(content), html_options.merge(:type => Mime::JS))
- block_given? ? concat(tag) : tag
+ if block_called_from_erb?(block)
+ concat(tag)
+ else
+ tag
+ end
end
def javascript_cdata_section(content) #:nodoc:
"\n//#{cdata_section("\n#{content}\n//")}\n"
end
-
+
protected
def options_for_javascript(options)
- '{' + options.map {|k, v| "#{k}:#{v}"}.sort.join(', ') + '}'
+ if options.empty?
+ '{}'
+ else
+ "{#{options.keys.map { |k| "#{k}:#{options[k]}" }.sort.join(', ')}}"
+ end
end
-
+
def array_or_string_for_javascript(option)
- js_option = if option.kind_of?(Array)
+ if option.kind_of?(Array)
"['#{option.join('\',\'')}']"
elsif !option.nil?
"'#{option}'"
end
- js_option
end
end
-
+
JavascriptHelper = JavaScriptHelper unless const_defined? :JavascriptHelper
end
end
diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb
index e1abec1847..aeafd3906d 100644
--- a/actionpack/lib/action_view/helpers/tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/tag_helper.rb
@@ -12,14 +12,14 @@ module ActionView
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
- # with HTML 4.0 and below. Add HTML attributes by passing an attributes
+ # Returns an empty HTML tag of type +name+ which by default is XHTML
+ # compliant. Set +open+ to true to create an open tag compatible
+ # with HTML 4.0 and below. Add HTML attributes by passing an attributes
# hash to +options+. Set +escape+ to false to disable attribute value
# escaping.
#
# ==== Options
- # The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and
+ # The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and
# <tt>readonly</tt>), which you can give a value of true in the +options+ hash. You can use
# symbols or strings for the attribute names.
#
@@ -30,7 +30,7 @@ module ActionView
# tag("br", nil, true)
# # => <br>
#
- # tag("input", { :type => 'text', :disabled => true })
+ # tag("input", { :type => 'text', :disabled => true })
# # => <input type="text" disabled="disabled" />
#
# tag("img", { :src => "open & shut.png" })
@@ -43,13 +43,13 @@ module ActionView
end
# Returns an HTML block tag of type +name+ surrounding the +content+. Add
- # HTML attributes by passing an attributes hash to +options+.
+ # HTML attributes by passing an attributes hash to +options+.
# Instead of passing the content as an argument, you can also use a block
# in which case, you pass your +options+ as the second parameter.
# Set escape to false to disable attribute value escaping.
#
# ==== Options
- # The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and
+ # The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and
# <tt>readonly</tt>), which you can give a value of true in the +options+ hash. You can use
# symbols or strings for the attribute names.
#
@@ -68,7 +68,13 @@ 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)
- concat(content_tag_string(name, capture(&block), options, escape))
+ content_tag = content_tag_string(name, capture(&block), options, escape)
+
+ if block_called_from_erb?(block)
+ concat(content_tag)
+ else
+ content_tag
+ end
else
content_tag_string(name, content_or_options_with_block, options, escape)
end
@@ -102,6 +108,16 @@ module ActionView
end
private
+ BLOCK_CALLED_FROM_ERB = 'defined? __in_erb_template'
+
+ # Check whether we're called from an erb template.
+ # We'd return a string in any other case, but erb <%= ... %>
+ # can't take an <% end %> later on, so we have to use <% ... %>
+ # and implicitly concat.
+ def block_called_from_erb?(block)
+ block && eval(BLOCK_CALLED_FROM_ERB, block)
+ end
+
def content_tag_string(name, content, options, escape = true)
tag_options = tag_options(options, escape) if options
"<#{name}#{tag_options}>#{content}</#{name}>"
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index a1a91f6b3d..a6c48737e9 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -30,11 +30,7 @@ module ActionView
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
+ output_buffer << string
end
if RUBY_VERSION < '1.9'
@@ -472,7 +468,7 @@ module ActionView
[-\w]+ # subdomain or domain
(?:\.[-\w]+)* # remaining subdomains or domain
(?::\d+)? # port
- (?:/(?:(?:[~\w\+@%=\(\)-]|(?:[,.;:][^\s$]))+)?)* # path
+ (?:/(?:(?:[~\w\+@%=\(\)-]|(?:[,.;:'][^\s$]))+)?)* # path
(?:\?[\w\+@%&=.;-]+)? # query string
(?:\#[\w\-]*)? # trailing anchor
)
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index baecd304cd..d5b7255642 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -535,7 +535,7 @@ module ActionView
when method
"#{method_javascript_function(method, url, href)}return false;"
when popup
- popup_javascript_function(popup) + 'return false;'
+ "#{popup_javascript_function(popup)}return false;"
else
html_options["onclick"]
end
diff --git a/actionpack/lib/action_view/template_handlers/compilable.rb b/actionpack/lib/action_view/template_handlers/compilable.rb
index 1aef81ba1a..783456ab53 100644
--- a/actionpack/lib/action_view/template_handlers/compilable.rb
+++ b/actionpack/lib/action_view/template_handlers/compilable.rb
@@ -106,7 +106,13 @@ module ActionView
locals_code << "#{key} = local_assigns[:#{key}]\n"
end
- "def #{render_symbol}(local_assigns)\nold_output_buffer = output_buffer;#{locals_code}#{body}\nensure\nself.output_buffer = old_output_buffer\nend"
+ <<-end_src
+ def #{render_symbol}(local_assigns)
+ old_output_buffer = output_buffer;#{locals_code}#{body}
+ ensure
+ self.output_buffer = old_output_buffer
+ end
+ end_src
end
# Return true if the given template was compiled for a superset of the keys in local_assigns
diff --git a/actionpack/lib/action_view/template_handlers/erb.rb b/actionpack/lib/action_view/template_handlers/erb.rb
index ad4ccc7c42..ac715e30c2 100644
--- a/actionpack/lib/action_view/template_handlers/erb.rb
+++ b/actionpack/lib/action_view/template_handlers/erb.rb
@@ -42,12 +42,20 @@ module ActionView
class ERB < TemplateHandler
include Compilable
+ # Specify trim mode for the ERB compiler. Defaults to '-'.
+ # See ERb documentation for suitable values.
+ cattr_accessor :erb_trim_mode
+ self.erb_trim_mode = '-'
+
def compile(template)
- ::ERB.new(template.source, nil, @view.erb_trim_mode, '@output_buffer').src
+ src = ::ERB.new(template.source, nil, erb_trim_mode, '@output_buffer').src
+ "__in_erb_template=true;#{src}"
end
def cache_fragment(block, name = {}, options = nil) #:nodoc:
- @view.fragment_for(block, name, options) { @view.response.template.output_buffer ||= '' }
+ @view.fragment_for(block, name, options) do
+ @view.response.template.output_buffer
+ end
end
end
end
diff --git a/actionpack/lib/action_view/view_load_paths.rb b/actionpack/lib/action_view/view_load_paths.rb
index e873d96aa0..f23ac665f1 100644
--- a/actionpack/lib/action_view/view_load_paths.rb
+++ b/actionpack/lib/action_view/view_load_paths.rb
@@ -6,19 +6,15 @@ module ActionView #:nodoc:
class LoadPath #:nodoc:
attr_reader :path, :paths
- delegate :to_s, :inspect, :to => :path
+ delegate :to_s, :to_str, :inspect, :to => :path
def initialize(path)
@path = path.freeze
reload!
end
- def eql?(view_path)
- view_path.is_a?(ViewPath) && @path == view_path.path
- end
-
- def hash
- @path.hash
+ def ==(path)
+ to_str == path.to_str
end
# Rebuild load path directory cache
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index fa1c3293b4..70f6a28a9c 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -22,6 +22,7 @@ ActiveSupport::Deprecation.debug = true
ActionController::Base.logger = nil
ActionController::Routing::Routes.reload rescue nil
+FIXTURE_LOAD_PATH = ActionView::ViewLoadPaths::LoadPath.new(File.join(File.dirname(__FILE__), 'fixtures'))
# Wrap tests that use Mocha and skip if unavailable.
def uses_mocha(test_name)
diff --git a/actionpack/test/active_record_unit.rb b/actionpack/test/active_record_unit.rb
index a7d526850e..a377ccad24 100644
--- a/actionpack/test/active_record_unit.rb
+++ b/actionpack/test/active_record_unit.rb
@@ -30,7 +30,6 @@ end
$stderr.flush
-
# Define the rest of the connector
class ActiveRecordTestConnector
class << self
@@ -48,46 +47,45 @@ class ActiveRecordTestConnector
end
private
-
- def setup_connection
- if Object.const_defined?(:ActiveRecord)
- defaults = { :database => ':memory:' }
- begin
- options = defaults.merge :adapter => 'sqlite3', :timeout => 500
- ActiveRecord::Base.establish_connection(options)
- ActiveRecord::Base.configurations = { 'sqlite3_ar_integration' => options }
- ActiveRecord::Base.connection
- rescue Exception # errors from establishing a connection
- $stderr.puts 'SQLite 3 unavailable; trying SQLite 2.'
- options = defaults.merge :adapter => 'sqlite'
- ActiveRecord::Base.establish_connection(options)
- ActiveRecord::Base.configurations = { 'sqlite2_ar_integration' => options }
- ActiveRecord::Base.connection
+ def setup_connection
+ if Object.const_defined?(:ActiveRecord)
+ defaults = { :database => ':memory:' }
+ begin
+ options = defaults.merge :adapter => 'sqlite3', :timeout => 500
+ ActiveRecord::Base.establish_connection(options)
+ ActiveRecord::Base.configurations = { 'sqlite3_ar_integration' => options }
+ ActiveRecord::Base.connection
+ rescue Exception # errors from establishing a connection
+ $stderr.puts 'SQLite 3 unavailable; trying SQLite 2.'
+ options = defaults.merge :adapter => 'sqlite'
+ ActiveRecord::Base.establish_connection(options)
+ ActiveRecord::Base.configurations = { 'sqlite2_ar_integration' => options }
+ ActiveRecord::Base.connection
+ end
+
+ Object.send(:const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type')) unless Object.const_defined?(:QUOTED_TYPE)
+ else
+ raise "Can't setup connection since ActiveRecord isn't loaded."
end
-
- Object.send(:const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type')) unless Object.const_defined?(:QUOTED_TYPE)
- else
- raise "Can't setup connection since ActiveRecord isn't loaded."
end
- end
- # Load actionpack sqlite tables
- def load_schema
- File.read(File.dirname(__FILE__) + "/fixtures/db_definitions/sqlite.sql").split(';').each do |sql|
- ActiveRecord::Base.connection.execute(sql) unless sql.blank?
+ # Load actionpack sqlite tables
+ def load_schema
+ File.read(File.dirname(__FILE__) + "/fixtures/db_definitions/sqlite.sql").split(';').each do |sql|
+ ActiveRecord::Base.connection.execute(sql) unless sql.blank?
+ end
end
- end
- def require_fixture_models
- Dir.glob(File.dirname(__FILE__) + "/fixtures/*.rb").each {|f| require f}
- end
+ def require_fixture_models
+ Dir.glob(File.dirname(__FILE__) + "/fixtures/*.rb").each {|f| require f}
+ end
end
end
class ActiveRecordTestCase < ActiveSupport::TestCase
# Set our fixture path
if ActiveRecordTestConnector.able_to_connect
- self.fixture_path = "#{File.dirname(__FILE__)}/fixtures/"
+ self.fixture_path = [FIXTURE_LOAD_PATH]
self.use_transactional_fixtures = false
end
diff --git a/actionpack/test/activerecord/render_partial_with_record_identification_test.rb b/actionpack/test/activerecord/render_partial_with_record_identification_test.rb
index ed10e72953..af2725a99b 100644
--- a/actionpack/test/activerecord/render_partial_with_record_identification_test.rb
+++ b/actionpack/test/activerecord/render_partial_with_record_identification_test.rb
@@ -40,11 +40,12 @@ class RenderPartialWithRecordIdentificationController < ActionController::Base
render :partial => @developers
end
end
-RenderPartialWithRecordIdentificationController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
+
+RenderPartialWithRecordIdentificationController.view_paths = [FIXTURE_LOAD_PATH]
class RenderPartialWithRecordIdentificationTest < ActiveRecordTestCase
fixtures :developers, :projects, :developers_projects, :topics, :replies, :companies, :mascots
-
+
def setup
@controller = RenderPartialWithRecordIdentificationController.new
@request = ActionController::TestRequest.new
@@ -56,22 +57,22 @@ class RenderPartialWithRecordIdentificationTest < ActiveRecordTestCase
get :render_with_has_many_and_belongs_to_association
assert_template 'projects/_project'
end
-
+
def test_rendering_partial_with_has_many_association
get :render_with_has_many_association
assert_template 'replies/_reply'
end
-
+
def test_rendering_partial_with_named_scope
get :render_with_named_scope
assert_template 'replies/_reply'
end
-
+
def test_render_with_record
get :render_with_record
assert_template 'developers/_developer'
end
-
+
def test_render_with_record_collection
get :render_with_record_collection
assert_template 'developers/_developer'
@@ -116,7 +117,8 @@ class RenderPartialWithRecordIdentificationController < ActionController::Base
render :partial => @developers
end
end
-RenderPartialWithRecordIdentificationController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
+
+RenderPartialWithRecordIdentificationController.view_paths = [FIXTURE_LOAD_PATH]
class Game < Struct.new(:name, :id)
def to_param
@@ -134,7 +136,8 @@ module Fun
render :partial => [ Game.new("Pong"), Game.new("Tank") ]
end
end
- NestedController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
+
+ NestedController.view_paths = [FIXTURE_LOAD_PATH]
module Serious
class NestedDeeperController < ActionController::Base
@@ -146,7 +149,8 @@ module Fun
render :partial => [ Game.new("Chess"), Game.new("Sudoku"), Game.new("Solitaire") ]
end
end
- NestedDeeperController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
+
+ NestedDeeperController.view_paths = [FIXTURE_LOAD_PATH]
end
end
@@ -167,7 +171,6 @@ class RenderPartialWithRecordIdentificationAndNestedControllersTest < ActiveReco
get :render_with_record_collection_in_nested_controller
assert_template 'fun/games/_game'
end
-
end
class RenderPartialWithRecordIdentificationAndNestedDeeperControllersTest < ActiveRecordTestCase
@@ -187,5 +190,4 @@ class RenderPartialWithRecordIdentificationAndNestedDeeperControllersTest < Acti
get :render_with_record_collection_in_deeper_nested_controller
assert_template 'fun/serious/games/_game'
end
-
-end \ No newline at end of file
+end
diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb
index c25e9e1df6..7a90a9408e 100644
--- a/actionpack/test/controller/action_pack_assertions_test.rb
+++ b/actionpack/test/controller/action_pack_assertions_test.rb
@@ -157,7 +157,7 @@ module Admin
def redirect_to_fellow_controller
redirect_to :controller => 'user'
end
-
+
def redirect_to_top_level_named_route
redirect_to top_level_url(:id => "foo")
end
@@ -170,7 +170,7 @@ end
# tell the controller where to find its templates but start from parent
# directory of test_request_response to simulate the behaviour of a
# production environment
-ActionPackAssertionsController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
+ActionPackAssertionsController.view_paths = [FIXTURE_LOAD_PATH]
# a test case to exercise the new capabilities TestRequest & TestResponse
class ActionPackAssertionsControllerTest < Test::Unit::TestCase
@@ -533,7 +533,6 @@ class ActionPackHeaderTest < Test::Unit::TestCase
assert_equal('application/pdf; charset=utf-8', @response.headers['type'])
end
-
def test_render_text_with_custom_content_type
get :render_text_with_custom_content_type
assert_equal 'application/rss+xml; charset=utf-8', @response.headers['type']
diff --git a/actionpack/test/controller/addresses_render_test.rb b/actionpack/test/controller/addresses_render_test.rb
index a31734203d..df87182082 100644
--- a/actionpack/test/controller/addresses_render_test.rb
+++ b/actionpack/test/controller/addresses_render_test.rb
@@ -1,7 +1,6 @@
require 'abstract_unit'
class Address
-
def Address.count(conditions = nil, join = nil)
nil
end
@@ -20,7 +19,7 @@ class AddressesTestController < ActionController::Base
def self.controller_path; "addresses"; end
end
-AddressesTestController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
+AddressesTestController.view_paths = [FIXTURE_LOAD_PATH]
class AddressesTest < Test::Unit::TestCase
def setup
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index 14cf0a86a1..0140654155 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -6,7 +6,7 @@ CACHE_DIR = 'test_cache'
FILE_STORE_PATH = File.join(File.dirname(__FILE__), '/../temp/', CACHE_DIR)
ActionController::Base.page_cache_directory = FILE_STORE_PATH
ActionController::Base.cache_store = :file_store, FILE_STORE_PATH
-ActionController::Base.view_paths = [ File.dirname(__FILE__) + '/../fixtures/' ]
+ActionController::Base.view_paths = [FIXTURE_LOAD_PATH]
class PageCachingTestController < ActionController::Base
caches_page :ok, :no_content, :if => Proc.new { |c| !c.request.format.json? }
@@ -631,7 +631,7 @@ class FunctionalCachingController < ActionController::Base
end
end
-FunctionalCachingController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
+FunctionalCachingController.view_paths = [FIXTURE_LOAD_PATH]
class FunctionalFragmentCachingTest < Test::Unit::TestCase
def setup
@@ -642,6 +642,7 @@ class FunctionalFragmentCachingTest < Test::Unit::TestCase
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end
+
def test_fragment_caching
get :fragment_cached
assert_response :success
diff --git a/actionpack/test/controller/capture_test.rb b/actionpack/test/controller/capture_test.rb
index 2604844b84..87f9ce8ab3 100644
--- a/actionpack/test/controller/capture_test.rb
+++ b/actionpack/test/controller/capture_test.rb
@@ -23,7 +23,7 @@ class CaptureController < ActionController::Base
def rescue_action(e) raise end
end
-CaptureController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
+CaptureController.view_paths = [FIXTURE_LOAD_PATH]
class CaptureTest < Test::Unit::TestCase
def setup
diff --git a/actionpack/test/controller/content_type_test.rb b/actionpack/test/controller/content_type_test.rb
index d262ce8103..2019b4a2d0 100644
--- a/actionpack/test/controller/content_type_test.rb
+++ b/actionpack/test/controller/content_type_test.rb
@@ -13,12 +13,12 @@ class ContentTypeController < ActionController::Base
def render_content_type_from_render
render :text => "hello world!", :content_type => Mime::RSS
end
-
+
def render_charset_from_body
response.charset = "utf-16"
render :text => "hello world!"
end
-
+
def render_default_for_rhtml
end
@@ -45,7 +45,7 @@ class ContentTypeController < ActionController::Base
def rescue_action(e) raise end
end
-ContentTypeController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
+ContentTypeController.view_paths = [FIXTURE_LOAD_PATH]
class ContentTypeTest < Test::Unit::TestCase
def setup
@@ -68,7 +68,7 @@ class ContentTypeTest < Test::Unit::TestCase
def test_render_changed_charset_default
ContentTypeController.default_charset = "utf-16"
get :render_defaults
- assert_equal "utf-16", @response.charset
+ assert_equal "utf-16", @response.charset
assert_equal Mime::HTML, @response.content_type
ContentTypeController.default_charset = "utf-8"
end
@@ -76,13 +76,13 @@ class ContentTypeTest < Test::Unit::TestCase
def test_content_type_from_body
get :render_content_type_from_body
assert_equal "application/rss+xml", @response.content_type
- assert_equal "utf-8", @response.charset
+ assert_equal "utf-8", @response.charset
end
def test_content_type_from_render
get :render_content_type_from_render
assert_equal "application/rss+xml", @response.content_type
- assert_equal "utf-8", @response.charset
+ assert_equal "utf-8", @response.charset
end
def test_charset_from_body
@@ -94,27 +94,27 @@ class ContentTypeTest < Test::Unit::TestCase
def test_default_for_rhtml
get :render_default_for_rhtml
assert_equal Mime::HTML, @response.content_type
- assert_equal "utf-8", @response.charset
+ assert_equal "utf-8", @response.charset
end
def test_default_for_rxml
get :render_default_for_rxml
assert_equal Mime::XML, @response.content_type
- assert_equal "utf-8", @response.charset
+ assert_equal "utf-8", @response.charset
end
def test_default_for_rjs
xhr :post, :render_default_for_rjs
assert_equal Mime::JS, @response.content_type
- assert_equal "utf-8", @response.charset
+ assert_equal "utf-8", @response.charset
end
def test_change_for_rxml
get :render_change_for_rxml
assert_equal Mime::HTML, @response.content_type
- assert_equal "utf-8", @response.charset
+ assert_equal "utf-8", @response.charset
end
-
+
def test_render_default_content_types_for_respond_to
@request.env["HTTP_ACCEPT"] = Mime::HTML.to_s
get :render_default_content_types_for_respond_to
@@ -130,7 +130,7 @@ class ContentTypeTest < Test::Unit::TestCase
get :render_default_content_types_for_respond_to
assert_equal Mime::XML, @response.content_type
end
-
+
def test_render_default_content_types_for_respond_to_with_overwrite
@request.env["HTTP_ACCEPT"] = Mime::RSS.to_s
get :render_default_content_types_for_respond_to
diff --git a/actionpack/test/controller/custom_handler_test.rb b/actionpack/test/controller/custom_handler_test.rb
deleted file mode 100644
index ac484ae17e..0000000000
--- a/actionpack/test/controller/custom_handler_test.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-require 'abstract_unit'
-
-class CustomHandler < ActionView::TemplateHandler
- def initialize( view )
- @view = view
- end
-
- def render( template )
- [ template.source,
- template.locals,
- @view ]
- end
-end
-
-class CustomHandlerTest < Test::Unit::TestCase
- def setup
- ActionView::Template.register_template_handler "foo", CustomHandler
- ActionView::Template.register_template_handler :foo2, CustomHandler
- @view = ActionView::Base.new
- end
-
- def test_custom_render
- template = ActionView::InlineTemplate.new(@view, "hello <%= one %>", { :one => "two" }, "foo")
-
- result = @view.render_template(template)
- assert_equal(
- [ "hello <%= one %>", { :one => "two" }, @view ],
- result )
- end
-
- def test_custom_render2
- template = ActionView::InlineTemplate.new(@view, "hello <%= one %>", { :one => "two" }, "foo2")
- result = @view.render_template(template)
- assert_equal(
- [ "hello <%= one %>", { :one => "two" }, @view ],
- result )
- end
-
- def test_unhandled_extension
- # uses the ERb handler by default if the extension isn't recognized
- template = ActionView::InlineTemplate.new(@view, "hello <%= one %>", { :one => "two" }, "bar")
- result = @view.render_template(template)
- assert_equal "hello two", result
- end
-end
diff --git a/actionpack/test/controller/deprecation/deprecated_base_methods_test.rb b/actionpack/test/controller/deprecation/deprecated_base_methods_test.rb
index 8c1a8954a5..f485500b7f 100644
--- a/actionpack/test/controller/deprecation/deprecated_base_methods_test.rb
+++ b/actionpack/test/controller/deprecation/deprecated_base_methods_test.rb
@@ -2,7 +2,6 @@ require 'abstract_unit'
class DeprecatedBaseMethodsTest < Test::Unit::TestCase
class Target < ActionController::Base
-
def home_url(greeting)
"http://example.com/#{greeting}"
end
@@ -14,7 +13,7 @@ class DeprecatedBaseMethodsTest < Test::Unit::TestCase
def rescue_action(e) raise e end
end
- Target.view_paths = [ File.dirname(__FILE__) + "/../../fixtures" ]
+ Target.view_paths = [FIXTURE_LOAD_PATH]
def setup
@request = ActionController::TestRequest.new
diff --git a/actionpack/test/controller/html-scanner/document_test.rb b/actionpack/test/controller/html-scanner/document_test.rb
index 0519533dbd..1c3facb9e3 100644
--- a/actionpack/test/controller/html-scanner/document_test.rb
+++ b/actionpack/test/controller/html-scanner/document_test.rb
@@ -120,4 +120,29 @@ HTML
assert doc.find(:tag => "div", :attributes => { :id => "map" }, :content => "")
assert doc.find(:tag => "div", :attributes => { :id => "map" }, :content => nil)
end
+
+ def test_parse_invalid_document
+ assert_nothing_raised do
+ doc = HTML::Document.new("<html>
+ <table>
+ <tr>
+ <td style=\"color: #FFFFFF; height: 17px; onclick=\"window.location.href='http://www.rmeinc.com/about_rme.aspx'\" style=\"cursor:pointer; height: 17px;\"; nowrap onclick=\"window.location.href='http://www.rmeinc.com/about_rme.aspx'\" onmouseout=\"this.bgColor='#0066cc'; this.style.color='#FFFFFF'\" onmouseover=\"this.bgColor='#ffffff'; this.style.color='#0033cc'\">About Us</td>
+ </tr>
+ </table>
+ </html>")
+ end
+ end
+
+ def test_invalid_document_raises_exception_when_strict
+ assert_raises RuntimeError do
+ doc = HTML::Document.new("<html>
+ <table>
+ <tr>
+ <td style=\"color: #FFFFFF; height: 17px; onclick=\"window.location.href='http://www.rmeinc.com/about_rme.aspx'\" style=\"cursor:pointer; height: 17px;\"; nowrap onclick=\"window.location.href='http://www.rmeinc.com/about_rme.aspx'\" onmouseout=\"this.bgColor='#0066cc'; this.style.color='#FFFFFF'\" onmouseover=\"this.bgColor='#ffffff'; this.style.color='#0033cc'\">About Us</td>
+ </tr>
+ </table>
+ </html>", true)
+ end
+ end
+
end
diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb
index c617cb2e84..fb2519563d 100644
--- a/actionpack/test/controller/mime_responds_test.rb
+++ b/actionpack/test/controller/mime_responds_test.rb
@@ -107,7 +107,7 @@ class RespondToController < ActionController::Base
type.any(:js, :xml) { render :text => "Either JS or XML" }
end
end
-
+
def handle_any_any
respond_to do |type|
type.html { render :text => 'HTML' }
@@ -120,12 +120,12 @@ class RespondToController < ActionController::Base
type.html
type.js
end
- end
-
- def iphone_with_html_response_type
+ end
+
+ def iphone_with_html_response_type
Mime::Type.register_alias("text/html", :iphone)
request.format = :iphone if request.env["HTTP_ACCEPT"] == "text/iphone"
-
+
respond_to do |type|
type.html { @type = "Firefox" }
type.iphone { @type = "iPhone" }
@@ -138,7 +138,7 @@ class RespondToController < ActionController::Base
def iphone_with_html_response_type_without_layout
Mime::Type.register_alias("text/html", :iphone)
request.format = "iphone" if request.env["HTTP_ACCEPT"] == "text/iphone"
-
+
respond_to do |type|
type.html { @type = "Firefox"; render :action => "iphone_with_html_response_type" }
type.iphone { @type = "iPhone" ; render :action => "iphone_with_html_response_type" }
@@ -162,7 +162,7 @@ class RespondToController < ActionController::Base
end
end
-RespondToController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
+RespondToController.view_paths = [FIXTURE_LOAD_PATH]
class MimeControllerTest < Test::Unit::TestCase
def setup
@@ -247,7 +247,7 @@ class MimeControllerTest < Test::Unit::TestCase
get :just_xml
assert_equal 'XML', @response.body
end
-
+
def test_using_defaults
@request.env["HTTP_ACCEPT"] = "*/*"
get :using_defaults
@@ -347,12 +347,12 @@ class MimeControllerTest < Test::Unit::TestCase
get :handle_any_any
assert_equal 'HTML', @response.body
end
-
+
def test_handle_any_any_parameter_format
get :handle_any_any, {:format=>'html'}
assert_equal 'HTML', @response.body
end
-
+
def test_handle_any_any_explicit_html
@request.env["HTTP_ACCEPT"] = "text/html"
get :handle_any_any
@@ -364,7 +364,7 @@ class MimeControllerTest < Test::Unit::TestCase
get :handle_any_any
assert_equal 'Whatever you ask for, I got it', @response.body
end
-
+
def test_handle_any_any_xml
@request.env["HTTP_ACCEPT"] = "text/xml"
get :handle_any_any
@@ -445,31 +445,31 @@ class MimeControllerTest < Test::Unit::TestCase
get :using_defaults, :format => "xml"
assert_equal "using_defaults - xml", @response.body
- end
-
+ end
+
def test_format_with_custom_response_type
get :iphone_with_html_response_type
- assert_equal '<html><div id="html">Hello future from Firefox!</div></html>', @response.body
-
+ assert_equal '<html><div id="html">Hello future from Firefox!</div></html>', @response.body
+
get :iphone_with_html_response_type, :format => "iphone"
assert_equal "text/html", @response.content_type
assert_equal '<html><div id="iphone">Hello iPhone future from iPhone!</div></html>', @response.body
- end
-
+ end
+
def test_format_with_custom_response_type_and_request_headers
@request.env["HTTP_ACCEPT"] = "text/iphone"
get :iphone_with_html_response_type
assert_equal '<html><div id="iphone">Hello iPhone future from iPhone!</div></html>', @response.body
assert_equal "text/html", @response.content_type
- end
+ end
def test_format_with_custom_response_type_and_request_headers_with_only_one_layout_present
get :iphone_with_html_response_type_without_layout
- assert_equal '<html><div id="html_missing">Hello future from Firefox!</div></html>', @response.body
+ assert_equal '<html><div id="html_missing">Hello future from Firefox!</div></html>', @response.body
@request.env["HTTP_ACCEPT"] = "text/iphone"
assert_raises(ActionView::MissingTemplate) { get :iphone_with_html_response_type_without_layout }
- end
+ end
end
class AbstractPostController < ActionController::Base
@@ -497,7 +497,7 @@ class PostController < AbstractPostController
end
end
-class SuperPostController < PostController
+class SuperPostController < PostController
def index
respond_to do |type|
type.html
@@ -514,25 +514,24 @@ class MimeControllerLayoutsTest < Test::Unit::TestCase
@controller = PostController.new
@request.host = "www.example.com"
end
-
+
def test_missing_layout_renders_properly
get :index
- assert_equal '<html><div id="html">Hello Firefox</div></html>', @response.body
+ assert_equal '<html><div id="html">Hello Firefox</div></html>', @response.body
@request.env["HTTP_ACCEPT"] = "text/iphone"
get :index
assert_equal 'Hello iPhone', @response.body
end
-
+
def test_format_with_inherited_layouts
@controller = SuperPostController.new
-
+
get :index
assert_equal 'Super Firefox', @response.body
-
+
@request.env["HTTP_ACCEPT"] = "text/iphone"
get :index
assert_equal '<html><div id="super_iphone">Super iPhone</div></html>', @response.body
end
end
-
diff --git a/actionpack/test/controller/new_render_test.rb b/actionpack/test/controller/new_render_test.rb
index b77b3ceffa..deda47f352 100644
--- a/actionpack/test/controller/new_render_test.rb
+++ b/actionpack/test/controller/new_render_test.rb
@@ -45,11 +45,11 @@ class NewRenderTestController < ActionController::Base
def render_action_hello_world_as_symbol
render :action => :hello_world
end
-
+
def render_text_hello_world
render :text => "hello world"
end
-
+
def render_text_hello_world_with_layout
@variable_for_layout = ", I'm here!"
render :text => "hello world", :layout => true
@@ -68,7 +68,7 @@ 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'))
@@ -76,14 +76,14 @@ class NewRenderTestController < ActionController::Base
def render_file_with_locals
path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_locals.erb')
- render :file => path, :locals => {:secret => 'in the sauce'}
+ render :file => path, :locals => {:secret => 'in the sauce'}
end
def render_file_not_using_full_path
@secret = 'in the sauce'
render :file => 'test/render_file_with_ivar', :use_full_path => true
end
-
+
def render_file_not_using_full_path_with_dot_in_path
@secret = 'in the sauce'
render :file => 'test/dot.directory/render_file_with_ivar', :use_full_path => true
@@ -105,7 +105,7 @@ class NewRenderTestController < ActionController::Base
def layout_test_with_different_layout
render :action => "hello_world", :layout => "standard"
end
-
+
def rendering_without_layout
render :action => "hello_world", :layout => false
end
@@ -113,11 +113,11 @@ class NewRenderTestController < ActionController::Base
def layout_overriding_layout
render :action => "hello_world", :layout => "standard"
end
-
+
def rendering_nothing_on_layout
render :nothing => true
end
-
+
def builder_layout_test
render :action => "hello"
end
@@ -135,9 +135,9 @@ class NewRenderTestController < ActionController::Base
def partial_only_with_layout
render :partial => "partial_only", :layout => true
end
-
+
def partial_with_locals
- render :partial => "customer", :locals => { :customer => Customer.new("david") }
+ render :partial => "customer", :locals => { :customer => Customer.new("david") }
end
def partial_with_form_builder
@@ -151,11 +151,11 @@ class NewRenderTestController < ActionController::Base
def partial_collection
render :partial => "customer", :collection => [ Customer.new("david"), Customer.new("mary") ]
end
-
+
def partial_collection_with_spacer
render :partial => "customer", :spacer_template => "partial_only", :collection => [ Customer.new("david"), Customer.new("mary") ]
end
-
+
def partial_collection_with_counter
render :partial => "customer_counter", :collection => [ Customer.new("david"), Customer.new("mary") ]
end
@@ -186,33 +186,33 @@ class NewRenderTestController < ActionController::Base
def empty_partial_collection
render :partial => "customer", :collection => []
end
-
+
def partial_with_hash_object
render :partial => "hash_object", :object => {:first_name => "Sam"}
end
-
+
def partial_hash_collection
render :partial => "hash_object", :collection => [ {:first_name => "Pratik"}, {:first_name => "Amy"} ]
end
-
+
def partial_hash_collection_with_locals
render :partial => "hash_greeting", :collection => [ {:first_name => "Pratik"}, {:first_name => "Amy"} ], :locals => { :greeting => "Hola" }
end
-
+
def partial_with_implicit_local_assignment
@customer = Customer.new("Marcel")
render :partial => "customer"
end
-
+
def missing_partial
render :partial => 'thisFileIsntHere'
end
-
+
def hello_in_a_string
@customers = [ Customer.new("david"), Customer.new("mary") ]
render :text => "How's there? " << render_to_string(:template => "test/list")
end
-
+
def render_to_string_with_assigns
@before = "i'm before the render"
render_to_string :text => "foo"
@@ -222,14 +222,14 @@ class NewRenderTestController < ActionController::Base
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"
- end
-
+ @partial_with_locals = render_to_string :partial => "customer", :locals => { :customer => Customer.new("david") }
+ render :action => "test/hello_world"
+ end
+
def render_to_string_with_exception
render_to_string :file => "exception that will not be caught - this will certainly not work", :use_full_path => true
end
-
+
def render_to_string_with_caught_exception
@before = "i'm before the render"
begin
@@ -282,7 +282,7 @@ class NewRenderTestController < ActionController::Base
render :text => "hello"
redirect_to :action => "double_render"
end
-
+
def render_to_string_and_render
@stuff = render_to_string :text => "here is some cached stuff"
render :text => "Hi web users! #{@stuff}"
@@ -329,7 +329,7 @@ class NewRenderTestController < ActionController::Base
def render_with_location
render :xml => "<hello/>", :location => "http://example.com", :status => 201
end
-
+
def render_with_object_location
customer = Customer.new("Some guy", 1)
render :xml => "<customer/>", :location => customer_url(customer), :status => :created
@@ -341,12 +341,12 @@ class NewRenderTestController < ActionController::Base
"<i-am-xml/>"
end
end.new
-
+
render :xml => to_xmlable
end
helper NewRenderTestHelper
- helper do
+ helper do
def rjs_helper_method(value)
page.visual_effect :highlight, value
end
@@ -383,7 +383,7 @@ class NewRenderTestController < ActionController::Base
page.visual_effect :highlight, 'balance'
end
end
-
+
def update_page_with_instance_variables
@money = '$37,000,000.00'
@div_id = 'balance'
@@ -426,12 +426,12 @@ class NewRenderTestController < ActionController::Base
def render_using_layout_around_block_in_main_layout_and_within_content_for_layout
render :action => "using_layout_around_block"
end
-
+
def rescue_action(e) raise end
-
+
private
def determine_layout
- case action_name
+ case action_name
when "hello_world", "layout_test", "rendering_without_layout",
"rendering_nothing_on_layout", "render_text_hello_world",
"render_text_hello_world_with_layout",
@@ -443,7 +443,7 @@ class NewRenderTestController < ActionController::Base
"render_js_with_explicit_template",
"render_js_with_explicit_action_template",
"delete_with_js", "update_page", "update_page_with_instance_variables"
-
+
"layouts/standard"
when "builder_layout_test"
"layouts/builder"
@@ -457,8 +457,8 @@ class NewRenderTestController < ActionController::Base
end
end
-NewRenderTestController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
-Fun::GamesController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
+NewRenderTestController.view_paths = [FIXTURE_LOAD_PATH]
+Fun::GamesController.view_paths = [FIXTURE_LOAD_PATH]
class NewRenderTest < Test::Unit::TestCase
def setup
@@ -527,7 +527,7 @@ class NewRenderTest < Test::Unit::TestCase
end
def test_render_file_not_using_full_path
- get :render_file_not_using_full_path
+ get :render_file_not_using_full_path
assert_equal "The secret is in the sauce\n", @response.body
end
@@ -540,7 +540,7 @@ 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
@@ -661,7 +661,7 @@ EOS
assert_not_deprecated { get :hello_in_a_string }
assert_equal "How's there? goodbyeHello: davidHello: marygoodbye\n", @response.body
end
-
+
def test_render_to_string_doesnt_break_assigns
get :render_to_string_with_assigns
assert_equal "i'm before the render", assigns(:before)
@@ -672,12 +672,12 @@ EOS
get :render_to_string_with_partial
assert_equal "only partial", assigns(:partial_only)
assert_equal "Hello: david", assigns(:partial_with_locals)
- end
+ end
def test_bad_render_to_string_still_throws_exception
assert_raises(ActionView::MissingTemplate) { get :render_to_string_with_exception }
end
-
+
def test_render_to_string_that_throws_caught_exception_doesnt_break_assigns
assert_nothing_raised { get :render_to_string_with_caught_exception }
assert_equal "i'm before the render", assigns(:before)
@@ -715,7 +715,7 @@ EOS
def test_render_and_redirect
assert_raises(ActionController::DoubleRenderError) { get :render_and_redirect }
end
-
+
# specify the one exception to double render rule - render_to_string followed by render
def test_render_to_string_and_render
get :render_to_string_and_render
@@ -736,7 +736,7 @@ EOS
get :partials_list
assert_equal "goodbyeHello: davidHello: marygoodbye\n", @response.body
end
-
+
def test_partial_with_locals
get :partial_with_locals
assert_equal "Hello: david", @response.body
@@ -758,17 +758,17 @@ EOS
get :partial_collection
assert_equal "Hello: davidHello: mary", @response.body
end
-
+
def test_partial_collection_with_counter
get :partial_collection_with_counter
assert_equal "david0mary1", @response.body
end
-
+
def test_partial_collection_with_locals
get :partial_collection_with_locals
assert_equal "Bonjour: davidBonjour: mary", @response.body
end
-
+
def test_partial_collection_with_spacer
get :partial_collection_with_spacer
assert_equal "Hello: davidonly partialHello: mary", @response.body
@@ -793,12 +793,12 @@ EOS
get :partial_with_hash_object
assert_equal "Sam\nmaS\n", @response.body
end
-
+
def test_hash_partial_collection
get :partial_hash_collection
assert_equal "Pratik\nkitarP\nAmy\nymA\n", @response.body
end
-
+
def test_partial_hash_collection_with_locals
get :partial_hash_collection_with_locals
assert_equal "Hola: PratikHola: Amy", @response.body
@@ -808,25 +808,25 @@ EOS
get :partial_with_implicit_local_assignment
assert_equal "Hello: Marcel", @response.body
end
-
+
def test_render_missing_partial_template
assert_raises(ActionView::MissingTemplate) do
get :missing_partial
end
end
-
+
def test_render_text_with_assigns
get :render_text_with_assigns
assert_equal "world", assigns["hello"]
end
-
+
def test_update_page
get :update_page
assert_template nil
assert_equal 'text/javascript; charset=utf-8', @response.headers['type']
assert_equal 2, @response.body.split($/).length
end
-
+
def test_update_page_with_instance_variables
get :update_page_with_instance_variables
assert_template nil
@@ -834,7 +834,7 @@ EOS
assert_match /balance/, @response.body
assert_match /\$37/, @response.body
end
-
+
def test_yield_content_for
assert_not_deprecated { get :yield_content_for }
assert_equal "<title>Putting stuff in the title!</title>\n\nGreat stuff!\n", @response.body
@@ -906,12 +906,12 @@ EOS
get :render_with_location
assert_equal "http://example.com", @response.headers["Location"]
end
-
+
def test_rendering_xml_should_call_to_xml_if_possible
get :render_with_to_xml
assert_equal "<i-am-xml/>", @response.body
end
-
+
def test_rendering_with_object_location_should_set_header_with_url_for
ActionController::Routing::Routes.draw do |map|
map.resources :customers
@@ -941,5 +941,4 @@ EOS
get :render_using_layout_around_block_in_main_layout_and_within_content_for_layout
assert_equal "Before (Anthony)\nInside from first block in layout\nAfter\nBefore (David)\nInside from block\nAfter\nBefore (Ramm)\nInside from second block in layout\nAfter\n", @response.body
end
-
end
diff --git a/actionpack/test/controller/polymorphic_routes_test.rb b/actionpack/test/controller/polymorphic_routes_test.rb
index 4ec0d3cd4e..3f52526f08 100644
--- a/actionpack/test/controller/polymorphic_routes_test.rb
+++ b/actionpack/test/controller/polymorphic_routes_test.rb
@@ -118,6 +118,39 @@ uses_mocha 'polymorphic URL helpers' do
polymorphic_url([:site, :admin, @article, @response, @tag])
end
+ def test_nesting_with_array_ending_in_singleton_resource
+ expects(:article_response_url).with(@article)
+ polymorphic_url([@article, :response])
+ end
+
+ def test_nesting_with_array_containing_singleton_resource
+ @tag = Tag.new
+ @tag.save
+ expects(:article_response_tag_url).with(@article, @tag)
+ polymorphic_url([@article, :response, @tag])
+ end
+
+ def test_nesting_with_array_containing_namespace_and_singleton_resource
+ @tag = Tag.new
+ @tag.save
+ expects(:admin_article_response_tag_url).with(@article, @tag)
+ polymorphic_url([:admin, @article, :response, @tag])
+ end
+
+ def test_nesting_with_array_containing_singleton_resource_and_format
+ @tag = Tag.new
+ @tag.save
+ expects(:formatted_article_response_tag_url).with(@article, @tag, :pdf)
+ formatted_polymorphic_url([@article, :response, @tag, :pdf])
+ end
+
+ def test_nesting_with_array_containing_singleton_resource_and_format_option
+ @tag = Tag.new
+ @tag.save
+ expects(:article_response_tag_url).with(@article, @tag, :pdf)
+ polymorphic_url([@article, :response, @tag], :format => :pdf)
+ end
+
# TODO: Needs to be updated to correctly know about whether the object is in a hash or not
def xtest_with_hash
expects(:article_url).with(@article)
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index 066fa6acd4..65862c6b14 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -23,11 +23,11 @@ class TestController < ActionController::Base
def render_hello_world_with_forward_slash
render :template => "/test/hello_world"
end
-
+
def render_template_in_top_directory
render :template => 'shared'
end
-
+
def render_template_in_top_directory_with_slash
render :template => '/shared'
end
@@ -86,7 +86,7 @@ class TestController < ActionController::Base
def render_nothing_with_appendix
render :text => "appended"
end
-
+
def render_invalid_args
render("test/hello")
end
@@ -171,7 +171,7 @@ class TestController < ActionController::Base
def partial_dot_html
render :partial => 'partial.html.erb'
end
-
+
def partial_as_rjs
render :update do |page|
page.replace :foo, :partial => 'partial'
@@ -217,8 +217,8 @@ class TestController < ActionController::Base
end
end
-TestController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
-Fun::GamesController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
+TestController.view_paths = [FIXTURE_LOAD_PATH]
+Fun::GamesController.view_paths = [FIXTURE_LOAD_PATH]
class RenderTest < Test::Unit::TestCase
def setup
@@ -251,13 +251,13 @@ class RenderTest < Test::Unit::TestCase
get :render_hello_world_with_forward_slash
assert_template "test/hello_world"
end
-
+
def test_render_in_top_directory
get :render_template_in_top_directory
assert_template "shared"
assert_equal "Elastica", @response.body
end
-
+
def test_render_in_top_directory_with_slash
get :render_template_in_top_directory_with_slash
assert_template "shared"
@@ -336,11 +336,11 @@ class RenderTest < Test::Unit::TestCase
assert_response 200
assert_equal 'appended', @response.body
end
-
+
def test_attempt_to_render_with_invalid_arguments
assert_raises(ActionController::RenderError) { get :render_invalid_args }
end
-
+
def test_attempt_to_access_object_method
assert_raises(ActionController::UnknownAction, "No action responded to [clone]") { get :clone }
end
@@ -467,17 +467,17 @@ class RenderTest < Test::Unit::TestCase
get :formatted_html_erb
assert_equal 'formatted html erb', @response.body
end
-
+
def test_should_render_formatted_xml_erb_template
get :formatted_xml_erb, :format => :xml
assert_equal '<test>passed formatted xml erb</test>', @response.body
end
-
+
def test_should_render_formatted_html_erb_template
get :formatted_xml_erb
assert_equal '<test>passed formatted html erb</test>', @response.body
end
-
+
def test_should_render_formatted_html_erb_template_with_faulty_accepts_header
@request.env["HTTP_ACCEPT"] = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, appliction/x-shockwave-flash, */*"
get :formatted_xml_erb
@@ -520,7 +520,6 @@ class RenderTest < Test::Unit::TestCase
end
protected
-
def etag_for(text)
%("#{Digest::MD5.hexdigest(text)}")
end
diff --git a/actionpack/test/controller/send_file_test.rb b/actionpack/test/controller/send_file_test.rb
index 406825fe59..ddec51d173 100644
--- a/actionpack/test/controller/send_file_test.rb
+++ b/actionpack/test/controller/send_file_test.rb
@@ -1,13 +1,11 @@
require 'abstract_unit'
-
module TestFileUtils
def file_name() File.basename(__FILE__) end
def file_path() File.expand_path(__FILE__) end
def file_data() File.open(file_path, 'rb') { |f| f.read } end
end
-
class SendFileController < ActionController::Base
include TestFileUtils
layout "layouts/standard" # to make sure layouts don't interfere
@@ -21,7 +19,7 @@ class SendFileController < ActionController::Base
def rescue_action(e) raise end
end
-SendFileController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
+SendFileController.view_paths = [FIXTURE_LOAD_PATH]
class SendFileTest < Test::Unit::TestCase
include TestFileUtils
diff --git a/actionpack/test/controller/view_paths_test.rb b/actionpack/test/controller/view_paths_test.rb
index 1b4c1fae2f..9401c87d10 100644
--- a/actionpack/test/controller/view_paths_test.rb
+++ b/actionpack/test/controller/view_paths_test.rb
@@ -1,9 +1,7 @@
require 'abstract_unit'
class ViewLoadPathsTest < Test::Unit::TestCase
- LOAD_PATH_ROOT = File.join(File.dirname(__FILE__), '..', 'fixtures')
-
- ActionController::Base.view_paths = [LOAD_PATH_ROOT]
+ ActionController::Base.view_paths = [FIXTURE_LOAD_PATH]
class TestController < ActionController::Base
def self.controller_path() "test" end
@@ -16,7 +14,7 @@ class ViewLoadPathsTest < Test::Unit::TestCase
private
def add_view_path
- prepend_view_path "#{LOAD_PATH_ROOT}/override"
+ prepend_view_path "#{FIXTURE_LOAD_PATH}/override"
end
end
@@ -47,35 +45,35 @@ class ViewLoadPathsTest < Test::Unit::TestCase
end
def test_template_load_path_was_set_correctly
- assert_equal [ LOAD_PATH_ROOT ], @controller.view_paths.map(&:to_s)
+ assert_equal [FIXTURE_LOAD_PATH], @controller.view_paths
end
def test_controller_appends_view_path_correctly
@controller.append_view_path 'foo'
- assert_equal [LOAD_PATH_ROOT, 'foo'], @controller.view_paths.map(&:to_s)
+ assert_equal [FIXTURE_LOAD_PATH, 'foo'], @controller.view_paths
@controller.append_view_path(%w(bar baz))
- assert_equal [LOAD_PATH_ROOT, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s)
+ assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths
- @controller.append_view_path(LOAD_PATH_ROOT)
- assert_equal ['foo', 'bar', 'baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s)
+ @controller.append_view_path(FIXTURE_LOAD_PATH)
+ assert_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths
- @controller.append_view_path([LOAD_PATH_ROOT])
- assert_equal ['foo', 'bar', 'baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s)
+ @controller.append_view_path([FIXTURE_LOAD_PATH])
+ assert_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths
end
def test_controller_prepends_view_path_correctly
@controller.prepend_view_path 'baz'
- assert_equal ['baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s)
+ assert_equal ['baz', FIXTURE_LOAD_PATH], @controller.view_paths
@controller.prepend_view_path(%w(foo bar))
- assert_equal ['foo', 'bar', 'baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s)
+ assert_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths
- @controller.prepend_view_path(LOAD_PATH_ROOT)
- assert_equal [LOAD_PATH_ROOT, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s)
+ @controller.prepend_view_path(FIXTURE_LOAD_PATH)
+ assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths
- @controller.prepend_view_path([LOAD_PATH_ROOT])
- assert_equal [LOAD_PATH_ROOT, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s)
+ @controller.prepend_view_path([FIXTURE_LOAD_PATH])
+ assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths
end
def test_template_appends_view_path_correctly
@@ -83,10 +81,10 @@ class ViewLoadPathsTest < Test::Unit::TestCase
class_view_paths = TestController.view_paths
@controller.append_view_path 'foo'
- assert_equal [LOAD_PATH_ROOT, 'foo'], @controller.view_paths.map(&:to_s)
+ assert_equal [FIXTURE_LOAD_PATH, 'foo'], @controller.view_paths
@controller.append_view_path(%w(bar baz))
- assert_equal [LOAD_PATH_ROOT, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s)
+ assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths
assert_equal class_view_paths, TestController.view_paths
end
@@ -95,10 +93,10 @@ class ViewLoadPathsTest < Test::Unit::TestCase
class_view_paths = TestController.view_paths
@controller.prepend_view_path 'baz'
- assert_equal ['baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s)
+ assert_equal ['baz', FIXTURE_LOAD_PATH], @controller.view_paths
@controller.prepend_view_path(%w(foo bar))
- assert_equal ['foo', 'bar', 'baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s)
+ assert_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths
assert_equal class_view_paths, TestController.view_paths
end
@@ -109,7 +107,7 @@ class ViewLoadPathsTest < Test::Unit::TestCase
end
def test_view_paths_override
- TestController.prepend_view_path "#{LOAD_PATH_ROOT}/override"
+ TestController.prepend_view_path "#{FIXTURE_LOAD_PATH}/override"
get :hello_world
assert_response :success
assert_equal "Hello overridden world!", @response.body
@@ -117,7 +115,7 @@ class ViewLoadPathsTest < Test::Unit::TestCase
def test_view_paths_override_for_layouts_in_controllers_with_a_module
@controller = Test::SubController.new
- Test::SubController.view_paths = [ "#{LOAD_PATH_ROOT}/override", LOAD_PATH_ROOT, "#{LOAD_PATH_ROOT}/override2" ]
+ Test::SubController.view_paths = [ "#{FIXTURE_LOAD_PATH}/override", FIXTURE_LOAD_PATH, "#{FIXTURE_LOAD_PATH}/override2" ]
get :hello_world
assert_response :success
assert_equal "layout: Hello overridden world!", @response.body
@@ -140,13 +138,13 @@ class ViewLoadPathsTest < Test::Unit::TestCase
A.view_paths = ['a/path']
- assert_equal ['a/path'], A.view_paths.map(&:to_s)
+ assert_equal ['a/path'], A.view_paths
assert_equal A.view_paths, B.view_paths
assert_equal original_load_paths, C.view_paths
C.view_paths = []
assert_nothing_raised { C.view_paths << 'c/path' }
- assert_equal ['c/path'], C.view_paths.map(&:to_s)
+ assert_equal ['c/path'], C.view_paths
end
def test_find_template_file_for_path
diff --git a/actionpack/test/fixtures/test/hello.builder b/actionpack/test/fixtures/test/hello.builder
index 82a4a310d3..86a8bb3d7b 100644
--- a/actionpack/test/fixtures/test/hello.builder
+++ b/actionpack/test/fixtures/test/hello.builder
@@ -1,4 +1,4 @@
xml.html do
xml.p "Hello #{@name}"
- xml << render_file("test/greeting")
+ xml << render("test/greeting")
end \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/non_erb_block_content_for.builder b/actionpack/test/fixtures/test/non_erb_block_content_for.builder
index 6ff6db0f95..a94643561c 100644
--- a/actionpack/test/fixtures/test/non_erb_block_content_for.builder
+++ b/actionpack/test/fixtures/test/non_erb_block_content_for.builder
@@ -1,4 +1,4 @@
content_for :title do
'Putting stuff in the title!'
end
-xml << "\nGreat stuff!" \ No newline at end of file
+xml << "\nGreat stuff!"
diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb
index 11b3bdb3fa..3faa363459 100755
--- a/actionpack/test/template/date_helper_test.rb
+++ b/actionpack/test/template/date_helper_test.rb
@@ -1155,6 +1155,30 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, date_select("post", "written_on", {}, :class => 'selector')
end
+ def test_date_select_with_html_options_within_fields_for
+ @post = Post.new
+ @post.written_on = Date.new(2004, 6, 15)
+
+ fields_for :post, @post do |f|
+ concat f.date_select(:written_on, {}, :class => 'selector')
+ end
+
+ expected = %{<select id="post_written_on_1i" name="post[written_on(1i)]" class="selector">\n}
+ expected << %{<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 value="2004" selected="selected">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}
+ expected << "</select>\n"
+
+ expected << %{<select id="post_written_on_2i" name="post[written_on(2i)]" class="selector">\n}
+ expected << %{<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 value="6" selected="selected">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}
+ expected << "</select>\n"
+
+ expected << %{<select id="post_written_on_3i" name="post[written_on(3i)]" class="selector">\n}
+ expected << %{<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 value="15" selected="selected">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}
+
+ expected << "</select>\n"
+
+ assert_dom_equal expected, output_buffer
+ end
+
def test_time_select
@post = Post.new
@post.written_on = Time.local(2004, 6, 15, 15, 16, 35)
@@ -1216,6 +1240,29 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, time_select("post", "written_on", {}, :class => 'selector')
end
+ def test_time_select_with_html_options_within_fields_for
+ @post = Post.new
+ @post.written_on = Time.local(2004, 6, 15, 15, 16, 35)
+
+ fields_for :post, @post do |f|
+ concat f.time_select(:written_on, {}, :class => 'selector')
+ end
+
+ expected = %{<input type="hidden" id="post_written_on_1i" name="post[written_on(1i)]" value="2004" />\n}
+ expected << %{<input type="hidden" id="post_written_on_2i" name="post[written_on(2i)]" value="6" />\n}
+ expected << %{<input type="hidden" id="post_written_on_3i" name="post[written_on(3i)]" value="15" />\n}
+
+ expected << %(<select id="post_written_on_4i" name="post[written_on(4i)]" class="selector">\n)
+ 0.upto(23) { |i| expected << %(<option value="#{leading_zero_on_single_digits(i)}"#{' selected="selected"' if i == 15}>#{leading_zero_on_single_digits(i)}</option>\n) }
+ expected << "</select>\n"
+ expected << " : "
+ expected << %(<select id="post_written_on_5i" name="post[written_on(5i)]" class="selector">\n)
+ 0.upto(59) { |i| expected << %(<option value="#{leading_zero_on_single_digits(i)}"#{' selected="selected"' if i == 16}>#{leading_zero_on_single_digits(i)}</option>\n) }
+ expected << "</select>\n"
+
+ assert_dom_equal expected, output_buffer
+ end
+
def test_datetime_select
@post = Post.new
@post.updated_at = Time.local(2004, 6, 15, 16, 35)
@@ -1281,21 +1328,21 @@ class DateHelperTest < ActionView::TestCase
end
end
- def test_datetime_select_within_fields_for
+ def test_datetime_select_with_html_options_within_fields_for
@post = Post.new
@post.updated_at = Time.local(2004, 6, 15, 16, 35)
fields_for :post, @post do |f|
- concat f.datetime_select(:updated_at)
+ concat f.datetime_select(:updated_at, {}, :class => 'selector')
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"
- expected << "<select id='post_updated_at_2i' name='post[updated_at(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_updated_at_3i' name='post[updated_at(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"
- 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"
+ expected = "<select id='post_updated_at_1i' name='post[updated_at(1i)]' class='selector'>\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_updated_at_2i' name='post[updated_at(2i)]' class='selector'>\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_updated_at_3i' name='post[updated_at(3i)]' class='selector'>\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"
+ expected << " &mdash; <select id='post_updated_at_4i' name='post[updated_at(4i)]' class='selector'>\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)]' class='selector'>\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, output_buffer)
+ assert_dom_equal expected, output_buffer
end
def test_date_select_with_zero_value_and_no_start_year
diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb
index 3f89a5e426..1db3a4d7d8 100644
--- a/actionpack/test/template/form_options_helper_test.rb
+++ b/actionpack/test/template/form_options_helper_test.rb
@@ -1300,6 +1300,24 @@ COUNTRIES
html
end
+ uses_mocha "time_zone_select_with_priority_zones_as_regexp" do
+ def test_time_zone_select_with_priority_zones_as_regexp
+ @firm = Firm.new("D")
+ MockTimeZone.any_instance.stubs(:=~).returns(true,false,false,true,false)
+
+ html = time_zone_select("firm", "time_zone", /A|D/)
+ assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" +
+ "<option value=\"A\">A</option>\n" +
+ "<option value=\"D\" selected=\"selected\">D</option>" +
+ "<option value=\"\" disabled=\"disabled\">-------------</option>\n" +
+ "<option value=\"B\">B</option>\n" +
+ "<option value=\"C\">C</option>\n" +
+ "<option value=\"E\">E</option>" +
+ "</select>",
+ html
+ end
+ end
+
def test_time_zone_select_with_default_time_zone_and_nil_value
@firm = Firm.new()
@firm.time_zone = nil
diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb
index 47b3605849..eabbe9c8a0 100644
--- a/actionpack/test/template/form_tag_helper_test.rb
+++ b/actionpack/test/template/form_tag_helper_test.rb
@@ -35,21 +35,23 @@ class FormTagHelperTest < ActionView::TestCase
expected = %(<form action="http://www.example.com" method="post"><div style='margin:0;padding:0'><input type="hidden" name="_method" value="put" /></div>)
assert_dom_equal expected, actual
end
-
+
def test_form_tag_with_method_delete
actual = form_tag({}, { :method => :delete })
expected = %(<form action="http://www.example.com" method="post"><div style='margin:0;padding:0'><input type="hidden" name="_method" value="delete" /></div>)
assert_dom_equal expected, actual
end
- def test_form_tag_with_block
+ def test_form_tag_with_block_in_erb
+ __in_erb_template = ''
form_tag("http://example.com") { concat "Hello world!" }
expected = %(<form action="http://example.com" method="post">Hello world!</form>)
assert_dom_equal expected, output_buffer
end
- def test_form_tag_with_block_and_method
+ def test_form_tag_with_block_and_method_in_erb
+ __in_erb_template = ''
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>)
@@ -88,11 +90,11 @@ class FormTagHelperTest < ActionView::TestCase
actual = radio_button_tag("gender", "m") + radio_button_tag("gender", "f")
expected = %(<input id="gender_m" name="gender" type="radio" value="m" /><input id="gender_f" name="gender" type="radio" value="f" />)
assert_dom_equal expected, actual
-
+
actual = radio_button_tag("opinion", "-1") + radio_button_tag("opinion", "1")
expected = %(<input id="opinion_-1" name="opinion" type="radio" value="-1" /><input id="opinion_1" name="opinion" type="radio" value="1" />)
assert_dom_equal expected, actual
-
+
actual = radio_button_tag("person[gender]", "m")
expected = %(<input id="person_gender_m" name="person[gender]" type="radio" value="m" />)
assert_dom_equal expected, actual
@@ -103,13 +105,13 @@ class FormTagHelperTest < ActionView::TestCase
expected = %(<select id="people" name="people"><option>david</option></select>)
assert_dom_equal expected, actual
end
-
+
def test_select_tag_with_multiple
actual = select_tag "colors", "<option>Red</option><option>Blue</option><option>Green</option>", :multiple => :true
expected = %(<select id="colors" multiple="multiple" name="colors"><option>Red</option><option>Blue</option><option>Green</option></select>)
assert_dom_equal expected, actual
end
-
+
def test_select_tag_disabled
actual = select_tag "places", "<option>Home</option><option>Work</option><option>Pub</option>", :disabled => :true
expected = %(<select id="places" disabled="disabled" name="places"><option>Home</option><option>Work</option><option>Pub</option></select>)
@@ -145,37 +147,37 @@ class FormTagHelperTest < ActionView::TestCase
expected = %(<input class="admin" id="title" name="title" type="text" value="Hello!" />)
assert_dom_equal expected, actual
end
-
+
def test_text_field_tag_size_symbol
actual = text_field_tag "title", "Hello!", :size => 75
expected = %(<input id="title" name="title" size="75" type="text" value="Hello!" />)
assert_dom_equal expected, actual
end
-
+
def test_text_field_tag_size_string
actual = text_field_tag "title", "Hello!", "size" => "75"
expected = %(<input id="title" name="title" size="75" type="text" value="Hello!" />)
assert_dom_equal expected, actual
end
-
+
def test_text_field_tag_maxlength_symbol
actual = text_field_tag "title", "Hello!", :maxlength => 75
expected = %(<input id="title" name="title" maxlength="75" type="text" value="Hello!" />)
assert_dom_equal expected, actual
end
-
+
def test_text_field_tag_maxlength_string
actual = text_field_tag "title", "Hello!", "maxlength" => "75"
expected = %(<input id="title" name="title" maxlength="75" type="text" value="Hello!" />)
assert_dom_equal expected, actual
end
-
+
def test_text_field_disabled
actual = text_field_tag "title", "Hello!", :disabled => :true
expected = %(<input id="title" name="title" disabled="disabled" type="text" value="Hello!" />)
assert_dom_equal expected, actual
end
-
+
def test_text_field_tag_with_multiple_options
actual = text_field_tag "title", "Hello!", :size => 70, :maxlength => 80
expected = %(<input id="title" name="title" size="70" maxlength="80" type="text" value="Hello!" />)
@@ -226,12 +228,13 @@ class FormTagHelperTest < ActionView::TestCase
submit_tag("Save", :confirm => "Are you sure?")
)
end
-
+
def test_pass
assert_equal 1, 1
end
- def test_field_set_tag
+ def test_field_set_tag_in_erb
+ __in_erb_template = ''
field_set_tag("Your details") { concat "Hello world!" }
expected = %(<fieldset><legend>Your details</legend>Hello world!</fieldset>)
diff --git a/actionpack/test/template/javascript_helper_test.rb b/actionpack/test/template/javascript_helper_test.rb
index 8c649ea544..d6d398d224 100644
--- a/actionpack/test/template/javascript_helper_test.rb
+++ b/actionpack/test/template/javascript_helper_test.rb
@@ -48,7 +48,7 @@ class JavaScriptHelperTest < ActionView::TestCase
end
def test_link_to_function_with_href
- assert_dom_equal %(<a href="http://example.com/" onclick="alert('Hello world!'); return false;">Greeting</a>),
+ assert_dom_equal %(<a href="http://example.com/" onclick="alert('Hello world!'); return false;">Greeting</a>),
link_to_function("Greeting", "alert('Hello world!')", :href => 'http://example.com/')
end
@@ -95,12 +95,14 @@ class JavaScriptHelperTest < ActionView::TestCase
javascript_tag("alert('hello')", :id => "the_js_tag")
end
- def test_javascript_tag_with_block
+ def test_javascript_tag_with_block_in_erb
+ __in_erb_template = ''
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
+ def test_javascript_tag_with_block_and_options_in_erb
+ __in_erb_template = ''
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
diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb
index a5be0d2789..60b83b476d 100644
--- a/actionpack/test/template/prototype_helper_test.rb
+++ b/actionpack/test/template/prototype_helper_test.rb
@@ -54,7 +54,7 @@ class PrototypeHelperBaseTest < ActionView::TestCase
end
def create_generator
- block = Proc.new { |*args| yield *args if block_given? }
+ block = Proc.new { |*args| yield *args if block_given? }
JavaScriptGenerator.new self, &block
end
end
@@ -70,7 +70,7 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
assert_dom_equal %(<a class=\"fine\" href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true}); return false;\">Remote outauthor</a>),
link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }}, { :class => "fine" })
assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onComplete:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
- link_to_remote("Remote outauthor", :complete => "alert(request.responseText)", :url => { :action => "whatnot" })
+ link_to_remote("Remote outauthor", :complete => "alert(request.responseText)", :url => { :action => "whatnot" })
assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onSuccess:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
link_to_remote("Remote outauthor", :success => "alert(request.responseText)", :url => { :action => "whatnot" })
assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
@@ -78,12 +78,12 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot?a=10&amp;b=20', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
link_to_remote("Remote outauthor", :failure => "alert(request.responseText)", :url => { :action => "whatnot", :a => '10', :b => '20' })
end
-
+
def test_link_to_remote_html_options
assert_dom_equal %(<a class=\"fine\" href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true}); return false;\">Remote outauthor</a>),
link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :html => { :class => "fine" } })
end
-
+
def test_link_to_remote_url_quote_escaping
assert_dom_equal %(<a href="#" onclick="new Ajax.Request('http://www.example.com/whatnot\\\'s', {asynchronous:true, evalScripts:true}); return false;">Remote</a>),
link_to_remote("Remote", { :url => { :action => "whatnot's" } })
@@ -93,14 +93,14 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
assert_dom_equal %(<script type="text/javascript">\n//<![CDATA[\nnew PeriodicalExecuter(function() {new Ajax.Updater('schremser_bier', 'http://www.example.com/mehr_bier', {asynchronous:true, evalScripts:true})}, 10)\n//]]>\n</script>),
periodically_call_remote(:update => "schremser_bier", :url => { :action => "mehr_bier" })
end
-
+
def test_periodically_call_remote_with_frequency
assert_dom_equal(
"<script type=\"text/javascript\">\n//<![CDATA[\nnew PeriodicalExecuter(function() {new Ajax.Request('http://www.example.com/', {asynchronous:true, evalScripts:true})}, 2)\n//]]>\n</script>",
periodically_call_remote(:frequency => 2)
)
end
-
+
def test_form_remote_tag
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;\">),
form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast })
@@ -117,21 +117,22 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :html => { :method => :put })
end
- def test_form_remote_tag_with_block
+ def test_form_remote_tag_with_block_in_erb
+ __in_erb_template = ''
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
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, output_buffer
end
def test_remote_form_for_with_record_identification_without_html_options
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, output_buffer
end
@@ -139,23 +140,23 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
def test_remote_form_for_with_record_identification_with_existing_record
@record.save
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, output_buffer
end
def test_remote_form_for_with_new_object_in_list
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, output_buffer
end
-
+
def test_remote_form_for_with_existing_object_in_list
@author.save
@article.save
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, output_buffer
end
@@ -172,18 +173,18 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({success:'glass_of_beer',failure:'glass_of_water'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
form_remote_tag(:update => { :success => "glass_of_beer", :failure => "glass_of_water" }, :url => { :action => :fast }, callback=>"monkeys();")
end
-
+
#HTTP status codes 200 up to 599 have callbacks
#these should work
100.upto(599) do |callback|
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, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
end
-
+
#test 200 and 404
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, on200:function(request){monkeys();}, on404:function(request){bananas();}, parameters:Form.serialize(this)}); return false;">),
form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, 200=>"monkeys();", 404=>"bananas();")
-
+
#these shouldn't
1.upto(99) do |callback|
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;">),
@@ -193,44 +194,44 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
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;">),
form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
end
-
+
#test ultimate combo
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, on200:function(request){monkeys();}, on404:function(request){bananas();}, onComplete:function(request){c();}, onFailure:function(request){f();}, onLoading:function(request){c1()}, onSuccess:function(request){s()}, parameters:Form.serialize(this)}); return false;\">),
form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :loading => "c1()", :success => "s()", :failure => "f();", :complete => "c();", 200=>"monkeys();", 404=>"bananas();")
-
+
end
-
+
def test_submit_to_remote
assert_dom_equal %(<input name=\"More beer!\" onclick=\"new Ajax.Updater('empty_bottle', 'http://www.example.com/', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)}); return false;\" type=\"button\" value=\"1000000\" />),
submit_to_remote("More beer!", 1_000_000, :update => "empty_bottle")
end
-
+
def test_observe_field
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/reorder_if_empty', {asynchronous:true, evalScripts:true, parameters:value})})\n//]]>\n</script>),
observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" })
end
-
+
def test_observe_field_using_with_option
expected = %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/check_value', {asynchronous:true, evalScripts:true, parameters:'id=' + encodeURIComponent(value)})})\n//]]>\n</script>)
assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id')
assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + encodeURIComponent(value)")
end
-
+
def test_observe_field_using_json_in_with_option
expected = %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/check_value', {asynchronous:true, evalScripts:true, parameters:{'id':value}})})\n//]]>\n</script>)
- assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}")
+ assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}")
end
-
+
def test_observe_field_using_function_for_callback
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {alert('Element changed')})\n//]]>\n</script>),
observe_field("glass", :frequency => 5.minutes, :function => "alert('Element changed')")
end
-
+
def test_observe_form
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Observer('cart', 2, function(element, value) {new Ajax.Request('http://www.example.com/cart_changed', {asynchronous:true, evalScripts:true, parameters:value})})\n//]]>\n</script>),
observe_form("cart", :frequency => 2, :url => { :action => "cart_changed" })
end
-
+
def test_observe_form_using_function_for_callback
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Observer('cart', 2, function(element, value) {alert('Form changed')})\n//]]>\n</script>),
observe_form("cart", :frequency => 2, :function => "alert('Form changed')")
@@ -245,7 +246,7 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
block = Proc.new { |page| page.replace_html('foo', 'bar') }
assert_equal create_generator(&block).to_s, update_page(&block)
end
-
+
def test_update_page_tag
block = Proc.new { |page| page.replace_html('foo', 'bar') }
assert_equal javascript_tag(create_generator(&block).to_s), update_page_tag(&block)
@@ -261,15 +262,15 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
def author_path(record)
"/authors/#{record.id}"
end
-
+
def authors_path
"/authors"
end
-
+
def author_articles_path(author)
"/authors/#{author.id}/articles"
end
-
+
def author_article_path(author, article)
"/authors/#{author.id}/articles/#{article.id}"
end
@@ -280,7 +281,7 @@ class JavaScriptGeneratorTest < PrototypeHelperBaseTest
super
@generator = create_generator
end
-
+
def test_insert_html_with_string
assert_equal 'new Insertion.Top("element", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");',
@generator.insert_html(:top, 'element', '<p>This is a test</p>')
@@ -291,56 +292,56 @@ class JavaScriptGeneratorTest < PrototypeHelperBaseTest
assert_equal 'new Insertion.After("element", "\\u003Cp\u003EThis is a test\\u003C/p\u003E");',
@generator.insert_html(:after, 'element', '<p>This is a test</p>')
end
-
+
def test_replace_html_with_string
assert_equal 'Element.update("element", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");',
@generator.replace_html('element', '<p>This is a test</p>')
end
-
+
def test_replace_element_with_string
assert_equal 'Element.replace("element", "\\u003Cdiv id=\"element\"\\u003E\\u003Cp\\u003EThis is a test\\u003C/p\\u003E\\u003C/div\\u003E");',
@generator.replace('element', '<div id="element"><p>This is a test</p></div>')
end
-
+
def test_remove
assert_equal 'Element.remove("foo");',
@generator.remove('foo')
assert_equal '["foo", "bar", "baz"].each(Element.remove);',
@generator.remove('foo', 'bar', 'baz')
end
-
+
def test_show
assert_equal 'Element.show("foo");',
@generator.show('foo')
assert_equal '["foo", "bar", "baz"].each(Element.show);',
- @generator.show('foo', 'bar', 'baz')
+ @generator.show('foo', 'bar', 'baz')
end
-
+
def test_hide
assert_equal 'Element.hide("foo");',
@generator.hide('foo')
assert_equal '["foo", "bar", "baz"].each(Element.hide);',
- @generator.hide('foo', 'bar', 'baz')
+ @generator.hide('foo', 'bar', 'baz')
end
-
+
def test_toggle
assert_equal 'Element.toggle("foo");',
@generator.toggle('foo')
assert_equal '["foo", "bar", "baz"].each(Element.toggle);',
- @generator.toggle('foo', 'bar', 'baz')
+ @generator.toggle('foo', 'bar', 'baz')
end
-
+
def test_alert
assert_equal 'alert("hello");', @generator.alert('hello')
end
-
+
def test_redirect_to
assert_equal 'window.location.href = "http://www.example.com/welcome";',
@generator.redirect_to(:action => 'welcome')
assert_equal 'window.location.href = "http://www.example.com/welcome?a=b&c=d";',
@generator.redirect_to("http://www.example.com/welcome?a=b&c=d")
end
-
+
def test_reload
assert_equal 'window.location.reload();',
@generator.reload
@@ -350,16 +351,16 @@ class JavaScriptGeneratorTest < PrototypeHelperBaseTest
@generator.delay(20) do
@generator.hide('foo')
end
-
+
assert_equal "setTimeout(function() {\n;\nElement.hide(\"foo\");\n}, 20000);", @generator.to_s
end
-
+
def test_to_s
@generator.insert_html(:top, 'element', '<p>This is a test</p>')
@generator.insert_html(:bottom, 'element', '<p>This is a test</p>')
@generator.remove('foo', 'bar')
@generator.replace_html('baz', '<p>This is a test</p>')
-
+
assert_equal <<-EOS.chomp, @generator.to_s
new Insertion.Top("element", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
new Insertion.Bottom("element", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
@@ -381,12 +382,12 @@ Element.update("baz", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
@generator['hello'].hide
assert_equal %($("hello").hide();), @generator.to_s
end
-
+
def test_element_proxy_variable_access
@generator['hello']['style']
assert_equal %($("hello").style;), @generator.to_s
end
-
+
def test_element_proxy_variable_access_with_assignment
@generator['hello']['style']['color'] = 'red'
assert_equal %($("hello").style.color = "red";), @generator.to_s
@@ -401,7 +402,7 @@ Element.update("baz", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
@generator['hello'].hide("first").clean_whitespace
assert_equal %($("hello").hide("first").cleanWhitespace();), @generator.to_s
end
-
+
def test_select_access
assert_equal %($$("div.hello");), @generator.select('div.hello')
end
@@ -410,29 +411,29 @@ Element.update("baz", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
@generator.select('p.welcome b').first.hide
assert_equal %($$("p.welcome b").first().hide();), @generator.to_s
end
-
+
def test_visual_effect
- assert_equal %(new Effect.Puff("blah",{});),
+ assert_equal %(new Effect.Puff("blah",{});),
@generator.visual_effect(:puff,'blah')
- end
-
+ end
+
def test_visual_effect_toggle
- assert_equal %(Effect.toggle("blah",'appear',{});),
+ assert_equal %(Effect.toggle("blah",'appear',{});),
@generator.visual_effect(:toggle_appear,'blah')
end
-
+
def test_sortable
- assert_equal %(Sortable.create("blah", {onUpdate:function(){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize("blah")})}});),
+ assert_equal %(Sortable.create("blah", {onUpdate:function(){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize("blah")})}});),
@generator.sortable('blah', :url => { :action => "order" })
end
-
+
def test_draggable
- assert_equal %(new Draggable("blah", {});),
+ assert_equal %(new Draggable("blah", {});),
@generator.draggable('blah')
end
-
+
def test_drop_receiving
- assert_equal %(Droppables.add("blah", {onDrop:function(element){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:'id=' + encodeURIComponent(element.id)})}});),
+ assert_equal %(Droppables.add("blah", {onDrop:function(element){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:'id=' + encodeURIComponent(element.id)})}});),
@generator.drop_receiving('blah', :url => { :action => "order" })
end
@@ -534,7 +535,7 @@ return array.reverse();
});
EOS
end
-
+
def test_collection_proxy_with_find_all
@generator.select('p').find_all 'a' do |value, index|
@generator << '(value.className == "welcome")'
@@ -546,7 +547,7 @@ return (value.className == "welcome");
});
EOS
end
-
+
def test_collection_proxy_with_in_groups_of
@generator.select('p').in_groups_of('a', 3)
@generator.select('p').in_groups_of('a', 3, 'x')
@@ -555,13 +556,13 @@ var a = $$("p").inGroupsOf(3);
var a = $$("p").inGroupsOf(3, "x");
EOS
end
-
+
def test_collection_proxy_with_each_slice
@generator.select('p').each_slice('a', 3)
@generator.select('p').each_slice('a', 3) do |group, index|
group.reverse
end
-
+
assert_equal <<-EOS.strip, @generator.to_s
var a = $$("p").eachSlice(3);
var a = $$("p").eachSlice(3, function(value, index) {
@@ -569,7 +570,7 @@ return value.reverse();
});
EOS
end
-
+
def test_debug_rjs
ActionView::Base.debug_rjs = true
@generator['welcome'].replace_html 'Welcome'
@@ -577,7 +578,7 @@ return value.reverse();
ensure
ActionView::Base.debug_rjs = false
end
-
+
def test_literal
literal = @generator.literal("function() {}")
assert_equal "function() {}", literal.to_json
@@ -588,7 +589,7 @@ return value.reverse();
@generator.form.focus('my_field')
assert_equal "Form.focus(\"my_field\");", @generator.to_s
end
-
+
def test_call_with_block
@generator.call(:before)
@generator.call(:my_method) do |p|
@@ -601,7 +602,7 @@ return value.reverse();
end
assert_equal "before();\nmy_method(function() { $(\"one\").show();\n$(\"two\").hide(); });\nin_between();\nmy_method_with_arguments(true, \"hello\", function() { $(\"three\").visualEffect(\"highlight\"); });", @generator.to_s
end
-
+
def test_class_proxy_call_with_block
@generator.my_object.my_method do |p|
p[:one].show
diff --git a/actionpack/test/template/record_tag_helper_test.rb b/actionpack/test/template/record_tag_helper_test.rb
index 441dc6b720..34a200b933 100644
--- a/actionpack/test/template/record_tag_helper_test.rb
+++ b/actionpack/test/template/record_tag_helper_test.rb
@@ -2,7 +2,7 @@ require 'abstract_unit'
class Post
def id
- 45
+ 45
end
def body
"What a wonderful world!"
@@ -15,35 +15,36 @@ class RecordTagHelperTest < ActionView::TestCase
def setup
@post = Post.new
end
-
+
def test_content_tag_for
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
expected = %(<ul class="post" id="archived_post_45"></ul>)
actual = content_tag_for(:ul, @post, :archived) { }
- assert_dom_equal expected, actual
+ assert_dom_equal expected, actual
end
-
+
def test_content_tag_for_with_extra_html_tags
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
+ assert_dom_equal expected, actual
end
-
- def test_block_works_with_content_tag_for
+
+ def test_block_works_with_content_tag_for_in_erb
+ __in_erb_template = ''
expected = %(<tr class="post" id="post_45">#{@post.body}</tr>)
actual = content_tag_for(:tr, @post) { concat @post.body }
- assert_dom_equal expected, actual
+ assert_dom_equal expected, actual
end
-
- def test_div_for
+
+ def test_div_for_in_erb
+ __in_erb_template = ''
expected = %(<div class="post bar" id="post_45">#{@post.body}</div>)
actual = div_for(@post, :class => "bar") { concat @post.body }
assert_dom_equal expected, actual
- end
-
+ end
end
diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb
new file mode 100644
index 0000000000..54e4bbda1b
--- /dev/null
+++ b/actionpack/test/template/render_test.rb
@@ -0,0 +1,122 @@
+require 'abstract_unit'
+require 'controller/fake_models'
+
+class ViewRenderTest < Test::Unit::TestCase
+ def setup
+ @assigns = { :secret => 'in the sauce' }
+ @view = ActionView::Base.new([FIXTURE_LOAD_PATH], @assigns)
+ end
+
+ def test_render_file
+ assert_equal "Hello world!", @view.render("test/hello_world.erb")
+ end
+
+ def test_render_file_not_using_full_path
+ assert_equal "Hello world!", @view.render(:file => "test/hello_world.erb", :use_full_path => true)
+ end
+
+ def test_render_file_without_specific_extension
+ assert_equal "Hello world!", @view.render("test/hello_world")
+ end
+
+ def test_render_file_with_full_path
+ template_path = File.join(File.dirname(__FILE__), '../fixtures/test/hello_world.erb')
+ assert_equal "Hello world!", @view.render(:file => template_path, :use_full_path => false)
+ end
+
+ def test_render_file_with_instance_variables
+ assert_equal "The secret is in the sauce\n", @view.render("test/render_file_with_ivar.erb")
+ end
+
+ def test_render_file_with_locals
+ locals = { :secret => 'in the sauce' }
+ assert_equal "The secret is in the sauce\n", @view.render("test/render_file_with_locals.erb", locals)
+ end
+
+ def test_render_file_not_using_full_path_with_dot_in_path
+ assert_equal "The secret is in the sauce\n", @view.render("test/dot.directory/render_file_with_ivar")
+ end
+
+ def test_render_update
+ # TODO: You should not have to stub out template because template is self!
+ @view.instance_variable_set(:@template, @view)
+ assert_equal 'alert("Hello, World!");', @view.render(:update) { |page| page.alert('Hello, World!') }
+ end
+
+ def test_render_partial
+ assert_equal "only partial", @view.render(:partial => "test/partial_only")
+ end
+
+ def test_render_partial_with_errors
+ assert_raise(ActionView::TemplateError) { @view.render(:partial => "test/raise") }
+ end
+
+ def test_render_partial_collection
+ assert_equal "Hello: davidHello: mary", @view.render(:partial => "test/customer", :collection => [ Customer.new("david"), Customer.new("mary") ])
+ end
+
+ # TODO: The reason for this test is unclear, improve documentation
+ def test_render_partial_and_fallback_to_layout
+ assert_equal "Before (Josh)\n\nAfter", @view.render(:partial => "test/layout_for_partial", :locals => { :name => "Josh" })
+ end
+
+ # TODO: The reason for this test is unclear, improve documentation
+ def test_render_js_partial_and_fallback_to_erb_layout
+ @view.template_format = :js
+ assert_equal "Before (Josh)\n\nAfter", @view.render(:partial => "test/layout_for_partial", :locals => { :name => "Josh" })
+ end
+
+ # TODO: The reason for this test is unclear, improve documentation
+ def test_render_missing_xml_partial_and_raise_missing_template
+ @view.template_format = :xml
+ assert_raise(ActionView::MissingTemplate) { @view.render(:partial => "test/layout_for_partial") }
+ end
+
+ def test_render_inline
+ assert_equal "Hello, World!", @view.render(:inline => "Hello, World!")
+ end
+
+ def test_render_inline_with_locals
+ assert_equal "Hello, Josh!", @view.render(:inline => "Hello, <%= name %>!", :locals => { :name => "Josh" })
+ end
+
+ def test_render_fallbacks_to_erb_for_unknown_types
+ assert_equal "Hello, World!", @view.render(:inline => "Hello, World!", :type => :foo)
+ end
+
+ class CustomHandler < ActionView::TemplateHandler
+ def render(template)
+ [template.source, template.locals].inspect
+ end
+ end
+
+ def test_render_inline_with_custom_type
+ ActionView::Template.register_template_handler :foo, CustomHandler
+ assert_equal '["Hello, World!", {}]', @view.render(:inline => "Hello, World!", :type => :foo)
+ end
+
+ def test_render_inline_with_locals_and_custom_type
+ ActionView::Template.register_template_handler :foo, CustomHandler
+ assert_equal '["Hello, <%= name %>!", {:name=>"Josh"}]', @view.render(:inline => "Hello, <%= name %>!", :locals => { :name => "Josh" }, :type => :foo)
+ end
+
+ class CompilableCustomHandler < ActionView::TemplateHandler
+ include ActionView::TemplateHandlers::Compilable
+
+ def compile(template)
+ "@output_buffer = ''\n" +
+ "@output_buffer << 'locals: #{template.locals.inspect}, '\n" +
+ "@output_buffer << 'source: #{template.source.inspect}'\n"
+ end
+ end
+
+ def test_render_inline_with_compilable_custom_type
+ ActionView::Template.register_template_handler :foo, CompilableCustomHandler
+ assert_equal 'locals: {}, source: "Hello, World!"', @view.render(:inline => "Hello, World!", :type => :foo)
+ end
+
+ def test_render_inline_with_locals_and_compilable_custom_type
+ ActionView::Template.register_template_handler :foo, CompilableCustomHandler
+ assert_equal 'locals: {:name=>"Josh"}, source: "Hello, <%= name %>!"', @view.render(:inline => "Hello, <%= name %>!", :locals => { :name => "Josh" }, :type => :foo)
+ end
+end
diff --git a/actionpack/test/template/tag_helper_test.rb b/actionpack/test/template/tag_helper_test.rb
index 2941dfe217..fc49d340ef 100644
--- a/actionpack/test/template/tag_helper_test.rb
+++ b/actionpack/test/template/tag_helper_test.rb
@@ -33,23 +33,40 @@ class TagHelperTest < ActionView::TestCase
assert_equal content_tag("a", "Create", "href" => "create"),
content_tag("a", "Create", :href => "create")
end
-
- def test_content_tag_with_block
+
+ def test_content_tag_with_block_in_erb
+ __in_erb_template = ''
content_tag(:div) { concat "Hello world!" }
assert_dom_equal "<div>Hello world!</div>", output_buffer
end
-
- def test_content_tag_with_block_and_options
+
+ def test_content_tag_with_block_and_options_in_erb
+ __in_erb_template = ''
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
+
+ def test_content_tag_with_block_and_options_out_of_erb
+ assert_dom_equal %(<div class="green">Hello world!</div>), content_tag(:div, :class => "green") { "Hello world!" }
+ end
+
+ def test_content_tag_with_block_and_options_outside_out_of_erb
assert_equal content_tag("a", "Create", :href => "create"),
- content_tag("a", "href" => "create") { "Create" }
+ content_tag("a", "href" => "create") { "Create" }
end
-
+
+ def test_content_tag_nested_in_content_tag_out_of_erb
+ assert_equal content_tag("p", content_tag("b", "Hello")),
+ content_tag("p") { content_tag("b", "Hello") },
+ output_buffer
+ end
+
+ def test_content_tag_nested_in_content_tag_in_erb
+ __in_erb_template = true
+ content_tag("p") { concat content_tag("b", "Hello") }
+ assert_equal '<p><b>Hello</b></p>', output_buffer
+ end
+
def test_cdata_section
assert_equal "<![CDATA[<hello world>]]>", cdata_section("<hello world>")
end
diff --git a/actionpack/test/template/template_file_test.rb b/actionpack/test/template/template_file_test.rb
deleted file mode 100644
index d14a966c1c..0000000000
--- a/actionpack/test/template/template_file_test.rb
+++ /dev/null
@@ -1,95 +0,0 @@
-require 'abstract_unit'
-
-class TemplateFileTest < Test::Unit::TestCase
- LOAD_PATH_ROOT = File.join(File.dirname(__FILE__), '..', 'fixtures')
-
- def setup
- @template = ActionView::TemplateFile.new("test/hello_world.html.erb")
- @another_template = ActionView::TemplateFile.new("test/hello_world.erb")
- @file_only = ActionView::TemplateFile.new("hello_world.erb")
- @full_path = ActionView::TemplateFile.new("/u/app/scales/config/../app/views/test/hello_world.erb", true)
- @layout = ActionView::TemplateFile.new("layouts/hello")
- @multipart = ActionView::TemplateFile.new("test_mailer/implicitly_multipart_example.text.html.erb")
- end
-
- def test_path
- assert_equal "test/hello_world.html.erb", @template.path
- assert_equal "test/hello_world.erb", @another_template.path
- assert_equal "hello_world.erb", @file_only.path
- assert_equal "/u/app/scales/config/../app/views/test/hello_world.erb", @full_path.path
- assert_equal "layouts/hello", @layout.path
- assert_equal "test_mailer/implicitly_multipart_example.text.html.erb", @multipart.path
- end
-
- def test_path_without_extension
- assert_equal "test/hello_world.html", @template.path_without_extension
- assert_equal "test/hello_world", @another_template.path_without_extension
- assert_equal "hello_world", @file_only.path_without_extension
- assert_equal "layouts/hello", @layout.path_without_extension
- assert_equal "test_mailer/implicitly_multipart_example.text.html", @multipart.path_without_extension
- end
-
- def test_path_without_format_and_extension
- assert_equal "test/hello_world", @template.path_without_format_and_extension
- assert_equal "test/hello_world", @another_template.path_without_format_and_extension
- assert_equal "hello_world", @file_only.path_without_format_and_extension
- assert_equal "layouts/hello", @layout.path_without_format_and_extension
- assert_equal "test_mailer/implicitly_multipart_example", @multipart.path_without_format_and_extension
- end
-
- def test_name
- assert_equal "hello_world", @template.name
- assert_equal "hello_world", @another_template.name
- assert_equal "hello_world", @file_only.name
- assert_equal "hello_world", @full_path.name
- assert_equal "hello", @layout.name
- assert_equal "implicitly_multipart_example", @multipart.name
- end
-
- def test_format
- assert_equal "html", @template.format
- assert_equal nil, @another_template.format
- assert_equal nil, @layout.format
- assert_equal "text.html", @multipart.format
- end
-
- def test_extension
- assert_equal "erb", @template.extension
- assert_equal "erb", @another_template.extension
- assert_equal nil, @layout.extension
- assert_equal "erb", @multipart.extension
- end
-
- def test_format_and_extension
- assert_equal "html.erb", @template.format_and_extension
- assert_equal "erb", @another_template.format_and_extension
- assert_equal nil, @layout.format_and_extension
- assert_equal "text.html.erb", @multipart.format_and_extension
- end
-
- def test_new_file_with_extension
- file = @template.dup_with_extension(:haml)
- assert_equal "test/hello_world.html", file.path_without_extension
- assert_equal "haml", file.extension
- assert_equal "test/hello_world.html.haml", file.path
-
- file = @another_template.dup_with_extension(:haml)
- assert_equal "test/hello_world", file.path_without_extension
- assert_equal "haml", file.extension
- assert_equal "test/hello_world.haml", file.path
-
- file = @another_template.dup_with_extension(nil)
- assert_equal "test/hello_world", file.path_without_extension
- assert_equal nil, file.extension
- assert_equal "test/hello_world", file.path
- end
-
- def test_freezes_entire_contents
- @template.freeze
- assert @template.frozen?
- assert @template.base_path.frozen?
- assert @template.name.frozen?
- assert @template.format.frozen?
- assert @template.extension.frozen?
- end
-end
diff --git a/actionpack/test/template/template_object_test.rb b/actionpack/test/template/template_object_test.rb
deleted file mode 100644
index 2cfc4523c6..0000000000
--- a/actionpack/test/template/template_object_test.rb
+++ /dev/null
@@ -1,92 +0,0 @@
-require 'abstract_unit'
-
-class TemplateObjectTest < Test::Unit::TestCase
- LOAD_PATH_ROOT = File.join(File.dirname(__FILE__), '..', 'fixtures')
-
- class TemplateTest < Test::Unit::TestCase
- def setup
- @view = ActionView::Base.new(LOAD_PATH_ROOT)
- @path = "test/hello_world.erb"
- end
-
- def test_should_create_valid_template
- template = ActionView::Template.new(@view, @path, true)
-
- assert_kind_of ActionView::TemplateHandlers::ERB, template.handler
- assert_equal "test/hello_world.erb", template.path.to_s
- assert_nil template.instance_variable_get(:"@source")
- assert_equal "erb", template.extension
- end
-
- uses_mocha 'Template preparation tests' do
- def test_should_prepare_template_properly
- template = ActionView::Template.new(@view, @path, true)
- view = template.instance_variable_get(:"@view")
-
- view.expects(:evaluate_assigns)
- template.handler.expects(:compile_template).with(template)
- view.expects(:method_names).returns({})
-
- template.prepare!
- end
- end
- end
-
- class PartialTemplateTest < Test::Unit::TestCase
- def setup
- @view = ActionView::Base.new(LOAD_PATH_ROOT)
- @path = "test/partial_only"
- end
-
- def test_should_create_valid_partial_template
- template = ActionView::PartialTemplate.new(@view, @path, nil)
-
- assert_equal "test/_partial_only", template.path.path_without_format_and_extension
- assert_equal :partial_only, template.variable_name
-
- assert template.locals.has_key?(:object)
- assert template.locals.has_key?(:partial_only)
- end
-
- def test_partial_with_errors
- template = ActionView::PartialTemplate.new(@view, 'test/raise', nil)
- assert_raise(ActionView::TemplateError) { template.render_template }
- end
-
- uses_mocha 'Partial template preparation tests' do
- def test_should_prepare_on_initialization
- ActionView::PartialTemplate.any_instance.expects(:prepare!)
- template = ActionView::PartialTemplate.new(@view, @path, 1)
- end
- end
- end
-
- class PartialTemplateFallbackTest < Test::Unit::TestCase
- def setup
- @view = ActionView::Base.new(LOAD_PATH_ROOT)
- @path = 'test/layout_for_partial'
- end
-
- def test_default
- template = ActionView::PartialTemplate.new(@view, @path, nil)
- assert_equal 'test/_layout_for_partial', template.path.path_without_format_and_extension
- assert_equal 'erb', template.extension
- assert_equal :html, @view.template_format
- end
-
- def test_js
- @view.template_format = :js
- template = ActionView::PartialTemplate.new(@view, @path, nil)
- assert_equal 'test/_layout_for_partial', template.path.path_without_format_and_extension
- assert_equal 'erb', template.extension
- assert_equal :html, @view.template_format
- end
-
- def test_xml
- @view.template_format = :xml
- assert_raise ActionView::MissingTemplate do
- ActionView::PartialTemplate.new(@view, @path, nil)
- end
- end
- end
-end
diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb
index cbb5c7ee74..4999525939 100644
--- a/actionpack/test/template/text_helper_test.rb
+++ b/actionpack/test/template/text_helper_test.rb
@@ -13,9 +13,7 @@ class TextHelperTest < ActionView::TestCase
def test_concat
self.output_buffer = 'foo'
- concat 'bar'
- assert_equal 'foobar', output_buffer
- assert_nothing_raised { concat nil }
+ assert_equal 'foobar', concat('bar')
assert_equal 'foobar', output_buffer
end
@@ -195,6 +193,7 @@ class TextHelperTest < ActionView::TestCase
http://www.mail-archive.com/rails@lists.rubyonrails.org/
http://www.amazon.com/Testing-Equal-Sign-In-Path/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1198861734&sr=8-1
http://en.wikipedia.org/wiki/Sprite_(computer_graphics)
+ http://en.wikipedia.org/wiki/Texas_hold'em
)
urls.each do |url|
diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb
index 0713cea8ac..3d5f7eae11 100644
--- a/actionpack/test/template/url_helper_test.rb
+++ b/actionpack/test/template/url_helper_test.rb
@@ -80,7 +80,7 @@ class UrlHelperTest < ActionView::TestCase
def test_link_tag_with_straight_url
assert_dom_equal "<a href=\"http://www.example.com\">Hello</a>", link_to("Hello", "http://www.example.com")
end
-
+
def test_link_tag_without_host_option
ActionController::Base.class_eval { attr_accessor :url }
url = {:controller => 'weblog', :action => 'show'}
@@ -121,7 +121,7 @@ class UrlHelperTest < ActionView::TestCase
@controller.request = RequestMock.new("http://www.example.com/weblog/show", nil, nil, {'HTTP_REFERER' => 'http://www.example.com/referer'})
assert_dom_equal "<a href=\"http://www.example.com/referer\">go back</a>", link_to('go back', :back)
end
-
+
def test_link_tag_with_back_and_no_referer
@controller.request = RequestMock.new("http://www.example.com/weblog/show", nil, nil, {})
assert_dom_equal "<a href=\"javascript:history.back()\">go back</a>", link_to('go back', :back)
@@ -212,14 +212,14 @@ class UrlHelperTest < ActionView::TestCase
assert_raises(ActionView::ActionViewError) { link_to("Hello", "http://www.example.com", :popup => true, :method => :post, :confirm => "Are you serious?") }
end
- def test_link_tag_using_block
- self.output_buffer = ''
+ def test_link_tag_using_block_in_erb
+ __in_erb_template = ''
link_to("http://example.com") { concat("Example site") }
assert_equal '<a href="http://example.com">Example site</a>', output_buffer
end
-
+
def test_link_to_unless
assert_equal "Showing", link_to_unless(true, "Showing", :action => "show", :controller => "weblog")
assert_dom_equal "<a href=\"http://www.example.com\">Listing</a>", link_to_unless(false, "Listing", :action => "list", :controller => "weblog")
@@ -293,7 +293,7 @@ class UrlHelperTest < ActionView::TestCase
assert_dom_equal "<a href=\"&#109;&#97;&#105;&#108;&#116;&#111;&#58;%6d%65@%64%6f%6d%61%69%6e.%63%6f%6d\">&#109;&#101;&#40;&#97;&#116;&#41;&#100;&#111;&#109;&#97;&#105;&#110;&#40;&#100;&#111;&#116;&#41;&#99;&#111;&#109;</a>", mail_to("me@domain.com", nil, :encode => "hex", :replace_at => "(at)", :replace_dot => "(dot)")
assert_dom_equal "<script type=\"text/javascript\">eval(unescape('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%22%3e%4d%79%20%65%6d%61%69%6c%3c%2f%61%3e%27%29%3b'))</script>", mail_to("me@domain.com", "My email", :encode => "javascript", :replace_at => "(at)", :replace_dot => "(dot)")
end
-
+
def protect_against_forgery?
false
end
@@ -301,7 +301,7 @@ end
class UrlHelperWithControllerTest < ActionView::TestCase
class UrlHelperController < ActionController::Base
- self.view_paths = [ "#{File.dirname(__FILE__)}/../fixtures/" ]
+ self.view_paths = [FIXTURE_LOAD_PATH]
def self.controller_path; 'url_helper_with_controller' end
@@ -356,7 +356,7 @@ end
class LinkToUnlessCurrentWithControllerTest < ActionView::TestCase
class TasksController < ActionController::Base
- self.view_paths = ["#{File.dirname(__FILE__)}/../fixtures/"]
+ self.view_paths = [FIXTURE_LOAD_PATH]
def self.controller_path; 'tasks' end
@@ -420,11 +420,11 @@ class Workshop
def initialize(id, new_record)
@id, @new_record = id, new_record
end
-
+
def new_record?
@new_record
end
-
+
def to_s
id.to_s
end
@@ -448,7 +448,7 @@ end
class PolymorphicControllerTest < ActionView::TestCase
class WorkshopsController < ActionController::Base
- self.view_paths = ["#{File.dirname(__FILE__)}/../fixtures/"]
+ self.view_paths = [FIXTURE_LOAD_PATH]
def self.controller_path; 'workshops' end
@@ -466,7 +466,7 @@ class PolymorphicControllerTest < ActionView::TestCase
end
class SessionsController < ActionController::Base
- self.view_paths = ["#{File.dirname(__FILE__)}/../fixtures/"]
+ self.view_paths = [FIXTURE_LOAD_PATH]
def self.controller_path; 'sessions' end
diff --git a/activemodel/Rakefile b/activemodel/Rakefile
index 034c2fbd01..4b60f8d682 100644
--- a/activemodel/Rakefile
+++ b/activemodel/Rakefile
@@ -18,7 +18,7 @@ Rake::RDocTask.new do |rdoc|
rdoc.title = "Active Model"
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
rdoc.options << '--charset' << 'utf-8'
- rdoc.template = "#{ENV['template']}.rb" if ENV['template']
+ rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
rdoc.rdoc_files.include('README', 'CHANGES')
rdoc.rdoc_files.include('lib/**/*.rb')
-end \ No newline at end of file
+end
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index a1d82fb45d..d6cc589381 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,5 +1,22 @@
*Edge*
+* Allow conditions on multiple tables to be specified using hash. [Pratik Naik]. Example:
+
+ User.all :joins => :items, :conditions => { :age => 10, :items => { :color => 'black' } }
+ Item.first :conditions => { :items => { :color => 'red' } }
+
+* Always treat integer :limit as byte length. #420 [Tarmo Tänav]
+
+* Partial updates don't update lock_version if nothing changed. #426 [Daniel Morrison]
+
+* Fix column collision with named_scope and :joins. #46 [Duncan Beevers, Mark Catley]
+
+* db:migrate:down and :up update schema_migrations. #369 [Michael Raidel, RaceCondition]
+
+* PostgreSQL: support :conditions => [':foo::integer', { :foo => 1 }] without treating the ::integer typecast as a bind variable. [Tarmo Tänav]
+
+* MySQL: rename_column preserves column defaults. #466 [Diego Algorta]
+
* 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]
diff --git a/activerecord/Rakefile b/activerecord/Rakefile
index 7a5296c458..60b17e02b9 100755
--- a/activerecord/Rakefile
+++ b/activerecord/Rakefile
@@ -141,7 +141,7 @@ Rake::RDocTask.new { |rdoc|
rdoc.title = "Active Record -- Object-relation mapping put on rails"
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
rdoc.options << '--charset' << 'utf-8'
- rdoc.template = "#{ENV['template']}.rb" if ENV['template']
+ rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
rdoc.rdoc_files.include('README', 'RUNNING_UNIT_TESTS', 'CHANGELOG')
rdoc.rdoc_files.include('lib/**/*.rb')
rdoc.rdoc_files.exclude('lib/active_record/vendor/*')
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index db99b7165d..4b7154043f 100755
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -711,7 +711,8 @@ module ActiveRecord
configure_dependency_for_has_many(reflection)
- add_multiple_associated_save_callbacks(reflection.name) unless options[:validate] == false
+ add_multiple_associated_validation_callbacks(reflection.name) unless options[:validate] == false
+ add_multiple_associated_save_callbacks(reflection.name)
add_association_callbacks(reflection.name, reflection.options)
if options[:through]
@@ -801,7 +802,7 @@ module ActiveRecord
end
after_save method_name
- add_single_associated_save_callbacks(reflection.name) if options[:validate] == true
+ add_single_associated_validation_callbacks(reflection.name) if options[:validate] == true
association_accessor_methods(reflection, HasOneAssociation)
association_constructor_method(:build, reflection, HasOneAssociation)
association_constructor_method(:create, reflection, HasOneAssociation)
@@ -940,7 +941,7 @@ module ActiveRecord
)
end
- add_single_associated_save_callbacks(reflection.name) if options[:validate] == true
+ add_single_associated_validation_callbacks(reflection.name) if options[:validate] == true
configure_dependency_for_belongs_to(reflection)
end
@@ -1043,7 +1044,8 @@ 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) unless options[:validate] == false
+ add_multiple_associated_validation_callbacks(reflection.name) unless options[:validate] == false
+ add_multiple_associated_save_callbacks(reflection.name)
collection_accessor_methods(reflection, HasAndBelongsToManyAssociation)
# Don't use a before_destroy callback since users' before_destroy
@@ -1163,7 +1165,7 @@ module ActiveRecord
end
end
- def add_single_associated_save_callbacks(association_name)
+ def add_single_associated_validation_callbacks(association_name)
method_name = "validate_associated_records_for_#{association_name}".to_sym
define_method(method_name) do
association = instance_variable_get("@#{association_name}")
@@ -1175,7 +1177,7 @@ module ActiveRecord
validate method_name
end
- def add_multiple_associated_save_callbacks(association_name)
+ def add_multiple_associated_validation_callbacks(association_name)
method_name = "validate_associated_records_for_#{association_name}".to_sym
ivar = "@#{association_name}"
@@ -1196,6 +1198,10 @@ module ActiveRecord
end
validate method_name
+ end
+
+ def add_multiple_associated_save_callbacks(association_name)
+ ivar = "@#{association_name}"
method_name = "before_save_associated_records_for_#{association_name}".to_sym
define_method(method_name) do
@@ -1217,7 +1223,6 @@ module ActiveRecord
else
[]
end
-
records_to_save.each { |record| association.send(:insert_record, record) } unless records_to_save.blank?
# reconstruct the SQL queries now that we know the owner's id
diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb
index 11c64243a2..77fc827e11 100644
--- a/activerecord/lib/active_record/associations/association_proxy.rb
+++ b/activerecord/lib/active_record/associations/association_proxy.rb
@@ -85,7 +85,7 @@ module ActiveRecord
end
def conditions
- @conditions ||= interpolate_sql(sanitize_sql(@reflection.options[:conditions])) if @reflection.options[:conditions]
+ @conditions ||= interpolate_sql(@reflection.sanitized_conditions) if @reflection.sanitized_conditions
end
alias :sql_conditions :conditions
@@ -219,6 +219,10 @@ module ActiveRecord
def flatten_deeper(array)
array.collect { |element| element.respond_to?(:flatten) ? element.flatten : element }.flatten
end
+
+ def owner_quoted_id
+ @owner.quoted_id
+ end
end
end
end
diff --git a/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb b/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb
index 918404eac6..d516d54151 100644
--- a/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb
+++ b/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb
@@ -37,7 +37,7 @@ module ActiveRecord
attributes = columns.inject({}) do |attrs, column|
case column.name.to_s
when @reflection.primary_key_name.to_s
- attrs[column.name] = @owner.quoted_id
+ attrs[column.name] = owner_quoted_id
when @reflection.association_foreign_key.to_s
attrs[column.name] = record.quoted_id
else
@@ -64,7 +64,7 @@ module ActiveRecord
records.each { |record| @owner.connection.delete(interpolate_sql(sql, record)) }
else
ids = quoted_record_ids(records)
- sql = "DELETE FROM #{@owner.connection.quote_table_name @reflection.options[:join_table]} WHERE #{@reflection.primary_key_name} = #{@owner.quoted_id} AND #{@reflection.association_foreign_key} IN (#{ids})"
+ sql = "DELETE FROM #{@owner.connection.quote_table_name @reflection.options[:join_table]} WHERE #{@reflection.primary_key_name} = #{owner_quoted_id} AND #{@reflection.association_foreign_key} IN (#{ids})"
@owner.connection.delete(sql)
end
end
@@ -75,7 +75,7 @@ module ActiveRecord
if @reflection.options[:finder_sql]
@finder_sql = @reflection.options[:finder_sql]
else
- @finder_sql = "#{@owner.connection.quote_table_name @reflection.options[:join_table]}.#{@reflection.primary_key_name} = #{@owner.quoted_id} "
+ @finder_sql = "#{@owner.connection.quote_table_name @reflection.options[:join_table]}.#{@reflection.primary_key_name} = #{owner_quoted_id} "
@finder_sql << " AND (#{conditions})" if conditions
end
diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb
index 295beb2966..37440aa84d 100644
--- a/activerecord/lib/active_record/associations/has_many_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_association.rb
@@ -60,7 +60,7 @@ module ActiveRecord
ids = quoted_record_ids(records)
@reflection.klass.update_all(
"#{@reflection.primary_key_name} = NULL",
- "#{@reflection.primary_key_name} = #{@owner.quoted_id} AND #{@reflection.klass.primary_key} IN (#{ids})"
+ "#{@reflection.primary_key_name} = #{owner_quoted_id} AND #{@reflection.klass.primary_key} IN (#{ids})"
)
end
end
@@ -76,12 +76,12 @@ module ActiveRecord
when @reflection.options[:as]
@finder_sql =
- "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_id = #{@owner.quoted_id} AND " +
+ "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_id = #{owner_quoted_id} AND " +
"#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_type = #{@owner.class.quote_value(@owner.class.base_class.name.to_s)}"
@finder_sql << " AND (#{conditions})" if conditions
else
- @finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} = #{@owner.quoted_id}"
+ @finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} = #{owner_quoted_id}"
@finder_sql << " AND (#{conditions})" if conditions
end
diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb
index 52ced36d16..e1bfff5923 100644
--- a/activerecord/lib/active_record/associations/has_many_through_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_through_association.rb
@@ -107,12 +107,12 @@ module ActiveRecord
# Associate attributes pointing to owner, quoted.
def construct_quoted_owner_attributes(reflection)
if as = reflection.options[:as]
- { "#{as}_id" => @owner.quoted_id,
+ { "#{as}_id" => owner_quoted_id,
"#{as}_type" => reflection.klass.quote_value(
@owner.class.base_class.name.to_s,
reflection.klass.columns_hash["#{as}_type"]) }
else
- { reflection.primary_key_name => @owner.quoted_id }
+ { reflection.primary_key_name => owner_quoted_id }
end
end
@@ -183,7 +183,7 @@ module ActiveRecord
when @reflection.options[:finder_sql]
@finder_sql = interpolate_sql(@reflection.options[:finder_sql])
- @finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} = #{@owner.quoted_id}"
+ @finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} = #{owner_quoted_id}"
@finder_sql << " AND (#{conditions})" if conditions
else
@finder_sql = construct_conditions
diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb
index c2b3503e0d..25a268e95c 100755
--- a/activerecord/lib/active_record/associations/has_one_association.rb
+++ b/activerecord/lib/active_record/associations/has_one_association.rb
@@ -63,10 +63,10 @@ module ActiveRecord
case
when @reflection.options[:as]
@finder_sql =
- "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_id = #{@owner.quoted_id} AND " +
+ "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_id = #{owner_quoted_id} AND " +
"#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_type = #{@owner.class.quote_value(@owner.class.base_class.name.to_s)}"
else
- @finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} = #{@owner.quoted_id}"
+ @finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} = #{owner_quoted_id}"
end
@finder_sql << " AND (#{conditions})" if conditions
end
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 8fca34e524..962c2b36d9 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -1479,7 +1479,7 @@ module ActiveRecord #:nodoc:
def construct_finder_sql(options)
scope = scope(:find)
- sql = "SELECT #{options[:select] || (scope && scope[:select]) || (options[:joins] && quoted_table_name + '.*') || '*'} "
+ sql = "SELECT #{options[:select] || (scope && scope[:select]) || ((options[:joins] || (scope && scope[:joins])) && quoted_table_name + '.*') || '*'} "
sql << "FROM #{(scope && scope[:from]) || options[:from] || quoted_table_name} "
add_joins!(sql, options, scope)
@@ -1999,24 +1999,28 @@ module ActiveRecord #:nodoc:
# # => "age BETWEEN 13 AND 18"
# { 'other_records.id' => 7 }
# # => "`other_records`.`id` = 7"
+ # { :other_records => { :id => 7 } }
+ # # => "`other_records`.`id` = 7"
# And for value objects on a composed_of relationship:
# { :address => Address.new("123 abc st.", "chicago") }
# # => "address_street='123 abc st.' and address_city='chicago'"
- def sanitize_sql_hash_for_conditions(attrs)
+ def sanitize_sql_hash_for_conditions(attrs, table_name = quoted_table_name)
attrs = expand_hash_conditions_for_aggregates(attrs)
conditions = attrs.map do |attr, value|
- attr = attr.to_s
+ unless value.is_a?(Hash)
+ attr = attr.to_s
+
+ # Extract table name from qualified attribute names.
+ if attr.include?('.')
+ table_name, attr = attr.split('.', 2)
+ table_name = connection.quote_table_name(table_name)
+ end
- # Extract table name from qualified attribute names.
- if attr.include?('.')
- table_name, attr = attr.split('.', 2)
- table_name = connection.quote_table_name(table_name)
+ "#{table_name}.#{connection.quote_column_name(attr)} #{attribute_condition(value)}"
else
- table_name = quoted_table_name
+ sanitize_sql_hash_for_conditions(value, connection.quote_table_name(attr.to_s))
end
-
- "#{table_name}.#{connection.quote_column_name(attr)} #{attribute_condition(value)}"
end.join(' AND ')
replace_bind_variables(conditions, expand_range_bind_variables(attrs.values))
@@ -2055,9 +2059,10 @@ module ActiveRecord #:nodoc:
end
def replace_named_bind_variables(statement, bind_vars) #:nodoc:
- statement.gsub(/:([a-zA-Z]\w*)/) do
- match = $1.to_sym
- if bind_vars.include?(match)
+ statement.gsub(/(:?):([a-zA-Z]\w*)/) do
+ if $1 == ':' # skip postgresql casts
+ $& # return the whole match
+ elsif bind_vars.include?(match = $2.to_sym)
quote_bound_value(bind_vars[match])
else
raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}"
@@ -2069,6 +2074,8 @@ module ActiveRecord #:nodoc:
expanded = []
bind_vars.each do |var|
+ next if var.is_a?(Hash)
+
if var.is_a?(Range)
expanded << var.first
expanded << var.last
@@ -2169,11 +2176,11 @@ module ActiveRecord #:nodoc:
def cache_key
case
when new_record?
- "#{self.class.name.tableize}/new"
- when self[:updated_at]
- "#{self.class.name.tableize}/#{id}-#{updated_at.to_s(:number)}"
+ "#{self.class.model_name.cache_key}/new"
+ when timestamp = self[:updated_at]
+ "#{self.class.model_name.cache_key}/#{id}-#{timestamp.to_s(:number)}"
else
- "#{self.class.name.tableize}/#{id}"
+ "#{self.class.model_name.cache_key}/#{id}"
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
index f968b9b173..2c03de0f17 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -30,11 +30,11 @@ module ActiveRecord
end
def text?
- [:string, :text].include? type
+ type == :string || type == :text
end
def number?
- [:float, :integer, :decimal].include? type
+ type == :integer || type == :float || type == :decimal
end
# Returns the Ruby class that corresponds to the abstract data type.
@@ -304,8 +304,7 @@ module ActiveRecord
#
# Available options are (none of these exists by default):
# * <tt>:limit</tt> -
- # Requests a maximum column length (<tt>:string</tt>, <tt>:text</tt>,
- # <tt>:binary</tt> or <tt>:integer</tt> columns only)
+ # Requests a maximum column length. This is number of characters for <tt>:string</tt> and <tt>:text</tt> columns and number of bytes for :binary and :integer columns.
# * <tt>:default</tt> -
# The column's default value. Use nil for NULL.
# * <tt>:null</tt> -
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index 93aafaaad1..c5962764f5 100755
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -99,7 +99,8 @@ module ActiveRecord
end
def extract_limit(sql_type)
- if sql_type =~ /blob|text/i
+ case sql_type
+ when /blob|text/i
case sql_type
when /tiny/i
255
@@ -110,6 +111,11 @@ module ActiveRecord
else
super # we could return 65535 here, but we leave it undecorated by default
end
+ when /^bigint/i; 8
+ when /^int/i; 4
+ when /^mediumint/i; 3
+ when /^smallint/i; 2
+ when /^tinyint/i; 1
else
super
end
@@ -168,7 +174,7 @@ module ActiveRecord
:primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY".freeze,
:string => { :name => "varchar", :limit => 255 },
:text => { :name => "text" },
- :integer => { :name => "int"},
+ :integer => { :name => "int", :limit => 4 },
:float => { :name => "float" },
:decimal => { :name => "decimal" },
:datetime => { :name => "datetime" },
@@ -450,8 +456,16 @@ module ActiveRecord
end
def rename_column(table_name, column_name, new_column_name) #:nodoc:
+ options = {}
+ if column = columns(table_name).find { |c| c.name == column_name.to_s }
+ options[:default] = column.default
+ else
+ raise ActiveRecordError, "No such column: #{table_name}.#{column_name}"
+ end
current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"]
- execute "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}"
+ rename_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}"
+ add_column_options!(rename_column_sql, options)
+ execute(rename_column_sql)
end
# Maps logical Rails types to MySQL-specific data types.
@@ -459,14 +473,12 @@ module ActiveRecord
return super unless type.to_s == 'integer'
case limit
- when 0..3
- "smallint(#{limit})"
- when 4..8
- "int(#{limit})"
- when 9..20
- "bigint(#{limit})"
- else
- 'int(11)'
+ when 1; 'tinyint'
+ when 2; 'smallint'
+ when 3; 'mediumint'
+ when nil, 4, 11; 'int(11)' # compatibility with MySQL default
+ when 5..8; 'bigint'
+ else raise(ActiveRecordError, "No integer type has byte size #{limit}")
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 294f4c1929..2e2d50ccf4 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -47,6 +47,15 @@ module ActiveRecord
end
private
+ def extract_limit(sql_type)
+ case sql_type
+ when /^integer/i; 4
+ when /^bigint/i; 8
+ when /^smallint/i; 2
+ else super
+ end
+ end
+
# Extracts the scale from PostgreSQL-specific data types.
def extract_scale(sql_type)
# Money type has a fixed scale of 2.
@@ -324,12 +333,7 @@ module ActiveRecord
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
+ postgresql_version >= 80200
end
# Returns the configured supported identifier length supported by PostgreSQL,
@@ -553,7 +557,15 @@ module ActiveRecord
# Example:
# drop_database 'matt_development'
def drop_database(name) #:nodoc:
- execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
+ if postgresql_version >= 80200
+ execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
+ else
+ begin
+ execute "DROP DATABASE #{quote_table_name(name)}"
+ rescue ActiveRecord::StatementInvalid
+ @logger.warn "#{name} database doesn't exist." if @logger
+ end
+ end
end
@@ -782,15 +794,14 @@ module ActiveRecord
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
return super unless type.to_s == 'integer'
- if limit.nil? || limit == 4
- 'integer'
- elsif limit < 4
- 'smallint'
- else
- 'bigint'
+ case limit
+ when 1..2; 'smallint'
+ when 3..4, nil; 'integer'
+ when 5..8; 'bigint'
+ else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
end
end
-
+
# Returns a SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
#
# PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
diff --git a/activerecord/lib/active_record/dirty.rb b/activerecord/lib/active_record/dirty.rb
index b32e17e990..a7d767486c 100644
--- a/activerecord/lib/active_record/dirty.rb
+++ b/activerecord/lib/active_record/dirty.rb
@@ -142,9 +142,11 @@ module ActiveRecord
def field_changed?(attr, old, value)
if column = column_for_attribute(attr)
- if column.type == :integer && column.null && old.nil?
+ if column.type == :integer && column.null && (old.nil? || old == 0)
# For nullable integer columns, NULL gets stored in database for blank (i.e. '') values.
# Hence we don't record it as a change if the value changes from nil to ''.
+ # If an old value of 0 is set to '' we want this to get changed to nil as otherwise it'll
+ # be typecast back to 0 (''.to_i => 0)
value = nil if value.blank?
else
value = column.type_cast(value)
diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb
index c66034d18b..ff9899d032 100644
--- a/activerecord/lib/active_record/locking/optimistic.rb
+++ b/activerecord/lib/active_record/locking/optimistic.rb
@@ -68,6 +68,7 @@ module ActiveRecord
def update_with_lock(attribute_names = @attributes.keys) #:nodoc:
return update_without_lock(attribute_names) unless locking_enabled?
+ return 0 if attribute_names.empty?
lock_col = self.class.locking_column
previous_value = send(lock_col).to_i
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index b47b01e99a..e095b3c766 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -399,7 +399,10 @@ module ActiveRecord
def run
target = migrations.detect { |m| m.version == @target_version }
raise UnknownMigrationVersionError.new(@target_version) if target.nil?
- target.migrate(@direction)
+ unless (up? && migrated.include?(target.version.to_i)) || (down? && !migrated.include?(target.version.to_i))
+ target.migrate(@direction)
+ record_version_state_after_migrating(target.version)
+ end
end
def migrate
diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb
index b0c8a8b815..eac61e9e43 100644
--- a/activerecord/lib/active_record/named_scope.rb
+++ b/activerecord/lib/active_record/named_scope.rb
@@ -82,6 +82,7 @@ module ActiveRecord
# expected_options = { :conditions => { :colored => 'red' } }
# assert_equal expected_options, Shirt.colored('red').proxy_options
def named_scope(name, options = {}, &block)
+ name = name.to_sym
scopes[name] = lambda do |parent_scope, *args|
Scope.new(parent_scope, case options
when Hash
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 8614ef8751..3f74c03714 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -112,6 +112,10 @@ module ActiveRecord
name == other_aggregation.name && other_aggregation.options && active_record == other_aggregation.active_record
end
+ def sanitized_conditions #:nodoc:
+ @sanitized_conditions ||= klass.send(:sanitize_sql, options[:conditions]) if options[:conditions]
+ end
+
private
def derive_class_name
name.to_s.camelize
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index b638143c5a..1e21614f45 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -345,7 +345,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_invalid_adding_with_validate_false
firm = Firm.find(:first)
client = Client.new
- firm.unvalidated_clients_of_firm << Client.new
+ firm.unvalidated_clients_of_firm << client
assert firm.valid?
assert !client.valid?
@@ -353,6 +353,23 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert client.new_record?
end
+ def test_valid_adding_with_validate_false
+ no_of_clients = Client.count
+
+ firm = Firm.find(:first)
+ client = Client.new("name" => "Apple")
+
+ assert firm.valid?
+ assert client.valid?
+ assert client.new_record?
+
+ firm.unvalidated_clients_of_firm << client
+
+ assert firm.save
+ assert !client.new_record?
+ assert_equal no_of_clients+1, Client.count
+ 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/dirty_test.rb b/activerecord/test/cases/dirty_test.rb
index c011ffaf57..e5e022050d 100644
--- a/activerecord/test/cases/dirty_test.rb
+++ b/activerecord/test/cases/dirty_test.rb
@@ -2,6 +2,7 @@ require 'cases/helper'
require 'models/topic' # For booleans
require 'models/pirate' # For timestamps
require 'models/parrot'
+require 'models/person' # For optimistic locking
class Pirate # Just reopening it, not defining it
attr_accessor :detected_changes_in_after_update # Boolean for if changes are detected
@@ -54,6 +55,33 @@ class DirtyTest < ActiveRecord::TestCase
end
end
+ def test_zero_to_blank_marked_as_changed
+ pirate = Pirate.new
+ pirate.catchphrase = "Yarrrr, me hearties"
+ pirate.parrot_id = 1
+ pirate.save
+
+ # check the change from 1 to ''
+ pirate = Pirate.find_by_catchphrase("Yarrrr, me hearties")
+ pirate.parrot_id = ''
+ assert pirate.parrot_id_changed?
+ assert_equal([1, nil], pirate.parrot_id_change)
+ pirate.save
+
+ # check the change from nil to 0
+ pirate = Pirate.find_by_catchphrase("Yarrrr, me hearties")
+ pirate.parrot_id = 0
+ assert pirate.parrot_id_changed?
+ assert_equal([nil, 0], pirate.parrot_id_change)
+ pirate.save
+
+ # check the change from 0 to ''
+ pirate = Pirate.find_by_catchphrase("Yarrrr, me hearties")
+ pirate.parrot_id = ''
+ assert pirate.parrot_id_changed?
+ assert_equal([0, nil], pirate.parrot_id_change)
+ end
+
def test_object_should_be_changed_if_any_attribute_is_changed
pirate = Pirate.new
assert !pirate.changed?
@@ -125,6 +153,24 @@ class DirtyTest < ActiveRecord::TestCase
end
end
+ def test_partial_update_with_optimistic_locking
+ person = Person.new(:first_name => 'foo')
+ old_lock_version = 1
+
+ with_partial_updates Person, false do
+ assert_queries(2) { 2.times { person.save! } }
+ Person.update_all({ :first_name => 'baz' }, :id => person.id)
+ end
+
+ with_partial_updates Person, true do
+ assert_queries(0) { 2.times { person.save! } }
+ assert_equal old_lock_version, person.reload.lock_version
+
+ assert_queries(1) { person.first_name = 'bar'; person.save! }
+ assert_not_equal old_lock_version, person.reload.lock_version
+ end
+ end
+
def test_changed_attributes_should_be_preserved_if_save_failure
pirate = Pirate.new
pirate.parrot_id = 1
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 80936d51f3..b97db73b68 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -1,5 +1,6 @@
require "cases/helper"
require 'models/author'
+require 'models/categorization'
require 'models/comment'
require 'models/company'
require 'models/topic'
@@ -199,6 +200,23 @@ class FinderTest < ActiveRecord::TestCase
assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { 'topics.approved' => true }) }
end
+ def test_find_on_hash_conditions_with_hashed_table_name
+ assert Topic.find(1, :conditions => {:topics => { :approved => false }})
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => {:topics => { :approved => true }}) }
+ end
+
+ def test_find_with_hash_conditions_on_joined_table
+ firms = Firm.all :joins => :account, :conditions => {:accounts => { :credit_limit => 50 }}
+ assert_equal 1, firms.size
+ assert_equal companies(:first_firm), firms.first
+ end
+
+ def test_find_with_hash_conditions_on_joined_table_and_with_range
+ firms = DependentFirm.all :joins => :account, :conditions => {:name => 'RailsCore', :accounts => { :credit_limit => 55..60 }}
+ assert_equal 1, firms.size
+ assert_equal companies(:rails_core), firms.first
+ end
+
def test_find_on_hash_conditions_with_explicit_table_name_and_aggregate
david = customers(:david)
assert Customer.find(david.id, :conditions => { 'customers.name' => david.name, :address => david.address })
@@ -394,6 +412,12 @@ class FinderTest < ActiveRecord::TestCase
assert_equal '1,1,1', bind('?', os)
end
+ def test_named_bind_with_postgresql_type_casts
+ l = Proc.new { bind(":a::integer '2009-01-01'::date", :a => '10') }
+ assert_nothing_raised(&l)
+ assert_equal "#{ActiveRecord::Base.quote_value('10')}::integer '2009-01-01'::date", l.call
+ end
+
def test_string_sanitation
assert_not_equal "#{ActiveRecord::Base.connection.quoted_string_prefix}'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1")
assert_equal "#{ActiveRecord::Base.connection.quoted_string_prefix}'something; select table'", ActiveRecord::Base.sanitize("something; select table")
diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb
index 7db6c570b5..701187223f 100644
--- a/activerecord/test/cases/locking_test.rb
+++ b/activerecord/test/cases/locking_test.rb
@@ -29,10 +29,12 @@ class OptimisticLockingTest < ActiveRecord::TestCase
assert_equal 0, p1.lock_version
assert_equal 0, p2.lock_version
+ p1.first_name = 'stu'
p1.save!
assert_equal 1, p1.lock_version
assert_equal 0, p2.lock_version
+ p2.first_name = 'sue'
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
end
@@ -42,11 +44,14 @@ class OptimisticLockingTest < ActiveRecord::TestCase
assert_equal 0, p1.lock_version
assert_equal 0, p2.lock_version
+ p1.first_name = 'stu'
p1.save!
assert_equal 1, p1.lock_version
assert_equal 0, p2.lock_version
+ p2.first_name = 'sue'
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
+ p2.first_name = 'sue2'
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
end
@@ -54,15 +59,18 @@ class OptimisticLockingTest < ActiveRecord::TestCase
p1 = Person.new(:first_name => 'anika')
assert_equal 0, p1.lock_version
+ p1.first_name = 'anika2'
p1.save!
p2 = Person.find(p1.id)
assert_equal 0, p1.lock_version
assert_equal 0, p2.lock_version
+ p1.first_name = 'anika3'
p1.save!
assert_equal 1, p1.lock_version
assert_equal 0, p2.lock_version
+ p2.first_name = 'sue'
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
end
@@ -81,10 +89,12 @@ class OptimisticLockingTest < ActiveRecord::TestCase
assert_equal 0, t1.version
assert_equal 0, t2.version
+ t1.tps_report_number = 700
t1.save!
assert_equal 1, t1.version
assert_equal 0, t2.version
+ t2.tps_report_number = 800
assert_raises(ActiveRecord::StaleObjectError) { t2.save! }
end
@@ -93,6 +103,7 @@ class OptimisticLockingTest < ActiveRecord::TestCase
assert_equal 0, p1.lock_version
assert_equal p1.lock_version, Person.new(p1.attributes).lock_version
+ p1.first_name = 'bianca2'
p1.save!
assert_equal 1, p1.lock_version
assert_equal p1.lock_version, Person.new(p1.attributes).lock_version
@@ -146,6 +157,15 @@ class OptimisticLockingTest < ActiveRecord::TestCase
assert ref.save
end
+ # Useful for partial updates, don't only update the lock_version if there
+ # is nothing else being updated.
+ def test_update_without_attributes_does_not_only_update_lock_version
+ assert_nothing_raised do
+ p1 = Person.new(:first_name => 'anika')
+ p1.send(:update_with_lock, [])
+ end
+ end
+
private
def add_counter_column_to(model)
diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb
index 1a9a875730..d6b3e341df 100644
--- a/activerecord/test/cases/method_scoping_test.rb
+++ b/activerecord/test/cases/method_scoping_test.rb
@@ -87,6 +87,16 @@ class MethodScopingTest < ActiveRecord::TestCase
assert_equal 1, scoped_developers.size
end
+ def test_scoped_find_joins
+ scoped_developers = Developer.with_scope(:find => { :joins => 'JOIN developers_projects ON id = developer_id' } ) do
+ Developer.find(:all, :conditions => 'developers_projects.project_id = 2')
+ end
+ assert scoped_developers.include?(developers(:david))
+ assert !scoped_developers.include?(developers(:jamis))
+ assert_equal 1, scoped_developers.size
+ assert_equal developers(:david).attributes, scoped_developers.first.attributes
+ end
+
def test_scoped_count_include
# with the include, will retrieve only developers for the given project
Developer.with_scope(:find => { :include => :projects }) do
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index f36255e209..4482b487dd 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -153,9 +153,10 @@ if ActiveRecord::Base.connection.supports_migrations?
t.column :default_int, :integer
- t.column :one_int, :integer, :limit => 1
- t.column :four_int, :integer, :limit => 4
- t.column :eight_int, :integer, :limit => 8
+ t.column :one_int, :integer, :limit => 1
+ t.column :four_int, :integer, :limit => 4
+ t.column :eight_int, :integer, :limit => 8
+ t.column :eleven_int, :integer, :limit => 11
end
end
@@ -167,12 +168,20 @@ if ActiveRecord::Base.connection.supports_migrations?
one = columns.detect { |c| c.name == "one_int" }
four = columns.detect { |c| c.name == "four_int" }
eight = columns.detect { |c| c.name == "eight_int" }
+ eleven = columns.detect { |c| c.name == "eleven_int" }
if current_adapter?(:PostgreSQLAdapter)
assert_equal 'integer', default.sql_type
assert_equal 'smallint', one.sql_type
assert_equal 'integer', four.sql_type
assert_equal 'bigint', eight.sql_type
+ assert_equal 'integer', eleven.sql_type
+ elsif current_adapter?(:MysqlAdapter)
+ assert_match 'int(11)', default.sql_type
+ assert_match 'tinyint', one.sql_type
+ assert_match 'int', four.sql_type
+ assert_match 'bigint', eight.sql_type
+ assert_match 'int(11)', eleven.sql_type
elsif current_adapter?(:OracleAdapter)
assert_equal 'NUMBER(38)', default.sql_type
assert_equal 'NUMBER(1)', one.sql_type
@@ -483,6 +492,32 @@ if ActiveRecord::Base.connection.supports_migrations?
end
end
+ def test_rename_column_preserves_default_value_not_null
+ begin
+ default_before = Developer.connection.columns("developers").find { |c| c.name == "salary" }.default
+ assert_equal 70000, default_before
+ Developer.connection.rename_column "developers", "salary", "anual_salary"
+ Developer.reset_column_information
+ assert Developer.column_names.include?("anual_salary")
+ default_after = Developer.connection.columns("developers").find { |c| c.name == "anual_salary" }.default
+ assert_equal 70000, default_after
+ ensure
+ Developer.connection.rename_column "developers", "anual_salary", "salary"
+ Developer.reset_column_information
+ end
+ end
+
+ def test_rename_nonexistent_column
+ ActiveRecord::Base.connection.create_table(:hats) do |table|
+ table.column :hat_name, :string, :default => nil
+ end
+ assert_raises(ActiveRecord::ActiveRecordError) do
+ Person.connection.rename_column "hats", "nonexistent", "should_fail"
+ end
+ ensure
+ ActiveRecord::Base.connection.drop_table(:hats)
+ end
+
def test_rename_column_with_sql_reserved_word
begin
assert_nothing_raised { Person.connection.rename_column "people", "first_name", "group" }
@@ -799,6 +834,21 @@ if ActiveRecord::Base.connection.supports_migrations?
assert !Reminder.table_exists?
end
+ def test_migrator_double_up
+ assert_equal(0, ActiveRecord::Migrator.current_version)
+ ActiveRecord::Migrator.run(:up, MIGRATIONS_ROOT + "/valid", 1)
+ assert_nothing_raised { ActiveRecord::Migrator.run(:up, MIGRATIONS_ROOT + "/valid", 1) }
+ assert_equal(1, ActiveRecord::Migrator.current_version)
+ end
+
+ def test_migrator_double_down
+ assert_equal(0, ActiveRecord::Migrator.current_version)
+ ActiveRecord::Migrator.run(:up, MIGRATIONS_ROOT + "/valid", 1)
+ ActiveRecord::Migrator.run(:down, MIGRATIONS_ROOT + "/valid", 1)
+ assert_nothing_raised { ActiveRecord::Migrator.run(:down, MIGRATIONS_ROOT + "/valid", 1) }
+ assert_equal(0, ActiveRecord::Migrator.current_version)
+ end
+
def test_finds_migrations
migrations = ActiveRecord::Migrator.new(:up, MIGRATIONS_ROOT + "/valid").migrations
[['1', 'people_have_last_names'],
@@ -888,16 +938,6 @@ if ActiveRecord::Base.connection.supports_migrations?
ActiveRecord::Migrator.rollback(MIGRATIONS_ROOT + "/valid")
assert_equal(0, ActiveRecord::Migrator.current_version)
end
-
- def test_migrator_run
- assert_equal(0, ActiveRecord::Migrator.current_version)
- ActiveRecord::Migrator.run(:up, MIGRATIONS_ROOT + "/valid", 3)
- assert_equal(0, ActiveRecord::Migrator.current_version)
-
- assert_equal(0, ActiveRecord::Migrator.current_version)
- ActiveRecord::Migrator.run(:down, MIGRATIONS_ROOT + "/valid", 3)
- assert_equal(0, ActiveRecord::Migrator.current_version)
- end
def test_schema_migrations_table_name
ActiveRecord::Base.table_name_prefix = "prefix_"
@@ -1206,10 +1246,10 @@ if ActiveRecord::Base.connection.supports_migrations?
end
def integer_column
- if current_adapter?(:SQLite3Adapter) || current_adapter?(:SQLiteAdapter) || current_adapter?(:PostgreSQLAdapter)
- "integer"
- else
+ if current_adapter?(:MysqlAdapter)
'int(11)'
+ else
+ 'integer'
end
end
diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb
index d890cf7936..7d73541ee1 100644
--- a/activerecord/test/cases/named_scope_test.rb
+++ b/activerecord/test/cases/named_scope_test.rb
@@ -6,7 +6,7 @@ require 'models/reply'
require 'models/author'
class NamedScopeTest < ActiveRecord::TestCase
- fixtures :posts, :authors, :topics, :comments
+ fixtures :posts, :authors, :topics, :comments, :author_addresses
def test_implements_enumerable
assert !Topic.find(:all).empty?
@@ -59,6 +59,16 @@ class NamedScopeTest < ActiveRecord::TestCase
assert_equal Topic.count(:conditions => {:approved => true}), Topic.approved.count
end
+ def test_scopes_with_string_name_can_be_composed
+ # NOTE that scopes defined with a string as a name worked on their own
+ # but when called on another scope the other scope was completely replaced
+ assert_equal Topic.replied.approved, Topic.replied.approved_as_string
+ end
+
+ def test_scopes_can_be_specified_with_deep_hash_conditions
+ assert_equal Topic.replied.approved, Topic.replied.approved_as_hash_condition
+ end
+
def test_scopes_are_composable
assert_equal (approved = Topic.find(:all, :conditions => {:approved => true})), Topic.approved
assert_equal (replied = Topic.find(:all, :conditions => 'replies_count > 0')), Topic.replied
@@ -77,6 +87,25 @@ class NamedScopeTest < ActiveRecord::TestCase
assert_equal topics_written_before_the_second, Topic.written_before(topics(:second).written_on)
end
+ def test_scopes_with_joins
+ address = author_addresses(:david_address)
+ posts_with_authors_at_address = Post.find(
+ :all, :joins => 'JOIN authors ON authors.id = posts.author_id',
+ :conditions => [ 'authors.author_address_id = ?', address.id ]
+ )
+ assert_equal posts_with_authors_at_address, Post.with_authors_at_address(address)
+ end
+
+ def test_scopes_with_joins_respects_custom_select
+ address = author_addresses(:david_address)
+ posts_with_authors_at_address_titles = Post.find(:all,
+ :select => 'title',
+ :joins => 'JOIN authors ON authors.id = posts.author_id',
+ :conditions => [ 'authors.author_address_id = ?', address.id ]
+ )
+ assert_equal posts_with_authors_at_address_titles, Post.with_authors_at_address(address).find(:all, :select => 'title')
+ end
+
def test_extensions
assert_equal 1, Topic.anonymous_extension.one
assert_equal 2, Topic.named_extension.two
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index c42b0efba0..ee7e285a73 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -72,6 +72,52 @@ class SchemaDumperTest < ActiveRecord::TestCase
assert_match %r{:null => false}, output
end
+ def test_schema_dump_includes_limit_constraint_for_integer_columns
+ stream = StringIO.new
+
+ ActiveRecord::SchemaDumper.ignore_tables = [/^(?!integer_limits)/]
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
+ output = stream.string
+
+ if current_adapter?(:PostgreSQLAdapter)
+ assert_match %r{c_int_1.*:limit => 2}, output
+ assert_match %r{c_int_2.*:limit => 2}, output
+
+ # int 3 is 4 bytes in postgresql
+ assert_match %r{c_int_3.*}, output
+ assert_no_match %r{c_int_3.*:limit}, output
+
+ assert_match %r{c_int_4.*}, output
+ assert_no_match %r{c_int_4.*:limit}, output
+ elsif current_adapter?(:MysqlAdapter)
+ assert_match %r{c_int_1.*:limit => 1}, output
+ assert_match %r{c_int_2.*:limit => 2}, output
+ assert_match %r{c_int_3.*:limit => 3}, output
+
+ assert_match %r{c_int_4.*}, output
+ assert_no_match %r{c_int_4.*:limit}, output
+ elsif current_adapter?(:SQLiteAdapter)
+ assert_match %r{c_int_1.*:limit => 1}, output
+ assert_match %r{c_int_2.*:limit => 2}, output
+ assert_match %r{c_int_3.*:limit => 3}, output
+ assert_match %r{c_int_4.*:limit => 4}, output
+ end
+ assert_match %r{c_int_without_limit.*}, output
+ assert_no_match %r{c_int_without_limit.*:limit}, output
+
+ if current_adapter?(:SQLiteAdapter)
+ assert_match %r{c_int_5.*:limit => 5}, output
+ assert_match %r{c_int_6.*:limit => 6}, output
+ assert_match %r{c_int_7.*:limit => 7}, output
+ assert_match %r{c_int_8.*:limit => 8}, output
+ else
+ assert_match %r{c_int_5.*:limit => 8}, output
+ assert_match %r{c_int_6.*:limit => 8}, output
+ assert_match %r{c_int_7.*:limit => 8}, output
+ assert_match %r{c_int_8.*:limit => 8}, output
+ end
+ end
+
def test_schema_dump_with_string_ignored_table
stream = StringIO.new
diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb
index d9101706b5..3adbc0ce1f 100644
--- a/activerecord/test/models/post.rb
+++ b/activerecord/test/models/post.rb
@@ -1,6 +1,11 @@
class Post < ActiveRecord::Base
named_scope :containing_the_letter_a, :conditions => "body LIKE '%a%'"
-
+ named_scope :with_authors_at_address, lambda { |address| {
+ :conditions => [ 'authors.author_address_id = ?', address.id ],
+ :joins => 'JOIN authors ON authors.id = posts.author_id'
+ }
+ }
+
belongs_to :author do
def greeting
"hello"
diff --git a/activerecord/test/models/topic.rb b/activerecord/test/models/topic.rb
index f63e862cfd..47b2eec938 100755
--- a/activerecord/test/models/topic.rb
+++ b/activerecord/test/models/topic.rb
@@ -4,6 +4,8 @@ class Topic < ActiveRecord::Base
{ :conditions => ['written_on < ?', time] }
}
named_scope :approved, :conditions => {:approved => true}
+ named_scope :approved_as_hash_condition, :conditions => {:topics => {:approved => true}}
+ named_scope 'approved_as_string', :conditions => {:approved => true}
named_scope :replied, :conditions => ['replies_count > 0']
named_scope :anonymous_extension do
def one
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 423929fd55..234c43494a 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -407,6 +407,13 @@ ActiveRecord::Schema.define do
t.column :key, :string
end
+ create_table :integer_limits, :force => true do |t|
+ t.integer :"c_int_without_limit"
+ (1..8).each do |i|
+ t.integer :"c_int_#{i}", :limit => i
+ end
+ end
+
except 'SQLite' do
# fk_test_has_fk should be before fk_test_has_pk
create_table :fk_test_has_fk, :force => true do |t|
diff --git a/activeresource/Rakefile b/activeresource/Rakefile
index 89901292a5..8c3ad36a02 100644
--- a/activeresource/Rakefile
+++ b/activeresource/Rakefile
@@ -42,7 +42,7 @@ Rake::RDocTask.new { |rdoc|
rdoc.title = "Active Resource -- Object-oriented REST services"
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
rdoc.options << '--charset' << 'utf-8'
- rdoc.template = "#{ENV['template']}.rb" if ENV['template']
+ rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
rdoc.rdoc_files.include('README', 'CHANGELOG')
rdoc.rdoc_files.include('lib/**/*.rb')
rdoc.rdoc_files.exclude('lib/activeresource.rb')
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index d87558aba9..a540150329 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -1,12 +1,14 @@
*Edge*
+* Added TimeZone #=~, to support matching zones by regex in time_zone_select. #195 [Ernie Miller]
+
* Added Array#second through Array#tenth as aliases for Array#[1] through Array#[9] [DHH]
* Added test/do declaration style testing to ActiveSupport::TestCase [DHH via Jay Fields]
* Added Object#present? which is equivalent to !Object#blank? [DHH]
-* Added Enumberable#many? to encapsulate collection.size > 1 [DHH]
+* Added Enumberable#many? to encapsulate collection.size > 1 [DHH/Damian Janowski]
* Add more standard Hash methods to ActiveSupport::OrderedHash [Steve Purcell]
diff --git a/activesupport/Rakefile b/activesupport/Rakefile
index 74d2750011..f2885c69a4 100644
--- a/activesupport/Rakefile
+++ b/activesupport/Rakefile
@@ -33,7 +33,7 @@ Rake::RDocTask.new { |rdoc|
rdoc.title = "Active Support -- Utility classes and standard library extensions from Rails"
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.options << '--charset' << 'utf-8'
- rdoc.template = "#{ENV['template']}.rb" if ENV['template']
+ rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
rdoc.rdoc_files.include('README', 'CHANGELOG')
rdoc.rdoc_files.include('lib/active_support.rb')
rdoc.rdoc_files.include('lib/active_support/**/*.rb')
diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb
index 2f1143e610..3e3dc18263 100644
--- a/activesupport/lib/active_support/cache.rb
+++ b/activesupport/lib/active_support/cache.rb
@@ -19,19 +19,19 @@ module ActiveSupport
def self.expand_cache_key(key, namespace = nil)
expanded_cache_key = namespace ? "#{namespace}/" : ""
-
+
if ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]
expanded_cache_key << "#{ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]}/"
end
expanded_cache_key << case
- when key.respond_to?(:cache_key)
- key.cache_key
- when key.is_a?(Array)
- key.collect { |element| expand_cache_key(element) }.to_param
- when key.respond_to?(:to_param)
- key.to_param
- end
+ when key.respond_to?(:cache_key)
+ key.cache_key
+ when key.is_a?(Array)
+ key.collect { |element| expand_cache_key(element) }.to_param
+ when key
+ key.to_param
+ end.to_s
expanded_cache_key
end
diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb
index a9882828ca..49ada8f174 100644
--- a/activesupport/lib/active_support/core_ext/array/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/array/conversions.rb
@@ -27,7 +27,7 @@ module ActiveSupport #:nodoc:
# Calls <tt>to_param</tt> on all its elements and joins the result with
# slashes. This is used by <tt>url_for</tt> in Action Pack.
def to_param
- map(&:to_param).join '/'
+ collect { |e| e.to_param }.join '/'
end
# Converts an array into a string suitable for use as a URL query string,
@@ -35,7 +35,8 @@ module ActiveSupport #:nodoc:
#
# ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"
def to_query(key)
- collect { |value| value.to_query("#{key}[]") } * '&'
+ prefix = "#{key}[]"
+ collect { |value| value.to_query(prefix) }.join '&'
end
def self.included(base) #:nodoc:
diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb
index 9647797ec2..e451e9933a 100644
--- a/activesupport/lib/active_support/core_ext/enumerable.rb
+++ b/activesupport/lib/active_support/core_ext/enumerable.rb
@@ -79,7 +79,9 @@ module Enumerable
end
# Returns true if the collection has more than 1 element. Functionally equivalent to collection.size > 1.
- def many?
+ # Works with a block too ala any?, so people.many? { |p| p.age > 26 } # => returns true if more than 1 person is over 26.
+ def many?(&block)
+ size = block_given? ? select(&block).size : self.size
size > 1
end
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
index 26e76ab556..5518f5417b 100644
--- a/activesupport/lib/active_support/core_ext/module/model_naming.rb
+++ b/activesupport/lib/active_support/core_ext/module/model_naming.rb
@@ -1,12 +1,13 @@
module ActiveSupport
class ModelName < String
- attr_reader :singular, :plural, :partial_path
+ attr_reader :singular, :plural, :cache_key, :partial_path
def initialize(name)
super
@singular = underscore.tr('/', '_').freeze
@plural = @singular.pluralize.freeze
- @partial_path = "#{tableize}/#{demodulize.underscore}".freeze
+ @cache_key = tableize.freeze
+ @partial_path = "#{@cache_key}/#{demodulize.underscore}".freeze
end
end
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index 7a8c4d0326..d3d9ff9de4 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -299,7 +299,7 @@ module ActiveSupport #:nodoc:
# Will the provided constant descriptor be unloaded?
def will_unload?(const_desc)
- autoloaded?(desc) ||
+ autoloaded?(const_desc) ||
explicitly_unloadable_constants.include?(to_constant_name(const_desc))
end
diff --git a/activesupport/lib/active_support/testing/performance.rb b/activesupport/lib/active_support/testing/performance.rb
index 2317171467..5f2027eb3b 100644
--- a/activesupport/lib/active_support/testing/performance.rb
+++ b/activesupport/lib/active_support/testing/performance.rb
@@ -18,7 +18,7 @@ module ActiveSupport
{ :benchmark => false,
:runs => 1,
:min_percent => 0.02,
- :metrics => [:process_time, :memory, :objects, :gc_runs, :gc_time],
+ :metrics => [:process_time, :memory, :objects],
:formats => [:flat, :graph_html, :call_tree],
:output => 'tmp/performance' }
end
@@ -99,7 +99,7 @@ module ActiveSupport
def report
rate = @total / profile_options[:runs]
- '%20s: %s/run' % [@metric.name, @metric.format(rate)]
+ '%20s: %s' % [@metric.name, @metric.format(rate)]
end
protected
@@ -288,7 +288,7 @@ module ActiveSupport
end
class CpuTime < Time
- Mode = RubyProf::CPU_TIME
+ Mode = RubyProf::CPU_TIME if RubyProf.const_defined?(:CPU_TIME)
def initialize(*args)
# FIXME: yeah my CPU is 2.33 GHz
@@ -302,7 +302,7 @@ module ActiveSupport
end
class Memory < Base
- Mode = RubyProf::MEMORY
+ Mode = RubyProf::MEMORY if RubyProf.const_defined?(:MEMORY)
# ruby-prof wrapper
if RubyProf.respond_to?(:measure_memory)
@@ -335,7 +335,7 @@ module ActiveSupport
end
class Objects < Base
- Mode = RubyProf::ALLOCATIONS
+ Mode = RubyProf::ALLOCATIONS if RubyProf.const_defined?(:ALLOCATIONS)
if RubyProf.respond_to?(:measure_allocations)
def measure
@@ -353,7 +353,7 @@ module ActiveSupport
end
class GcRuns < Base
- Mode = RubyProf::GC_RUNS
+ Mode = RubyProf::GC_RUNS if RubyProf.const_defined?(:GC_RUNS)
if RubyProf.respond_to?(:measure_gc_runs)
def measure
@@ -375,7 +375,7 @@ module ActiveSupport
end
class GcTime < Base
- Mode = RubyProf::GC_TIME
+ Mode = RubyProf::GC_TIME if RubyProf.const_defined?(:GC_TIME)
if RubyProf.respond_to?(:measure_gc_time)
def measure
diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb
index 5b2d42aa3c..788d40bfa8 100644
--- a/activesupport/lib/active_support/values/time_zone.rb
+++ b/activesupport/lib/active_support/values/time_zone.rb
@@ -201,6 +201,12 @@ module ActiveSupport
result
end
+ # Compare #name and TZInfo identifier to a supplied regexp, returning true
+ # if a match is found.
+ def =~(re)
+ return true if name =~ re || MAPPING[name] =~ re
+ end
+
# Returns a textual representation of this time zone.
def to_s
"(GMT#{formatted_offset}) #{name}"
diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb
index 09b56525e0..f3220d27aa 100644
--- a/activesupport/test/caching_test.rb
+++ b/activesupport/test/caching_test.rb
@@ -1,5 +1,11 @@
require 'abstract_unit'
+class CacheKeyTest < Test::Unit::TestCase
+ def test_expand_cache_key
+ assert_equal 'name/1/2/true', ActiveSupport::Cache.expand_cache_key([1, '2', true], :name)
+ end
+end
+
class CacheStoreSettingTest < Test::Unit::TestCase
def test_file_fragment_cache_store
store = ActiveSupport::Cache.lookup_store :file_store, "/path/to/cache/directory"
diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb
index fb9b9b8916..2315d8f3db 100644
--- a/activesupport/test/core_ext/enumerable_test.rb
+++ b/activesupport/test/core_ext/enumerable_test.rb
@@ -63,10 +63,15 @@ class EnumerableTests < Test::Unit::TestCase
assert_equal({ 5 => payments[0], 15 => payments[1], 10 => payments[2] },
payments.index_by { |p| p.price })
end
-
- def test_several
+
+ def test_many
assert ![].many?
assert ![ 1 ].many?
assert [ 1, 2 ].many?
+
+ assert ![].many? {|x| x > 1 }
+ assert ![ 2 ].many? {|x| x > 1 }
+ assert ![ 1, 2 ].many? {|x| x > 1 }
+ assert [ 1, 2, 2 ].many? {|x| x > 1 }
end
end
diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb
index b42dcd17f8..515ffcf0bf 100644
--- a/activesupport/test/time_zone_test.rb
+++ b/activesupport/test/time_zone_test.rb
@@ -250,6 +250,13 @@ class TimeZoneTest < Test::Unit::TestCase
assert zone1 == zone1
end
+ def test_zone_match
+ zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
+ assert zone =~ /Eastern/
+ assert zone =~ /New_York/
+ assert zone !~ /Nonexistent_Place/
+ end
+
def test_to_s
assert_equal "(GMT+03:00) Moscow", ActiveSupport::TimeZone['Moscow'].to_s
end
diff --git a/doc/template/horo.rb b/doc/template/horo.rb
new file mode 100644
index 0000000000..e028422a2e
--- /dev/null
+++ b/doc/template/horo.rb
@@ -0,0 +1,613 @@
+# Horo RDoc template
+# Author: Hongli Lai - http://izumi.plan99.net/blog/
+#
+# Based on the Jamis template:
+# http://weblog.jamisbuck.org/2005/4/8/rdoc-template
+
+if defined?(RDoc::Diagram)
+ RDoc::Diagram.class_eval do
+ remove_const(:FONT)
+ const_set(:FONT, "\"Bitstream Vera Sans\"")
+ end
+end
+
+module RDoc
+module Page
+
+FONTS = "\"Bitstream Vera Sans\", Verdana, Arial, Helvetica, sans-serif"
+
+STYLE = <<CSS
+a {
+ color: #00F;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #77F;
+ text-decoration: underline;
+}
+
+body, td, p {
+ font-family: %fonts%;
+ background: #FFF;
+ color: #000;
+ margin: 0px;
+ font-size: small;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+#content {
+ margin: 2em;
+ margin-left: 3.5em;
+ margin-right: 3.5em;
+}
+
+#description p {
+ margin-bottom: 0.5em;
+}
+
+.sectiontitle {
+ margin-top: 1em;
+ margin-bottom: 1em;
+ padding: 0.5em;
+ padding-left: 2em;
+ background: #005;
+ color: #FFF;
+ font-weight: bold;
+}
+
+.attr-rw {
+ padding-left: 1em;
+ padding-right: 1em;
+ text-align: center;
+ color: #055;
+}
+
+.attr-name {
+ font-weight: bold;
+}
+
+.attr-desc {
+}
+
+.attr-value {
+ font-family: monospace;
+}
+
+.file-title-prefix {
+ font-size: large;
+}
+
+.file-title {
+ font-size: large;
+ font-weight: bold;
+ background: #005;
+ color: #FFF;
+}
+
+.banner {
+ background: #005;
+ color: #FFF;
+ border: 1px solid black;
+ padding: 1em;
+}
+
+.banner td {
+ background: transparent;
+ color: #FFF;
+}
+
+h1 a, h2 a, .sectiontitle a, .banner a {
+ color: #FF0;
+}
+
+h1 a:hover, h2 a:hover, .sectiontitle a:hover, .banner a:hover {
+ color: #FF7;
+}
+
+.dyn-source {
+ display: none;
+ background: #fffde8;
+ color: #000;
+ border: #ffe0bb dotted 1px;
+ margin: 0.5em 2em 0.5em 2em;
+ padding: 0.5em;
+}
+
+.dyn-source .cmt {
+ color: #00F;
+ font-style: italic;
+}
+
+.dyn-source .kw {
+ color: #070;
+ font-weight: bold;
+}
+
+.method {
+ margin-left: 1em;
+ margin-right: 1em;
+ margin-bottom: 1em;
+}
+
+.description pre {
+ padding: 0.5em;
+ border: #ffe0bb dotted 1px;
+ background: #fffde8;
+}
+
+.method .title {
+ font-family: monospace;
+ font-size: large;
+ border-bottom: 1px dashed black;
+ margin-bottom: 0.3em;
+ padding-bottom: 0.1em;
+}
+
+.method .description, .method .sourcecode {
+ margin-left: 1em;
+}
+
+.description p, .sourcecode p {
+ margin-bottom: 0.5em;
+}
+
+.method .sourcecode p.source-link {
+ text-indent: 0em;
+ margin-top: 0.5em;
+}
+
+.method .aka {
+ margin-top: 0.3em;
+ margin-left: 1em;
+ font-style: italic;
+ text-indent: 2em;
+}
+
+h1 {
+ padding: 1em;
+ margin-left: -1.5em;
+ font-size: x-large;
+ font-weight: bold;
+ color: #FFF;
+ background: #007;
+}
+
+h2 {
+ padding: 0.5em 1em 0.5em 1em;
+ margin-left: -1.5em;
+ font-size: large;
+ font-weight: bold;
+ color: #FFF;
+ background: #009;
+}
+
+h3, h4, h5, h6 {
+ color: #220088;
+ border-bottom: #5522bb solid 1px;
+}
+
+.sourcecode > pre {
+ padding: 0.5em;
+ border: 1px dotted black;
+ background: #FFE;
+}
+
+dt {
+ font-weight: bold
+}
+
+dd {
+ margin-bottom: 0.7em;
+}
+CSS
+
+XHTML_PREAMBLE = %{<?xml version="1.0" encoding="%charset%"?>
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+}
+
+XHTML_FRAMESET_PREAMBLE = %{
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
+}
+
+HEADER = XHTML_PREAMBLE + <<ENDHEADER
+<html>
+ <head>
+ <title>%title%</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
+ <link rel="stylesheet" href="%style_url%" type="text/css" media="screen" />
+
+ <script language="JavaScript" type="text/javascript">
+ // <![CDATA[
+
+ function toggleSource( id )
+ {
+ var elem
+ var link
+
+ if( document.getElementById )
+ {
+ elem = document.getElementById( id )
+ link = document.getElementById( "l_" + id )
+ }
+ else if ( document.all )
+ {
+ elem = eval( "document.all." + id )
+ link = eval( "document.all.l_" + id )
+ }
+ else
+ return false;
+
+ if( elem.style.display == "block" )
+ {
+ elem.style.display = "none"
+ link.innerHTML = "show source"
+ }
+ else
+ {
+ elem.style.display = "block"
+ link.innerHTML = "hide source"
+ }
+ }
+
+ function openCode( url )
+ {
+ window.open( url, "SOURCE_CODE", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=480,width=750" ).focus();
+ }
+ // ]]>
+ </script>
+ </head>
+
+ <body>
+ENDHEADER
+
+FILE_PAGE = <<HTML
+<table border='0' cellpadding='0' cellspacing='0' width="100%" class='banner'>
+ <tr><td>
+ <table width="100%" border='0' cellpadding='0' cellspacing='0'><tr>
+ <td class="file-title" colspan="2"><span class="file-title-prefix">File</span><br />%short_name%</td>
+ <td align="right">
+ <table border='0' cellspacing="0" cellpadding="2">
+ <tr>
+ <td>Path:</td>
+ <td>%full_path%
+IF:cvsurl
+ &nbsp;(<a href="%cvsurl%">CVS</a>)
+ENDIF:cvsurl
+ </td>
+ </tr>
+ <tr>
+ <td>Modified:</td>
+ <td>%dtm_modified%</td>
+ </tr>
+ </table>
+ </td></tr>
+ </table>
+ </td></tr>
+</table><br />
+HTML
+
+###################################################################
+
+CLASS_PAGE = <<HTML
+<table width="100%" border='0' cellpadding='0' cellspacing='0' class='banner'><tr>
+ <td class="file-title"><span class="file-title-prefix">%classmod%</span><br />%full_name%</td>
+ <td align="right">
+ <table cellspacing="0" cellpadding="2">
+ <tr valign="top">
+ <td>In:</td>
+ <td>
+START:infiles
+HREF:full_path_url:full_path:
+IF:cvsurl
+&nbsp;(<a href="%cvsurl%">CVS</a>)
+ENDIF:cvsurl
+END:infiles
+ </td>
+ </tr>
+IF:parent
+ <tr>
+ <td>Parent:</td>
+ <td>
+IF:par_url
+ <a href="%par_url%">
+ENDIF:par_url
+%parent%
+IF:par_url
+ </a>
+ENDIF:par_url
+ </td>
+ </tr>
+ENDIF:parent
+ </table>
+ </td>
+ </tr>
+ </table>
+HTML
+
+###################################################################
+
+METHOD_LIST = <<HTML
+ <div id="content">
+IF:diagram
+ <table cellpadding='0' cellspacing='0' border='0' width="100%"><tr><td align="center">
+ %diagram%
+ </td></tr></table>
+ENDIF:diagram
+
+IF:description
+ <div class="description">%description%</div>
+ENDIF:description
+
+IF:requires
+ <div class="sectiontitle">Required Files</div>
+ <ul>
+START:requires
+ <li>HREF:aref:name:</li>
+END:requires
+ </ul>
+ENDIF:requires
+
+IF:toc
+ <div class="sectiontitle">Contents</div>
+ <ul>
+START:toc
+ <li><a href="#%href%">%secname%</a></li>
+END:toc
+ </ul>
+ENDIF:toc
+
+IF:methods
+ <div class="sectiontitle">Methods</div>
+ <ul>
+START:methods
+ <li>HREF:aref:name:</li>
+END:methods
+ </ul>
+ENDIF:methods
+
+IF:includes
+<div class="sectiontitle">Included Modules</div>
+<ul>
+START:includes
+ <li>HREF:aref:name:</li>
+END:includes
+</ul>
+ENDIF:includes
+
+START:sections
+IF:sectitle
+<div class="sectiontitle"><a name="%secsequence%">%sectitle%</a></div>
+IF:seccomment
+<div class="description">
+%seccomment%
+</div>
+ENDIF:seccomment
+ENDIF:sectitle
+
+IF:classlist
+ <div class="sectiontitle">Classes and Modules</div>
+ %classlist%
+ENDIF:classlist
+
+IF:constants
+ <div class="sectiontitle">Constants</div>
+ <table border='0' cellpadding='5'>
+START:constants
+ <tr valign='top'>
+ <td class="attr-name">%name%</td>
+ <td>=</td>
+ <td class="attr-value">%value%</td>
+ </tr>
+IF:desc
+ <tr valign='top'>
+ <td>&nbsp;</td>
+ <td colspan="2" class="attr-desc">%desc%</td>
+ </tr>
+ENDIF:desc
+END:constants
+ </table>
+ENDIF:constants
+
+IF:attributes
+ <div class="sectiontitle">Attributes</div>
+ <table border='0' cellpadding='5'>
+START:attributes
+ <tr valign='top'>
+ <td class='attr-rw'>
+IF:rw
+[%rw%]
+ENDIF:rw
+ </td>
+ <td class='attr-name'>%name%</td>
+ <td class='attr-desc'>%a_desc%</td>
+ </tr>
+END:attributes
+ </table>
+ENDIF:attributes
+
+IF:method_list
+START:method_list
+IF:methods
+<div class="sectiontitle">%type% %category% methods</div>
+START:methods
+<div class="method">
+ <div class="title">
+IF:callseq
+ <a name="%aref%"></a><b>%callseq%</b>
+ENDIF:callseq
+IFNOT:callseq
+ <a name="%aref%"></a><b>%name%</b>%params%
+ENDIF:callseq
+IF:codeurl
+[&nbsp;<a href="%codeurl%" target="SOURCE_CODE" onclick="javascript:openCode('%codeurl%'); return false;">source</a>&nbsp;]
+ENDIF:codeurl
+ </div>
+IF:m_desc
+ <div class="description">
+ %m_desc%
+ </div>
+ENDIF:m_desc
+IF:aka
+<div class="aka">
+ This method is also aliased as
+START:aka
+ <a href="%aref%">%name%</a>
+END:aka
+</div>
+ENDIF:aka
+IF:sourcecode
+<div class="sourcecode">
+ <p class="source-link">[ <a href="javascript:toggleSource('%aref%_source')" id="l_%aref%_source">show source</a> ]</p>
+ <div id="%aref%_source" class="dyn-source">
+<pre>
+%sourcecode%
+</pre>
+ </div>
+</div>
+ENDIF:sourcecode
+</div>
+END:methods
+ENDIF:methods
+END:method_list
+ENDIF:method_list
+END:sections
+</div>
+HTML
+
+FOOTER = <<ENDFOOTER
+ </body>
+</html>
+ENDFOOTER
+
+BODY = HEADER + <<ENDBODY
+ !INCLUDE! <!-- banner header -->
+
+ <div id="bodyContent">
+ #{METHOD_LIST}
+ </div>
+
+ #{FOOTER}
+ENDBODY
+
+########################## Source code ##########################
+
+SRC_PAGE = XHTML_PREAMBLE + <<HTML
+<html>
+<head><title>%title%</title>
+<meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
+<style type="text/css">
+.ruby-comment { color: green; font-style: italic }
+.ruby-constant { color: #4433aa; font-weight: bold; }
+.ruby-identifier { color: #222222; }
+.ruby-ivar { color: #2233dd; }
+.ruby-keyword { color: #3333FF; font-weight: bold }
+.ruby-node { color: #777777; }
+.ruby-operator { color: #111111; }
+.ruby-regexp { color: #662222; }
+.ruby-value { color: #662222; font-style: italic }
+ .kw { color: #3333FF; font-weight: bold }
+ .cmt { color: green; font-style: italic }
+ .str { color: #662222; font-style: italic }
+ .re { color: #662222; }
+</style>
+</head>
+<body bgcolor="white">
+<pre>%code%</pre>
+</body>
+</html>
+HTML
+
+########################## Index ################################
+
+FR_INDEX_BODY = <<HTML
+!INCLUDE!
+HTML
+
+FILE_INDEX = XHTML_PREAMBLE + <<HTML
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
+<title>Index</title>
+<style type="text/css">
+<!--
+ body {
+ background-color: #EEE;
+ font-family: #{FONTS};
+ color: #000;
+ margin: 0px;
+ }
+ .banner {
+ background: #005;
+ color: #FFF;
+ padding: 0.2em;
+ font-size: small;
+ font-weight: bold;
+ text-align: center;
+ }
+ .entries {
+ margin: 0.25em 1em 0 1em;
+ font-size: x-small;
+ }
+ a {
+ color: #00F;
+ text-decoration: none;
+ white-space: nowrap;
+ }
+ a:hover {
+ color: #77F;
+ text-decoration: underline;
+ }
+-->
+</style>
+<base target="docwin" />
+</head>
+<body>
+<div class="banner">%list_title%</div>
+<div class="entries">
+START:entries
+<a href="%href%">%name%</a><br />
+END:entries
+</div>
+</body></html>
+HTML
+
+CLASS_INDEX = FILE_INDEX
+METHOD_INDEX = FILE_INDEX
+
+INDEX = XHTML_FRAMESET_PREAMBLE + <<HTML
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>%title%</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
+</head>
+
+<frameset cols="20%,*">
+ <frameset rows="15%,55%,30%">
+ <frame src="fr_file_index.html" title="Files" name="Files" />
+ <frame src="fr_class_index.html" name="Classes" />
+ <frame src="fr_method_index.html" name="Methods" />
+ </frameset>
+ <frame src="%initial_page%" name="docwin" />
+ <noframes>
+ <body bgcolor="white">
+ Click <a href="html/index.html">here</a> for a non-frames
+ version of this page.
+ </body>
+ </noframes>
+</frameset>
+
+</html>
+HTML
+
+end
+end
+
diff --git a/railties/CHANGELOG b/railties/CHANGELOG
index 27d4313862..a37dc6c0eb 100644
--- a/railties/CHANGELOG
+++ b/railties/CHANGELOG
@@ -1,5 +1,9 @@
*Edge*
+* Added Thin support to script/server. #488 [Bob Klosinski]
+
+* Fix script/about in production mode. #370 [Cheah Chu Yeow, Xavier Noria, David Krmpotic]
+
* Add the gem load paths before the framework is loaded, so certain gems like RedCloth and BlueCloth can be frozen.
* Fix discrepancies with loading rails/init.rb from gems.
diff --git a/railties/Rakefile b/railties/Rakefile
index 78fe8e6662..f64b60b0dd 100644
--- a/railties/Rakefile
+++ b/railties/Rakefile
@@ -264,7 +264,7 @@ Rake::RDocTask.new { |rdoc|
rdoc.title = "Railties -- Gluing the Engine to the Rails"
rdoc.options << '--line-numbers' << '--inline-source' << '--accessor' << 'cattr_accessor=object'
rdoc.options << '--charset' << 'utf-8'
- rdoc.template = "#{ENV['template']}.rb" if ENV['template']
+ rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
rdoc.rdoc_files.include('README', 'CHANGELOG')
rdoc.rdoc_files.include('lib/*.rb')
rdoc.rdoc_files.include('lib/rails/*.rb')
diff --git a/railties/bin/about b/railties/bin/about
index cd38a32abf..ed8deb0dfc 100644
--- a/railties/bin/about
+++ b/railties/bin/about
@@ -1,3 +1,4 @@
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
-require 'commands/about'
+$LOAD_PATH.unshift "#{RAILTIES_PATH}/builtin/rails_info"
+require 'commands/about' \ No newline at end of file
diff --git a/railties/lib/commands/about.rb b/railties/lib/commands/about.rb
index 313bc18c6a..7f53ac8a2e 100644
--- a/railties/lib/commands/about.rb
+++ b/railties/lib/commands/about.rb
@@ -1,2 +1,3 @@
require 'environment'
+require 'rails/info'
puts Rails::Info
diff --git a/railties/lib/commands/server.rb b/railties/lib/commands/server.rb
index 40ffdd1167..7306c248fb 100644
--- a/railties/lib/commands/server.rb
+++ b/railties/lib/commands/server.rb
@@ -13,11 +13,19 @@ rescue Exception
# Mongrel not available
end
+begin
+ require_library_or_gem 'thin'
+rescue Exception
+ # Thin not available
+end
+
server = case ARGV.first
- when "lighttpd", "mongrel", "new_mongrel", "webrick"
+ when "lighttpd", "mongrel", "new_mongrel", "webrick", "thin"
ARGV.shift
else
- if defined?(Mongrel)
+ if defined?(Thin)
+ "thin"
+ elsif defined?(Mongrel)
"mongrel"
elsif RUBY_PLATFORM !~ /(:?mswin|mingw)/ && !silence_stderr { `lighttpd -version` }.blank? && defined?(FCGI)
"lighttpd"
@@ -33,6 +41,8 @@ case server
puts "=> Booting lighttpd (use 'script/server webrick' to force WEBrick)"
when "mongrel", "new_mongrel"
puts "=> Booting Mongrel (use 'script/server webrick' to force WEBrick)"
+ when "thin"
+ puts "=> Booting Thin (use 'script/server webrick' to force WEBrick)"
end
%w(cache pids sessions sockets).each { |dir_to_make| FileUtils.mkdir_p(File.join(RAILS_ROOT, 'tmp', dir_to_make)) }
diff --git a/railties/lib/commands/servers/thin.rb b/railties/lib/commands/servers/thin.rb
new file mode 100644
index 0000000000..833469cab1
--- /dev/null
+++ b/railties/lib/commands/servers/thin.rb
@@ -0,0 +1,25 @@
+require 'rbconfig'
+require 'commands/servers/base'
+require 'thin'
+
+
+options = ARGV.clone
+options.insert(0,'start') unless Thin::Runner.commands.include?(options[0])
+
+thin = Thin::Runner.new(options)
+
+puts "=> Rails #{Rails.version} application starting on http://#{thin.options[:address]}:#{thin.options[:port]}"
+puts "=> Ctrl-C to shutdown server"
+
+log = Pathname.new("#{File.expand_path(RAILS_ROOT)}/log/#{RAILS_ENV}.log").cleanpath
+open(log, (File::WRONLY | File::APPEND | File::CREAT)) unless File.exist? log
+tail_thread = tail(log)
+trap(:INT) { exit }
+
+begin
+ thin.run!
+ensure
+ tail_thread.kill if tail_thread
+ puts 'Exiting'
+end
+
diff --git a/railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb b/railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb
index cae38e9a2a..03f6d5666e 100644
--- a/railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb
+++ b/railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb
@@ -1,6 +1,6 @@
require 'test_helper'
-class <%= class_name %>ObserverTest < Test::Unit::TestCase
+class <%= class_name %>ObserverTest < ActiveSupport::TestCase
# Replace this with your real tests.
test "the truth" do
assert true
diff --git a/railties/lib/rails_generator/generators/components/performance_test/USAGE b/railties/lib/rails_generator/generators/components/performance_test/USAGE
new file mode 100644
index 0000000000..d84051eb02
--- /dev/null
+++ b/railties/lib/rails_generator/generators/components/performance_test/USAGE
@@ -0,0 +1,8 @@
+Description:
+ Stubs out a new performance test. Pass the name of the test, either
+ CamelCased or under_scored, as an argument. The new test class is
+ generated in test/performance/testname_test.rb
+
+Example:
+ `./script/generate performance_test GeneralStories` creates a GeneralStories
+ performance test in test/performance/general_stories_test.rb
diff --git a/railties/lib/rails_generator/generators/components/performance_test/performance_test_generator.rb b/railties/lib/rails_generator/generators/components/performance_test/performance_test_generator.rb
new file mode 100644
index 0000000000..fbcc1cf683
--- /dev/null
+++ b/railties/lib/rails_generator/generators/components/performance_test/performance_test_generator.rb
@@ -0,0 +1,16 @@
+class PerformanceTestGenerator < Rails::Generator::NamedBase
+ default_options :skip_migration => false
+
+ def manifest
+ record do |m|
+ # Check for class naming collisions.
+ m.class_collisions class_path, class_name, "#{class_name}Test"
+
+ # performance test directory
+ m.directory File.join('test/performance', class_path)
+
+ # performance test stub
+ m.template 'performance_test.rb', File.join('test/performance', class_path, "#{file_name}_test.rb")
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/performance_test/templates/performance_test.rb b/railties/lib/rails_generator/generators/components/performance_test/templates/performance_test.rb
new file mode 100644
index 0000000000..352ff48054
--- /dev/null
+++ b/railties/lib/rails_generator/generators/components/performance_test/templates/performance_test.rb
@@ -0,0 +1,8 @@
+require 'performance/test_helper'
+
+class <%= class_name %>Test < ActionController::PerformanceTest
+ # Replace this with your real tests.
+ def test_homepage
+ get '/'
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb b/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb
index e2902bf4b9..5fecfe0167 100644
--- a/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb
+++ b/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb
@@ -1,5 +1,5 @@
class ScaffoldGenerator < Rails::Generator::NamedBase
- default_options :skip_timestamps => false, :skip_migration => false
+ default_options :skip_timestamps => false, :skip_migration => false, :force_plural => false
attr_reader :controller_name,
:controller_class_path,
@@ -16,6 +16,11 @@ class ScaffoldGenerator < Rails::Generator::NamedBase
def initialize(runtime_args, runtime_options = {})
super
+ if @name == @name.pluralize && !options[:force_plural]
+ logger.warning "Plural version of the model detected, using singularized version. Override with --force-plural."
+ @name = @name.singularize
+ end
+
@controller_name = @name.pluralize
base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@controller_name)
@@ -81,6 +86,8 @@ class ScaffoldGenerator < Rails::Generator::NamedBase
"Don't add timestamps to the migration file for this model") { |v| options[:skip_timestamps] = v }
opt.on("--skip-migration",
"Don't generate a migration file for this model") { |v| options[:skip_migration] = v }
+ opt.on("--force-plural",
+ "Forces the generation of a plural ModelName") { |v| options[:force_plural] = v }
end
def scaffold_views
diff --git a/railties/test/generators/rails_scaffold_generator_test.rb b/railties/test/generators/rails_scaffold_generator_test.rb
index 220f9e372e..de6b38dafe 100644
--- a/railties/test/generators/rails_scaffold_generator_test.rb
+++ b/railties/test/generators/rails_scaffold_generator_test.rb
@@ -1,4 +1,5 @@
require 'generators/generator_test_helper'
+require 'abstract_unit'
class RailsScaffoldGeneratorTest < GeneratorTestCase
@@ -104,4 +105,45 @@ class RailsScaffoldGeneratorTest < GeneratorTestCase
assert_added_route_for :products
end
+ uses_mocha("scaffold_force_plural_names") do
+ def test_scaffolded_plural_names
+ Rails::Generator::Base.logger.expects(:warning)
+ g = Rails::Generator::Base.instance('scaffold', %w(ProductLines))
+ assert_equal "ProductLines", g.controller_name
+ assert_equal "ProductLines", g.controller_class_name
+ assert_equal "ProductLine", g.controller_singular_name
+ assert_equal "product_lines", g.controller_plural_name
+ assert_equal "product_lines", g.controller_file_name
+ assert_equal "product_lines", g.controller_table_name
+ end
+ end
+
+ def test_scaffold_plural_model_name_without_force_plural_generates_singular_model
+ run_generator('scaffold', %w(Products name:string))
+
+ assert_generated_model_for :product
+ assert_generated_functional_test_for :products
+ assert_generated_unit_test_for :product
+ assert_generated_fixtures_for :products
+ assert_generated_helper_for :products
+ assert_generated_stylesheet :scaffold
+ assert_generated_views_for :products, "index.html.erb","new.html.erb","edit.html.erb","show.html.erb"
+ assert_skipped_migration :create_products
+ assert_added_route_for :products
+ end
+
+ def test_scaffold_plural_model_name_with_force_plural_forces_plural_model
+ run_generator('scaffold', %w(Products name:string --force-plural))
+
+ assert_generated_model_for :products
+ assert_generated_functional_test_for :products
+ assert_generated_unit_test_for :products
+ assert_generated_fixtures_for :products
+ assert_generated_helper_for :products
+ assert_generated_stylesheet :scaffold
+ assert_generated_views_for :products, "index.html.erb","new.html.erb","edit.html.erb","show.html.erb"
+ assert_skipped_migration :create_products
+ assert_added_route_for :products
+ end
+
end