aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionmailer/lib/action_mailer/base.rb27
-rw-r--r--actionmailer/test/delivery_method_test.rb22
-rw-r--r--actionmailer/test/mail_service_test.rb17
-rw-r--r--actionpack/examples/very_simple.rb4
-rw-r--r--actionpack/lib/abstract_controller.rb20
-rw-r--r--actionpack/lib/abstract_controller/helpers.rb2
-rw-r--r--actionpack/lib/abstract_controller/layouts.rb24
-rw-r--r--actionpack/lib/abstract_controller/rendering_controller.rb (renamed from actionpack/lib/abstract_controller/renderer.rb)6
-rw-r--r--actionpack/lib/action_controller.rb6
-rw-r--r--actionpack/lib/action_controller/base.rb6
-rw-r--r--actionpack/lib/action_controller/caching/fragments.rb4
-rw-r--r--actionpack/lib/action_controller/legacy/layout.rb2
-rw-r--r--actionpack/lib/action_controller/metal/conditional_get.rb7
-rw-r--r--actionpack/lib/action_controller/metal/layouts.rb2
-rw-r--r--actionpack/lib/action_controller/metal/mime_responds.rb115
-rw-r--r--actionpack/lib/action_controller/metal/render_options.rb10
-rw-r--r--actionpack/lib/action_controller/metal/rendering_controller.rb (renamed from actionpack/lib/action_controller/metal/renderer.rb)7
-rw-r--r--actionpack/lib/action_controller/metal/responder.rb181
-rw-r--r--actionpack/lib/action_controller/metal/streaming.rb2
-rw-r--r--actionpack/lib/action_controller/metal/verification.rb4
-rw-r--r--actionpack/lib/action_controller/routing/generation/polymorphic_routes.rb28
-rw-r--r--actionpack/lib/action_view/base.rb2
-rw-r--r--actionpack/lib/action_view/helpers/active_model_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/number_helper.rb2
-rw-r--r--actionpack/lib/action_view/paths.rb10
-rw-r--r--actionpack/lib/action_view/render/partials.rb142
-rw-r--r--actionpack/lib/action_view/render/rendering.rb7
-rw-r--r--actionpack/lib/action_view/template/resolver.rb2
-rw-r--r--actionpack/test/abstract_controller/abstract_controller_test.rb10
-rw-r--r--actionpack/test/abstract_controller/helper_test.rb4
-rw-r--r--actionpack/test/abstract_controller/layouts_test.rb2
-rw-r--r--actionpack/test/activerecord/polymorphic_routes_test.rb55
-rw-r--r--actionpack/test/controller/caching_test.rb15
-rw-r--r--actionpack/test/controller/mime_responds_test.rb198
-rw-r--r--actionpack/test/controller/render_test.rb17
-rw-r--r--actionpack/test/controller/render_xml_test.rb4
-rw-r--r--actionpack/test/controller/routing_test.rb2
-rw-r--r--actionpack/test/fixtures/respond_with/edit.html.erb1
-rw-r--r--actionpack/test/fixtures/respond_with/new.html.erb1
-rw-r--r--actionpack/test/fixtures/respond_with/using_resource.html.erb1
-rw-r--r--actionpack/test/fixtures/respond_with/using_resource.js.rjs1
-rw-r--r--actionpack/test/lib/controller/fake_models.rb22
-rw-r--r--actionpack/test/template/number_helper_test.rb1
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb2
-rwxr-xr-xactiverecord/lib/active_record/base.rb7
-rw-r--r--activerecord/lib/active_record/migration.rb10
-rw-r--r--activerecord/test/cases/adapter_test.rb8
-rw-r--r--activerecord/test/cases/associations/belongs_to_associations_test.rb6
-rw-r--r--activerecord/test/cases/associations/eager_test.rb7
-rw-r--r--activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb6
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb80
-rw-r--r--activerecord/test/cases/associations/join_model_test.rb10
-rw-r--r--activerecord/test/cases/attribute_methods_test.rb14
-rw-r--r--activerecord/test/cases/autosave_association_test.rb46
-rwxr-xr-xactiverecord/test/cases/base_test.rb17
-rw-r--r--activerecord/test/cases/calculations_test.rb7
-rw-r--r--activerecord/test/cases/database_statements_test.rb9
-rw-r--r--activerecord/test/cases/finder_test.rb59
-rw-r--r--activerecord/test/cases/inheritance_test.rb3
-rw-r--r--activerecord/test/cases/invalid_date_test.rb14
-rw-r--r--activerecord/test/cases/method_scoping_test.rb1
-rw-r--r--activerecord/test/cases/migration_test.rb83
-rw-r--r--activerecord/test/cases/named_scope_test.rb3
-rw-r--r--activerecord/test/cases/nested_attributes_test.rb37
-rw-r--r--activerecord/test/cases/query_cache_test.rb7
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb12
-rw-r--r--activerecord/test/cases/validations/association_validation_test.rb23
-rw-r--r--activerecord/test/connections/native_oracle/connection.rb55
-rw-r--r--activerecord/test/models/company.rb8
-rw-r--r--activerecord/test/models/subject.rb10
-rw-r--r--activerecord/test/schema/oracle_specific_schema.rb27
-rw-r--r--activerecord/test/schema/schema.rb31
-rw-r--r--activeresource/lib/active_resource/connection.rb2
-rw-r--r--activesupport/lib/active_support/json/backends/yaml.rb17
-rw-r--r--activesupport/test/json/decoding_test.rb8
-rw-r--r--railties/lib/generators.rb66
-rw-r--r--railties/lib/generators/active_model.rb (renamed from railties/lib/generators/action_orm.rb)14
-rw-r--r--railties/lib/generators/active_record.rb4
-rw-r--r--railties/lib/generators/named_base.rb10
-rw-r--r--railties/lib/generators/rails/app/app_generator.rb21
-rw-r--r--railties/lib/tasks/databases.rake15
-rw-r--r--railties/lib/tasks/routes.rake7
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/error.rb27
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/tasks.rb4
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/tasks/install.rb35
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/tasks/package.rb31
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/tasks/spec.rb70
-rw-r--r--railties/lib/vendor/thor-0.11.5/CHANGELOG.rdoc (renamed from railties/lib/vendor/thor-0.11.3/CHANGELOG.rdoc)6
-rw-r--r--railties/lib/vendor/thor-0.11.5/LICENSE (renamed from railties/lib/vendor/thor-0.11.3/LICENSE)0
-rw-r--r--railties/lib/vendor/thor-0.11.5/README.rdoc (renamed from railties/lib/vendor/thor-0.11.3/README.markdown)75
-rwxr-xr-xrailties/lib/vendor/thor-0.11.5/bin/rake2thor (renamed from railties/lib/vendor/thor-0.11.3/bin/rake2thor)0
-rwxr-xr-xrailties/lib/vendor/thor-0.11.5/bin/thor (renamed from railties/lib/vendor/thor-0.11.3/bin/thor)0
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor.rb)39
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/actions.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/actions.rb)30
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/actions/create_file.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/actions/create_file.rb)0
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/actions/directory.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/actions/directory.rb)2
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/actions/empty_directory.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/actions/empty_directory.rb)0
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/actions/file_manipulation.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/actions/file_manipulation.rb)0
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/actions/inject_into_file.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/actions/inject_into_file.rb)2
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/base.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/base.rb)42
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/core_ext/hash_with_indifferent_access.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/core_ext/hash_with_indifferent_access.rb)4
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/core_ext/ordered_hash.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/core_ext/ordered_hash.rb)4
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/error.rb27
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/group.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/group.rb)6
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/invocation.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/invocation.rb)42
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/parser.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/parser.rb)0
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/parser/argument.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/parser/argument.rb)2
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/parser/arguments.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/parser/arguments.rb)2
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/parser/option.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/parser/option.rb)2
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/parser/options.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/parser/options.rb)2
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/rake_compat.rb67
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/runner.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/runner.rb)22
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/shell.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/shell.rb)2
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/shell/basic.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/shell/basic.rb)38
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/shell/color.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/shell/color.rb)16
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/task.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/task.rb)24
-rw-r--r--railties/lib/vendor/thor-0.11.5/lib/thor/util.rb (renamed from railties/lib/vendor/thor-0.11.3/lib/thor/util.rb)41
-rw-r--r--railties/test/fixtures/lib/template.rb1
-rw-r--r--railties/test/fixtures/vendor/gems/gems/mspec/lib/generators/mspec_generator.rb (renamed from railties/test/fixtures/vendor/gems/mspec/lib/generators/mspec_generator.rb)0
-rw-r--r--railties/test/fixtures/vendor/gems/gems/wrong/lib/generators/wrong_generator.rb (renamed from railties/test/fixtures/vendor/gems/wrong/lib/generators/wrong_generator.rb)0
-rw-r--r--railties/test/generators/app_generator_test.rb5
-rw-r--r--railties/test/generators/generators_test_helper.rb2
-rw-r--r--railties/test/generators/scaffold_controller_generator_test.rb2
124 files changed, 1608 insertions, 833 deletions
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index 7b03a7f9ff..5ecefe7c09 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -1,3 +1,5 @@
+require 'tmpdir'
+
require "active_support/core_ext/class"
# Use the old layouts until actionmailer gets refactored
require "action_controller/legacy/layout"
@@ -224,9 +226,13 @@ module ActionMailer #:nodoc:
# * <tt>:location</tt> - The location of the sendmail executable. Defaults to <tt>/usr/sbin/sendmail</tt>.
# * <tt>:arguments</tt> - The command line arguments. Defaults to <tt>-i -t</tt>.
#
+ # * <tt>file_settings</tt> - Allows you to override options for the <tt>:file</tt> delivery method.
+ # * <tt>:location</tt> - The directory into which emails will be written. Defaults to the application <tt>tmp/mails</tt>.
+ #
# * <tt>raise_delivery_errors</tt> - Whether or not errors should be raised if the email fails to be delivered.
#
- # * <tt>delivery_method</tt> - Defines a delivery method. Possible values are <tt>:smtp</tt> (default), <tt>:sendmail</tt>, and <tt>:test</tt>.
+ # * <tt>delivery_method</tt> - Defines a delivery method. Possible values are <tt>:smtp</tt> (default), <tt>:sendmail</tt>, <tt>:test</tt>,
+ # and <tt>:file</tt>.
#
# * <tt>perform_deliveries</tt> - Determines whether <tt>deliver_*</tt> methods are actually carried out. By default they are,
# but this can be turned off to help functional testing.
@@ -279,6 +285,12 @@ module ActionMailer #:nodoc:
}
cattr_accessor :sendmail_settings
+ @@file_settings = {
+ :location => defined?(Rails) ? "#{Rails.root}/tmp/mails" : "#{Dir.tmpdir}/mails"
+ }
+
+ cattr_accessor :file_settings
+
@@raise_delivery_errors = true
cattr_accessor :raise_delivery_errors
@@ -499,7 +511,7 @@ module ActionMailer #:nodoc:
# ====
# TODO: Revisit this
# template_exists = @parts.empty?
- # template_exists ||= template_root.find_by_parts("#{mailer_name}/#{@template}")
+ # template_exists ||= template_root.find("#{mailer_name}/#{@template}")
# @body = render_message(@template, @body) if template_exists
# Finally, if there are other message parts and a textual body exists,
@@ -556,6 +568,7 @@ module ActionMailer #:nodoc:
@headers ||= {}
@body ||= {}
@mime_version = @@default_mime_version.dup if @@default_mime_version
+ @sent_on ||= Time.now
end
def render_template(template, body)
@@ -585,7 +598,7 @@ module ActionMailer #:nodoc:
if file
prefix = mailer_name unless file =~ /\//
- template = view_paths.find_by_parts(file, {:formats => formats}, prefix)
+ template = view_paths.find(file, {:formats => formats}, prefix)
end
layout = _pick_layout(layout,
@@ -723,6 +736,14 @@ module ActionMailer #:nodoc:
def perform_delivery_test(mail)
deliveries << mail
end
+
+ def perform_delivery_file(mail)
+ FileUtils.mkdir_p file_settings[:location]
+
+ (mail.to + mail.cc + mail.bcc).uniq.each do |to|
+ File.open(File.join(file_settings[:location], to), 'a') { |f| f.write(mail) }
+ end
+ end
end
Base.class_eval do
diff --git a/actionmailer/test/delivery_method_test.rb b/actionmailer/test/delivery_method_test.rb
index 0731512ea4..1b8c3ba523 100644
--- a/actionmailer/test/delivery_method_test.rb
+++ b/actionmailer/test/delivery_method_test.rb
@@ -7,6 +7,10 @@ class NonDefaultDeliveryMethodMailer < ActionMailer::Base
self.delivery_method = :sendmail
end
+class FileDeliveryMethodMailer < ActionMailer::Base
+ self.delivery_method = :file
+end
+
class ActionMailerBase_delivery_method_Test < Test::Unit::TestCase
def setup
set_delivery_method :smtp
@@ -49,3 +53,21 @@ class NonDefaultDeliveryMethodMailer_delivery_method_Test < Test::Unit::TestCase
end
end
+class FileDeliveryMethodMailer_delivery_method_Test < Test::Unit::TestCase
+ def setup
+ set_delivery_method :smtp
+ end
+
+ def teardown
+ restore_delivery_method
+ end
+
+ def test_should_be_the_set_delivery_method
+ assert_equal :file, FileDeliveryMethodMailer.delivery_method
+ end
+
+ def test_should_default_location_to_the_tmpdir
+ assert_equal "#{Dir.tmpdir}/mails", ActionMailer::Base.file_settings[:location]
+ end
+end
+
diff --git a/actionmailer/test/mail_service_test.rb b/actionmailer/test/mail_service_test.rb
index f2a8c2303c..008ca498b1 100644
--- a/actionmailer/test/mail_service_test.rb
+++ b/actionmailer/test/mail_service_test.rb
@@ -18,7 +18,6 @@ class TestMailer < ActionMailer::Base
@recipients = recipient
@subject = "[Signed up] Welcome #{recipient}"
@from = "system@loudthinking.com"
- @sent_on = Time.local(2004, 12, 12)
@body["recipient"] = recipient
end
@@ -357,12 +356,14 @@ class ActionMailerTest < Test::Unit::TestCase
end
def test_signed_up
+ Time.stubs(:now => Time.now)
+
expected = new_mail
expected.to = @recipient
expected.subject = "[Signed up] Welcome #{@recipient}"
expected.body = "Hello there, \n\nMr. #{@recipient}"
expected.from = "system@loudthinking.com"
- expected.date = Time.local(2004, 12, 12)
+ expected.date = Time.now
created = nil
assert_nothing_raised { created = TestMailer.create_signed_up(@recipient) }
@@ -888,6 +889,18 @@ EOF
assert_no_match %r{^Bcc: root@loudthinking.com}, MockSMTP.deliveries[0][0]
end
+ def test_file_delivery_should_create_a_file
+ ActionMailer::Base.delivery_method = :file
+ tmp_location = ActionMailer::Base.file_settings[:location]
+
+ TestMailer.deliver_cc_bcc(@recipient)
+ assert File.exists? tmp_location
+ assert File.directory? tmp_location
+ assert File.exists? File.join(tmp_location, @recipient)
+ assert File.exists? File.join(tmp_location, 'nobody@loudthinking.com')
+ assert File.exists? File.join(tmp_location, 'root@loudthinking.com')
+ end
+
def test_recursive_multipart_processing
fixture = File.read(File.dirname(__FILE__) + "/fixtures/raw_email7")
mail = TMail::Mail.parse(fixture)
diff --git a/actionpack/examples/very_simple.rb b/actionpack/examples/very_simple.rb
index 422c4c3298..6714185172 100644
--- a/actionpack/examples/very_simple.rb
+++ b/actionpack/examples/very_simple.rb
@@ -6,7 +6,7 @@ require "action_controller"
class Kaigi < ActionController::Metal
include AbstractController::Callbacks
include ActionController::RackConvenience
- include ActionController::Renderer
+ include ActionController::RenderingController
include ActionController::Layouts
include ActionView::Context
@@ -47,4 +47,4 @@ app = Rack::Builder.new do
map("/kaigi/alt") { run Kaigi.action(:alt) }
end.to_app
-Rack::Handler::Mongrel.run app, :Port => 3000 \ No newline at end of file
+Rack::Handler::Mongrel.run app, :Port => 3000
diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb
index f020abaa45..cdeb55b915 100644
--- a/actionpack/lib/abstract_controller.rb
+++ b/actionpack/lib/abstract_controller.rb
@@ -2,15 +2,15 @@ require "active_support/core_ext/module/attr_internal"
require "active_support/core_ext/module/delegation"
module AbstractController
- autoload :Base, "abstract_controller/base"
- autoload :Benchmarker, "abstract_controller/benchmarker"
- autoload :Callbacks, "abstract_controller/callbacks"
- autoload :Helpers, "abstract_controller/helpers"
- autoload :Layouts, "abstract_controller/layouts"
- autoload :Logger, "abstract_controller/logger"
- autoload :Renderer, "abstract_controller/renderer"
+ autoload :Base, "abstract_controller/base"
+ autoload :Benchmarker, "abstract_controller/benchmarker"
+ autoload :Callbacks, "abstract_controller/callbacks"
+ autoload :Helpers, "abstract_controller/helpers"
+ autoload :Layouts, "abstract_controller/layouts"
+ autoload :Logger, "abstract_controller/logger"
+ autoload :RenderingController, "abstract_controller/rendering_controller"
# === Exceptions
- autoload :ActionNotFound, "abstract_controller/exceptions"
- autoload :DoubleRenderError, "abstract_controller/exceptions"
- autoload :Error, "abstract_controller/exceptions"
+ autoload :ActionNotFound, "abstract_controller/exceptions"
+ autoload :DoubleRenderError, "abstract_controller/exceptions"
+ autoload :Error, "abstract_controller/exceptions"
end
diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb
index 5efa37fde3..04eaa02441 100644
--- a/actionpack/lib/abstract_controller/helpers.rb
+++ b/actionpack/lib/abstract_controller/helpers.rb
@@ -2,7 +2,7 @@ module AbstractController
module Helpers
extend ActiveSupport::Concern
- include Renderer
+ include RenderingController
included do
extlib_inheritable_accessor(:_helpers) { Module.new }
diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb
index 038598a3b3..0063d54149 100644
--- a/actionpack/lib/abstract_controller/layouts.rb
+++ b/actionpack/lib/abstract_controller/layouts.rb
@@ -2,7 +2,7 @@ module AbstractController
module Layouts
extend ActiveSupport::Concern
- include Renderer
+ include RenderingController
included do
extlib_inheritable_accessor(:_layout_conditions) { Hash.new }
@@ -76,7 +76,7 @@ module AbstractController
when nil
self.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1
def _layout(details)
- if view_paths.find_by_parts?("#{_implied_layout_name}", details, "layouts")
+ if view_paths.exists?("#{_implied_layout_name}", details, "layouts")
"#{_implied_layout_name}"
else
super
@@ -89,16 +89,18 @@ module AbstractController
end
def render_to_body(options = {})
+ # In the case of a partial with a layout, handle the layout
+ # here, and make sure the view does not try to handle it
+ layout = options.delete(:layout) if options.key?(:partial)
+
response = super
- if options.key?(:partial)
- # This is a little bit messy. We need to explicitly handle partial
- # layouts here since the core lookup logic is in the view, but
- # we need to determine the layout based on the controller
- if options.key?(:layout)
- layout = _layout_for_option(options[:layout], options[:_template].details)
- response = layout.render(view_context, options[:locals]) { response }
- end
+ # This is a little bit messy. We need to explicitly handle partial
+ # layouts here since the core lookup logic is in the view, but
+ # we need to determine the layout based on the controller
+ if layout
+ layout = _layout_for_option(layout, options[:_template].details)
+ response = layout.render(view_context, options[:locals] || {}) { response }
end
response
@@ -131,7 +133,7 @@ module AbstractController
def _find_layout(name, details)
# TODO: Make prefix actually part of details in ViewPath#find_by_parts
prefix = details.key?(:prefix) ? details.delete(:prefix) : "layouts"
- view_paths.find_by_parts(name, details, prefix)
+ view_paths.find(name, details, prefix)
end
# Returns the default layout for this controller and a given set of details.
diff --git a/actionpack/lib/abstract_controller/renderer.rb b/actionpack/lib/abstract_controller/rendering_controller.rb
index da57d0ff4d..bb7891fbfd 100644
--- a/actionpack/lib/abstract_controller/renderer.rb
+++ b/actionpack/lib/abstract_controller/rendering_controller.rb
@@ -1,7 +1,7 @@
require "abstract_controller/logger"
module AbstractController
- module Renderer
+ module RenderingController
extend ActiveSupport::Concern
include AbstractController::Logger
@@ -67,7 +67,7 @@ module AbstractController
#
# :api: plugin
def render_to_string(options = {})
- AbstractController::Renderer.body_to_s(render_to_body(options))
+ AbstractController::RenderingController.body_to_s(render_to_body(options))
end
# Renders the template from an object.
@@ -111,7 +111,7 @@ module AbstractController
def _determine_template(options)
name = (options[:_template_name] || action_name).to_s
- options[:_template] ||= view_paths.find_by_parts(
+ options[:_template] ||= view_paths.find(
name, { :formats => formats }, options[:_prefix], options[:_partial]
)
end
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb
index 22c2c4f499..37ff618edd 100644
--- a/actionpack/lib/action_controller.rb
+++ b/actionpack/lib/action_controller.rb
@@ -7,10 +7,10 @@ module ActionController
autoload :RackConvenience, "action_controller/metal/rack_convenience"
autoload :Rails2Compatibility, "action_controller/metal/compatibility"
autoload :Redirector, "action_controller/metal/redirector"
- autoload :Renderer, "action_controller/metal/renderer"
+ autoload :RenderingController, "action_controller/metal/rendering_controller"
autoload :RenderOptions, "action_controller/metal/render_options"
- autoload :Renderers, "action_controller/metal/render_options"
autoload :Rescue, "action_controller/metal/rescuable"
+ autoload :Responder, "action_controller/metal/responder"
autoload :Testing, "action_controller/metal/testing"
autoload :UrlFor, "action_controller/metal/url_for"
autoload :Session, "action_controller/metal/session"
@@ -69,4 +69,4 @@ require 'active_support/core_ext/load_error'
require 'active_support/core_ext/module/attr_internal'
require 'active_support/core_ext/module/delegation'
require 'active_support/core_ext/name_error'
-require 'active_support/inflector' \ No newline at end of file
+require 'active_support/inflector'
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 9d9f735e27..61f1c715c8 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -10,8 +10,8 @@ module ActionController
include ActionController::HideActions
include ActionController::UrlFor
include ActionController::Redirector
- include ActionController::Renderer
- include ActionController::Renderers::All
+ include ActionController::RenderingController
+ include ActionController::RenderOptions::All
include ActionController::Layouts
include ActionController::ConditionalGet
include ActionController::RackConvenience
@@ -51,7 +51,7 @@ module ActionController
def method_for_action(action_name)
super || begin
- if view_paths.find_by_parts?(action_name.to_s, {:formats => formats, :locales => [I18n.locale]}, controller_path)
+ if view_paths.exists?(action_name.to_s, {:formats => formats, :locales => [I18n.locale]}, controller_path)
"default_render"
end
end
diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/action_controller/caching/fragments.rb
index 95cba0e411..4ef600bea0 100644
--- a/actionpack/lib/action_controller/caching/fragments.rb
+++ b/actionpack/lib/action_controller/caching/fragments.rb
@@ -36,8 +36,8 @@ module ActionController #:nodoc:
def fragment_for(buffer, name = {}, options = nil, &block) #:nodoc:
if perform_caching
- if cache = read_fragment(name, options)
- buffer.concat(cache)
+ if fragment_exist?(name,options)
+ buffer.concat(read_fragment(name, options))
else
pos = buffer.length
block.call
diff --git a/actionpack/lib/action_controller/legacy/layout.rb b/actionpack/lib/action_controller/legacy/layout.rb
index 3f3d20b95f..43aea0eba2 100644
--- a/actionpack/lib/action_controller/legacy/layout.rb
+++ b/actionpack/lib/action_controller/legacy/layout.rb
@@ -191,7 +191,7 @@ module ActionController #:nodoc:
def memoized_find_layout(layout, formats) #:nodoc:
return layout if layout.nil? || layout.respond_to?(:render)
prefix = layout.to_s =~ /layouts\// ? nil : "layouts"
- view_paths.find_by_parts(layout.to_s, {:formats => formats}, prefix)
+ view_paths.find(layout.to_s, {:formats => formats}, prefix)
end
def find_layout(*args)
diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb
index 6d35137428..8575d30335 100644
--- a/actionpack/lib/action_controller/metal/conditional_get.rb
+++ b/actionpack/lib/action_controller/metal/conditional_get.rb
@@ -55,14 +55,15 @@ module ActionController
elsif args.empty?
raise ArgumentError, "too few arguments to head"
end
- options = args.extract_options!
- status = args.shift || options.delete(:status) || :ok
+ options = args.extract_options!
+ status = args.shift || options.delete(:status) || :ok
+ location = options.delete(:location)
options.each do |key, value|
headers[key.to_s.dasherize.split(/-/).map { |v| v.capitalize }.join("-")] = value.to_s
end
- render :nothing => true, :status => status
+ render :nothing => true, :status => status, :location => location
end
# Sets the etag and/or last_modified on the response and checks it against
diff --git a/actionpack/lib/action_controller/metal/layouts.rb b/actionpack/lib/action_controller/metal/layouts.rb
index 365351b421..cac529b1ae 100644
--- a/actionpack/lib/action_controller/metal/layouts.rb
+++ b/actionpack/lib/action_controller/metal/layouts.rb
@@ -158,7 +158,7 @@ module ActionController
module Layouts
extend ActiveSupport::Concern
- include ActionController::Renderer
+ include ActionController::RenderingController
include AbstractController::Layouts
module ClassMethods
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb
index f4a4007a43..c8d042acb5 100644
--- a/actionpack/lib/action_controller/metal/mime_responds.rb
+++ b/actionpack/lib/action_controller/metal/mime_responds.rb
@@ -177,106 +177,67 @@ module ActionController #:nodoc:
# Be sure to check respond_with and respond_to documentation for more examples.
#
def respond_to(*mimes, &block)
- options = mimes.extract_options!
raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?
- resource = options.delete(:with)
- responder = Responder.new
-
+ collector = Collector.new
mimes = collect_mimes_from_class_level if mimes.empty?
- mimes.each { |mime| responder.send(mime) }
- block.call(responder) if block_given?
+ mimes.each { |mime| collector.send(mime) }
+ block.call(collector) if block_given?
+
+ if format = request.negotiate_mime(collector.order)
+ self.formats = [format.to_sym]
- if format = request.negotiate_mime(responder.order)
- respond_to_block_or_template_or_resource(format, resource,
- options, &responder.response_for(format))
+ if response = collector.response_for(format)
+ response.call
+ else
+ default_render
+ end
else
head :not_acceptable
end
end
- # respond_with allows you to respond an action with a given resource. It
- # requires that you set your class with a :respond_to method with the
- # formats allowed:
+ # respond_with wraps a resource around a responder for default representation.
+ # First it invokes respond_to, if a response cannot be found (ie. no block
+ # for the request was given and template was not available), it instantiates
+ # an ActionController::Responder with the controller and resource.
#
- # class PeopleController < ApplicationController
- # respond_to :html, :xml, :json
+ # ==== Example
#
- # def index
- # @people = Person.find(:all)
- # respond_with(@person)
- # end
+ # def index
+ # @users = User.all
+ # respond_with(@users)
# end
#
- # When a request comes with format :xml, the respond_with will first search
- # for a template as person/index.xml, if the template is not available, it
- # will see if the given resource responds to :to_xml.
- #
- # If neither are available, it will raise an error.
+ # It also accepts a block to be given. It's used to overwrite a default
+ # response:
#
- # Extra parameters given to respond_with are used when :to_format is invoked.
- # This allows you to set status and location for several formats at the same
- # time. Consider this restful controller response on create for both xml
- # and json formats:
+ # def destroy
+ # @user = User.find(params[:id])
+ # flash[:notice] = "User was successfully created." if @user.save
#
- # class PeopleController < ApplicationController
- # respond_to :xml, :json
- #
- # def create
- # @person = Person.new(params[:person])
- #
- # if @person.save
- # respond_with(@person, :status => :ok, :location => person_url(@person))
- # else
- # respond_with(@person.errors, :status => :unprocessable_entity)
- # end
+ # respond_with(@user) do |format|
+ # format.html { render }
# end
# end
#
- # Finally, respond_with also accepts blocks, as in respond_to. Let's take
- # the same controller and create action above and add common html behavior:
- #
- # class PeopleController < ApplicationController
- # respond_to :html, :xml, :json
- #
- # def create
- # @person = Person.new(params[:person])
- #
- # if @person.save
- # options = { :status => :ok, :location => person_url(@person) }
- #
- # respond_with(@person, options) do |format|
- # format.html { redirect_to options[:location] }
- # end
- # else
- # respond_with(@person.errors, :status => :unprocessable_entity) do
- # format.html { render :action => :new }
- # end
- # end
- # end
- # end
+ # All options given to respond_with are sent to the underlying responder,
+ # except for the option :responder itself. Since the responder interface
+ # is quite simple (it just needs to respond to call), you can even give
+ # a proc to it.
#
def respond_with(resource, options={}, &block)
- respond_to(options.merge!(:with => resource), &block)
+ respond_to(&block)
+ rescue ActionView::MissingTemplate
+ (options.delete(:responder) || responder).call(self, resource, options)
end
- protected
-
- def respond_to_block_or_template_or_resource(format, resource, options)
- self.formats = [format.to_sym]
- return yield if block_given?
-
- begin
- default_render
- rescue ActionView::MissingTemplate => e
- if resource && resource.respond_to?(:"to_#{format.to_sym}")
- render options.merge(format.to_sym => resource)
- else
- raise e
- end
- end
+ def responder
+ ActionController::Responder
end
+ protected
+
# Collect mimes declared in the class method respond_to valid for the
# current action.
#
@@ -296,7 +257,7 @@ module ActionController #:nodoc:
end
end
- class Responder #:nodoc:
+ class Collector #:nodoc:
attr_accessor :order
def initialize
diff --git a/actionpack/lib/action_controller/metal/render_options.rb b/actionpack/lib/action_controller/metal/render_options.rb
index c6a965472f..0d69ca10df 100644
--- a/actionpack/lib/action_controller/metal/render_options.rb
+++ b/actionpack/lib/action_controller/metal/render_options.rb
@@ -47,7 +47,7 @@ module ActionController
end
end
- module Renderers
+ module RenderOptions
module Json
extend RenderOption
register_renderer :json
@@ -94,10 +94,10 @@ module ActionController
module All
extend ActiveSupport::Concern
- include ActionController::Renderers::Json
- include ActionController::Renderers::Js
- include ActionController::Renderers::Xml
- include ActionController::Renderers::RJS
+ include ActionController::RenderOptions::Json
+ include ActionController::RenderOptions::Js
+ include ActionController::RenderOptions::Xml
+ include ActionController::RenderOptions::RJS
end
end
end
diff --git a/actionpack/lib/action_controller/metal/renderer.rb b/actionpack/lib/action_controller/metal/rendering_controller.rb
index 31ba7e582a..5b1be763ad 100644
--- a/actionpack/lib/action_controller/metal/renderer.rb
+++ b/actionpack/lib/action_controller/metal/rendering_controller.rb
@@ -1,8 +1,8 @@
module ActionController
- module Renderer
+ module RenderingController
extend ActiveSupport::Concern
- include AbstractController::Renderer
+ include AbstractController::RenderingController
def process_action(*)
self.formats = request.formats.map {|x| x.to_sym}
@@ -53,9 +53,6 @@ module ActionController
super
end
- def _render_partial(partial, options)
- end
-
def _process_options(options)
status, content_type, location = options.values_at(:status, :content_type, :location)
self.status = status if status
diff --git a/actionpack/lib/action_controller/metal/responder.rb b/actionpack/lib/action_controller/metal/responder.rb
new file mode 100644
index 0000000000..9ed99ca623
--- /dev/null
+++ b/actionpack/lib/action_controller/metal/responder.rb
@@ -0,0 +1,181 @@
+module ActionController #:nodoc:
+ # Responder is responsible to expose a resource for different mime requests,
+ # usually depending on the HTTP verb. The responder is triggered when
+ # respond_with is called. The simplest case to study is a GET request:
+ #
+ # class PeopleController < ApplicationController
+ # respond_to :html, :xml, :json
+ #
+ # def index
+ # @people = Person.find(:all)
+ # respond_with(@people)
+ # end
+ # end
+ #
+ # When a request comes, for example with format :xml, three steps happen:
+ #
+ # 1) respond_with searches for a template at people/index.xml;
+ #
+ # 2) if the template is not available, it will create a responder, passing
+ # the controller and the resource and invoke :to_xml on it;
+ #
+ # 3) if the responder does not respond_to :to_xml, call to_format on it.
+ #
+ # === Builtin HTTP verb semantics
+ #
+ # Rails default responder holds semantics for each HTTP verb. Depending on the
+ # content type, verb and the resource status, it will behave differently.
+ #
+ # Using Rails default responder, a POST request for creating an object could
+ # be written as:
+ #
+ # def create
+ # @user = User.new(params[:user])
+ # flash[:notice] = 'User was successfully created.' if @user.save
+ # respond_with(@user)
+ # end
+ #
+ # Which is exactly the same as:
+ #
+ # def create
+ # @user = User.new(params[:user])
+ #
+ # respond_to do |format|
+ # if @user.save
+ # flash[:notice] = 'User was successfully created.'
+ # format.html { redirect_to(@user) }
+ # format.xml { render :xml => @user, :status => :created, :location => @user }
+ # else
+ # format.html { render :action => "new" }
+ # format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
+ # end
+ # end
+ # end
+ #
+ # The same happens for PUT and DELETE requests.
+ #
+ # === Nested resources
+ #
+ # You can given nested resource as you do in form_for and polymorphic_url.
+ # Consider the project has many tasks example. The create action for
+ # TasksController would be like:
+ #
+ # def create
+ # @project = Project.find(params[:project_id])
+ # @task = @project.comments.build(params[:task])
+ # flash[:notice] = 'Task was successfully created.' if @task.save
+ # respond_with([@project, @task])
+ # end
+ #
+ # Giving an array of resources, you ensure that the responder will redirect to
+ # project_task_url instead of task_url.
+ #
+ # Namespaced and singleton resources requires a symbol to be given, as in
+ # polymorphic urls. If a project has one manager which has many tasks, it
+ # should be invoked as:
+ #
+ # respond_with([@project, :manager, @task])
+ #
+ # Check polymorphic_url documentation for more examples.
+ #
+ class Responder
+ attr_reader :controller, :request, :format, :resource, :resource_location, :options
+
+ def initialize(controller, resource, options={})
+ @controller = controller
+ @request = controller.request
+ @format = controller.formats.first
+ @resource = resource.is_a?(Array) ? resource.last : resource
+ @resource_location = options[:location] || resource
+ @options = options
+ end
+
+ delegate :head, :render, :redirect_to, :to => :controller
+ delegate :get?, :post?, :put?, :delete?, :to => :request
+
+ # Undefine :to_json since it's defined on Object
+ undef_method :to_json
+
+ # Initializes a new responder an invoke the proper format. If the format is
+ # not defined, call to_format.
+ #
+ def self.call(*args)
+ responder = new(*args)
+ method = :"to_#{responder.format}"
+ responder.respond_to?(method) ? responder.send(method) : responder.to_format
+ end
+
+ # HTML format does not render the resource, it always attempt to render a
+ # template.
+ #
+ def to_html
+ if get?
+ render
+ elsif has_errors?
+ render :action => default_action
+ else
+ redirect_to resource_location
+ end
+ end
+
+ # All others formats try to render the resource given instead. For this
+ # purpose a helper called display as a shortcut to render a resource with
+ # the current format.
+ #
+ def to_format
+ return render unless resourceful?
+
+ if get?
+ display resource
+ elsif has_errors?
+ display resource.errors, :status => :unprocessable_entity
+ elsif post?
+ display resource, :status => :created, :location => resource_location
+ else
+ head :ok
+ end
+ end
+
+ protected
+
+ # Checks whether the resource responds to the current format or not.
+ #
+ def resourceful?
+ resource.respond_to?(:"to_#{format}")
+ end
+
+ # display is just a shortcut to render a resource with the current format.
+ #
+ # display @user, :status => :ok
+ #
+ # For xml request is equivalent to:
+ #
+ # render :xml => @user, :status => :ok
+ #
+ # Options sent by the user are also used:
+ #
+ # respond_with(@user, :status => :created)
+ # display(@user, :status => :ok)
+ #
+ # Results in:
+ #
+ # render :xml => @user, :status => :created
+ #
+ def display(resource, given_options={})
+ render given_options.merge!(options).merge!(format => resource)
+ end
+
+ # Check if the resource has errors or not.
+ #
+ def has_errors?
+ resource.respond_to?(:errors) && !resource.errors.empty?
+ end
+
+ # By default, render the :edit action for html requests with failure, unless
+ # the verb is post.
+ #
+ def default_action
+ request.post? ? :new : :edit
+ end
+ end
+end
diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb
index f0317c6e99..57318e8747 100644
--- a/actionpack/lib/action_controller/metal/streaming.rb
+++ b/actionpack/lib/action_controller/metal/streaming.rb
@@ -6,7 +6,7 @@ module ActionController #:nodoc:
module Streaming
extend ActiveSupport::Concern
- include ActionController::Renderer
+ include ActionController::RenderingController
DEFAULT_SEND_FILE_OPTIONS = {
:type => 'application/octet-stream'.freeze,
diff --git a/actionpack/lib/action_controller/metal/verification.rb b/actionpack/lib/action_controller/metal/verification.rb
index 951ae1bee1..d3d78e3749 100644
--- a/actionpack/lib/action_controller/metal/verification.rb
+++ b/actionpack/lib/action_controller/metal/verification.rb
@@ -2,7 +2,7 @@ module ActionController #:nodoc:
module Verification #:nodoc:
extend ActiveSupport::Concern
- include AbstractController::Callbacks, Session, Flash, Renderer
+ include AbstractController::Callbacks, Session, Flash, RenderingController
# This module provides a class-level method for specifying that certain
# actions are guarded against being called without certain prerequisites
@@ -127,4 +127,4 @@ module ActionController #:nodoc:
end
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_controller/routing/generation/polymorphic_routes.rb b/actionpack/lib/action_controller/routing/generation/polymorphic_routes.rb
index 159d869a54..2adf3575a7 100644
--- a/actionpack/lib/action_controller/routing/generation/polymorphic_routes.rb
+++ b/actionpack/lib/action_controller/routing/generation/polymorphic_routes.rb
@@ -50,6 +50,7 @@ module ActionController
# 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"
+ # polymorphic_url(Comment) # => "http://example.com/comments"
#
# ==== Options
#
@@ -70,6 +71,9 @@ module ActionController
# record = Comment.new
# polymorphic_url(record) # same as comments_url()
#
+ # # the class of a record will also map to the collection
+ # polymorphic_url(Comment) # same as comments_url()
+ #
def polymorphic_url(record_or_hash_or_array, options = {})
if record_or_hash_or_array.kind_of?(Array)
record_or_hash_or_array = record_or_hash_or_array.compact
@@ -86,17 +90,19 @@ module ActionController
else [ record_or_hash_or_array ]
end
- inflection =
- case
- when options[:action].to_s == "new"
- args.pop
- :singular
- when record.respond_to?(:new_record?) && record.new_record?
- args.pop
- :plural
- else
- :singular
- end
+ inflection = if options[:action].to_s == "new"
+ args.pop
+ :singular
+ elsif (record.respond_to?(:new_record?) && record.new_record?) ||
+ (record.respond_to?(:destroyed?) && record.destroyed?)
+ args.pop
+ :plural
+ elsif record.is_a?(Class)
+ args.pop
+ :plural
+ else
+ :singular
+ end
args.delete_if {|arg| arg.is_a?(Symbol) || arg.is_a?(String)}
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index 9e696af83b..7932f01ebb 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -202,7 +202,7 @@ module ActionView #:nodoc:
delegate :logger, :to => :controller, :allow_nil => true
- delegate :find_by_parts, :to => :view_paths
+ delegate :find, :to => :view_paths
include Context
diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionpack/lib/action_view/helpers/active_model_helper.rb
index 4fd7f7d83c..3e6e62237d 100644
--- a/actionpack/lib/action_view/helpers/active_model_helper.rb
+++ b/actionpack/lib/action_view/helpers/active_model_helper.rb
@@ -278,9 +278,7 @@ module ActionView
end
%w(tag content_tag to_date_select_tag to_datetime_select_tag to_time_select_tag).each do |meth|
- define_method meth do |*|
- error_wrapping(super)
- end
+ module_eval "def #{meth}(*) error_wrapping(super) end"
end
def error_wrapping(html_tag)
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index e126b35e90..1abe7775e0 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -263,7 +263,7 @@ module ActionView
escape = options.key?("escape") ? options.delete("escape") : true
content = html_escape(content) if escape
- content_tag :textarea, content, { "name" => name, "id" => sanitize_to_id(name) }.update(options.stringify_keys)
+ content_tag :textarea, content, { "name" => name, "id" => sanitize_to_id(name) }.update(options)
end
# Creates a check box form input tag.
diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb
index 999d5b34fc..897a7cc348 100644
--- a/actionpack/lib/action_view/helpers/number_helper.rb
+++ b/actionpack/lib/action_view/helpers/number_helper.rb
@@ -215,7 +215,7 @@ module ActionView
delimiter ||= (options[:delimiter] || defaults[:delimiter])
begin
- rounded_number = (Float(number) * (10 ** precision)).round.to_f / 10 ** precision
+ rounded_number = BigDecimal.new((Float(number) * (10 ** precision)).to_s).round.to_f / 10 ** precision
number_with_delimiter("%01.#{precision}f" % rounded_number,
:separator => separator,
:delimiter => delimiter)
diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb
index 074b475819..4001757a9b 100644
--- a/actionpack/lib/action_view/paths.rb
+++ b/actionpack/lib/action_view/paths.rb
@@ -33,12 +33,12 @@ module ActionView #:nodoc:
super(*objs.map { |obj| self.class.type_cast(obj) })
end
- def find_by_parts(path, details = {}, prefix = nil, partial = false)
+ def find(path, details = {}, prefix = nil, partial = false)
# template_path = path.sub(/^\//, '')
template_path = path
each do |load_path|
- if template = load_path.find_by_parts(template_path, details, prefix, partial)
+ if template = load_path.find(template_path, details, prefix, partial)
return template
end
end
@@ -48,11 +48,11 @@ module ActionView #:nodoc:
raise ActionView::MissingTemplate.new(self, "#{prefix}/#{path} - #{details.inspect} - partial: #{!!partial}")
end
- def find_by_parts?(path, extension = nil, prefix = nil, partial = false)
+ def exists?(path, extension = nil, prefix = nil, partial = false)
template_path = path.sub(/^\//, '')
each do |load_path|
- return true if template = load_path.find_by_parts(template_path, extension, prefix, partial)
+ return true if template = load_path.find(template_path, extension, prefix, partial)
end
false
end
@@ -62,7 +62,7 @@ module ActionView #:nodoc:
template_path = original_template_path.sub(/^\//, '')
each do |load_path|
- if template = load_path.find_by_parts(template_path, format)
+ if template = load_path.find(template_path, format)
return template
# Try to find html version if the format is javascript
elsif format == :js && html_fallback && template = load_path["#{template_path}.#{I18n.locale}.html"]
diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb
index 48cba9c02b..986d3af454 100644
--- a/actionpack/lib/action_view/render/partials.rb
+++ b/actionpack/lib/action_view/render/partials.rb
@@ -170,95 +170,117 @@ module ActionView
# <%- end -%>
# <% end %>
module Partials
- extend ActiveSupport::Memoizable
extend ActiveSupport::Concern
- included do
- attr_accessor :_partial
- end
-
- module ClassMethods
- def _partial_names
- @_partial_names ||= ActiveSupport::ConcurrentHash.new
+ class PartialRenderer
+ def self.partial_names
+ @partial_names ||= Hash.new {|h,k| h[k] = ActiveSupport::ConcurrentHash.new }
end
- end
- def render_partial(options)
- @assigns_added = false
- # TODO: Handle other details here.
- self.formats = options[:_details][:formats]
- _render_partial(options)
- end
+ def initialize(view_context, options, formats)
+ object = options[:partial]
- def _render_partial(options, &block) #:nodoc:
- options[:locals] ||= {}
+ @view, @formats = view_context, formats
+ @options = options || {}
- path = partial = options[:partial]
+ if object.is_a?(String)
+ @path = object
+ elsif
+ @object = object
+ @path = partial_path unless collection
+ end
- if partial.respond_to?(:to_ary)
- return _render_partial_collection(partial, options, &block)
- elsif !partial.is_a?(String)
- options[:object] = object = partial
- path = _partial_path(object)
+ @locals = options[:locals] || {}
+ @object ||= @options[:object] || @locals[:object]
+ @layout = options[:layout]
end
- _render_partial_object(_pick_partial_template(path), options, &block)
- end
+ def render(&block)
+ template = find if @path
- private
- def _partial_path(object)
- self.class._partial_names[[controller.class, object.class]] ||= begin
- name = object.class.model_name
- if controller_path && controller_path.include?("/")
- File.join(File.dirname(controller_path), name.partial_path)
- else
- name.partial_path
- end
+ if collection
+ render_collection(template, &block)
+ else
+ render_object(template, &block)
end
end
- def _render_partial_template(template, locals, object, options = {}, &block)
- options[:_template] = template
- locals[:object] = locals[template.variable_name] = object
- locals[options[:as]] = object if options[:as]
+ def render_template(template, &block)
+ @options[:_template] = template
+ @locals[:object] = @locals[template.variable_name] = @object
+ @locals[@options[:as]] = @object if @options[:as]
- _render_single_template(template, locals, &block)
+ content = @view._render_single_template(template, @locals, &block)
+ return content if block_given? || !@layout
+ find(@layout).render(@view, @locals) { content }
end
- def _render_partial_object(template, options, &block)
- if options.key?(:collection)
- _render_partial_collection(options.delete(:collection), options, template, &block)
- else
- locals = (options[:locals] ||= {})
- object = options[:object] || locals[:object] || locals[template.variable_name]
-
- _render_partial_template(template, locals, object, options, &block)
- end
+ def render_object(template, &block)
+ @object ||= @locals[template.variable_name]
+ render_template(template, &block)
end
- def _render_partial_collection(collection, options = {}, template = nil, &block) #:nodoc:
- options[:_template] ||= template
+ def render_collection(passed_template = nil, &block)
+ @options[:_template] = passed_template
return nil if collection.blank?
- if options.key?(:spacer_template)
- spacer = _render_partial(:partial => options[:spacer_template])
+ if @options.key?(:spacer_template)
+ spacer = @view.render_partial(
+ :partial => @options[:spacer_template], :_details => @options[:_details])
end
- locals, index = options[:locals] || {}, 0
+ index = 0
- collection.map do |object|
- tmp = template || _pick_partial_template(_partial_path(object))
- locals[tmp.counter_name] = index
+ collection.map do |@object|
+ @path = partial_path
+ template = passed_template || find
+ @locals[template.counter_name] = index
index += 1
- _render_partial_template(tmp, locals, object, options, &block)
+ render_template(template, &block)
end.join(spacer)
end
- def _pick_partial_template(partial_path) #:nodoc:
- prefix = controller_path unless partial_path.include?(?/)
- find_by_parts(partial_path, {:formats => formats}, prefix, true)
+ private
+ def collection
+ @collection ||= if @object.respond_to?(:to_ary)
+ @object
+ elsif @options.key?(:collection)
+ @options[:collection] || []
+ end
end
+
+ def find(path = @path)
+ prefix = @view.controller.controller_path unless path.include?(?/)
+ @view.find(path, {:formats => @view.formats}, prefix, true)
+ end
+
+ def partial_path(object = @object)
+ self.class.partial_names[@view.controller.class][object.class] ||= begin
+ return nil unless object.class.respond_to?(:model_name)
+
+ name = object.class.model_name
+ path = @view.controller_path
+ if path && path.include?(?/)
+ File.join(File.dirname(path), name.partial_path)
+ else
+ name.partial_path
+ end
+ end
+ end
+ end
+
+ def render_partial(options)
+ @assigns_added = false
+ # TODO: Handle other details here.
+ self.formats = options[:_details][:formats] if options[:_details]
+ _render_partial(options)
+ end
+
+ def _render_partial(options, &block) #:nodoc:
+ PartialRenderer.new(self, options, formats).render(&block)
+ end
+
end
end
diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb
index 9c25fab6bb..c7afc56e3b 100644
--- a/actionpack/lib/action_view/render/rendering.rb
+++ b/actionpack/lib/action_view/render/rendering.rb
@@ -20,14 +20,13 @@ module ActionView
if block_given?
return concat(_render_partial(options.merge(:partial => layout), &block))
elsif options.key?(:partial)
- layout = _pick_partial_template(layout) if layout
- return _render_content(_render_partial(options), layout, options[:locals])
+ return _render_partial(options)
end
- layout = find_by_parts(layout, {:formats => formats}) if layout
+ layout = find(layout, {:formats => formats}) if layout
if file = options[:file]
- template = find_by_parts(file, {:formats => formats})
+ template = find(file, {:formats => formats})
_render_template(template, layout, :locals => options[:locals] || {})
elsif inline = options[:inline]
_render_inline(inline, layout, options)
diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb
index d15f53a11b..ebfc6cc8ce 100644
--- a/actionpack/lib/action_view/template/resolver.rb
+++ b/actionpack/lib/action_view/template/resolver.rb
@@ -10,7 +10,7 @@ module ActionView
end
# Normalizes the arguments and passes it on to find_template
- def find_by_parts(*args)
+ def find(*args)
find_all_by_parts(*args).first
end
diff --git a/actionpack/test/abstract_controller/abstract_controller_test.rb b/actionpack/test/abstract_controller/abstract_controller_test.rb
index 56ec6a6a31..9438a4dfc9 100644
--- a/actionpack/test/abstract_controller/abstract_controller_test.rb
+++ b/actionpack/test/abstract_controller/abstract_controller_test.rb
@@ -27,7 +27,7 @@ module AbstractController
# Test Render mixin
# ====
class RenderingController < AbstractController::Base
- include Renderer
+ include ::AbstractController::RenderingController
def _prefix() end
@@ -65,8 +65,8 @@ module AbstractController
self.response_body = render_to_string :_template_name => "naked_render.erb"
end
end
-
- class TestRenderer < ActiveSupport::TestCase
+
+ class TestRenderingController < ActiveSupport::TestCase
test "rendering templates works" do
result = Me2.new.process(:index)
assert_equal "Hello from index.erb", result.response_body
@@ -139,10 +139,10 @@ module AbstractController
private
def self.layout(formats)
begin
- view_paths.find_by_parts(name.underscore, {:formats => formats}, "layouts")
+ view_paths.find(name.underscore, {:formats => formats}, "layouts")
rescue ActionView::MissingTemplate
begin
- view_paths.find_by_parts("application", {:formats => formats}, "layouts")
+ view_paths.find("application", {:formats => formats}, "layouts")
rescue ActionView::MissingTemplate
end
end
diff --git a/actionpack/test/abstract_controller/helper_test.rb b/actionpack/test/abstract_controller/helper_test.rb
index 0a2535f834..e9a60c0307 100644
--- a/actionpack/test/abstract_controller/helper_test.rb
+++ b/actionpack/test/abstract_controller/helper_test.rb
@@ -4,7 +4,7 @@ module AbstractController
module Testing
class ControllerWithHelpers < AbstractController::Base
- include Renderer
+ include AbstractController::RenderingController
include Helpers
def render(string)
@@ -40,4 +40,4 @@ module AbstractController
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/test/abstract_controller/layouts_test.rb b/actionpack/test/abstract_controller/layouts_test.rb
index b28df7743f..42f73faa61 100644
--- a/actionpack/test/abstract_controller/layouts_test.rb
+++ b/actionpack/test/abstract_controller/layouts_test.rb
@@ -6,7 +6,7 @@ module AbstractControllerTests
# Base controller for these tests
class Base < AbstractController::Base
- include AbstractController::Renderer
+ include AbstractController::RenderingController
include AbstractController::Layouts
self.view_paths = [ActionView::FixtureResolver.new(
diff --git a/actionpack/test/activerecord/polymorphic_routes_test.rb b/actionpack/test/activerecord/polymorphic_routes_test.rb
index 2036d1eeb5..37f1f6dff8 100644
--- a/actionpack/test/activerecord/polymorphic_routes_test.rb
+++ b/actionpack/test/activerecord/polymorphic_routes_test.rb
@@ -45,6 +45,12 @@ class PolymorphicRoutesTest < ActionController::TestCase
assert_equal "http://example.com/projects/#{@project.id}", polymorphic_url(@project)
end
end
+
+ def test_with_class
+ with_test_routes do
+ assert_equal "http://example.com/projects", polymorphic_url(@project.class)
+ end
+ end
def test_with_new_record
with_test_routes do
@@ -52,6 +58,13 @@ class PolymorphicRoutesTest < ActionController::TestCase
end
end
+ def test_with_destroyed_record
+ with_test_routes do
+ @project.destroy
+ assert_equal "http://example.com/projects", polymorphic_url(@project)
+ end
+ end
+
def test_with_record_and_action
with_test_routes do
assert_equal "http://example.com/projects/new", polymorphic_url(@project, :action => 'new')
@@ -129,6 +142,27 @@ class PolymorphicRoutesTest < ActionController::TestCase
end
end
+ def test_with_nested_destroyed
+ with_test_routes do
+ @project.save
+ @task.destroy
+ assert_equal "http://example.com/projects/#{@project.id}/tasks", polymorphic_url([@project, @task])
+ end
+ end
+
+ def test_with_nested_class
+ with_test_routes do
+ @project.save
+ assert_equal "http://example.com/projects/#{@project.id}/tasks", polymorphic_url([@project, @task.class])
+ end
+ end
+
+ def test_class_with_array_and_namespace
+ with_admin_test_routes do
+ assert_equal "http://example.com/admin/projects", polymorphic_url([:admin, @project.class])
+ end
+ end
+
def test_new_with_array_and_namespace
with_admin_test_routes do
assert_equal "http://example.com/admin/projects/new", polymorphic_url([:admin, @project], :action => 'new')
@@ -252,11 +286,24 @@ class PolymorphicRoutesTest < ActionController::TestCase
end
end
+ def test_with_irregular_plural_class
+ with_test_routes do
+ assert_equal "http://example.com/taxes", polymorphic_url(@tax.class)
+ end
+ end
+
def test_with_irregular_plural_new_record
with_test_routes do
assert_equal "http://example.com/taxes", polymorphic_url(@tax)
end
end
+
+ def test_with_irregular_plural_destroyed_record
+ with_test_routes do
+ @tax.destroy
+ assert_equal "http://example.com/taxes", polymorphic_url(@tax)
+ end
+ end
def test_with_irregular_plural_record_and_action
with_test_routes do
@@ -298,6 +345,12 @@ class PolymorphicRoutesTest < ActionController::TestCase
end
end
+ def test_class_with_irregular_plural_array_and_namespace
+ with_admin_test_routes do
+ assert_equal "http://example.com/admin/taxes", polymorphic_url([:admin, @tax.class])
+ end
+ end
+
def test_unsaved_with_irregular_plural_array_and_namespace
with_admin_test_routes do
assert_equal "http://example.com/admin/taxes", polymorphic_url([:admin, @tax])
@@ -395,4 +448,4 @@ class PolymorphicRoutesTest < ActionController::TestCase
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index c286976315..68529cc8f7 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -625,6 +625,21 @@ class FragmentCachingTest < ActionController::TestCase
assert !fragment_computed
assert_equal 'generated till now -> fragment content', buffer
end
+
+ def test_fragment_for_logging
+ fragment_computed = false
+
+ @controller.class.expects(:benchmark).with('Cached fragment exists?: views/expensive')
+ @controller.class.expects(:benchmark).with('Cached fragment miss: views/expensive')
+ @controller.class.expects(:benchmark).with('Cached fragment hit: views/expensive').never
+
+ buffer = 'generated till now -> '
+ @controller.fragment_for(buffer, 'expensive') { fragment_computed = true }
+
+ assert fragment_computed
+ assert_equal 'generated till now -> ', buffer
+ end
+
end
class FunctionalCachingController < ActionController::Base
diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb
index 117f4ea4f0..8319b5c573 100644
--- a/actionpack/test/controller/mime_responds_test.rb
+++ b/actionpack/test/controller/mime_responds_test.rb
@@ -1,4 +1,5 @@
require 'abstract_unit'
+require 'controller/fake_models'
class RespondToController < ActionController::Base
layout :set_layout
@@ -471,22 +472,10 @@ class RespondToControllerTest < ActionController::TestCase
end
end
-class RespondResource
- undef_method :to_json
-
- def to_xml
- "XML"
- end
-
- def to_js
- "JS"
- end
-end
-
class RespondWithController < ActionController::Base
respond_to :html, :json
respond_to :xml, :except => :using_defaults
- respond_to :js, :only => :using_defaults
+ respond_to :js, :only => [ :using_defaults, :using_resource ]
def using_defaults
respond_to do |format|
@@ -498,20 +487,27 @@ class RespondWithController < ActionController::Base
respond_to(:js, :xml)
end
+ def default_overwritten
+ respond_to do |format|
+ format.html { render :text => "HTML" }
+ end
+ end
+
def using_resource
- respond_with(RespondResource.new)
+ respond_with(Customer.new("david", 13))
end
- def using_resource_with_options
- respond_with(RespondResource.new, :status => :unprocessable_entity) do |format|
- format.js
- end
+ def using_resource_with_parent
+ respond_with([Quiz::Store.new("developer?", 11), Customer.new("david", 13)])
end
- def default_overwritten
- respond_to do |format|
- format.html { render :text => "HTML" }
- end
+ def using_resource_with_status_and_location
+ respond_with(Customer.new("david", 13), :location => "http://test.host/", :status => :created)
+ end
+
+ def using_resource_with_responder
+ responder = proc { |c, r, o| c.render :text => "Resource name is #{r.name}" }
+ respond_with(Customer.new("david", 13), :responder => responder)
end
protected
@@ -527,7 +523,7 @@ class InheritedRespondWithController < RespondWithController
respond_to :xml, :json
def index
- respond_with(RespondResource.new) do |format|
+ respond_with(Customer.new("david", 13)) do |format|
format.json { render :text => "JSON" }
end
end
@@ -540,6 +536,11 @@ class RespondWithControllerTest < ActionController::TestCase
super
ActionController::Base.use_accept_header = true
@request.host = "www.example.com"
+
+ ActionController::Routing::Routes.draw do |map|
+ map.resources :customers
+ map.resources :quiz_stores, :has_many => :customers
+ end
end
def teardown
@@ -576,11 +577,17 @@ class RespondWithControllerTest < ActionController::TestCase
assert_equal "<p>Hello world!</p>\n", @response.body
end
+ def test_default_overwritten
+ get :default_overwritten
+ assert_equal "text/html", @response.content_type
+ assert_equal "HTML", @response.body
+ end
+
def test_using_resource
- @request.accept = "text/html"
+ @request.accept = "text/javascript"
get :using_resource
- assert_equal "text/html", @response.content_type
- assert_equal "Hello world!", @response.body
+ assert_equal "text/javascript", @response.content_type
+ assert_equal '$("body").visualEffect("highlight");', @response.body
@request.accept = "application/xml"
get :using_resource
@@ -593,24 +600,114 @@ class RespondWithControllerTest < ActionController::TestCase
end
end
- def test_using_resource_with_options
+ def test_using_resource_for_post_with_html
+ post :using_resource
+ assert_equal "text/html", @response.content_type
+ assert_equal 302, @response.status
+ assert_equal "http://www.example.com/customers/13", @response.location
+ assert @response.redirect?
+
+ errors = { :name => :invalid }
+ Customer.any_instance.stubs(:errors).returns(errors)
+ post :using_resource
+ assert_equal "text/html", @response.content_type
+ assert_equal 200, @response.status
+ assert_equal "New world!\n", @response.body
+ assert_nil @response.location
+ end
+
+ def test_using_resource_for_post_with_xml
@request.accept = "application/xml"
- get :using_resource_with_options
+
+ post :using_resource
assert_equal "application/xml", @response.content_type
- assert_equal 422, @response.status
+ assert_equal 201, @response.status
assert_equal "XML", @response.body
+ assert_equal "http://www.example.com/customers/13", @response.location
- @request.accept = "text/javascript"
- get :using_resource_with_options
- assert_equal "text/javascript", @response.content_type
+ errors = { :name => :invalid }
+ Customer.any_instance.stubs(:errors).returns(errors)
+ post :using_resource
+ assert_equal "application/xml", @response.content_type
assert_equal 422, @response.status
- assert_equal "JS", @response.body
+ assert_equal errors.to_xml, @response.body
+ assert_nil @response.location
end
- def test_default_overwritten
- get :default_overwritten
+ def test_using_resource_for_put_with_html
+ put :using_resource
assert_equal "text/html", @response.content_type
- assert_equal "HTML", @response.body
+ assert_equal 302, @response.status
+ assert_equal "http://www.example.com/customers/13", @response.location
+ assert @response.redirect?
+
+ errors = { :name => :invalid }
+ Customer.any_instance.stubs(:errors).returns(errors)
+ put :using_resource
+ assert_equal "text/html", @response.content_type
+ assert_equal 200, @response.status
+ assert_equal "Edit world!\n", @response.body
+ assert_nil @response.location
+ end
+
+ def test_using_resource_for_put_with_xml
+ @request.accept = "application/xml"
+
+ put :using_resource
+ assert_equal "application/xml", @response.content_type
+ assert_equal 200, @response.status
+ assert_equal " ", @response.body
+
+ errors = { :name => :invalid }
+ Customer.any_instance.stubs(:errors).returns(errors)
+ put :using_resource
+ assert_equal "application/xml", @response.content_type
+ assert_equal 422, @response.status
+ assert_equal errors.to_xml, @response.body
+ assert_nil @response.location
+ end
+
+ def test_using_resource_for_delete_with_html
+ Customer.any_instance.stubs(:destroyed?).returns(true)
+ delete :using_resource
+ assert_equal "text/html", @response.content_type
+ assert_equal 302, @response.status
+ assert_equal "http://www.example.com/customers", @response.location
+ end
+
+ def test_using_resource_for_delete_with_xml
+ Customer.any_instance.stubs(:destroyed?).returns(true)
+ @request.accept = "application/xml"
+ delete :using_resource
+ assert_equal "application/xml", @response.content_type
+ assert_equal 200, @response.status
+ assert_equal " ", @response.body
+ end
+
+ def test_using_resource_with_parent_for_get
+ @request.accept = "application/xml"
+ get :using_resource_with_parent
+ assert_equal "application/xml", @response.content_type
+ assert_equal 200, @response.status
+ assert_equal "XML", @response.body
+ end
+
+ def test_using_resource_with_parent_for_post
+ @request.accept = "application/xml"
+
+ post :using_resource_with_parent
+ assert_equal "application/xml", @response.content_type
+ assert_equal 201, @response.status
+ assert_equal "XML", @response.body
+ assert_equal "http://www.example.com/quiz_stores/11/customers/13", @response.location
+
+ errors = { :name => :invalid }
+ Customer.any_instance.stubs(:errors).returns(errors)
+ post :using_resource
+ assert_equal "application/xml", @response.content_type
+ assert_equal 422, @response.status
+ assert_equal errors.to_xml, @response.body
+ assert_nil @response.location
end
def test_clear_respond_to
@@ -628,6 +725,29 @@ class RespondWithControllerTest < ActionController::TestCase
assert_equal "XML", @response.body
end
+ def test_no_double_render_is_raised
+ @request.accept = "text/html"
+ assert_raise ActionView::MissingTemplate do
+ get :using_resource
+ end
+ end
+
+ def test_using_resource_with_status_and_location
+ @request.accept = "text/html"
+ post :using_resource_with_status_and_location
+ assert @response.redirect?
+ assert_equal "http://test.host/", @response.location
+
+ @request.accept = "application/xml"
+ get :using_resource_with_status_and_location
+ assert_equal 201, @response.status
+ end
+
+ def test_using_resource_with_responder
+ get :using_resource_with_responder
+ assert_equal "Resource name is david", @response.body
+ end
+
def test_not_acceptable
@request.accept = "application/xml"
get :using_defaults
@@ -642,14 +762,12 @@ class RespondWithControllerTest < ActionController::TestCase
assert_equal 406, @response.status
@request.accept = "text/javascript"
- get :using_resource
+ get :default_overwritten
assert_equal 406, @response.status
end
end
class AbstractPostController < ActionController::Base
- respond_to :html, :iphone
-
self.view_paths = File.dirname(__FILE__) + "/../fixtures/post_test/"
end
@@ -658,7 +776,7 @@ class PostController < AbstractPostController
around_filter :with_iphone
def index
- respond_to # It will use formats declared above
+ respond_to(:html, :iphone)
end
protected
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index 947ffa9ea6..9546fdb50d 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -458,6 +458,10 @@ class TestController < ActionController::Base
head :location => "/foo"
end
+ def head_with_location_object
+ head :location => Customer.new("david", 1)
+ end
+
def head_with_symbolic_status
head :status => params[:status].intern
end
@@ -618,6 +622,7 @@ class TestController < ActionController::Base
end
private
+
def determine_layout
case action_name
when "hello_world", "layout_test", "rendering_without_layout",
@@ -1084,6 +1089,18 @@ class RenderTest < ActionController::TestCase
assert_response :ok
end
+ def test_head_with_location_object
+ ActionController::Routing::Routes.draw do |map|
+ map.resources :customers
+ map.connect ':controller/:action/:id'
+ end
+
+ get :head_with_location_object
+ assert @response.body.blank?
+ assert_equal "http://www.nextangle.com/customers/1", @response.headers["Location"]
+ assert_response :ok
+ end
+
def test_head_with_custom_header
get :head_with_custom_header
assert @response.body.blank?
diff --git a/actionpack/test/controller/render_xml_test.rb b/actionpack/test/controller/render_xml_test.rb
index 052b4f0b52..139f55d8bd 100644
--- a/actionpack/test/controller/render_xml_test.rb
+++ b/actionpack/test/controller/render_xml_test.rb
@@ -11,7 +11,7 @@ class TestController < ActionController::Base
def render_with_object_location
customer = Customer.new("Some guy", 1)
- render :xml => "<customer/>", :location => customer_url(customer), :status => :created
+ render :xml => "<customer/>", :location => customer, :status => :created
end
def render_with_to_xml
@@ -78,4 +78,4 @@ class RenderTest < ActionController::TestCase
get :implicit_content_type, :format => 'atom'
assert_equal Mime::ATOM, @response.content_type
end
-end \ No newline at end of file
+end
diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb
index fb83dba395..5f9ae6292c 100644
--- a/actionpack/test/controller/routing_test.rb
+++ b/actionpack/test/controller/routing_test.rb
@@ -1,3 +1,4 @@
+# encoding: utf-8
require 'abstract_unit'
require 'controller/fake_controllers'
require 'active_support/dependencies'
@@ -1179,7 +1180,6 @@ class LegacyRouteSetTests < Test::Unit::TestCase
assert_equal({:controller => "content", :action => 'show_page', :id => 'foo'}, rs.recognize_path("/page/foo"))
token = "\321\202\320\265\320\272\321\201\321\202" # 'text' in russian
- token.force_encoding("UTF-8") if token.respond_to?(:force_encoding)
escaped_token = CGI::escape(token)
assert_equal '/page/' + escaped_token, rs.generate(:controller => 'content', :action => 'show_page', :id => token)
diff --git a/actionpack/test/fixtures/respond_with/edit.html.erb b/actionpack/test/fixtures/respond_with/edit.html.erb
new file mode 100644
index 0000000000..ae82dfa4fc
--- /dev/null
+++ b/actionpack/test/fixtures/respond_with/edit.html.erb
@@ -0,0 +1 @@
+Edit world!
diff --git a/actionpack/test/fixtures/respond_with/new.html.erb b/actionpack/test/fixtures/respond_with/new.html.erb
new file mode 100644
index 0000000000..96c8f1b88b
--- /dev/null
+++ b/actionpack/test/fixtures/respond_with/new.html.erb
@@ -0,0 +1 @@
+New world!
diff --git a/actionpack/test/fixtures/respond_with/using_resource.html.erb b/actionpack/test/fixtures/respond_with/using_resource.html.erb
deleted file mode 100644
index 6769dd60bd..0000000000
--- a/actionpack/test/fixtures/respond_with/using_resource.html.erb
+++ /dev/null
@@ -1 +0,0 @@
-Hello world! \ No newline at end of file
diff --git a/actionpack/test/fixtures/respond_with/using_resource.js.rjs b/actionpack/test/fixtures/respond_with/using_resource.js.rjs
new file mode 100644
index 0000000000..737c175a4e
--- /dev/null
+++ b/actionpack/test/fixtures/respond_with/using_resource.js.rjs
@@ -0,0 +1 @@
+page[:body].visual_effect :highlight
diff --git a/actionpack/test/lib/controller/fake_models.rb b/actionpack/test/lib/controller/fake_models.rb
index c6726432ec..0faf8f3f9a 100644
--- a/actionpack/test/lib/controller/fake_models.rb
+++ b/actionpack/test/lib/controller/fake_models.rb
@@ -4,9 +4,27 @@ class Customer < Struct.new(:name, :id)
extend ActiveModel::Naming
include ActiveModel::Conversion
+ undef_method :to_json
+
def to_param
id.to_s
end
+
+ def to_xml
+ "XML"
+ end
+
+ def to_js
+ "JS"
+ end
+
+ def errors
+ []
+ end
+
+ def destroyed?
+ false
+ end
end
class BadCustomer < Customer
@@ -24,4 +42,8 @@ module Quiz
id.to_s
end
end
+
+ class Store < Question
+ end
end
+
diff --git a/actionpack/test/template/number_helper_test.rb b/actionpack/test/template/number_helper_test.rb
index 57b740032e..85a97d570c 100644
--- a/actionpack/test/template/number_helper_test.rb
+++ b/actionpack/test/template/number_helper_test.rb
@@ -88,6 +88,7 @@ class NumberHelperTest < ActionView::TestCase
assert_equal("111.00", number_with_precision(111, :precision => 2))
assert_equal("111.235", number_with_precision("111.2346"))
assert_equal("31.83", number_with_precision("31.825", :precision => 2))
+ assert_equal("3268", number_with_precision((32.675 * 100.00), :precision => 0))
assert_equal("112", number_with_precision(111.50, :precision => 0))
assert_equal("1234567892", number_with_precision(1234567891.50, :precision => 0))
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index 0b7d6d9094..3da3d9d8cc 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -12,7 +12,7 @@ module ActiveRecord
self.attribute_types_cached_by_default = ATTRIBUTE_TYPES_CACHED_BY_DEFAULT
# Undefine id so it can be used as an attribute name
- undef_method :id
+ undef_method(:id) if method_defined?(:id)
end
module ClassMethods
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 06bd2dab95..2eb2699949 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -2494,6 +2494,11 @@ module ActiveRecord #:nodoc:
@new_record || false
end
+ # Returns true if this object has been destroyed, otherwise returns false.
+ def destroyed?
+ @destroyed || false
+ end
+
# :call-seq:
# save(perform_validation = true)
#
@@ -2544,6 +2549,7 @@ module ActiveRecord #:nodoc:
# options, use <tt>#destroy</tt>.
def delete
self.class.delete(id) unless new_record?
+ @destroyed = true
freeze
end
@@ -2554,6 +2560,7 @@ module ActiveRecord #:nodoc:
arel_table(true).where(arel_table[self.class.primary_key].eq(id)).delete
end
+ @destroyed = true
freeze
end
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index 7631f3ec35..d5d4808074 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -393,6 +393,16 @@ module ActiveRecord
down(migrations_path, finish ? finish.version : 0)
end
+ def forward(migrations_path, steps=1)
+ migrator = self.new(:up, migrations_path)
+ start_index = migrator.migrations.index(migrator.current_migration)
+
+ return unless start_index
+
+ finish = migrator.migrations[start_index + steps]
+ up(migrations_path, finish ? finish.version : 0)
+ end
+
def up(migrations_path, target_version = nil)
self.new(:up, migrations_path, target_version).migrate
end
diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb
index 12808194f9..8009b1457c 100644
--- a/activerecord/test/cases/adapter_test.rb
+++ b/activerecord/test/cases/adapter_test.rb
@@ -120,7 +120,13 @@ class AdapterTest < ActiveRecord::TestCase
def test_foreign_key_violations_are_translated_to_specific_exception
unless @connection.adapter_name == 'SQLite'
assert_raises(ActiveRecord::InvalidForeignKey) do
- @connection.execute "INSERT INTO fk_test_has_fk (fk_id) VALUES (0)"
+ # Oracle adapter uses prefetched primary key values from sequence and passes them to connection adapter insert method
+ if @connection.prefetch_primary_key?
+ id_value = @connection.next_sequence_value(@connection.default_sequence_name("fk_test_has_fk", "id"))
+ @connection.execute "INSERT INTO fk_test_has_fk (id, fk_id) VALUES (#{id_value},0)"
+ else
+ @connection.execute "INSERT INTO fk_test_has_fk (fk_id) VALUES (0)"
+ end
end
end
end
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index ab6f752243..784c484178 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -293,7 +293,8 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
def test_new_record_with_foreign_key_but_no_object
c = Client.new("firm_id" => 1)
- assert_equal Firm.find(:first), c.firm_with_basic_id
+ # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
+ assert_equal Firm.find(:first, :order => "id"), c.firm_with_basic_id
end
def test_forgetting_the_load_when_foreign_key_enters_late
@@ -301,7 +302,8 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_nil c.firm_with_basic_id
c.firm_id = 1
- assert_equal Firm.find(:first), c.firm_with_basic_id
+ # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
+ assert_equal Firm.find(:first, :order => "id"), c.firm_with_basic_id
end
def test_field_name_same_as_foreign_key
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index 4cf49be668..811ebfbe3f 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -813,7 +813,12 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_include_has_many_using_primary_key
expected = Firm.find(1).clients_using_primary_key.sort_by &:name
- firm = Firm.find 1, :include => :clients_using_primary_key, :order => 'clients_using_primary_keys_companies.name'
+ # Oracle adapter truncates alias to 30 characters
+ if current_adapter?(:OracleAdapter)
+ firm = Firm.find 1, :include => :clients_using_primary_key, :order => 'clients_using_primary_keys_companies'[0,30]+'.name'
+ else
+ firm = Firm.find 1, :include => :clients_using_primary_key, :order => 'clients_using_primary_keys_companies.name'
+ end
assert_no_queries do
assert_equal expected, firm.clients_using_primary_key
end
diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
index 9c915ab010..1bce45865f 100644
--- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
@@ -284,12 +284,14 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
end
def test_creation_respects_hash_condition
- post = categories(:general).post_with_conditions.build(:body => '')
+ # in Oracle '' is saved as null therefore need to save ' ' in not null column
+ post = categories(:general).post_with_conditions.build(:body => ' ')
assert post.save
assert_equal 'Yet Another Testing Title', post.title
- another_post = categories(:general).post_with_conditions.create(:body => '')
+ # in Oracle '' is saved as null therefore need to save ' ' in not null column
+ another_post = categories(:general).post_with_conditions.create(:body => ' ')
assert !another_post.new_record?
assert_equal 'Yet Another Testing Title', another_post.title
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index 15919e2289..a3d92c3bdb 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -24,28 +24,29 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
companies(:first_firm).clients_of_firm.each {|f| }
end
+ # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
def test_counting_with_counter_sql
- assert_equal 2, Firm.find(:first).clients.count
+ assert_equal 2, Firm.find(:first, :order => "id").clients.count
end
def test_counting
- assert_equal 2, Firm.find(:first).plain_clients.count
+ assert_equal 2, Firm.find(:first, :order => "id").plain_clients.count
end
def test_counting_with_empty_hash_conditions
- assert_equal 2, Firm.find(:first).plain_clients.count(:conditions => {})
+ assert_equal 2, Firm.find(:first, :order => "id").plain_clients.count(:conditions => {})
end
def test_counting_with_single_conditions
- assert_equal 1, Firm.find(:first).plain_clients.count(:conditions => ['name=?', "Microsoft"])
+ assert_equal 1, Firm.find(:first, :order => "id").plain_clients.count(:conditions => ['name=?', "Microsoft"])
end
def test_counting_with_single_hash
- assert_equal 1, Firm.find(:first).plain_clients.count(:conditions => {:name => "Microsoft"})
+ assert_equal 1, Firm.find(:first, :order => "id").plain_clients.count(:conditions => {:name => "Microsoft"})
end
def test_counting_with_column_name_and_hash
- assert_equal 2, Firm.find(:first).plain_clients.count(:name)
+ assert_equal 2, Firm.find(:first, :order => "id").plain_clients.count(:name)
end
def test_counting_with_association_limit
@@ -55,12 +56,12 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_finding
- assert_equal 2, Firm.find(:first).clients.length
+ assert_equal 2, Firm.find(:first, :order => "id").clients.length
end
def test_find_with_blank_conditions
[[], {}, nil, ""].each do |blank|
- assert_equal 2, Firm.find(:first).clients.find(:all, :conditions => blank).size
+ assert_equal 2, Firm.find(:first, :order => "id").clients.find(:all, :conditions => blank).size
end
end
@@ -115,52 +116,53 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_triple_equality
- assert !(Array === Firm.find(:first).clients)
- assert Firm.find(:first).clients === Array
+ # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
+ assert !(Array === Firm.find(:first, :order => "id").clients)
+ assert Firm.find(:first, :order => "id").clients === Array
end
def test_finding_default_orders
- assert_equal "Summit", Firm.find(:first).clients.first.name
+ assert_equal "Summit", Firm.find(:first, :order => "id").clients.first.name
end
def test_finding_with_different_class_name_and_order
- assert_equal "Microsoft", Firm.find(:first).clients_sorted_desc.first.name
+ assert_equal "Microsoft", Firm.find(:first, :order => "id").clients_sorted_desc.first.name
end
def test_finding_with_foreign_key
- assert_equal "Microsoft", Firm.find(:first).clients_of_firm.first.name
+ assert_equal "Microsoft", Firm.find(:first, :order => "id").clients_of_firm.first.name
end
def test_finding_with_condition
- assert_equal "Microsoft", Firm.find(:first).clients_like_ms.first.name
+ assert_equal "Microsoft", Firm.find(:first, :order => "id").clients_like_ms.first.name
end
def test_finding_with_condition_hash
- assert_equal "Microsoft", Firm.find(:first).clients_like_ms_with_hash_conditions.first.name
+ assert_equal "Microsoft", Firm.find(:first, :order => "id").clients_like_ms_with_hash_conditions.first.name
end
def test_finding_using_primary_key
- assert_equal "Summit", Firm.find(:first).clients_using_primary_key.first.name
+ assert_equal "Summit", Firm.find(:first, :order => "id").clients_using_primary_key.first.name
end
def test_finding_using_sql
- firm = Firm.find(:first)
+ firm = Firm.find(:first, :order => "id")
first_client = firm.clients_using_sql.first
assert_not_nil first_client
assert_equal "Microsoft", first_client.name
assert_equal 1, firm.clients_using_sql.size
- assert_equal 1, Firm.find(:first).clients_using_sql.size
+ assert_equal 1, Firm.find(:first, :order => "id").clients_using_sql.size
end
def test_counting_using_sql
- assert_equal 1, Firm.find(:first).clients_using_counter_sql.size
- assert Firm.find(:first).clients_using_counter_sql.any?
- assert_equal 0, Firm.find(:first).clients_using_zero_counter_sql.size
- assert !Firm.find(:first).clients_using_zero_counter_sql.any?
+ assert_equal 1, Firm.find(:first, :order => "id").clients_using_counter_sql.size
+ assert Firm.find(:first, :order => "id").clients_using_counter_sql.any?
+ assert_equal 0, Firm.find(:first, :order => "id").clients_using_zero_counter_sql.size
+ assert !Firm.find(:first, :order => "id").clients_using_zero_counter_sql.any?
end
def test_counting_non_existant_items_using_sql
- assert_equal 0, Firm.find(:first).no_clients_using_counter_sql.size
+ assert_equal 0, Firm.find(:first, :order => "id").no_clients_using_counter_sql.size
end
def test_counting_using_finder_sql
@@ -183,7 +185,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_find_ids
- firm = Firm.find(:first)
+ firm = Firm.find(:first, :order => "id")
assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find }
@@ -203,7 +205,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_find_string_ids_when_using_finder_sql
- firm = Firm.find(:first)
+ firm = Firm.find(:first, :order => "id")
client = firm.clients_using_finder_sql.find("2")
assert_kind_of Client, client
@@ -219,7 +221,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_find_all
- firm = Firm.find(:first)
+ firm = Firm.find(:first, :order => "id")
assert_equal 2, firm.clients.find(:all, :conditions => "#{QUOTED_TYPE} = 'Client'").length
assert_equal 1, firm.clients.find(:all, :conditions => "name = 'Summit'").length
end
@@ -264,24 +266,25 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_find_all_sanitized
- firm = Firm.find(:first)
+ # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
+ firm = Firm.find(:first, :order => "id")
summit = firm.clients.find(:all, :conditions => "name = 'Summit'")
assert_equal summit, firm.clients.find(:all, :conditions => ["name = ?", "Summit"])
assert_equal summit, firm.clients.find(:all, :conditions => ["name = :name", { :name => "Summit" }])
end
def test_find_first
- firm = Firm.find(:first)
+ firm = Firm.find(:first, :order => "id")
client2 = Client.find(2)
- assert_equal firm.clients.first, firm.clients.find(:first)
- assert_equal client2, firm.clients.find(:first, :conditions => "#{QUOTED_TYPE} = 'Client'")
+ assert_equal firm.clients.first, firm.clients.find(:first, :order => "id")
+ assert_equal client2, firm.clients.find(:first, :conditions => "#{QUOTED_TYPE} = 'Client'", :order => "id")
end
def test_find_first_sanitized
- firm = Firm.find(:first)
+ firm = Firm.find(:first, :order => "id")
client2 = Client.find(2)
- assert_equal client2, firm.clients.find(:first, :conditions => ["#{QUOTED_TYPE} = ?", 'Client'])
- assert_equal client2, firm.clients.find(:first, :conditions => ["#{QUOTED_TYPE} = :type", { :type => 'Client' }])
+ assert_equal client2, firm.clients.find(:first, :conditions => ["#{QUOTED_TYPE} = ?", 'Client'], :order => "id")
+ assert_equal client2, firm.clients.find(:first, :conditions => ["#{QUOTED_TYPE} = :type", { :type => 'Client' }], :order => "id")
end
def test_find_in_collection
@@ -341,7 +344,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_create_with_bang_on_has_many_raises_when_record_not_saved
assert_raise(ActiveRecord::RecordInvalid) do
- firm = Firm.find(:first)
+ firm = Firm.find(:first, :order => "id")
firm.plain_clients.create!
end
end
@@ -731,7 +734,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_destroy_dependent_when_deleted_from_association
- firm = Firm.find(:first)
+ # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
+ firm = Firm.find(:first, :order => "id")
assert_equal 2, firm.clients.size
client = firm.clients.first
@@ -798,7 +802,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_replace_with_less
- firm = Firm.find(:first)
+ firm = Firm.find(:first, :order => "id")
firm.clients = [companies(:first_client)]
assert firm.save, "Could not save firm"
firm.reload
@@ -812,7 +816,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_replace_with_new
- firm = Firm.find(:first)
+ firm = Firm.find(:first, :order => "id")
firm.clients = [companies(:second_client), Client.new("name" => "New Client")]
firm.save
firm.reload
@@ -1104,7 +1108,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_creating_using_primary_key
- firm = Firm.find(:first)
+ firm = Firm.find(:first, :order => "id")
client = firm.clients_using_primary_key.create!(:name => 'test')
assert_equal firm.name, client.firm_name
end
diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb
index b1060d01af..9da7fc2639 100644
--- a/activerecord/test/cases/associations/join_model_test.rb
+++ b/activerecord/test/cases/associations/join_model_test.rb
@@ -14,7 +14,9 @@ require 'models/citation'
class AssociationsJoinModelTest < ActiveRecord::TestCase
self.use_transactional_fixtures = false
- fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :items, :books
+ fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :items, :books,
+ # Reload edges table from fixtures as otherwise repeated test was failing
+ :edges
def test_has_many
assert authors(:david).categories.include?(categories(:general))
@@ -343,14 +345,16 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
def test_has_many_polymorphic_with_source_type
- assert_equal posts(:welcome, :thinking), tags(:general).tagged_posts
+ # added sort by ID as otherwise Oracle select sometimes returned rows in different order
+ assert_equal posts(:welcome, :thinking).sort_by(&:id), tags(:general).tagged_posts.sort_by(&:id)
end
def test_eager_has_many_polymorphic_with_source_type
tag_with_include = Tag.find(tags(:general).id, :include => :tagged_posts)
desired = posts(:welcome, :thinking)
assert_no_queries do
- assert_equal desired, tag_with_include.tagged_posts
+ # added sort by ID as otherwise test using JRuby was failing as array elements were in different order
+ assert_equal desired.sort_by(&:id), tag_with_include.tagged_posts.sort_by(&:id)
end
assert_equal 5, tag_with_include.taggings.length
end
diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb
index ab8768ea3e..055590da0a 100644
--- a/activerecord/test/cases/attribute_methods_test.rb
+++ b/activerecord/test/cases/attribute_methods_test.rb
@@ -75,13 +75,23 @@ class AttributeMethodsTest < ActiveRecord::TestCase
def test_typecast_attribute_from_select_to_false
topic = Topic.create(:title => 'Budget')
- topic = Topic.find(:first, :select => "topics.*, 1=2 as is_test")
+ # Oracle does not support boolean expressions in SELECT
+ if current_adapter?(:OracleAdapter)
+ topic = Topic.find(:first, :select => "topics.*, 0 as is_test")
+ else
+ topic = Topic.find(:first, :select => "topics.*, 1=2 as is_test")
+ end
assert !topic.is_test?
end
def test_typecast_attribute_from_select_to_true
topic = Topic.create(:title => 'Budget')
- topic = Topic.find(:first, :select => "topics.*, 2=2 as is_test")
+ # Oracle does not support boolean expressions in SELECT
+ if current_adapter?(:OracleAdapter)
+ topic = Topic.find(:first, :select => "topics.*, 1 as is_test")
+ else
+ topic = Topic.find(:first, :select => "topics.*, 2=2 as is_test")
+ end
assert topic.is_test?
end
diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb
index ddca5e962d..271086af8e 100644
--- a/activerecord/test/cases/autosave_association_test.rb
+++ b/activerecord/test/cases/autosave_association_test.rb
@@ -154,7 +154,8 @@ class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::Test
end
def test_save_fails_for_invalid_belongs_to
- assert log = AuditLog.create(:developer_id => 0, :message => "")
+ # Oracle saves empty string as NULL therefore :message changed to one space
+ assert log = AuditLog.create(:developer_id => 0, :message => " ")
log.developer = Developer.new
assert !log.developer.valid?
@@ -164,7 +165,8 @@ class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::Test
end
def test_save_succeeds_for_invalid_belongs_to_with_validate_false
- assert log = AuditLog.create(:developer_id => 0, :message=> "")
+ # Oracle saves empty string as NULL therefore :message changed to one space
+ assert log = AuditLog.create(:developer_id => 0, :message=> " ")
log.unvalidated_developer = Developer.new
assert !log.unvalidated_developer.valid?
@@ -666,7 +668,12 @@ class TestAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase
@pirate.catchphrase = ''
@pirate.ship.name = ''
@pirate.save(false)
- assert_equal ['', ''], [@pirate.reload.catchphrase, @pirate.ship.name]
+ # Oracle saves empty string as NULL
+ if current_adapter?(:OracleAdapter)
+ assert_equal [nil, nil], [@pirate.reload.catchphrase, @pirate.ship.name]
+ else
+ assert_equal ['', ''], [@pirate.reload.catchphrase, @pirate.ship.name]
+ end
end
def test_should_allow_to_bypass_validations_on_associated_models_at_any_depth
@@ -678,7 +685,12 @@ class TestAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase
@pirate.save(false)
values = [@pirate.reload.catchphrase, @pirate.ship.name, *@pirate.ship.parts.map(&:name)]
- assert_equal ['', '', '', ''], values
+ # Oracle saves empty string as NULL
+ if current_adapter?(:OracleAdapter)
+ assert_equal [nil, nil, nil, nil], values
+ else
+ assert_equal ['', '', '', ''], values
+ end
end
def test_should_still_raise_an_ActiveRecordRecord_Invalid_exception_if_we_want_that
@@ -756,7 +768,12 @@ class TestAutosaveAssociationOnABelongsToAssociation < ActiveRecord::TestCase
@ship.pirate.catchphrase = ''
@ship.name = ''
@ship.save(false)
- assert_equal ['', ''], [@ship.reload.name, @ship.pirate.catchphrase]
+ # Oracle saves empty string as NULL
+ if current_adapter?(:OracleAdapter)
+ assert_equal [nil, nil], [@ship.reload.name, @ship.pirate.catchphrase]
+ else
+ assert_equal ['', ''], [@ship.reload.name, @ship.pirate.catchphrase]
+ end
end
def test_should_still_raise_an_ActiveRecordRecord_Invalid_exception_if_we_want_that
@@ -837,11 +854,20 @@ module AutosaveAssociationOnACollectionAssociationTests
@pirate.send(@association_name).each { |child| child.name = '' }
assert @pirate.save(false)
- assert_equal ['', '', ''], [
- @pirate.reload.catchphrase,
- @pirate.send(@association_name).first.name,
- @pirate.send(@association_name).last.name
- ]
+ # Oracle saves empty string as NULL
+ if current_adapter?(:OracleAdapter)
+ assert_equal [nil, nil, nil], [
+ @pirate.reload.catchphrase,
+ @pirate.send(@association_name).first.name,
+ @pirate.send(@association_name).last.name
+ ]
+ else
+ assert_equal ['', '', ''], [
+ @pirate.reload.catchphrase,
+ @pirate.send(@association_name).first.name,
+ @pirate.send(@association_name).last.name
+ ]
+ end
end
def test_should_validation_the_associated_models_on_create
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index d5b0d58b8a..8434b8efe9 100755
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1271,6 +1271,23 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal Topic.find(1).new_record?, false
end
+ def test_destroyed_returns_boolean
+ developer = Developer.new
+ assert_equal developer.destroyed?, false
+ developer.destroy
+ assert_equal developer.destroyed?, true
+
+ developer = Developer.first
+ assert_equal developer.destroyed?, false
+ developer.destroy
+ assert_equal developer.destroyed?, true
+
+ developer = Developer.last
+ assert_equal developer.destroyed?, false
+ developer.delete
+ assert_equal developer.destroyed?, true
+ end
+
def test_clone
topic = Topic.find(1)
cloned_topic = nil
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index 8edbdbd20f..855b4c60ae 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -298,7 +298,12 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_should_sum_expression
- assert_equal '636', Account.sum("2 * credit_limit")
+ # Oracle adapter returns floating point value 636.0 after SUM
+ if current_adapter?(:OracleAdapter)
+ assert_equal 636, Account.sum("2 * credit_limit")
+ else
+ assert_equal '636', Account.sum("2 * credit_limit")
+ end
end
def test_count_with_from_option
diff --git a/activerecord/test/cases/database_statements_test.rb b/activerecord/test/cases/database_statements_test.rb
index 6274d5250f..c689e97d83 100644
--- a/activerecord/test/cases/database_statements_test.rb
+++ b/activerecord/test/cases/database_statements_test.rb
@@ -6,7 +6,14 @@ class DatabaseStatementsTest < ActiveRecord::TestCase
end
def test_insert_should_return_the_inserted_id
- id = @connection.insert("INSERT INTO accounts (firm_id,credit_limit) VALUES (42,5000)")
+ # Oracle adapter uses prefetched primary key values from sequence and passes them to connection adapter insert method
+ if current_adapter?(:OracleAdapter)
+ sequence_name = "accounts_seq"
+ id_value = @connection.next_sequence_value(sequence_name)
+ id = @connection.insert("INSERT INTO accounts (id, firm_id,credit_limit) VALUES (accounts_seq.nextval,42,5000)", nil, :id, id_value, sequence_name)
+ else
+ id = @connection.insert("INSERT INTO accounts (firm_id,credit_limit) VALUES (42,5000)")
+ end
assert_not_nil id
end
end
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 600a9fe451..3de07797d4 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -156,10 +156,8 @@ class FinderTest < ActiveRecord::TestCase
end
def test_find_all_with_limit
- entrants = Entrant.find(:all, :order => "id ASC", :limit => 2)
-
- assert_equal(2, entrants.size)
- assert_equal(entrants(:first).name, entrants.first.name)
+ assert_equal(2, Entrant.find(:all, :limit => 2).size)
+ assert_equal(0, Entrant.find(:all, :limit => 0).size)
end
def test_find_all_with_prepared_limit_and_offset
@@ -168,22 +166,23 @@ class FinderTest < ActiveRecord::TestCase
assert_equal(2, entrants.size)
assert_equal(entrants(:second).name, entrants.first.name)
+ assert_equal 3, Entrant.count
entrants = Entrant.find(:all, :order => "id ASC", :limit => 2, :offset => 2)
assert_equal(1, entrants.size)
assert_equal(entrants(:third).name, entrants.first.name)
end
- def test_find_all_with_limit_and_offset_and_multiple_orderings
- developers = Developer.find(:all, :order => "salary ASC, id DESC", :limit => 3, :offset => 1)
- assert_equal ["David", "fixture_10", "fixture_9"], developers.collect {|d| d.name}
- end
+ def test_find_all_with_limit_and_offset_and_multiple_order_clauses
+ first_three_posts = Post.find :all, :order => 'author_id, id', :limit => 3, :offset => 0
+ second_three_posts = Post.find :all, :order => ' author_id,id ', :limit => 3, :offset => 3
+ last_posts = Post.find :all, :order => ' author_id, id ', :limit => 3, :offset => 6
- def test_find_with_limit_and_condition
- developers = Developer.find(:all, :order => "id DESC", :conditions => "salary = 100000", :limit => 3, :offset =>7)
- assert_equal(1, developers.size)
- assert_equal("fixture_3", developers.first.name)
+ assert_equal [[0,3],[1,1],[1,2]], first_three_posts.map { |p| [p.author_id, p.id] }
+ assert_equal [[1,4],[1,5],[1,6]], second_three_posts.map { |p| [p.author_id, p.id] }
+ assert_equal [[2,7]], last_posts.map { |p| [p.author_id, p.id] }
end
+
def test_find_with_group
developers = Developer.find(:all, :group => "salary", :select => "salary")
assert_equal 4, developers.size
@@ -978,40 +977,6 @@ class FinderTest < ActiveRecord::TestCase
assert_raise(ArgumentError) { Topic.find_by_title 'No Title', :join => "It should be `joins'" }
end
- def test_find_all_with_limit
- first_five_developers = Developer.find :all, :order => 'id ASC', :limit => 5
- assert_equal 5, first_five_developers.length
- assert_equal 'David', first_five_developers.first.name
- assert_equal 'fixture_5', first_five_developers.last.name
-
- no_developers = Developer.find :all, :order => 'id ASC', :limit => 0
- assert_equal 0, no_developers.length
- end
-
- def test_find_all_with_limit_and_offset
- first_three_developers = Developer.find :all, :order => 'id ASC', :limit => 3, :offset => 0
- second_three_developers = Developer.find :all, :order => 'id ASC', :limit => 3, :offset => 3
- last_two_developers = Developer.find :all, :order => 'id ASC', :limit => 2, :offset => 8
-
- assert_equal 3, first_three_developers.length
- assert_equal 3, second_three_developers.length
- assert_equal 2, last_two_developers.length
-
- assert_equal 'David', first_three_developers.first.name
- assert_equal 'fixture_4', second_three_developers.first.name
- assert_equal 'fixture_9', last_two_developers.first.name
- end
-
- def test_find_all_with_limit_and_offset_and_multiple_order_clauses
- first_three_posts = Post.find :all, :order => 'author_id, id', :limit => 3, :offset => 0
- second_three_posts = Post.find :all, :order => ' author_id,id ', :limit => 3, :offset => 3
- last_posts = Post.find :all, :order => ' author_id, id ', :limit => 3, :offset => 6
-
- assert_equal [[0,3],[1,1],[1,2]], first_three_posts.map { |p| [p.author_id, p.id] }
- assert_equal [[1,4],[1,5],[1,6]], second_three_posts.map { |p| [p.author_id, p.id] }
- assert_equal [[2,7]], last_posts.map { |p| [p.author_id, p.id] }
- end
-
def test_find_all_with_join
developers_on_project_one = Developer.find(
:all,
@@ -1027,7 +992,7 @@ class FinderTest < ActiveRecord::TestCase
def test_joins_dont_clobber_id
first = Firm.find(
:first,
- :joins => 'INNER JOIN companies AS clients ON clients.firm_id = companies.id',
+ :joins => 'INNER JOIN companies clients ON clients.firm_id = companies.id',
:conditions => 'companies.id = 1'
)
assert_equal 1, first.id
diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb
index 8580d67e5f..73e51fbd91 100644
--- a/activerecord/test/cases/inheritance_test.rb
+++ b/activerecord/test/cases/inheritance_test.rb
@@ -137,7 +137,8 @@ class InheritanceTest < ActiveRecord::TestCase
def test_update_all_within_inheritance
Client.update_all "name = 'I am a client'"
assert_equal "I am a client", Client.find(:all).first.name
- assert_equal "37signals", Firm.find(:all).first.name
+ # Order by added as otherwise Oracle tests were failing because of different order of results
+ assert_equal "37signals", Firm.find(:all, :order => "id").first.name
end
def test_alt_update_all_within_inheritance
diff --git a/activerecord/test/cases/invalid_date_test.rb b/activerecord/test/cases/invalid_date_test.rb
index e2bb17c37f..99af7d2986 100644
--- a/activerecord/test/cases/invalid_date_test.rb
+++ b/activerecord/test/cases/invalid_date_test.rb
@@ -11,13 +11,23 @@ class InvalidDateTest < Test::Unit::TestCase
valid_dates.each do |date_src|
topic = Topic.new("last_read(1i)" => date_src[0].to_s, "last_read(2i)" => date_src[1].to_s, "last_read(3i)" => date_src[2].to_s)
- assert_equal(topic.last_read, Date.new(*date_src))
+ # Oracle DATE columns are datetime columns and Oracle adapter returns Time value
+ if current_adapter?(:OracleAdapter)
+ assert_equal(topic.last_read.to_date, Date.new(*date_src))
+ else
+ assert_equal(topic.last_read, Date.new(*date_src))
+ end
end
invalid_dates.each do |date_src|
assert_nothing_raised do
topic = Topic.new({"last_read(1i)" => date_src[0].to_s, "last_read(2i)" => date_src[1].to_s, "last_read(3i)" => date_src[2].to_s})
- assert_equal(topic.last_read, Time.local(*date_src).to_date, "The date should be modified according to the behaviour of the Time object")
+ # Oracle DATE columns are datetime columns and Oracle adapter returns Time value
+ if current_adapter?(:OracleAdapter)
+ assert_equal(topic.last_read.to_date, Time.local(*date_src).to_date, "The date should be modified according to the behaviour of the Time object")
+ else
+ assert_equal(topic.last_read, Time.local(*date_src).to_date, "The date should be modified according to the behaviour of the Time object")
+ end
end
end
end
diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb
index d4e63ce2fd..6dec474f7d 100644
--- a/activerecord/test/cases/method_scoping_test.rb
+++ b/activerecord/test/cases/method_scoping_test.rb
@@ -379,6 +379,7 @@ class NestedScopingTest < ActiveRecord::TestCase
poor_jamis = developers(:poor_jamis)
Developer.with_scope(:find => { :conditions => "salary < 100000" }) do
Developer.with_scope(:find => { :offset => 1, :order => 'id asc' }) do
+ # Oracle adapter does not generated space after asc therefore trailing space removed from regex
assert_sql /ORDER BY id asc/ do
assert_equal(poor_jamis, Developer.find(:first, :order => 'id asc'))
end
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index 215b5a427a..f0f21615e0 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -446,18 +446,22 @@ if ActiveRecord::Base.connection.supports_migrations?
assert_equal Date, bob.favorite_day.class
end
- # Test DateTime column and defaults, including timezone.
- # FIXME: moment of truth may be Time on 64-bit platforms.
- if bob.moment_of_truth.is_a?(DateTime)
-
- with_env_tz 'US/Eastern' do
- assert_equal DateTime.local_offset, bob.moment_of_truth.offset
- assert_not_equal 0, bob.moment_of_truth.offset
- assert_not_equal "Z", bob.moment_of_truth.zone
- # US/Eastern is -5 hours from GMT
- assert_equal Rational(-5, 24), bob.moment_of_truth.offset
- assert_match /\A-05:?00\Z/, bob.moment_of_truth.zone #ruby 1.8.6 uses HH:MM, prior versions use HHMM
- assert_equal DateTime::ITALY, bob.moment_of_truth.start
+ # Oracle adapter stores Time or DateTime with timezone value already in _before_type_cast column
+ # therefore no timezone change is done afterwards when default timezone is changed
+ unless current_adapter?(:OracleAdapter)
+ # Test DateTime column and defaults, including timezone.
+ # FIXME: moment of truth may be Time on 64-bit platforms.
+ if bob.moment_of_truth.is_a?(DateTime)
+
+ with_env_tz 'US/Eastern' do
+ assert_equal DateTime.local_offset, bob.moment_of_truth.offset
+ assert_not_equal 0, bob.moment_of_truth.offset
+ assert_not_equal "Z", bob.moment_of_truth.zone
+ # US/Eastern is -5 hours from GMT
+ assert_equal Rational(-5, 24), bob.moment_of_truth.offset
+ assert_match /\A-05:?00\Z/, bob.moment_of_truth.zone #ruby 1.8.6 uses HH:MM, prior versions use HHMM
+ assert_equal DateTime::ITALY, bob.moment_of_truth.start
+ end
end
end
@@ -571,7 +575,7 @@ if ActiveRecord::Base.connection.supports_migrations?
ActiveRecord::Base.connection.create_table(:hats) do |table|
table.column :hat_name, :string, :default => nil
end
- exception = if current_adapter?(:PostgreSQLAdapter)
+ exception = if current_adapter?(:PostgreSQLAdapter, :OracleAdapter)
ActiveRecord::StatementInvalid
else
ActiveRecord::ActiveRecordError
@@ -625,7 +629,13 @@ if ActiveRecord::Base.connection.supports_migrations?
table.column :hat_size, :integer
table.column :hat_style, :string, :limit => 100
end
- ActiveRecord::Base.connection.add_index "hats", ["hat_style", "hat_size"], :unique => true
+ # Oracle index names should be 30 or less characters
+ if current_adapter?(:OracleAdapter)
+ ActiveRecord::Base.connection.add_index "hats", ["hat_style", "hat_size"], :unique => true,
+ :name => 'index_hats_on_hat_style_size'
+ else
+ ActiveRecord::Base.connection.add_index "hats", ["hat_style", "hat_size"], :unique => true
+ end
assert_nothing_raised { Person.connection.remove_column("hats", "hat_size") }
ensure
@@ -727,19 +737,20 @@ if ActiveRecord::Base.connection.supports_migrations?
def test_change_column
Person.connection.add_column 'people', 'age', :integer
- old_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
+ label = "test_change_column Columns"
+ old_columns = Person.connection.columns(Person.table_name, label)
assert old_columns.find { |c| c.name == 'age' and c.type == :integer }
assert_nothing_raised { Person.connection.change_column "people", "age", :string }
- new_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
+ new_columns = Person.connection.columns(Person.table_name, label)
assert_nil new_columns.find { |c| c.name == 'age' and c.type == :integer }
assert new_columns.find { |c| c.name == 'age' and c.type == :string }
- old_columns = Topic.connection.columns(Topic.table_name, "#{name} Columns")
+ old_columns = Topic.connection.columns(Topic.table_name, label)
assert old_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => false }
- new_columns = Topic.connection.columns(Topic.table_name, "#{name} Columns")
+ new_columns = Topic.connection.columns(Topic.table_name, label)
assert_nil new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
assert new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == false }
assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => true }
@@ -783,7 +794,12 @@ if ActiveRecord::Base.connection.supports_migrations?
assert_nothing_raised { Person.connection.change_column :testings, :select, :string, :limit => 10 }
- assert_nothing_raised { Person.connection.execute "insert into testings (#{Person.connection.quote_column_name('select')}) values ('7 chars')" }
+ # Oracle needs primary key value from sequence
+ if current_adapter?(:OracleAdapter)
+ assert_nothing_raised { Person.connection.execute "insert into testings (id, #{Person.connection.quote_column_name('select')}) values (testings_seq.nextval, '7 chars')" }
+ else
+ assert_nothing_raised { Person.connection.execute "insert into testings (#{Person.connection.quote_column_name('select')}) values ('7 chars')" }
+ end
ensure
Person.connection.drop_table :testings rescue nil
end
@@ -799,7 +815,12 @@ if ActiveRecord::Base.connection.supports_migrations?
person_klass.reset_column_information
assert_equal 99, person_klass.columns_hash["wealth"].default
assert_equal false, person_klass.columns_hash["wealth"].null
- assert_nothing_raised {person_klass.connection.execute("insert into testings (title) values ('tester')")}
+ # Oracle needs primary key value from sequence
+ if current_adapter?(:OracleAdapter)
+ assert_nothing_raised {person_klass.connection.execute("insert into testings (id, title) values (testings_seq.nextval, 'tester')")}
+ else
+ assert_nothing_raised {person_klass.connection.execute("insert into testings (title) values ('tester')")}
+ end
# change column default to see that column doesn't lose its not null definition
person_klass.connection.change_column_default "testings", "wealth", 100
@@ -1054,7 +1075,12 @@ if ActiveRecord::Base.connection.supports_migrations?
end
def test_migrator_db_has_no_schema_migrations_table
- ActiveRecord::Base.connection.execute("DROP TABLE schema_migrations;")
+ # Oracle adapter raises error if semicolon is present as last character
+ if current_adapter?(:OracleAdapter)
+ ActiveRecord::Base.connection.execute("DROP TABLE schema_migrations")
+ else
+ ActiveRecord::Base.connection.execute("DROP TABLE schema_migrations;")
+ end
assert_nothing_raised do
ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", 1)
end
@@ -1110,6 +1136,17 @@ if ActiveRecord::Base.connection.supports_migrations?
assert_equal(0, ActiveRecord::Migrator.current_version)
end
+ def test_migrator_forward
+ ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", 1)
+ assert_equal(1, ActiveRecord::Migrator.current_version)
+
+ ActiveRecord::Migrator.forward(MIGRATIONS_ROOT + "/valid", 2)
+ assert_equal(3, ActiveRecord::Migrator.current_version)
+
+ ActiveRecord::Migrator.forward(MIGRATIONS_ROOT + "/valid")
+ assert_equal(3, ActiveRecord::Migrator.current_version)
+ end
+
def test_schema_migrations_table_name
ActiveRecord::Base.table_name_prefix = "prefix_"
ActiveRecord::Base.table_name_suffix = "_suffix"
@@ -1412,6 +1449,8 @@ if ActiveRecord::Base.connection.supports_migrations?
def string_column
if current_adapter?(:PostgreSQLAdapter)
"character varying(255)"
+ elsif current_adapter?(:OracleAdapter)
+ 'VARCHAR2(255)'
else
'varchar(255)'
end
@@ -1420,6 +1459,8 @@ if ActiveRecord::Base.connection.supports_migrations?
def integer_column
if current_adapter?(:MysqlAdapter)
'int(11)'
+ elsif current_adapter?(:OracleAdapter)
+ 'NUMBER(38)'
else
'integer'
end
diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb
index 3cb6b01e80..330ba7189f 100644
--- a/activerecord/test/cases/named_scope_test.rb
+++ b/activerecord/test/cases/named_scope_test.rb
@@ -154,7 +154,8 @@ class NamedScopeTest < ActiveRecord::TestCase
assert !authors(:david).posts.ranked_by_comments.limit(5).empty?
assert_not_equal Post.ranked_by_comments.limit(5), authors(:david).posts.ranked_by_comments.limit(5)
assert_not_equal Post.top(5), authors(:david).posts.top(5)
- assert_equal authors(:david).posts.ranked_by_comments.limit(5), authors(:david).posts.top(5)
+ # Oracle sometimes sorts differently if WHERE condition is changed
+ assert_equal authors(:david).posts.ranked_by_comments.limit(5).sort_by(&:id), authors(:david).posts.top(5).sort_by(&:id)
assert_equal Post.ranked_by_comments.limit(5), Post.top(5)
end
diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb
index f31275163d..d033c1e760 100644
--- a/activerecord/test/cases/nested_attributes_test.rb
+++ b/activerecord/test/cases/nested_attributes_test.rb
@@ -4,6 +4,8 @@ require "models/ship"
require "models/bird"
require "models/parrot"
require "models/treasure"
+require "models/man"
+require "models/interest"
require 'active_support/hash_with_indifferent_access'
module AssertRaiseWithMessage
@@ -470,6 +472,41 @@ module NestedAttributesOnACollectionAssociationTests
assert Pirate.reflect_on_association(@association_name).options[:autosave]
end
+ def test_validate_presence_of_parent__works_with_inverse_of
+ Man.accepts_nested_attributes_for(:interests)
+ assert_equal :man, Man.reflect_on_association(:interests).options[:inverse_of]
+ assert_equal :interests, Interest.reflect_on_association(:man).options[:inverse_of]
+
+ repair_validations(Interest) do
+ Interest.validates_presence_of(:man)
+ assert_difference 'Man.count' do
+ assert_difference 'Interest.count', 2 do
+ man = Man.create!(:name => 'John',
+ :interests_attributes => [{:topic=>'Cars'}, {:topic=>'Sports'}])
+ assert_equal 2, man.interests.count
+ end
+ end
+ end
+ end
+
+ def test_validate_presence_of_parent__fails_without_inverse_of
+ Man.accepts_nested_attributes_for(:interests)
+ Man.reflect_on_association(:interests).options.delete(:inverse_of)
+ Interest.reflect_on_association(:man).options.delete(:inverse_of)
+
+ repair_validations(Interest) do
+ Interest.validates_presence_of(:man)
+ assert_no_difference ['Man.count', 'Interest.count'] do
+ man = Man.create(:name => 'John',
+ :interests_attributes => [{:topic=>'Cars'}, {:topic=>'Sports'}])
+ assert !man.errors[:interests_man].empty?
+ end
+ end
+ # restore :inverse_of
+ Man.reflect_on_association(:interests).options[:inverse_of] = :man
+ Interest.reflect_on_association(:man).options[:inverse_of] = :interests
+ end
+
private
def association_setter
diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb
index f90a66d1dc..2af6a56b6a 100644
--- a/activerecord/test/cases/query_cache_test.rb
+++ b/activerecord/test/cases/query_cache_test.rb
@@ -50,7 +50,12 @@ class QueryCacheTest < ActiveRecord::TestCase
def test_cache_does_not_wrap_string_results_in_arrays
Task.cache do
- assert_instance_of String, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
+ # Oracle adapter returns count() as Fixnum or Float
+ if current_adapter?(:OracleAdapter)
+ assert Task.connection.select_value("SELECT count(*) AS count_all FROM tasks").is_a?(Numeric)
+ else
+ assert_instance_of String, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
+ end
end
end
end
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index 9612b0beb6..4f8e20b3ba 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -114,6 +114,11 @@ class SchemaDumperTest < ActiveRecord::TestCase
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
+ elsif current_adapter?(:OracleAdapter)
+ 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
@@ -193,6 +198,11 @@ class SchemaDumperTest < ActiveRecord::TestCase
def test_schema_dump_keeps_large_precision_integer_columns_as_decimal
output = standard_dump
- assert_match %r{t.decimal\s+"atoms_in_universe",\s+:precision => 55,\s+:scale => 0}, output
+ # Oracle supports precision up to 38 and it identifies decimals with scale 0 as integers
+ if current_adapter?(:OracleAdapter)
+ assert_match %r{t.integer\s+"atoms_in_universe",\s+:precision => 38,\s+:scale => 0}, output
+ else
+ assert_match %r{t.decimal\s+"atoms_in_universe",\s+:precision => 55,\s+:scale => 0}, output
+ end
end
end
diff --git a/activerecord/test/cases/validations/association_validation_test.rb b/activerecord/test/cases/validations/association_validation_test.rb
index b1203c12ed..278a7a6a06 100644
--- a/activerecord/test/cases/validations/association_validation_test.rb
+++ b/activerecord/test/cases/validations/association_validation_test.rb
@@ -3,6 +3,9 @@ require "cases/helper"
require 'models/topic'
require 'models/reply'
require 'models/owner'
+require 'models/pet'
+require 'models/man'
+require 'models/interest'
class AssociationValidationTest < ActiveRecord::TestCase
fixtures :topics, :owners
@@ -98,4 +101,24 @@ class AssociationValidationTest < ActiveRecord::TestCase
end
end
end
+
+ def test_validates_presence_of_belongs_to_association__parent_is_new_record
+ repair_validations(Interest) do
+ # Note that Interest and Man have the :inverse_of option set
+ Interest.validates_presence_of(:man)
+ man = Man.new(:name => 'John')
+ interest = man.interests.build(:topic => 'Airplanes')
+ assert interest.valid?, "Expected interest to be valid, but was not. Interest should have a man object associated"
+ end
+ end
+
+ def test_validates_presence_of_belongs_to_association__existing_parent
+ repair_validations(Interest) do
+ Interest.validates_presence_of(:man)
+ man = Man.create!(:name => 'John')
+ interest = man.interests.build(:topic => 'Airplanes')
+ assert interest.valid?, "Expected interest to be valid, but was not. Interest should have a man object associated"
+ end
+ end
+
end
diff --git a/activerecord/test/connections/native_oracle/connection.rb b/activerecord/test/connections/native_oracle/connection.rb
index 0954b27f87..c8183dc0fb 100644
--- a/activerecord/test/connections/native_oracle/connection.rb
+++ b/activerecord/test/connections/native_oracle/connection.rb
@@ -1,27 +1,68 @@
+# gem "rsim-activerecord-oracle_enhanced-adapter"
+# gem "activerecord-oracle_enhanced-adapter", ">=1.2.1"
+# uses local copy of oracle_enhanced adapter
+$:.unshift("../../oracle-enhanced/lib")
+require 'active_record/connection_adapters/oracle_enhanced_adapter'
+# gem "activerecord-jdbc-adapter"
+# require 'active_record/connection_adapters/jdbc_adapter'
+
+# otherwise failed with silence_warnings method missing exception
+require 'active_support/core_ext/kernel/reporting'
+
print "Using Oracle\n"
require_dependency 'models/course'
require 'logger'
-ActiveRecord::Base.logger = Logger.new STDOUT
-ActiveRecord::Base.logger.level = Logger::WARN
+# ActiveRecord::Base.logger = Logger.new STDOUT
+# ActiveRecord::Base.logger.level = Logger::WARN
+ActiveRecord::Base.logger = Logger.new("debug.log")
# Set these to your database connection strings
-db = ENV['ARUNIT_DB'] || 'activerecord_unittest'
+db = ENV['ARUNIT_DB_NAME'] = 'orcl'
ActiveRecord::Base.configurations = {
'arunit' => {
- :adapter => 'oracle',
+ :adapter => 'oracle_enhanced',
+ :database => db,
+ :host => "localhost", # used just by JRuby to construct JDBC connect string
+ # :adapter => "jdbc",
+ # :driver => "oracle.jdbc.driver.OracleDriver",
+ # :url => "jdbc:oracle:thin:@localhost:1521:#{db}",
:username => 'arunit',
:password => 'arunit',
- :database => db,
+ :emulate_oracle_adapter => true
},
'arunit2' => {
- :adapter => 'oracle',
+ :adapter => 'oracle_enhanced',
+ :database => db,
+ :host => "localhost", # used just by JRuby to construct JDBC connect string
+ # :adapter => "jdbc",
+ # :driver => "oracle.jdbc.driver.OracleDriver",
+ # :url => "jdbc:oracle:thin:@localhost:1521:#{db}",
:username => 'arunit2',
:password => 'arunit2',
- :database => db
+ :emulate_oracle_adapter => true
}
}
ActiveRecord::Base.establish_connection 'arunit'
Course.establish_connection 'arunit2'
+
+# ActiveRecord::Base.connection.execute %q{alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'}
+# ActiveRecord::Base.connection.execute %q{alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS'} rescue nil
+
+# for assert_queries test helper
+ActiveRecord::Base.connection.class.class_eval do
+ IGNORED_SELECT_SQL = [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /^\s*select .* from all_tab_columns/im]
+
+ def select_with_query_record(sql, name = nil, return_column_names = false)
+ $queries_executed ||= []
+ $queries_executed << sql unless IGNORED_SELECT_SQL.any? { |r| sql =~ r }
+ select_without_query_record(sql, name, return_column_names)
+ end
+
+ alias_method_chain :select, :query_record
+end
+
+# For JRuby Set default $KCODE to UTF8
+$KCODE = "UTF8" if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb
index 22168468a6..1c05e523e0 100644
--- a/activerecord/test/models/company.rb
+++ b/activerecord/test/models/company.rb
@@ -73,12 +73,16 @@ class Firm < Company
has_one :unvalidated_account, :foreign_key => "firm_id", :class_name => 'Account', :validate => false
has_one :account_with_select, :foreign_key => "firm_id", :select => "id, firm_id", :class_name=>'Account'
has_one :readonly_account, :foreign_key => "firm_id", :class_name => "Account", :readonly => true
- has_one :account_using_primary_key, :primary_key => "firm_id", :class_name => "Account"
+ # added order by id as in fixtures there are two accounts for Rails Core
+ # Oracle tests were failing because of that as the second fixture was selected
+ has_one :account_using_primary_key, :primary_key => "firm_id", :class_name => "Account", :order => "id"
has_one :deletable_account, :foreign_key => "firm_id", :class_name => "Account", :dependent => :delete
end
class DependentFirm < Company
- has_one :account, :foreign_key => "firm_id", :dependent => :nullify
+ # added order by id as in fixtures there are two accounts for Rails Core
+ # Oracle tests were failing because of that as the second fixture was selected
+ has_one :account, :foreign_key => "firm_id", :dependent => :nullify, :order => "id"
has_many :companies, :foreign_key => 'client_of', :order => "id", :dependent => :nullify
end
diff --git a/activerecord/test/models/subject.rb b/activerecord/test/models/subject.rb
index 3502943f3a..1b9d8107f8 100644
--- a/activerecord/test/models/subject.rb
+++ b/activerecord/test/models/subject.rb
@@ -1,4 +1,12 @@
-# used for OracleSynonymTest, see test/synonym_test_oci.rb
+# used for OracleSynonymTest, see test/synonym_test_oracle.rb
#
class Subject < ActiveRecord::Base
+ protected
+ # added initialization of author_email_address in the same way as in Topic class
+ # as otherwise synonym test was failing
+ def after_initialize
+ if self.new_record?
+ self.author_email_address = 'test@test.com'
+ end
+ end
end
diff --git a/activerecord/test/schema/oracle_specific_schema.rb b/activerecord/test/schema/oracle_specific_schema.rb
index 2d87f34625..3314687445 100644
--- a/activerecord/test/schema/oracle_specific_schema.rb
+++ b/activerecord/test/schema/oracle_specific_schema.rb
@@ -2,6 +2,10 @@ ActiveRecord::Schema.define do
execute "drop table test_oracle_defaults" rescue nil
execute "drop sequence test_oracle_defaults_seq" rescue nil
+ execute "drop sequence companies_nonstd_seq" rescue nil
+ execute "drop synonym subjects" rescue nil
+ execute "drop table defaults" rescue nil
+ execute "drop sequence defaults_seq" rescue nil
execute <<-SQL
create table test_oracle_defaults (
@@ -16,4 +20,27 @@ create table test_oracle_defaults (
create sequence test_oracle_defaults_seq minvalue 10000
SQL
+ execute "create sequence companies_nonstd_seq minvalue 10000"
+
+ execute "create synonym subjects for topics"
+
+ execute <<-SQL
+ CREATE TABLE defaults (
+ id integer not null,
+ modified_date date default sysdate,
+ modified_date_function date default sysdate,
+ fixed_date date default to_date('2004-01-01', 'YYYY-MM-DD'),
+ modified_time date default sysdate,
+ modified_time_function date default sysdate,
+ fixed_time date default TO_DATE('2004-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'),
+ char1 varchar2(1) default 'Y',
+ char2 varchar2(50) default 'a varchar field',
+ char3 clob default 'a text field',
+ positive_integer integer default 1,
+ negative_integer integer default -1,
+ decimal_number number(3,2) default 2.78
+ )
+ SQL
+ execute "create sequence defaults_seq minvalue 10000"
+
end
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 1e47cdbaf6..5f60d5e137 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -104,7 +104,13 @@ ActiveRecord::Schema.define do
create_table :comments, :force => true do |t|
t.integer :post_id, :null => false
- t.text :body, :null => false
+ # use VARCHAR2(4000) instead of CLOB datatype as CLOB data type has many limitations in
+ # Oracle SELECT WHERE clause which causes many unit test failures
+ if current_adapter?(:OracleAdapter)
+ t.string :body, :null => false, :limit => 4000
+ else
+ t.text :body, :null => false
+ end
t.string :type
end
@@ -279,7 +285,12 @@ ActiveRecord::Schema.define do
t.decimal :my_house_population, :precision => 2, :scale => 0
t.decimal :decimal_number_with_default, :precision => 3, :scale => 2, :default => 2.78
t.float :temperature
- t.decimal :atoms_in_universe, :precision => 55, :scale => 0
+ # Oracle supports precision up to 38
+ if current_adapter?(:OracleAdapter)
+ t.decimal :atoms_in_universe, :precision => 38, :scale => 0
+ else
+ t.decimal :atoms_in_universe, :precision => 55, :scale => 0
+ end
end
create_table :orders, :force => true do |t|
@@ -350,7 +361,13 @@ ActiveRecord::Schema.define do
create_table :posts, :force => true do |t|
t.integer :author_id
t.string :title, :null => false
- t.text :body, :null => false
+ # use VARCHAR2(4000) instead of CLOB datatype as CLOB data type has many limitations in
+ # Oracle SELECT WHERE clause which causes many unit test failures
+ if current_adapter?(:OracleAdapter)
+ t.string :body, :null => false, :limit => 4000
+ else
+ t.text :body, :null => false
+ end
t.string :type
t.integer :comments_count, :default => 0
t.integer :taggings_count, :default => 0
@@ -423,7 +440,13 @@ ActiveRecord::Schema.define do
t.datetime :written_on
t.time :bonus_time
t.date :last_read
- t.text :content
+ # use VARCHAR2(4000) instead of CLOB datatype as CLOB data type has many limitations in
+ # Oracle SELECT WHERE clause which causes many unit test failures
+ if current_adapter?(:OracleAdapter)
+ t.string :content, :limit => 4000
+ else
+ t.text :content
+ end
t.boolean :approved, :default => true
t.integer :replies_count, :default => 0
t.integer :parent_id
diff --git a/activeresource/lib/active_resource/connection.rb b/activeresource/lib/active_resource/connection.rb
index fb3fde59d6..99d4b8f2ca 100644
--- a/activeresource/lib/active_resource/connection.rb
+++ b/activeresource/lib/active_resource/connection.rb
@@ -134,7 +134,7 @@ module ActiveResource
def http
http = Net::HTTP.new(@site.host, @site.port)
http.use_ssl = @site.is_a?(URI::HTTPS)
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl?
http.read_timeout = @timeout if @timeout # If timeout is not set, the default Net::HTTP timeout (60s) is used.
http
end
diff --git a/activesupport/lib/active_support/json/backends/yaml.rb b/activesupport/lib/active_support/json/backends/yaml.rb
index 667016f45d..92dd31cfbc 100644
--- a/activesupport/lib/active_support/json/backends/yaml.rb
+++ b/activesupport/lib/active_support/json/backends/yaml.rb
@@ -34,11 +34,9 @@ module ActiveSupport
pos = scanner.pos
elsif quoting == char
if json[pos..scanner.pos-2] =~ DATE_REGEX
- # found a date, track the exact positions of the quotes so we can remove them later.
- # oh, and increment them for each current mark, each one is an extra padded space that bumps
- # the position in the final YAML output
- total_marks = marks.size
- times << pos+total_marks << scanner.pos+total_marks
+ # found a date, track the exact positions of the quotes so we can
+ # overwrite them with spaces later.
+ times << pos << scanner.pos
end
quoting = false
end
@@ -64,7 +62,12 @@ module ActiveSupport
output = []
left_pos.each_with_index do |left, i|
scanner.pos = left.succ
- output << scanner.peek(right_pos[i] - scanner.pos + 1).gsub(/\\([\\\/]|u[[:xdigit:]]{4})/) do
+ chunk = scanner.peek(right_pos[i] - scanner.pos + 1)
+ # overwrite the quotes found around the dates with spaces
+ while times.size > 0 && times[0] <= right_pos[i]
+ chunk[times.shift - scanner.pos - 1] = ' '
+ end
+ chunk.gsub!(/\\([\\\/]|u[[:xdigit:]]{4})/) do
ustr = $1
if ustr.start_with?('u')
[ustr[1..-1].to_i(16)].pack("U")
@@ -74,10 +77,10 @@ module ActiveSupport
ustr
end
end
+ output << chunk
end
output = output * " "
- times.each { |i| output[i-1] = ' ' }
output.gsub!(/\\\//, '/')
output
end
diff --git a/activesupport/test/json/decoding_test.rb b/activesupport/test/json/decoding_test.rb
index 09fd0d09ba..4129a4fab6 100644
--- a/activesupport/test/json/decoding_test.rb
+++ b/activesupport/test/json/decoding_test.rb
@@ -33,7 +33,13 @@ class TestJSONDecoding < ActiveSupport::TestCase
%q({"a": "\u003cunicode\u0020escape\u003e"}) => {"a" => "<unicode escape>"},
%q({"a": "\\\\u0020skip double backslashes"}) => {"a" => "\\u0020skip double backslashes"},
%q({"a": "\u003cbr /\u003e"}) => {'a' => "<br />"},
- %q({"b":["\u003ci\u003e","\u003cb\u003e","\u003cu\u003e"]}) => {'b' => ["<i>","<b>","<u>"]}
+ %q({"b":["\u003ci\u003e","\u003cb\u003e","\u003cu\u003e"]}) => {'b' => ["<i>","<b>","<u>"]},
+ # test combination of dates and escaped or unicode encoded data in arrays
+ %q([{"d":"1970-01-01", "s":"\u0020escape"},{"d":"1970-01-01", "s":"\u0020escape"}]) =>
+ [{'d' => Date.new(1970, 1, 1), 's' => ' escape'},{'d' => Date.new(1970, 1, 1), 's' => ' escape'}],
+ %q([{"d":"1970-01-01","s":"http:\/\/example.com"},{"d":"1970-01-01","s":"http:\/\/example.com"}]) =>
+ [{'d' => Date.new(1970, 1, 1), 's' => 'http://example.com'},
+ {'d' => Date.new(1970, 1, 1), 's' => 'http://example.com'}]
}
# load the default JSON backend
diff --git a/railties/lib/generators.rb b/railties/lib/generators.rb
index 64ec808ee4..c97c61507a 100644
--- a/railties/lib/generators.rb
+++ b/railties/lib/generators.rb
@@ -11,7 +11,7 @@ end
$:.unshift(File.dirname(__FILE__))
-require 'vendor/thor-0.11.3/lib/thor'
+require 'vendor/thor-0.11.5/lib/thor'
require 'generators/base'
require 'generators/named_base'
@@ -83,6 +83,34 @@ module Rails
@@options ||= DEFAULT_OPTIONS.dup
end
+ # Get paths only from loaded rubygems. In other words, to use rspec
+ # generators, you first have to ensure that rspec gem was already loaded.
+ #
+ def self.rubygems_generators_paths
+ paths = []
+ return paths unless defined?(Gem)
+
+ Gem.loaded_specs.each do |name, spec|
+ generator_path = File.join(spec.full_gem_path, "lib/generators")
+ paths << generator_path if File.exist?(generator_path)
+ end
+
+ paths
+ end
+
+ # If RAILS_ROOT is defined, add vendor/gems, vendor/plugins and lib/generators
+ # paths.
+ #
+ def self.rails_root_generators_paths
+ paths = []
+ if defined?(RAILS_ROOT)
+ paths += Dir[File.join(RAILS_ROOT, "vendor", "gems", "gems", "*", "lib", "generators")]
+ paths += Dir[File.join(RAILS_ROOT, "vendor", "plugins", "*", "lib", "generators")]
+ paths << File.join(RAILS_ROOT, "lib", "generators")
+ end
+ paths
+ end
+
# Hold configured generators fallbacks. If a plugin developer wants a
# generator group to fallback to another group in case of missing generators,
# they can add a fallback.
@@ -108,30 +136,25 @@ module Rails
# Generators load paths used on lookup. The lookup happens as:
#
- # 1) builtin generators
- # 2) frozen gems generators
- # 3) rubygems gems generators (not available yet)
- # 4) plugin generators
- # 5) lib generators
- # 6) ~/rails/generators
+ # 1) lib generators
+ # 2) vendor/plugin generators
+ # 3) vendor/gems generators
+ # 4) ~/rails/generators
+ # 5) rubygems generators
+ # 6) builtin generators
#
- # TODO Add Rubygems generators (depends on dependencies system rework)
# TODO Remove hardcoded paths for all, except (1).
#
- def self.load_path
- @@load_path ||= begin
- paths = []
- paths << File.expand_path(File.join(File.dirname(__FILE__), "generators"))
- if defined?(RAILS_ROOT)
- paths += Dir[File.join(RAILS_ROOT, "vendor", "gems", "*", "lib", "generators")]
- paths += Dir[File.join(RAILS_ROOT, "vendor", "plugins", "*", "lib", "generators")]
- paths << File.join(RAILS_ROOT, "lib", "generators")
- end
+ def self.load_paths
+ @@load_paths ||= begin
+ paths = self.rails_root_generators_paths
paths << File.join(Thor::Util.user_home, ".rails", "generators")
+ paths += self.rubygems_generators_paths
+ paths << File.expand_path(File.join(File.dirname(__FILE__), "generators"))
paths
end
end
- load_path # Cache load paths. Needed to avoid __FILE__ pointing to wrong paths.
+ load_paths # Cache load paths. Needed to avoid __FILE__ pointing to wrong paths.
# Receives a namespace and tries different combinations to find a generator.
#
@@ -204,8 +227,8 @@ module Rails
puts "Builtin: #{rails.join(', ')}."
# Load paths and remove builtin
- paths, others = load_path.dup, []
- paths.shift
+ paths, others = load_paths.dup, []
+ paths.pop
paths.each do |path|
tail = [ "*", "*", "*_generator.rb" ]
@@ -242,7 +265,6 @@ module Rails
#
def self.invoke_fallbacks_for(name, base)
return nil unless base && fallbacks[base.to_sym]
-
invoked_fallbacks = []
Array(fallbacks[base.to_sym]).each do |fallback|
@@ -283,7 +305,7 @@ module Rails
generators_path.uniq!
generators_path = "{#{generators_path.join(',')}}"
- self.load_path.each do |path|
+ self.load_paths.each do |path|
Dir[File.join(path, generators_path, name)].each do |file|
begin
require file
diff --git a/railties/lib/generators/action_orm.rb b/railties/lib/generators/active_model.rb
index 69cf227fd7..1a849a0e02 100644
--- a/railties/lib/generators/action_orm.rb
+++ b/railties/lib/generators/active_model.rb
@@ -1,6 +1,6 @@
module Rails
module Generators
- # ActionORM is a class to be implemented by each ORM to allow Rails to
+ # ActiveModel is a class to be implemented by each ORM to allow Rails to
# generate customized controller code.
#
# The API has the same methods as ActiveRecord, but each method returns a
@@ -8,22 +8,22 @@ module Rails
#
# For example:
#
- # ActiveRecord::Generators::ActionORM.find(Foo, "params[:id]")
+ # ActiveRecord::Generators::ActiveModel.find(Foo, "params[:id]")
# #=> "Foo.find(params[:id])"
#
- # Datamapper::Generators::ActionORM.find(Foo, "params[:id]")
+ # Datamapper::Generators::ActiveModel.find(Foo, "params[:id]")
# #=> "Foo.get(params[:id])"
#
- # On initialization, the ActionORM accepts the instance name that will
+ # On initialization, the ActiveModel accepts the instance name that will
# receive the calls:
#
- # builder = ActiveRecord::Generators::ActionORM.new "@foo"
+ # builder = ActiveRecord::Generators::ActiveModel.new "@foo"
# builder.save #=> "@foo.save"
#
- # The only exception in ActionORM for ActiveRecord is the use of self.build
+ # The only exception in ActiveModel for ActiveRecord is the use of self.build
# instead of self.new.
#
- class ActionORM
+ class ActiveModel
attr_reader :name
def initialize(name)
diff --git a/railties/lib/generators/active_record.rb b/railties/lib/generators/active_record.rb
index 64bee3904e..924b70881a 100644
--- a/railties/lib/generators/active_record.rb
+++ b/railties/lib/generators/active_record.rb
@@ -1,6 +1,6 @@
require 'generators/named_base'
require 'generators/migration'
-require 'generators/action_orm'
+require 'generators/active_model'
require 'active_record'
module ActiveRecord
@@ -20,7 +20,7 @@ module ActiveRecord
end
end
- class ActionORM < Rails::Generators::ActionORM #:nodoc:
+ class ActiveModel < Rails::Generators::ActiveModel #:nodoc:
def self.all(klass)
"#{klass}.all"
end
diff --git a/railties/lib/generators/named_base.rb b/railties/lib/generators/named_base.rb
index 699b8ed651..9632e6806c 100644
--- a/railties/lib/generators/named_base.rb
+++ b/railties/lib/generators/named_base.rb
@@ -124,18 +124,18 @@ module Rails
protected
- # Loads the ORM::Generators::ActionORM class. This class is responsable
+ # Loads the ORM::Generators::ActiveModel class. This class is responsable
# to tell scaffold entities how to generate an specific method for the
- # ORM. Check Rails::Generators::ActionORM for more information.
+ # ORM. Check Rails::Generators::ActiveModel for more information.
#
def orm_class
@orm_class ||= begin
# Raise an error if the class_option :orm was not defined.
unless self.class.class_options[:orm]
- raise "You need to have :orm as class option to invoke orm_class and orm_instance"
+ raise "You need to have :orm as class option to invoke orm_class and orm_instance"
end
- action_orm = "#{options[:orm].to_s.classify}::Generators::ActionORM"
+ action_orm = "#{options[:orm].to_s.classify}::Generators::ActiveModel"
# If the orm was not loaded, try to load it at "generators/orm",
# for example "generators/active_record" or "generators/sequel".
@@ -152,7 +152,7 @@ module Rails
end
end
- # Initialize ORM::Generators::ActionORM to access instance methods.
+ # Initialize ORM::Generators::ActiveModel to access instance methods.
#
def orm_instance(name=file_name)
@orm_instance ||= @orm_class.new(name)
diff --git a/railties/lib/generators/rails/app/app_generator.rb b/railties/lib/generators/rails/app/app_generator.rb
index c8044d13b1..c80a344e0d 100644
--- a/railties/lib/generators/rails/app/app_generator.rb
+++ b/railties/lib/generators/rails/app/app_generator.rb
@@ -49,7 +49,7 @@ module Rails::Generators
self.destination_root = File.expand_path(app_path, destination_root)
empty_directory '.'
- app_name # Sets the app name
+ set_default_accessors!
FileUtils.cd(destination_root)
end
@@ -164,9 +164,9 @@ module Rails::Generators
end
def apply_rails_template
- apply options[:template] if options[:template]
+ apply rails_template if rails_template
rescue Thor::Error, LoadError, Errno::ENOENT => e
- raise Error, "The template [#{options[:template]}] could not be loaded. Error: #{e}"
+ raise Error, "The template [#{rails_template}] could not be loaded. Error: #{e}"
end
def freeze?
@@ -175,6 +175,21 @@ module Rails::Generators
protected
+ attr_accessor :rails_template
+
+ def set_default_accessors!
+ app_name # Cache app name
+
+ self.rails_template = case options[:template]
+ when /^http:\/\//
+ options[:template]
+ when String
+ File.expand_path(options[:template], Dir.pwd)
+ else
+ options[:template]
+ end
+ end
+
# Define file as an alias to create_file for backwards compatibility.
#
def file(*args, &block)
diff --git a/railties/lib/tasks/databases.rake b/railties/lib/tasks/databases.rake
index 0d4d658315..23a3a73a7f 100644
--- a/railties/lib/tasks/databases.rake
+++ b/railties/lib/tasks/databases.rake
@@ -101,8 +101,12 @@ namespace :db do
ActiveRecord::Base.configurations.each_value do |config|
# Skip entries that don't have a database key
next unless config['database']
- # Only connect to local databases
- local_database?(config) { drop_database(config) }
+ begin
+ # Only connect to local databases
+ local_database?(config) { drop_database(config) }
+ rescue Exception => e
+ puts "Couldn't drop #{config['database']} : #{e.inspect}"
+ end
end
end
end
@@ -172,6 +176,13 @@ namespace :db do
Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
end
+ desc 'Pushes the schema to the next version. Specify the number of steps with STEP=n'
+ task :forward => :environment do
+ step = ENV['STEP'] ? ENV['STEP'].to_i : 1
+ ActiveRecord::Migrator.forward('db/migrate/', step)
+ Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
+ end
+
desc 'Drops and recreates the database from db/schema.rb for the current environment and loads the seeds.'
task :reset => [ 'db:drop', 'db:setup' ]
diff --git a/railties/lib/tasks/routes.rake b/railties/lib/tasks/routes.rake
index 39b7139167..abbf3258c1 100644
--- a/railties/lib/tasks/routes.rake
+++ b/railties/lib/tasks/routes.rake
@@ -1,6 +1,7 @@
-desc 'Print out all defined routes in match order, with names.'
+desc 'Print out all defined routes in match order, with names. Target specific controller with CONTROLLER=x.'
task :routes => :environment do
- routes = ActionController::Routing::Routes.routes.collect do |route|
+ all_routes = ENV['CONTROLLER'] ? ActionController::Routing::Routes.routes.select { |route| route.defaults[:controller] == ENV['CONTROLLER'] } : ActionController::Routing::Routes.routes
+ routes = all_routes.collect do |route|
name = ActionController::Routing::Routes.named_routes.routes.index(route).to_s
verb = route.conditions[:method].to_s.upcase
segs = route.segments.inject("") { |str,s| str << s.to_s }
@@ -14,4 +15,4 @@ task :routes => :environment do
routes.each do |r|
puts "#{r[:name].rjust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:segs].ljust(segs_width)} #{r[:reqs]}"
end
-end \ No newline at end of file
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/error.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/error.rb
deleted file mode 100644
index c846e9ce74..0000000000
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/error.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-class Thor
- # Thor::Error is raised when it's caused by the user invoking the task and
- # only errors that inherit from it are rescued.
- #
- # So, for example, if the developer declares a required argument after an
- # option, it should raise an ::ArgumentError and not ::Thor::ArgumentError,
- # because it was caused by the developer and not the "final user".
- #
- class Error < StandardError #:nodoc:
- end
-
- # Raised when a task was not found.
- #
- class UndefinedTaskError < Error #:nodoc:
- end
-
- # Raised when a task was found, but not invoked properly.
- #
- class InvocationError < Error #:nodoc:
- end
-
- class RequiredArgumentMissingError < InvocationError #:nodoc:
- end
-
- class MalformattedArgumentError < InvocationError #:nodoc:
- end
-end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/tasks.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/tasks.rb
deleted file mode 100644
index d1a7b1c673..0000000000
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/tasks.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-# This only loads all tasks inside tasks.
-Dir[File.join(File.dirname(__FILE__), "tasks", "*.rb")].each do |task|
- require task
-end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/tasks/install.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/tasks/install.rb
deleted file mode 100644
index 6b20ff1634..0000000000
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/tasks/install.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-class Thor
- # Creates an install task.
- #
- # ==== Parameters
- # spec<Gem::Specification>
- #
- # ==== Options
- # :dir - The directory where the package is hold before installation. Defaults to ./pkg.
- #
- def self.install_task(spec, options={})
- package_task(spec, options)
- tasks['install'] = Thor::InstallTask.new(spec, options)
- end
-
- class InstallTask < Task
- attr_accessor :spec, :config
-
- def initialize(gemspec, config={})
- super(:install, "Install the gem", "install", {})
- @spec = gemspec
- @config = { :dir => File.join(Dir.pwd, "pkg") }.merge(config)
- end
-
- def run(instance, args=[])
- null, sudo, gem = RUBY_PLATFORM =~ /mswin|mingw/ ? ['NUL', '', 'gem.bat'] :
- ['/dev/null', 'sudo', 'gem']
-
- old_stderr, $stderr = $stderr.dup, File.open(null, "w")
- instance.invoke(:package)
- $stderr = old_stderr
-
- system %{#{sudo} #{Gem.ruby} -S #{gem} install #{config[:dir]}/#{spec.name}-#{spec.version} --no-rdoc --no-ri --no-update-sources}
- end
- end
-end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/tasks/package.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/tasks/package.rb
deleted file mode 100644
index 603d61b4ab..0000000000
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/tasks/package.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-require "fileutils"
-
-class Thor
- # Creates a package task.
- #
- # ==== Parameters
- # spec<Gem::Specification>
- #
- # ==== Options
- # :dir - The package directory. Defaults to ./pkg.
- #
- def self.package_task(spec, options={})
- tasks['package'] = Thor::PackageTask.new(spec, options)
- end
-
- class PackageTask < Task
- attr_accessor :spec, :config
-
- def initialize(gemspec, config={})
- super(:package, "Build a gem package", "package", {})
- @spec = gemspec
- @config = {:dir => File.join(Dir.pwd, "pkg")}.merge(config)
- end
-
- def run(instance, args=[])
- FileUtils.mkdir_p(config[:dir])
- Gem::Builder.new(spec).build
- FileUtils.mv(spec.file_name, File.join(config[:dir], spec.file_name))
- end
- end
-end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/tasks/spec.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/tasks/spec.rb
deleted file mode 100644
index c7d00968e8..0000000000
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/tasks/spec.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-require "fileutils"
-
-class Thor
- # Creates a spec task.
- #
- # ==== Parameters
- # files<Array> - Array of files to spec
- #
- # ==== Options
- # :name - The name of the task. It can be rcov or spec. Spec is the default.
- # :rcov - A hash with rcov specific options.
- # :rcov_dir - Where rcov reports should be printed.
- # :verbose - Sets the default value for verbose, although it can be specified
- # also through the command line.
- #
- # All other options are added to rspec.
- #
- def self.spec_task(files, options={})
- name = (options.delete(:name) || 'spec').to_s
- tasks[name] = Thor::SpecTask.new(name, files, options)
- end
-
- class SpecTask < Task
- attr_accessor :name, :files, :rcov_dir, :rcov_config, :spec_config
-
- def initialize(name, files, config={})
- options = { :verbose => Thor::Option.parse(:verbose, config.delete(:verbose) || false) }
- super(name, "#{name.capitalize} task", name, options)
-
- @name = name
- @files = files.map{ |f| %["#{f}"] }.join(" ")
- @rcov_dir = config.delete(:rdoc_dir) || File.join(Dir.pwd, 'coverage')
- @rcov_config = config.delete(:rcov) || {}
- @spec_config = { :format => 'specdoc', :color => true }.merge(config)
- end
-
- def run(instance, args=[])
- rcov_opts = Thor::Options.to_switches(rcov_config)
- spec_opts = Thor::Options.to_switches(spec_config)
-
- require 'rbconfig'
- cmd = RbConfig::CONFIG['ruby_install_name'] << " "
-
- if rcov?
- FileUtils.rm_rf(rcov_dir)
- cmd << "-S #{where('rcov')} -o #{rcov_dir} #{rcov_opts} "
- end
-
- cmd << [where('spec'), rcov? ? " -- " : nil, files, spec_opts].join(" ")
-
- puts cmd if instance.options.verbose?
- system(cmd)
- exit($?.exitstatus)
- end
-
- private
-
- def rcov?
- name == "rcov"
- end
-
- def where(file)
- ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
- file_with_path = File.join(path, file)
- next unless File.exist?(file_with_path) && File.executable?(file_with_path)
- return File.expand_path(file_with_path)
- end
- end
- end
-end
diff --git a/railties/lib/vendor/thor-0.11.3/CHANGELOG.rdoc b/railties/lib/vendor/thor-0.11.5/CHANGELOG.rdoc
index 544dde8c02..dba25b7205 100644
--- a/railties/lib/vendor/thor-0.11.3/CHANGELOG.rdoc
+++ b/railties/lib/vendor/thor-0.11.5/CHANGELOG.rdoc
@@ -1,9 +1,11 @@
== TODO
* Improve spec coverage for Thor::Runner
-* Improve help output to list shorthand switches, too
-== Current
+== 0.11.x, released 2009-07-01
+
+* Added a rake compatibility layer. It allows you to use spec and rdoc tasks on
+ Thor classes.
* BACKWARDS INCOMPATIBLE: aliases are not generated automatically anymore
since it wrong behavior to the invocation system.
diff --git a/railties/lib/vendor/thor-0.11.3/LICENSE b/railties/lib/vendor/thor-0.11.5/LICENSE
index 98722da459..98722da459 100644
--- a/railties/lib/vendor/thor-0.11.3/LICENSE
+++ b/railties/lib/vendor/thor-0.11.5/LICENSE
diff --git a/railties/lib/vendor/thor-0.11.3/README.markdown b/railties/lib/vendor/thor-0.11.5/README.rdoc
index a1d7259775..f1106f02b6 100644
--- a/railties/lib/vendor/thor-0.11.3/README.markdown
+++ b/railties/lib/vendor/thor-0.11.5/README.rdoc
@@ -1,5 +1,4 @@
-thor
-====
+= thor
Map options to a class. Simply create a class with the appropriate annotations
and have options automatically map to functions and parameters.
@@ -34,26 +33,18 @@ That gets converted to:
App.new.install("myname")
# with {'force' => true} as options hash
-1. Inherit from Thor to turn a class into an option mapper
-2. Map additional non-valid identifiers to specific methods. In this case, convert -L to :list
-3. Describe the method immediately below. The first parameter is the usage information, and the second parameter is the description
-4. Provide any additional options that will be available the instance method options.
-
-Types for `method_options`
---------------------------
-
-<dl>
- <dt><code>:boolean</code></dt>
- <dd>is parsed as --option or --option=true</dd>
- <dt><code>:string</code></dt>
- <dd>is parsed as --option=VALUE</dd>
- <dt><code>:numeric</code></dt>
- <dd>is parsed as --option=N</dd>
- <dt><code>:array</code></dt>
- <dd>is parsed as --option=one two three</dd>
- <dt><code>:hash</code></dt>
- <dd>is parsed as --option=key:value key:value key:value</dd>
-</dl>
+1. Inherit from Thor to turn a class into an option mapper
+2. Map additional non-valid identifiers to specific methods. In this case, convert -L to :list
+3. Describe the method immediately below. The first parameter is the usage information, and the second parameter is the description
+4. Provide any additional options that will be available the instance method options.
+
+== Types for <tt>method_options</tt>
+
+* :boolean - is parsed as <tt>--option</tt> or <tt>--option=true</tt>
+* :string - is parsed as <tt>--option=VALUE</tt>
+* :numeric - is parsed as <tt>--option=N</tt>
+* :array - is parsed as <tt>--option=one two three</tt>
+* :hash - is parsed as <tt>--option=name:string age:integer</tt>
Besides, method_option allows a default value to be given, examples:
@@ -66,9 +57,9 @@ Besides, method_option allows a default value to be given, examples:
method_options :threshold => 3.0
#=> Creates a numeric option with default value 3.0
-You can also supply :option => :required to mark an option as required. The
+You can also supply <tt>:option => :required</tt> to mark an option as required. The
type is assumed to be string. If you want a required hash with default values
-as option, you can use `method_option` which uses a more declarative style:
+as option, you can use <tt>method_option</tt> which uses a more declarative style:
method_option :attributes, :type => :hash, :default => {}, :required => true
@@ -91,8 +82,7 @@ You can supply as many aliases as you want.
NOTE: Type :optional available in Thor 0.9.0 was deprecated. Use :string or :boolean instead.
-Namespaces
-----------
+== Namespaces
By default, your Thor tasks are invoked using Ruby namespace. In the example
above, tasks are invoked as:
@@ -124,8 +114,7 @@ And then your tasks hould be invoked as:
thor myapp:install name --force
-Invocations
------------
+== Invocations
Thor comes with a invocation-dependency system as well which allows a task to be
invoked only once. For example:
@@ -158,8 +147,7 @@ The output is "1 2 3", which means that the three task was invoked only once.
You can even invoke tasks from another class, so be sure to check the
documentation.
-Thor::Group
------------
+== Thor::Group
Thor has a special class called Thor::Group. The main difference to Thor class
is that it invokes all tasks at once. The example above could be rewritten in
@@ -185,10 +173,10 @@ When invoked:
thor counter
-It prints "1 2 3" as well. Notice you should described (desc) only the class
-and not each task anymore. Thor::Group is a great tool to create generators,
-since you can define several steps which are invoked in the order they are
-defined (Thor::Group is the tool use in generators in Rails 3.0).
+It prints "1 2 3" as well. Notice you should describe (using the method <tt>desc</tt>)
+only the class and not each task anymore. Thor::Group is a great tool to create
+generators, since you can define several steps which are invoked in the order they
+are defined (Thor::Group is the tool use in generators in Rails 3.0).
Besides, Thor::Group can parse arguments and options as Thor tasks:
@@ -218,17 +206,17 @@ The counter above expects one parameter and has the folling outputs:
thor counter 11
# Prints "11 12 13"
-You can also give options to Thor::Group, but instead of using `method_option` and
-`method_options`, you should use `class_option` and `class_options`. Both argument
-and class_options methods are available to Thor class as well.
+You can also give options to Thor::Group, but instead of using <tt>method_option</tt>
+and <tt>method_options</tt>, you should use <tt>class_option</tt> and <tt>class_options</tt>.
+Both argument and class_options methods are available to Thor class as well.
-Actions
--------
+== Actions
Thor comes with several actions which helps with script and generator tasks. You
-might be familiar with them since some came from Rails Templates. They are: `say`,
-`ask`, `yes?`, `no?`, `add_file`, `remove_file`, `copy_file`, `template`,
-`directory`, `inside`, `run`, `inject_into_file` and a couple more.
+might be familiar with them since some came from Rails Templates. They are:
+<tt>say</tt>, <tt>ask</tt>, <tt>yes?</tt>, <tt>no?</tt>, <tt>add_file</tt>,
+<tt>remove_file</tt>, <tt>copy_file</tt>, <tt>template</tt>, <tt>directory</tt>,
+<tt>inside</tt>, <tt>run</tt>, <tt>inject_into_file</tt> and a couple more.
To use them, you just need to include Thor::Actions in your Thor classes:
@@ -241,7 +229,6 @@ Some actions like copy file requires that a class method called source_root is
defined in your class. This is the directory where your templates should be
placed. Be sure to check the documentation.
-License
--------
+== License
See MIT LICENSE.
diff --git a/railties/lib/vendor/thor-0.11.3/bin/rake2thor b/railties/lib/vendor/thor-0.11.5/bin/rake2thor
index 50c7410d80..50c7410d80 100755
--- a/railties/lib/vendor/thor-0.11.3/bin/rake2thor
+++ b/railties/lib/vendor/thor-0.11.5/bin/rake2thor
diff --git a/railties/lib/vendor/thor-0.11.3/bin/thor b/railties/lib/vendor/thor-0.11.5/bin/thor
index eaf849fb4a..eaf849fb4a 100755
--- a/railties/lib/vendor/thor-0.11.3/bin/thor
+++ b/railties/lib/vendor/thor-0.11.5/bin/thor
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor.rb b/railties/lib/vendor/thor-0.11.5/lib/thor.rb
index f65455cdda..8dfcfd4c5b 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor.rb
@@ -101,8 +101,7 @@ class Thor
# :required - If the argument is required or not.
# :default - Default value for this argument. It cannot be required and have default values.
# :aliases - Aliases for this option.
- # :type - The type of the argument, can be :string, :hash, :array, :numeric, :boolean or :default.
- # Default accepts arguments as booleans (--switch) or as strings (--switch=VALUE).
+ # :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean.
# :group - The group for this options. Use by class options to output options in different levels.
# :banner - String to show on usage notes.
#
@@ -160,39 +159,43 @@ class Thor
raise UndefinedTaskError, "task '#{meth}' could not be found in namespace '#{self.namespace}'" unless task
shell.say "Usage:"
- shell.say " #{banner(task, options[:namespace])}"
+ shell.say " #{banner(task, options[:namespace], false)}"
shell.say
- class_options_help(shell, "Class")
+ class_options_help(shell, "Class", :Method => task.options.map { |_, o| o })
shell.say task.description
else
list = (options[:short] ? tasks : all_tasks).map do |_, task|
- item = [ " " + banner(task, options[:namespace]) ]
- item << if task.short_description
- "\n # #{task.short_description}\n"
- else
- "\n"
- end
+ item = [ banner(task, options[:namespace]) ]
+ item << "# #{task.short_description}" if task.short_description
+ item << " "
end
+ options[:ident] ||= 2
if options[:short]
- shell.print_table(list)
+ shell.print_list(list, :ident => options[:ident])
else
shell.say "Tasks:"
- shell.print_table(list)
- class_options_help(shell, "Class")
+ shell.print_list(list, :ident => options[:ident])
end
+
+ Thor::Util.thor_classes_in(self).each do |subclass|
+ namespace = options[:namespace] == true || subclass.namespace.gsub(/^#{self.namespace}:/, '')
+ subclass.help(shell, options.merge(:short => true, :namespace => namespace))
+ end
+
+ class_options_help(shell, "Class") unless options[:short]
end
end
protected
# The banner for this class. You can customize it if you are invoking the
- # thor class by another means which is not the Thor::Runner. It receives
- # the task that is going to be invoked and if the namespace should be
- # displayed.
+ # thor class by another ways which is not the Thor::Runner. It receives
+ # the task that is going to be invoked and a boolean which indicates if
+ # the namespace should be displayed as arguments.
#
- def banner(task, namespace=true) #:nodoc:
- task.formatted_usage(self, namespace)
+ def banner(task, namespace=true, show_options=true)
+ task.formatted_usage(self, namespace, show_options)
end
def baseclass #:nodoc:
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/actions.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/actions.rb
index b8cfde1940..1d09dc38ae 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/actions.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/actions.rb
@@ -43,13 +43,11 @@ class Thor
# 3) Parents source paths
#
def source_paths_for_search
- @source_paths_for_search ||= begin
- paths = []
- paths += self.source_paths
- paths << self.source_root if self.respond_to?(:source_root)
- paths += from_superclass(:source_paths, [])
- paths
- end
+ paths = []
+ paths += self.source_paths
+ paths << self.source_root if self.respond_to?(:source_root)
+ paths += from_superclass(:source_paths, [])
+ paths
end
end
@@ -60,8 +58,7 @@ class Thor
# It also accepts :force, :skip and :pretend to set the behavior
# and the respective option.
#
- # destination_root<String>:: The root directory needed for some actions. It's also known
- # as destination root.
+ # destination_root<String>:: The root directory needed for some actions.
#
def initialize(args=[], options={}, config={})
self.behavior = case config[:behavior].to_s
@@ -80,7 +77,7 @@ class Thor
# Wraps an action object and call it accordingly to the thor class behavior.
#
- def action(instance)
+ def action(instance) #:nodoc:
if behavior == :revoke
instance.revoke!
else
@@ -110,18 +107,23 @@ class Thor
remove_dot ? (path[2..-1] || '') : path
end
+ # Holds source paths in instance so they can be manipulated.
+ #
+ def source_paths
+ @source_paths ||= self.class.source_paths_for_search
+ end
+
# Receives a file or directory and search for it in the source paths.
#
def find_in_source_paths(file)
relative_root = relative_to_original_destination_root(destination_root, false)
- paths = self.class.source_paths_for_search
- paths.each do |source|
+ source_paths.each do |source|
source_file = File.expand_path(file, File.join(source, relative_root))
return source_file if File.exists?(source_file)
end
- if paths.empty?
+ if source_paths.empty?
raise Error, "You don't have any source path defined for class #{self.class.name}. To fix this, " <<
"you can define a source_root in your class."
else
@@ -205,7 +207,7 @@ class Thor
end
say_status :run, desc, config.fetch(:verbose, true)
- `#{command}` unless options[:pretend]
+ system(command) unless options[:pretend]
end
# Executes a ruby script (taking into account WIN32 platform quirks).
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/actions/create_file.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/actions/create_file.rb
index 8f6badee27..8f6badee27 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/actions/create_file.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/actions/create_file.rb
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/actions/directory.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/actions/directory.rb
index e33639f4e5..be5eb822ac 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/actions/directory.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/actions/directory.rb
@@ -3,7 +3,7 @@ require 'thor/actions/empty_directory'
class Thor
module Actions
- # Copies interactively the files from source directory to root directory.
+ # Copies recursively the files from source directory to root directory.
# If any of the files finishes with .tt, it's considered to be a template
# and is placed in the destination without the extension .tt. If any
# empty directory is found, it's copied and all .empty_directory files are
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/actions/empty_directory.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/actions/empty_directory.rb
index 03c1fe4af1..03c1fe4af1 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/actions/empty_directory.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/actions/empty_directory.rb
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/actions/file_manipulation.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/actions/file_manipulation.rb
index 74c157ba8c..74c157ba8c 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/actions/file_manipulation.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/actions/file_manipulation.rb
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/actions/inject_into_file.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/actions/inject_into_file.rb
index 089bd894e4..66dd1f5fc1 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/actions/inject_into_file.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/actions/inject_into_file.rb
@@ -34,7 +34,7 @@ class Thor
action InjectIntoFile.new(self, destination, data, config)
end
- class InjectIntoFile < EmptyDirectory
+ class InjectIntoFile < EmptyDirectory #:nodoc:
attr_reader :flag, :replacement
def initialize(base, destination, data, config)
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/base.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/base.rb
index 0bdcc1f4d5..0fa87f8162 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/base.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/base.rb
@@ -8,7 +8,10 @@ require 'thor/task'
require 'thor/util'
class Thor
+ # Shortcuts for help.
HELP_MAPPINGS = %w(-h -? --help -D)
+
+ # Thor methods that should not be overwritten by the user.
THOR_RESERVED_WORDS = %w(invoke shell options behavior root destination_root relative_root
action add_file create_file in_root inside run run_ruby_script)
@@ -78,7 +81,6 @@ class Thor
# Whenever a class inherits from Thor or Thor::Group, we should track the
# class and the file on Thor::Base. This is the method responsable for it.
- # Also adds the source root to the source paths if the klass respond to it.
#
def register_klass_file(klass) #:nodoc:
file = caller[1].match(/(.*):\d+/)[1]
@@ -246,7 +248,8 @@ class Thor
# Returns the tasks for this Thor class.
#
# ==== Returns
- # OrderedHash:: An ordered hash with this class tasks.
+ # OrderedHash:: An ordered hash with tasks names as keys and Thor::Task
+ # objects as values.
#
def tasks
@tasks ||= Thor::CoreExt::OrderedHash.new
@@ -255,7 +258,8 @@ class Thor
# Returns the tasks for this Thor class and all subclasses.
#
# ==== Returns
- # OrderedHash
+ # OrderedHash:: An ordered hash with tasks names as keys and Thor::Task
+ # objects as values.
#
def all_tasks
@all_tasks ||= from_superclass(:all_tasks, Thor::CoreExt::OrderedHash.new)
@@ -334,7 +338,7 @@ class Thor
def namespace(name=nil)
case name
when nil
- @namespace ||= Thor::Util.constant_to_namespace(self, false)
+ @namespace ||= Thor::Util.namespace_from_thor_class(self, false)
else
@namespace = name.to_s
end
@@ -342,7 +346,7 @@ class Thor
# Default way to start generators from the command line.
#
- def start(given_args=ARGV, config={}) #:nodoc:
+ def start(given_args=ARGV, config={})
config[:shell] ||= Thor::Base.shell.new
yield
rescue Thor::Error => e
@@ -360,7 +364,7 @@ class Thor
# hooks to add extra options, one of them if the third argument called
# extra_group that should be a hash in the format :group => Array[Options].
#
- # The second is by returning a lamda used to print values. The lambda
+ # The second is by returning a lambda used to print values. The lambda
# requires two options: the group name and the array of options.
#
def class_options_help(shell, ungrouped_name=nil, extra_group=nil) #:nodoc:
@@ -377,24 +381,14 @@ class Thor
options.each do |option|
item = [ option.usage(padding) ]
-
- item << if option.description
- "# #{option.description}"
- else
- ""
- end
+ item.push(option.description ? "# #{option.description}" : "")
list << item
list << [ "", "# Default: #{option.default}" ] if option.show_default?
end
unless list.empty?
- if group_name
- shell.say "#{group_name} options:"
- else
- shell.say "Options:"
- end
-
+ shell.say(group_name ? "#{group_name} options:" : "Options:")
shell.print_table(list, :ident => 2)
shell.say ""
end
@@ -412,7 +406,7 @@ class Thor
# Raises an error if the word given is a Thor reserved word.
#
- def is_thor_reserved_word?(word, type)
+ def is_thor_reserved_word?(word, type) #:nodoc:
return false unless THOR_RESERVED_WORDS.include?(word.to_s)
raise "#{word.inspect} is a Thor reserved word and cannot be defined as #{type}"
end
@@ -423,7 +417,7 @@ class Thor
# name<Symbol>:: The name of the argument.
# options<Hash>:: Described in both class_option and method_option.
#
- def build_option(name, options, scope)
+ def build_option(name, options, scope) #:nodoc:
scope[name] = Thor::Option.new(name, options[:desc], options[:required],
options[:type], options[:default], options[:banner],
options[:group], options[:aliases])
@@ -437,7 +431,7 @@ class Thor
# ==== Parameters
# Hash[Symbol => Object]
#
- def build_options(options, scope)
+ def build_options(options, scope) #:nodoc:
options.each do |key, value|
scope[key] = Thor::Option.parse(key, value)
end
@@ -447,7 +441,7 @@ class Thor
# class, just return it, otherwise dup it and add the fresh copy to the
# current task hash.
#
- def find_and_refresh_task(name)
+ def find_and_refresh_task(name) #:nodoc:
task = if task = tasks[name.to_s]
task
elsif task = all_tasks[name.to_s]
@@ -465,7 +459,7 @@ class Thor
end
# Fire this callback whenever a method is added. Added methods are
- # tracked as tasks if the requirements set by valid_task? are valid.
+ # tracked as tasks by invoking the create_task method.
#
def method_added(meth)
meth = meth.to_s
@@ -486,7 +480,7 @@ class Thor
end
# Retrieves a value from superclass. If it reaches the baseclass,
- # returns nil.
+ # returns default.
#
def from_superclass(method, default=nil)
if self == baseclass || !superclass.respond_to?(method, true)
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/core_ext/hash_with_indifferent_access.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/core_ext/hash_with_indifferent_access.rb
index 3213961fe4..78bc5cf4bf 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/core_ext/hash_with_indifferent_access.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/core_ext/hash_with_indifferent_access.rb
@@ -1,5 +1,5 @@
class Thor
- module CoreExt
+ module CoreExt #:nodoc:
# A hash with indifferent access and magic predicates.
#
@@ -9,7 +9,7 @@ class Thor
# hash['foo'] #=> 'bar'
# hash.foo? #=> true
#
- class HashWithIndifferentAccess < ::Hash
+ class HashWithIndifferentAccess < ::Hash #:nodoc:
def initialize(hash={})
super()
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/core_ext/ordered_hash.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/core_ext/ordered_hash.rb
index 5e4ad5609f..27fea5bb35 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/core_ext/ordered_hash.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/core_ext/ordered_hash.rb
@@ -1,6 +1,4 @@
-require 'forwardable'
-
-class Thor #:nodoc:
+class Thor
module CoreExt #:nodoc:
if RUBY_VERSION >= '1.9'
diff --git a/railties/lib/vendor/thor-0.11.5/lib/thor/error.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/error.rb
new file mode 100644
index 0000000000..f9b31a35d1
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/error.rb
@@ -0,0 +1,27 @@
+class Thor
+ # Thor::Error is raised when it's caused by wrong usage of thor classes. Those
+ # errors have their backtrace supressed and are nicely shown to the user.
+ #
+ # Errors that are caused by the developer, like declaring a method which
+ # overwrites a thor keyword, it SHOULD NOT raise a Thor::Error. This way, we
+ # ensure that developer errors are shown with full backtrace.
+ #
+ class Error < StandardError
+ end
+
+ # Raised when a task was not found.
+ #
+ class UndefinedTaskError < Error
+ end
+
+ # Raised when a task was found, but not invoked properly.
+ #
+ class InvocationError < Error
+ end
+
+ class RequiredArgumentMissingError < InvocationError
+ end
+
+ class MalformattedArgumentError < InvocationError
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/group.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/group.rb
index 1be1c35ba5..1e59df2313 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/group.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/group.rb
@@ -221,9 +221,9 @@ class Thor::Group
protected
# The banner for this class. You can customize it if you are invoking the
- # thor class by another means which is not the Thor::Runner.
+ # thor class by another ways which is not the Thor::Runner.
#
- def banner #:nodoc:
+ def banner
"#{self.namespace} #{self.arguments.map {|a| a.usage }.join(' ')}"
end
@@ -244,7 +244,7 @@ class Thor::Group
# Shortcut to invoke with padding and block handling. Use internally by
# invoke and invoke_from_option class methods.
#
- def _invoke_for_class_method(klass, task=nil, *args, &block)
+ def _invoke_for_class_method(klass, task=nil, *args, &block) #:nodoc:
shell.padding += 1
result = if block_given?
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/invocation.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/invocation.rb
index 34e7a4b911..c0388dd863 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/invocation.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/invocation.rb
@@ -11,7 +11,7 @@ class Thor
def prepare_for_invocation(key, name) #:nodoc:
case name
when Symbol, String
- Thor::Util.namespace_to_thor_class(name.to_s, false)
+ Thor::Util.namespace_to_thor_class_and_task(name.to_s, false)
else
name
end
@@ -96,20 +96,8 @@ class Thor
task, args, opts, config = nil, task, args, opts if task.nil? || task.is_a?(Array)
args, opts, config = nil, args, opts if args.is_a?(Hash)
- object, task = _prepare_for_invocation(name, task)
- if object.is_a?(Class)
- klass = object
-
- stored_args, stored_opts, stored_config = @_initializer
- args ||= stored_args.dup
- opts ||= stored_opts.dup
-
- config ||= {}
- config = stored_config.merge(_shared_configuration).merge!(config)
- instance = klass.new(args, opts, config)
- else
- klass, instance = object.class, object
- end
+ object, task = _prepare_for_invocation(name, task)
+ klass, instance = _initialize_klass_with_initializer(object, args, opts, config)
method_args = []
current = @_invocations[klass]
@@ -134,7 +122,7 @@ class Thor
# Configuration values that are shared between invocations.
#
- def _shared_configuration
+ def _shared_configuration #:nodoc:
{ :invocations => @_invocations }
end
@@ -154,13 +142,13 @@ class Thor
# If the object was not set, use self and use the name as task.
object, task = self, name unless object
- return object, _validate_klass_and_task(object, task)
+ return object, _validate_task(object, task)
end
# Check if the object given is a Thor class object and get a task object
# for it.
#
- def _validate_klass_and_task(object, task) #:nodoc:
+ def _validate_task(object, task) #:nodoc:
klass = object.is_a?(Class) ? object : object.class
raise "Expected Thor class, got #{klass}" unless klass <= Thor::Base
@@ -168,5 +156,23 @@ class Thor
task = klass.all_tasks[task.to_s] || Task.dynamic(task) if task && !task.is_a?(Thor::Task)
task
end
+
+ # Initialize klass using values stored in the @_initializer.
+ #
+ def _initialize_klass_with_initializer(object, args, opts, config) #:nodoc:
+ if object.is_a?(Class)
+ klass = object
+
+ stored_args, stored_opts, stored_config = @_initializer
+ args ||= stored_args.dup
+ opts ||= stored_opts.dup
+
+ config ||= {}
+ config = stored_config.merge(_shared_configuration).merge!(config)
+ [ klass, klass.new(args, opts, config) ]
+ else
+ [ object.class, object ]
+ end
+ end
end
end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/parser.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/parser.rb
index 57a3f6e1a5..57a3f6e1a5 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/parser.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/parser.rb
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/parser/argument.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/parser/argument.rb
index 2d7f4dbafb..aa8ace4719 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/parser/argument.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/parser/argument.rb
@@ -1,5 +1,5 @@
class Thor
- class Argument
+ class Argument #:nodoc:
VALID_TYPES = [ :numeric, :hash, :array, :string ]
attr_reader :name, :description, :required, :type, :default, :banner
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/parser/arguments.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/parser/arguments.rb
index 9a2262d6f7..fb5d965e06 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/parser/arguments.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/parser/arguments.rb
@@ -1,5 +1,5 @@
class Thor
- class Arguments
+ class Arguments #:nodoc:
NUMERIC = /(\d*\.\d+|\d+)/
# Receives an array of args and returns two arrays, one with arguments
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/parser/option.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/parser/option.rb
index 5c43f6b18f..9e40ec73fa 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/parser/option.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/parser/option.rb
@@ -1,5 +1,5 @@
class Thor
- class Option < Argument
+ class Option < Argument #:nodoc:
attr_reader :aliases, :group
VALID_TYPES = [:boolean, :numeric, :hash, :array, :string]
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/parser/options.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/parser/options.rb
index 01c86b7b27..75092308b5 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/parser/options.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/parser/options.rb
@@ -2,7 +2,7 @@ class Thor
# This is a modified version of Daniel Berger's Getopt::Long class, licensed
# under Ruby's license.
#
- class Options < Arguments
+ class Options < Arguments #:nodoc:
LONG_RE = /^(--\w+[-\w+]*)$/
SHORT_RE = /^(-[a-z])$/i
EQ_RE = /^(--\w+[-\w+]*|-[a-z])=(.*)$/i
diff --git a/railties/lib/vendor/thor-0.11.5/lib/thor/rake_compat.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/rake_compat.rb
new file mode 100644
index 0000000000..3ab6bb21f5
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/rake_compat.rb
@@ -0,0 +1,67 @@
+require 'rake'
+
+class Thor
+ # Adds a compatibility layer to your Thor classes which allows you to use
+ # rake package tasks. For example, to use rspec rake tasks, one can do:
+ #
+ # require 'thor/rake_compat'
+ #
+ # class Default < Thor
+ # include Thor::RakeCompat
+ #
+ # Spec::Rake::SpecTask.new(:spec) do |t|
+ # t.spec_opts = ['--options', "spec/spec.opts"]
+ # t.spec_files = FileList['spec/**/*_spec.rb']
+ # end
+ # end
+ #
+ module RakeCompat
+ def self.rake_classes
+ @rake_classes ||= []
+ end
+
+ def self.included(base)
+ # Hack. Make rakefile point to invoker, so rdoc task is generated properly.
+ Rake.application.instance_variable_set(:@rakefile, caller[0].match(/(.*):\d+/)[1])
+ self.rake_classes << base
+ end
+ end
+end
+
+class Object #:nodoc:
+ alias :rake_task :task
+ alias :rake_namespace :namespace
+
+ def task(*args, &block)
+ task = rake_task(*args, &block)
+
+ if klass = Thor::RakeCompat.rake_classes.last
+ non_namespaced_name = task.name.split(':').last
+
+ description = non_namespaced_name
+ description << task.arg_names.map{ |n| n.to_s.upcase }.join(' ')
+ description.strip!
+
+ klass.desc description, task.comment || non_namespaced_name
+ klass.class_eval <<-METHOD
+ def #{non_namespaced_name}(#{task.arg_names.join(', ')})
+ Rake::Task[#{task.name.to_sym.inspect}].invoke(#{task.arg_names.join(', ')})
+ end
+ METHOD
+ end
+
+ task
+ end
+
+ def namespace(name, &block)
+ if klass = Thor::RakeCompat.rake_classes.last
+ const_name = Thor::Util.camel_case(name.to_s).to_sym
+ klass.const_set(const_name, Class.new(Thor))
+ new_klass = klass.const_get(const_name)
+ Thor::RakeCompat.rake_classes << new_klass
+ end
+
+ rake_namespace(name, &block)
+ Thor::RakeCompat.rake_classes.pop
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/runner.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/runner.rb
index 6782c61dec..3639ac0aa9 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/runner.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/runner.rb
@@ -4,7 +4,7 @@ require 'yaml'
require 'digest/md5'
require 'pathname'
-class Thor::Runner < Thor
+class Thor::Runner < Thor #:nodoc:
map "-T" => :list, "-i" => :install, "-u" => :update
# Override Thor#help so it can give information about any class and any method.
@@ -12,8 +12,9 @@ class Thor::Runner < Thor
def help(meth=nil)
if meth && !self.respond_to?(meth)
initialize_thorfiles(meth)
- klass, task = Thor::Util.namespace_to_thor_class(meth)
- klass.start(["-h", task].compact, :shell => self.shell) # send mapping -h because it works with Thor::Group too
+ klass, task = Thor::Util.namespace_to_thor_class_and_task(meth)
+ # Send mapping -h because it works with Thor::Group too
+ klass.start(["-h", task].compact, :shell => self.shell)
else
super
end
@@ -25,12 +26,12 @@ class Thor::Runner < Thor
def method_missing(meth, *args)
meth = meth.to_s
initialize_thorfiles(meth)
- klass, task = Thor::Util.namespace_to_thor_class(meth)
+ klass, task = Thor::Util.namespace_to_thor_class_and_task(meth)
args.unshift(task) if task
klass.start(args, :shell => shell)
end
- desc "install NAME", "Install a Thor file into your system tasks, optionally named for future updates"
+ desc "install NAME", "Install an optionally named Thor file into your system tasks"
method_options :as => :string, :relative => :boolean
def install(name)
initialize_thorfiles
@@ -76,7 +77,7 @@ class Thor::Runner < Thor
thor_yaml[as] = {
:filename => Digest::MD5.hexdigest(name + as),
:location => location,
- :namespaces => Thor::Util.namespaces_in_contents(contents, base)
+ :namespaces => Thor::Util.namespaces_in_content(contents, base)
}
save_yaml(thor_yaml)
@@ -130,8 +131,7 @@ class Thor::Runner < Thor
display_klasses(true, klasses)
end
- desc "list [SEARCH]",
- "List the available thor tasks (--substring means SEARCH anywhere in the namespace)"
+ desc "list [SEARCH]", "List the available thor tasks (--substring means .*SEARCH)"
method_options :substring => :boolean, :group => :string, :all => :boolean
def list(search="")
initialize_thorfiles
@@ -269,6 +269,10 @@ class Thor::Runner < Thor
end
unless klasses.empty?
+ klasses.dup.each do |klass|
+ klasses -= Thor::Util.thor_classes_in(klass)
+ end
+
klasses.each { |k| display_tasks(k) }
else
say "\033[1;34mNo Thor tasks available\033[0m"
@@ -285,7 +289,7 @@ class Thor::Runner < Thor
say shell.set_color(base, color, true)
say "-" * base.length
- klass.help(shell, :short => true, :namespace => true)
+ klass.help(shell, :short => true, :ident => 0, :namespace => true)
end
end
end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/shell.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/shell.rb
index 7ed4a24bfb..0d3f4d5951 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/shell.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/shell.rb
@@ -64,7 +64,7 @@ class Thor
# Allow shell to be shared between invocations.
#
- def _shared_configuration
+ def _shared_configuration #:nodoc:
super.merge!(:shell => self.shell)
end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/shell/basic.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/shell/basic.rb
index e294c87567..3c02e47c33 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/shell/basic.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/shell/basic.rb
@@ -11,9 +11,9 @@ class Thor
@base, @padding = nil, 0
end
- # Do not allow padding to be less than zero.
+ # Sets the output padding, not allowing less than zero values.
#
- def padding=(value) #:nodoc:
+ def padding=(value)
@padding = [0, value].max
end
@@ -52,7 +52,7 @@ class Thor
# in log_status, avoiding the message from being shown. If a Symbol is
# given in log_status, it's used as the color.
#
- def say_status(status, message, log_status=true) #:nodoc:
+ def say_status(status, message, log_status=true)
return if quiet? || log_status == false
spaces = " " * (padding + 1)
color = log_status.is_a?(Symbol) ? log_status : :green
@@ -80,17 +80,21 @@ class Thor
#
# ==== Parameters
# list<Array[String, String, ...]>
- # mode<Symbol>:: Can be :rows or :inline. Defaults to :rows.
#
- def print_list(list, mode=:rows)
+ # ==== Options
+ # mode:: Can be :rows or :inline. Defaults to :rows.
+ # ident:: Ident each item with the value given.
+ #
+ def print_list(list, options={})
return if list.empty?
- content = case mode
+ ident = " " * (options[:ident] || 0)
+ content = case options[:mode]
when :inline
last = list.pop
"#{list.join(", ")}, and #{last}"
else # rows
- list.join("\n")
+ ident + list.join("\n#{ident}")
end
$stdout.puts content
@@ -103,7 +107,6 @@ class Thor
#
# ==== Options
# ident<Integer>:: Ident the first column by ident value.
- # emphasize_last<Boolean>:: When true, add a different behavior to the last column.
#
def print_table(table, options={})
return if table.empty?
@@ -131,7 +134,7 @@ class Thor
#
# ==== Parameters
# destination<String>:: the destination file to solve conflicts
- # block<Proc>:: an optional proc that returns the value to be used in diff
+ # block<Proc>:: an optional block that returns the value to be used in diff
#
def file_collision(destination)
return true if @always_force
@@ -164,19 +167,20 @@ class Thor
# wrong, you can always raise an exception. If you raise a Thor::Error, it
# will be rescued and wrapped in the method below.
#
- def error(statement) #:nodoc:
+ def error(statement)
$stderr.puts statement
end
- # Apply color to the given string with optional bold.
+ # Apply color to the given string with optional bold. Disabled in the
+ # Thor::Shell::Basic class.
#
- def set_color(string, color, bold=false)
+ def set_color(string, color, bold=false) #:nodoc:
string
end
protected
- def is?(value)
+ def is?(value) #:nodoc:
value = value.to_s
if value.size == 1
@@ -186,7 +190,7 @@ class Thor
end
end
- def file_collision_help
+ def file_collision_help #:nodoc:
<<HELP
Y - yes, overwrite
n - no, do not overwrite
@@ -197,17 +201,17 @@ h - help, show this help
HELP
end
- def show_diff(destination, content)
+ def show_diff(destination, content) #:nodoc:
diff_cmd = ENV['THOR_DIFF'] || ENV['RAILS_DIFF'] || 'diff -u'
Tempfile.open(File.basename(destination), File.dirname(destination)) do |temp|
temp.write content
temp.rewind
- say `#{diff_cmd} "#{destination}" "#{temp.path}"`
+ system %(#{diff_cmd} "#{destination}" "#{temp.path}")
end
end
- def quiet?
+ def quiet? #:nodoc:
base && base.options[:quiet]
end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/shell/color.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/shell/color.rb
index be7995146a..24704f7885 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/shell/color.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/shell/color.rb
@@ -2,7 +2,8 @@ require 'thor/shell/basic'
class Thor
module Shell
- # Set color in the output. Got color values from HighLine.
+ # Inherit from Thor::Shell::Basic and add set_color behavior. Check
+ # Thor::Shell::Basic to see all available methods.
#
class Color < Basic
# Embed in a String to clear all previous ANSI sequences.
@@ -44,9 +45,10 @@ class Thor
# Set the terminal's background ANSI color to white.
ON_WHITE = "\e[47m"
- # Set color by using a string or one of the defined constants. Based
- # on Highline implementation. CLEAR is automatically be embedded to
- # the end of the returned String.
+ # Set color by using a string or one of the defined constants. If a third
+ # option is set to true, it also adds bold to the string. This is based
+ # on Highline implementation and it automatically appends CLEAR to the end
+ # of the returned String.
#
def set_color(string, color, bold=false)
color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol)
@@ -59,7 +61,7 @@ class Thor
# Overwrite show_diff to show diff with colors if Diff::LCS is
# available.
#
- def show_diff(destination, content)
+ def show_diff(destination, content) #:nodoc:
if diff_lcs_loaded? && ENV['THOR_DIFF'].nil? && ENV['RAILS_DIFF'].nil?
actual = File.read(destination).to_s.split("\n")
content = content.to_s.split("\n")
@@ -72,7 +74,7 @@ class Thor
end
end
- def output_diff_line(diff)
+ def output_diff_line(diff) #:nodoc:
case diff.action
when '-'
say "- #{diff.old_element.chomp}", :red, true
@@ -89,7 +91,7 @@ class Thor
# Check if Diff::LCS is loaded. If it is, use it to create pretty output
# for diff.
#
- def diff_lcs_loaded?
+ def diff_lcs_loaded? #:nodoc:
return true if defined?(Diff::LCS)
return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/task.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/task.rb
index 92c0776c04..23d35b883c 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/task.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/task.rb
@@ -12,7 +12,7 @@ class Thor
super(name.to_s, description, usage, options || {})
end
- def initialize_copy(other)
+ def initialize_copy(other) #:nodoc:
super(other)
self.options = other.options.dup if other.options
end
@@ -36,11 +36,19 @@ class Thor
# Returns the formatted usage. If a class is given, the class arguments are
# injected in the usage.
#
- def formatted_usage(klass=nil, namespace=false)
+ def formatted_usage(klass=nil, namespace=false, show_options=true)
formatted = ''
- formatted << "#{klass.namespace.gsub(/^default/,'')}:" if klass && namespace
+
+ formatted = if namespace.is_a?(String)
+ "#{namespace}:"
+ elsif klass && namespace
+ "#{klass.namespace.gsub(/^default/,'')}:"
+ else
+ ""
+ end
+
formatted << formatted_arguments(klass)
- formatted << " #{formatted_options}"
+ formatted << " #{formatted_options}" if show_options
formatted.strip!
formatted
end
@@ -67,20 +75,20 @@ class Thor
# Given a target, checks if this class name is not a private/protected method.
#
- def public_method?(instance)
+ def public_method?(instance) #:nodoc:
collection = instance.private_methods + instance.protected_methods
!(collection).include?(name.to_s) && !(collection).include?(name.to_sym) # For Ruby 1.9
end
# Clean everything that comes from the Thor gempath and remove the caller.
#
- def sans_backtrace(backtrace, caller)
+ def sans_backtrace(backtrace, caller) #:nodoc:
dirname = /^#{Regexp.escape(File.dirname(__FILE__))}/
saned = backtrace.reject { |frame| frame =~ dirname }
saned -= caller
end
- def parse_argument_error(instance, e, caller)
+ def parse_argument_error(instance, e, caller) #:nodoc:
backtrace = sans_backtrace(e.backtrace, caller)
if backtrace.empty? && e.message =~ /wrong number of arguments/
@@ -95,7 +103,7 @@ class Thor
end
end
- def parse_no_method_error(instance, e)
+ def parse_no_method_error(instance, e) #:nodoc:
if e.message =~ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/
raise UndefinedTaskError, "The #{instance.class.namespace} namespace " <<
"doesn't have a '#{name}' task"
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/util.rb b/railties/lib/vendor/thor-0.11.5/lib/thor/util.rb
index 26db24aadb..4938dc4aca 100644
--- a/railties/lib/vendor/thor-0.11.3/lib/thor/util.rb
+++ b/railties/lib/vendor/thor-0.11.5/lib/thor/util.rb
@@ -1,14 +1,14 @@
require 'rbconfig'
class Thor
- module Sandbox; end
+ module Sandbox #:nodoc:
+ end
# This module holds several utilities:
#
# 1) Methods to convert thor namespaces to constants and vice-versa.
#
- # Thor::Utils.constant_to_namespace(Foo::Bar::Baz) #=> "foo:bar:baz"
- # Thor::Utils.namespace_to_constant("foo:bar:baz") #=> Foo::Bar::Baz
+ # Thor::Utils.namespace_from_thor_class(Foo::Bar::Baz) #=> "foo:bar:baz"
#
# 2) Loading thor files and sandboxing:
#
@@ -43,15 +43,15 @@ class Thor
# ==== Returns
# String:: If we receive Foo::Bar::Baz it returns "foo:bar:baz"
#
- def self.constant_to_namespace(constant, remove_default=true)
+ def self.namespace_from_thor_class(constant, remove_default=true)
constant = constant.to_s.gsub(/^Thor::Sandbox::/, "")
constant = snake_case(constant).squeeze(":")
constant.gsub!(/^default/, '') if remove_default
constant
end
- # Given the contents, evaluate it inside the sandbox and returns the thor
- # classes defined in the sandbox.
+ # Given the contents, evaluate it inside the sandbox and returns the
+ # namespaces defined in the sandbox.
#
# ==== Parameters
# contents<String>
@@ -59,7 +59,7 @@ class Thor
# ==== Returns
# Array[Object]
#
- def self.namespaces_in_contents(contents, file=__FILE__)
+ def self.namespaces_in_content(contents, file=__FILE__)
old_constants = Thor::Base.subclasses.dup
Thor::Base.subclasses.clear
@@ -73,6 +73,14 @@ class Thor
new_constants
end
+ # Returns the thor classes declared inside the given class.
+ #
+ def self.thor_classes_in(klass)
+ Thor::Base.subclasses.select do |subclass|
+ klass.constants.include?(subclass.name.gsub("#{klass.name}::", ''))
+ end
+ end
+
# Receives a string and convert it to snake case. SnakeCase returns snake_case.
#
# ==== Parameters
@@ -87,6 +95,19 @@ class Thor
return $+.downcase
end
+ # Receives a string and convert it to camel case. camel_case returns CamelCase.
+ #
+ # ==== Parameters
+ # String
+ #
+ # ==== Returns
+ # String
+ #
+ def self.camel_case(str)
+ return str if str !~ /_/ && str =~ /[A-Z]+.*/
+ str.split('_').map { |i| i.capitalize }.join
+ end
+
# Receives a namespace and tries to retrieve a Thor or Thor::Group class
# from it. It first searches for a class using the all the given namespace,
# if it's not found, removes the highest entry and searches for the class
@@ -115,7 +136,7 @@ class Thor
# Thor::Error:: raised if the namespace evals to a class which does not
# inherit from Thor or Thor::Group.
#
- def self.namespace_to_thor_class(namespace, raise_if_nil=true)
+ def self.namespace_to_thor_class_and_task(namespace, raise_if_nil=true)
klass, task_name = Thor::Util.find_by_namespace(namespace), nil
if klass.nil? && namespace.include?(?:)
@@ -156,7 +177,7 @@ class Thor
yaml.each do |k, v|
next unless v[:constants] && v[:namespaces].nil?
yaml_changed = true
- yaml[k][:namespaces] = v[:constants].map{|c| Thor::Util.constant_to_namespace(c)}
+ yaml[k][:namespaces] = v[:constants].map{|c| Thor::Util.namespace_from_thor_class(c)}
end
yaml_changed
@@ -214,7 +235,7 @@ class Thor
# Return the path to the ruby interpreter taking into account multiple
# installations and windows extensions.
#
- def self.ruby_command #:nodoc:
+ def self.ruby_command
@ruby_command ||= begin
ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
ruby << Config::CONFIG['EXEEXT']
diff --git a/railties/test/fixtures/lib/template.rb b/railties/test/fixtures/lib/template.rb
new file mode 100644
index 0000000000..c14a1a8784
--- /dev/null
+++ b/railties/test/fixtures/lib/template.rb
@@ -0,0 +1 @@
+say "It works from file!"
diff --git a/railties/test/fixtures/vendor/gems/mspec/lib/generators/mspec_generator.rb b/railties/test/fixtures/vendor/gems/gems/mspec/lib/generators/mspec_generator.rb
index 191bdbf2fc..191bdbf2fc 100644
--- a/railties/test/fixtures/vendor/gems/mspec/lib/generators/mspec_generator.rb
+++ b/railties/test/fixtures/vendor/gems/gems/mspec/lib/generators/mspec_generator.rb
diff --git a/railties/test/fixtures/vendor/gems/wrong/lib/generators/wrong_generator.rb b/railties/test/fixtures/vendor/gems/gems/wrong/lib/generators/wrong_generator.rb
index 6aa7cb052e..6aa7cb052e 100644
--- a/railties/test/fixtures/vendor/gems/wrong/lib/generators/wrong_generator.rb
+++ b/railties/test/fixtures/vendor/gems/gems/wrong/lib/generators/wrong_generator.rb
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index c794a2ade6..19e41c15c8 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -131,6 +131,11 @@ class AppGeneratorTest < GeneratorsTestCase
assert_file 'config/environment.rb', /# RAILS_GEM_VERSION/
end
+ def test_template_from_dir_pwd
+ FileUtils.cd(RAILS_ROOT)
+ assert_match /It works from file!/, run_generator(["-m", "lib/template.rb"])
+ end
+
def test_template_raises_an_error_with_invalid_path
content = capture(:stderr){ run_generator(["-m", "non/existant/path"]) }
assert_match /The template \[.*\] could not be loaded/, content
diff --git a/railties/test/generators/generators_test_helper.rb b/railties/test/generators/generators_test_helper.rb
index 011bd518f8..9444a9ed4b 100644
--- a/railties/test/generators/generators_test_helper.rb
+++ b/railties/test/generators/generators_test_helper.rb
@@ -20,7 +20,7 @@ class GeneratorsTestCase < Test::Unit::TestCase
def destination_root
@destination_root ||= File.expand_path(File.join(File.dirname(__FILE__),
- '..', '..', 'fixtures', 'tmp'))
+ '..', 'fixtures', 'tmp'))
end
def setup
diff --git a/railties/test/generators/scaffold_controller_generator_test.rb b/railties/test/generators/scaffold_controller_generator_test.rb
index 024ea439ef..834e43e776 100644
--- a/railties/test/generators/scaffold_controller_generator_test.rb
+++ b/railties/test/generators/scaffold_controller_generator_test.rb
@@ -99,7 +99,7 @@ class ScaffoldControllerGeneratorTest < GeneratorsTestCase
def test_error_is_shown_if_orm_does_not_provide_interface
error = capture(:stderr){ run_generator ["User", "--orm=unknown"] }
- assert_equal "Could not load Unknown::Generators::ActionORM, skipping controller. " <<
+ assert_equal "Could not load Unknown::Generators::ActiveModel, skipping controller. " <<
"Error: no such file to load -- generators/unknown.\n", error
end